-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
/
Copy pathLink.js
147 lines (120 loc) · 3.61 KB
/
Link.js
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
var React = require('react');
var ActiveState = require('../mixins/ActiveState');
var withoutProperties = require('../helpers/withoutProperties');
var transitionTo = require('../helpers/transitionTo');
var makeHref = require('../helpers/makeHref');
var hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
/**
* A map of <Link> component props that are reserved for use by the
* router and/or React. All other props are used as params that are
* interpolated into the link's path.
*/
var RESERVED_PROPS = {
to: true,
className: true,
activeClassName: true,
query: true,
children: true // ReactChildren
};
/**
* <Link> components are used to create an <a> element that links to a route.
* When that route is active, the link gets an "active" class name (or the
* value of its `activeClassName` prop).
*
* For example, assuming you have the following route:
*
* <Route name="showPost" path="/posts/:postId" handler={Post}/>
*
* You could use the following component to link to that route:
*
* <Link to="showPost" postId="123"/>
*
* In addition to params, links may pass along query string parameters
* using the `query` prop.
*
* <Link to="showPost" postId="123" query={{show:true}}/>
*/
var Link = React.createClass({
displayName: 'Link',
mixins: [ ActiveState ],
statics: {
getUnreservedProps: function (props) {
return withoutProperties(props, RESERVED_PROPS);
}
},
propTypes: {
to: React.PropTypes.string.isRequired,
activeClassName: React.PropTypes.string.isRequired,
query: React.PropTypes.object
},
getDefaultProps: function () {
return {
activeClassName: 'active'
};
},
getInitialState: function () {
return {
isActive: false
};
},
/**
* Returns a hash of URL parameters to use in this <Link>'s path.
*/
getParams: function () {
return Link.getUnreservedProps(this.props);
},
/**
* Returns the value of the "href" attribute to use on the DOM element.
*/
getHref: function () {
return makeHref(this.props.to, this.getParams(), this.props.query);
},
/**
* Returns the value of the "class" attribute to use on the DOM element, which contains
* the value of the activeClassName property when this <Link> is active.
*/
getClassName: function () {
var className = this.props.className || '';
if (this.state.isActive)
return className + ' ' + this.props.activeClassName;
return className;
},
componentWillReceiveProps: function (nextProps) {
var params = Link.getUnreservedProps(nextProps);
this.setState({
isActive: Link.isActive(nextProps.to, params, nextProps.query)
});
},
updateActiveState: function () {
this.setState({
isActive: Link.isActive(this.props.to, this.getParams(), this.props.query)
});
},
handleClick: function (event) {
if (isModifiedEvent(event) || !isLeftClick(event))
return;
event.preventDefault();
transitionTo(this.props.to, this.getParams(), this.props.query);
},
render: function () {
var props = {
href: this.getHref(),
className: this.getClassName(),
onClick: this.handleClick
};
// pull in props without overriding
for (var propName in this.props) {
if (hasOwn(this.props, propName) && hasOwn(props, propName) === false) {
props[propName] = this.props[propName];
}
}
return React.DOM.a(props, this.props.children);
}
});
function isLeftClick(event) {
return event.button === 0;
}
function isModifiedEvent(event) {
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
}
module.exports = Link;