Skip to content

Commit

Permalink
up down enter on perspective dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
annyhe committed Dec 20, 2016
1 parent dcfde84 commit cb62935
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 19 deletions.
Binary file removed assets/images/favicon.ico
Binary file not shown.
3 changes: 3 additions & 0 deletions public/css/perspective.css
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ body {
margin: -5px 0 0 0;
}

.slds-lookup__item-action.slds-media.highlighted {
background: #e0e5ee;
}

/* radio button width */

Expand Down
65 changes: 64 additions & 1 deletion tests/view/components/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import Dropdown from '../../../view/admin/components/common/Dropdown.js';
describe('Dropdown component tests', () => {
const ZERO = 0;
const ONE = 1;
const DUMMY_STRING = 'COOL';
const DUMMY_STRING = 'UNITED';
const DUMMY_ARRAY = DUMMY_STRING.split('');
const DUMMY_FUNCTION = () => {};

/**
Expand All @@ -41,6 +42,7 @@ describe('Dropdown component tests', () => {
onAddNewButton: DUMMY_FUNCTION,
onClickItem: DUMMY_FUNCTION,
showInputElem: false, //default
// close, open are by default false
};
// update props as needed
if (propAddons) {
Expand All @@ -53,6 +55,67 @@ describe('Dropdown component tests', () => {
return enzymeWrapper;
}

it('on toggle true, dropdown opens', () => {
const enzymeWrapper = setup();
const instance = enzymeWrapper.instance();
// by default dropdown is closed
expect(instance.state.open).to.equal(false);
instance.toggle(true);
expect(instance.state.open).to.equal(true);
});

it('on toggle false, dropdown closes', () => {
const enzymeWrapper = setup();
const instance = enzymeWrapper.instance();
// set up
instance.setState({ open: true });
expect(instance.state.open).to.equal(true);

instance.toggle(false);
expect(instance.state.open).to.equal(false);
});

it('there are NO otions, ' +
'highlighted index is -1', () => {
// default: no options
const enzymeWrapper = setup();
const instance = enzymeWrapper.instance();
expect(instance.state.highlightedIndex).to.equal(-ONE);
});

it('the INPUT has no value, and there are options, ' +
'the first cell is highlighted', () => {
const enzymeWrapper = setup({ options: DUMMY_ARRAY, defaultValue: '' });
const instance = enzymeWrapper.instance();
expect(instance.state.highlightedIndex).to.equal(ZERO);
});

it('the INPUT has value, the highlighted index ' +
'has value === INPUT.value', () => {
const INPUT_VAL = 'D';
const enzymeWrapper = setup({
options: DUMMY_ARRAY,
defaultValue: INPUT_VAL
});
const instance = enzymeWrapper.instance();
expect(instance.state.highlightedIndex)
.to.equal(DUMMY_ARRAY.indexOf(INPUT_VAL));
});

it('up key wraps around the highlighted index. 0 -> options.length-1', () => {
const ARR_LEN = DUMMY_ARRAY.length;
const newIndex = Dropdown.getupdatedIndex(ZERO, ARR_LEN, true);
expect(newIndex).to.equal(ARR_LEN-ONE);
});

it('down key increments the highlighted index, when index === 0', () => {
const newIndex = Dropdown.getupdatedIndex(ZERO, DUMMY_ARRAY.length, false);
expect(newIndex).to.equal(ONE);
});

it('on enter, url changes to end with the value of' +
' the highlighted cell');

it('calling close from props closes the dropdown', () => {
const enzymeWrapper = setup();
const instance = enzymeWrapper.instance();
Expand Down
122 changes: 104 additions & 18 deletions view/admin/components/common/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/

import React, { PropTypes } from 'react';
const ZERO = 0;
const ONE = 1;

/**
* Returns subset of data array that matches text.
Expand All @@ -23,34 +25,79 @@ import React, { PropTypes } from 'react';
*/
function filterData(dataArr, searchText, callback) {
const data = dataArr.filter(
(entry) => entry.toUpperCase().indexOf(searchText.toUpperCase()) > -1
(entry) => entry.toUpperCase().indexOf(searchText.toUpperCase()) > -ONE
);
callback(data);
}

/**
* Returns the index of the defaultValue in array options.
* Or -1 if empty array
* @param {Array} options
* @param {String} defaultValue
* @returns {Integer} Index of the defaultValue in options
*/
function getIndexFromArray(options, defaultValue) {
let index = -ONE; // default: no options in dropdown
if (options.length) {
index = options.indexOf(defaultValue);
// indexOf might return 0
if (index < ZERO) {
index = ZERO;
}
}
return index;
}

class Dropdown extends React.Component {

/**
* The index wraps around SIZE
* @param {String} oldIndex
* @param {Integer} size
* @param {Bool} direction true to go up,
* false to go down (increment index)
* @returns {Integer} updated index
*/
static getupdatedIndex(oldIndex, size, direction) {
let newIndex = ZERO;
if (direction) {
newIndex = oldIndex === ZERO ? size-ONE : oldIndex-ONE;
} else {
newIndex = (oldIndex+ONE)%size;
}

return newIndex;
}

constructor(props) {
super(props);
this.state = {
open: false, // dropdown is open or closed
data: [], // data in dropdown
highlightedIndex: getIndexFromArray(props.options, props. defaultValue),
};
this.handleClose = this.handleClose.bind(this);
this.toggle = this.toggle.bind(this);
}
componentDidMount() {
// click anywhere outside of container
// to hide dropdown
const containerEl = this.refs.dropdown;
const closeDropdown = this.handleClose;
const closeDropdown = this.toggle;
document.addEventListener('click', (event) => {
if (!containerEl.contains(event.target)) {
closeDropdown();
closeDropdown(false);
}
}, true);
}
handleClose() {

/**
* @param {Boolean} bool If true, open
* else close
*/
toggle(bool) {
this.setState({
open: false,
open: bool,
});
}
handleFocus() {
Expand All @@ -60,20 +107,55 @@ class Dropdown extends React.Component {
data: this.props.options,
});
}
handleKeyUp(event) {
const searchText = event.target.value || '';
this.setState({ data: [] });
filterData(this.props.options, searchText, (data) => {
this.setState({ data, loading: false });
});
handleKeyUp(evt) {
const Key = {
UP: 38,
DOWN: 40,
ENTER: 13,
};
// enter key, up or down key, or text change
const event = evt || window.event; // for IE compatible
// also for cross-browser compatible
const keycode = event.keyCode || event.which;
const { highlightedIndex } = this.state;
const { getupdatedIndex } = this.constructor;
const { options } = this.props;
if (keycode === Key.UP) {
this.setState({
highlightedIndex: getupdatedIndex(
highlightedIndex,
options.length,
true,
),
});
} else if (keycode === Key.DOWN) {
this.setState({
highlightedIndex: getupdatedIndex(
highlightedIndex,
options.length,
false,
),
});
} else if (keycode === Key.ENTER) {
const persName = options[highlightedIndex];
window.location.href = '/perspectives/' + persName;
} else {
const searchText = event.target.value || '';
this.setState({ data: [] });
filterData(this.props.options, searchText, (data) => {
this.setState({ data, loading: false });
});
}
}
componentWillReceiveProps(nextProps) {
// update dropdown options on props change
if (nextProps.options !== this.props.options) {
this.setState({ data: nextProps.options });
this.setState({
data: nextProps.options,
});
}
if (nextProps.close) {
this.handleClose();
this.toggle(false);
}
}
render () {
Expand All @@ -82,25 +164,29 @@ class Dropdown extends React.Component {
dropDownStyle,
allOptionsLabel,
placeholderText,
defaultValue,
title,
showSearchIcon,
onAddNewButton,
onClickItem,
showInputElem,
children, // react elements
defaultValue,
} = this.props;
const { data } = this.state;
let outputUL = '';
// if options exist, load them
if (data.length) {
outputUL = <ul className='slds-lookup__list' role='presentation'>
{data.map((optionsName) => {
{data.map((optionsName, index) => {
let className = 'slds-lookup__item-action ' +
'slds-media slds-media--center';
if (index === this.state.highlightedIndex) {
className += ' highlighted';
}
return (
<li key={ optionsName }
onClick={ onClickItem }
className={'slds-lookup__item-action ' +
'slds-media slds-media--center'}>
className={ className }>
<svg aria-hidden='true'
className={'slds-icon slds-icon-standard-account' +
' slds-icon--small slds-media__figure'}>
Expand Down

0 comments on commit cb62935

Please sign in to comment.