Extensibility: discussion list params

Also give the root controller the name of the current route so they can
easily route back to it
This commit is contained in:
Toby Zerner
2015-05-02 08:43:38 +09:30
parent 288fd694a8
commit ffc2863f70
4 changed files with 70 additions and 37 deletions

View File

@ -16,19 +16,30 @@ export default class DiscussionList extends Component {
this.loading = m.prop(true); this.loading = m.prop(true);
this.moreResults = m.prop(false); this.moreResults = m.prop(false);
this.discussions = m.prop([]); this.discussions = m.prop([]);
this.sort = m.prop(this.props.sort || 'recent');
this.sortOptions = m.prop([
{key: 'recent', value: 'Recent', sort: 'recent'},
{key: 'replies', value: 'Replies', sort: '-replies'},
{key: 'newest', value: 'Newest', sort: '-created'},
{key: 'oldest', value: 'Oldest', sort: 'created'}
]);
this.refresh(); this.refresh();
app.session.on('loggedIn', this.loggedInHandler = this.refresh.bind(this)) app.session.on('loggedIn', this.loggedInHandler = this.refresh.bind(this))
} }
params() {
var params = {};
for (var i in this.props.params) {
params[i] = this.props.params[i];
}
params.sort = this.sortMap()[params.sort];
return params;
}
sortMap() {
return {
recent: 'recent',
replies: '-replies',
newest: '-created',
oldest: 'created'
};
}
refresh() { refresh() {
m.startComputation(); m.startComputation();
this.loading(true); this.loading(true);
@ -42,26 +53,16 @@ export default class DiscussionList extends Component {
} }
terminalPostType() { terminalPostType() {
return ['newest', 'oldest'].indexOf(this.sort()) !== -1 ? 'start' : 'last' return ['newest', 'oldest'].indexOf(this.props.sort) !== -1 ? 'start' : 'last'
} }
countType() { countType() {
return this.sort() === 'replies' ? 'replies' : 'unread'; return this.props.sort === 'replies' ? 'replies' : 'unread';
} }
loadResults(start) { loadResults(start) {
var self = this; var params = this.params();
params.start = start;
var sort = this.sortOptions()[0].sort;
this.sortOptions().some(function(option) {
if (option.key === self.sort()) {
sort = option.sort;
return true;
}
});
var params = {sort, start};
return app.store.find('discussions', params); return app.store.find('discussions', params);
} }
@ -97,10 +98,10 @@ export default class DiscussionList extends Component {
view() { view() {
return m('div', [ return m('div', [
m('ul.discussions-list', [ m('ul.discussions-list', [
this.discussions().map(function(discussion) { this.discussions().map(discussion => {
var startUser = discussion.startUser() var startUser = discussion.startUser()
var isUnread = discussion.isUnread() var isUnread = discussion.isUnread()
var displayUnread = this.props.countType !== 'replies' && isUnread var displayUnread = this.countType() !== 'replies' && isUnread
var jumpTo = Math.min(discussion.lastPostNumber(), (discussion.readNumber() || 0) + 1) var jumpTo = Math.min(discussion.lastPostNumber(), (discussion.readNumber() || 0) + 1)
var controls = discussion.controls(this).toArray(); var controls = discussion.controls(this).toArray();
@ -135,7 +136,7 @@ export default class DiscussionList extends Component {
m('span.label', displayUnread ? 'unread' : 'replies') m('span.label', displayUnread ? 'unread' : 'replies')
]) ])
]) ])
}.bind(this)) })
]), ]),
this.loading() this.loading()
? LoadingIndicator.component() ? LoadingIndicator.component()
@ -159,7 +160,7 @@ export default class DiscussionList extends Component {
items.add('terminalPost', items.add('terminalPost',
TerminalPost.component({ TerminalPost.component({
discussion, discussion,
lastPost: this.props.terminalPostType !== 'start' lastPost: this.terminalPostType() !== 'start'
}) })
); );

View File

@ -18,15 +18,17 @@ export default class IndexPage extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
var params = this.params();
if (app.cache.discussionList) { if (app.cache.discussionList) {
if (app.cache.discussionList.props.sort !== m.route.param('sort')) { Object.keys(params).some(key => {
app.cache.discussionList = null; if (app.cache.discussionList.props.params[key] !== params[key]) {
} app.cache.discussionList = null;
return true;
}
});
} }
if (!app.cache.discussionList) { if (!app.cache.discussionList) {
app.cache.discussionList = new DiscussionList({ app.cache.discussionList = new DiscussionList({params});
sort: m.route.param('sort')
});
} }
app.history.push('index'); app.history.push('index');
@ -34,10 +36,34 @@ export default class IndexPage extends Component {
app.composer.minimize(); app.composer.minimize();
} }
/**
Params that stick between filter changes
*/
stickyParams() {
return {
sort: m.route.param('sort'),
show: m.route.param('show'),
q: m.route.param('q')
}
}
/**
Params which are passed to the DiscussionList
*/
params() {
var params = this.stickyParams();
params.filter = m.route.param('filter');
return params;
}
reorder(sort) { reorder(sort) {
var filter = m.route.param('filter') || ''; var params = this.params();
var params = sort !== 'recent' ? {sort} : {}; if (sort === 'recent') {
m.route(app.route('index.filter', {filter}, params)); delete params.sort;
} else {
params.sort = sort;
}
m.route(app.route(this.props.routeName, params));
} }
/** /**
@ -47,6 +73,11 @@ export default class IndexPage extends Component {
@return void @return void
*/ */
view() { view() {
var sortOptions = {};
for (var i in app.cache.discussionList.sortMap()) {
sortOptions[i] = i.substr(0, 1).toUpperCase()+i.substr(1);
}
return m('div.index-area', {config: this.onload.bind(this)}, [ return m('div.index-area', {config: this.onload.bind(this)}, [
WelcomeHero.component(), WelcomeHero.component(),
m('div.container', [ m('div.container', [
@ -57,8 +88,8 @@ export default class IndexPage extends Component {
m('div.index-toolbar', [ m('div.index-toolbar', [
m('div.index-toolbar-view', [ m('div.index-toolbar-view', [
SelectInput.component({ SelectInput.component({
options: app.cache.discussionList.sortOptions(), options: sortOptions,
value: app.cache.discussionList.sort(), value: m.route.param('sort'),
onchange: this.reorder.bind(this) onchange: this.reorder.bind(this)
}), }),
]), ]),

View File

@ -5,7 +5,7 @@ export default class SelectInput extends Component {
view(ctrl) { view(ctrl) {
return m('span.select-input', [ return m('span.select-input', [
m('select.form-control', {onchange: m.withAttr('value', this.props.onchange.bind(ctrl)), value: this.props.value}, [ m('select.form-control', {onchange: m.withAttr('value', this.props.onchange.bind(ctrl)), value: this.props.value}, [
this.props.options.map(function(option) { return m('option', {value: option.key}, option.value) }) Object.keys(this.props.options).map(key => m('option', {value: key}, this.props.options[key]))
]), ]),
icon('sort') icon('sort')
]) ])

View File

@ -1,6 +1,7 @@
export default function mapRoutes(routes) { export default function mapRoutes(routes) {
var map = {}; var map = {};
for (var r in routes) { for (var r in routes) {
routes[r][1].props.routeName = r;
map[routes[r][0]] = routes[r][1]; map[routes[r][0]] = routes[r][1];
} }
return map; return map;