Skip to content

Commit

Permalink
clean up timeouts and filter logic
Browse files Browse the repository at this point in the history
fixes #46 by making sure that pending timeouts are cleared on unmount,
for cases like modal layers and portals
  • Loading branch information
jquense committed Feb 6, 2015
1 parent c606b9f commit 8781a47
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 119 deletions.
35 changes: 35 additions & 0 deletions example/example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ var SelectList = require('../src/SelectList.jsx')
var chance = new (require('chance'))
var _ = require('lodash')

var { ModalTrigger
, Modal } = require('react-bootstrap')

// var g = require('globalize')
var culture = require('globalize/lib/cultures/globalize.culture.es');
Expand All @@ -26,6 +28,26 @@ var ListItem = React.createClass({
// var a = { a:1, b: 3};
// var c = { ...a, x: 1 };

var MyModal = React.createClass({
render: function() {
var list = generateList()
return (
<Modal {...this.props} title="Modal heading" animation={false}>
<DropdownList
isRtl={false}
id='MyDropdownList'
data={ list }
textField='name'
valueField='id'
defaultValue={list[1]}/>
<div className="modal-footer">
<button onClick={this.props.onRequestHide}>Close</button>
</div>
</Modal>
);
}
});

var App = React.createClass({

getInitialState: function(){
Expand Down Expand Up @@ -77,6 +99,9 @@ var App = React.createClass({
return (
<div style={{ fontSize: 14 }}>
<div style={{ maxWidth: 600 }}>
<ModalTrigger modal={<MyModal />}>
<button>Launch demo modal</button>
</ModalTrigger>
{/*<section className="example">
<div style={{ height: 150 }}>
sgsdgsdg sdgdg<br/>assdgsdgsdg<br/>asdasdasdasdasd
Expand All @@ -94,6 +119,16 @@ var App = React.createClass({
</section>*/}

<section className="example" style={{ marginBottom: 20 }}>
<SelectList style={{ maxHeight: 300 }}
textField='name'
valueField='id'
data={this.state.data}
value={this.state.selectValues}
disabled={[1 ,6]}
busy={false}
name="super_name"
multiple
onChange={change.bind(null, 'selectValues')}/>
<DropdownList
isRtl={false}
id='MyDropdownList'
Expand Down
7 changes: 5 additions & 2 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />


<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="../dist/css/react-widgets.css" rel="stylesheet">
<meta charset="utf-8" />


<title>React Widgets</title>
<style>
body {
Expand Down
7 changes: 3 additions & 4 deletions src/Calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ var Calendar = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/PureRenderMixin'),
require('./mixins/RtlParentContextMixin')
],
Expand Down Expand Up @@ -217,9 +218,7 @@ var Calendar = React.createClass({
if ( +this.props.tabIndex === -1)
return

clearTimeout(this.timer)

this.timer = setTimeout(() =>{
this.setTimeout('focus', () => {

if(focused)
this.getDOMNode().focus()
Expand All @@ -232,7 +231,7 @@ var Calendar = React.createClass({
},

change: function(date){
setTimeout( () => this._focus(true))
setTimeout(() => this._focus(true))

if ( this.props.onChange && this.state.view === this.props.initialView)
return this.notify('onChange', date)
Expand Down
2 changes: 1 addition & 1 deletion src/Combobox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var ComboBox = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TextSearchMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/DataFilterMixin'),
require('./mixins/DataHelpersMixin'),
require('./mixins/PopupScrollToMixin'),
Expand Down
5 changes: 2 additions & 3 deletions src/DateTimePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ var DateTimePicker = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/PureRenderMixin'),
require('./mixins/PopupScrollToMixin'),
require('./mixins/RtlParentContextMixin')
Expand Down Expand Up @@ -265,9 +266,7 @@ var DateTimePicker = React.createClass({
_focus: function(focused, e){
var input = this.refs.valueInput;

clearTimeout(this.timer)

this.timer = setTimeout(() =>{
this.setTimeout('focus', () => {

if(focused) input.getDOMNode().focus()
else this.close()
Expand Down
25 changes: 12 additions & 13 deletions src/DropdownList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var DropdownList = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/PureRenderMixin'),
require('./mixins/DataHelpersMixin'),
require('./mixins/PopupScrollToMixin'),
Expand All @@ -72,6 +73,8 @@ var DropdownList = React.createClass({
getInitialState: function(){
var initialIdx = this._dataIndexOf(this.props.data, this.props.value);

this._timers = Object.create(null);

return {
selectedItem: this.props.data[initialIdx],
focusedItem: this.props.data[initialIdx] || this.props.data[0],
Expand All @@ -90,7 +93,7 @@ var DropdownList = React.createClass({
}
},

componentDidMount: function() {
componentDidMount() {

This comment has been minimized.

Copy link
@schutterp

schutterp Feb 6, 2015

looks like an unintended code change here

This comment has been minimized.

Copy link
@jquense

jquense Feb 6, 2015

Author Owner

not sure what you mean, which change?

This comment has been minimized.

Copy link
@schutterp

schutterp Feb 6, 2015

Nevermind it looks ok. the diff is showing the line as componentDidMount() { and I thought it was missing the componentDidMount: function part. The diff shouldn't look like that, but either way it's my bad.

Thanks!

validateList(this.refs.list)
},

Expand Down Expand Up @@ -170,20 +173,17 @@ var DropdownList = React.createClass({
},

_focus: function(focused, e){
var self = this;

clearTimeout(self.timer)
self.timer = setTimeout(function(){
this.setTimeout('focus', () => {

if(focused) self.getDOMNode().focus()
else self.close()
if(focused) this.getDOMNode().focus()
else this.close()

if( focused !== self.state.focused){
self.notify(focused ? 'onFocus' : 'onBlur', e)
self.setState({ focused: focused })
if( focused !== this.state.focused){
this.notify(focused ? 'onFocus' : 'onBlur', e)
this.setState({ focused: focused })
}

}, 0)
})
},

_onSelect: function(data){
Expand Down Expand Up @@ -262,10 +262,9 @@ var DropdownList = React.createClass({
search: function(character, cb){
var word = ((this._searchTerm || '') + character).toLowerCase();

clearTimeout(this._timer)
this._searchTerm = word

this._timer = setTimeout(() => {
this.setTimeout('search', () => {
var list = this.refs.list
, key = this.props.open ? 'focusedItem' : 'selectedItem'
, item = list.next(this.state[key], word);
Expand Down
5 changes: 2 additions & 3 deletions src/Multiselect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ var Multiselect = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/DataFilterMixin'),
require('./mixins/DataHelpersMixin'),
require('./mixins/PopupScrollToMixin'),
Expand Down Expand Up @@ -234,9 +235,7 @@ var Multiselect = React.createClass({
if (this.props.disabled === true )
return

clearTimeout(this.timer)

this.timer = setTimeout(() => {
this.setTimeout('focus', () => {
if( focused) {
this.refs.input.focus()
this.open()
Expand Down
4 changes: 2 additions & 2 deletions src/NumberPicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ var NumberPicker = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/PureRenderMixin'),
require('./mixins/RtlParentContextMixin'),
],
Expand Down Expand Up @@ -182,9 +183,8 @@ var NumberPicker = React.createClass({
},

_focus: function(focused, e){
clearTimeout(this.timer)

this.timer = setTimeout(() =>{
this.setTimeout('focus', () => {
var el = this.refs.input.getDOMNode()

focused && el.focus()
Expand Down
42 changes: 25 additions & 17 deletions src/SelectList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var React = require('react')
, PlainList = require('./List')
, GroupableList = require('./ListGroupable')
, validateList = require('./util/validateListInterface')
, filter = require('./util/filter')
, scrollTo = require('./util/dom/scroll');

var propTypes = {
Expand All @@ -29,6 +30,7 @@ var propTypes = {

busy: React.PropTypes.bool,

filter: React.PropTypes.string,
delay: React.PropTypes.number,

disabled: React.PropTypes.oneOfType([
Expand All @@ -55,7 +57,7 @@ var SelectList = React.createClass({

mixins: [
require('./mixins/WidgetMixin'),
require('./mixins/TextSearchMixin'),
require('./mixins/TimeoutMixin'),
require('./mixins/DataHelpersMixin'),
require('./mixins/RtlParentContextMixin')
],
Expand Down Expand Up @@ -135,6 +137,7 @@ var SelectList = React.createClass({
'rw-loading-mask': this.props.busy
})}>
<List ref='list'
{..._.pick(this.props, Object.keys(List.type.propTypes))}
data={this._data()}
focused={focusedItem}
optID ={optID}
Expand Down Expand Up @@ -196,9 +199,7 @@ var SelectList = React.createClass({
this._selectAll()
}
else
this.search(
String.fromCharCode(e.keyCode)
, this._locate)
this.search(String.fromCharCode(e.keyCode))

function change(item, cked){
if( item ){
Expand Down Expand Up @@ -258,17 +259,13 @@ var SelectList = React.createClass({
},

_focus: function(focused, e){
var self = this;

clearTimeout(self.timer)

self.timer = setTimeout(function(){
if( focused) self.getDOMNode().focus()
if( focused !== self.state.focused){
self.setState({ focused: focused })
//!focused && self.next(0)
this.setTimeout('focus', () => {
if( focused) this.getDOMNode().focus()
if( focused !== this.state.focused){
this.setState({ focused: focused })
}
}, 0)
})
},

isDisabledItem: function(item) {
Expand All @@ -279,11 +276,21 @@ var SelectList = React.createClass({
return this.isReadOnly() || this._contains(item, this.props.readOnly)
},

_locate: function(word){
var idx = this.findNextWordIndex(word, this.state.focusedIndex);
search: function(character){
var word = ((this._searchTerm || '') + character).toLowerCase()
, list = this.refs.list;

this._searchTerm = word

this.setTimeout('search', () => {
var focusedItem = list.next(this.state.focusedItem, word);

if ( idx !== -1)
this.setFocusedIndex(idx)
this._searchTerm = ''

if ( focusedItem)
this.setState({ focusedItem })

}, this.props.delay)
},

_data:function(){
Expand All @@ -304,6 +311,7 @@ var SelectList = React.createClass({

});


function getListItem(parent){

return React.createClass({
Expand Down
13 changes: 8 additions & 5 deletions src/TimeList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ module.exports = React.createClass({
culture: React.PropTypes.string,
},

getDefaultProps: function(){
mixins: [
require('./mixins/TimeoutMixin')
],

getDefaultProps(){
return {
step: 30,
format: 't',
Expand All @@ -31,7 +35,7 @@ module.exports = React.createClass({
}
},

getInitialState: function(){
getInitialState(){
var data = this._dates(this.props)
, focusedItem = this._closestDate(data, this.props.value);

Expand All @@ -41,7 +45,7 @@ module.exports = React.createClass({
}
},

componentWillReceiveProps: function(nextProps) {
componentWillReceiveProps(nextProps) {
var data = this._dates(nextProps)
, focusedItem = this._closestDate(data, this.props.value);

Expand Down Expand Up @@ -170,10 +174,9 @@ module.exports = React.createClass({
search: function(character, cb){
var word = ((this._searchTerm || '') + character).toLowerCase();

clearTimeout(this._timer)
this._searchTerm = word

this._timer = setTimeout(() => {
this.setTimeout('search', () => {
var list = this.refs.list
, item = list.next(this.state.focusedItem, word);

Expand Down
3 changes: 1 addition & 2 deletions src/mixins/DataFilterMixin.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use strict';
var React = require('react')
, filters = require('../util/filter')
, helper = require('./DataHelpersMixin')
, _ = require('../util/_');
, helper = require('./DataHelpersMixin');

var filterTypes = Object.keys(filters).filter( i => i !== 'filter')

Expand Down
Loading

0 comments on commit 8781a47

Please sign in to comment.