Skip to content

Commit fadce5b

Browse files
committed
Merge pull request #101 from hotosm/develop
Update master
2 parents e20250b + c3922ac commit fadce5b

25 files changed

+1026
-119
lines changed

app/assets/scripts/actions/actions.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ module.exports = Reflux.createActions({
1111

1212
'resultsChange': {},
1313

14+
// Filter actios
15+
'setDateFilter': {
16+
shouldEmit: function (val) {
17+
return [ 'all', 'week', 'month', 'year' ].indexOf(val) >= 0;
18+
}
19+
},
20+
'setResolutionFilter': {
21+
shouldEmit: function (val) {
22+
return [ 'all', 'low', 'medium', 'high' ].indexOf(val) >= 0;
23+
}
24+
},
25+
'setDataTypeFilter': {
26+
shouldEmit: function (val) {
27+
return [ 'all', 'service' ].indexOf(val) >= 0;
28+
}
29+
},
30+
1431
// Results pane related actions.
1532
'resultItemSelect': {},
1633
'resultItemView': {},
@@ -29,4 +46,7 @@ module.exports = Reflux.createActions({
2946
'goToLatest': {},
3047

3148
'geocoderResult': {},
32-
});
49+
50+
51+
'miniMapClick': {},
52+
});

app/assets/scripts/components/app.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,31 @@ var Router = require('react-router');
44
var RouteHandler = Router.RouteHandler;
55
var InfoModal = require('./modals/info_modal');
66
var WelcomeModal = require('./modals/welcome_modal');
7+
var MessageModal = require('./modals/message_modal');
78
var Header = require('./header');
9+
var actions = require('../actions/actions');
810

911
var App = React.createClass({
12+
mixins: [ Router.State ],
1013

11-
aboutClickHandler: function(e) {
12-
e.preventDefault();
13-
actions.openModal('about');
14+
componentDidMount: function () {
15+
// Pull the search filter state from the URL. Why is this here instead
16+
// of in the Filters component? Because we want to ensure that we set
17+
// these filter parameters BEFORE the map component loads, since that is
18+
// where the map move action will get fired, triggering the first API load.
19+
//
20+
// TODO: this is really a stopgap until we integrate the router more
21+
// fully. (See routes.js for more.)
22+
var params = this.getQuery();
23+
if (params.date) {
24+
actions.setDateFilter(params.date);
25+
}
26+
if (params.resolution) {
27+
actions.setResolutionFilter(params.resolution);
28+
}
29+
if (params.type) {
30+
actions.setDataTypeFilter(params.type);
31+
}
1432
},
1533

1634
render: function() {
@@ -22,6 +40,7 @@ var App = React.createClass({
2240
</main>
2341
<WelcomeModal />
2442
<InfoModal />
43+
<MessageModal />
2544
</div>
2645
);
2746
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use strict';
2+
var React = require('react/addons');
3+
var Reflux = require('reflux');
4+
var Router = require('react-router');
5+
var Dropdown = require('./shared/dropdown');
6+
var actions = require('../actions/actions');
7+
var searchQuery = require('../stores/search_query_store');
8+
9+
var Filters = module.exports = React.createClass({
10+
mixins: [
11+
Reflux.listenTo(searchQuery, 'onSearchQuery'),
12+
Router.Navigation,
13+
Router.State
14+
],
15+
16+
getInitialState: function () {
17+
return {
18+
date: 'all',
19+
resolution: 'all',
20+
dataType: 'all'
21+
}
22+
},
23+
24+
onSearchQuery: function (data) {
25+
this.setState(data);
26+
},
27+
28+
setDate: function (d) {
29+
actions.setDateFilter(d.key);
30+
this._updateUrl('date', d.key);
31+
},
32+
33+
setResolution: function (d) {
34+
actions.setResolutionFilter(d.key);
35+
this._updateUrl('resolution', d.key)
36+
},
37+
38+
setDataType: function (d) {
39+
actions.setDataTypeFilter(d.key);
40+
this._updateUrl('type', d.key);
41+
},
42+
43+
_updateUrl: function (prop, value) {
44+
var query = this.getQuery();
45+
if (value === 'all') {
46+
delete query[prop]
47+
} else {
48+
query[prop] = value;
49+
}
50+
var routes = this.getRoutes();
51+
this.replaceWith(routes[routes.length - 1].name, this.getParams(), query);
52+
},
53+
54+
55+
render: function() {
56+
function filterItem (property, clickHandler, d) {
57+
var klass = this.state[property] === d.key ? 'active' : '';
58+
var click = clickHandler.bind(this, d);
59+
return (
60+
<dd key={property + '-filter-' + d.key} className={klass}>
61+
<a onClick={click} title={d.title}>{d.title}</a>
62+
</dd>);
63+
}
64+
65+
var dates = [
66+
{key: 'all', title: 'All'},
67+
{key: 'week', title: 'Last week'},
68+
{key: 'month', title: 'Last month'},
69+
{key: 'year', title: 'Last year'}
70+
].map(filterItem.bind(this, 'date', this.setDate));
71+
72+
var resolutions = [
73+
{key: 'all', title: 'All'},
74+
{key: 'low', title: 'Low'},
75+
{key: 'medium', title: 'Medium'},
76+
{key: 'high', title: 'High'}
77+
].map(filterItem.bind(this, 'resolution', this.setResolution));
78+
79+
var dataTypes = [
80+
{key: 'all', title: 'All Images'},
81+
{key: 'service', title: 'Image + Map Layer'}
82+
].map(filterItem.bind(this, 'dataType', this.setDataType));
83+
84+
return (
85+
<Dropdown element="li" className="drop dropdown center" triggerTitle="Settings" triggerClassName="bttn-settings" triggerText="Settings">
86+
<dl className="drop-menu filters-options-menu" role="menu">
87+
<dt className="drop-menu-sectitle">Time</dt>
88+
{dates}
89+
<dt className="drop-menu-sectitle">Resolution</dt>
90+
{resolutions}
91+
<dt className="drop-menu-sectitle">Data Type</dt>
92+
{dataTypes}
93+
</dl>
94+
</Dropdown>
95+
);
96+
}
97+
});

app/assets/scripts/components/header.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
11
'use strict';
22
var React = require('react/addons');
3+
var Keys = require('react-keybinding');
34
var actions = require('../actions/actions');
4-
var actions = require('../actions/actions');
5+
var Filters = require('./filters');
56

67
var Header = React.createClass({
8+
mixins: [
9+
Keys
10+
],
11+
12+
keybindings: {
13+
'i': function() {
14+
actions.openModal('info');
15+
},
16+
's': function() {
17+
var geocoder = this.getDOMNode().querySelector('[data-hook="geocoder"]');
18+
geocoder.focus();
19+
// Prevent the 's' from being typed in the search box.
20+
setTimeout(function() {
21+
geocoder.value = '';
22+
}, 1);
23+
}
24+
},
725

826
aboutClickHandler: function(e) {
927
e.preventDefault();
@@ -35,12 +53,7 @@ var Header = React.createClass({
3553
</div>
3654
</form>
3755
<ul className="app-menu">
38-
<li className="drop dropdown center" data-title="Coming soon!">
39-
<a href="#" title="Settings" className="bttn-settings disabled" data-toggle="drop"><span>Settings</span></a>
40-
<div className="drop-content">
41-
<p>Settings go here.</p>
42-
</div>
43-
</li>
56+
<Filters />
4457
</ul>
4558
</div>
4659
<div className="nav-block-sec">

app/assets/scripts/components/home.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
'use strict';
22
var React = require('react/addons');
33
var MapBoxMap = require('./map');
4+
var MiniMap = require('./minimap');
45
var ResultsPane = require('./results_pane');
56

67
var Home = React.createClass({
78
render: function() {
89
return (
910
<div>
1011
<MapBoxMap />
12+
<MiniMap />
1113
<ResultsPane />
1214
</div>
1315
);

0 commit comments

Comments
 (0)