mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Use query params for sortable table headings
This commit is contained in:
parent
2eab288dc9
commit
b3ed8b6a32
@ -23,10 +23,7 @@ Discourse.BasicTopicListComponent = Ember.Component.extend({
|
|||||||
|
|
||||||
_initFromTopicList: function(topicList) {
|
_initFromTopicList: function(topicList) {
|
||||||
if (topicList !== null) {
|
if (topicList !== null) {
|
||||||
this.setProperties({
|
this.set('topics', topicList.get('topics'));
|
||||||
topics: topicList.get('topics'),
|
|
||||||
sortOrder: topicList.get('sortOrder')
|
|
||||||
});
|
|
||||||
this.rerender();
|
this.rerender();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -12,23 +12,16 @@ Discourse.SortableHeadingComponent = Ember.Component.extend({
|
|||||||
attributeBindings: ['colspan'],
|
attributeBindings: ['colspan'],
|
||||||
|
|
||||||
sortable: function() {
|
sortable: function() {
|
||||||
return this.get('sortOrder') && this.get('sortBy');
|
return this.get('order') && this.get('sortBy');
|
||||||
}.property('sortOrder', 'sortBy'),
|
}.property('order', 'sortBy'),
|
||||||
|
|
||||||
iconSortClass: function() {
|
iconSortClass: function() {
|
||||||
var sortable = this.get('sortable');
|
if (this.get('sortable') && this.get('sortBy') === this.get('order')) {
|
||||||
|
return this.get('ascending') ? 'fa fa-chevron-up' : 'fa fa-chevron-down';
|
||||||
if (sortable && this.get('sortBy') === this.get('sortOrder.order')) {
|
|
||||||
return this.get('sortOrder.descending') ? 'fa fa-chevron-down' : 'fa fa-chevron-up';
|
|
||||||
}
|
}
|
||||||
}.property('sortable', 'sortOrder.order', 'sortOrder.descending'),
|
}.property('sortable', 'order', 'ascending'),
|
||||||
|
|
||||||
click: function() {
|
click: function() {
|
||||||
var sortOrder = this.get('sortOrder'),
|
this.sendAction('action', this.get('sortBy'));
|
||||||
sortBy = this.get('sortBy');
|
|
||||||
|
|
||||||
if (sortBy && sortOrder) {
|
|
||||||
sortOrder.toggle(sortBy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -25,3 +25,4 @@ Discourse.DiscoveryController = Discourse.ObjectController.extend({
|
|||||||
showMoreMonthlyUrl: function() { return this.showMoreUrl('monthly'); }.property('category', 'noSubcategories'),
|
showMoreMonthlyUrl: function() { return this.showMoreUrl('monthly'); }.property('category', 'noSubcategories'),
|
||||||
showMoreYearlyUrl: function() { return this.showMoreUrl('yearly'); }.property('category', 'noSubcategories')
|
showMoreYearlyUrl: function() { return this.showMoreUrl('yearly'); }.property('category', 'noSubcategories')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
Discourse.DiscoverySortableController = Discourse.Controller.extend({
|
||||||
|
needs: ['discoveryTopics'],
|
||||||
|
queryParams: ['order', 'ascending'],
|
||||||
|
order: Em.computed.alias('controllers.discoveryTopics.order'),
|
||||||
|
ascending: Em.computed.alias('controllers.discoveryTopics.ascending')
|
||||||
|
});
|
@ -11,7 +11,20 @@ Discourse.DiscoveryTopicsController = Discourse.DiscoveryController.extend({
|
|||||||
bulkSelectEnabled: false,
|
bulkSelectEnabled: false,
|
||||||
selected: [],
|
selected: [],
|
||||||
|
|
||||||
|
order: 'default',
|
||||||
|
ascending: false,
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
||||||
|
changeSort: function(sortBy) {
|
||||||
|
if (sortBy === this.get('order')) {
|
||||||
|
this.toggleProperty('ascending');
|
||||||
|
} else {
|
||||||
|
this.setProperties({ order: sortBy, ascending: false });
|
||||||
|
}
|
||||||
|
this.get('model').refreshSort(sortBy, this.get('ascending'));
|
||||||
|
},
|
||||||
|
|
||||||
// Show newly inserted topics
|
// Show newly inserted topics
|
||||||
showInserted: function() {
|
showInserted: function() {
|
||||||
var tracker = Discourse.TopicTrackingState.current();
|
var tracker = Discourse.TopicTrackingState.current();
|
||||||
@ -117,11 +130,6 @@ Discourse.DiscoveryTopicsController = Discourse.DiscoveryController.extend({
|
|||||||
}.property('allLoaded', 'topics.length'),
|
}.property('allLoaded', 'topics.length'),
|
||||||
|
|
||||||
loadMoreTopics: function() {
|
loadMoreTopics: function() {
|
||||||
var topicList = this.get('model');
|
return this.get('model').loadMore();
|
||||||
return topicList.loadMore().then(function(moreUrl) {
|
|
||||||
if (!Em.isEmpty(moreUrl)) {
|
|
||||||
Discourse.URL.replaceState(Discourse.getURL("/") + topicList.get('filter') + "/more");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -22,12 +22,7 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||||||
return this.get('postStream.summary') ? "summary" : null;
|
return this.get('postStream.summary') ? "summary" : null;
|
||||||
}.property('postStream.summary'),
|
}.property('postStream.summary'),
|
||||||
|
|
||||||
username_filters: function(key, value) {
|
username_filters: Discourse.computed.queryAlias('postStream.streamFilters.username_filters'),
|
||||||
// TODO: Ember bug? If I don't have a value parameter this does not update
|
|
||||||
if (value) {
|
|
||||||
}
|
|
||||||
return this.get('postStream.streamFilters.username_filters');
|
|
||||||
}.property("postStream.streamFilters.username_filters"),
|
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super();
|
this._super();
|
||||||
|
@ -110,6 +110,23 @@ Discourse.computed = {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return computed.property.apply(computed, args);
|
return computed.property.apply(computed, args);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a one way alias to a computed property, suitable for query params.
|
||||||
|
|
||||||
|
@method queryAlias
|
||||||
|
@param {String} path to the alias
|
||||||
|
@param {String} defaultValue for the variable (omitted if equal)
|
||||||
|
**/
|
||||||
|
queryAlias: function(path, defaultValue) {
|
||||||
|
return Ember.computed(function(key, value) {
|
||||||
|
if (value) {
|
||||||
|
// Annoying but this ensures the parameter is present
|
||||||
|
}
|
||||||
|
var result = this.get(path);
|
||||||
|
if (typeof result !== "undefined" && result.toString() === defaultValue) { return; }
|
||||||
|
return result;
|
||||||
|
}).property(path);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -10,9 +10,6 @@ Discourse.URL = Em.Object.createWithMixins({
|
|||||||
// Used for matching a topic
|
// Used for matching a topic
|
||||||
TOPIC_REGEXP: /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/,
|
TOPIC_REGEXP: /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/,
|
||||||
|
|
||||||
// Used for matching a /more URL
|
|
||||||
MORE_REGEXP: /\/more$/,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Browser aware replaceState. Will only be invoked if the browser supports it.
|
Browser aware replaceState. Will only be invoked if the browser supports it.
|
||||||
|
|
||||||
@ -75,7 +72,6 @@ Discourse.URL = Em.Object.createWithMixins({
|
|||||||
|
|
||||||
// TODO: Extract into rules we can inject into the URL handler
|
// TODO: Extract into rules we can inject into the URL handler
|
||||||
if (this.navigatedToHome(oldPath, path)) { return; }
|
if (this.navigatedToHome(oldPath, path)) { return; }
|
||||||
if (this.navigatedToListMore(oldPath, path)) { return; }
|
|
||||||
if (this.navigatedToPost(oldPath, path)) { return; }
|
if (this.navigatedToPost(oldPath, path)) { return; }
|
||||||
|
|
||||||
if (path.match(/^\/?users\/[^\/]+$/)) {
|
if (path.match(/^\/?users\/[^\/]+$/)) {
|
||||||
@ -111,24 +107,6 @@ Discourse.URL = Em.Object.createWithMixins({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
@private
|
|
||||||
|
|
||||||
If we're viewing more topics, scroll to where we were previously.
|
|
||||||
|
|
||||||
@method navigatedToListMore
|
|
||||||
@param {String} oldPath the previous path we were on
|
|
||||||
@param {String} path the path we're navigating to
|
|
||||||
**/
|
|
||||||
navigatedToListMore: function(oldPath, path) {
|
|
||||||
// If we transition from a /more path, scroll to the top
|
|
||||||
if (this.MORE_REGEXP.exec(oldPath) && (oldPath.indexOf(path) === 0)) {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@private
|
@private
|
||||||
|
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
Represents the sort order of something, for example a topics list.
|
|
||||||
|
|
||||||
@class SortOrder
|
|
||||||
@extends Ember.Object
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.SortOrder = Ember.Object.extend({
|
|
||||||
order: 'default',
|
|
||||||
descending: true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
Changes the sort to another column
|
|
||||||
|
|
||||||
@method toggle
|
|
||||||
@params {String} order the new sort order
|
|
||||||
**/
|
|
||||||
toggle: function(order) {
|
|
||||||
if (this.get('order') === order) {
|
|
||||||
this.toggleProperty('descending');
|
|
||||||
} else {
|
|
||||||
this.setProperties({
|
|
||||||
order: order,
|
|
||||||
descending: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
@ -27,7 +27,6 @@ Discourse.TopList.reopenClass({
|
|||||||
if (result[period]) {
|
if (result[period]) {
|
||||||
// instanciate a new topic list with no sorting
|
// instanciate a new topic list with no sorting
|
||||||
topList.set(period, Discourse.TopicList.from(result[period]));
|
topList.set(period, Discourse.TopicList.from(result[period]));
|
||||||
topList.set(period + ".sortOrder", undefined);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -45,23 +45,12 @@ Discourse.TopicList = Discourse.Model.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
sortOrder: function() {
|
refreshSort: function(order, ascending) {
|
||||||
return Discourse.SortOrder.create();
|
|
||||||
}.property(),
|
|
||||||
|
|
||||||
/**
|
|
||||||
If the sort order changes, replace the topics in the list with the new
|
|
||||||
order.
|
|
||||||
|
|
||||||
@observes sortOrder
|
|
||||||
**/
|
|
||||||
_sortOrderChanged: function() {
|
|
||||||
var self = this,
|
var self = this,
|
||||||
sortOrder = this.get('sortOrder'),
|
|
||||||
params = this.get('params');
|
params = this.get('params');
|
||||||
|
|
||||||
params.sort_order = sortOrder.get('order');
|
params.order = order;
|
||||||
params.sort_descending = sortOrder.get('descending');
|
params.ascending = ascending;
|
||||||
|
|
||||||
this.set('loaded', false);
|
this.set('loaded', false);
|
||||||
var finder = finderFor(this.get('filter'), params);
|
var finder = finderFor(this.get('filter'), params);
|
||||||
@ -73,8 +62,7 @@ Discourse.TopicList = Discourse.Model.extend({
|
|||||||
topics.pushObjects(newTopics);
|
topics.pushObjects(newTopics);
|
||||||
self.setProperties({ loaded: true, more_topics_url: result.topic_list.more_topics_url });
|
self.setProperties({ loaded: true, more_topics_url: result.topic_list.more_topics_url });
|
||||||
});
|
});
|
||||||
|
},
|
||||||
}.observes('sortOrder.order', 'sortOrder.descending'),
|
|
||||||
|
|
||||||
loadMore: function() {
|
loadMore: function() {
|
||||||
if (this.get('loadingMore')) { return Ember.RSVP.resolve(); }
|
if (this.get('loadingMore')) { return Ember.RSVP.resolve(); }
|
||||||
|
@ -32,25 +32,17 @@ Discourse.Route.buildRoutes(function() {
|
|||||||
Discourse.Site.currentProp('periods').forEach(function(period) {
|
Discourse.Site.currentProp('periods').forEach(function(period) {
|
||||||
var top = 'top' + period.capitalize();
|
var top = 'top' + period.capitalize();
|
||||||
router.route(top, { path: '/top/' + period });
|
router.route(top, { path: '/top/' + period });
|
||||||
router.route(top, { path: '/top/' + period + '/more' });
|
|
||||||
router.route(top + 'Category', { path: '/category/:slug/l/top/' + period });
|
router.route(top + 'Category', { path: '/category/:slug/l/top/' + period });
|
||||||
router.route(top + 'Category', { path: '/category/:slug/l/top/' + period + '/more' });
|
|
||||||
router.route(top + 'CategoryNone', { path: '/category/:slug/none/l/top/' + period });
|
router.route(top + 'CategoryNone', { path: '/category/:slug/none/l/top/' + period });
|
||||||
router.route(top + 'CategoryNone', { path: '/category/:slug/none/l/top/' + period + '/more' });
|
|
||||||
router.route(top + 'Category', { path: '/category/:parentSlug/:slug/l/top/' + period });
|
router.route(top + 'Category', { path: '/category/:parentSlug/:slug/l/top/' + period });
|
||||||
router.route(top + 'Category', { path: '/category/:parentSlug/:slug/l/top/' + period + '/more' });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// filters
|
// filters
|
||||||
Discourse.Site.currentProp('filters').forEach(function(filter) {
|
Discourse.Site.currentProp('filters').forEach(function(filter) {
|
||||||
router.route(filter, { path: '/' + filter });
|
router.route(filter, { path: '/' + filter });
|
||||||
router.route(filter, { path: '/' + filter + '/more' });
|
|
||||||
router.route(filter + 'Category', { path: '/category/:slug/l/' + filter });
|
router.route(filter + 'Category', { path: '/category/:slug/l/' + filter });
|
||||||
router.route(filter + 'Category', { path: '/category/:slug/l/' + filter + '/more' });
|
|
||||||
router.route(filter + 'CategoryNone', { path: '/category/:slug/none/l/' + filter });
|
router.route(filter + 'CategoryNone', { path: '/category/:slug/none/l/' + filter });
|
||||||
router.route(filter + 'CategoryNone', { path: '/category/:slug/none/l/' + filter + '/more' });
|
|
||||||
router.route(filter + 'Category', { path: '/category/:parentSlug/:slug/l/' + filter });
|
router.route(filter + 'Category', { path: '/category/:parentSlug/:slug/l/' + filter });
|
||||||
router.route(filter + 'Category', { path: '/category/:parentSlug/:slug/l/' + filter + '/more' });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route('categories');
|
this.route('categories');
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
@namespace Discourse
|
@namespace Discourse
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.DiscoveryRoute = Discourse.Route.extend(Discourse.OpenComposer, {
|
Discourse.DiscoveryRoute = Discourse.Route.extend(Discourse.ScrollTop, Discourse.OpenComposer, {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
loading: function() {
|
loading: function() {
|
||||||
var controller = this.controllerFor('discovery');
|
var controller = this.controllerFor('discovery');
|
||||||
@ -25,6 +26,7 @@ Discourse.DiscoveryRoute = Discourse.Route.extend(Discourse.OpenComposer, {
|
|||||||
var controller = this.controllerFor('discovery');
|
var controller = this.controllerFor('discovery');
|
||||||
Ember.run.cancel(controller.get('scheduledSpinner'));
|
Ember.run.cancel(controller.get('scheduledSpinner'));
|
||||||
controller.setProperties({ loading: false, loadingSpinner: false });
|
controller.setProperties({ loading: false, loadingSpinner: false });
|
||||||
|
this._scrollTop();
|
||||||
},
|
},
|
||||||
|
|
||||||
didTransition: function() {
|
didTransition: function() {
|
||||||
|
@ -6,15 +6,28 @@
|
|||||||
**/
|
**/
|
||||||
function buildTopicRoute(filter) {
|
function buildTopicRoute(filter) {
|
||||||
return Discourse.Route.extend({
|
return Discourse.Route.extend({
|
||||||
|
queryParams: {
|
||||||
|
sort: { replace: true },
|
||||||
|
ascending: { replace: true }
|
||||||
|
},
|
||||||
|
|
||||||
beforeModel: function() {
|
beforeModel: function() {
|
||||||
this.controllerFor('navigationDefault').set('filterMode', filter);
|
this.controllerFor('navigationDefault').set('filterMode', filter);
|
||||||
},
|
},
|
||||||
|
|
||||||
model: function() {
|
model: function(data, transaction) {
|
||||||
|
|
||||||
|
var params = transaction.queryParams;
|
||||||
|
|
||||||
// attempt to stop early cause we need this to be called before .sync
|
// attempt to stop early cause we need this to be called before .sync
|
||||||
Discourse.ScreenTrack.current().stop();
|
Discourse.ScreenTrack.current().stop();
|
||||||
|
|
||||||
return Discourse.TopicList.list(filter).then(function(list) {
|
var findOpts = {};
|
||||||
|
if (params && params.order) { findOpts.order = params.order; }
|
||||||
|
if (params && params.ascending) { findOpts.ascending = params.ascending; }
|
||||||
|
|
||||||
|
|
||||||
|
return Discourse.TopicList.list(filter, findOpts).then(function(list) {
|
||||||
var tracking = Discourse.TopicTrackingState.current();
|
var tracking = Discourse.TopicTrackingState.current();
|
||||||
if (tracking) {
|
if (tracking) {
|
||||||
tracking.sync(list, filter);
|
tracking.sync(list, filter);
|
||||||
@ -24,7 +37,13 @@ function buildTopicRoute(filter) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController: function(controller, model) {
|
setupController: function(controller, model, trans) {
|
||||||
|
|
||||||
|
controller.setProperties({
|
||||||
|
order: Em.get(trans, 'queryParams.order'),
|
||||||
|
ascending: Em.get(trans, 'queryParams.ascending')
|
||||||
|
});
|
||||||
|
|
||||||
var period = filter.indexOf('/') > 0 ? filter.split('/')[1] : '',
|
var period = filter.indexOf('/') > 0 ? filter.split('/')[1] : '',
|
||||||
filterText = I18n.t('filters.' + filter.replace('/', '.') + '.title', {count: 0});
|
filterText = I18n.t('filters.' + filter.replace('/', '.') + '.title', {count: 0});
|
||||||
|
|
||||||
@ -141,6 +160,7 @@ Discourse.addInitializer(function() {
|
|||||||
Discourse.DiscoveryCategoryNoneRoute = buildCategoryRoute('latest', {no_subcategories: true});
|
Discourse.DiscoveryCategoryNoneRoute = buildCategoryRoute('latest', {no_subcategories: true});
|
||||||
|
|
||||||
Discourse.Site.currentProp('filters').forEach(function(filter) {
|
Discourse.Site.currentProp('filters').forEach(function(filter) {
|
||||||
|
Discourse["Discovery" + filter.capitalize() + "Controller"] = Discourse.DiscoverySortableController.extend();
|
||||||
Discourse["Discovery" + filter.capitalize() + "Route"] = buildTopicRoute(filter);
|
Discourse["Discovery" + filter.capitalize() + "Route"] = buildTopicRoute(filter);
|
||||||
Discourse["Discovery" + filter.capitalize() + "CategoryRoute"] = buildCategoryRoute(filter);
|
Discourse["Discovery" + filter.capitalize() + "CategoryRoute"] = buildCategoryRoute(filter);
|
||||||
Discourse["Discovery" + filter.capitalize() + "CategoryNoneRoute"] = buildCategoryRoute(filter, {no_subcategories: true});
|
Discourse["Discovery" + filter.capitalize() + "CategoryNoneRoute"] = buildCategoryRoute(filter, {no_subcategories: true});
|
||||||
|
@ -10,14 +10,8 @@ Discourse.TopicRoute = Discourse.Route.extend({
|
|||||||
redirect: function() { Discourse.redirectIfLoginRequired(this); },
|
redirect: function() { Discourse.redirectIfLoginRequired(this); },
|
||||||
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
filter: {
|
filter: { replace: true },
|
||||||
refreshModel: false,
|
username_filters: { replace: true }
|
||||||
replace: true
|
|
||||||
},
|
|
||||||
username_filters: {
|
|
||||||
refreshModel: false,
|
|
||||||
replace: true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@ -114,16 +108,18 @@ Discourse.TopicRoute = Discourse.Route.extend({
|
|||||||
return topic;
|
return topic;
|
||||||
},
|
},
|
||||||
|
|
||||||
model: function(params) {
|
model: function(params, transition) {
|
||||||
|
var queryParams = transition.queryParams;
|
||||||
|
|
||||||
var topic = this.modelFor('topic');
|
var topic = this.modelFor('topic');
|
||||||
if (topic && (topic.get('id') === parseInt(params.id, 10))) {
|
if (topic && (topic.get('id') === parseInt(params.id, 10))) {
|
||||||
this.setupParams(topic, params);
|
this.setupParams(topic, queryParams);
|
||||||
// If we have the existing model, refresh it
|
// If we have the existing model, refresh it
|
||||||
return topic.get('postStream').refresh().then(function() {
|
return topic.get('postStream').refresh().then(function() {
|
||||||
return topic;
|
return topic;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return this.setupParams(Discourse.Topic.create(_.omit(params, 'username_filters', 'filter')), params);
|
return this.setupParams(Discourse.Topic.create(_.omit(params, 'username_filters', 'filter')), queryParams);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ Discourse.UserRoute = Discourse.Route.extend({
|
|||||||
|
|
||||||
serialize: function(model) {
|
serialize: function(model) {
|
||||||
if (!model) return {};
|
if (!model) return {};
|
||||||
return { username: model.get('username').toLowerCase() };
|
return { username: (Em.get(model, 'username') || '').toLowerCase() };
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController: function(controller, user) {
|
setupController: function(controller, user) {
|
||||||
|
@ -3,24 +3,24 @@
|
|||||||
<table id="topic-list">
|
<table id="topic-list">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{{#sortable-heading sortBy="default" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="default"}}
|
||||||
{{i18n topic.title}}
|
{{i18n topic.title}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#unless controller.hideCategory}}
|
{{#unless controller.hideCategory}}
|
||||||
{{#sortable-heading sortBy="category" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="category"}}
|
||||||
{{i18n category_title}}
|
{{i18n category_title}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{#sortable-heading sortBy="posts" number=true sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="posts" number=true}}
|
||||||
{{i18n posts}}
|
{{i18n posts}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="likes" number=true sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="likes" number=true}}
|
||||||
{{i18n likes}}
|
{{i18n likes}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="views" number=true sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="views" number=true}}
|
||||||
{{i18n views}}
|
{{i18n views}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="activity" number=true colspan="2" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="activity" number=true colspan="2"}}
|
||||||
{{i18n activity}}
|
{{i18n activity}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -16,27 +16,27 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</th>
|
</th>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#sortable-heading sortBy="default" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="default" action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n topic.title}}
|
{{i18n topic.title}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#unless controller.hideCategory}}
|
{{#unless controller.hideCategory}}
|
||||||
{{#sortable-heading sortBy="category" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="category" action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n category_title}}
|
{{i18n category_title}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{#sortable-heading sortBy="posters" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="posters" action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n users}}
|
{{i18n users}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="posts" number=true sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="posts" number=true action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n posts}}
|
{{i18n posts}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="likes" number=true sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="likes" number=true action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n likes}}
|
{{i18n likes}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="views" number=true sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="views" number=true action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n views}}
|
{{i18n views}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
{{#sortable-heading sortBy="activity" number=true colspan="2" sortOrder=sortOrder}}
|
{{#sortable-heading sortBy="activity" number=true colspan="2" action="changeSort" order=order ascending=ascending}}
|
||||||
{{i18n activity}}
|
{{i18n activity}}
|
||||||
{{/sortable-heading}}
|
{{/sortable-heading}}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -26,10 +26,7 @@ Discourse.DiscoveryTopicsView = Discourse.View.extend(Discourse.LoadMore, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_readjustScrollPosition: function() {
|
_readjustScrollPosition: function() {
|
||||||
var scrollTo = Discourse.Session.currentProp('topicListScrollPosition'),
|
var scrollTo = Discourse.Session.currentProp('topicListScrollPosition');
|
||||||
url = document.location.href;
|
|
||||||
|
|
||||||
if (url && url.indexOf('/more') === -1) { scrollTo = 0; }
|
|
||||||
|
|
||||||
if (typeof scrollTo !== "undefined") {
|
if (typeof scrollTo !== "undefined") {
|
||||||
Em.run.schedule('afterRender', function() {
|
Em.run.schedule('afterRender', function() {
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
|
|
||||||
// These will help us migrate up to the new ember's default behavior
|
// These will help us migrate up to the new ember's default behavior
|
||||||
window.ENV = {
|
window.ENV = {
|
||||||
CP_DEFAULT_CACHEABLE: true,
|
|
||||||
VIEW_PRESERVES_CONTEXT: true,
|
|
||||||
MANDATORY_SETTER: false,
|
MANDATORY_SETTER: false,
|
||||||
FEATURES: {'query-params-new': true}
|
FEATURES: {'query-params-new': true}
|
||||||
};
|
};
|
||||||
|
@ -236,8 +236,8 @@ class ListController < ApplicationController
|
|||||||
route_params = {format: 'json'}
|
route_params = {format: 'json'}
|
||||||
route_params[:category] = @category.slug_for_url if @category
|
route_params[:category] = @category.slug_for_url if @category
|
||||||
route_params[:parent_category] = @category.parent_category.slug_for_url if @category && @category.parent_category
|
route_params[:parent_category] = @category.parent_category.slug_for_url if @category && @category.parent_category
|
||||||
route_params[:sort_order] = opts[:sort_order] if opts[:sort_order].present?
|
route_params[:order] = opts[:order] if opts[:order].present?
|
||||||
route_params[:sort_descending] = opts[:sort_descending] if opts[:sort_descending].present?
|
route_params[:ascending] = opts[:ascending] if opts[:ascending].present?
|
||||||
route_params
|
route_params
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -265,8 +265,8 @@ class ListController < ApplicationController
|
|||||||
topic_ids: param_to_integer_list(:topic_ids),
|
topic_ids: param_to_integer_list(:topic_ids),
|
||||||
exclude_category: (params[:exclude_category] || select_menu_item.try(:filter)),
|
exclude_category: (params[:exclude_category] || select_menu_item.try(:filter)),
|
||||||
category: params[:category],
|
category: params[:category],
|
||||||
sort_order: params[:sort_order],
|
order: params[:order],
|
||||||
sort_descending: params[:sort_descending],
|
ascending: params[:ascending],
|
||||||
status: params[:status]
|
status: params[:status]
|
||||||
}
|
}
|
||||||
options[:no_subcategories] = true if params[:no_subcategories] == 'true'
|
options[:no_subcategories] = true if params[:no_subcategories] == 'true'
|
||||||
|
@ -249,7 +249,6 @@ Discourse::Application.routes.draw do
|
|||||||
|
|
||||||
# We've renamed popular to latest. If people access it we want a permanent redirect.
|
# We've renamed popular to latest. If people access it we want a permanent redirect.
|
||||||
get "popular" => "list#popular_redirect"
|
get "popular" => "list#popular_redirect"
|
||||||
get "popular/more" => "list#popular_redirect"
|
|
||||||
|
|
||||||
resources :categories, :except => :show
|
resources :categories, :except => :show
|
||||||
get "category/:id/show" => "categories#show"
|
get "category/:id/show" => "categories#show"
|
||||||
@ -278,13 +277,9 @@ Discourse::Application.routes.draw do
|
|||||||
|
|
||||||
Discourse.filters.each do |filter|
|
Discourse.filters.each do |filter|
|
||||||
get "#{filter}" => "list##{filter}"
|
get "#{filter}" => "list##{filter}"
|
||||||
get "#{filter}/more" => "list##{filter}"
|
|
||||||
get "category/:category/l/#{filter}" => "list#category_#{filter}", as: "category_#{filter}"
|
get "category/:category/l/#{filter}" => "list#category_#{filter}", as: "category_#{filter}"
|
||||||
get "category/:category/l/#{filter}/more" => "list#category_#{filter}"
|
|
||||||
get "category/:category/none/l/#{filter}" => "list#category_none_#{filter}", as: "category_none_#{filter}"
|
get "category/:category/none/l/#{filter}" => "list#category_none_#{filter}", as: "category_none_#{filter}"
|
||||||
get "category/:category/none/l/#{filter}/more" => "list#category_none_#{filter}"
|
|
||||||
get "category/:parent_category/:category/l/#{filter}" => "list#parent_category_category_#{filter}", as: "parent_category_category_#{filter}"
|
get "category/:parent_category/:category/l/#{filter}" => "list#parent_category_category_#{filter}", as: "parent_category_category_#{filter}"
|
||||||
get "category/:parent_category/:category/l/#{filter}/more" => "list#parent_category_category_#{filter}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
get "search" => "search#query"
|
get "search" => "search#query"
|
||||||
|
@ -16,13 +16,13 @@ class TopicQuery
|
|||||||
topic_ids
|
topic_ids
|
||||||
visible
|
visible
|
||||||
category
|
category
|
||||||
sort_order
|
order
|
||||||
|
ascending
|
||||||
no_subcategories
|
no_subcategories
|
||||||
sort_descending
|
|
||||||
no_definitions
|
no_definitions
|
||||||
status).map(&:to_sym)
|
status).map(&:to_sym)
|
||||||
|
|
||||||
# Maps `sort_order` to a columns in `topics`
|
# Maps `order` to a columns in `topics`
|
||||||
SORTABLE_MAPPING = {
|
SORTABLE_MAPPING = {
|
||||||
'likes' => 'like_count',
|
'likes' => 'like_count',
|
||||||
'views' => 'views',
|
'views' => 'views',
|
||||||
@ -189,8 +189,8 @@ class TopicQuery
|
|||||||
end
|
end
|
||||||
|
|
||||||
def apply_ordering(result, options)
|
def apply_ordering(result, options)
|
||||||
sort_column = SORTABLE_MAPPING[options[:sort_order]] || 'default'
|
sort_column = SORTABLE_MAPPING[options[:order]] || 'default'
|
||||||
sort_dir = (options[:sort_descending] == "false") ? "ASC" : "DESC"
|
sort_dir = (options[:ascending] == "true") ? "ASC" : "DESC"
|
||||||
|
|
||||||
# If we are sorting in the default order desc, we should consider including pinned
|
# If we are sorting in the default order desc, we should consider including pinned
|
||||||
# topics. Otherwise, just use bumped_at.
|
# topics. Otherwise, just use bumped_at.
|
||||||
|
@ -151,7 +151,7 @@ describe TopicQuery do
|
|||||||
context 'sort_order' do
|
context 'sort_order' do
|
||||||
|
|
||||||
def ids_in_order(order, descending=true)
|
def ids_in_order(order, descending=true)
|
||||||
TopicQuery.new(admin, sort_order: order, sort_descending: descending ? 'true' : 'false').list_latest.topics.map(&:id)
|
TopicQuery.new(admin, order: order, ascending: descending ? 'false' : 'true').list_latest.topics.map(&:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the topics in correct order" do
|
it "returns the topics in correct order" do
|
||||||
|
@ -148,7 +148,7 @@ test("streamFilters", function() {
|
|||||||
|
|
||||||
postStream.toggleParticipant(participant.username);
|
postStream.toggleParticipant(participant.username);
|
||||||
deepEqual(postStream.get('streamFilters'), {
|
deepEqual(postStream.get('streamFilters'), {
|
||||||
username_filters: ['eviltrout']
|
username_filters: 'eviltrout'
|
||||||
}, "streamFilters contains the username we filtered");
|
}, "streamFilters contains the username we filtered");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
module("Discourse.SortOrder");
|
|
||||||
|
|
||||||
test('defaults', function() {
|
|
||||||
var sortOrder = Discourse.SortOrder.create();
|
|
||||||
equal(sortOrder.get('order'), 'default', 'it is `default` by default');
|
|
||||||
equal(sortOrder.get('descending'), true, 'it is descending by default');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('toggle', function() {
|
|
||||||
var sortOrder = Discourse.SortOrder.create();
|
|
||||||
|
|
||||||
sortOrder.toggle('default');
|
|
||||||
equal(sortOrder.get('descending'), false, 'if we toggle the same name it swaps the asc/desc');
|
|
||||||
|
|
||||||
sortOrder.toggle('name');
|
|
||||||
equal(sortOrder.get('order'), 'name', 'it changes the order');
|
|
||||||
equal(sortOrder.get('descending'), true, 'when toggling names it switches back to descending');
|
|
||||||
|
|
||||||
sortOrder.toggle('name');
|
|
||||||
sortOrder.toggle('name');
|
|
||||||
equal(sortOrder.get('descending'), true, 'toggling twice goes back to descending');
|
|
||||||
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user