diff --git a/app/components/AddEdgeForm.jsx b/app/components/AddEdgeForm.jsx index 4e5931e..7f7035a 100644 --- a/app/components/AddEdgeForm.jsx +++ b/app/components/AddEdgeForm.jsx @@ -1,5 +1,6 @@ import React, { Component, PropTypes } from 'react'; import BaseComponent from './BaseComponent'; +import Select from 'react-select'; import values from 'lodash/object/values'; import sortBy from 'lodash/collection/sortBy'; import { HotKeys } from 'react-hotkeys'; @@ -33,23 +34,34 @@ export default class AddEdgeForm extends BaseComponent { let nodes = sortBy(values(this.props.nodes), (node) => node.display.name); + let nodesMapped = nodes.map(function(node, i) { + return ( + { key: node.id, value: node.id, label: node.display.name } + ); + }); + + //note the keypress listener on input so it submits the form on enter + //due to Select library elements containing input forms return (
- - - + + e.key == "Enter" ? this._handleSubmit(e) : null } />
@@ -57,8 +69,8 @@ export default class AddEdgeForm extends BaseComponent { } _handleSubmit(e) { - let node1Id = this.refs.node1Id.value; - let node2Id = this.refs.node2Id.value; + let node1Id = this.refs.node1Id.state.value; + let node2Id = this.refs.node2Id.state.value; let label = this.refs.label.value.trim(); if (node1Id && node2Id && label) { diff --git a/app/components/__tests__/AddEdgeForm-test.js b/app/components/__tests__/AddEdgeForm-test.js new file mode 100644 index 0000000..0740514 --- /dev/null +++ b/app/components/__tests__/AddEdgeForm-test.js @@ -0,0 +1,119 @@ +jest.unmock('../BaseComponent'); +jest.unmock('../AddEdgeForm'); +jest.unmock('react-select'); + +import React from 'react'; +import { mount } from "enzyme"; + +import AddEdgeForm from "../AddEdgeForm"; + +describe("AddEdgeForm", () => { + + let nodes = { 1: { id: 1, display: { name: "Node 1" } }, 2: { id: 2, display: { name: "Node 2"} }, 3: { id: 3, display: { name: "Node 3" } } }; + + describe("rendering", () => { + + it("renders two react-select elements", () => { + let wrapper = mount( + + ); + expect(wrapper.find("Select").length).toBe(2); + + let firstReactSelect = wrapper.ref("node1Id"); + expect(firstReactSelect.is("Select")).toBe(true); + + let secondReactSelect = wrapper.ref("node2Id"); + expect(secondReactSelect.is("Select")).toBe(true); + }); + + it("renders one an additional input element (not part of React-Selects)", () => { + let wrapper = mount( + + ); + expect(wrapper.find(".form-control.input-sm").length).toBe(1); + }); + + it("returns empty string values for the two Select elements if data is null", () => { + let wrapper = mount( + + ); + let firstReactSelect = wrapper.ref("node1Id"); + expect(firstReactSelect.get(0).state.value).toBe(''); + + let secondReactSelect = wrapper.ref("node2Id"); + expect(secondReactSelect.get(0).state.value).toBe(''); + }); + + it("returns the first two node values from the data array for the two Select elements if data array > 1", () => { + let wrapper = mount( + + ); + let firstReactSelect = wrapper.ref("node1Id"); + expect(firstReactSelect.get(0).state.value).toBe(1); + + let secondReactSelect = wrapper.ref("node2Id"); + expect(secondReactSelect.get(0).state.value).toBe(2); + }); + + it("sets the state of only the first Select component to equal the id of a single passed in node data", () => { + let wrapper = mount( + + ); + let firstReactSelect = wrapper.ref("node1Id"); + expect(firstReactSelect.get(0).state.value).toBe(1); + + let secondReactSelect = wrapper.ref("node2Id"); + expect(secondReactSelect.get(0).state.value).toBe(''); + }); + + it("sets the Select components options to correspond to the nodes prop", () => { + let wrapper = mount( + + ); + let firstReactSelect = wrapper.ref("node1Id"); + expect(firstReactSelect.get(0).props.options.length).toBe(Object.keys(nodes).length); + + let secondReactSelect = wrapper.ref("node2Id"); + expect(secondReactSelect.get(0).props.options.length).toBe(Object.keys(nodes).length); + + }); + }) + + describe("behaviour", () => { + let addEdgeFunction = jest.genMockFunction(); + let closeAddFormFunction = jest.genMockFunction();; + + it("calls to both addEdge and to closeAddForm when enter is pressed on a non-empty label input field", () => { + let wrapper = mount( + + ); + + let selectForm = wrapper.find(".form-control.input-sm"); + selectForm.get(0).value = 'label'; + selectForm.simulate('keyPress', { key: "Enter" }); + expect(addEdgeFunction.mock.calls.length).toBe(1); + expect(closeAddFormFunction.mock.calls.length).toBe(1); + + }); + + + }) + + + +}) \ No newline at end of file diff --git a/app/main.jsx b/app/main.jsx index 4f7f303..3657d23 100644 --- a/app/main.jsx +++ b/app/main.jsx @@ -21,6 +21,7 @@ import merge from 'lodash/object/merge'; import assign from 'lodash/object/assign'; import difference from 'lodash/array/difference'; require ('./styles/oligrapher.css'); +import 'react-select/dist/react-select.css'; class Oligrapher { constructor(config = {}) { diff --git a/app/styles/oligrapher.editor.css b/app/styles/oligrapher.editor.css index 93a42ee..5de107b 100755 --- a/app/styles/oligrapher.editor.css +++ b/app/styles/oligrapher.editor.css @@ -212,4 +212,31 @@ button#toggleEditTools { #edgeUrlInput { width: 337px; -} \ No newline at end of file +} + +/*overwriting react-select styles*/ + +.Select .Select-control { + font-size: 12px; + height: 32px; +} + +.Select-menu-outer { + font-size: 0.8em; +} + +.Select .Select-input { + height: 30px; +} + +.Select .Select-placeholder{ + line-height: 30px; +} + +.Select .Select-input > input { + height: 30px; +} + +.Select { + margin-bottom: 10px; +} diff --git a/package.json b/package.json index 265fde5..69fa9ec 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "redux-undo": "^0.6.0", "shortid": "^2.2.4", "springy": "^2.7.1", - "titleize": "^1.0.0" + "titleize": "^1.0.0", + "react-select": "^0.9.1" }, "devDependencies": { "babel-core": "^6.7.7", @@ -72,4 +73,4 @@ "/node_modules/" ] } -} +} \ No newline at end of file