<commit_before>define(["intern!object",
	"intern/chai!assert",
	"require"
], function (registerSuite, assert, require) {

	registerSuite({
		name: "KeyNav functional tests",

		"setup": function () {
			return this.remote
				.get(require.toUrl("./KeyNavTests.html"))
				.waitForCondition("ready", 10000);
		},

		"inter widget tab navigation": function () {
			if (/safari|iPhone/.test(this.remote.environmentType.browserName)) {
				// SafariDriver doesn't support tabbing, see https://code.google.com/p/selenium/issues/detail?id=5403
				return;
			}
			return this.remote.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("autofocusInput", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					})
				.keys("\uE008\uE004") // shift tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("autofocusInput", value);
					})
				.keys("\uE008") // release shift
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("emptyContainer", value);
					})
				.keys("\uE008\uE004") // shift tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					})
				.keys("\uE008") // release shift
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("emptyContainer", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("autofocusInput", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("emptyContainer", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("autofocusInput", value);
					});
		},
		"intra widget arrow navigation": function () {
			if (/safari|iPhone/.test(this.remote.environmentType.browserName)) {
				// SafariDriver doesn't support tabbing, see https://code.google.com/p/selenium/issues/detail?id=5403
				return;
			}
			return this.remote.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("autofocusInput", value);
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("two", value);
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("three", value);
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("four", value);
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("five", value);
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("five", value);
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("four", value);
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("three", value);
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("two", value);
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value);
					});
		}

	});
});<commit_msg>Fix KeyNav test on IE10, IE11. Tabbing from the last element on the page does not necessarily go to the first element. It might go to the address bar instead.<commit_after>define(["intern!object",
	"intern/chai!assert",
	"require"
], function (registerSuite, assert, require) {

	registerSuite({
		name: "KeyNav functional tests",

		"setup": function () {
			return this.remote
				.get(require.toUrl("./KeyNavTests.html"))
				.waitForCondition("ready", 10000);
		},

		"inter widget tab navigation": function () {
			if (/safari|iPhone/.test(this.remote.environmentType.browserName)) {
				// SafariDriver doesn't support tabbing, see https://code.google.com/p/selenium/issues/detail?id=5403
				return;
			}
			return this.remote.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "autofocusInput", "initial element");
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "one", "tab to one");
					})
				.keys("\uE008\uE004") // shift tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "autofocusInput", "shift tab back to autofocusInput");
					})
				.keys("\uE008") // release shift
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "one", "tab to one again");
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "emptyContainer", "tab to emptyContainer");
					})
				.keys("\uE008\uE004") // shift tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "one", "shift tab to one");
					})
				.keys("\uE008") // release shift
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "emptyContainer", "tab to emptyContainer again");
					});
		},
		"intra widget arrow navigation": function () {
			if (/safari|iPhone/.test(this.remote.environmentType.browserName)) {
				// SafariDriver doesn't support tabbing, see https://code.google.com/p/selenium/issues/detail?id=5403
				return;
			}
			return this.remote.execute("autofocusInput.focus();")
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "autofocusInput", "start on autofocusInput");
					})
				.keys("\uE004") // tab
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "one", "tabbed to one");
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "two", "arrowed to two");
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "three", "arrowed to three");
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "four", "arrowed to four");
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "five", "arrowed to five");
					})
				.keys("\uE015") // arrow down
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "five", "still on five");
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "four", "back to four");
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal(value, "three", "back to three");
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("two", value, "back to two");
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value, "back to one");
					})
				.keys("\uE013") // arrow up
				.execute("return document.activeElement.id")
					.then(function (value) {
						assert.equal("one", value, "still on one");
					});
		}
	});
});<|endoftext|>


<commit_before>'use strict';
const Text = require('../../index');
const Noun = require('./noun');

class Nouns extends Text {
  isPlural() {
    return this.list.map((ts) => ts.isPlural());
  }
  hasPlural() {
    return this.list.map((ts) => ts.hasPlural());
  }
  toSingular() {
    this.list.forEach((ts) => ts.toSingular());
    return this;
  }
  toPlural() {
    this.list.forEach((ts) => ts.toPlural());
    return this;
  }
  data() {
    return this.list.map((ts) => ts.data());
  }
  static find(r, n) {
    r = r.clauses();
    r = r.match('#Noun+');
    r = r.not('#Pronoun');
    r = r.not('#Date');
    if (typeof n === 'number') {
      r = r.get(n);
    }
    r.list = r.list.map((ts) => {
      return new Noun(ts.terms, ts.lexicon, ts.refText, ts.refTerms);
    });
    return r;
  }
}
module.exports = Nouns;
<commit_msg>dates working<commit_after>'use strict';
const Text = require('../../index');
const Noun = require('./noun');

class Nouns extends Text {
  isPlural() {
    return this.list.map((ts) => ts.isPlural());
  }
  hasPlural() {
    return this.list.map((ts) => ts.hasPlural());
  }
  toSingular() {
    this.list.forEach((ts) => ts.toSingular());
    return this;
  }
  toPlural() {
    this.list.forEach((ts) => ts.toPlural());
    return this;
  }
  data() {
    return this.list.map((ts) => ts.data());
  }
  static find(r, n) {
    r = r.clauses();
    r = r.match('#Noun+');
    r = r.not('#Pronoun');
    r = r.not('(#Month|#WeekDay)'); //allow Durations, Holidays
    if (typeof n === 'number') {
      r = r.get(n);
    }
    r.list = r.list.map((ts) => {
      return new Noun(ts.terms, ts.lexicon, ts.refText, ts.refTerms);
    });
    return r;
  }
}
module.exports = Nouns;
<|endoftext|>


<commit_before>import { getItemText } from "./ItemsTextMixin.js";
import { indexOfItemContainingTarget } from "./utilities.js";
import * as internal from "./internal.js";
import * as template from "./template.js";
import ComboBox from "./ComboBox.js";
import DelegateItemsMixin from "./DelegateItemsMixin.js";
import DirectionSelectionMixin from "./DirectionSelectionMixin.js";
import ListBox from "./ListBox.js";
import SingleSelectionMixin from "./SingleSelectionMixin.js";

const Base = DelegateItemsMixin(
  DirectionSelectionMixin(SingleSelectionMixin(ComboBox))
);

/**
 * A combo box whose popup presents a list of choices
 *
 * @inherits ComboBox
 * @mixes DelegateItemsMixin
 * @mixes DirectionSelectionMixin
 * @mixes SingleSelectionMixin
 * @part {ListBox} list - the list of choices
 */
class ListComboBox extends Base {
  [internal.componentDidMount]() {
    super[internal.componentDidMount]();
    this.setAttribute("aria-haspopup", "listbox");
  }

  get [internal.defaultState]() {
    const state = Object.assign(super[internal.defaultState], {
      horizontalAlign: "stretch",
      listPartType: ListBox,
      selectedIndex: -1
    });

    // If value was changed directly or items have updated, select the
    // corresponding item in list.
    state.onChange(["items", "value"], state => {
      const { value } = state;
      /** @type {ListItemElement[]} */ const items = state.items;
      if (items && value != null) {
        const searchText = value.toLowerCase();
        const selectedIndex = items.findIndex(item => {
          const itemText = getItemText(item);
          return itemText.toLowerCase() === searchText;
        });
        return {
          selectedIndex
        };
      }
      return null;
    });

    // If user selects a new item, or combo is closing, make selected item the
    // value.
    state.onChange(["opened", "selectedIndex"], (state, changed) => {
      const { closeResult, items, opened, selectedIndex, value } = state;
      const closing = changed.opened && !opened;
      const canceled = closeResult && closeResult.canceled;
      if (
        selectedIndex >= 0 &&
        (changed.selectedIndex || (closing && !canceled))
      ) {
        const selectedItem = items[selectedIndex];
        if (selectedItem) {
          const selectedItemText = getItemText(selectedItem);
          // See notes on mobile at ComboBox.defaultState.
          const probablyMobile = matchMedia("(pointer: coarse)").matches;
          const selectText = !probablyMobile;
          if (value !== selectedItemText) {
            return {
              selectText,
              value: selectedItemText
            };
          }
        }
      }
      return null;
    });

    // When items change, we need to recalculate popup size.
    state.onChange("items", () => ({
      popupMeasured: false
    }));

    return state;
  }

  // We do our own handling of the Up and Down arrow keys, rather than relying
  // on KeyboardDirectionMixin. The latter supports Home and End, and we don't
  // want to handle those -- we want to let the text input handle them.
  // We also need to forward PageDown/PageUp to the list element.
  [internal.keydown](/** @type {KeyboardEvent} */ event) {
    let handled;
    /** @type {any} */
    const list = this[internal.ids].list;

    switch (event.key) {
      case "ArrowDown":
        if (this.opened) {
          handled = event.altKey
            ? this[internal.goEnd]()
            : this[internal.goDown]();
        }
        break;

      case "ArrowUp":
        if (this.opened) {
          handled = event.altKey
            ? this[internal.goStart]()
            : this[internal.goUp]();
        }
        break;

      case "PageDown":
        if (this.opened) {
          handled = list.pageDown && list.pageDown();
        }
        break;

      case "PageUp":
        if (this.opened) {
          handled = list.pageUp && list.pageUp();
        }
        break;
    }

    // Prefer mixin result if it's defined, otherwise use base result.
    return (
      handled || (super[internal.keydown] && super[internal.keydown](event))
    );
  }

  /**
   * The class, tag, or template used to create the `list` part - the list of
   * available choices shown in the popup.
   *
   * @type {PartDescriptor}
   * @default ListBox
   */
  get listPartType() {
    return this[internal.state].listPartType;
  }
  set listPartType(listPartType) {
    this[internal.setState]({ listPartType });
  }

  get [internal.itemsDelegate]() {
    return this[internal.ids].list;
  }

  [internal.render](/** @type {PlainObject} */ changed) {
    super[internal.render](changed);
    if (changed.inputPartType) {
      this[internal.ids].input.setAttribute("aria-autocomplete", "both");
    }
    if (changed.listPartType) {
      template.transmute(
        this[internal.ids].list,
        this[internal.state].listPartType
      );

      this[internal.ids].list.addEventListener("mousedown", event => {
        // Mousing down inside a list item closes the popup.
        /** @type {any} */
        const target = event.target;
        if (target) {
          const targetIndex = indexOfItemContainingTarget(this.items, target);
          if (this.opened && targetIndex >= 0) {
            this[internal.raiseChangeEvents] = true;
            this.close();
            this[internal.raiseChangeEvents] = false;
          }
        }
      });

      // Track changes in the list's selection state.
      // Known bug: this behavior seems to confuse Gboard on Chrome for Android.
      // If we update our notion of the selection index, we'll ultimately update
      // the text shown in the input and leave it selected. If the user then
      // presses Backspace to delete that selected text, Gboard/Chrome seems to
      // ignore the first press of the Backspace key. The user must press
      // Backspace a second time to actually delete the selected text.
      this[internal.ids].list.addEventListener(
        "selected-index-changed",
        event => {
          /** @type {any} */
          const cast = event;
          const listSelectedIndex = cast.detail.selectedIndex;
          if (this[internal.state].selectedIndex !== listSelectedIndex) {
            this[internal.raiseChangeEvents] = true;
            this[internal.setState]({
              selectedIndex: listSelectedIndex
            });
            this[internal.raiseChangeEvents] = false;
          }
        }
      );
    }
    if (changed.selectedIndex) {
      const list = /** @type {any} */ (this[internal.ids].list);
      if ("selectedIndex" in list) {
        list.selectedIndex = this[internal.state].selectedIndex;
      }
    }
  }

  get [internal.template]() {
    const result = super[internal.template];

    // Wrap default slot with a list.
    const listTemplate = template.html`

        <slot></slot>

    `;
    const defaultSlot = template.defaultSlot(result.content);
    if (defaultSlot) {
      template.transmute(defaultSlot, listTemplate);
    }

    return result;
  }
}

export default ListComboBox;
<commit_msg>Avoid letting the list in the popup take focus from the input if the user, e.g., clicks on the list's scroll bar to scroll the list. We want to keep the focus on the input, otherwise the blur event on the input will cause the popup to close.<commit_after>import { getItemText } from "./ItemsTextMixin.js";
import { indexOfItemContainingTarget, forwardFocus } from "./utilities.js";
import * as internal from "./internal.js";
import * as template from "./template.js";
import ComboBox from "./ComboBox.js";
import DelegateItemsMixin from "./DelegateItemsMixin.js";
import DirectionSelectionMixin from "./DirectionSelectionMixin.js";
import ListBox from "./ListBox.js";
import SingleSelectionMixin from "./SingleSelectionMixin.js";

const Base = DelegateItemsMixin(
  DirectionSelectionMixin(SingleSelectionMixin(ComboBox))
);

/**
 * A combo box whose popup presents a list of choices
 *
 * @inherits ComboBox
 * @mixes DelegateItemsMixin
 * @mixes DirectionSelectionMixin
 * @mixes SingleSelectionMixin
 * @part {ListBox} list - the list of choices
 */
class ListComboBox extends Base {
  [internal.componentDidMount]() {
    super[internal.componentDidMount]();
    this.setAttribute("aria-haspopup", "listbox");
  }

  get [internal.defaultState]() {
    const state = Object.assign(super[internal.defaultState], {
      horizontalAlign: "stretch",
      listPartType: ListBox,
      selectedIndex: -1
    });

    // If value was changed directly or items have updated, select the
    // corresponding item in list.
    state.onChange(["items", "value"], state => {
      const { value } = state;
      /** @type {ListItemElement[]} */ const items = state.items;
      if (items && value != null) {
        const searchText = value.toLowerCase();
        const selectedIndex = items.findIndex(item => {
          const itemText = getItemText(item);
          return itemText.toLowerCase() === searchText;
        });
        return {
          selectedIndex
        };
      }
      return null;
    });

    // If user selects a new item, or combo is closing, make selected item the
    // value.
    state.onChange(["opened", "selectedIndex"], (state, changed) => {
      const { closeResult, items, opened, selectedIndex, value } = state;
      const closing = changed.opened && !opened;
      const canceled = closeResult && closeResult.canceled;
      if (
        selectedIndex >= 0 &&
        (changed.selectedIndex || (closing && !canceled))
      ) {
        const selectedItem = items[selectedIndex];
        if (selectedItem) {
          const selectedItemText = getItemText(selectedItem);
          // See notes on mobile at ComboBox.defaultState.
          const probablyMobile = matchMedia("(pointer: coarse)").matches;
          const selectText = !probablyMobile;
          if (value !== selectedItemText) {
            return {
              selectText,
              value: selectedItemText
            };
          }
        }
      }
      return null;
    });

    // When items change, we need to recalculate popup size.
    state.onChange("items", () => ({
      popupMeasured: false
    }));

    return state;
  }

  // We do our own handling of the Up and Down arrow keys, rather than relying
  // on KeyboardDirectionMixin. The latter supports Home and End, and we don't
  // want to handle those -- we want to let the text input handle them.
  // We also need to forward PageDown/PageUp to the list element.
  [internal.keydown](/** @type {KeyboardEvent} */ event) {
    let handled;
    /** @type {any} */
    const list = this[internal.ids].list;

    switch (event.key) {
      case "ArrowDown":
        if (this.opened) {
          handled = event.altKey
            ? this[internal.goEnd]()
            : this[internal.goDown]();
        }
        break;

      case "ArrowUp":
        if (this.opened) {
          handled = event.altKey
            ? this[internal.goStart]()
            : this[internal.goUp]();
        }
        break;

      case "PageDown":
        if (this.opened) {
          handled = list.pageDown && list.pageDown();
        }
        break;

      case "PageUp":
        if (this.opened) {
          handled = list.pageUp && list.pageUp();
        }
        break;
    }

    // Prefer mixin result if it's defined, otherwise use base result.
    return (
      handled || (super[internal.keydown] && super[internal.keydown](event))
    );
  }

  /**
   * The class, tag, or template used to create the `list` part - the list of
   * available choices shown in the popup.
   *
   * @type {PartDescriptor}
   * @default ListBox
   */
  get listPartType() {
    return this[internal.state].listPartType;
  }
  set listPartType(listPartType) {
    this[internal.setState]({ listPartType });
  }

  get [internal.itemsDelegate]() {
    return this[internal.ids].list;
  }

  [internal.render](/** @type {PlainObject} */ changed) {
    if (changed.listPartType && this[internal.ids].list) {
      // Turn off focus handling for old list.
      /** @type {any} */
      const cast = this[internal.ids].list;
      forwardFocus(cast, null);
    }
    super[internal.render](changed);
    if (changed.inputPartType) {
      this[internal.ids].input.setAttribute("aria-autocomplete", "both");
    }
    if (changed.listPartType) {
      template.transmute(
        this[internal.ids].list,
        this[internal.state].listPartType
      );

      this[internal.ids].list.addEventListener("mousedown", event => {
        // Mousing down inside a list item closes the popup.
        /** @type {any} */
        const target = event.target;
        if (target) {
          const targetIndex = indexOfItemContainingTarget(this.items, target);
          if (this.opened && targetIndex >= 0) {
            this[internal.raiseChangeEvents] = true;
            this.close();
            this[internal.raiseChangeEvents] = false;
          }
        }
      });

      // Keep focus off of the list and on the top level combo box (which should
      // delegate focus to the input).
      /** @type {any} */
      const cast = this[internal.ids].list;
      forwardFocus(cast, this);

      // Track changes in the list's selection state.
      // Known bug: this behavior seems to confuse Gboard on Chrome for Android.
      // If we update our notion of the selection index, we'll ultimately update
      // the text shown in the input and leave it selected. If the user then
      // presses Backspace to delete that selected text, Gboard/Chrome seems to
      // ignore the first press of the Backspace key. The user must press
      // Backspace a second time to actually delete the selected text.
      this[internal.ids].list.addEventListener(
        "selected-index-changed",
        event => {
          /** @type {any} */
          const cast = event;
          const listSelectedIndex = cast.detail.selectedIndex;
          if (this[internal.state].selectedIndex !== listSelectedIndex) {
            this[internal.raiseChangeEvents] = true;
            this[internal.setState]({
              selectedIndex: listSelectedIndex
            });
            this[internal.raiseChangeEvents] = false;
          }
        }
      );
    }
    if (changed.selectedIndex) {
      const list = /** @type {any} */ (this[internal.ids].list);
      if ("selectedIndex" in list) {
        list.selectedIndex = this[internal.state].selectedIndex;
      }
    }
  }

  get [internal.template]() {
    const result = super[internal.template];

    // Wrap default slot with a list.
    const listTemplate = template.html`

        <slot></slot>

    `;
    const defaultSlot = template.defaultSlot(result.content);
    if (defaultSlot) {
      template.transmute(defaultSlot, listTemplate);
    }

    return result;
  }
}

export default ListComboBox;
<|endoftext|>


<commit_before>import React from 'react';
import ReactTable from "react-table";
import { Link } from 'react-router-dom';
import 'react-table/react-table.css'
import Griddle, { pageProperties, plugins, RowDefinition, ColumnDefinition}from 'griddle-react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import RaisedButton from '@material-ui/core/Button';
import BackButton from '../BackButton';
import NewSubjectForm from './NewSubjectForm';
import LoadingGif from '../LoadingGif';
import * as ProtocolActions from '../../actions/protocol';
import * as SubjectActions from '../../actions/subject';
import Button from 'react-bootstrap/Button'

class SubjectSelect extends React.PureComponent {

  constructor(props) {
    super(props);
    this.handleNewSubject = this.handleNewSubject.bind(this);
    this.handleClick = this.handleClick.bind(this);
    const { dispatch } = this.props;
  }

  componentDidMount() {
    const { dispatch } = this.props;
    this.props.dispatch(ProtocolActions.setActiveProtocol(this.props.match.params.id));
    this.props.dispatch(SubjectActions.fetchSubjects(this.props.match.params.id));

  }

  componentWillUnmount() {
    const { dispatch } = this.props;
    dispatch(SubjectActions.clearSubjectsState());
  }

  getActiveProtocol() {
    let activeProtocol = {};
    if (this.props.protocol.items) {
      activeProtocol = this.props.protocol;
      }
    return activeProtocol;
  }

  griddleFrendlySubjects() {
    let orgIdLabel = 'Identifier';
    let subs = [];
    let row = {};
    let rows = [];
    if (this.props.subject.items.length >0) {
      subs = this.props.subject.items.map((sub) => {
        let externalIds = '';
        sub.external_ids.forEach((exId) => {
          externalIds += `${exId.label_desc} : ${exId.record_id}\n`;
        }, this);
        let row = {
          Organization: sub.organization_name,
          'First Name': sub.first_name,
          'Last Name': sub.last_name,
          'Birth Date': sub.dob,
          'External IDs': externalIds,
          subject: sub,
        };
        row[orgIdLabel] = sub.organization_subject_id;
        // return row
        rows.push(row);
      });
    }
    return rows
  }

  handleNewSubject() {
    const { dispatch } = this.props;
    dispatch(SubjectActions.setAddSubjectMode(true));
    this.props.dispatch(ProtocolActions.setActiveProtocol(this.props.protocol.activeProtocolId));
  }

  handleClick(row) {
    const subject = row.original;
    const { dispatch } = this.props;

    // Update state with new active subject
    dispatch(SubjectActions.setActiveSubject(subject));
    // Push to the correct pathname (and therefore view)
    this.props.history.push(`${this.props.match.url}/subject/${subject.id}`);
  }

  render() {
    // If this view is navigated to directly. Get active protocol based on param
    const subjects = this.props.subject.items;
    const protocol = this.getActiveProtocol();
    const filterCaseInsensitive = ({ id, value }, row) =>
      row[id] ? row[id].toLowerCase().includes(value.toLowerCase()) : true
    // const rows = this.griddleFrendlySubjects(); //This is not needed for react-table

    let manageExternalIDs = false;
    const subjectCountStyle = {
      paddingLeft: '10px',
      paddingRight: '10px',
      paddingBottom: '10px',
      color: '#7a7a7a',
      fontWeight: 'bold',
    };
    if (this.props.activeProtocolId) {
      if (parseInt(this.props.match.params.id, 10) === parseInt(protocol.id, 10)) {
        this.props.protocol.activeProtocol = protocol;
        protocol.data_sources.forEach((ds) => {
          // HACK obtains datasource Id
          const pdsId = parseInt(ds.slice(ds.length - 2, ds.length - 1), 10);
          if (pdsId === 3) {
            manageExternalIDs = true;
          }
        }, this);
      }
    }
    let orgIdLabel = 'Identifier';

    const columns = [{
      Header: 'Subjects',
      columns: [{
        Header: 'Organization',
        headerStyle: {textAlign: 'left'},
        accessor: 'organization_name', // String-based value accessors!
        style: { 'whiteSpace': 'unset' },
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'Identifier',
        headerStyle: {textAlign: 'left'},
        accessor: 'organization_subject_id', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'First Name',
        headerStyle: {textAlign: 'left'},
        accessor: 'first_name', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'Last Name',
        headerStyle: {textAlign: 'left'},
        accessor: 'last_name', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'Birth Date',
        headerStyle: {textAlign: 'left'},
        accessor: 'dob', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        }]
      }]

    return (
      this.props.subject.items.length>0 && this.props.protocol.items ?

          {this.props.subject.addSubjectMode ?
            <NewSubjectForm orgs={this.props.protocol.orgs} /> :

          }
          {!this.props.subject.addSubjectMode ?
            <BackButton /> :

          }

Project: {this.props.protocol.items.name}

                <Button
                  labelcolor={'#7AC29A'}
                  onClick={this.handleNewSubject}
                  label={'New Subject'}
                > New Subject </Button>

{this.props.subject.items.length} Subjects

            {(this.props.subject.items.length>0) ?

              <ReactTable
                data={this.props.subject.items}
                columns={columns}
                filterable = {true}
                defaultFilterMethod={filterCaseInsensitive}
                className="-highlight"
                getTdProps={(state, rowInfo) => {
                  return {
                    onClick: (e, handleOrigional) => {
                      this.handleClick(rowInfo);
                    }
                  }}
                }
                />
               : <LoadingGif />}

 :

    );
  }
}

SubjectSelect.propTypes = {
  dispatch: PropTypes.func,
  history: PropTypes.object,
  params: PropTypes.object,
  subject: PropTypes.object,
  protocol: PropTypes.object,
};

function mapStateToProps(state) {
  return {
    protocol: {
      items: state.protocol.items,
      activeProtocolId: state.protocol.activeProtocolId,
      orgs: state.protocol.orgs,
      pds: state.pds,
    },
    subject: {
      items: state.subject.items,
      addSubjectMode: state.subject.addSubjectMode,
      isFetching: state.subject.isFetching,
    },
  };
}

export default connect(mapStateToProps)(SubjectSelect);
<commit_msg>when zero subjects are alligned to a protocol, show add subject button<commit_after>import React from 'react';
import ReactTable from "react-table";
import { Link } from 'react-router-dom';
import 'react-table/react-table.css'
import Griddle, { pageProperties, plugins, RowDefinition, ColumnDefinition}from 'griddle-react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import RaisedButton from '@material-ui/core/Button';
import BackButton from '../BackButton';
import NewSubjectForm from './NewSubjectForm';
import LoadingGif from '../LoadingGif';
import * as ProtocolActions from '../../actions/protocol';
import * as SubjectActions from '../../actions/subject';
import Button from 'react-bootstrap/Button'

class SubjectSelect extends React.PureComponent {

  constructor(props) {
    super(props);
    this.handleNewSubject = this.handleNewSubject.bind(this);
    this.handleClick = this.handleClick.bind(this);
    const { dispatch } = this.props;
  }

  componentDidMount() {
    const { dispatch } = this.props;
    this.props.dispatch(ProtocolActions.setActiveProtocol(this.props.match.params.id));
    this.props.dispatch(SubjectActions.fetchSubjects(this.props.match.params.id));

  }

  componentWillUnmount() {
    const { dispatch } = this.props;
    dispatch(SubjectActions.clearSubjectsState());
  }

  getActiveProtocol() {
    let activeProtocol = {};
    if (this.props.protocol.items) {
      activeProtocol = this.props.protocol;
      }
    return activeProtocol;
  }

  griddleFrendlySubjects() {
    let orgIdLabel = 'Identifier';
    let subs = [];
    let row = {};
    let rows = [];
    if (this.props.subject.items.length >0) {
      subs = this.props.subject.items.map((sub) => {
        let externalIds = '';
        sub.external_ids.forEach((exId) => {
          externalIds += `${exId.label_desc} : ${exId.record_id}\n`;
        }, this);
        let row = {
          Organization: sub.organization_name,
          'First Name': sub.first_name,
          'Last Name': sub.last_name,
          'Birth Date': sub.dob,
          'External IDs': externalIds,
          subject: sub,
        };
        row[orgIdLabel] = sub.organization_subject_id;
        // return row
        rows.push(row);
      });
    }
    return rows
  }

  handleNewSubject() {
    const { dispatch } = this.props;
    dispatch(SubjectActions.setAddSubjectMode(true));
    this.props.dispatch(ProtocolActions.setActiveProtocol(this.props.protocol.activeProtocolId));
  }

  handleClick(row) {
    const subject = row.original;
    const { dispatch } = this.props;

    // Update state with new active subject
    dispatch(SubjectActions.setActiveSubject(subject));
    // Push to the correct pathname (and therefore view)
    this.props.history.push(`${this.props.match.url}/subject/${subject.id}`);
  }

  render() {
    // If this view is navigated to directly. Get active protocol based on param
    const subjects = this.props.subject.items;
    const protocol = this.getActiveProtocol();
    const filterCaseInsensitive = ({ id, value }, row) =>
      row[id] ? row[id].toLowerCase().includes(value.toLowerCase()) : true
    // const rows = this.griddleFrendlySubjects(); //This is not needed for react-table

    let manageExternalIDs = false;
    const subjectCountStyle = {
      paddingLeft: '10px',
      paddingRight: '10px',
      paddingBottom: '10px',
      color: '#7a7a7a',
      fontWeight: 'bold',
    };
    if (this.props.activeProtocolId) {
      if (parseInt(this.props.match.params.id, 10) === parseInt(protocol.id, 10)) {
        this.props.protocol.activeProtocol = protocol;
        protocol.data_sources.forEach((ds) => {
          // HACK obtains datasource Id
          const pdsId = parseInt(ds.slice(ds.length - 2, ds.length - 1), 10);
          if (pdsId === 3) {
            manageExternalIDs = true;
          }
        }, this);
      }
    }
    let orgIdLabel = 'Identifier';

    const columns = [{
      Header: 'Subjects',
      columns: [{
        Header: 'Organization',
        headerStyle: {textAlign: 'left'},
        accessor: 'organization_name', // String-based value accessors!
        style: { 'whiteSpace': 'unset' },
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'Identifier',
        headerStyle: {textAlign: 'left'},
        accessor: 'organization_subject_id', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'First Name',
        headerStyle: {textAlign: 'left'},
        accessor: 'first_name', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'Last Name',
        headerStyle: {textAlign: 'left'},
        accessor: 'last_name', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        },
        {
        Header: 'Birth Date',
        headerStyle: {textAlign: 'left'},
        accessor: 'dob', // String-based value accessors!
        Filter: ({filter, onChange}) => (<input placeholder="search" value={filter ? filter.value : ''}
                       onChange={event => onChange(event.target.value)} />),
        }]
      }]

    return (
      this.props.protocol.items ?

          {this.props.subject.addSubjectMode ?
            <NewSubjectForm orgs={this.props.protocol.orgs} /> :

          }
          {!this.props.subject.addSubjectMode ?
            <BackButton /> :

          }

Project: {this.props.protocol.items.name}

                <Button
                  labelcolor={'#7AC29A'}
                  onClick={this.handleNewSubject}
                  label={'New Subject'}
                > New Subject </Button>

{this.props.subject.items.length} Subjects

            {(this.props.subject.items.length>0) ?

              <ReactTable
                data={this.props.subject.items}
                columns={columns}
                filterable = {true}
                defaultFilterMethod={filterCaseInsensitive}
                className="-highlight"
                getTdProps={(state, rowInfo) => {
                  return {
                    onClick: (e, handleOrigional) => {
                      this.handleClick(rowInfo);
                    }
                  }}
                }
                />
               : <LoadingGif />}

 :

    );
  }
}

SubjectSelect.propTypes = {
  dispatch: PropTypes.func,
  history: PropTypes.object,
  params: PropTypes.object,
  subject: PropTypes.object,
  protocol: PropTypes.object,
};

function mapStateToProps(state) {
  return {
    protocol: {
      items: state.protocol.items,
      activeProtocolId: state.protocol.activeProtocolId,
      orgs: state.protocol.orgs,
      pds: state.pds,
    },
    subject: {
      items: state.subject.items,
      addSubjectMode: state.subject.addSubjectMode,
      isFetching: state.subject.isFetching,
    },
  };
}

export default connect(mapStateToProps)(SubjectSelect);
<|endoftext|>


<commit_before>var ModeHandler = function(mode, DrawContext) {

  var handlers = {
    drag: [],
    click: [],
    mousemove: [],
    mousedown: [],
    mouseup: [],
    keydown: [],
    keyup: []
  };

  var ctx = {
    on: function(event, selector, fn) {
      if (handlers[event] === undefined) {
        throw new Error(`Invalid event type: ${event}`);
      }
      handlers[event].push({
        selector: selector,
        fn: fn
      });
    },
    render: function(id) {
      DrawContext.store.featureChanged(id);
    }
  };

  var delegate = function (eventName, event) {
    var handles = handlers[eventName];
    var iHandle = handles.length;
    var handlerCalled = false;
    while (iHandle--) {
      var handle = handles[iHandle];
      if (handle.selector(event)) {
        handle.fn.call(ctx, event);
        handlerCalled = true;
      }
    }
    if (handlerCalled) {
      DrawContext.store.render();
      DrawContext.ui.updateMapClasses();
    }
  };

  mode.start.call(ctx);

  return {
    render: mode.render || function(geojson) {return geojson; },
    stop: function() {
      if (mode.stop) mode.stop();
    },
    trash: function() {
      if (mode.trash) {
        mode.trash();
        DrawContext.store.render();
      }
    },
    drag: function(event) {
      delegate('drag', event);
    },
    click: function(event) {
      delegate('click', event);
    },
    mousemove: function(event) {
      delegate('mousemove', event);
    },
    mousedown: function(event) {
      delegate('mousedown', event);
    },
    mouseup: function(event) {
      delegate('mouseup', event);
    },
    keydown: function(event) {
      delegate('keydown', event);
    },
    keyup: function(event) {
      delegate('keyup', event);
    }
  };
};

module.exports = ModeHandler;
<commit_msg>every mode has a custom render, lets drop the default<commit_after>var ModeHandler = function(mode, DrawContext) {

  var handlers = {
    drag: [],
    click: [],
    mousemove: [],
    mousedown: [],
    mouseup: [],
    keydown: [],
    keyup: []
  };

  var ctx = {
    on: function(event, selector, fn) {
      if (handlers[event] === undefined) {
        throw new Error(`Invalid event type: ${event}`);
      }
      handlers[event].push({
        selector: selector,
        fn: fn
      });
    },
    render: function(id) {
      DrawContext.store.featureChanged(id);
    }
  };

  var delegate = function (eventName, event) {
    var handles = handlers[eventName];
    var iHandle = handles.length;
    var handlerCalled = false;
    while (iHandle--) {
      var handle = handles[iHandle];
      if (handle.selector(event)) {
        handle.fn.call(ctx, event);
        handlerCalled = true;
      }
    }
    if (handlerCalled) {
      DrawContext.store.render();
      DrawContext.ui.updateMapClasses();
    }
  };

  mode.start.call(ctx);

  return {
    render: mode.render,
    stop: function() {
      if (mode.stop) mode.stop();
    },
    trash: function() {
      if (mode.trash) {
        mode.trash();
        DrawContext.store.render();
      }
    },
    drag: function(event) {
      delegate('drag', event);
    },
    click: function(event) {
      delegate('click', event);
    },
    mousemove: function(event) {
      delegate('mousemove', event);
    },
    mousedown: function(event) {
      delegate('mousedown', event);
    },
    mouseup: function(event) {
      delegate('mouseup', event);
    },
    keydown: function(event) {
      delegate('keydown', event);
    },
    keyup: function(event) {
      delegate('keyup', event);
    }
  };
};

module.exports = ModeHandler;
<|endoftext|>


<commit_before>/*
Alugaqui JavaScript File
*/

/* 1 - FORM FUNCTIONS */

/* Search function */

function buscaImovel() {
  var bairros = [
    "barra",
    "recreio",
    "ilha",
    "ipanema",
    "leblon",
    "botafogo",
    "lagoa"
  ];
  var bairrosTamanho = bairros.length;
  var input = document.getElementById("buscaBairro");
  var inputValue = input.value;

  criariImoveis();

  console.log("Valor de busca:" + inputValue);
  console.log("Valores de bairros:");
  var i;
  for (i = 0; i < bairrosTamanho; i++) {
    console.log(bairros[i]);
  }
  /* Validation of the search */
  var resultadoBusca = false;

  for (i = 0; i < bairrosTamanho; i++) {
    if ( inputValue == bairros[i]){
      resultadoBusca = true;
    }
  }
  console.log("O resultado da busca:")

  if ( resultadoBusca == true ){
    console.log("FOI ENCONTRADO! =)");
  }
  else{
    console.log("NÃO FOI ENCONTRADO! =(");
  }

  sendFormData(inputValue);
};

/* Function to create Dummy ImoveisObjects */

function criariImoveis() {

  var imovel = {
    endereco : "Rua de Teste para Validacao",
    cep : "22631450" ,
    bairro: "barra"
  };

  console.log("Imovel criado!");
  console.log("Endereço: " + imovel.endereco);
  console.log("CEP: " + imovel.cep);
  console.log("Bairro: " + imovel.bairro);
};

/* Formats FORM data as a JSON string */
function formJSON() {
  // Test with 3 sample inputs
  var numberInputs = 3;
  var count;
  var jsonString = '{';

  for (count = 0; count < numberInputs ; count++) {
    if (count != 0){
      jsonString += ',';
    }
    jsonString += $("input").eq(count).attr('id') + ':';
    jsonString += $("input").eq(count).val();
  }

  jsonString += '}';

  // Testing to validate response
  console.log (jsonString);
  return jsonString;
};

/* Send JSON formatted data to Server */
function sendFormData(data){
  //Sends data to the server
  var httpReq = new XMLHttpRequest();

  httpReq.open("GET", "/bairro/" + data , true);

  httpReq.send();

};

/* Validates FORM data */
function validateFormData(){

};
  <commit_msg>Render page with the HTTP response from Server<commit_after>/*
Alugaqui JavaScript File
*/

/* 1 - FORM FUNCTIONS */

/* Search function */

function buscaImovel() {
  var bairros = [
    "barra",
    "recreio",
    "ilha",
    "ipanema",
    "leblon",
    "botafogo",
    "lagoa"
  ];
  var bairrosTamanho = bairros.length;
  var input = document.getElementById("buscaBairro");
  var inputValue = input.value;

  criariImoveis();

  console.log("Valor de busca:" + inputValue);
  console.log("Valores de bairros:");
  var i;
  for (i = 0; i < bairrosTamanho; i++) {
    console.log(bairros[i]);
  }
  /* Validation of the search */
  var resultadoBusca = false;

  for (i = 0; i < bairrosTamanho; i++) {
    if ( inputValue == bairros[i]){
      resultadoBusca = true;
    }
  }
  console.log("O resultado da busca:")

  if ( resultadoBusca == true ){
    console.log("FOI ENCONTRADO! =)");
  }
  else{
    console.log("NÃO FOI ENCONTRADO! =(");
  }

  sendFormData(inputValue);
};

/* Function to create Dummy ImoveisObjects */

function criariImoveis() {

  var imovel = {
    endereco : "Rua de Teste para Validacao",
    cep : "22631450" ,
    bairro: "barra"
  };

  console.log("Imovel criado!");
  console.log("Endereço: " + imovel.endereco);
  console.log("CEP: " + imovel.cep);
  console.log("Bairro: " + imovel.bairro);
};

/* Formats FORM data as a JSON string */
function formJSON() {
  // Test with 3 sample inputs
  var numberInputs = 3;
  var count;
  var jsonString = '{';

  for (count = 0; count < numberInputs ; count++) {
    if (count != 0){
      jsonString += ',';
    }
    jsonString += $("input").eq(count).attr('id') + ':';
    jsonString += $("input").eq(count).val();
  }

  jsonString += '}';

  // Testing to validate response
  console.log (jsonString);
  return jsonString;
};

/* Send JSON formatted data to Server */
function sendFormData(data){
  //Sends data to the server
  var httpReq = new XMLHttpRequest();

  httpReq.open("GET", "/bairro/" + data , true);
  httpReq.send(null);
  /* Renders the page with the HTTP Response from Server */
  httpReq.onreadystatechange = function () {
        if(httpReq.readyState === XMLHttpRequest.DONE && httpReq.status === 200) {
            document.write(httpReq.responseText);
        }
    };
};
  <|endoftext|>