1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
const React = require('react');
const ReactRedux = require('react-redux');
const navigation = require('../actions/navigation');
/**
* Check if an element is inside a link
* @param {DOMElement} el
* @param {String} name
* @return {DOMElement|undefined
*/
function findParentByTagName(el, name) {
while (el && el !== document) {
if (el.tagName && el.tagName.toUpperCase() === name) {
return el;
}
el = el.parentNode;
}
return false;
}
/**
* Internal: Return the `href` component of given URL object with the hash
* portion removed.
*
* @param {Location|HTMLAnchorElement} location
* @return {String}
*/
function stripHash(location) {
return location.href.replace(/#.*/, '');
}
/**
* Test if a click event should be handled,
* return the new url if it's a normal lcick
*/
function getHrefForEvent(event) {
const link = findParentByTagName(event.target, 'A');
if (!link)
return;
// Middle click, cmd click, and ctrl click should open
// links in a new tab as normal.
if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
return;
// Ignore cross origin links
if (location.protocol !== link.protocol || location.hostname !== link.hostname)
return;
// Ignore case when a hash is being tacked on the current URL
if (link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location))
return;
// Ignore event with default prevented
if (event.defaultPrevented)
return;
// Explicitly ignored
if (link.getAttribute('data-nopjax'))
return;
return link.href;
}
/*
Wrapper to bind all navigation events to fetch pages.
*/
const PJAXWrapper = React.createClass({
propTypes: {
children: React.PropTypes.node,
dispatch: React.PropTypes.func
},
onClick(event) {
const { dispatch } = this.props;
const href = getHrefForEvent(event);
if (!href) {
return;
}
event.preventDefault();
dispatch(navigation.fetchPage(href));
},
onPopState(event) {
const { dispatch } = this.props;
event.preventDefault();
dispatch(navigation.fetchPage(location.href, { replace: true }));
},
componentDidMount() {
document.addEventListener('click', this.onClick, false);
window.addEventListener('popstate', this.onPopState, false);
},
componentWillUnmount() {
document.removeEventListener('click', this.onClick, false);
window.removeEventListener('popstate', this.onPopState, false);
},
render() {
return React.Children.only(this.props.children);
}
});
module.exports = ReactRedux.connect()(PJAXWrapper);
|