Skip to content

Commit

Permalink
compile the lib
Browse files Browse the repository at this point in the history
  • Loading branch information
Zachary Hickman committed Mar 31, 2016
1 parent df1aac7 commit dd0fda8
Show file tree
Hide file tree
Showing 7 changed files with 848 additions and 0 deletions.
13 changes: 13 additions & 0 deletions lib/keyevent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* PolyFills make me sad
*/
var KeyEvent = KeyEvent || {};
KeyEvent.DOM_VK_UP = KeyEvent.DOM_VK_UP || 38;
KeyEvent.DOM_VK_DOWN = KeyEvent.DOM_VK_DOWN || 40;
KeyEvent.DOM_VK_BACK_SPACE = KeyEvent.DOM_VK_BACK_SPACE || 8;
KeyEvent.DOM_VK_RETURN = KeyEvent.DOM_VK_RETURN || 13;
KeyEvent.DOM_VK_ENTER = KeyEvent.DOM_VK_ENTER || 14;
KeyEvent.DOM_VK_ESCAPE = KeyEvent.DOM_VK_ESCAPE || 27;
KeyEvent.DOM_VK_TAB = KeyEvent.DOM_VK_TAB || 9;

module.exports = KeyEvent;
7 changes: 7 additions & 0 deletions lib/react-typeahead.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var Typeahead = require('./typeahead');
var Tokenizer = require('./tokenizer');

module.exports = {
Typeahead: Typeahead,
Tokenizer: Tokenizer
};
210 changes: 210 additions & 0 deletions lib/tokenizer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/**
* @jsx React.DOM
*/

var React = require('react');
var Token = require('./token');
var KeyEvent = require('../keyevent');
var Typeahead = require('../typeahead');
var classNames = require('classnames');

function _arraysAreDifferent(array1, array2) {
if (array1.length != array2.length){
return true;
}
for (var i = array2.length - 1; i >= 0; i--) {
if (array2[i] !== array1[i]){
return true;
}
}
}

/**
* A typeahead that, when an option is selected, instead of simply filling
* the text entry widget, prepends a renderable "token", that may be deleted
* by pressing backspace on the beginning of the line with the keyboard.
*/
var TypeaheadTokenizer = React.createClass({displayName: "TypeaheadTokenizer",
propTypes: {
name: React.PropTypes.string,
options: React.PropTypes.array,
customClasses: React.PropTypes.object,
allowCustomValues: React.PropTypes.number,
defaultSelected: React.PropTypes.array,
defaultValue: React.PropTypes.string,
placeholder: React.PropTypes.string,
disabled: React.PropTypes.bool,
inputProps: React.PropTypes.object,
onTokenRemove: React.PropTypes.func,
onKeyDown: React.PropTypes.func,
onKeyPress: React.PropTypes.func,
onKeyUp: React.PropTypes.func,
onTokenAdd: React.PropTypes.func,
onFocus: React.PropTypes.func,
onBlur: React.PropTypes.func,
filterOption: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.func
]),
displayOption: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.func
]),
maxVisible: React.PropTypes.number,
defaultClassNames: React.PropTypes.bool
},

getInitialState: function() {
return {
// We need to copy this to avoid incorrect sharing
// of state across instances (e.g., via getDefaultProps())
selected: this.props.defaultSelected.slice(0)
};
},

getDefaultProps: function() {
return {
options: [],
defaultSelected: [],
customClasses: {},
allowCustomValues: 0,
defaultValue: "",
placeholder: "",
disabled: false,
inputProps: {},
defaultClassNames: true,
filterOption: null,
displayOption: function(token){return token },
onKeyDown: function(event) {},
onKeyPress: function(event) {},
onKeyUp: function(event) {},
onFocus: function(event) {},
onBlur: function(event) {},
onTokenAdd: function() {},
onTokenRemove: function() {}
};
},

componentWillReceiveProps: function(nextProps){
// if we get new defaultProps, update selected
if (_arraysAreDifferent(this.props.defaultSelected, nextProps.defaultSelected)){
this.setState({selected: nextProps.defaultSelected.slice(0)})
}
},

focus: function(){
this.refs.typeahead.focus();
},

getSelectedTokens: function(){
return this.state.selected;
},

// TODO: Support initialized tokens
//
_renderTokens: function() {
var tokenClasses = {};
tokenClasses[this.props.customClasses.token] = !!this.props.customClasses.token;
var classList = classNames(tokenClasses);
var result = this.state.selected.map(function(selected) {
var displayString = this.props.displayOption(selected);
return (
React.createElement(Token, {key: displayString, className: classList,
onRemove: this._removeTokenForValue,
object: selected,
name: this.props.name},
displayString
)
);
}, this);
return result;
},

_getOptionsForTypeahead: function() {
// return this.props.options without this.selected
return this.props.options;
},

_onKeyDown: function(event) {
// We only care about intercepting backspaces
if (event.keyCode === KeyEvent.DOM_VK_BACK_SPACE) {
return this._handleBackspace(event);
}
this.props.onKeyDown(event);
},

_handleBackspace: function(event){
// No tokens
if (!this.state.selected.length) {
return;
}

// Remove token ONLY when bksp pressed at beginning of line
// without a selection
var entry = this.refs.typeahead.refs.entry;
if (entry.selectionStart == entry.selectionEnd &&
entry.selectionStart == 0) {
this._removeTokenForValue(
this.state.selected[this.state.selected.length - 1]);
event.preventDefault();
}
},

_removeTokenForValue: function(value) {
var index = this.state.selected.indexOf(value);
if (index == -1) {
return;
}

this.state.selected.splice(index, 1);
this.setState({selected: this.state.selected});
this.props.onTokenRemove(value);
return;
},

_addTokenForValue: function(value) {
if (this.state.selected.indexOf(value) != -1) {
return;
}
this.state.selected.push(value);
this.setState({selected: this.state.selected});
this.refs.typeahead.setEntryText("");
this.props.onTokenAdd(value);
},

render: function() {
var classes = {};
classes[this.props.customClasses.typeahead] = !!this.props.customClasses.typeahead;
var classList = classNames(classes);
var tokenizerClasses = [this.props.defaultClassNames && "typeahead-tokenizer"];
tokenizerClasses[this.props.className] = !!this.props.className;
var tokenizerClassList = classNames(tokenizerClasses)

return (
React.createElement("div", {className: tokenizerClassList},
this._renderTokens(),
React.createElement(Typeahead, {ref: "typeahead",
className: classList,
placeholder: this.props.placeholder,
disabled: this.props.disabled,
inputProps: this.props.inputProps,
allowCustomValues: this.props.allowCustomValues,
customClasses: this.props.customClasses,
options: this._getOptionsForTypeahead(),
defaultValue: this.props.defaultValue,
maxVisible: this.props.maxVisible,
onOptionSelected: this._addTokenForValue,
onKeyDown: this._onKeyDown,
onKeyPress: this.props.onKeyPress,
onKeyUp: this.props.onKeyUp,
onFocus: this.props.onFocus,
onBlur: this.props.onBlur,
displayOption: this.props.displayOption,
defaultClassNames: this.props.defaultClassNames,
filterOption: this.props.filterOption})
)
);
}
});

module.exports = TypeaheadTokenizer;
67 changes: 67 additions & 0 deletions lib/tokenizer/token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* @jsx React.DOM
*/

var React = require('react');
var classNames = require('classnames');

/**
* Encapsulates the rendering of an option that has been "selected" in a
* TypeaheadTokenizer
*/
var Token = React.createClass({displayName: "Token",
propTypes: {
className: React.PropTypes.string,
name: React.PropTypes.string,
children: React.PropTypes.string,
object: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.object,
]),
onRemove: React.PropTypes.func
},

render: function() {
var className = classNames([
"typeahead-token",
this.props.className
]);

return (
React.createElement("div", {className: className},
this._renderHiddenInput(),
this.props.children,
this._renderCloseButton()
)
);
},

_renderHiddenInput: function() {
// If no name was set, don't create a hidden input
if (!this.props.name) {
return null;
}

return (
React.createElement("input", {
type: "hidden",
name: this.props.name + '[]',
value: this.props.object}
)
);
},

_renderCloseButton: function() {
if (!this.props.onRemove) {
return "";
}
return (
React.createElement("a", {className: "typeahead-token-close", href: "#", onClick: function(event) {
this.props.onRemove(this.props.object);
event.preventDefault();
}.bind(this)}, "×")
);
}
});

module.exports = Token;
Loading

0 comments on commit dd0fda8

Please sign in to comment.