UX: Add drop down for top lists, big refactor of repeated code.

This commit is contained in:
Robin Ward 2014-08-20 17:37:28 -04:00
parent bb14e4230f
commit c1aa2458f8
22 changed files with 219 additions and 73 deletions

View File

@ -0,0 +1,3 @@
export default Ember.Component.extend({
classNames: ['top-title-buttons']
});

View File

@ -0,0 +1,31 @@
import CleansUp from 'discourse/mixins/cleans-up';
export default Ember.Component.extend(CleansUp, {
classNames: 'period-chooser',
showPeriods: false,
cleanUp: function() {
this.set('showPeriods', false);
$('html').off('mousedown.top-period');
},
_clickToClose: function() {
var self = this;
$('html').off('mousedown.top-period').on('mousedown.top-period', function(e) {
var $target = $(e.target);
if (($target.prop('id') === 'topic-entrance') || (self.$().has($target).length !== 0)) {
return;
}
self.cleanUp();
});
},
click: function() {
if (!this.get('showPeriods')) {
var $chevron = this.$('i.fa-caret-down');
this.$('#period-popup').css($chevron.position());
this.set('showPeriods', true);
this._clickToClose();
}
}
});

View File

@ -0,0 +1,13 @@
import TopTitle from 'discourse/components/top-title';
export default TopTitle.extend({
tagName: 'button',
classNameBindings: [':btn', ':btn-default', 'unless:hidden'],
click: function() {
var url = this.get('period.showMoreUrl');
if (url) {
Discourse.URL.routeTo(url);
}
}
});

View File

@ -0,0 +1,8 @@
export default Ember.Component.extend({
tagName: 'h2',
_shouldRerender: Discourse.View.renderIfChanged('period.title'),
render: function(buffer) {
buffer.push("<i class='fa fa-calendar-o'></i> " + this.get('period.title'));
}
});

View File

@ -1,10 +1,15 @@
import ObjectController from 'discourse/controllers/object';
import TopPeriod from 'discourse/models/top-period';
export default ObjectController.extend({
needs: ['navigation/category'],
loading: false,
loadingSpinner: false,
scheduledSpinner: null,
category: Em.computed.alias('controllers.navigation/category.category'),
noSubcategories: Em.computed.alias('controllers.navigation/category.noSubcategories'),
showMoreUrl: function(period) {
var url = '', category = this.get('category');
if (category) {
@ -14,8 +19,15 @@ export default ObjectController.extend({
return url;
},
showMoreDailyUrl: function() { return this.showMoreUrl('daily'); }.property('category', 'noSubcategories'),
showMoreWeeklyUrl: function() { return this.showMoreUrl('weekly'); }.property('category', 'noSubcategories'),
showMoreMonthlyUrl: function() { return this.showMoreUrl('monthly'); }.property('category', 'noSubcategories'),
showMoreYearlyUrl: function() { return this.showMoreUrl('yearly'); }.property('category', 'noSubcategories')
periods: function() {
var self = this,
periods = [];
Discourse.Site.currentProp('periods').forEach(function(p) {
periods.pushObject(TopPeriod.create({ id: p,
showMoreUrl: self.showMoreUrl(p),
periods: periods }));
});
return periods;
}.property('category', 'noSubcategories'),
});

View File

@ -3,6 +3,14 @@ import DiscoveryController from 'discourse/controllers/discovery';
export default DiscoveryController.extend({
needs: ['discovery'],
period: function() {
return this.get('controllers.discovery.periods').findBy('id', this.get('periodId'));
}.property('periodId'),
topicList: function() {
return this.get('model.' + this.get('periodId'));
}.property('periodId'),
actions: {
refresh: function() {
var self = this;
@ -16,7 +24,6 @@ export default DiscoveryController.extend({
self.send('loadingComplete');
});
}
},
}
hasDisplayedAllTopLists: Em.computed.and('content.yearly', 'content.monthly', 'content.weekly', 'content.daily')
});

View File

@ -0,0 +1,11 @@
// Include this mixin if you want to be notified when the dom should be
// cleaned (usually on route change.)
export default Ember.Mixin.create({
_initializeChooser: function() {
this.appEvents.on('dom:clean', this, "cleanUp");
}.on('didInsertElement'),
_clearChooser: function() {
this.appEvents.off('dom:clean', this, "cleanUp");
}.on('willDestroyElement')
});

View File

@ -0,0 +1,30 @@
export default Ember.Object.extend({
title: null,
availablePeriods: function() {
var periods = this.get('periods');
if (!periods) { return; }
var self = this;
return periods.filter(function(p) {
return p !== self;
});
}.property('showMoreUrl'),
_createTitle: function() {
var id = this.get('id');
if (id) {
var title = "this_week";
if (id === "yearly") {
title = "this_year";
} else if (id === "monthly") {
title = "this_month";
} else if (id === "daily") {
title = "today";
}
this.set('title', I18n.t("filters.top." + title));
}
}.on('init')
});

View File

@ -27,6 +27,7 @@ Discourse.TopList.reopenClass({
if (result[period]) {
// instanciate a new topic list with no sorting
topList.set(period, Discourse.TopicList.from(result[period]));
topList.set('periodId', period);
}
});

View File

@ -62,7 +62,8 @@ export default function(filter, params) {
setupController: function(controller, model) {
var topics = this.get('topics'),
period = filter.indexOf('/') > 0 ? filter.split('/')[1] : '',
periods = this.controllerFor('discovery').get('periods'),
periodId = filter.indexOf('/') > 0 ? filter.split('/')[1] : '',
filterText = I18n.t('filters.' + filter.replace('/', '.') + '.title', {count: 0});
Discourse.set('title', I18n.t('filters.with_category', { filter: filterText, category: model.get('name') }));
@ -71,7 +72,7 @@ export default function(filter, params) {
this.controllerFor('discovery/topics').setProperties({
model: topics,
category: model,
period: period,
period: periods.findBy('id', periodId),
selected: [],
noSubcategories: params && !!params.no_subcategories
});

View File

@ -35,7 +35,8 @@ export default function(filter) {
return 'queryParams.' + v;
})));
var period = filter.indexOf('/') > 0 ? filter.split('/')[1] : '',
var periods = this.controllerFor('discovery').get('periods'),
periodId = filter.indexOf('/') > 0 ? filter.split('/')[1] : '',
filterText = I18n.t('filters.' + filter.replace('/', '.') + '.title', {count: 0});
if (filter === Discourse.Utilities.defaultHomepage()) {
@ -47,7 +48,7 @@ export default function(filter) {
this.controllerFor('discovery/topics').setProperties({
model: model,
category: null,
period: period,
period: periods.findBy('id', periodId),
selected: []
});

View File

@ -0,0 +1,3 @@
{{#each period.availablePeriods}}
{{top-title-button period=this}}
{{/each}}

View File

@ -0,0 +1,10 @@
{{top-title period=period}}
<button><i class='fa fa-caret-down'></i></button>
<div id='period-popup' {{bind-attr class="showPeriods::hidden"}}>
<ul>
{{#each period.availablePeriods}}
<li><a {{bind-attr href="showMoreUrl"}}>{{title}}</a></li>
{{/each}}
</ul>
</div>

View File

@ -2,44 +2,22 @@
{{#if currentUser.redirected_to_top_reason}}
<div class="alert alert-info">{{currentUser.redirected_to_top_reason}}</div>
{{/if}}
{{#if content.yearly}}
{{#if topicList}}
<div class="clearfix">
<h2><i class="fa fa-calendar-o"></i> {{i18n filters.top.this_year}}</h2>
{{basic-topic-list topicList=content.yearly hideCategory=hideCategory postsAction="showTopicEntrance"}}
{{#if content.yearly.topics.length}}<a href="{{unbound showMoreYearlyUrl}}" class='btn btn-default pull-right'>{{i18n show_more}}</a>{{/if}}
</div>
{{/if}}
{{#if content.monthly}}
<div class="clearfix">
<h2><i class="fa fa-calendar-o"></i> {{i18n filters.top.this_month}}</h2>
{{basic-topic-list topicList=content.monthly hideCategory=hideCategory postsAction="showTopicEntrance"}}
{{#if content.monthly.topics.length}}<a href="{{unbound showMoreMonthlyUrl}}" class='btn btn-default pull-right'>{{i18n show_more}}</a>{{/if}}
</div>
{{/if}}
{{#if content.weekly}}
<div class="clearfix">
<h2><i class="fa fa-calendar-o"></i> {{i18n filters.top.this_week}}</h2>
{{basic-topic-list topicList=content.weekly hideCategory=hideCategory postsAction="showTopicEntrance"}}
{{#if content.weekly.topics.length}}<a href="{{unbound showMoreWeeklyUrl}}" class='btn btn-default pull-right'>{{i18n show_more}}</a>{{/if}}
</div>
{{/if}}
{{#if content.daily}}
<div class="clearfix">
<h2><i class="fa fa-calendar-o"></i> {{i18n filters.top.today}}</h2>
{{basic-topic-list topicList=content.daily hideCategory=hideCategory postsAction="showTopicEntrance"}}
{{#if content.daily.topics.length}}<a href="{{unbound showMoreDailyUrl}}" class='btn btn-default pull-right'>{{i18n show_more}}</a>{{/if}}
{{top-period-chooser period=period}}
{{basic-topic-list topicList=topicList hideCategory=hideCategory postsAction="showTopicEntrance"}}
{{#if topicList.topics.length}}<a href="{{unbound period.showMoreUrl}}" class='btn btn-default pull-right'>{{i18n show_more}}</a>{{/if}}
</div>
{{/if}}
<footer class="topic-list-bottom">
<h3>
{{#if hasDisplayedAllTopLists}}
{{#link-to "discovery.categories"}}{{i18n topic.browse_all_categories}}{{/link-to}} {{i18n or}} {{#link-to 'discovery.latest'}}{{i18n topic.view_latest_topics}}{{/link-to}}.
{{else}}
{{#link-to "discovery.categories"}}{{i18n topic.browse_all_categories}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n topic.view_latest_topics}}{{/link-to}} {{i18n or}} {{i18n filters.top.other_periods}}
{{#unless content.yearly}}<a href="{{unbound showMoreYearlyUrl}}" class='btn btn-default'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_year}}</a>{{/unless}}
{{#unless content.monthly}}<a href="{{unbound showMoreMonthlyUrl}}" class='btn btn-default'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_month}}</a>{{/unless}}
{{#unless content.weekly}}<a href="{{unbound showMoreWeeklyUrl}}" class='btn btn-default'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_week}}</a>{{/unless}}
{{#unless content.daily}}<a href="{{unbound showMoreDailyUrl}}" class='btn btn-default'><i class="fa fa-calendar-o"></i>{{i18n filters.top.today}}</a>{{/unless}}
{{top-period-buttons period=period}}
{{/if}}
</h3>
</footer>

View File

@ -18,10 +18,9 @@
<div class='contents'>
{{#if top}}
{{#if yearly}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.this_year}}</h2>{{/if}}
{{#if monthly}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.this_month}}</h2>{{/if}}
{{#if weekly}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.this_week}}</h2>{{/if}}
{{#if daily}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.today}}</h2>{{/if}}
<div class='top-lists'>
{{top-period-chooser period=period}}
</div>
{{/if}}
{{#if showTable}}
<table class='topic-list'>
@ -101,11 +100,7 @@
{{#if top}}
<h3>
{{#link-to "discovery.categories"}}{{i18n topic.browse_all_categories}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n topic.view_latest_topics}}{{/link-to}} {{i18n or}} {{i18n filters.top.other_periods}}
{{#unless yearly}}<a href="{{unbound showMoreYearlyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_year}}</a>{{/unless}}
{{#unless monthly}}<a href="{{unbound showMoreMonthlyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_month}}</a>{{/unless}}
{{#unless weekly}}<a href="{{unbound showMoreWeeklyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_week}}</a>{{/unless}}
{{#unless daily}}<a href="{{unbound showMoreDailyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.today}}</a>{{/unless}}
</h3>
{{top-period-buttons period=period}}
{{else}}
{{{footerEducation}}}
<h3>

View File

@ -1,10 +1,9 @@
<div class='contents'>
{{#if showTable}}
{{#if top}}
{{#if yearly}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.this_year}}</h2>{{/if}}
{{#if monthly}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.this_month}}</h2>{{/if}}
{{#if weekly}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.this_week}}</h2>{{/if}}
{{#if daily}}<h2><i class="fa fa-calendar-o"></i>&nbsp;{{i18n filters.top.today}}</h2>{{/if}}
<div class='top-lists'>
{{top-period-chooser period=period}}
</div>
{{/if}}
<table class='topic-list'>
{{#if topicTrackingState.hasIncoming}}
@ -47,10 +46,7 @@
{{#if top}}
<h3>
{{#link-to "discovery.categories"}}{{i18n topic.browse_all_categories}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n topic.view_latest_topics}}{{/link-to}} {{i18n or}} {{i18n filters.top.other_periods}}
{{#unless yearly}}<a href="{{unbound showMoreYearlyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_year}}</a>{{/unless}}
{{#unless monthly}}<a href="{{unbound showMoreMonthlyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_month}}</a>{{/unless}}
{{#unless weekly}}<a href="{{unbound showMoreWeeklyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.this_week}}</a>{{/unless}}
{{#unless daily}}<a href="{{unbound showMoreDailyUrl}}" class='btn'><i class="fa fa-calendar-o"></i>{{i18n filters.top.today}}</a>{{/unless}}
{{top-period-buttons period=period}}
</h3>
{{else}}
{{{footerEducation}}}

View File

@ -1,13 +1,14 @@
import CleansUp from 'discourse/mixins/cleans-up';
var clickOutsideEventName = "mousedown.outside-poster-expansion";
export default Discourse.View.extend({
export default Discourse.View.extend(CleansUp, {
elementId: 'poster-expansion',
classNameBindings: ['controller.visible::hidden', 'controller.showBadges'],
_setup: function() {
var self = this;
this.appEvents.on('poster:expand', this, '_posterExpand');
this.appEvents.on('dom:clean', this, '_cleanUp');
$('html').off(clickOutsideEventName).on(clickOutsideEventName, function(e) {
if (self.get('controller.visible')) {
@ -43,14 +44,13 @@ export default Discourse.View.extend({
});
},
_cleanUp: function() {
cleanUp: function() {
this.get('controller').close();
},
_removeEvents: function() {
$('html').off(clickOutsideEventName);
this.appEvents.off('poster:expand', this, '_posterExpand');
this.appEvents.off('dom:clean', this, '_cleanUp');
}.on('willDestroyElement')
});

View File

@ -1,3 +1,5 @@
import CleansUp from 'discourse/mixins/cleans-up';
export default Ember.View.extend({
elementId: 'topic-entrance',
classNameBindings: ['visible::hidden'],
@ -29,27 +31,22 @@ export default Ember.View.extend({
if (($target.prop('id') === 'topic-entrance') || ($self.has($target).length !== 0)) {
return;
}
self._cleanUp();
self.cleanUp();
});
}.observes('controller.position'),
_removed: function() {
$('html').off('mousedown.topic-entrance');
this.appEvents.off('dom:clean', this, '_cleanUp');
}.on('willDestroyElement'),
_cleanUp: function() {
cleanUp: function() {
this.set('controller.model', null);
$('html').off('mousedown.topic-entrance');
},
_wireClean: function() {
this.appEvents.on('dom:clean', this, '_cleanUp');
}.on('didInsertElement'),
keyDown: function(e) {
if (e.which === 27) {
this._cleanUp();
this.cleanUp();
}
}

View File

@ -19,6 +19,7 @@
//= require ./discourse/models/user_action
//= require ./discourse/models/composer
//= require ./discourse/models/topic
//= require ./discourse/models/top-period
//= require ./discourse/controllers/controller
//= require ./discourse/controllers/discovery-sortable
//= require ./discourse/controllers/object
@ -34,6 +35,7 @@
//= require ./discourse/routes/discourse_route
//= require ./discourse/routes/build-topic-route
//= require ./discourse/routes/discourse_restricted_user_route
//= require ./discourse/components/top-title
//= require ./discourse/components/text-field
//= require ./discourse/helpers/user-avatar
//= require ./discourse/helpers/cold-age-class

View File

@ -260,3 +260,48 @@ ol.category-breadcrumb {
.topic-statuses .fa {
padding-right: 3px;
}
.period-chooser {
h2 {
float: left;
}
button {
outline: 0;
background: transparent;
border: 0;
font-size: 20px;
padding: 5px 10px 0 10px;
}
#period-popup {
border: 1px solid scale-color-diff();
padding: 5px;
background: $secondary;
position: absolute;
z-index: 1110;
@include box-shadow(0 2px 2px rgba(0,0,0, .4));
ul {
list-style: none;
margin: 0;
padding: 0;
li {
margin: 0;
padding: 0;
a {
display: block;
padding: 5px;
}
&:hover {
background-color: dark-light-diff($highlight, $secondary, 50%, -70%);
}
}
}
}
}
.top-title-buttons {
display: inline;
}

View File

@ -296,3 +296,9 @@ ol.category-breadcrumb {
max-width: 100%;
padding: 8px 0;
}
.period-chooser {
button {
margin-top: 10px;
}
}

View File

@ -317,11 +317,7 @@ class ListController < ApplicationController
options[:per_page] = SiteSetting.topics_per_period_in_top_summary
topic_query = TopicQuery.new(current_user, options)
if current_user.present?
periods = [ListController.best_period_for(current_user.previous_visit_at, options[:category])]
else
periods = TopTopic.periods
end
periods = [ListController.best_period_for(current_user.try(:previous_visit_at), options[:category])]
periods.each { |period| top.send("#{period}=", topic_query.list_top_for(period)) }