<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import PopperContent from './PopperContent';
import { getTarget, DOMElement, mapToCssModules, omit, PopperPlacements } from './utils';

const propTypes = {
  placement: PropTypes.oneOf(PopperPlacements),
  target: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    DOMElement,
  ]).isRequired,
  container: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    DOMElement,
  ]),
  isOpen: PropTypes.bool,
  disabled: PropTypes.bool,
  hideArrow: PropTypes.bool,
  className: PropTypes.string,
  innerClassName: PropTypes.string,
  cssModule: PropTypes.object,
  toggle: PropTypes.func,
  autohide: PropTypes.bool,
  placementPrefix: PropTypes.string,
  delay: PropTypes.oneOfType([
    PropTypes.shape({ show: PropTypes.number, hide: PropTypes.number }),
    PropTypes.number,
  ]),
  modifiers: PropTypes.object,
  offset: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number
  ]),
};

const DEFAULT_DELAYS = {
  show: 0,
  hide: 250
};

const defaultProps = {
  isOpen: false,
  hideArrow: false,
  placement: 'top',
  placementPrefix: 'bs-tooltip',
  delay: DEFAULT_DELAYS,
  autohide: true,
  toggle: function () { }
};

class Tooltip extends React.Component {
  constructor(props) {
    super(props);

    this.addTargetEvents = this.addTargetEvents.bind(this);
    this.handleDocumentClick = this.handleDocumentClick.bind(this);
    this.removeTargetEvents = this.removeTargetEvents.bind(this);
    this.toggle = this.toggle.bind(this);
    this.onMouseOverTooltip = this.onMouseOverTooltip.bind(this);
    this.onMouseLeaveTooltip = this.onMouseLeaveTooltip.bind(this);
    this.onMouseOverTooltipContent = this.onMouseOverTooltipContent.bind(this);
    this.onMouseLeaveTooltipContent = this.onMouseLeaveTooltipContent.bind(this);
    this.show = this.show.bind(this);
    this.hide = this.hide.bind(this);
    this.onEscKeyDown = this.onEscKeyDown.bind(this);
  }

  componentDidMount() {
    this._target = getTarget(this.props.target);
    this.addTargetEvents();
  }

  componentWillUnmount() {
    this.removeTargetEvents();
  }

  onMouseOverTooltip() {
    if (this._hideTimeout) {
      this.clearHideTimeout();
    }
    this._showTimeout = setTimeout(this.show, this.getDelay('show'));
  }

  onMouseLeaveTooltip() {
    if (this._showTimeout) {
      this.clearShowTimeout();
    }
    this._hideTimeout = setTimeout(this.hide, this.getDelay('hide'));
  }

  onMouseOverTooltipContent() {
    if (this.props.autohide) {
      return;
    }
    if (this._hideTimeout) {
      this.clearHideTimeout();
    }
  }

  onMouseLeaveTooltipContent() {
    if (this.props.autohide) {
      return;
    }
    if (this._showTimeout) {
      this.clearShowTimeout();
    }
    this._hideTimeout = setTimeout(this.hide, this.getDelay('hide'));
  }

  onEscKeyDown(e) {
    if (e.key === 'Escape') {
      this.hide();
    }
  }

  getDelay(key) {
    const { delay } = this.props;
    if (typeof delay === 'object') {
      return isNaN(delay[key]) ? DEFAULT_DELAYS[key] : delay[key];
    }
    return delay;
  }

  show() {
    if (!this.props.isOpen) {
      this.clearShowTimeout();
      this.toggle();
    }
  }

  hide() {
    if (this.props.isOpen) {
      this.clearHideTimeout();
      this.toggle();
    }
  }

  clearShowTimeout() {
    clearTimeout(this._showTimeout);
    this._showTimeout = undefined;
  }

  clearHideTimeout() {
    clearTimeout(this._hideTimeout);
    this._hideTimeout = undefined;
  }

  handleDocumentClick(e) {
    if (e.target === this._target || this._target.contains(e.target)) {
      if (this._hideTimeout) {
        this.clearHideTimeout();
      }

      if (!this.props.isOpen) {
        this.toggle();
      }
    }
  }

  addTargetEvents() {
    this._target.addEventListener('mouseover', this.onMouseOverTooltip, true);
    this._target.addEventListener('mouseout', this.onMouseLeaveTooltip, true);
    this._target.addEventListener('keydown', this.onEscKeyDown, true);
    this._target.addEventListener('focusin', this.show, true);
    this._target.addEventListener('focusout', this.hide, true);

    ['click', 'touchstart'].forEach(event =>
      document.addEventListener(event, this.handleDocumentClick, true)
    );
  }

  removeTargetEvents() {
    this._target.removeEventListener('mouseover', this.onMouseOverTooltip, true);
    this._target.removeEventListener('mouseout', this.onMouseLeaveTooltip, true);
    this._target.addEventListener('keydown', this.onEscKeyDown, true);
    this._target.addEventListener('focusin', this.show, true);
    this._target.addEventListener('focusout', this.hide, true);

    ['click', 'touchstart'].forEach(event =>
      document.removeEventListener(event, this.handleDocumentClick, true)
    );
  }

  toggle(e) {
    if (this.props.disabled) {
      return e && e.preventDefault();
    }

    return this.props.toggle();
  }

  render() {
    if (!this.props.isOpen) {
      return null;
    }

    const attributes = omit(this.props, Object.keys(propTypes));
    const classes = mapToCssModules(classNames(
      'tooltip-inner',
      this.props.innerClassName
    ), this.props.cssModule);

    const popperClasses = mapToCssModules(classNames(
      'tooltip',
      'show',
      this.props.className
    ), this.props.cssModule);

    return (
      <PopperContent
        className={popperClasses}
        target={this.props.target}
        isOpen={this.props.isOpen}
        hideArrow={this.props.hideArrow}
        placement={this.props.placement}
        placementPrefix={this.props.placementPrefix}
        container={this.props.container}
        modifiers={this.props.modifiers}
        offset={this.props.offset}
        cssModule={this.props.cssModule}
      >
        <div
          {...attributes}
          className={classes}
          role="tooltip"
          aria-hidden={this.props.isOpen}
          onMouseOver={this.onMouseOverTooltipContent}
          onMouseLeave={this.onMouseLeaveTooltipContent}
          onKeyDown={this.onEscKeyDown}
        />
      </PopperContent>
    );
  }
}

Tooltip.propTypes = propTypes;
Tooltip.defaultProps = defaultProps;

export default Tooltip;
<commit_msg>fix(tooltip): fixed tooltip not disappearing on mobile (#1083)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import PopperContent from './PopperContent';
import { getTarget, DOMElement, mapToCssModules, omit, PopperPlacements } from './utils';

const propTypes = {
  placement: PropTypes.oneOf(PopperPlacements),
  target: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    DOMElement,
  ]).isRequired,
  container: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.func,
    DOMElement,
  ]),
  isOpen: PropTypes.bool,
  disabled: PropTypes.bool,
  hideArrow: PropTypes.bool,
  className: PropTypes.string,
  innerClassName: PropTypes.string,
  cssModule: PropTypes.object,
  toggle: PropTypes.func,
  autohide: PropTypes.bool,
  placementPrefix: PropTypes.string,
  delay: PropTypes.oneOfType([
    PropTypes.shape({ show: PropTypes.number, hide: PropTypes.number }),
    PropTypes.number,
  ]),
  modifiers: PropTypes.object,
  offset: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number
  ]),
};

const DEFAULT_DELAYS = {
  show: 0,
  hide: 250
};

const defaultProps = {
  isOpen: false,
  hideArrow: false,
  placement: 'top',
  placementPrefix: 'bs-tooltip',
  delay: DEFAULT_DELAYS,
  autohide: true,
  toggle: function () { }
};

class Tooltip extends React.Component {
  constructor(props) {
    super(props);

    this.addTargetEvents = this.addTargetEvents.bind(this);
    this.handleDocumentClick = this.handleDocumentClick.bind(this);
    this.removeTargetEvents = this.removeTargetEvents.bind(this);
    this.toggle = this.toggle.bind(this);
    this.onMouseOverTooltip = this.onMouseOverTooltip.bind(this);
    this.onMouseLeaveTooltip = this.onMouseLeaveTooltip.bind(this);
    this.onMouseOverTooltipContent = this.onMouseOverTooltipContent.bind(this);
    this.onMouseLeaveTooltipContent = this.onMouseLeaveTooltipContent.bind(this);
    this.show = this.show.bind(this);
    this.hide = this.hide.bind(this);
    this.onEscKeyDown = this.onEscKeyDown.bind(this);
  }

  componentDidMount() {
    this._target = getTarget(this.props.target);
    this.addTargetEvents();
  }

  componentWillUnmount() {
    this.removeTargetEvents();
  }

  onMouseOverTooltip() {
    if (this._hideTimeout) {
      this.clearHideTimeout();
    }
    this._showTimeout = setTimeout(this.show, this.getDelay('show'));
  }

  onMouseLeaveTooltip() {
    if (this._showTimeout) {
      this.clearShowTimeout();
    }
    this._hideTimeout = setTimeout(this.hide, this.getDelay('hide'));
  }

  onMouseOverTooltipContent() {
    if (this.props.autohide) {
      return;
    }
    if (this._hideTimeout) {
      this.clearHideTimeout();
    }
  }

  onMouseLeaveTooltipContent() {
    if (this.props.autohide) {
      return;
    }
    if (this._showTimeout) {
      this.clearShowTimeout();
    }
    this._hideTimeout = setTimeout(this.hide, this.getDelay('hide'));
  }

  onEscKeyDown(e) {
    if (e.key === 'Escape') {
      this.hide();
    }
  }

  getDelay(key) {
    const { delay } = this.props;
    if (typeof delay === 'object') {
      return isNaN(delay[key]) ? DEFAULT_DELAYS[key] : delay[key];
    }
    return delay;
  }

  show() {
    if (!this.props.isOpen) {
      this.clearShowTimeout();
      this.toggle();
    }
  }

  hide() {
    if (this.props.isOpen) {
      this.clearHideTimeout();
      this.toggle();
    }
  }

  clearShowTimeout() {
    clearTimeout(this._showTimeout);
    this._showTimeout = undefined;
  }

  clearHideTimeout() {
    clearTimeout(this._hideTimeout);
    this._hideTimeout = undefined;
  }

  handleDocumentClick(e) {
    if (e.target === this._target || this._target.contains(e.target)) {
      if (this._hideTimeout) {
        this.clearHideTimeout();
      }

      if (!this.props.isOpen) {
        this.toggle();
      }
    } else if (this.props.isOpen && e.target.getAttribute('role') !== 'tooltip') {
      if (this._showTimeout) {
        this.clearShowTimeout();
      }

      this._hideTimeout = setTimeout(this.hide, this.getDelay('hide'));
    }
  }

  addTargetEvents() {
    this._target.addEventListener('mouseover', this.onMouseOverTooltip, true);
    this._target.addEventListener('mouseout', this.onMouseLeaveTooltip, true);
    this._target.addEventListener('keydown', this.onEscKeyDown, true);
    this._target.addEventListener('focusin', this.show, true);
    this._target.addEventListener('focusout', this.hide, true);

    ['click', 'touchstart'].forEach(event =>
      document.addEventListener(event, this.handleDocumentClick, true)
    );
  }

  removeTargetEvents() {
    this._target.removeEventListener('mouseover', this.onMouseOverTooltip, true);
    this._target.removeEventListener('mouseout', this.onMouseLeaveTooltip, true);
    this._target.addEventListener('keydown', this.onEscKeyDown, true);
    this._target.addEventListener('focusin', this.show, true);
    this._target.addEventListener('focusout', this.hide, true);

    ['click', 'touchstart'].forEach(event =>
      document.removeEventListener(event, this.handleDocumentClick, true)
    );
  }

  toggle(e) {
    if (this.props.disabled) {
      return e && e.preventDefault();
    }

    return this.props.toggle();
  }

  render() {
    if (!this.props.isOpen) {
      return null;
    }

    const attributes = omit(this.props, Object.keys(propTypes));
    const classes = mapToCssModules(classNames(
      'tooltip-inner',
      this.props.innerClassName
    ), this.props.cssModule);

    const popperClasses = mapToCssModules(classNames(
      'tooltip',
      'show',
      this.props.className
    ), this.props.cssModule);

    return (
      <PopperContent
        className={popperClasses}
        target={this.props.target}
        isOpen={this.props.isOpen}
        hideArrow={this.props.hideArrow}
        placement={this.props.placement}
        placementPrefix={this.props.placementPrefix}
        container={this.props.container}
        modifiers={this.props.modifiers}
        offset={this.props.offset}
        cssModule={this.props.cssModule}
      >
        <div
          {...attributes}
          className={classes}
          role="tooltip"
          aria-hidden={this.props.isOpen}
          onMouseOver={this.onMouseOverTooltipContent}
          onMouseLeave={this.onMouseLeaveTooltipContent}
          onKeyDown={this.onEscKeyDown}
        />
      </PopperContent>
    );
  }
}

Tooltip.propTypes = propTypes;
Tooltip.defaultProps = defaultProps;

export default Tooltip;
<|endoftext|>


<commit_before>/**
	A multi-line text input that supports rich formatting, such as bold, italics,
	and underlining.

	Use the _value_ property to get or set the displayed text.

	RichText is not supported on Android < 3.

	Selection operations and [insertAtCursor](#enyo.RichText::insertAtCursor)
	use the HTML Editing APIs.

	[HTML Editing APIs # Selection Reference](https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections)
*/
enyo.kind({
	name: "enyo.RichText",
	classes: "enyo-richtext enyo-selectable",
	published: {
		/**
			_allowHtml_ is enabled by default in RichText to take advantage of all the rich editing properties.
			However, this allows for **ANY** HTML to be inserted into the RichText, including _iframe_ and _script_ tags, which can be a secuity concern in some situations.
			If set to false, inserted HTML will be escaped.
		*/
		allowHtml: true,
		disabled: false,
		value: ""
	},
	//* Set to true to focus this control when it is rendered.
	defaultFocus: false,
	//* @protected
	kind: enyo.Input,
	tag: "div",
	attributes: {
		contenteditable: true,
	},
	handlers: {
		onfocus: "focusHandler",
		onblur: "blurHandler"
	},
	// simulate onchange event that inputs expose
	focusHandler: function() {
		this._value = this.getValue();
	},
	blurHandler: function() {
		if (this._value !== this.getValue()) {
			this.bubble("onchange");
		}
	},
	valueChanged: function() {
		if (this.hasFocus()) {
			this.selectAll();
			this.insertAtCursor(this.value);
		} else {
			this.setPropertyValue("content", this.value, "contentChanged");
		}
	},
	//* @public
	getValue: function() {
		if (this.hasNode()) {
			return this.node.innerHTML;
		}
	},
	//* Returns true if the RichText is focused.
	hasFocus: function() {
		if (this.hasNode()) {
			return document.activeElement === this.node;
		}
	},
	/**
		Returns the selection object.
	*/
	getSelection: function() {
		if (this.hasFocus()) {
			return window.getSelection();
		}
	},
	removeSelection: function(inStart) {
		var s = this.getSelection();
		if (s) {
			s[inStart ? "collapseToStart" : "collapseToEnd"]();
		}
	},
	modifySelection: function(inType, inDirection, inAmount) {
		var s = this.getSelection();
		if (s) {
			s.modify(inType || "move", inDirection, inAmount);
		}
	},
	//* Moves the cursor according to the Editing API.
	moveCursor: function(inDirection, inAmount) {
		this.modifySelection("move", inDirection, inAmount);
	},
	moveCursorToEnd: function() {
		this.moveCursor("forward", "documentboundary");
	},
	moveCursorToStart: function() {
		this.moveCursor("backward", "documentboundary");
	},
	selectAll: function() {
		if (this.hasFocus()) {
			document.execCommand("selectAll");
		}
	},
	//* Inserts HTML at the cursor position.  HTML is escaped unless the
	//* _allowHTML_ property is true.
	insertAtCursor: function(inValue) {
		if (this.hasFocus()) {
			var v = this.allowHtml ? inValue : enyo.Control.escapeHtml(inValue).replace(/\n/g, "
");
			document.execCommand("insertHTML", false, v);
		}
	}
});
<commit_msg>Remove trailing comma from enyo.RichText<commit_after>/**
	A multi-line text input that supports rich formatting, such as bold, italics,
	and underlining.

	Use the _value_ property to get or set the displayed text.

	RichText is not supported on Android < 3.

	Selection operations and [insertAtCursor](#enyo.RichText::insertAtCursor)
	use the HTML Editing APIs.

	[HTML Editing APIs # Selection Reference](https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections)
*/
enyo.kind({
	name: "enyo.RichText",
	classes: "enyo-richtext enyo-selectable",
	published: {
		/**
			_allowHtml_ is enabled by default in RichText to take advantage of all the rich editing properties.
			However, this allows for **ANY** HTML to be inserted into the RichText, including _iframe_ and _script_ tags, which can be a secuity concern in some situations.
			If set to false, inserted HTML will be escaped.
		*/
		allowHtml: true,
		disabled: false,
		value: ""
	},
	//* Set to true to focus this control when it is rendered.
	defaultFocus: false,
	//* @protected
	kind: enyo.Input,
	tag: "div",
	attributes: {
		contenteditable: true
	},
	handlers: {
		onfocus: "focusHandler",
		onblur: "blurHandler"
	},
	// simulate onchange event that inputs expose
	focusHandler: function() {
		this._value = this.getValue();
	},
	blurHandler: function() {
		if (this._value !== this.getValue()) {
			this.bubble("onchange");
		}
	},
	valueChanged: function() {
		if (this.hasFocus()) {
			this.selectAll();
			this.insertAtCursor(this.value);
		} else {
			this.setPropertyValue("content", this.value, "contentChanged");
		}
	},
	//* @public
	getValue: function() {
		if (this.hasNode()) {
			return this.node.innerHTML;
		}
	},
	//* Returns true if the RichText is focused.
	hasFocus: function() {
		if (this.hasNode()) {
			return document.activeElement === this.node;
		}
	},
	/**
		Returns the selection object.
	*/
	getSelection: function() {
		if (this.hasFocus()) {
			return window.getSelection();
		}
	},
	removeSelection: function(inStart) {
		var s = this.getSelection();
		if (s) {
			s[inStart ? "collapseToStart" : "collapseToEnd"]();
		}
	},
	modifySelection: function(inType, inDirection, inAmount) {
		var s = this.getSelection();
		if (s) {
			s.modify(inType || "move", inDirection, inAmount);
		}
	},
	//* Moves the cursor according to the Editing API.
	moveCursor: function(inDirection, inAmount) {
		this.modifySelection("move", inDirection, inAmount);
	},
	moveCursorToEnd: function() {
		this.moveCursor("forward", "documentboundary");
	},
	moveCursorToStart: function() {
		this.moveCursor("backward", "documentboundary");
	},
	selectAll: function() {
		if (this.hasFocus()) {
			document.execCommand("selectAll");
		}
	},
	//* Inserts HTML at the cursor position.  HTML is escaped unless the
	//* _allowHTML_ property is true.
	insertAtCursor: function(inValue) {
		if (this.hasFocus()) {
			var v = this.allowHtml ? inValue : enyo.Control.escapeHtml(inValue).replace(/\n/g, "
");
			document.execCommand("insertHTML", false, v);
		}
	}
});
<|endoftext|>


<commit_before>// @flow

import * as c from '@frogpond/colors'

export type ViewType =
	| {
			type: 'view',
			view: string,
			title: string,
			icon: string,
			foreground: 'light' | 'dark',
			tint: string,
			gradient?: [string, string],
	  }
	| {
			type: 'url',
			view: string,
			url: string,
			title: string,
			icon: string,
			foreground: 'light' | 'dark',
			tint: string,
			gradient?: [string, string],
	  }
	| {
			type: 'browser-url',
			view: string,
			url: string,
			title: string,
			icon: string,
			foreground: 'light' | 'dark',
			tint: string,
			gradient?: [string, string],
	  }

export const allViews: Array<ViewType> = [
	{
		type: 'view',
		view: 'MenusView',
		title: 'Menus',
		icon: 'bowl',
		foreground: 'light',
		tint: c.emerald,
		gradient: c.grassToLime,
	},
	{
		type: 'view',
		view: 'SISView',
		title: 'SIS',
		icon: 'fingerprint',
		foreground: 'light',
		tint: c.goldenrod,
		gradient: c.yellowToGoldDark,
	},
	{
		type: 'view',
		view: 'BuildingHoursView',
		title: 'Building Hours',
		icon: 'clock',
		foreground: 'light',
		tint: c.wave,
		gradient: c.lightBlueToBlueDark,
	},
	{
		type: 'view',
		view: 'CalendarView',
		title: 'Calendar',
		icon: 'calendar',
		foreground: 'light',
		tint: c.coolPurple,
		gradient: c.magentaToPurple,
	},
	{
		type: 'url',
		url: 'https://www.stolaf.edu/personal/index.cfm',
		view: 'DirectoryView',
		title: 'Directory',
		icon: 'v-card',
		foreground: 'light',
		tint: c.indianRed,
		gradient: c.redToPurple,
	},
	{
		type: 'view',
		view: 'StreamingView',
		title: 'Streaming Media',
		icon: 'video',
		foreground: 'light',
		tint: c.denim,
		gradient: c.lightBlueToBlueLight,
	},
	{
		type: 'view',
		view: 'NewsView',
		title: 'News',
		icon: 'news',
		foreground: 'light',
		tint: c.eggplant,
		gradient: c.purpleToIndigo,
	},
	{
		type: 'url',
		url: 'https://www.myatlascms.com/map/index.php?id=294',
		view: 'MapView',
		title: 'Campus Map',
		icon: 'map',
		foreground: 'light',
		tint: c.coffee,
		gradient: c.navyToNavy,
	},
	{
		type: 'view',
		view: 'ContactsView',
		title: 'Important Contacts',
		icon: 'phone',
		foreground: 'light',
		tint: c.crimson,
		gradient: c.orangeToRed,
	},
	{
		type: 'view',
		view: 'TransportationView',
		title: 'Transportation',
		icon: 'address',
		foreground: 'light',
		tint: c.cardTable,
		gradient: c.grayToDarkGray,
	},
	{
		type: 'view',
		view: 'DictionaryView',
		title: 'Campus Dictionary',
		icon: 'open-book',
		foreground: 'light',
		tint: c.olive,
		gradient: c.pinkToHotpink,
	},
	{
		type: 'view',
		view: 'StudentOrgsView',
		title: 'Student Orgs',
		icon: 'globe',
		foreground: 'light',
		tint: c.wave,
		gradient: c.darkBlueToIndigo,
	},
	{
		type: 'url',
		url: 'https://moodle.stolaf.edu/',
		view: 'MoodleView',
		title: 'Moodle',
		icon: 'graduation-cap',
		foreground: 'light',
		tint: c.cantaloupe,
		gradient: c.yellowToGoldLight,
	},
	{
		type: 'view',
		view: 'HelpView',
		title: 'Report A Problem',
		icon: 'help',
		foreground: 'light',
		tint: c.lavender,
		gradient: c.seafoamToGrass,
	},
	{
		type: 'view',
		view: 'PrintJobsView',
		title: 'stoPrint',
		icon: 'print',
		foreground: 'light',
		tint: c.periwinkle,
		gradient: c.tealToSeafoam,
	},
	{
		type: 'browser-url',
		url: 'https://wp.stolaf.edu/safety-committee/report-a-safety-concern-2/',
		view: 'SafetyView',
		title: 'Safety Concerns',
		icon: 'warning',
		foreground: 'dark',
		tint: c.periwinkle,
		gradient: c.yellowToGoldMid,
	},
]

export const allViewNames: Array<string> = allViews.map(v => v.view)
<commit_msg>update Safety Committee url<commit_after>// @flow

import * as c from '@frogpond/colors'

export type ViewType =
	| {
			type: 'view',
			view: string,
			title: string,
			icon: string,
			foreground: 'light' | 'dark',
			tint: string,
			gradient?: [string, string],
	  }
	| {
			type: 'url',
			view: string,
			url: string,
			title: string,
			icon: string,
			foreground: 'light' | 'dark',
			tint: string,
			gradient?: [string, string],
	  }
	| {
			type: 'browser-url',
			view: string,
			url: string,
			title: string,
			icon: string,
			foreground: 'light' | 'dark',
			tint: string,
			gradient?: [string, string],
	  }

export const allViews: Array<ViewType> = [
	{
		type: 'view',
		view: 'MenusView',
		title: 'Menus',
		icon: 'bowl',
		foreground: 'light',
		tint: c.emerald,
		gradient: c.grassToLime,
	},
	{
		type: 'view',
		view: 'SISView',
		title: 'SIS',
		icon: 'fingerprint',
		foreground: 'light',
		tint: c.goldenrod,
		gradient: c.yellowToGoldDark,
	},
	{
		type: 'view',
		view: 'BuildingHoursView',
		title: 'Building Hours',
		icon: 'clock',
		foreground: 'light',
		tint: c.wave,
		gradient: c.lightBlueToBlueDark,
	},
	{
		type: 'view',
		view: 'CalendarView',
		title: 'Calendar',
		icon: 'calendar',
		foreground: 'light',
		tint: c.coolPurple,
		gradient: c.magentaToPurple,
	},
	{
		type: 'url',
		url: 'https://www.stolaf.edu/personal/index.cfm',
		view: 'DirectoryView',
		title: 'Directory',
		icon: 'v-card',
		foreground: 'light',
		tint: c.indianRed,
		gradient: c.redToPurple,
	},
	{
		type: 'view',
		view: 'StreamingView',
		title: 'Streaming Media',
		icon: 'video',
		foreground: 'light',
		tint: c.denim,
		gradient: c.lightBlueToBlueLight,
	},
	{
		type: 'view',
		view: 'NewsView',
		title: 'News',
		icon: 'news',
		foreground: 'light',
		tint: c.eggplant,
		gradient: c.purpleToIndigo,
	},
	{
		type: 'url',
		url: 'https://www.myatlascms.com/map/index.php?id=294',
		view: 'MapView',
		title: 'Campus Map',
		icon: 'map',
		foreground: 'light',
		tint: c.coffee,
		gradient: c.navyToNavy,
	},
	{
		type: 'view',
		view: 'ContactsView',
		title: 'Important Contacts',
		icon: 'phone',
		foreground: 'light',
		tint: c.crimson,
		gradient: c.orangeToRed,
	},
	{
		type: 'view',
		view: 'TransportationView',
		title: 'Transportation',
		icon: 'address',
		foreground: 'light',
		tint: c.cardTable,
		gradient: c.grayToDarkGray,
	},
	{
		type: 'view',
		view: 'DictionaryView',
		title: 'Campus Dictionary',
		icon: 'open-book',
		foreground: 'light',
		tint: c.olive,
		gradient: c.pinkToHotpink,
	},
	{
		type: 'view',
		view: 'StudentOrgsView',
		title: 'Student Orgs',
		icon: 'globe',
		foreground: 'light',
		tint: c.wave,
		gradient: c.darkBlueToIndigo,
	},
	{
		type: 'url',
		url: 'https://moodle.stolaf.edu/',
		view: 'MoodleView',
		title: 'Moodle',
		icon: 'graduation-cap',
		foreground: 'light',
		tint: c.cantaloupe,
		gradient: c.yellowToGoldLight,
	},
	{
		type: 'view',
		view: 'HelpView',
		title: 'Report A Problem',
		icon: 'help',
		foreground: 'light',
		tint: c.lavender,
		gradient: c.seafoamToGrass,
	},
	{
		type: 'view',
		view: 'PrintJobsView',
		title: 'stoPrint',
		icon: 'print',
		foreground: 'light',
		tint: c.periwinkle,
		gradient: c.tealToSeafoam,
	},
	{
		type: 'browser-url',
		url: 'https://wp.stolaf.edu/safety-committee/report/',
		view: 'SafetyView',
		title: 'Safety Concerns',
		icon: 'warning',
		foreground: 'dark',
		tint: c.periwinkle,
		gradient: c.yellowToGoldMid,
	},
]

export const allViewNames: Array<string> = allViews.map(v => v.view)
<|endoftext|>


<commit_before>import React from 'react';

import { expect } from 'chai';
import { describe, beforeEach, it } from '@bigtest/mocha';
import { mount } from '../../../tests/helpers';

import ModalFooter from '../ModalFooter';
import Button from '../../Button';
import ModalFooterInteractor from './interactor';

describe('ModalFooter', () => {
  const modalFooter = new ModalFooterInteractor();
  const primaryButtonLabel = 'Primary Button';
  const primaryButtonId = 'modalFooterPrimaryButton';
  const secondaryButtonLabel = 'Secondary Button';
  const secondaryButtonId = 'modalFooterSecondaryButton';

  beforeEach(async () => {
    await mount(
      <ModalFooter>
        <Button id={primaryButtonId} buttonStyle="primary">
          {primaryButtonLabel}
        </Button>
        <Button id={secondaryButtonId}>
          {secondaryButtonLabel}
        </Button>
      </ModalFooter>
    );
  });

  it('renders a primary button', () => {
    expect(modalFooter.primaryButton.rendersPrimary).to.be.true;
  });

  it('renders a default button', () => {
    expect(modalFooter.secondaryButton.rendersDefault).to.be.true;
  });

  it(`renders a button with a label of "${secondaryButtonLabel}"`, () => {
    expect(modalFooter.secondaryButton.label).to.equal(secondaryButtonLabel);
  });

  it(`renders a button with a label of "${primaryButtonLabel}"`, () => {
    expect(modalFooter.primaryButton.label).to.equal(primaryButtonLabel);
  });
});
<commit_msg>increase ModalFooter code coverage (#1029)<commit_after>import React from 'react';

import { expect } from 'chai';
import { describe, beforeEach, it } from '@bigtest/mocha';
import { mount } from '../../../tests/helpers';

import ModalFooter from '../ModalFooter';
import Button from '../../Button';
import ModalFooterInteractor from './interactor';

describe('ModalFooter', () => {
  const modalFooter = new ModalFooterInteractor();
  const primaryButtonLabel = 'Primary Button';
  const primaryButtonId = 'modalFooterPrimaryButton';
  const secondaryButtonLabel = 'Secondary Button';
  const secondaryButtonId = 'modalFooterSecondaryButton';

  describe('when buttons are passed as children', () => {
    beforeEach(async () => {
      await mount(
        <ModalFooter>
          <Button id={primaryButtonId} buttonStyle="primary">
            {primaryButtonLabel}
          </Button>
          <Button id={secondaryButtonId}>
            {secondaryButtonLabel}
          </Button>
        </ModalFooter>
      );
    });

    it('renders a primary button', () => {
      expect(modalFooter.primaryButton.rendersPrimary).to.be.true;
    });

    it('renders a default button', () => {
      expect(modalFooter.secondaryButton.rendersDefault).to.be.true;
    });

    it(`renders a button with a label of "${secondaryButtonLabel}"`, () => {
      expect(modalFooter.secondaryButton.label).to.equal(secondaryButtonLabel);
    });

    it(`renders a button with a label of "${primaryButtonLabel}"`, () => {
      expect(modalFooter.primaryButton.label).to.equal(primaryButtonLabel);
    });
  });

  describe('when buttons are configured using props', () => {
    beforeEach(async () => {
      await mount(
        <ModalFooter
          primaryButton={{
            id: primaryButtonId,
            label: primaryButtonLabel
          }}
          secondaryButton={{
            id: secondaryButtonId,
            label: secondaryButtonLabel
          }}
        />
      );
    });

    it('renders a primary button', () => {
      expect(modalFooter.primaryButton.rendersPrimary).to.be.true;
    });

    it('renders a default button', () => {
      expect(modalFooter.secondaryButton.rendersDefault).to.be.true;
    });

    it(`renders a button with a label of "${secondaryButtonLabel}"`, () => {
      expect(modalFooter.secondaryButton.label).to.equal(secondaryButtonLabel);
    });

    it(`renders a button with a label of "${primaryButtonLabel}"`, () => {
      expect(modalFooter.primaryButton.label).to.equal(primaryButtonLabel);
    });
  });
});
<|endoftext|>


<commit_before>const request = require('request');
const url = require('url');
const Constants = require('./Constants');
const Encode = require('./util/Encode');
const Video = require('./structures/Video');
const Playlist = require('./structures/Playlist');

/**
 * The YouTube API module
 */

class YouTube {
    /**
     * Create the YouTube API caller
     * @param {String} key your youtube data api v3 key
     */
    constructor(key) {
        /**
         * Your YouTube Data API key
         * @type {?String}
         */
        this.key = key;
    }

    /**
     * Make a request to the YouTube API
     * @param {String} endpoint the endpoint of the api
     * @param {Object} uriOptions the uri options to send to the api
     * @returns {Promise<Object, Error>}
     */
    request(endpoint, uriOptions) {
        return new Promise((resolve, reject) => {
            request(`https://www.googleapis.com/youtube/v3/${endpoint}?${Encode(uriOptions)}`, (err, resp, body) => {
                if (err) return reject(`An error occured: ${err}`);
                if (resp.statusCode !== 200) return reject(JSON.parse(body));
                return resolve(JSON.parse(body));
            });
        });
    }

    /**
     * Get a video by id
     * @param {String} videoId the video id
     * @returns {Promise<Array<Video>, Error>}
     * @example
     * Api.videoById('3odIdmuFfEY')
     *  .then(results => {
     *    console.log(`The videos' title is ${resolts[0].title}`);
     *  })
     *  .catch(console.log);
     */
    videoById(videoId) {
        return new Promise((resolve, reject) => {
            this.request('videos', {'id': videoId, 'key': this.key, 'part': Constants.PARTS.VideoByID})
                .then(result => {
                    return resolve(result.items.map(item => {
                        return new Video(this, item);
                    }));
                })
                .catch(reject);
        });
    }

    /**
     * Get a video by URL or ID
     * @param {String} videoUrl the video URL/ID
     * @returns {Promise<Array<Video>, Error>}
     * @example
     * Api.videoByUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
     *  .then(results => {
     *    console.log(`The videos' title is ${resolts[0].title}`);
     *  })
     *  .catch(console.log);
     */
    videoByUrl(videoUrl) {
        const parsed = url.parse(videoUrl, true);
        let id = parsed.query.v;
        if (parsed.hostname === 'youtu.be' || !id) {
            const s = parsed.pathname.split('/');
            id = s[s.length - 1];
        }
        if (!id) throw new Error(`No video ID found in URL: ${videoUrl}`);
        return this.videoById(id);
    }

    /**
     * Get a playlist by id
     * @param {String} playlistId the playlist id
     * @returns {Promise<Array<Playlist>, Error>}
     * @example
     * Api.playlistById('PL2BN1Zd8U_MsyMeK8r9Vdv1lnQGtoJaSa')
     *  .then(results => {
     *    console.log(`The playlists' title is ${resolts[0].title}`);
     *  })
     *  .catch(console.log);
     */
    playlistById(playlistId) {
        return new Promise((resolve, reject) => {
            this.request('playlists', {'id': playlistId, 'key': this.key, 'part': Constants.PARTS.Playlist})
                .then(result => {
                    return resolve(result.items.map(item => {
                        return new Playlist(this, item);
                    }));
                })
                .catch(reject);
        });
    }

    /**
     * Get a video by name
     * @param {String} query the query to search
     * @param {Number} [results = 5] the max amount of results
     * @returns {Promise<Array<Playlist>, Error>}
     * @example
     * Api.search('Centuries')
     *  .then(results => {
     *    console.log(`I got ${results.length} videos`);
     *  })
     *  .catch(console.log);
     */
    search(query, limit = 5) {
        return new Promise((resolve, reject) => {
            this.request('search', {'q': query, 'maxResults': limit, 'key': this.key, 'part': Constants.PARTS.Search})
                .then(result => {
                    const items = result.items;
                    return resolve(result.items.map(item => {
                        return new Video(this, item);
                    }));
                })
                .catch(reject);
        });
    }
}

module.exports = YouTube;

/*
    search(query, results = 5) {
        return new Promise((resolve, reject) => {
            sendRequest('search', {'q': query, 'maxResults': results, 'key': this.key, 'part': parts.search}).then(resolve).catch(reject);
        });
    }

    getPlaylistItems(playlistId) {
        return new Promise((resolve, reject) => {
            sendRequest('playlistItems', {'playlistId': playlistId, 'key': this.key, 'part': parts.playlistItems}).then(resolve).catch(reject);
        });
    }
*/
<commit_msg>Make videoByUrl return rejected Promise instead of throwing<commit_after>const request = require('request');
const url = require('url');
const Constants = require('./Constants');
const Encode = require('./util/Encode');
const Video = require('./structures/Video');
const Playlist = require('./structures/Playlist');

/**
 * The YouTube API module
 */

class YouTube {
    /**
     * Create the YouTube API caller
     * @param {String} key your youtube data api v3 key
     */
    constructor(key) {
        /**
         * Your YouTube Data API key
         * @type {?String}
         */
        this.key = key;
    }

    /**
     * Make a request to the YouTube API
     * @param {String} endpoint the endpoint of the api
     * @param {Object} uriOptions the uri options to send to the api
     * @returns {Promise<Object, Error>}
     */
    request(endpoint, uriOptions) {
        return new Promise((resolve, reject) => {
            request(`https://www.googleapis.com/youtube/v3/${endpoint}?${Encode(uriOptions)}`, (err, resp, body) => {
                if (err) return reject(`An error occured: ${err}`);
                if (resp.statusCode !== 200) return reject(JSON.parse(body));
                return resolve(JSON.parse(body));
            });
        });
    }

    /**
     * Get a video by id
     * @param {String} videoId the video id
     * @returns {Promise<Array<Video>, Error>}
     * @example
     * Api.videoById('3odIdmuFfEY')
     *  .then(results => {
     *    console.log(`The videos' title is ${resolts[0].title}`);
     *  })
     *  .catch(console.log);
     */
    videoById(videoId) {
        return new Promise((resolve, reject) => {
            this.request('videos', {'id': videoId, 'key': this.key, 'part': Constants.PARTS.VideoByID})
                .then(result => {
                    return resolve(result.items.map(item => {
                        return new Video(this, item);
                    }));
                })
                .catch(reject);
        });
    }

    /**
     * Get a video by URL or ID
     * @param {String} videoUrl the video URL/ID
     * @returns {Promise<Array<Video>, Error>}
     * @example
     * Api.videoByUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
     *  .then(results => {
     *    console.log(`The videos' title is ${resolts[0].title}`);
     *  })
     *  .catch(console.log);
     */
    videoByUrl(videoUrl) {
        const parsed = url.parse(videoUrl, true);
        let id = parsed.query.v;
        if (parsed.hostname === 'youtu.be' || !id) {
            const s = parsed.pathname.split('/');
            id = s[s.length - 1];
        }
        if (!id) return Promise.reject(new Error(`No video ID found in URL: ${videoUrl}`));
        return this.videoById(id);
    }

    /**
     * Get a playlist by id
     * @param {String} playlistId the playlist id
     * @returns {Promise<Array<Playlist>, Error>}
     * @example
     * Api.playlistById('PL2BN1Zd8U_MsyMeK8r9Vdv1lnQGtoJaSa')
     *  .then(results => {
     *    console.log(`The playlists' title is ${resolts[0].title}`);
     *  })
     *  .catch(console.log);
     */
    playlistById(playlistId) {
        return new Promise((resolve, reject) => {
            this.request('playlists', {'id': playlistId, 'key': this.key, 'part': Constants.PARTS.Playlist})
                .then(result => {
                    return resolve(result.items.map(item => {
                        return new Playlist(this, item);
                    }));
                })
                .catch(reject);
        });
    }

    /**
     * Get a video by name
     * @param {String} query the query to search
     * @param {Number} [results = 5] the max amount of results
     * @returns {Promise<Array<Playlist>, Error>}
     * @example
     * Api.search('Centuries')
     *  .then(results => {
     *    console.log(`I got ${results.length} videos`);
     *  })
     *  .catch(console.log);
     */
    search(query, limit = 5) {
        return new Promise((resolve, reject) => {
            this.request('search', {'q': query, 'maxResults': limit, 'key': this.key, 'part': Constants.PARTS.Search})
                .then(result => {
                    const items = result.items;
                    return resolve(result.items.map(item => {
                        return new Video(this, item);
                    }));
                })
                .catch(reject);
        });
    }
}

module.exports = YouTube;

/*
    search(query, results = 5) {
        return new Promise((resolve, reject) => {
            sendRequest('search', {'q': query, 'maxResults': results, 'key': this.key, 'part': parts.search}).then(resolve).catch(reject);
        });
    }

    getPlaylistItems(playlistId) {
        return new Promise((resolve, reject) => {
            sendRequest('playlistItems', {'playlistId': playlistId, 'key': this.key, 'part': parts.playlistItems}).then(resolve).catch(reject);
        });
    }
*/
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

import React from 'react';
import randomize from 'random-string';
import youtubePlayer from 'youtube-player';

/**
 * Create a new `YouTube` component.
 */

class YouTube extends React.Component {
  static propTypes = {
    // changing the url will cause a new player to be loaded
    url: React.PropTypes.string.isRequired,

    // custom ID for player element
    id: React.PropTypes.string,

    // custom class name for player element
    className: React.PropTypes.string,

    // https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player
    opts: React.PropTypes.object,

    // event subscriptions
    onReady: React.PropTypes.func,
    onError: React.PropTypes.func,
    onPlay: React.PropTypes.func,
    onPause: React.PropTypes.func,
    onEnd: React.PropTypes.func,
    onStateChange: React.PropTypes.func,
  };

  static defaultProps = {
    opts: {},
    onReady: () => {},
    onError: () => {},
    onPlay: () => {},
    onPause: () => {},
    onEnd: () => {},
    onStateChange: () => {},
  };

  /**
   * @param {Object} props
   */

  constructor(props) {
    super(props);

    this._containerId = props.id || randomize();
    this._internalPlayer = null;
  }

  componentDidMount() {
    // create player
    this._internalPlayer = youtubePlayer( this._containerId, this.props.opts );
    // attach event handlers
    this._internalPlayer.on( 'ready', this.props.onReady );
    this._internalPlayer.on( 'error', this.props.onError );
    this._internalPlayer.on( 'stateChange', ::this.onPlayerStateChange );
    // update video
    this.updateVideo();
  }

 componentDidUpdate(prevProps) {
    if (prevProps.url !== this.props.url) {
      this.updateVideo();
    }
    // check changes in other props?
  }

  componentWillUnmount() {
    // needed?
    this._internalPlayer.destroy();
  }

  /**
   * https://developers.google.com/youtube/iframe_api_reference#onStateChange
   *
   * @param {Object} event
   *   @param {Integer} data  - status change type
   *   @param {Object} target - actual YT player
   */

  onPlayerStateChange(event) {
    this.props.onStateChange(event);

    switch (event.data) {

    case window.YT.PlayerState.ENDED:
      this.props.onEnd(event);
      break;

    case window.YT.PlayerState.PLAYING:
      this.props.onPlay(event);
      break;

    case window.YT.PlayerState.PAUSED:
      this.props.onPause(event);
      break;

    default:
      return;
    }
  }

  updateVideo() {
    if (this.props.opts.playerVars !== undefined && this.props.opts.playerVars.autoplay === 1) {
      this._internalPlayer.loadVideoByUrl( this.props.url );
      return;
    }
    this._internalPlayer.cueVideoByUrl( this.props.url );
  }

  /**
   * @returns Object
   */

  render() {
    return (

    );
  }
}

/**
 * Expose `YouTube`
 */

export default YouTube;
<commit_msg>Moved the event handlers for `onReady` and `onError` to internal methods This allows users of the component to change the event handler.<commit_after>/**
 * Module dependencies
 */

import React from 'react';
import randomize from 'random-string';
import youtubePlayer from 'youtube-player';

/**
 * Create a new `YouTube` component.
 */

class YouTube extends React.Component {
  static propTypes = {
    // changing the url will cause a new player to be loaded
    url: React.PropTypes.string.isRequired,

    // custom ID for player element
    id: React.PropTypes.string,

    // custom class name for player element
    className: React.PropTypes.string,

    // https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player
    opts: React.PropTypes.object,

    // event subscriptions
    onReady: React.PropTypes.func,
    onError: React.PropTypes.func,
    onPlay: React.PropTypes.func,
    onPause: React.PropTypes.func,
    onEnd: React.PropTypes.func,
    onStateChange: React.PropTypes.func,
  };

  static defaultProps = {
    opts: {},
    onReady: () => {},
    onError: () => {},
    onPlay: () => {},
    onPause: () => {},
    onEnd: () => {},
    onStateChange: () => {},
  };

  /**
   * @param {Object} props
   */

  constructor(props) {
    super(props);

    this._containerId = props.id || randomize();
    this._internalPlayer = null;
  }

  componentDidMount() {
    // create player
    this._internalPlayer = youtubePlayer( this._containerId, this.props.opts );
    // attach event handlers
    this._internalPlayer.on( 'ready', ::this.onPlayerReady );
    this._internalPlayer.on( 'error', ::this.onPlayerError );
    this._internalPlayer.on( 'stateChange', ::this.onPlayerStateChange );
    // update video
    this.updateVideo();
  }

 componentDidUpdate(prevProps) {
    if (prevProps.url !== this.props.url) {
      this.updateVideo();
    }
    // check changes in other props?
  }

  componentWillUnmount() {
    // needed?
    this._internalPlayer.destroy();
  }

  /**
   * https://developers.google.com/youtube/iframe_api_reference#onReady
   *
   * @param {Object} event
   *   @param {Object} target - player object
   */

  onPlayerReady(event) {
    this.props.onReady(event);
  }

  /**
   * https://developers.google.com/youtube/iframe_api_reference#onError
   *
   * @param {Object} event
   *   @param {Integer} data  - error type
   *   @param {Object} target - player object
   */

  onPlayerError(event) {
    this.props.onError(event);
  }

  /**
   * https://developers.google.com/youtube/iframe_api_reference#onStateChange
   *
   * @param {Object} event
   *   @param {Integer} data  - status change type
   *   @param {Object} target - actual YT player
   */

  onPlayerStateChange(event) {
    this.props.onStateChange(event);

    switch (event.data) {

    case window.YT.PlayerState.ENDED:
      this.props.onEnd(event);
      break;

    case window.YT.PlayerState.PLAYING:
      this.props.onPlay(event);
      break;

    case window.YT.PlayerState.PAUSED:
      this.props.onPause(event);
      break;

    default:
      return;
    }
  }

  updateVideo() {
    if (this.props.opts.playerVars !== undefined && this.props.opts.playerVars.autoplay === 1) {
      this._internalPlayer.loadVideoByUrl( this.props.url );
      return;
    }
    this._internalPlayer.cueVideoByUrl( this.props.url );
  }

  /**
   * @returns Object
   */

  render() {
    return (

    );
  }
}

/**
 * Expose `YouTube`
 */

export default YouTube;
<|endoftext|>


<commit_before>
"use strict";

import {Monad} from './classes/Monad';
import {RootController} from './controllers/RootController';
import {HomeController} from './controllers/HomeController';
import {LoginController} from './controllers/LoginController';
import {Navigation} from './services/Navigation';
import {Authentication} from './services/Authentication';
import {Language} from './services/Language';
import {default as normalizePost} from './helpers/post';
import {default as Directives} from './directives/angular';

function config($routeProvider, $locationProvider) {
    $locationProvider.html5Mode(false);
    $routeProvider.
        when('/', {
            controller: 'moController'
        }).
        when('/:language/', {
            controller: HomeController,
            controllerAs: 'home',
            templateUrl: '../monad/templates/home.html'
        }).
        when('/:language/login/', {
            controller: LoginController,
            controllerAs: 'login',
            templateUrl: '../monad/templates/login.html'
        });
};

function run(gettextCatalog, languages, $http, $rootScope, $route, $cacheFactory) {
    normalizePost($http);
    gettextCatalog.setCurrentLanguage(languages[0]);
    gettextCatalog.loadRemote('../js/i18n/' + languages[0] + '.json');
};

angular.module('monad.core', ['ng', 'ngRoute', 'gettext', 'ngSanitize', 'ui.bootstrap', Directives])
    .config(['$routeProvider', '$locationProvider', config])
    .run(['gettextCatalog', 'languages', '$http', '$rootScope', '$route', '$cacheFactory', run])
    .controller('moController', RootController)
    .service('moNavigation', Navigation)
    .service('Authentication', Authentication)
    .service('moLanguage', Language)
    .value('title', 'Default generic administrator')
    .constant('languages', ['en', 'nl'])
    .value('theme', '../monad/default.css')
    ;

let monad = new Monad();
window.monad = monad;

let bootstrap = angular.bootstrap;

angular.bootstrap = (...args) => {
    monad.bootstrap();
    bootstrap(...args);
};

export default monad;

<commit_msg>correctly load monad texts too, and set to debug just in case<commit_after>
"use strict";

import {Monad} from './classes/Monad';
import {RootController} from './controllers/RootController';
import {HomeController} from './controllers/HomeController';
import {LoginController} from './controllers/LoginController';
import {Navigation} from './services/Navigation';
import {Authentication} from './services/Authentication';
import {Language} from './services/Language';
import {default as normalizePost} from './helpers/post';
import {default as Directives} from './directives/angular';

function config($routeProvider, $locationProvider) {
    $locationProvider.html5Mode(false);
    $routeProvider.
        when('/', {
            controller: 'moController'
        }).
        when('/:language/', {
            controller: HomeController,
            controllerAs: 'home',
            templateUrl: '../monad/templates/home.html'
        }).
        when('/:language/login/', {
            controller: LoginController,
            controllerAs: 'login',
            templateUrl: '../monad/templates/login.html'
        });
};

function run(gettextCatalog, languages, $http, $rootScope, $route, $cacheFactory) {
    normalizePost($http);
    gettextCatalog.debug = true;
    gettextCatalog.setCurrentLanguage(languages[0]);
    gettextCatalog.loadRemote('../monad/i18n/' + languages[0] + '.json');
    gettextCatalog.loadRemote('../js/i18n/' + languages[0] + '.json');
};

angular.module('monad.core', ['ng', 'ngRoute', 'gettext', 'ngSanitize', 'ui.bootstrap', Directives])
    .config(['$routeProvider', '$locationProvider', config])
    .run(['gettextCatalog', 'languages', '$http', '$rootScope', '$route', '$cacheFactory', run])
    .controller('moController', RootController)
    .service('moNavigation', Navigation)
    .service('Authentication', Authentication)
    .service('moLanguage', Language)
    .value('title', 'Default generic administrator')
    .constant('languages', ['en', 'nl'])
    .value('theme', '../monad/default.css')
    ;

let monad = new Monad();
window.monad = monad;

let bootstrap = angular.bootstrap;

angular.bootstrap = (...args) => {
    monad.bootstrap();
    bootstrap(...args);
};

export default monad;

<|endoftext|>


<commit_before>'use strict';

describe('DateRange', function() {
  var clock, dateRange;

  beforeEach(function() {
    clock = Clock();
    spyOn(clock, 'currentDate').and.returnValue("2014-11-11");
    dateRange = DateRange(clock, dateManipulations);
  });

  describe('on creation', function() {
    it('should show the current week', function() {
      expectThatDateRange(dateRange).startsOn("2014-11-10").andEndsOn("2014-11-16");
    });
  });

  describe('when a new period is selected', function() {
    it('should show the current month in case of a month', function() {
      dateRange.useMonth();

      expectThatDateRange(dateRange).startsOn("2014-11-01").andEndsOn("2014-11-30");
    });

    it('should show the current year in case of a year', function() {
      dateRange.useYear();

      expectThatDateRange(dateRange).startsOn("2014-01-01").andEndsOn("2014-12-31");
    });

    it('should show the current week in case of a week', function() {
      dateRange.useYear();

      dateRange.useWeek();

      expectThatDateRange(dateRange).startsOn("2014-11-10").andEndsOn("2014-11-16");
    });
  });

  describe('when moving to the next period', function() {
    it('should show the next week in case of a week period', function() {
      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2014-11-17").andEndsOn("2014-11-23");
    });

    it('should show the next month in case of a month period', function() {
      dateRange.useMonth();

      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2014-12-01").andEndsOn("2014-12-31");
    });

    it('should show the next year in case of a year period', function() {
      dateRange.useYear();

      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2015-01-01").andEndsOn("2015-12-31");
    });
  });

  describe('when moving two periods ahead', function() {
    it('should show the week after the next week in case of a week period', function() {
      dateRange.next();
      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2014-11-24").andEndsOn("2014-11-30");
    });
  });

  describe('when moving to the previous period', function() {
    it('should show the previous week in case of a week period', function() {
      dateRange.previous();

      expectThatDateRange(dateRange).startsOn("2014-11-03").andEndsOn("2014-11-09");
    });

    it('should show the previous month in case of a month period', function() {
      dateRange.useMonth();

      dateRange.previous();

      expectThatDateRange(dateRange).startsOn("2014-10-01").andEndsOn("2014-10-31");
    });

    it('should show the previous year in case of a year period', function() {
      dateRange.useYear();

      dateRange.previous();

      expectThatDateRange(dateRange).startsOn("2013-01-01").andEndsOn("2013-12-31");
    });
  });

  function expectThatDateRange(dateRange) {
    return {
      startsOn: function(startDate) {
        return {
          andEndsOn: function(endDate) {
            expect(dateRange.startDate()).toEqual(moment(startDate).toDate());
            expect(dateRange.endDate()).toEqual(moment(endDate).toDate());
          }
        };
      }
    };
  }
});<commit_msg>Modified tests descriptions to better express their intents<commit_after>'use strict';

describe('DateRange', function() {
  var clock, dateRange;

  beforeEach(function() {
    clock = Clock();
    spyOn(clock, 'currentDate').and.returnValue("2014-11-11");
    dateRange = DateRange(clock, dateManipulations);
  });

  describe('on creation', function() {
    it('should contain the current week', function() {
      expectThatDateRange(dateRange).startsOn("2014-11-10").andEndsOn("2014-11-16");
    });
  });

  describe('when a new period is selected', function() {
    it('should contain the current month in case of a month', function() {
      dateRange.useMonth();

      expectThatDateRange(dateRange).startsOn("2014-11-01").andEndsOn("2014-11-30");
    });

    it('should contain the current year in case of a year', function() {
      dateRange.useYear();

      expectThatDateRange(dateRange).startsOn("2014-01-01").andEndsOn("2014-12-31");
    });

    it('should contain the current week in case of a week', function() {
      dateRange.useYear();

      dateRange.useWeek();

      expectThatDateRange(dateRange).startsOn("2014-11-10").andEndsOn("2014-11-16");
    });
  });

  describe('when moving to the next period', function() {
    it('should contain the next week in case of a week period', function() {
      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2014-11-17").andEndsOn("2014-11-23");
    });

    it('should contain the next month in case of a month period', function() {
      dateRange.useMonth();

      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2014-12-01").andEndsOn("2014-12-31");
    });

    it('should contain the next year in case of a year period', function() {
      dateRange.useYear();

      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2015-01-01").andEndsOn("2015-12-31");
    });
  });

  describe('when moving two periods ahead', function() {
    it('should contain the week after the next week in case of a week period', function() {
      dateRange.next();
      dateRange.next();

      expectThatDateRange(dateRange).startsOn("2014-11-24").andEndsOn("2014-11-30");
    });
  });

  describe('when moving to the previous period', function() {
    it('should contain the previous week in case of a week period', function() {
      dateRange.previous();

      expectThatDateRange(dateRange).startsOn("2014-11-03").andEndsOn("2014-11-09");
    });

    it('should contain the previous month in case of a month period', function() {
      dateRange.useMonth();

      dateRange.previous();

      expectThatDateRange(dateRange).startsOn("2014-10-01").andEndsOn("2014-10-31");
    });

    it('should contain the previous year in case of a year period', function() {
      dateRange.useYear();

      dateRange.previous();

      expectThatDateRange(dateRange).startsOn("2013-01-01").andEndsOn("2013-12-31");
    });
  });

  function expectThatDateRange(dateRange) {
    return {
      startsOn: function(startDate) {
        return {
          andEndsOn: function(endDate) {
            expect(dateRange.startDate()).toEqual(moment(startDate).toDate());
            expect(dateRange.endDate()).toEqual(moment(endDate).toDate());
          }
        };
      }
    };
  }
});<|endoftext|>


<commit_before>function NativePromiseWrapper(resolve, reject) {
  return new window.Promise(resolve, reject);
}

function InboxAPI(optionsOrAPIUrl, optionalPromiseConstructor) {
  var options;

  if (typeof optionsOrAPIUrl === 'object') {
    options = optionsOrAPIUrl;
  } else {
    options = {
      url: optionsOrAPIUrl,
      promise: optionsOrPromiseConstructor || window.Promise
    };
  }

  if (options.promise == null) {
    throw new TypeError("Unable to construct 'InboxAPI': missing option `promise`, " +
                        "or no native Promise available");
  } else if (typeof options.promise !== 'function') {
    throw new TypeError("Unable to construct 'InboxAPI': option `promise` must be a " +
                        "function which returns an ECMAScript6-compatible Promise");
  }

  if (typeof options.url == null) {
    throw new TypeError("Unable to construct 'InboxAPI': missing option `url`");
  } else if (typeof options.url !== 'string') {
    throw new TypeError("Unable to construct 'InboxAPI': option `url` must be a string");
  }

  if (options.promise === window.Promise) {
    options.promise = NativePromiseWrapper;
  }

  if (!(this instanceof Inbox)) {
    return new Inbox(options);
  }

  options._cache = {};

  this._ = options;
  DefineProperty(this, '_', INVISIBLE);
}
<commit_msg>fix(api.js): don't treat 'null' as an object<commit_after>function NativePromiseWrapper(resolve, reject) {
  return new window.Promise(resolve, reject);
}

function InboxAPI(optionsOrAPIUrl, optionalPromiseConstructor) {
  var options;

  if (optionsOrAPIUrl && typeof optionsOrAPIUrl === 'object') {
    options = optionsOrAPIUrl;
  } else {
    options = {
      url: optionsOrAPIUrl,
      promise: optionsOrPromiseConstructor || window.Promise
    };
  }

  if (options.promise == null) {
    throw new TypeError("Unable to construct 'InboxAPI': missing option `promise`, " +
                        "or no native Promise available");
  } else if (typeof options.promise !== 'function') {
    throw new TypeError("Unable to construct 'InboxAPI': option `promise` must be a " +
                        "function which returns an ECMAScript6-compatible Promise");
  }

  if (typeof options.url == null) {
    throw new TypeError("Unable to construct 'InboxAPI': missing option `url`");
  } else if (typeof options.url !== 'string') {
    throw new TypeError("Unable to construct 'InboxAPI': option `url` must be a string");
  }

  if (options.promise === window.Promise) {
    options.promise = NativePromiseWrapper;
  }

  if (!(this instanceof Inbox)) {
    return new Inbox(options);
  }

  options._cache = {};

  this._ = options;
  DefineProperty(this, '_', INVISIBLE);
}
<|endoftext|>


<commit_before>'use strict';

import Route from '../route/Route';
import Event from '../event/Event';

class App {
	constructor(props) {
		/**
		 * Maintains SPA routes
		 * @type {array}
		 * @default receive props routes
		 * @protected
		 */
		this.routes = props.routes;

		/**
		 * When enabled, routes are passed through the spa.
		 * @type {boolean}
		 * @protected
		 */
		this.enabled = props.enabled;

		/**
		 * Save the path name
		 * @type {string}
		 * @default null
		 * @protected
		 */
		this.path = null;

		/**
		 * Keeps all nodes tagged.
		 * @type {array}
		 * @default node list tag 'a'
		 * @protected
		 */
		this.nodeListTags = this.addTagsToArray();

		if (props.enabled) {
			this.init();
			this.onPopState();
		}
	}

	/**
	 * Starts the engine.
	 * @chainable
	 */
	init() {
		const initListen = this.addClickTags(this.nodeListTags, this.eventButton);
	}

	/**
	 * A NodeList object.
	 * @return {object}
	 */
	addTagsToArray() {
		return document.querySelectorAll('a');
	}

	/**
	 * Adds click event to all objects.
	 * @param {object} tags - Nodelist
	 * @param {function} func - Reference to function
	 * @chainable
	 */
	addClickTags(tags, func) {
		const self = this;
		const events = [].map.call(tags, element => {
			Event.addEventListenerClick(element, func, self);
		});
	}

	/**
	 * Adds click event to all objects.
	 * @param {object} event - Object of the event
	 * @chainable
	 */
	eventButton(event) {
		this.path = event.target.pathname;
		if (!event.target.attributes['data-no-spa']) {
			const router = new Route();

			router.checkRoutes(event, this.path, this.routes);
		}
	}

	/**
	 * Monitor history and update content when you return.
	 * @chainable
	 */
	onPopState() {
		window.onpopstate = (event) => {
			const router = new Route();

			router.checkRoutes(event, document.location.pathname, this.routes, true);
		}
	}
}

export default App;
<commit_msg>New name of the attribute.<commit_after>'use strict';

import Route from '../route/Route';
import Event from '../event/Event';

class App {
	constructor(props) {
		/**
		 * Maintains SPA routes
		 * @type {array}
		 * @default receive props routes
		 * @protected
		 */
		this.routes = props.routes;

		/**
		 * When enabled, routes are passed through the spa.
		 * @type {boolean}
		 * @protected
		 */
		this.enabled = props.enabled;

		/**
		 * Save the path name
		 * @type {string}
		 * @default null
		 * @protected
		 */
		this.path = null;

		/**
		 * Keeps all nodes tagged.
		 * @type {array}
		 * @default node list tag 'a'
		 * @protected
		 */
		this.nodeListTags = this.addTagsToArray();

		if (props.enabled) {
			this.init();
			this.onPopState();
		}
	}

	/**
	 * Starts the engine.
	 * @chainable
	 */
	init() {
		const initListen = this.addClickTags(this.nodeListTags, this.eventButton);
	}

	/**
	 * A NodeList object.
	 * @return {object}
	 */
	addTagsToArray() {
		return document.querySelectorAll('a');
	}

	/**
	 * Adds click event to all objects.
	 * @param {object} tags - Nodelist
	 * @param {function} func - Reference to function
	 * @chainable
	 */
	addClickTags(tags, func) {
		const self = this;
		const events = [].map.call(tags, element => {
			Event.addEventListenerClick(element, func, self);
		});
	}

	/**
	 * Adds click event to all objects.
	 * @param {object} event - Object of the event
	 * @chainable
	 */
	eventButton(event) {
		this.path = event.target.pathname;
		if (!event.target.attributes[':no-link']) {
			const router = new Route();

			router.checkRoutes(event, this.path, this.routes);
		}
	}

	/**
	 * Monitor history and update content when you return.
	 * @chainable
	 */
	onPopState() {
		window.onpopstate = (event) => {
			const router = new Route();

			router.checkRoutes(event, document.location.pathname, this.routes, true);
		}
	}
}

export default App;
<|endoftext|>


<commit_before>
export default class Router {

	/**
	 * routes
	 * @type {Object}
	 */
	routes = null;

	/**
	 * foward()
	 * @type {History}
	 */
	forward = null;

	/**
	 * back()
	 * @type {History}
	 */
	back = null;

	/**
	 * _pushState()
	 * @type {History}
	 */
	pushState = null;

	/**
	 * _replaceState()
	 * @type {History}
	 */
	replaceState = null;

	/**
	 * forceUrlchange
	 * @type {Boolean}
	 */
	forceUrlchange = false;

	/**
	 * listner
	 * @type {Object}
	 */
	listner = {
		action: null,
		urlchange: null,
	};

	/**
	 * event
	 * @type {Object}
	 */
	event = {
		action: null,
		urlchange: null,
	};

	/**
	 * mode
	 * @type {Object}
	 */
	mode = {
		stealth: null,
	};

	/**
	 * helper
	 * @type {Object}
	 */
	helper = {
		URLResolver: null,
		encodeURI: null,
		location: null,
		Promise: null,
	};

	/**
	 * _lastFragment
	 * @type {String}
	 */
	_lastFragment = null;

	/**
	 * _lastEvent
	 * @type {String}
	 */
	_lastEvent = null;

	/**
	 * _lastRoute
	 * @type {String|RegExp}
	 */
	_lastRoute = null;

	/**
	 * constructor
	 * @param  {Object} config
	 * @return {Router}
	 */
	constructor(config){

		Object.assign(this, config);
		this._init();

	}

	/**
	 * resolveURL
	 * @param  {String} href
	 * @return {URL} url
	 */
	resolveURL(href){

		let url = new this.helper.URLResolver(href);
		url.fragment = url.href.replace(url.origin, '');
		return url;

	}

	/**
	 * on
	 * @param  {String} event
	 * @param  {Function} handler
	 * @param  {Function} handler
	 * @return {Promise}
	 */
	on(event = null, ...args){

		let [ arg_2, arg_3 ] = args;

		if(!event){
			throw 'Please pass at least event e.g urlchange, Foo, Bar, ...';
		}

		let handler = null;
		let rule = null;
		let classof_arg2 = Object.classof(arg_2);
		let classof_arg3 = Object.classof(arg_3);

		if(event && classof_arg2 === 'Function' && classof_arg3 === 'Undefined'){
			handler = arg_2;
		}
		if(event && classof_arg2 === 'String' && classof_arg3 === 'Function'){
			rule = arg_2;
			handler = arg_3;
		}

		if(handler === null){
			throw 'You forget to pass the handler';
		}

		// if(Object.classof(this._scope[event]) !== 'Array'){
		// 	this._scope[event] = [];
		// }
		let promise = this.createPromise(::this._onPromiseResolved);
		// this._scope[event].push({ rule, handler, promise });

		return promise;

	}

	/**
	 * createPromise
	 * @param  {Function} handler
	 * @return {Promise}
	 */
	createPromise(handler=null) {

		if(!handler){
			throw `Please pass a handler function handler(){}!`;
		}

		return new this.helper.Promise(handler);
	}

	/**
	 * trigger
	 * @param  {String} event
	 * @param  {Object} options
	 * @return {Undefined}
	 */
	trigger(event = '', options = null){

		let _scope = this._scope[event];
		if(!_scope){
			throw `Allowed events: urlchange, ${(this._routes || []).join(', ')}`;
		}

		this._scope[this._event].trigger(event, options);

	}

	/**
	 * encodeURI
	 * @param  {String} uri
	 * @return {String}
	 */
	encodeURI(uri){
		return this.helper.encodeURI(uri);
	}

	/**
	 * destroy
	 * @return {Undefined}
	 */
	destroy() {
		this.listener.action.removeEvent(this.event.action);
		this.listener.urlchange.removeEvent(this.event.urlchange);
	}

	/**
	 * _init
	 * @return {Undefined}
	 */
	// sollte in start umbenannt werden
	_init(){

		this._bindEvents();
		this._bindRoutes();

	}

	/**
	 * _bindEvents
	 * @return {Undefined}
	 */
	_bindEvents(){

		this.listener.action.on(this.event.action, ::this._onAction);
		this.listener.urlchange.on(this.event.urlchange, ::this._onUrlchange);

	}

	/**
	 * _onAction
	 * @param  {Element} target
	 * @param  {String} type
	 * @return {Undefined}
	 */
	_onAction( event ){

		if(event instanceof Event){
			event.preventDefault();
			this.shadowEvent ? event.stopPropagation() : null;
		}

		let [ event_action_type ] = this.event.action.split(' ');
		let urlObject = this.resolveURL(
			event.type === event_action_type ? event.target.href : this.helper.location.href
		);

		if(urlObject.fragment !== this._lastFragment) {
			if(event.type === event_action_type){
				this.pushState(null, null, this.encodeURI(urlObject.fragment));
			}
			this.listener.urlchange.trigger(this.event.urlchange, urlObject);
		}

		this._lastFragment = urlObject.fragment;

	}

	/**
	 * _onUrlchange
	 * @param  {Event} event
	 * @return {Undefined}
	 */
	_onUrlchange( event ){
		console.log('_onUrlchange', event, event.detail.fragment);
	}

	/**
	 * _bindRoutes description
	 * @param  {Object} routes
	 * @return {Undefined}
	 */
	_bindRoutes(routes){

		if(routes) {
			for(let route in routes) {
				if(!routes.hasOwnProperty(route)){
					return;
				}
				this.on(/*routename, routepath, handler*/);
			}
		}

	}

	/**
	 * [_onPromiseResolved description]
	 * @param  {Function} resolve
	 * @param  {Function} reject
	 * @return {Undefined}
	 */
	_onPromiseResolved(resolve, reject) {

	}

	/**
	 * remove route
	 * @return {Undefined}
	 */
	removeEvent(){

	}

	/**
	 * redirect
	 * @return {undefined}
	 */
	redirect(){

	}

	/**
	 * constructURL
	 * @param  {String} route
	 * @param  {Object} params
	 * @return {String}
	 */
	constructURL(route, params = {}){

	}

	/**
	 * start
	 * @return {undefined}
	 */
	start(){

	}

	/**
	 * stop
	 * @return {Undefined}
	 */
	stop(){

	}

	/**
	 * var result2 = router.recognize("/product/detail/1");
	 * result2 === { handler: showPost, params: { id: "1" }, name: 'product::detail'};
	 *
	 * @param  {String} path
	 */
	recognize(path){

	}
}
<commit_msg>Router.js: implemented logic for on method if passed internal event eg. urlchange<commit_after>
export default class Router {

	/**
	 * routes
	 * @type {Object}
	 */
	routes = null;

	/**
	 * foward()
	 * @type {History}
	 */
	forward = null;

	/**
	 * back()
	 * @type {History}
	 */
	back = null;

	/**
	 * _pushState()
	 * @type {History}
	 */
	pushState = null;

	/**
	 * _replaceState()
	 * @type {History}
	 */
	replaceState = null;

	/**
	 * forceUrlchange
	 * @type {Boolean}
	 */
	forceUrlchange = false;

	/**
	 * listner
	 * @type {Object}
	 */
	listner = {
		action: null,
		urlchange: null,
	};

	/**
	 * event
	 * @type {Object}
	 */
	event = {
		action: null,
		urlchange: null,
	};

	/**
	 * handler
	 * @type {Object}
	 */
	handler = {
		urlchange: [],
	};

	/**
	 * mode
	 * @type {Object}
	 */
	mode = {
		stealth: null,
	};

	/**
	 * helper
	 * @type {Object}
	 */
	helper = {
		URLResolver: null,
		encodeURI: null,
		location: null,
		Promise: null,
	};

	/**
	 * _lastFragment
	 * @type {String}
	 */
	_lastFragment = null;

	/**
	 * _lastEvent
	 * @type {String}
	 */
	_lastEvent = null;

	/**
	 * _lastRoute
	 * @type {String|RegExp}
	 */
	_lastRoute = null;

	/**
	 * constructor
	 * @param  {Object} config
	 * @return {Router}
	 */
	constructor(config){

		Object.assign(this, config);
		this._init();

	}

	/**
	 * resolveURL
	 * @param  {String} href
	 * @return {URL} url
	 */
	resolveURL(href){

		let url = new this.helper.URLResolver(href);
		url.fragment = url.href.replace(url.origin, '');
		return url;

	}

	/**
	 * on
	 * @param  {String} event
	 * @param  {Function} handler
	 * @param  {Function} handler
	 * @return {Promise}
	 */
	on(event = null, ...args){

		let [ arg_2, arg_3 ] = args;
		let handler = null;
		let rule = null;
		let classof_arg2 = Object.classof(arg_2);
		let classof_arg3 = Object.classof(arg_3);

		if(!event){
			throw 'Please pass at least event e.g urlchange, Foo, Bar, ...';
		}

		// generic event e.g. urlchange
		if(event && classof_arg2 === 'Function' && classof_arg3 === 'Undefined'){
			handler = arg_2;
		}
		// if route event
		if(event && classof_arg2 === 'String' && classof_arg3 === 'Function'){
			rule = arg_2;
			handler = arg_3;
		}
		if(handler === null){
			throw 'You forget to pass the handler';
		}

		let promise = this.createPromise(::this._onPromiseResolved);

		// if passed 2 arguments e.g 'urlchange', handler
		if([event, ...args].length === 2) {

			if(!this.listener[event]){
				throw `Event: "${event} is not allowed! Allowed is: ${this.event.urlchange}"`;
			}
			this.handler[event].push({ handler, promise });

		} else {
			// if route
		}

		return promise;

	}

	/**
	 * createPromise
	 * @param  {Function} handler
	 * @return {Promise}
	 */
	createPromise(handler=null) {

		if(!handler){
			throw `Please pass a handler function handler(){}!`;
		}

		return new this.helper.Promise(handler);
	}

	/**
	 * trigger
	 * @param  {String} event
	 * @param  {Object} options
	 * @return {Undefined}
	 */
	trigger(event = '', options = null){

		if(!this.listener[event]){
			throw `Event: "${event} is not allowed! Please use: ${this.event.urlchange}"`;
		}

		this.listener[event].trigger(this.event[event], options);

	}

	/**
	 * encodeURI
	 * @param  {String} uri
	 * @return {String}
	 */
	encodeURI(uri){
		return this.helper.encodeURI(uri);
	}

	/**
	 * destroy
	 * @return {Undefined}
	 */
	destroy() {
		this.listener.action.removeEvent(this.event.action);
		this.listener.urlchange.removeEvent(this.event.urlchange);
	}

	/**
	 * _init
	 * @return {Undefined}
	 */
	// sollte in start umbenannt werden
	_init(){

		this._bindEvents();
		this._bindRoutes();

	}

	/**
	 * _bindEvents
	 * @return {Undefined}
	 */
	_bindEvents(){

		this.listener.action.on(this.event.action, ::this._onAction);
		this.listener.urlchange.on(this.event.urlchange, ::this._onUrlchange);

	}

	/**
	 * _onAction
	 * @param  {Element} target
	 * @param  {String} type
	 * @return {Undefined}
	 */
	_onAction( event ){

		if(event instanceof Event){
			event.preventDefault();
			this.shadowEvent ? event.stopPropagation() : null;
		}

		let [ event_action_type ] = this.event.action.split(' ');
		let urlObject = this.resolveURL(
			event.type === event_action_type ? event.target.href : this.helper.location.href
		);

		if(urlObject.fragment !== this._lastFragment) {
			if(event.type === event_action_type){
				this.pushState(null, null, this.encodeURI(urlObject.fragment));
			}
			this.listener.urlchange.trigger(this.event.urlchange, urlObject);
		}

		this._lastFragment = urlObject.fragment;

	}

	/**
	 * _onUrlchange
	 * @param  {Event} event
	 * @return {Undefined}
	 */
	_onUrlchange(event){

		// call registered internal events e.g. router.on('urlchange', handler);
		this._callRegisteredInternalEvents(event);

	}

	/**
	 * _callRegisteredInternalEvents
	 * @return {Undefined}
	 */
	_callRegisteredInternalEvents(event){

		// if has length its automatically handler and promise available
		if(!this.handler.urlchange.length){
			return;
		}

		for(let { handler, promise } of this.handler.urlchange){
			// call callback handler
			handler.call(this, event);
		}

	}

	/**
	 * _bindRoutes description
	 * @param  {Object} routes
	 * @return {Undefined}
	 */
	_bindRoutes(routes){

		if(routes) {
			for(let route in routes) {
				if(!routes.hasOwnProperty(route)){
					return;
				}
				this.on(/*routename, routepath, handler*/);
			}
		}

	}

	/**
	 * [_onPromiseResolved description]
	 * @param  {Function} resolve
	 * @param  {Function} reject
	 * @return {Undefined}
	 */
	_onPromiseResolved(resolve, reject) {

	}

	/**
	 * remove route
	 * @return {Undefined}
	 */
	removeEvent(){

	}

	/**
	 * redirect
	 * @return {undefined}
	 */
	redirect(){

	}

	/**
	 * constructURL
	 * @param  {String} route
	 * @param  {Object} params
	 * @return {String}
	 */
	constructURL(route, params = {}){

	}

	/**
	 * start
	 * @return {undefined}
	 */
	start(){

	}

	/**
	 * stop
	 * @return {Undefined}
	 */
	stop(){

	}

	/**
	 * var result2 = router.recognize("/product/detail/1");
	 * result2 === { handler: showPost, params: { id: "1" }, name: 'product::detail'};
	 *
	 * @param  {String} path
	 */
	recognize(path){

	}
}
<|endoftext|>


<commit_before>var app = require('./app.js'),
  $ = require('jquery'),
  config = require('./config.js'),
  socket,
  user,
  devices = [],
  popupWindow;

function initializeSocket() {
  socket = io(config.SOCKET_SERVER);
  socket.on('update', function (data) {
    devices = data;
    drawDevices(data);
  });
  socket.on('start', function (data) {
    if (data.user.id === user.id) {
      $('#go').hide();
      $('#stop-testing').show();
      if ($('#open-url').is(':checked')) {
        if (popupWindow && !popupWindow.closed) {
          popupWindow.location.href = data.url;
          popupWindow.focus();
        } else {
          popupWindow = window.open(data.url, '_blank');
        }
      }
    }
  });
}

function start() {

  // Start the app here

  initializeSocket();

  select();

  $(window).on('pageshow', function () {
    if (user) {
      $('#wait').hide();
      $('#content').addClass('devices');
      $('#container').removeClass('centerized');
      $('#devices').show();
    }
  });

}

function initializeUser(fn) {

  if (config.loginType == 1) {

    // Google Auth login

    $.getJSON('/user', function (res) {
      if (res.user) {
        user = res.user;
        fn();
      } else {
        login();
      }
    });

  } else if (config.loginType == 2) {

    // Nick name login
    identify(fn);

  }

}

function identify(fn) {

  $('#identify').show();
  var name = localStorage.getItem('name');

  if (name) {
    $('#name').val(name);
  }

  $('#identify-button').click(function () {

    $('#identify').hide();

    var name = $('#name').val();
    localStorage.setItem('name', name);

    user = {
      id: name,
      displayName: name
    };

    fn();

  });

}

function login() {
  $('#login').show();
  $('#login-button').click(function () {
    location = '/auth/google';
  });
}

function selectAll() {
  $('input[name="labels[]"]').not(':disabled').prop('checked', true);
}

function selectNone() {
  $('input[name="labels[]"]').not(':disabled').removeAttr('checked');
}

function drawDevices(data) {

  var devicesList = $('#devices-list');
  devicesList.html('');

	var battery = $('').html('🔋').html();

  $.each(data, function (key, value) {

    var rowElement = $('

');

    var
    	level = value.batteryStatus ? value.batteryStatus.level : null,
    	isPlugged = value.batteryStatus ? value.batteryStatus.isPlugged : null,
    	title = level ? 'Level: ' + level + ' %' + (isPlugged ? ', plugged' : '') : '',
    	position = level ? (level * .8 + 10) + '%' : '',
    	stop1 = (isPlugged ? '#0f0' : '#fff') + ' ' + position,
    	stop2 = (isPlugged ? '#0c0' : '#ccc') + ' ' + position,
    	style = ' style="background-image: -webkit-linear-gradient(left, ' + stop1 + ', ' + stop2 + ');"';

    rowElement.append(
      '' + value.label + '	' +
      '' + (value.model || '') + '	' +
      '' + (value.platform || '') + '	' +
      '' + (value.version || '') + '	' +
      '' + battery + '	' +
      '' + (value.userName || '') + '	' +
      '<time>' + (value.lastUsed ? moment(new Date(value.lastUsed)).fromNow() : '') + '</time>	' +
      '<input type="checkbox" name="labels[]" value="' + value.label + '" ' + (value.userId ? 'disabled' : '') + '>	'
    );

    devicesList.append(rowElement);

  });

 	$('#devices-list [contenteditable]').blur(function (event) {

		var
			element = $(event.target),
			label = element.parent().attr('data-label'),
			key = element.attr('data-key'),
			value = element.text();

		$.post('/save', {label: label, key: key, value: value});

	});

	$('#devices-list [contenteditable]').keypress(function (event) {
		if (event.which == 13) {
			event.target.blur();
			return false;
		}
	});

}

function select() {

  if (!user) {
    initializeUser(select);
    return;
  }

  $('#content').addClass('devices');

  $('#devices-form').submit(selectSubmit);

  $('#url').focus(function (event) {
    if (!event.target.value) {
      event.target.value = 'http://www.';
    }
  });

  setTimeout(function () {
    $('#devices').show();
    $('#container').removeClass('centerized');
  }, 300);

  var url = localStorage.getItem('url');

  if (url) {
    $('#url').val(url);
  }

  $('#select-all').click(selectAll);
  $('#select-none').click(selectNone);

  $('#stop-testing').click(stopTesting);

  $.getJSON('/devices', function (data) {
    devices = data;
    drawDevices(data);
  });

}

function selectSubmit(event) {

  var url = $('#url').val(),
      formData = {
        url: url,
        labels: $('input[name="labels[]"]:checked').map(function () {
          return $(this).val();
        }).get(),
        user: user
      };

  localStorage.setItem('url', url);

  socket.emit('start', formData);

  return false;

}

function getUserDevices() {

  var i,
      devicesLength = devices.length,
      userDevices = [];

  for (i = 0; i < devicesLength; i++) {
    if (devices[i].userId === user.id) {
      userDevices.push(devices[i].label);
    }
  }

  return userDevices;

}

function stopTesting() {
  socket.emit('stop', {user: user, labels: getUserDevices()});
  $('#stop-testing').hide();
  $('#go').show();
}

exports = module.exports = {
  start: start
};
<commit_msg>Keep label unique from control panel<commit_after>var app = require('./app.js'),
  $ = require('jquery'),
  config = require('./config.js'),
  socket,
  user,
  devices = [],
  popupWindow;

function initializeSocket() {
  socket = io(config.SOCKET_SERVER);
  socket.on('update', function (data) {
    devices = data;
    drawDevices(data);
  });
  socket.on('start', function (data) {
    if (data.user.id === user.id) {
      $('#go').hide();
      $('#stop-testing').show();
      if ($('#open-url').is(':checked')) {
        if (popupWindow && !popupWindow.closed) {
          popupWindow.location.href = data.url;
          popupWindow.focus();
        } else {
          popupWindow = window.open(data.url, '_blank');
        }
      }
    }
  });
}

function start() {

  // Start the app here

  initializeSocket();

  select();

  $(window).on('pageshow', function () {
    if (user) {
      $('#wait').hide();
      $('#content').addClass('devices');
      $('#container').removeClass('centerized');
      $('#devices').show();
    }
  });

}

function initializeUser(fn) {

  if (config.loginType == 1) {

    // Google Auth login

    $.getJSON('/user', function (res) {
      if (res.user) {
        user = res.user;
        fn();
      } else {
        login();
      }
    });

  } else if (config.loginType == 2) {

    // Nick name login
    identify(fn);

  }

}

function identify(fn) {

  $('#identify').show();
  var name = localStorage.getItem('name');

  if (name) {
    $('#name').val(name);
  }

  $('#identify-button').click(function () {

    $('#identify').hide();

    var name = $('#name').val();
    localStorage.setItem('name', name);

    user = {
      id: name,
      displayName: name
    };

    fn();

  });

}

function login() {
  $('#login').show();
  $('#login-button').click(function () {
    location = '/auth/google';
  });
}

function selectAll() {
  $('input[name="labels[]"]').not(':disabled').prop('checked', true);
}

function selectNone() {
  $('input[name="labels[]"]').not(':disabled').removeAttr('checked');
}

function drawDevices(data) {

  var devicesList = $('#devices-list');
  devicesList.html('');

  var battery = $('').html('🔋').html();

  $.each(data, function (key, value) {

    var rowElement = $('

');

    var
      level = value.batteryStatus ? value.batteryStatus.level : null,
      isPlugged = value.batteryStatus ? value.batteryStatus.isPlugged : null,
      title = level ? 'Level: ' + level + ' %' + (isPlugged ? ', plugged' : '') : '',
      position = level ? (level * 0.8 + 10) + '%' : '',
      stop1 = (isPlugged ? '#0f0' : '#fff') + ' ' + position,
      stop2 = (isPlugged ? '#0c0' : '#ccc') + ' ' + position,
      style = ' style="background-image: -webkit-linear-gradient(left, ' + stop1 + ', ' + stop2 + ');"';

    rowElement.append(
      '' + value.label + '	' +
      '' + (value.model || '') + '	' +
      '' + (value.platform || '') + '	' +
      '' + (value.version || '') + '	' +
      '' + battery + '	' +
      '' + (value.userName || '') + '	' +
      '<time>' + (value.lastUsed ? moment(new Date(value.lastUsed)).fromNow() : '') + '</time>	' +
      '<input type="checkbox" name="labels[]" value="' + value.label + '" ' + (value.userId ? 'disabled' : '') + '>	'
    );

    devicesList.append(rowElement);

  });

  $('#devices-list [contenteditable]').blur(function (event) {

    var
      element = $(event.target),
      label = element.parent().attr('data-label'),
      key = element.attr('data-key'),
      value = element.text(),
      labelIsntUnique;

    if (key === 'label') {
      if (label !== value) {
        for (var i = 0; i < devices.length; i++) {
          if (devices[i].label === value) {
            labelIsntUnique = true;
          }
        }
      }
    }
    if (labelIsntUnique) {
      element.text(label);
    } else {
      $.post('/save', {label: label, key: key, value: value});
    }
  });

  $('#devices-list [contenteditable]').keypress(function (event) {
    if (event.which == 13) {
      event.target.blur();
      return false;
    }
  });

}

function select() {

  if (!user) {
    initializeUser(select);
    return;
  }

  $('#content').addClass('devices');

  $('#devices-form').submit(selectSubmit);

  $('#url').focus(function (event) {
    if (!event.target.value) {
      event.target.value = 'http://www.';
    }
  });

  setTimeout(function () {
    $('#devices').show();
    $('#container').removeClass('centerized');
  }, 300);

  var url = localStorage.getItem('url');

  if (url) {
    $('#url').val(url);
  }

  $('#select-all').click(selectAll);
  $('#select-none').click(selectNone);

  $('#stop-testing').click(stopTesting);

  $.getJSON('/devices', function (data) {
    devices = data;
    drawDevices(data);
  });

}

function selectSubmit(event) {

  var url = $('#url').val(),
      formData = {
        url: url,
        labels: $('input[name="labels[]"]:checked').map(function () {
          return $(this).val();
        }).get(),
        user: user
      };

  localStorage.setItem('url', url);

  socket.emit('start', formData);

  return false;

}

function getUserDevices() {

  var i,
      devicesLength = devices.length,
      userDevices = [];

  for (i = 0; i < devicesLength; i++) {
    if (devices[i].userId === user.id) {
      userDevices.push(devices[i].label);
    }
  }

  return userDevices;

}

function stopTesting() {
  socket.emit('stop', {user: user, labels: getUserDevices()});
  $('#stop-testing').hide();
  $('#go').show();
}

exports = module.exports = {
  start: start
};
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const log_tree = require("../lib/log_tree");

describe("a log_tree object", function() {
  it("can be created from nothing", function() {
    var tree = log_tree();
  });

  it("can be created with a name", function() {
    var tree = log_tree("name");
  });

  it("has a length of 0 when created from nothing", function() {
    var tree = log_tree();
    expect(tree.length()).toBe(0);
  });
});
<commit_msg>:art: Merge two tests into a nested given<commit_after>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const log_tree = require("../lib/log_tree");

describe("a log_tree object", function() {
  describe("when created from nothing", function() {
    it("has a length of 0", function() {
      var tree = log_tree();
      expect(tree.length()).toBe(0);
    });
  });

  it("can be created with a name", function() {
    var tree = log_tree("name");
  });
});
<|endoftext|>


<commit_before>describe("mailcheck", function() {
  var domains = ['google.com', 'gmail.com', 'emaildomain.com', 'comcast.net', 'facebook.com', 'msn.com', 'gmx.de'];
  var secondLevelDomains = ["yahoo", "hotmail", "mail", "live", "outlook", "gmx"];
  var topLevelDomains = ['co.uk', 'com', 'org', 'info', 'fr'];

  describe("Mailcheck", function(){
    var mailcheck;

    beforeEach(function(){
      // We may be running in a CommonJS environment.
      // If so, mailcheck won't be in a global Kicksend object.
      mailcheck = typeof Mailcheck !== 'undefined' ? Mailcheck : require('../');
    });

    describe("run", function () {
      var suggestedSpy, emptySpy;

      beforeEach(function () {
        suggestedSpy = jasmine.createSpy();
        emptySpy = jasmine.createSpy();
      });

      it("calls the 'suggested' callback with the element and result when there's a suggestion", function () {
        mailcheck.run({
          email: 'test@gmail.co',
          suggested:suggestedSpy,
          empty:emptySpy
        });

        expect(suggestedSpy).toHaveBeenCalledWith({
          address:'test',
          domain:'gmail.com',
          full:'test@gmail.com'
        });

        expect(emptySpy).not.toHaveBeenCalled();
      });

      it("calls the 'empty' callback with the element when there's no suggestion", function () {
        mailcheck.run({
          email: 'contact@kicksend.com',
          suggested:suggestedSpy,
          empty:emptySpy
        });

        expect(suggestedSpy).not.toHaveBeenCalled();

        expect(emptySpy).toHaveBeenCalled();
      });

      it("returns the result when 'suggested' callback is not defined", function () {
        var result = mailcheck.run({
          email: 'test@gmail.co'
        });

        expect(result).toEqual({
          address:'test',
          domain:'gmail.com',
          full:'test@gmail.com'
        })
      })

      it("takes in an array of specified domains", function () {
        mailcheck.run({
          email: 'test@emaildomain.con',
          suggested:suggestedSpy,
          empty:emptySpy,
          domains:domains
        });

        expect(suggestedSpy).toHaveBeenCalledWith({
          address:'test',
          domain:'emaildomain.com',
          full:'test@emaildomain.com'
        });
      });
    });

    describe("encodeEmail", function () {
      it("escapes the element's value", function () {
        var result = mailcheck.encodeEmail('@emaildomain.con');
        expect(result).not.toMatch(/@emaildomain.con');
        expect(result).not.toMatch(/


<commit_before>import inquirerAsync from 'inquirer-async';

import {
  UserSettings,
} from 'xdl';

async function askForSendToAsync() {
  var sendToFromSettings = await UserSettings.getAsync('sendTo', null);
  console.log("Enter a mobile number or e-mail and we'll send a link to your phone.");
  var answers = await inquirerAsync.promptAsync([{
    type: 'input',
    name: 'sendTo',
    message: "Your mobile number or e-mail" + (sendToFromSettings ? " (space to not send anything)" : '') + ":",
    default: sendToFromSettings,
  }]);
  let recipient = answers.sendTo.trim();
  await UserSettings.mergeAsync({sendTo: recipient});
  return recipient;
}

export default {
  askForSendToAsync,
};

if (require.main === module) {
  askForSendToAsync().then(function (sendTo) {
    console.log("Your mobile number or email is", sendTo);
  });
}
<commit_msg>Confirm before publishing<commit_after>import inquirerAsync from 'inquirer-async';

import {
  UserSettings,
} from 'xdl';

async function askForSendToAsync() {
  var sendToFromSettings = await UserSettings.getAsync('sendTo', null);
  console.log("Enter a mobile number or e-mail and we'll send a link to your phone.");
  var answers = await inquirerAsync.promptAsync([{
    type: 'input',
    name: 'sendTo',
    message: "Your mobile number or e-mail" + (sendToFromSettings ? " (space to not send anything)" : '') + ":",
    default: sendToFromSettings,
  }]);
  let recipient = answers.sendTo.trim();
  await UserSettings.mergeAsync({sendTo: recipient});
  return recipient;
}

export default {
  askForSendToAsync,
};

if (require.main === module) {
  askForSendToAsync().then(function(sendTo) {
    console.log("Your mobile number or email is", sendTo);
  });
}
<|endoftext|>


<commit_before>'use strict';

const Measures = require('../src/measures');

describe('measures', () => {
  const lowerBound = 1;
  const upperBound = 5;
  const measures = new Measures(lowerBound, upperBound);

  describe('construction', () => {
    it('requires lowerBound', () => {
      expect(() => new Measures()).toThrowError('lowerBound is required');
    });

    it('requires upperBound', () => {
      expect(() => new Measures(lowerBound) ).toThrowError('upperBound is required');
    });
  });

  it('requires measure name', () => {
    expect( () => measures.add() ).toThrowError('measure name required');
  });

  it('requires measure value', () => {
    expect( () => measures.add('measure name') ).toThrowError('measure value required');
  });

  it('requires measure value to be in range', () => {
    expect( () => measures.add('measure name', 0) ).toThrowError('measure value must be larger than lowerBound');
    expect( () => measures.add('measure name', 6) ).toThrowError('measure value must be less than upperBound');
  });
});
<commit_msg>Group add tests<commit_after>'use strict';

const Measures = require('../src/measures');

describe('measures', () => {
  const lowerBound = 1;
  const upperBound = 5;
  const measures = new Measures(lowerBound, upperBound);

  describe('construction', () => {
    it('requires lowerBound', () => {
      expect(() => new Measures()).toThrowError('lowerBound is required');
    });

    it('requires upperBound', () => {
      expect(() => new Measures(lowerBound) ).toThrowError('upperBound is required');
    });
  });

  describe('adding measure', () => {
    const measureName = 'measure name';

    it('requires name', () => {
      expect( () => measures.add() ).toThrowError('measure name required');
    });

    it('requires value', () => {
      expect( () => measures.add(measureName) ).toThrowError('measure value required');
    });

    it('requires value to be in range', () => {
      expect( () => measures.add(measureName, lowerBound - 1) ).toThrowError('measure value must be larger than lowerBound');
      expect( () => measures.add(measureName, upperBound + 1) ).toThrowError('measure value must be less than upperBound');
    });
  });
});
<|endoftext|>


<commit_before>var config    = require("./config/config")
  , Sequelize = require("../index")
  , sequelize = new Sequelize(config.database, config.username, config.password, { logging: false })
  , Helpers   = new (require("./config/helpers"))(sequelize)
  , Migrator  = require("../lib/migrator")

describe('Migrator', function() {
  describe('getUndoneMigrations', function() {
    var migrator = null

    var setup = function(_options) {
      var options = Sequelize.Utils._.extend({
        path: __dirname + '/assets/migrations'
      }, _options || {})

      migrator = new Migrator(sequelize, options)
    }

    beforeEach(function() { migrator = null })

    // specs

    it("returns no files if timestamps are after the files timestamp", function() {
      setup({ from: 20120101010101 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(0)
          done()
        })
      })
    })

    it("returns only files between from and to", function() {
      setup({ from: 19700101000000, to: 20111117063700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(1)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          done()
        })
      })
    })

    it("returns also the file which is exactly options.from or options.to", function() {
      setup({ from: 20111117063700, to: 20111123060700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(2)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          expect(files[1]).toEqual('20111123060700-addBirthdateToPerson.js')
          done()
        })
      })
    })

    //it("returns")
  })
/*

  describe('getLastMigrationId', function() {
    it("should correctly transform array into IN", function() {
      Helpers.async(function(done) {
        new Migrator(sequelize, {
          path: __dirname + '/assets/migrations',
          from: 2011111706370020111117063700,
          to: 20111117063700
        }).migrate().success(function() {
          done()
        })
      })
    })
  })*/
})
<commit_msg>another spec<commit_after>var config    = require("./config/config")
  , Sequelize = require("../index")
  , sequelize = new Sequelize(config.database, config.username, config.password, { logging: false })
  , Helpers   = new (require("./config/helpers"))(sequelize)
  , Migrator  = require("../lib/migrator")

describe('Migrator', function() {
  describe('getUndoneMigrations', function() {
    var migrator = null

    var setup = function(_options) {
      var options = Sequelize.Utils._.extend({
        path: __dirname + '/assets/migrations'
      }, _options || {})

      migrator = new Migrator(sequelize, options)
    }

    beforeEach(function() { migrator = null })

    // specs

    it("returns no files if timestamps are after the files timestamp", function() {
      setup({ from: 20120101010101 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(0)
          done()
        })
      })
    })

    it("returns only files between from and to", function() {
      setup({ from: 19700101000000, to: 20111117063700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(1)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          done()
        })
      })
    })

    it("returns also the file which is exactly options.from or options.to", function() {
      setup({ from: 20111117063700, to: 20111123060700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(2)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          expect(files[1]).toEqual('20111123060700-addBirthdateToPerson.js')
          done()
        })
      })
    })

    it("returns all files to options.to if no options.from is defined", function() {
      setup({ to: 20111123060700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(2)
          done()
        })
      })
    })
  })
/*

  describe('getLastMigrationId', function() {
    it("should correctly transform array into IN", function() {
      Helpers.async(function(done) {
        new Migrator(sequelize, {
          path: __dirname + '/assets/migrations',
          from: 2011111706370020111117063700,
          to: 20111117063700
        }).migrate().success(function() {
          done()
        })
      })
    })
  })*/
})
<|endoftext|>