<commit_before>"use strict";

// A button or anchor provides:
//     disable="disabled": it should start disabled
//     data-always-enable: true if it should always be enabled
//     data-href: the URL that will either be a direct link or a "next=" after login
//     data-disabled-title (optional) = a title to set on the disabled element
//
// If data-always-enable is true, enable the button/anchor.
// If it's false then check config.loggedIn and determine whether to
// modify the button or anchor into a loginUrl redirector or to
// leave disabled and set the disabled text.
//
// When an anchor tag gets enabled, its href is set to its data-href.

var $ = require('jquery'),
    _ = require('underscore'),

    enablePermAttr = 'data-always-enable',
    disabledTitleAttr = 'data-disabled-title',
    redirectUrlAttr = 'data-redirect-url',
    hrefAttr = 'data-href',
    enablePermSelector = '[' + enablePermAttr + ']',
    config;

function makeRedirectToLogin($el, href) {

    var fullHref = config.loginUrl + href;

    $el.attr('disabled', false);
    $el.removeAttr('data-target'); // in case it triggers a modal

    if ($el.is('a')) { $el.attr('href', fullHref); }
    else if ($el.is('button')) {
        $el.off('click');
        $el.click(function () {
            window.location = fullHref;
        });
    }
}

function fullyEnable($el, href) {
    $el.attr('disabled', false);
    if ($el.is('a')) { $el.attr('href', href); }
}

function fullyDisable($el, disabledTitle) {
    $el.off('click');
    $el.removeAttr('data-target'); // in case it triggers a modal
    if (disabledTitle) { $el.attr('title', disabledTitle); }
}

exports.run = function (options) {
    var $elements = $(enablePermSelector);

    config = options.config;

    _.each($elements, function(element) {
        var $element = $(element),
            hasPerm = $element.attr(enablePermAttr),
            disabledTitle = $element.attr(disabledTitleAttr),
            href = $element.attr(hrefAttr);

        if (hasPerm === 'True') {
            fullyEnable($element, href);
        } else if (!config.loggedIn) {
            makeRedirectToLogin($element, href);
        } else {
            fullyDisable($element, disabledTitle);
        }
    });
};
<commit_msg>Remove data-action attribute in buttonEnabler<commit_after>"use strict";

// A button or anchor provides:
//     disable="disabled": it should start disabled
//     data-always-enable: true if it should always be enabled
//     data-href: the URL that will either be a direct link or a "next=" after login
//     data-disabled-title (optional) = a title to set on the disabled element
//
// If data-always-enable is true, enable the button/anchor.
// If it's false then check config.loggedIn and determine whether to
// modify the button or anchor into a loginUrl redirector or to
// leave disabled and set the disabled text.
//
// When an anchor tag gets enabled, its href is set to its data-href.

var $ = require('jquery'),
    _ = require('underscore'),

    enablePermAttr = 'data-always-enable',
    disabledTitleAttr = 'data-disabled-title',
    redirectUrlAttr = 'data-redirect-url',
    hrefAttr = 'data-href',
    enablePermSelector = '[' + enablePermAttr + ']',
    config;

function removeActionableDataAttributes($el) {
    // in case it triggers a modal
    $el.removeAttr('data-target');
    // in case an event is bound to this element
    $el.removeAttr('data-action');
}

function makeRedirectToLogin($el, href) {

    var fullHref = config.loginUrl + href;

    $el.attr('disabled', false);
    removeActionableDataAttributes($el);

    if ($el.is('a')) { $el.attr('href', fullHref); }
    else if ($el.is('button')) {
        $el.off('click');
        $el.click(function () {
            window.location = fullHref;
        });
    }
}

function fullyEnable($el, href) {
    $el.attr('disabled', false);
    if ($el.is('a')) { $el.attr('href', href); }
}

function fullyDisable($el, disabledTitle) {
    $el.off('click');
    removeActionableDataAttributes($el);
    if (disabledTitle) { $el.attr('title', disabledTitle); }
}

exports.run = function (options) {
    var $elements = $(enablePermSelector);

    config = options.config;

    _.each($elements, function(element) {
        var $element = $(element),
            hasPerm = $element.attr(enablePermAttr),
            disabledTitle = $element.attr(disabledTitleAttr),
            href = $element.attr(hrefAttr);

        if (hasPerm === 'True') {
            fullyEnable($element, href);
        } else if (!config.loggedIn) {
            makeRedirectToLogin($element, href);
        } else {
            fullyDisable($element, disabledTitle);
        }
    });
};
<|endoftext|>


<commit_before>'use strict';

import Action from '../actions/Action';
import MouseAction from '../actions/MouseAction';
import KeyboardAction from '../actions/KeyboardAction';
import FormAction from '../actions/FormAction';
import TouchAction from '../actions/TouchAction';

import ComponentObject from '../core/ComponentObject';

/**
 * The Atom class is the abstract base class for all component objects with
 * which the user can interact, using the mouse, keyboard, or other user input
 * device.
 *
 * You cannot instantiate the Atom class directly. A call to the new Atom()
 * constructor throws an ArgumentError exception.
 *
 * @constructor {name} Instance Name
 *
 */

class Atom extends ComponentObject {
  constructor(name) {
    super(name);

    if (new.target === Atom) {
      throw new TypeError("Yout cannot instantiate the Atom class directly");
    }

    /**
     * Specifies whether the object receives doubleClick actions.
     *
     */

    Object.defineProperty(this, 'doubleClickEnabled', {
      value: true
    });

    /**
     * Specifies whether this object receives mouse, or other user input,
     * messages.
     *
     * If mouseEnabled is set to false, the instance does not receive any mouse
     * actions (or other user input actions like keyboard actions).
     */

    Object.defineProperty(this, 'mouseEnabled', {
      value: true
    });

    /**
     * Specifies whether this object is in the tab order.
     *
     */

    Object.defineProperty(this, 'tabEnabled', {
      value: false
    });

    /**
     * Specifies the tab ordering.
     * The tabIndex property is -1 by default, meaning no tab index is set for
     * the object.
     *
     */

    Object.defineProperty(this, 'tabIndex', {
      value: -1
    });

    /**
     * Subscribe to DOM events after adding the component
     *
     */

    this.addActionListener(Action.ADDED, this.subscribeEvents, 0, true);
  }

  subscribeEvents(a) {
    this.view.addEventListener('onclick',       this.handleEventListener);
    this.view.addEventListener('ondclick',      this.handleEventListener);
    this.view.addEventListener('onmousedown',   this.handleEventListener);
    this.view.addEventListener('onmouseenter',  this.handleEventListener);
    this.view.addEventListener('onmouseleave',  this.handleEventListener);
    this.view.addEventListener('onmousemove',   this.handleEventListener);
    this.view.addEventListener('onmouseover',   this.handleEventListener);
    this.view.addEventListener('onmouseout',    this.handleEventListener);
    this.view.addEventListener('onmouseup',     this.handleEventListener);
    this.view.addEventListener('onwheel',       this.handleEventListener);
    this.view.addEventListener('onkeydown',     this.handleEventListener);
    this.view.addEventListener('onkeypress',    this.handleEventListener);
    this.view.addEventListener('onkeyup',       this.handleEventListener);
    this.view.addEventListener('onblur',        this.handleEventListener);
    this.view.addEventListener('onchange',      this.handleEventListener);
    this.view.addEventListener('onfocus',       this.handleEventListener);
    this.view.addEventListener('onfocusin',     this.handleEventListener);
    this.view.addEventListener('onfocusout',    this.handleEventListener);
    this.view.addEventListener('oninput',       this.handleEventListener);
    this.view.addEventListener('oninvalid',     this.handleEventListener);
    this.view.addEventListener('onreset',       this.handleEventListener);
    this.view.addEventListener('onsearch',      this.handleEventListener);
    this.view.addEventListener('onselect',      this.handleEventListener);
    this.view.addEventListener('oncopy',        this.handleEventListener);
    this.view.addEventListener('oncut',         this.handleEventListener);
    this.view.addEventListener('onpaste',       this.handleEventListener);
    this.view.addEventListener('ontouchcancel', this.handleEventListener);
    this.view.addEventListener('ontouchend',    this.handleEventListener);
    this.view.addEventListener('ontouchmove',   this.handleEventListener);
    this.view.addEventListener('ontouchstart',  this.handleEventListener);
  }

  /**
   * Handle Event Listener
   * Transform DOM Event into Action
   *
   * @param {e} Event
   *
   */

  handleEventListener(e) {
    let action = false;
    let data = {};

    switch (e.type) {
      case 'onclick':
        action = new MouseAction      (MouseAction    .CLICK        , data);
        break;
      case 'ondclick':
        if(this.doubleClickEnabled)
          action = new MouseAction    (MouseAction    .DOUBLE_CLICK , data);
        break;
      case 'onmousedown':
        action = new MouseAction      (MouseAction    .MOUSE_DOWN   , data);
        break;
      case 'onmouseenter':
        action = new MouseAction      (MouseAction    .MOUSE_ENTER  , data);
        break;
      case 'onmouseleave':
        action = new MouseAction      (MouseAction    .MOUSE_LEAVE  , data);
        break;
      case 'onmousemove':
        action = new MouseAction      (MouseAction    .MOUSE_MOVE   , data);
        break;
      case 'onmouseover':
        action = new MouseAction      (MouseAction    .MOUSE_OVER   , data);
        break;
      case 'onmouseout':
        action = new MouseAction      (MouseAction    .MOUSE_OUT    , data);
        break;
      case 'onmouseup':
        action = new MouseAction      (MouseAction    .MOUSE_UP     , data);
        break;
      case 'onwheel':
        action = new MouseAction      (MouseAction    .WHEEL        , data);
        break;
      case 'onkeydown':
        action = new KeyboardAction   (KeyboardAction .KEY_DOWN     , data);
        break;
      case 'onkeypress':
        action = new KeyboardAction   (KeyboardAction .KEY_PRESS    , data);
        break;
      case 'onkeyup':
        action = new KeyboardAction   (KeyboardAction .KEY_UP       , data);
        break;
      case 'onblur':
        action = new FormAction       (FormAction     .BLUR         , data);
        break;
      case 'onchange':
        action = new FormAction       (FormAction     .CHANGE       , data);
        break;
      case 'onfocus':
        action = new FormAction       (FormAction     .FOCUS        , data);
        break;
      case 'onfocusin':
        action = new FormAction       (FormAction     .FOCUS_IN     , data);
        break;
      case 'onfocusout':
        action = new FormAction       (FormAction     .FOCUS_OUT    , data);
        break;
      case 'oninput':
        action = new FormAction       (FormAction     .INPUT        , data);
        break;
      case 'oninvalid':
        action = new FormAction       (FormAction     .INVALID      , data);
        break;
      case 'onreset':
        action = new FormAction       (FormAction     .RESET        , data);
        break;
      case 'onsearch':
        action = new FormAction       (FormAction     .SEARCH       , data);
        break;
      case 'onselect':
        action = new Action           (Action         .SELECT       , data);
        break;
      case 'oncopy':
        action = new Action           (Action         .COPY         , data);
        break;
      case 'oncut':
        action = new Action           (Action         .CUT          , data);
        break;
      case 'onpaste':
        action = new Action           (Action         .PASTE        , data);
        break;
      case 'ontouchcancel':
        action = new TouchAction      (TouchAction    .TOUCH_CANCEL , data);
        break;
      case 'ontouchend':
        action = new TouchAction      (TouchAction    .TOUCH_END    , data);
        break;
      case 'ontouchmove':
        action = new TouchAction      (TouchAction    .TOUCH_MOVE   , data);
        break;
      case 'ontouchstart':
        action = new TouchAction      (TouchAction    .TOUCH_BEGIN  , data);
        break;
    }

    if(action) {
      if(!this.mouseEnabled) {
        if(action instanceof MouseAction ||
           action instanceof KeyboardAction ||
           action instanceof FormAction) {
           return;
        }
      }

      this.dispatchAction(action);
    }
  }
}

export default Atom;
<commit_msg>fix(Atom): path to ComponentObject<commit_after>'use strict';

import Action from '../actions/Action';
import MouseAction from '../actions/MouseAction';
import KeyboardAction from '../actions/KeyboardAction';
import FormAction from '../actions/FormAction';
import TouchAction from '../actions/TouchAction';

import ComponentObject from './ComponentObject';

/**
 * The Atom class is the abstract base class for all component objects with
 * which the user can interact, using the mouse, keyboard, or other user input
 * device.
 *
 * You cannot instantiate the Atom class directly. A call to the new Atom()
 * constructor throws an ArgumentError exception.
 *
 * @constructor {name} Instance Name
 *
 */

class Atom extends ComponentObject {
  constructor(name) {
    super(name);

    if (new.target === Atom) {
      throw new TypeError("Yout cannot instantiate the Atom class directly");
    }

    /**
     * Specifies whether the object receives doubleClick actions.
     *
     */

    Object.defineProperty(this, 'doubleClickEnabled', {
      value: true
    });

    /**
     * Specifies whether this object receives mouse, or other user input,
     * messages.
     *
     * If mouseEnabled is set to false, the instance does not receive any mouse
     * actions (or other user input actions like keyboard actions).
     */

    Object.defineProperty(this, 'mouseEnabled', {
      value: true
    });

    /**
     * Specifies whether this object is in the tab order.
     *
     */

    Object.defineProperty(this, 'tabEnabled', {
      value: false
    });

    /**
     * Specifies the tab ordering.
     * The tabIndex property is -1 by default, meaning no tab index is set for
     * the object.
     *
     */

    Object.defineProperty(this, 'tabIndex', {
      value: -1
    });

    /**
     * Subscribe to DOM events after adding the component
     *
     */

    this.addActionListener(Action.ADDED, this.subscribeEvents, 0, true);
  }

  subscribeEvents(a) {
    this.view.addEventListener('onclick',       this.handleEventListener);
    this.view.addEventListener('ondclick',      this.handleEventListener);
    this.view.addEventListener('onmousedown',   this.handleEventListener);
    this.view.addEventListener('onmouseenter',  this.handleEventListener);
    this.view.addEventListener('onmouseleave',  this.handleEventListener);
    this.view.addEventListener('onmousemove',   this.handleEventListener);
    this.view.addEventListener('onmouseover',   this.handleEventListener);
    this.view.addEventListener('onmouseout',    this.handleEventListener);
    this.view.addEventListener('onmouseup',     this.handleEventListener);
    this.view.addEventListener('onwheel',       this.handleEventListener);
    this.view.addEventListener('onkeydown',     this.handleEventListener);
    this.view.addEventListener('onkeypress',    this.handleEventListener);
    this.view.addEventListener('onkeyup',       this.handleEventListener);
    this.view.addEventListener('onblur',        this.handleEventListener);
    this.view.addEventListener('onchange',      this.handleEventListener);
    this.view.addEventListener('onfocus',       this.handleEventListener);
    this.view.addEventListener('onfocusin',     this.handleEventListener);
    this.view.addEventListener('onfocusout',    this.handleEventListener);
    this.view.addEventListener('oninput',       this.handleEventListener);
    this.view.addEventListener('oninvalid',     this.handleEventListener);
    this.view.addEventListener('onreset',       this.handleEventListener);
    this.view.addEventListener('onsearch',      this.handleEventListener);
    this.view.addEventListener('onselect',      this.handleEventListener);
    this.view.addEventListener('oncopy',        this.handleEventListener);
    this.view.addEventListener('oncut',         this.handleEventListener);
    this.view.addEventListener('onpaste',       this.handleEventListener);
    this.view.addEventListener('ontouchcancel', this.handleEventListener);
    this.view.addEventListener('ontouchend',    this.handleEventListener);
    this.view.addEventListener('ontouchmove',   this.handleEventListener);
    this.view.addEventListener('ontouchstart',  this.handleEventListener);
  }

  /**
   * Handle Event Listener
   * Transform DOM Event into Action
   *
   * @param {e} Event
   *
   */

  handleEventListener(e) {
    let action = false;
    let data = {};

    switch (e.type) {
      case 'onclick':
        action = new MouseAction      (MouseAction    .CLICK        , data);
        break;
      case 'ondclick':
        if(this.doubleClickEnabled)
          action = new MouseAction    (MouseAction    .DOUBLE_CLICK , data);
        break;
      case 'onmousedown':
        action = new MouseAction      (MouseAction    .MOUSE_DOWN   , data);
        break;
      case 'onmouseenter':
        action = new MouseAction      (MouseAction    .MOUSE_ENTER  , data);
        break;
      case 'onmouseleave':
        action = new MouseAction      (MouseAction    .MOUSE_LEAVE  , data);
        break;
      case 'onmousemove':
        action = new MouseAction      (MouseAction    .MOUSE_MOVE   , data);
        break;
      case 'onmouseover':
        action = new MouseAction      (MouseAction    .MOUSE_OVER   , data);
        break;
      case 'onmouseout':
        action = new MouseAction      (MouseAction    .MOUSE_OUT    , data);
        break;
      case 'onmouseup':
        action = new MouseAction      (MouseAction    .MOUSE_UP     , data);
        break;
      case 'onwheel':
        action = new MouseAction      (MouseAction    .WHEEL        , data);
        break;
      case 'onkeydown':
        action = new KeyboardAction   (KeyboardAction .KEY_DOWN     , data);
        break;
      case 'onkeypress':
        action = new KeyboardAction   (KeyboardAction .KEY_PRESS    , data);
        break;
      case 'onkeyup':
        action = new KeyboardAction   (KeyboardAction .KEY_UP       , data);
        break;
      case 'onblur':
        action = new FormAction       (FormAction     .BLUR         , data);
        break;
      case 'onchange':
        action = new FormAction       (FormAction     .CHANGE       , data);
        break;
      case 'onfocus':
        action = new FormAction       (FormAction     .FOCUS        , data);
        break;
      case 'onfocusin':
        action = new FormAction       (FormAction     .FOCUS_IN     , data);
        break;
      case 'onfocusout':
        action = new FormAction       (FormAction     .FOCUS_OUT    , data);
        break;
      case 'oninput':
        action = new FormAction       (FormAction     .INPUT        , data);
        break;
      case 'oninvalid':
        action = new FormAction       (FormAction     .INVALID      , data);
        break;
      case 'onreset':
        action = new FormAction       (FormAction     .RESET        , data);
        break;
      case 'onsearch':
        action = new FormAction       (FormAction     .SEARCH       , data);
        break;
      case 'onselect':
        action = new Action           (Action         .SELECT       , data);
        break;
      case 'oncopy':
        action = new Action           (Action         .COPY         , data);
        break;
      case 'oncut':
        action = new Action           (Action         .CUT          , data);
        break;
      case 'onpaste':
        action = new Action           (Action         .PASTE        , data);
        break;
      case 'ontouchcancel':
        action = new TouchAction      (TouchAction    .TOUCH_CANCEL , data);
        break;
      case 'ontouchend':
        action = new TouchAction      (TouchAction    .TOUCH_END    , data);
        break;
      case 'ontouchmove':
        action = new TouchAction      (TouchAction    .TOUCH_MOVE   , data);
        break;
      case 'ontouchstart':
        action = new TouchAction      (TouchAction    .TOUCH_BEGIN  , data);
        break;
    }

    if(action) {
      if(!this.mouseEnabled) {
        if(action instanceof MouseAction ||
           action instanceof KeyboardAction ||
           action instanceof FormAction) {
           return;
        }
      }

      this.dispatchAction(action);
    }
  }
}

export default Atom;
<|endoftext|>


<commit_before>// @flow

import React, { PureComponent } from 'react';
import type { Match, RouterHistory } from 'react-router-dom';

import { previousMonth, nextMonth, today } from '../../../domain/calendar';

import Calendar from './component';
import makeCancelable from '../../make-cancelable';

type Props = {
  match: Match,
  history: RouterHistory,
};
type State = {
  selectedMonth: number,
  selectedYear: number,
  today: SimpleDate,
  entries: Array<SummarizedEntry>,
  shouldLoad: boolean,
  loading: boolean,
};

export default class CalendarContainer extends PureComponent<Props, State> {
  static getDerivedStateFromProps(nextProps: Props, prevState: State) {
    const fromPath = getDateFromPath(nextProps.match);

    const { year, month } = fromPath;
    return Object.assign(prevState, {
      selectedMonth: month,
      selectedYear: year,
      shouldLoad: true,
      loading: true,
    });
  }

  calendarFetch: ?CancelablePromise<Response>;

  constructor(props: Props) {
    super(props);

    const todayDate = today();
    this.state = {
      selectedMonth: todayDate.month,
      selectedYear: todayDate.year,
      today: todayDate,
      entries: [],
      shouldLoad: true,
      loading: true,
    };
    this.calendarFetch = null;
    (this: any).onKeyDown = this.onKeyDown.bind(this);
    (this: any).loadCalendar = this.loadCalendar.bind(this);
  }

  componentDidMount() {
    this.loadCalendar();
    window.addEventListener('keydown', this.onKeyDown);
  }

  componentDidUpdate() {
    if (this.state.shouldLoad) {
      this.loadCalendar();
    }
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.onKeyDown);
    this.cancelFetch();
  }

  onKeyDown(event: SyntheticKeyboardEvent<Document>) {
    if (hadModifierKey(event)) {
      return;
    }

    const { history } = this.props;
    const { selectedYear, selectedMonth } = this.state;
    switch (event.key) {
      case 'ArrowLeft':
        routeToPreviousMonth(history, selectedYear, selectedMonth);
        break;
      case 'ArrowRight':
        routeToNextMonth(history, selectedYear, selectedMonth);
        break;
      default:
        break;
    }
  }

  loadCalendar() {
    this.cancelFetch();
    this.fetchCalendar(this.state.selectedYear, this.state.selectedMonth);
  }

  fetchCalendar(year: number, month: number) {
    this.calendarFetch = makeCancelable(
      fetch(`/api/calendar/${year}/${month}`),
    );

    this.calendarFetch.promise
      .then(res => res.json())
      .then(entries =>
        this.setState({ entries, shouldLoad: false, loading: false }))
      .catch(() => {});
  }

  cancelFetch() {
    if (this.calendarFetch != null) {
      this.calendarFetch.cancel();
    }
  }

  render() {
    return <Calendar {...this.state} />;
  }
}

function getDateFromPath(match: Match): { year: number, month: number } {
  return {
    year: parseFloat(match.params.year),
    month: parseFloat(match.params.month),
  };
}

function routeToPreviousMonth(
  history: RouterHistory,
  currentYear: number,
  currentMonth: number,
) {
  const { year, month } = previousMonth(currentYear, currentMonth);
  history.push(getCalendarPath(year, month));
}

function routeToNextMonth(
  history: RouterHistory,
  currentYear: number,
  currentMonth: number,
) {
  const { year, month } = nextMonth(currentYear, currentMonth);
  history.push(getCalendarPath(year, month));
}

function getCalendarPath(year: number, month: number): string {
  return `/calendar/${year}/${month}`;
}

function hadModifierKey(event: SyntheticKeyboardEvent<*>) {
  return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey;
}
<commit_msg>Only show loading icon for calender if slow load<commit_after>// @flow

import React, { PureComponent } from 'react';
import type { Match, RouterHistory } from 'react-router-dom';

import { previousMonth, nextMonth, today } from '../../../domain/calendar';

import Calendar from './component';
import makeCancelable from '../../make-cancelable';

type Props = {
  match: Match,
  history: RouterHistory,
};
type State = {
  selectedMonth: number,
  selectedYear: number,
  today: SimpleDate,
  entries: Array<SummarizedEntry>,
  shouldLoad: boolean,
  loading: boolean,
};

export default class CalendarContainer extends PureComponent<Props, State> {
  static getDerivedStateFromProps(nextProps: Props, prevState: State) {
    const fromPath = getDateFromPath(nextProps.match);

    const { year, month } = fromPath;
    return Object.assign(prevState, {
      selectedMonth: month,
      selectedYear: year,
      shouldLoad: true,
      loading: prevState.loading,
    });
  }

  loadingTimer: ?TimeoutID;
  calendarFetch: ?CancelablePromise<Response>;

  constructor(props: Props) {
    super(props);

    const todayDate = today();
    this.state = {
      selectedMonth: todayDate.month,
      selectedYear: todayDate.year,
      today: todayDate,
      entries: [],
      shouldLoad: true,
      loading: true,
    };

    this.loadingTimer = null;
    this.calendarFetch = null;
    (this: any).onKeyDown = this.onKeyDown.bind(this);
    (this: any).loadCalendar = this.loadCalendar.bind(this);
  }

  componentDidMount() {
    this.loadCalendar();
    window.addEventListener('keydown', this.onKeyDown);
  }

  componentDidUpdate() {
    if (this.state.shouldLoad) {
      this.loadCalendar();
    }
  }

  componentWillUnmount() {
    window.removeEventListener('keydown', this.onKeyDown);
    this.cancelFetch();
  }

  onKeyDown(event: SyntheticKeyboardEvent<Document>) {
    if (hadModifierKey(event)) {
      return;
    }

    const { history } = this.props;
    const { selectedYear, selectedMonth } = this.state;
    switch (event.key) {
      case 'ArrowLeft':
        routeToPreviousMonth(history, selectedYear, selectedMonth);
        break;
      case 'ArrowRight':
        routeToNextMonth(history, selectedYear, selectedMonth);
        break;
      default:
        break;
    }
  }

  loadCalendar() {
    this.cancelFetch();
    this.fetchCalendar(this.state.selectedYear, this.state.selectedMonth);
  }

  fetchCalendar(year: number, month: number) {
    this.loadingTimer = setTimeout(() => this.setState({ loading: true }), 50);

    this.calendarFetch = makeCancelable(
      fetch(`/api/calendar/${year}/${month}`),
    );

    this.calendarFetch.promise
      .then(res => res.json())
      .then((entries) => {
        this.cancelFetch();
        this.setState({ entries, shouldLoad: false, loading: false });
      })
      .catch(() => {});
  }

  cancelFetch() {
    if (this.loadingTimer != null) {
      clearTimeout(this.loadingTimer);
    }
    if (this.calendarFetch != null) {
      this.calendarFetch.cancel();
    }
  }

  render() {
    return <Calendar {...this.state} />;
  }
}

function getDateFromPath(match: Match): { year: number, month: number } {
  return {
    year: parseFloat(match.params.year),
    month: parseFloat(match.params.month),
  };
}

function routeToPreviousMonth(
  history: RouterHistory,
  currentYear: number,
  currentMonth: number,
) {
  const { year, month } = previousMonth(currentYear, currentMonth);
  history.push(getCalendarPath(year, month));
}

function routeToNextMonth(
  history: RouterHistory,
  currentYear: number,
  currentMonth: number,
) {
  const { year, month } = nextMonth(currentYear, currentMonth);
  history.push(getCalendarPath(year, month));
}

function getCalendarPath(year: number, month: number): string {
  return `/calendar/${year}/${month}`;
}

function hadModifierKey(event: SyntheticKeyboardEvent<*>) {
  return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey;
}
<|endoftext|>


<commit_before>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminPage");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserPermissionsTitle");}, gvm);

    gvm.userName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserName");}, gvm);
    gvm.firstName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Firstname");}, gvm);
    gvm.lastName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Lastname");}, gvm);
    gvm.userPermissions = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserPermissions");}, gvm);
    gvm.userActions = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserActions");}, gvm);

    gvm.permissionRole = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionRole");}, gvm);
    gvm.permissionDescription = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionDescription");}, gvm);
    fetchUsersData();

    gvm.usersPermissions = ko.observableArray([]);

    gvm.updateUsersPermissions = function(user)
    {
        console.log(user);
        gvm.usersPermissions.push(user);
    }
}

function fetchUsersData()
{
    $.getJSON("/api/alluserswithroles/", function(data)
    {
        var addedUsername = "";
        $.each(data, function(i, item){
            var permissions = "";
            var current = item.username;
            $.each(data, function(i, item)
            {
                if(item.username == current){
                    permissions += item.role + " - ";
                }
            });

            permissions = permissions.substr(0, permissions.length - 3);

            if (addedUsername != current){
                addedUsername = item.username;
                viewModel.updateUsersPermissions(new User(item.userid, item.username, item.firstname, item.lastname, permissions));
            }
        });
    });
}

function User(id, username, firstname, lastname, permissions) {
    return {
        id: ko.observable(id),
        username: ko.observable(username),
        firstname: ko.observable(firstname),
        lastname: ko.observable(lastname),
        permissions: ko.observable(permissions),
    };
}<commit_msg>Admin edit user<commit_after>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminPage");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserPermissionsTitle");}, gvm);

    gvm.userName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserName");}, gvm);
    gvm.firstName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Firstname");}, gvm);
    gvm.lastName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Lastname");}, gvm);
    gvm.userPermissions = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserPermissions");}, gvm);
    gvm.userActions = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserActions");}, gvm);

    gvm.permissionRole = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionRole");}, gvm);
    gvm.permissionDescription = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionDescription");}, gvm);
    fetchUsersData();

    gvm.usersPermissions = ko.observableArray([]);

    gvm.updateUsersPermissions = function(user)
    {
        console.log(user);
        gvm.usersPermissions.push(user);
    }
}

function fetchUsersData()
{
    $.getJSON("/api/alluserswithroles/", function(data)
    {
        var addedUsername = "";
        $.each(data, function(i, item){
            var permissions = "";
            var current = item.username;
            $.each(data, function(i, item)
            {
                if(item.username == current){
                    permissions += item.role + " - ";
                }
            });

            permissions = permissions.substr(0, permissions.length - 3);

            if (permissions == null){
                permissions = "Nog geen rechten toegekend";
            }

            if (addedUsername != current){
                addedUsername = item.username;
                viewModel.updateUsersPermissions(new User(item.userid, item.username, item.firstname, item.lastname, permissions));
            }
        });
    });
}

function User(id, username, firstname, lastname, permissions) {
    return {
        id: ko.observable(id),
        username: ko.observable(username),
        firstname: ko.observable(firstname),
        lastname: ko.observable(lastname),
        permissions: ko.observable(permissions),
    };
}<|endoftext|>


<commit_before>const MAX_SLIDES = 2
const literalNumbers = ['one', 'two', 'three', 'four', 'five', 'six']

// Preload images and randomly rotate
if (window.location.pathname === '/') {
	const hero = document.getElementsByClassName('hero-slide')[0]
	hero.classList.add('fade')
	// Slide in Hero Text
	for (let i = 0; i++; i<3) {
		const title = document.getElementsByClassName('hero-slide-title ' + literalNumbers[i])[0]
		title.classList.add('fade-slide')
	}
}<commit_msg>Added hero image onload.<commit_after>const MAX_SLIDES = 2
const literalNumbers = ['one', 'two', 'three', 'four', 'five', 'six']

// Preload images and randomly rotate
if (window.location.pathname === '/') {
	const hero = document.getElementsByClassName('hero-slide')[0]
	hero.classList.add('fade')
	// Slide in Hero Text
	for (let i = 0; i++; i<3) {
		const title = document.getElementsByClassName('hero-slide-title ' + literalNumbers[i])[0]
		title.classList.add('fade-slide')
		const title2 = document.getElementsByClassName('hero-slide-title ' + literalNumbers[i])[1]
		title2.classList.add('fade-slide')
	}
}<|endoftext|>


<commit_before>define(
        "sb/base/binding/PropagationGuardian",
        [
        ],
        function() {

                /**
                 * @class PropagationGuardian
                 * @constructor
                 * @namespace sb.base.binding
                 * @param {function():boolean} continueCondition
                 * @param {number} timeout
                 */
                function PropagationGuardian(continueCondition, timeout) {

                        if (typeof continueCondition !== "function") {
                                continueCondition = function() {
                                        return true;
                                };
                        }

                        if (typeof timeout !== "number"
                            || timeout <= 0) {
                                    timeout = 1;
                            }

                            /**
                             * @method createPropagation
                             * @public
                             */
                            this.createPropagation = function() {

                                    /**
                                     * Call Stack of observable.
                                     * @property callStack
                                     * @private
                                     * @for Propagation
                                     * @type Array
                                     */
                                    var callStack = [];

                                    /**
                                     * Test propagation is success with given continueCondition and timeout.
                                     * @class Propagation
                                     * @namespace sb.base.binding
                                     * @param {sb.base.binding.ObservableObject} source adjacent source of notify propagation
                                     * @param {sb.base.binding.NotificationEvent} e event object.
                                     */
                                    var propagation =  function(source, e) {

                                            /**
                                             * Get callStack of this propagation.
                                             * @method callStack
                                             * @public
                                             * @return {Array}
                                             */
                                            propagation.callStack = function() {
                                                    return callStack.concat();
                                            };

                                            /**
                                             * Get source observable.
                                             * @method getSource
                                             * @public
                                             * @return {sb.base.binding.ObservableObject}
                                             */
                                            propagation.getSource = function() {
                                                    return source;
                                            };

                                            /**
                                             * Get event object.
                                             * @method getEventObject
                                             * @public
                                             * @return {sb.base.binding.NotificationEvent}
                                             */
                                            propagation.getEventObject = function() {
                                                    return e;
                                            };

                                            // Counter for number of appearance
                                            // of same observable in callstack.
                                            var loopCount = 0;
                                            callStack.forEach(function(o) {
                                                    if (o === source) {
                                                            loopCount++;
                                                    }
                                            });

                                            // either loopCounter over timeout
                                            if (timeout <= loopCount) {
                                                    return false;
                                            }

                                            if (!continueCondition(source, e)) {
                                                    return false;
                                            }

                                            callStack.push(source);

                                            return true;
                                    };

                                    return propagation;
                            };
                };

                return PropagationGuardian;
        }
);
<commit_msg>pass lint<commit_after>define(
        "sb/base/binding/PropagationGuardian",
        [
        ],
        function() {

                /**
                 * @class PropagationGuardian
                 * @constructor
                 * @namespace sb.base.binding
                 * @param {function():boolean} continueCondition
                 * @param {number} timeout
                 */
                function PropagationGuardian(continueCondition, timeout) {

                        if (typeof continueCondition !== "function") {
                                continueCondition = function() {
                                        return true;
                                };
                        }

                        if (typeof timeout !== "number" ||
                            timeout <= 0) {
                                    timeout = 1;
                            }

                            /**
                             * @method createPropagation
                             * @public
                             */
                            this.createPropagation = function() {

                                    /**
                                     * Call Stack of observable.
                                     * @property callStack
                                     * @private
                                     * @for Propagation
                                     * @type Array
                                     */
                                    var callStack = [];

                                    /**
                                     * Test propagation is success with given continueCondition and timeout.
                                     * @class Propagation
                                     * @namespace sb.base.binding
                                     * @param {sb.base.binding.ObservableObject} source adjacent source of notify propagation
                                     * @param {sb.base.binding.NotificationEvent} e event object.
                                     */
                                    var propagation =  function(source, e) {

                                            /**
                                             * Get callStack of this propagation.
                                             * @method callStack
                                             * @public
                                             * @return {Array}
                                             */
                                            propagation.callStack = function() {
                                                    return callStack.concat();
                                            };

                                            /**
                                             * Get source observable.
                                             * @method getSource
                                             * @public
                                             * @return {sb.base.binding.ObservableObject}
                                             */
                                            propagation.getSource = function() {
                                                    return source;
                                            };

                                            /**
                                             * Get event object.
                                             * @method getEventObject
                                             * @public
                                             * @return {sb.base.binding.NotificationEvent}
                                             */
                                            propagation.getEventObject = function() {
                                                    return e;
                                            };

                                            // Counter for number of appearance
                                            // of same observable in callstack.
                                            var loopCount = 0;
                                            callStack.forEach(function(o) {
                                                    if (o === source) {
                                                            loopCount++;
                                                    }
                                            });

                                            // either loopCounter over timeout
                                            if (timeout <= loopCount) {
                                                    return false;
                                            }

                                            if (!continueCondition(source, e)) {
                                                    return false;
                                            }

                                            callStack.push(source);

                                            return true;
                                    };

                                    return propagation;
                            };
                }

                return PropagationGuardian;
        }
);
<|endoftext|>


<commit_before>var mongoose = require('mongoose'),
	Schema = mongoose.Schema,
	Card = require('./CardModel'),
	DeckSchema = new Schema({
		type: {
			type: String,
			required: true
		},
		cards: [{
			type: Schema.Types.ObjectId,
			ref: 'Card'
		}]
	}, {
		collection: 'decks',
		timestamps: true,
		toObject: {
			virtuals: true
		},
		toJSON: {
			virtuals: true
		}
	});

module.exports = {
	schema: DeckSchema,
	model: mongoose.model('Deck', DeckSchema)
};
<commit_msg>Change 'type' to 'deckType' for DeckModel to avoid issues with reserved word<commit_after>var mongoose = require('mongoose'),
	Schema = mongoose.Schema,
	Card = require('./CardModel'),
	DeckSchema = new Schema({
		deckType: {
			type: String,
			required: true
		},
		cards: [{
			type: Schema.Types.ObjectId,
			ref: 'Card'
		}]
	}, {
		collection: 'decks',
		timestamps: true,
		toObject: {
			virtuals: true
		},
		toJSON: {
			virtuals: true
		}
	});

module.exports = {
	schema: DeckSchema,
	model: mongoose.model('Deck', DeckSchema)
};
<|endoftext|>


<commit_before>function colorBasedOnState(tile) {
    var normalizedValue = Math.floor(tile.density * 255);
    var intensity = (normalizedValue).toString(16);
    if (tile.infected) {
        return '#00' + intensity + '00';
    } else {
        return '#' + intensity + '0000';
    }
}

var game = {};
game.running = false;
game.map = {};
game.map.tiles = [];

function setUp() {
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    var width = canvas.width;
    var height = canvas.height;
    var squaresInRow = 20;
    context.fillRect(0, 0, width, height);
    if (width !== height || width < 0) {
        throw Error('Expected a square canvas.');
    }
    if (width % squaresInRow !== 0) {
        throw Error('Expected the side of the canvas to be a multiple of 20.');
    }
    var canvasSide = width;
    var squareSide = width / squaresInRow;
    for (var y = 0; y <= canvasSide - squareSide; y += squareSide) {
        var tileRow = [];
        for (var x = 0; x <= canvasSide - squareSide; x += squareSide) {
            var tile = {'density': Math.random() * 0.5, 'infected': false};
            tileRow.push(tile);
            context.fillStyle = colorBasedOnState(tile);
            context.fillRect(x, y, squareSide, squareSide);
        }
        game.map.tiles.push(tileRow);
    }

    canvas.addEventListener('click', function (e) {
        if (!game.running) {
            var pos = getMousePos(canvas, e);
            var x = pos.x;
            var y = pos.y;
            console.log('Got a mouse click at (' + x + ', ' + y + ')');
        }
    }, false);
}

function getMousePos(canvas, event) {
    var rectangle = canvas.getBoundingClientRect();
    return {
        x: event.clientX - rectangle.left,
        y: event.clientY - rectangle.top
    };
}

(function () {
    setUp();
    var tickLength = 200; // 200 milliseconds.
    function main(timeFrame) {
        window.requestAnimationFrame(main);
    }

    main();
})();
<commit_msg>Wrote function to translate mouse position to tile<commit_after>function colorBasedOnState(tile) {
    var normalizedValue = Math.floor(tile.density * 255);
    var intensity = (normalizedValue).toString(16);
    if (tile.infected) {
        return '#00' + intensity + '00';
    } else {
        return '#' + intensity + '0000';
    }
}

var game = {};

function setUp() {
    game.running = false;
    game.map = {};
    game.map.tiles = [];
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    var width = canvas.width;
    var height = canvas.height;
    var tilesPerRow = game.tilesPerRow = 20;
    context.fillRect(0, 0, width, height);
    if (width !== height || width < 0) {
        throw Error('Expected a square canvas.');
    }
    if (width % tilesPerRow !== 0) {
        throw Error('Expected the side of the canvas to be a multiple of 20.');
    }
    var canvasSide = width;
    var squareSide = width / tilesPerRow;
    for (var y = 0; y <= canvasSide - squareSide; y += squareSide) {
        var tileRow = [];
        for (var x = 0; x <= canvasSide - squareSide; x += squareSide) {
            var tile = {'density': Math.random() * 0.5, 'infected': false};
            tileRow.push(tile);
            context.fillStyle = colorBasedOnState(tile);
            context.fillRect(x, y, squareSide, squareSide);
        }
        game.map.tiles.push(tileRow);
    }

    canvas.addEventListener('click', function (event) {
        if (!game.running) {
            var mousePosition = getMousePosition(canvas, event);
            var tilePosition = translateToTilePosition(canvas, mousePosition, tilesPerRow);
            var x = mousePosition.x;
            var y = mousePosition.y;
            console.log('Got a mouse click at (' + x + ', ' + y + '). Tile is (' + tilePosition.x + ', ' + tilePosition.y + ')');
        }
    }, false);
}

function getMousePosition(canvas, event) {
    var rectangle = canvas.getBoundingClientRect();
    return {
        x: event.clientX - rectangle.left,
        y: event.clientY - rectangle.top
    };
}

function translateToTilePosition(canvas, position, tilesPerRow) {
    var tileWidth = canvas.width / tilesPerRow;
    var tileHeight = canvas.height / tilesPerRow;
    return {x: Math.floor(position.x / tileWidth), y: Math.floor(position.y / tileHeight)};
}

(function () {
    setUp();
    var tickLength = 200; // 200 milliseconds.
    function main(timeFrame) {
        window.requestAnimationFrame(main);
    }

    main();
})();
<|endoftext|>


<commit_before>'use strict';

if (!process.env.BASE_DIR) {
    process.env.BASE_DIR = __dirname;
}
require('elyoos-server-lib').init('elyoos');

global.requireDb = function () {
    return require('elyoos-server-lib').neo4j;
};

global.requireModel = function (name) {
    return require(`${__dirname}/api/models/${name}`);
};

require('elyoos-server-lib').jsonValidation;
const Promise = require('bluebird');
Promise.promisifyAll(require('gm').prototype);

Promise.Promise.config({warnings: false, longStackTraces: true, cancellation: true});
const isDevelopment = process.env.NODE_ENV === 'development';
const isProduction = process.env.NODE_ENV === 'production';

const {Nuxt, Builder} = require('nuxt');
let nuxt = null;
if(isProduction || isDevelopment) {
    const nuxtConfig = require('./nuxt.config.js');
    nuxt = new Nuxt(nuxtConfig);
}
const kraken = require('kraken-js');
const emailService = require('./api/models/eMailService/eMail');
const dbConfig = require('elyoos-server-lib').databaseConfig;
const app = require('express')();
const options = require('elyoos-server-lib').spec(app, nuxt);
const logger = require('elyoos-server-lib').logging.getLogger(__filename);
const port = process.env.PORT || 3000;

if (isProduction || isDevelopment) {
    app.set('trust proxy', 1);
    logger.info('Enabled trust proxy');
}

if (isDevelopment) {
    new Builder(nuxt).build()
        .then(listen)
        .catch((error) => {
            console.error(error);
            process.exit(1);
        })
} else {
    listen();
}

app.use(kraken(options));

function listen() {
    app.listen(port, function (err) {
        if (err) {
            logger.fatal('Server failed to start', {message: err});
        } else {
            logger.info('[' + app.settings.env + '] Listening on http://localhost:' + port);
        }
    });
}

app.on('start', function () {
    dbConfig.connected.then(function () {
        emailService.start();
        logger.info('Server started');
    });
});

app.on('exit', function () {
    requireDb().closeDriver();
});

module.exports = app;

<commit_msg>Use kraken before listen.<commit_after>'use strict';

if (!process.env.BASE_DIR) {
    process.env.BASE_DIR = __dirname;
}
require('elyoos-server-lib').init('elyoos');

global.requireDb = function () {
    return require('elyoos-server-lib').neo4j;
};

global.requireModel = function (name) {
    return require(`${__dirname}/api/models/${name}`);
};

require('elyoos-server-lib').jsonValidation;
const Promise = require('bluebird');
Promise.promisifyAll(require('gm').prototype);

Promise.Promise.config({warnings: false, longStackTraces: true, cancellation: true});
const isDevelopment = process.env.NODE_ENV === 'development';
const isProduction = process.env.NODE_ENV === 'production';

const {Nuxt, Builder} = require('nuxt');
let nuxt = null;
if(isProduction || isDevelopment) {
    const nuxtConfig = require('./nuxt.config.js');
    nuxt = new Nuxt(nuxtConfig);
}
const kraken = require('kraken-js');
const emailService = require('./api/models/eMailService/eMail');
const dbConfig = require('elyoos-server-lib').databaseConfig;
const app = require('express')();
const options = require('elyoos-server-lib').spec(app, nuxt);
const logger = require('elyoos-server-lib').logging.getLogger(__filename);
const port = process.env.PORT || 3000;

if (isProduction || isDevelopment) {
    app.set('trust proxy', 1);
    logger.info('Enabled trust proxy');
}

app.use(kraken(options));

app.on('start', function () {
    dbConfig.connected.then(function () {
        emailService.start();
        logger.info('Server started');
    });
});

app.on('exit', function () {
    requireDb().closeDriver();
});

if (isDevelopment) {
    new Builder(nuxt).build()
        .then(listen)
        .catch((error) => {
            console.error(error);
            process.exit(1);
        })
} else {
    listen();
}

function listen() {
    app.listen(port, function (err) {
        if (err) {
            logger.fatal('Server failed to start', {message: err});
        } else {
            logger.info('[' + app.settings.env + '] Listening on http://localhost:' + port);
        }
    });
}

module.exports = app;

<|endoftext|>


<commit_before>define([
	"dojo/_base/declare", "dojo/_base/lang",
	"dojo/dom-construct", "dojo/request",
	"./TabViewerBase",
	"../GenomeOverview", "../AMRPanelGridContainer", "../Phylogeny",
	"../GenomeBrowser", "../CircularViewerContainer", "../SequenceGridContainer",
	"../FeatureGridContainer", "../SpecialtyGeneGridContainer", "../ProteinFamiliesContainer",
	"../PathwaysContainer", "../TranscriptomicsContainer", "../InteractionContainer",
	"../../util/PathJoin"
], function(declare, lang,
			domConstruct, xhr,
			TabViewerBase,
			GenomeOverview, AMRPanelGridContainer, Phylogeny,
			GenomeBrowser, CircularViewerContainer, SequenceGridContainer,
			FeatureGridContainer, SpecialtyGeneGridContainer, ProteinFamiliesContainer,
			PathwaysContainer, TranscriptomicsContainer, InteractionsContainer,
			PathJoin){
	return declare([TabViewerBase], {
		"baseClass": "GenomeGroup",
		"disabled": false,
		containerType: "genome_group",
		genome_id: "",
		perspectiveLabel: "Genome View",
		perspectiveIconClass: "icon-selection-Genome",

		_setGenome_idAttr: function(id){
			// console.log("_setGenome_IDAttr: ", id, this.genome_id);
			if(!id){
				return;
			}

			if(this.genome_id == id){
				// console.log("Genome ID Already Set");
				return;
			}

			this.genome_id = this.state.genome_id = id;
			this.state.genome_ids = [id];

			xhr.get(PathJoin(this.apiServiceUrl, "genome", id), {
				headers: {
					accept: "application/json",
					'X-Requested-With': null,
					'Authorization': (window.App.authorizationToken || "")
				},
				handleAs: "json"
			}).then(lang.hitch(this, function(genome){
				this.set("genome", genome)
			}));

		},

		setActivePanelState: function(){
			var activeQueryState;
			// console.log("Set ActivePanelState: ", JSON.stringify(this.state,null,4));
			if(this.state.genome_id){
				activeQueryState = lang.mixin({}, this.state, {search: "eq(genome_id," + this.state.genome_id + ")"});
			}
			var active = (this.state && this.state.hashParams && this.state.hashParams.view_tab) ? this.state.hashParams.view_tab : "overview";
			var activeTab = this[active];
			// console.log("Active Panel: ", active);

			switch(active){
				case "phylogeny":
				case "overview":
					if(this.state.genome){
						activeTab.set("state", lang.mixin({}, this.state));
					}
					break;
				case "transcriptomics":
					activeTab.set("state", lang.mixin({}, this.state, {search: "eq(genome_ids," + this.genome_id + ")"}));
					break;
				case "proteinFamilies":
					// do not set state, the container is built by setVisible already
					break;
				case "interactions":
					activeTab.set("state", lang.mixin({}, this.state, {
						search: "or(eq(genome_id_a," + this.genome_id + "),eq(genome_id_b," + this.genome_id + "))"
					}));
					break;
				default:
					if(activeQueryState){
						// console.log("Using Default ActiveQueryState: ", activeQueryState);
						activeTab.set("state", activeQueryState);
					}else{
						console.log("Missing Active Query State for: ", active)
					}
					break;
			}

			if(this.genome){
				var pageTitle = this.genome.genome_name + "::Genome " + activeTab.title;
				// console.log("Genome setActivePanelState: ", pageTitle);
				if(window.document.title !== pageTitle){
					window.document.title = pageTitle;
				}
			}
		},

		buildHeaderContent: function(genome){

			xhr.get(PathJoin(this.apiServiceUrl, "taxonomy", genome.taxon_id), {
				headers: {
					accept: "application/json"
				},
				handleAs: "json"
			}).then(lang.hitch(this, function(taxon){
				var taxon_lineage_names = taxon.lineage_names;
				var taxon_lineage_ids = taxon.lineage_ids;
				var taxon_lineage_ranks = taxon.lineage_ranks;

				var visibleRanks = ["superkingdom", "phylum", "class", "order", "family", "genus", "species"];
				var visibleIndexes = taxon_lineage_ranks.filter(function(rank){
					return visibleRanks.indexOf(rank) > -1;
				}).map(function(rank){
					return taxon_lineage_ranks.indexOf(rank);
				});

				var out = visibleIndexes.map(function(idx){
					return '' + taxon_lineage_names[idx] + '';
				});
				this.queryNode.innerHTML = out.join(" » ") + " » " + '' + genome.genome_name + '';
			}));
		},

		_setGenomeAttr: function(genome){
			this.state.genome = genome;

			this.buildHeaderContent(genome);
			domConstruct.empty(this.totalCountNode);

			this._set("genome", genome);
			this.setActivePanelState();
			this.resize();
		},

		onSetState: function(attr, oldState, state){

			var parts = state.pathname.split("/");
			this.set("genome_id", parts[parts.length - 1]);
			state.genome_id = parts[parts.length - 1];
			state.genome_ids = [state.genome_id];
			if(!state){
				return;
			}

			// console.log("Genome: ", state.genome, state.genome_id)

			if(state && state.genome_id && !state.genome){
				// console.log("No state.genome.  state.genome_id: ", state.genome_id);
				if(oldState && oldState.genome_id){
					// console.log("oldState.genome_id: ", oldState.genome_id)

					if((state.genome_id == oldState.genome_id)){
						if(oldState.genome || this.genome){
							// console.log("oldState Genome: ", oldState.genome || this.genome);
							state.genome = oldState.genome || this.genome;
						}else{
							console.log("oldState missing Genome");
						}
					}
				}
			}

			if(state.hashParams && state.hashParams.view_tab){

				if(this[state.hashParams.view_tab]){
					var vt = this[state.hashParams.view_tab];

					if(state.hashParams.view_tab === "proteinFamilies"){
						// state.hashParams = lang.mixin({}, state.hashParams, {
						// 	params: JSON.stringify({"family_type": "plfam"})
						// });

						this.proteinFamilies.state = lang.mixin({}, state, {
							hashParams: lang.mixin({}, state.hashParams, {
								params: encodeURIComponent(JSON.stringify({"family_type": "plfam"}))
							})
						});
					}

					vt.set("visible", true);
					this.viewer.selectChild(vt);
				}else{
					// console.log("No view-tab supplied in State Object");
				}
			}

			this.setActivePanelState();

			// console.log("viewer/Genome onSetState() after set genome_id")
		},

		postCreate: function(){
			if(!this.state){
				this.state = {};
			}

			this.inherited(arguments);

			this.overview = new GenomeOverview({
				title: "Overview",
				id: this.viewer.id + "_" + "overview",
				state: this.state
			});

			this.phylogeny = new Phylogeny({
				title: "Phylogeny",
				id: this.viewer.id + "_" + "phylogeny"
			});

			this.sequences = new SequenceGridContainer({
				title: "Sequences",
				id: this.viewer.id + "_" + "sequences",
				state: lang.mixin({}, this.state, {search: "?eq(genome_id," + this.genome_id + ")"})
			});

			this.amr = new AMRPanelGridContainer({
				title: "AMR Phenotypes",
				id: this.viewer.id + "_" + "amr"
			});

			this.features = new FeatureGridContainer({
				title: "Features",
				id: this.viewer.id + "_" + "features",
				state: lang.mixin({}, this.state, {search: "?eq(genome_id," + this.genome_id + ")"})
			});

			this.browser = new GenomeBrowser({
				title: "Genome Browser",
				id: this.viewer.id + "_" + "browser",
				state: lang.mixin({}, this.state),
				tooltip: 'The "Browser" tab shows genome sequence and genomic features using linear genome browser'
			});

			this.circular = new CircularViewerContainer({
				title: "Circular Viewer",
				id: this.viewer.id + "_" + "circular",
				state: lang.mixin({}, this.state)
			});

			this.specialtyGenes = new SpecialtyGeneGridContainer({
				title: "Specialty Genes",
				id: this.viewer.id + "_" + "specialtyGenes",
				state: lang.mixin({}, this.state, {search: "?eq(genome_id," + this.genome_id + ")"})
			});

			this.pathways = new PathwaysContainer({
				apiServer: this.apiServiceUrl,
				title: "Pathways",
				id: this.viewer.id + "_" + "pathways",
				state: this.state
			});

			this.proteinFamilies = new ProteinFamiliesContainer({
				title: "Protein Families",
				id: this.viewer.id + "_" + "proteinFamilies",
				state: this.state
			});

			this.transcriptomics = new TranscriptomicsContainer({
				title: "Transcriptomics",
				id: this.viewer.id + "_" + "transcriptomics",
				state: this.state
			});

			this.interactions = new InteractionsContainer({
				title: "Interactions",
				id: this.viewer.id + "_" + "interactions",
				state: this.state
			});

			this.viewer.addChild(this.overview);
			this.viewer.addChild(this.amr);
			this.viewer.addChild(this.phylogeny);
			this.viewer.addChild(this.browser);
			this.viewer.addChild(this.circular);
			this.viewer.addChild(this.sequences);
			this.viewer.addChild(this.features);
			this.viewer.addChild(this.specialtyGenes);
			this.viewer.addChild(this.proteinFamilies);
			this.viewer.addChild(this.pathways);
			this.viewer.addChild(this.transcriptomics);
			this.viewer.addChild(this.interactions);
		}
	});
});
<commit_msg>Bug fix for Remove the Circular Viewer tab for the host genomes #1474<commit_after>define([
	"dojo/_base/declare", "dojo/_base/lang",
	"dojo/dom-construct", "dojo/request",
	"./TabViewerBase",
	"../GenomeOverview", "../AMRPanelGridContainer", "../Phylogeny",
	"../GenomeBrowser", "../CircularViewerContainer", "../SequenceGridContainer",
	"../FeatureGridContainer", "../SpecialtyGeneGridContainer", "../ProteinFamiliesContainer",
	"../PathwaysContainer", "../TranscriptomicsContainer", "../InteractionContainer",
	"../../util/PathJoin"
], function(declare, lang,
			domConstruct, xhr,
			TabViewerBase,
			GenomeOverview, AMRPanelGridContainer, Phylogeny,
			GenomeBrowser, CircularViewerContainer, SequenceGridContainer,
			FeatureGridContainer, SpecialtyGeneGridContainer, ProteinFamiliesContainer,
			PathwaysContainer, TranscriptomicsContainer, InteractionsContainer,
			PathJoin){
	return declare([TabViewerBase], {
		"baseClass": "GenomeGroup",
		"disabled": false,
		containerType: "genome_group",
		genome_id: "",
		perspectiveLabel: "Genome View",
		perspectiveIconClass: "icon-selection-Genome",

		_setGenome_idAttr: function(id){
			// console.log("_setGenome_IDAttr: ", id, this.genome_id);
			if(!id){
				return;
			}

			if(this.genome_id == id){
				// console.log("Genome ID Already Set");
				return;
			}

			this.genome_id = this.state.genome_id = id;
			this.state.genome_ids = [id];

			xhr.get(PathJoin(this.apiServiceUrl, "genome", id), {
				headers: {
					accept: "application/json",
					'X-Requested-With': null,
					'Authorization': (window.App.authorizationToken || "")
				},
				handleAs: "json"
			}).then(lang.hitch(this, function(genome){
				this.set("genome", genome)
			}));

		},

		setActivePanelState: function(){
			var activeQueryState;
			// console.log("Set ActivePanelState: ", JSON.stringify(this.state,null,4));
			if(this.state.genome_id){
				activeQueryState = lang.mixin({}, this.state, {search: "eq(genome_id," + this.state.genome_id + ")"});
			}
			var active = (this.state && this.state.hashParams && this.state.hashParams.view_tab) ? this.state.hashParams.view_tab : "overview";
			var activeTab = this[active];
			// console.log("Active Panel: ", active);

			switch(active){
				case "phylogeny":
				case "overview":
					if(this.state.genome){
						activeTab.set("state", lang.mixin({}, this.state));
					}
					break;
				case "transcriptomics":
					activeTab.set("state", lang.mixin({}, this.state, {search: "eq(genome_ids," + this.genome_id + ")"}));
					break;
				case "proteinFamilies":
					// do not set state, the container is built by setVisible already
					break;
				case "interactions":
					activeTab.set("state", lang.mixin({}, this.state, {
						search: "or(eq(genome_id_a," + this.genome_id + "),eq(genome_id_b," + this.genome_id + "))"
					}));
					break;
				default:
					if(activeQueryState){
						// console.log("Using Default ActiveQueryState: ", activeQueryState);
						activeTab.set("state", activeQueryState);
					}else{
						console.log("Missing Active Query State for: ", active)
					}
					break;
			}

			if(this.genome){
				var pageTitle = this.genome.genome_name + "::Genome " + activeTab.title;
				// console.log("Genome setActivePanelState: ", pageTitle);
				if(window.document.title !== pageTitle){
					window.document.title = pageTitle;
				}
			}
		},

		buildHeaderContent: function(genome){

			xhr.get(PathJoin(this.apiServiceUrl, "taxonomy", genome.taxon_id), {
				headers: {
					accept: "application/json"
				},
				handleAs: "json"
			}).then(lang.hitch(this, function(taxon){
				var taxon_lineage_names = taxon.lineage_names;
				var taxon_lineage_ids = taxon.lineage_ids;
				var taxon_lineage_ranks = taxon.lineage_ranks;

				var visibleRanks = ["superkingdom", "phylum", "class", "order", "family", "genus", "species"];
				var visibleIndexes = taxon_lineage_ranks.filter(function(rank){
					return visibleRanks.indexOf(rank) > -1;
				}).map(function(rank){
					return taxon_lineage_ranks.indexOf(rank);
				});

				var out = visibleIndexes.map(function(idx){
					return '' + taxon_lineage_names[idx] + '';
				});
				this.queryNode.innerHTML = out.join(" » ") + " » " + '' + genome.genome_name + '';
			}));
		},

		_setGenomeAttr: function(genome){
			this.state.genome = genome;

			this.buildHeaderContent(genome);
			domConstruct.empty(this.totalCountNode);

			this._set("genome", genome);

			// check host genomes. remove the circular viewer tab if it's a host genome
			if(genome && genome.taxon_lineage_ids){
			    // console.log("this genome: ", genome);
				if (genome.taxon_lineage_ids.length>1 && genome.taxon_lineage_ids[1] == "2759"){
					this.viewer.removeChild(this.circular);
				}
			}

			this.setActivePanelState();
			this.resize();
		},

		onSetState: function(attr, oldState, state){

			var parts = state.pathname.split("/");
			this.set("genome_id", parts[parts.length - 1]);
			state.genome_id = parts[parts.length - 1];
			state.genome_ids = [state.genome_id];
			if(!state){
				return;
			}

			// console.log("Genome: ", state.genome, state.genome_id)

			if(state && state.genome_id && !state.genome){
				// console.log("No state.genome.  state.genome_id: ", state.genome_id);
				if(oldState && oldState.genome_id){
					// console.log("oldState.genome_id: ", oldState.genome_id)

					if((state.genome_id == oldState.genome_id)){
						if(oldState.genome || this.genome){
							// console.log("oldState Genome: ", oldState.genome || this.genome);
							state.genome = oldState.genome || this.genome;
						}else{
							console.log("oldState missing Genome");
						}
					}
				}
			}

			if(state.hashParams && state.hashParams.view_tab){

				if(this[state.hashParams.view_tab]){
					var vt = this[state.hashParams.view_tab];

					if(state.hashParams.view_tab === "proteinFamilies"){
						// state.hashParams = lang.mixin({}, state.hashParams, {
						// 	params: JSON.stringify({"family_type": "plfam"})
						// });

						this.proteinFamilies.state = lang.mixin({}, state, {
							hashParams: lang.mixin({}, state.hashParams, {
								params: encodeURIComponent(JSON.stringify({"family_type": "plfam"}))
							})
						});
					}

					vt.set("visible", true);
					this.viewer.selectChild(vt);
				}else{
					// console.log("No view-tab supplied in State Object");
				}
			}

			this.setActivePanelState();

			// console.log("viewer/Genome onSetState() after set genome_id")
		},

		postCreate: function(){
			if(!this.state){
				this.state = {};
			}

			this.inherited(arguments);

			this.overview = new GenomeOverview({
				title: "Overview",
				id: this.viewer.id + "_" + "overview",
				state: this.state
			});

			this.phylogeny = new Phylogeny({
				title: "Phylogeny",
				id: this.viewer.id + "_" + "phylogeny"
			});

			this.sequences = new SequenceGridContainer({
				title: "Sequences",
				id: this.viewer.id + "_" + "sequences",
				state: lang.mixin({}, this.state, {search: "?eq(genome_id," + this.genome_id + ")"})
			});

			this.amr = new AMRPanelGridContainer({
				title: "AMR Phenotypes",
				id: this.viewer.id + "_" + "amr"
			});

			this.features = new FeatureGridContainer({
				title: "Features",
				id: this.viewer.id + "_" + "features",
				state: lang.mixin({}, this.state, {search: "?eq(genome_id," + this.genome_id + ")"})
			});

			this.browser = new GenomeBrowser({
				title: "Genome Browser",
				id: this.viewer.id + "_" + "browser",
				state: lang.mixin({}, this.state),
				tooltip: 'The "Browser" tab shows genome sequence and genomic features using linear genome browser'
			});

			this.circular = new CircularViewerContainer({
				title: "Circular Viewer",
				id: this.viewer.id + "_" + "circular",
				state: lang.mixin({}, this.state)
			});

			this.specialtyGenes = new SpecialtyGeneGridContainer({
				title: "Specialty Genes",
				id: this.viewer.id + "_" + "specialtyGenes",
				state: lang.mixin({}, this.state, {search: "?eq(genome_id," + this.genome_id + ")"})
			});

			this.pathways = new PathwaysContainer({
				apiServer: this.apiServiceUrl,
				title: "Pathways",
				id: this.viewer.id + "_" + "pathways",
				state: this.state
			});

			this.proteinFamilies = new ProteinFamiliesContainer({
				title: "Protein Families",
				id: this.viewer.id + "_" + "proteinFamilies",
				state: this.state
			});

			this.transcriptomics = new TranscriptomicsContainer({
				title: "Transcriptomics",
				id: this.viewer.id + "_" + "transcriptomics",
				state: this.state
			});

			this.interactions = new InteractionsContainer({
				title: "Interactions",
				id: this.viewer.id + "_" + "interactions",
				state: this.state
			});

			this.viewer.addChild(this.overview);
			this.viewer.addChild(this.amr);
			this.viewer.addChild(this.phylogeny);
			this.viewer.addChild(this.browser);
			this.viewer.addChild(this.circular);
			this.viewer.addChild(this.sequences);
			this.viewer.addChild(this.features);
			this.viewer.addChild(this.specialtyGenes);
			this.viewer.addChild(this.proteinFamilies);
			this.viewer.addChild(this.pathways);
			this.viewer.addChild(this.transcriptomics);
			this.viewer.addChild(this.interactions);
		}
	});
});
<|endoftext|>


<commit_before>FpsWriter = function () {
    var currentFps = $("#fps");
    var possibleFps = $("#possibleFps");

    var prevTime = Date.now();
    this.possibleTimeSum = 0.0;
    var frames = 0;

    this.updateFps = function () {
        var currentTime = Date.now();
        ms = currentTime - prevTime;
        frames++;

        if (currentTime > prevTime + 1000) { // One second since last update
            var fps = Math.round((frames * 1000) / (currentTime - prevTime));

            var timePerLogicUpdate = this.possibleTimeSum / frames;
            var possible = 1.0 / timePerLogicUpdate;
            currentFps.html("" + fps);
            possibleFps.html("" + possible);

            prevTime = currentTime;
            frames = 0;
            this.possibleTimeSum = 0.0;
        }
    }
}

Wall = function () {
    this.positionY = 0;
    this.size = 10;

    this.draw = function (table) {
        table.context.lineWidth = this.size;
        table.context.beginPath();
        table.context.moveTo(0, this.positionY);
        table.context.lineTo(table.canvasWidth, this.positionY);
        table.context.stroke();
    }
}

Ball = function () {
    this.direction = [0, 0];
    this.position = [0, 0];
    this.speed = 1;
    this.size = 20;

    this.setStart = function (posX, posY) {
        this.position = [posX, posY];
        var angle = Math.random() * Math.PI * 2;
        this.direction = [Math.cos(angle), Math.sin(angle)];
    }
    this.draw = function (table) {
        table.context.beginPath();
        table.context.arc(this.position[0], this.position[1], this.size, 0, 2 * Math.PI, false);
        table.context.fill();
    }

    this.update = function (table, walls, paddles) {
        this.position[0] += this.direction[0] * this.speed;
        this.position[1] += this.direction[1] * this.speed;
        if (this.position[1] < this.size + walls[0].size) {
            this.position[1] = (this.size + walls[0].size) +
                (this.size + walls[0].size - this.position[1]);
            this.direction[1] *= -1;
        } else if (this.position[1] > table.canvasHeight - walls[1].size - this.size) {
            this.position[1] = (table.canvasHeight - walls[1].size - this.size) +
                (table.canvasHeight - walls[1].size - this.size - this.position[1]);
            this.direction[1] *= -1;
        }
    }
}

Table = function () {
    this.canvasWidth = 0;
    this.canvasHeight = 0;
    this.context = null;

    this.initTable = function () {
        var canvasTag = $("#regularPongCanvas");
        this.canvasWidth = canvasTag.width();
        this.canvasHeight = canvasTag.height();
        this.context = canvasTag[0].getContext("2d");
    }

    this.clearCanvas = function () {
        this.context.fillStyle = "#000";
        this.context.lineWidth = 1;
        this.context.strokeStyle = '#000';
        this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    }

    this.initTable();
    this.clearCanvas();
}

Paddle = function (paddleName, isAi) {
    this.name = paddleName;
    this.direction = 0;
    this.positionY = 200;
    this.positionX = 200;
    this.speed = 2;
    this.halfLength = 10;
    this.width = 5;
    this.isAi = isAi;

    this.toString = function () {
        return
            "Paddle: " + this.name +
            ", speed = " + this.speed * this.direction +
            ", positionY = " + this.positionY +
            ", size = " + this.halfLength;
    }

    this.getSpeed = function () {
        return this.speed * this.direction;
    }

    this.draw = function (table) {
        table.context.lineWidth = this.width;
        table.context.strokeStyle = '#000';
        table.context.beginPath();
        table.context.moveTo(this.positionX, this.positionY - this.halfLength);
        table.context.lineTo(this.positionX, this.positionY + this.halfLength);
        table.context.stroke();
    }

    this.update = function (table, walls) {
        var currentY = this.positionY + this.direction * this.speed;
        if (currentY - this.halfLength < walls[0].size) {
            currentY = this.halfLength + walls[0].size;
            if (this.isAi) {
                this.direction *= -1;
            }
        } else if (currentY + this.halfLength > table.canvasHeight - walls[1].size) {
            currentY = table.canvasHeight - this.halfLength - walls[1].size;
            if (this.isAi) {
                this.direction *= -1;
            }
        }
        this.positionY = currentY;
    }
}

Game = function (gameName) {
    var table = null;
    var player = null;
    var ai = null;
    var fpsWriter = null;
    var walls = [null, null];
    var ball = null;
    var paddles = [null, null];
    var fps = 100;
    var isRunning = false;

    this.initGame = function () {
        table = new Table();

        player = new Paddle("Player");
        player.positionX = player.width / 2;
        ai = new Paddle("AI", true);
        ai.positionX = table.canvasWidth - ai.width / 2;
        ai.direction = Math.random() < 0.5 ? -1 : 1; // Sets a beginning random direction for AI
        paddles[0] = player;
        paddles[1] = ai;
        fpsWriter = new FpsWriter();
        walls[0] = new Wall();
        walls[0].positionY = walls[0].size / 2;
        walls[1] = new Wall();
        walls[1].positionY = table.canvasHeight - walls[1].size / 2;
        ball = new Ball();
        ball.setStart(table.canvasWidth / 2, table.canvasHeight / 2);

        document.addEventListener("keydown", this.keyDownHandler, false);
        document.addEventListener("keyup", this.keyUpHandler, false);
    }

    var update = function () {
        player.update(table, walls);
        ai.update(table, walls);
        ball.update(table, walls, paddles);
    }
    var draw = function () {
        table.clearCanvas();
        walls[0].draw(table);
        walls[1].draw(table);
        ball.draw(table);
        player.draw(table);
        ai.draw(table);
    }

    var run = function () {
        var start = Date.now();
        update();
        draw();
        var time = Date.now() - start;
        fpsWriter.possibleTimeSum += time / 1000;
        fpsWriter.updateFps();
    }

    var startGame = function () {
        this._intervalId = setInterval(run, 1000 / fps);
        console.log("Game started!");
        isRunning = true;
    }

    var stopGame = function () {
        clearInterval(this._intervalId);
        console.log("Game stopped!");
        isRunning = false;
    }

    this.keyDownHandler = function (event) {
        switch (event.keyCode) {
            // key code for up arrow
            case 38:
                //console.log('up arrow key pressed!');
                player.direction = -1;
                break;
                // key code for down arrow
            case 40:
                //console.log('down arrow key pressed!');
                player.direction = 1;
                break;
        }
    }

    this.keyUpHandler = function (event) {
        switch (event.keyCode) {
            // key code for Enter key
            case 13:
                if (isRunning) {
                    stopGame();
                } else {
                    startGame();
                }
                break;
                // key code for up arrow
            case 38:
                // key code for down arrow
            case 40:
                player.direction = 0;
                break;
        }
    }
}

var pongGame = new Game("Regular Pong");
pongGame.initGame();<commit_msg>Major refactoring of js to OO format<commit_after>FpsWriter = function () {
    var currentFps = $("#fps");
    var possibleFps = $("#possibleFps");

    var prevTime = Date.now();
    this.possibleTimeSum = 0.0;
    var frames = 0;

    this.updateFps = function () {
        var currentTime = Date.now();
        ms = currentTime - prevTime;
        frames++;

        if (currentTime > prevTime + 1000) { // One second since last update
            var fps = Math.round((frames * 1000) / (currentTime - prevTime));

            var timePerLogicUpdate = this.possibleTimeSum / frames;
            var possible = 1.0 / timePerLogicUpdate;
            currentFps.html("" + fps);
            possibleFps.html("" + possible);

            prevTime = currentTime;
            frames = 0;
            this.possibleTimeSum = 0.0;
        }
    }
}

Wall = function () {
    this.positionY = 0;
    this.size = 10;

    this.draw = function (table) {
        table.context.lineWidth = this.size;
        table.context.beginPath();
        table.context.moveTo(0, this.positionY);
        table.context.lineTo(table.canvasWidth, this.positionY);
        table.context.stroke();
    }
}

Ball = function () {
    this.direction = [0, 0];
    this.position = [0, 0];
    this.speed = 1;
    this.size = 20;

    this.setStart = function (posX, posY) {
        this.position = [posX, posY];
        var angle = Math.random() * Math.PI * 2;
        this.direction = [Math.cos(angle), Math.sin(angle)];
    }
    this.draw = function (table) {
        table.context.beginPath();
        table.context.arc(this.position[0], this.position[1], this.size, 0, 2 * Math.PI, false);
        table.context.fill();
    }

    this.update = function (table, walls, paddles) {
        this.position[0] += this.direction[0] * this.speed;
        this.position[1] += this.direction[1] * this.speed;
        if (this.position[1] < this.size + walls[0].size) {
            this.position[1] = (this.size + walls[0].size) +
                (this.size + walls[0].size - this.position[1]);
            this.direction[1] *= -1;
        } else if (this.position[1] > table.canvasHeight - walls[1].size - this.size) {
            this.position[1] = (table.canvasHeight - walls[1].size - this.size) +
                (table.canvasHeight - walls[1].size - this.size - this.position[1]);
            this.direction[1] *= -1;
        }
    }
}

Table = function () {
    this.canvasWidth = 0;
    this.canvasHeight = 0;
    this.context = null;

    this.initTable = function () {
        var canvasTag = $("#regularPongCanvas");
        this.canvasWidth = canvasTag.width();
        this.canvasHeight = canvasTag.height();
        this.context = canvasTag[0].getContext("2d");
    }

    this.clearCanvas = function () {
        this.context.fillStyle = "#000";
        this.context.lineWidth = 1;
        this.context.strokeStyle = '#000';
        this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    }

    this.initTable();
    this.clearCanvas();
}

Paddle = function (paddleName, isAi) {
    this.name = paddleName;
    this.direction = 0;
    this.positionY = 200;
    this.positionX = 200;
    this.speed = 2;
    this.halfLength = 10;
    this.width = 5;
    this.isAi = isAi;

    this.toString = function () {
        return
        "Paddle: " + this.name +
        ", speed = " + this.speed * this.direction +
        ", positionY = " + this.positionY +
        ", size = " + this.halfLength;
    }

    this.getSpeed = function () {
        return this.speed * this.direction;
    }

    this.draw = function (table) {
        table.context.lineWidth = this.width;
        table.context.strokeStyle = '#000';
        table.context.beginPath();
        table.context.moveTo(this.positionX, this.positionY - this.halfLength);
        table.context.lineTo(this.positionX, this.positionY + this.halfLength);
        table.context.stroke();
    }

    this.update = function (table, walls) {
        var currentY = this.positionY + this.direction * this.speed;
        if (currentY - this.halfLength < walls[0].size) {
            currentY = this.halfLength + walls[0].size;
            if (this.isAi) {
                this.direction *= -1;
            }
        } else if (currentY + this.halfLength > table.canvasHeight - walls[1].size) {
            currentY = table.canvasHeight - this.halfLength - walls[1].size;
            if (this.isAi) {
                this.direction *= -1;
            }
        }
        this.positionY = currentY;
    }
}

Game = function (gameName) {
    var table = null;
    var player = null;
    var ai = null;
    var fpsWriter = null;
    var walls = [null, null];
    var ball = null;
    var paddles = [null, null];
    var fps = 100;
    var isRunning = false;

    this.initGame = function () {
        table = new Table();

        player = new Paddle("Player");
        player.positionX = player.width / 2;
        ai = new Paddle("AI", true);
        ai.positionX = table.canvasWidth - ai.width / 2;
        ai.direction = Math.random() < 0.5 ? -1 : 1; // Sets a beginning random direction for AI
        paddles[0] = player;
        paddles[1] = ai;
        fpsWriter = new FpsWriter();
        walls[0] = new Wall();
        walls[0].positionY = walls[0].size / 2;
        walls[1] = new Wall();
        walls[1].positionY = table.canvasHeight - walls[1].size / 2;
        ball = new Ball();
        ball.setStart(table.canvasWidth / 2, table.canvasHeight / 2);

        document.addEventListener("keydown", this.keyDownHandler, false);
        document.addEventListener("keyup", this.keyUpHandler, false);
    }

    var update = function () {
        player.update(table, walls);
        ai.update(table, walls);
        ball.update(table, walls, paddles);
    }
    var draw = function () {
        table.clearCanvas();
        walls[0].draw(table);
        walls[1].draw(table);
        ball.draw(table);
        player.draw(table);
        ai.draw(table);
    }

    var run = function () {
        var start = Date.now();
        update();
        draw();
        var time = Date.now() - start;
        fpsWriter.possibleTimeSum += time / 1000;
        fpsWriter.updateFps();
    }

    var startGame = function () {
        this._intervalId = setInterval(run, 1000 / fps);
        console.log("Game started!");
        isRunning = true;
    }

    var stopGame = function () {
        clearInterval(this._intervalId);
        console.log("Game stopped!");
        isRunning = false;
    }

    this.keyDownHandler = function (event) {
        switch (event.keyCode) {
            // key code for up arrow
            case 38:
                //console.log('up arrow key pressed!');
                player.direction = -1;
                break;
                // key code for down arrow
            case 40:
                //console.log('down arrow key pressed!');
                player.direction = 1;
                break;
        }
    }

    this.keyUpHandler = function (event) {
        switch (event.keyCode) {
            // key code for Enter key
            case 13:
                if (isRunning) {
                    stopGame();
                } else {
                    startGame();
                }
                break;
                // key code for up arrow
            case 38:
                // key code for down arrow
            case 40:
                player.direction = 0;
                break;
        }
    }
}

var pongGame = new Game("Regular Pong");
pongGame.initGame();<|endoftext|>