Skip to content

Commit 76951e7

Browse files
committed
Merge branch 'features/delay-func'
2 parents cc15d7f + 289e236 commit 76951e7

File tree

7 files changed

+98
-15
lines changed

7 files changed

+98
-15
lines changed

examples/delay/app.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ import React, { Component, PropTypes } from 'react';
22
import { connect } from 'react-redux';
33
import { Tooltip, Origin, actions } from '../../src/index';
44

5-
const { hide, delay } = actions;
5+
const { show, hide, delay } = actions;
66

77
class App extends Component {
8+
handleTimeout(type, duration) {
9+
this.props.dispatch(show({ origin: this.refs.bold }));
10+
}
11+
812
render() {
913
return (
1014
<div>
@@ -28,6 +32,11 @@ class App extends Component {
2832
You need to stay a while on it. Delay on <Origin delay delayOn="both" className="target">both</Origin>.
2933
</p>
3034

35+
<h2>Timeout callback</h2>
36+
<p>
37+
The callback function is <b ref="bold">called</b> when <Origin delay className="target" onTimeout={this.handleTimeout.bind(this)}>timeout</Origin>.
38+
</p>
39+
3140
<Tooltip>
3241
This is a <b>delay</b> tooltip.
3342
</Tooltip>

src/actions.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ export const content = createAction(CONTENT);
1717
export const place = createAction(PLACE);
1818

1919
export const DELAY = prefix('delay');
20-
const DEFAULT_DURATION = 1500;
21-
export function delay(action, duration = DEFAULT_DURATION) {
20+
const DURATION = 1500;
21+
export function delay(action, { duration, callback } = { duration: DURATION }) {
2222
if (!action.meta) {
2323
action.meta = {};
2424
}
25-
if (duration === true) {
26-
duration = DEFAULT_DURATION;
25+
if (typeof duration === 'undefined' || duration === true) {
26+
duration = DURATION;
2727
}
28-
action.meta[DELAY] = parseInt(duration);
28+
action.meta[DELAY] = { duration: parseInt(duration), callback };
2929
return action;
3030
}
3131

src/middleware.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default function middleware(store) {
2727
}
2828

2929
// Setup timeout
30+
const { duration, callback } = action.meta[DELAY];
3031
names.forEach(name => {
3132
const newToken = setTimeout(() => {
3233
// Ignore if token is cleared
@@ -38,8 +39,11 @@ export default function middleware(store) {
3839
// Dispatch original action
3940
delete action.meta[DELAY];
4041
next(action);
42+
43+
// Notify via callback
44+
callback && callback(action.type, duration, action);
4145
}
42-
}, action.meta[DELAY]);
46+
}, duration);
4347

4448
// Store timeout token
4549
next(startTimeout({ name, token: newToken }));

src/origin.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ class Origin extends Component {
1818
PropTypes.string,
1919
PropTypes.arrayOf(PropTypes.string)
2020
]),
21+
tagName: PropTypes.string,
2122
delay: PropTypes.oneOfType([
2223
PropTypes.bool,
2324
PropTypes.number,
2425
PropTypes.string
2526
]),
2627
delayOn: PropTypes.oneOf(['show', 'hide', 'both']),
27-
tagName: PropTypes.string,
28+
onTimeout: PropTypes.func,
2829
onMouseEnter: PropTypes.func,
2930
onMouseLeave: PropTypes.func,
3031
};
@@ -55,10 +56,10 @@ class Origin extends Component {
5556
}
5657

5758
createWithDelay(creator, extras = {}) {
58-
const { delay: duration } = this.props;
59+
const { delay: duration, onTimeout: callback } = this.props;
5960
let action = creator({ ...this.props, ...extras });
60-
if (duration) {
61-
action = delay(action, duration || undefined);
61+
if (duration || callback) {
62+
action = delay(action, { duration, callback });
6263
}
6364
return action;
6465
}

tests/feature/delay.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import React from 'react';
33
import ReactDOM from 'react-dom';
44
import TestUtils from 'react-addons-test-utils';
55
import { Provider } from 'react-redux';
6-
import { Tooltip, Origin } from '../../src/index';
6+
import { Tooltip, Origin, utils } from '../../src/index';
77
import App from '../../examples/delay/app';
88
import store from '../../examples/common/store';
99
import { firstComponent, getStyleValue } from '../helpers';
1010

11+
const { position } = utils;
12+
1113
describe('Delay Example', () => {
1214
before(() => {
1315
document.body.innerHTML += '<div id="container" style="position:absolute;top:0;left:0;"></div>';
@@ -208,4 +210,30 @@ describe('Delay Example', () => {
208210
assert(getStyleValue(tooltip, 'visibility') === 'hidden', 'tooltip should be hidden');
209211
});
210212
});
213+
214+
describe('timeout callback', () => {
215+
it('should be worked', () => {
216+
// Mouseover and mouseout
217+
const origin = firstComponent(tree, Origin.WrappedComponent, { onTimeout: undefined }).refs.wrapper;
218+
TestUtils.Simulate.mouseEnter(origin);
219+
TestUtils.Simulate.mouseLeave(origin);
220+
221+
const tooltip = firstComponent(tree, Tooltip.WrappedComponent).refs.tooltip;
222+
assert(getStyleValue(tooltip, 'visibility') === 'visible');
223+
224+
const pos1 = position(tooltip);
225+
226+
// 2 seconds later
227+
clock.tick(2000);
228+
assert(getStyleValue(tooltip, 'visibility') === 'visible');
229+
230+
const pos2 = position(tooltip);
231+
assert(pos2.left < pos1.left);
232+
assert(pos2.top === pos1.top);
233+
234+
// 10 seconds later
235+
clock.tick(10000);
236+
assert(getStyleValue(tooltip, 'visibility') === 'visible');
237+
});
238+
});
211239
});

tests/helpers.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ export function scryComponents(tree, cls, props = {}) {
66
const components = TestUtils.scryRenderedComponentsWithType(tree, cls);
77
return components.filter(comp => {
88
return Object.keys(props).map(key => {
9-
return equal(comp.props[key], props[key]);
9+
if (typeof props[key] === 'undefined') {
10+
return !!comp.props[key];
11+
} else {
12+
return equal(comp.props[key], props[key]);
13+
}
1014
}).reduce((prev, val) => prev && val, true);
1115
});
1216
}

tests/unit/test_actions.js

+39-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,41 @@ describe('actions', () => {
1818
value: 123
1919
},
2020
meta: {
21-
'redux-tooltip/delay': 1500,
21+
'redux-tooltip/delay': {
22+
duration: 1500,
23+
callback: undefined,
24+
},
25+
}
26+
});
27+
});
28+
29+
it('overwrites default duration', () => {
30+
assert.deepStrictEqual(actions.delay(action, { duration: 500 }), {
31+
type: 'WOO',
32+
payload: {
33+
value: 123
34+
},
35+
meta: {
36+
'redux-tooltip/delay': {
37+
duration: 500,
38+
callback: undefined,
39+
},
40+
}
41+
});
42+
});
43+
44+
it('overwrites default duration', () => {
45+
const fn = () => {};
46+
assert.deepStrictEqual(actions.delay(action, { callback: fn }), {
47+
type: 'WOO',
48+
payload: {
49+
value: 123
50+
},
51+
meta: {
52+
'redux-tooltip/delay': {
53+
duration: 1500,
54+
callback: fn,
55+
},
2256
}
2357
});
2458
});
@@ -47,7 +81,10 @@ describe('actions', () => {
4781
},
4882
meta: {
4983
gem: 'bundler',
50-
'redux-tooltip/delay': 1500,
84+
'redux-tooltip/delay': {
85+
duration: 1500,
86+
callback: undefined,
87+
},
5188
}
5289
});
5390
});

0 commit comments

Comments
 (0)