diff --git a/app/assets/javascripts/discourse/components/activity-column.js.es6 b/app/assets/javascripts/discourse/components/activity-column.js.es6 index 3f17f5b42..c0a526975 100644 --- a/app/assets/javascripts/discourse/components/activity-column.js.es6 +++ b/app/assets/javascripts/discourse/components/activity-column.js.es6 @@ -32,14 +32,25 @@ export default Ember.Component.extend({ }.property('bumpedAt', 'createdAt'), title: function() { - // return {{i18n last_post}}: {{{raw-date topic.bumped_at}}} return I18n.t('first_post') + ": " + Discourse.Formatter.longDate(this.get('createdAt')) + "\n" + I18n.t('last_post') + ": " + Discourse.Formatter.longDate(this.get('bumpedAt')); }.property('bumpedAt', 'createdAt'), render: function(buffer) { - buffer.push('<a href="' + this.get('topic.lastPostUrl') + '">'); buffer.push(Discourse.Formatter.autoUpdatingRelativeAge(this.get('bumpedAt'))); - buffer.push("</a>"); + }, + + click: function() { + var topic = this.get('topic'); + + if (Discourse.Mobile.mobileView) { + Discourse.URL.routeTo(topic.get('lastPostUrl')); + return; + } + + this.sendAction('action', { + topic: topic, + position: this.$('span').position() + }); } }); diff --git a/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 b/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 index 62373cce4..d966ca1cf 100644 --- a/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 +++ b/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 @@ -37,6 +37,12 @@ export default Ember.Component.extend({ // Without a topic list, we assume it's loaded always. this.set('loaded', true); } + }, + + actions: { + clickedActivity: function(data) { + this.sendAction('activityAction', data); + } } }); diff --git a/app/assets/javascripts/discourse/controllers/topic-entrance.js.es6 b/app/assets/javascripts/discourse/controllers/topic-entrance.js.es6 new file mode 100644 index 000000000..1a19dd442 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/topic-entrance.js.es6 @@ -0,0 +1,44 @@ +function entranceDate(dt) { + var bumpedAt = new Date(dt), + today = new Date(); + + if (bumpedAt.getDate() === today.getDate()) { + return moment(bumpedAt).format(I18n.t("dates.time")); + } + + if (bumpedAt.getYear() === today.getYear()) { + return moment(bumpedAt).format(I18n.t("dates.long_no_year")); + } + + return moment(bumpedAt).format(I18n.t('dates.long_with_year')); +} + +export default Ember.ObjectController.extend({ + position: null, + + topDate: function() { + return entranceDate(this.get('created_at')); + }.property('model.created_at'), + + bottomDate: function() { + return entranceDate(this.get('bumped_at')); + }.property('model.bumped_at'), + + actions: { + show: function(data) { + // Show the chooser but only if the model changes + if (this.get('model') !== data.topic) { + this.set('model', data.topic); + this.set('position', data.position); + } + }, + + enterTop: function() { + Discourse.URL.routeTo(this.get('url')); + }, + + enterBottom: function() { + Discourse.URL.routeTo(this.get('lastPostUrl')); + } + } +}); diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 2473f49e1..4a0902773 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -1,6 +1,10 @@ var ApplicationRoute = Em.Route.extend({ actions: { + showTopicEntrance: function(data) { + this.controllerFor('topic-entrance').send('show', data); + }, + error: function(err, transition) { if (err.status === 404) { // 404 diff --git a/app/assets/javascripts/discourse/routes/discourse_route.js b/app/assets/javascripts/discourse/routes/discourse_route.js index 1db776cc7..6934a9a48 100644 --- a/app/assets/javascripts/discourse/routes/discourse_route.js +++ b/app/assets/javascripts/discourse/routes/discourse_route.js @@ -77,6 +77,10 @@ Discourse.Route.reopenClass({ $('#discourse-modal').modal('hide'); var hideDropDownFunction = $('html').data('hide-dropdown'); if (hideDropDownFunction) { hideDropDownFunction(); } + + // TODO: Avoid container lookup here + var appEvents = Discourse.__container__.lookup('app-events:main'); + appEvents.trigger('dom:clean'); }, /** diff --git a/app/assets/javascripts/discourse/templates/application.js.handlebars b/app/assets/javascripts/discourse/templates/application.js.handlebars index 4a624f707..f850ab4ef 100644 --- a/app/assets/javascripts/discourse/templates/application.js.handlebars +++ b/app/assets/javascripts/discourse/templates/application.js.handlebars @@ -5,4 +5,5 @@ </div> {{render "modal"}} +{{render "topic-entrance"}} {{render "composer"}} diff --git a/app/assets/javascripts/discourse/templates/components/basic-topic-list.js.handlebars b/app/assets/javascripts/discourse/templates/components/basic-topic-list.js.handlebars index b9e1b8540..8c55a5f44 100644 --- a/app/assets/javascripts/discourse/templates/components/basic-topic-list.js.handlebars +++ b/app/assets/javascripts/discourse/templates/components/basic-topic-list.js.handlebars @@ -53,7 +53,7 @@ {{number topic.views numberKey="views_long"}} </td> - {{activity-column topic=topic class="num"}} + {{activity-column topic=topic class="num" action="clickedActivity"}} </tr> {{/grouped-each}} </tbody> diff --git a/app/assets/javascripts/discourse/templates/discovery/top.js.handlebars b/app/assets/javascripts/discourse/templates/discovery/top.js.handlebars index 27fbfbfe7..4ecd1c064 100644 --- a/app/assets/javascripts/discourse/templates/discovery/top.js.handlebars +++ b/app/assets/javascripts/discourse/templates/discovery/top.js.handlebars @@ -5,28 +5,28 @@ {{#if content.yearly}} <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}} + {{basic-topic-list topicList=content.yearly hideCategory=hideCategory activityAction="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}} + {{basic-topic-list topicList=content.monthly hideCategory=hideCategory activityAction="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}} + {{basic-topic-list topicList=content.weekly hideCategory=hideCategory activityAction="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}} + {{basic-topic-list topicList=content.daily hideCategory=hideCategory activityAction="showTopicEntrance"}} {{#if content.daily.topics.length}}<a href="{{unbound showMoreDailyUrl}}" class='btn btn-default pull-right'>{{i18n show_more}}</a>{{/if}} </div> {{/if}} diff --git a/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars b/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars index 5123e5fe1..e9baf550d 100644 --- a/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list/topic_list_item.js.handlebars @@ -49,4 +49,4 @@ {{posts-count-column topic=model class="num"}} <td {{bind-attr class=":num :views viewsHeat"}}>{{number views numberKey="views_long"}}</td> -{{activity-column topic=model class="num"}} +{{activity-column topic=model class="num" action="showTopicEntrance"}} diff --git a/app/assets/javascripts/discourse/templates/list/user_topics_list.js.handlebars b/app/assets/javascripts/discourse/templates/list/user_topics_list.js.handlebars index 44836b7c2..f7e73c447 100644 --- a/app/assets/javascripts/discourse/templates/list/user_topics_list.js.handlebars +++ b/app/assets/javascripts/discourse/templates/list/user_topics_list.js.handlebars @@ -1 +1,4 @@ -{{basic-topic-list topicList=model hideCategory=hideCategory showParticipants=showParticipants}} +{{basic-topic-list topicList=model + hideCategory=hideCategory + showParticipants=showParticipants + activityAction="showTopicEntrance"}} diff --git a/app/assets/javascripts/discourse/templates/topic-entrance.js.handlebars b/app/assets/javascripts/discourse/templates/topic-entrance.js.handlebars new file mode 100644 index 000000000..4291a27f4 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/topic-entrance.js.handlebars @@ -0,0 +1,6 @@ +<button {{action enterTop}} class='btn full no-text'> + <i class='fa fa-caret-up'></i> {{topDate}} +</button> +<button {{action enterBottom}} class='btn full no-text jump-bottom'> + <i class='fa fa-caret-down'></i> {{bottomDate}} +</button> diff --git a/app/assets/javascripts/discourse/templates/topic.js.handlebars b/app/assets/javascripts/discourse/templates/topic.js.handlebars index 6949cab4d..72cb989c4 100644 --- a/app/assets/javascripts/discourse/templates/topic.js.handlebars +++ b/app/assets/javascripts/discourse/templates/topic.js.handlebars @@ -102,7 +102,7 @@ <div id='suggested-topics'> <h3>{{i18n suggested_topics.title}}</h3> <div class='topics'> - {{basic-topic-list topics=details.suggested_topics}} + {{basic-topic-list topics=details.suggested_topics activityAction="showTopicEntrance"}} </div> <h3>{{{view.browseMoreMessage}}}</h3> </div> diff --git a/app/assets/javascripts/discourse/views/topic-entrance.js.es6 b/app/assets/javascripts/discourse/views/topic-entrance.js.es6 new file mode 100644 index 000000000..20408d0e3 --- /dev/null +++ b/app/assets/javascripts/discourse/views/topic-entrance.js.es6 @@ -0,0 +1,50 @@ +export default Ember.View.extend({ + elementId: 'topic-entrance', + classNameBindings: ['visible::hidden'], + visible: Em.computed.notEmpty('controller.model'), + + _positionChanged: function() { + var pos = this.get('controller.position'); + if (!pos) { return; } + + var $self = this.$(); + + // Move after we render so the height is correct + Em.run.schedule('afterRender', function() { + var width = $self.width(), + height = $self.height(); + pos.left = (parseInt(pos.left) - (width / 2)); + pos.top = (parseInt(pos.top) - (height / 2)); + + var windowWidth = $(window).width(); + if (pos.left + width > windowWidth) { + pos.left = (windowWidth - width) - 5; + } + $self.css(pos); + }); + + var self = this; + $('html').off('mousedown.topic-entrance').on('mousedown.topic-entrance', function(e) { + var $target = $(e.target); + if (($target.prop('id') === 'topic-entrance') || ($self.has($target).length !== 0)) { + return; + } + self._cleanUp(); + }); + }.observes('controller.position'), + + _removed: function() { + $('html').off('mousedown.topic-entrance'); + this.appEvents.off('dom:clean', this, '_cleanUp'); + }.on('willDestroyElement'), + + _cleanUp: function() { + this.set('controller.model', null); + $('html').off('mousedown.topic-entrance'); + }, + + _wireClean: function() { + this.appEvents.on('dom:clean', this, '_cleanUp'); + }.on('didInsertElement'), + +}); diff --git a/app/assets/stylesheets/desktop.scss b/app/assets/stylesheets/desktop.scss index fa2cf8ed3..a36b12e34 100644 --- a/app/assets/stylesheets/desktop.scss +++ b/app/assets/stylesheets/desktop.scss @@ -15,6 +15,7 @@ @import "desktop/topic"; @import "desktop/upload"; @import "desktop/user"; +@import "desktop/topic-entrance"; /* These files doesn't actually exist, they are injected by DiscourseSassImporter. */ diff --git a/app/assets/stylesheets/desktop/topic-entrance.scss b/app/assets/stylesheets/desktop/topic-entrance.scss new file mode 100644 index 000000000..058b389ea --- /dev/null +++ b/app/assets/stylesheets/desktop/topic-entrance.scss @@ -0,0 +1,25 @@ +#topic-entrance { + border: 1px solid scale-color-diff(); + padding: 5px; + background: $secondary; + @include box-shadow(0 0px 2px rgba(0,0,0, .2)); + z-index: 100; + + position: absolute; + width: 133px; + padding: 5px; + + button.full { + width: 100%; + margin-bottom: 5px; + i { + display: block; + margin-top: 2px; + margin-bottom: 2px; + font-size: 18px; + } + } + button.btn.jump-bottom { + margin: 5px 0 0 0; + } +} diff --git a/app/assets/stylesheets/desktop/topic-list.scss b/app/assets/stylesheets/desktop/topic-list.scss index 42e24c171..5ba472836 100644 --- a/app/assets/stylesheets/desktop/topic-list.scss +++ b/app/assets/stylesheets/desktop/topic-list.scss @@ -138,6 +138,9 @@ } .activity { width: 60px; + span { + cursor: pointer; + } } .age { width: 60px; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2fe32b5d2..d0fb8212a 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -30,6 +30,9 @@ en: mb: MB tb: TB dates: + time: "h:mm a" + long_no_year: "MMM DD h:mm a" + long_with_year: "MMM DD, YYYY h:mm a" tiny: half_a_minute: "< 1m" less_than_x_seconds: