From 0317cf960887c1f6512311565a28ebe3f78c216a Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 24 Jul 2013 17:15:21 -0400 Subject: [PATCH] Show topics as a list of topics on the User Stream. --- .../templates/site_settings.js.handlebars | 2 - .../site_settings/setting_bool.js.handlebars | 20 +- .../site_settings/setting_enum.js.handlebars | 32 ++- .../setting_string.js.handlebars | 32 ++- .../javascripts/discourse/components/url.js | 3 + .../discourse/components/utilities.js | 2 +- .../discourse/controllers/list_controller.js | 10 + .../controllers/list_topics_controller.js | 10 +- .../preferences_about_controller.js | 48 ----- .../controllers/preferences_controller.js | 18 -- .../preferences_email_controller.js | 29 --- .../preferences_username_controller.js | 29 --- .../controllers/user_activity_controller.js | 79 ------- .../javascripts/discourse/mixins/load_more.js | 39 ++++ .../discourse/models/topic_list.js | 34 ++-- .../javascripts/discourse/models/user.js | 1 + .../discourse/models/user_action.js | 6 +- .../discourse/models/user_stream.js | 2 +- .../discourse/routes/filtered_list_route.js | 2 - .../discourse/routes/preferences_routes.js | 119 +++++++++++ .../discourse/routes/user_invited_route.js | 21 -- .../discourse/routes/user_route.js | 56 ----- .../discourse/routes/user_routes.js | 192 ++++++++++++++++++ .../templates/embedded_post.js.handlebars | 32 ++- .../discourse/templates/list.js.handlebars | 44 ++++ .../list/basic_topic_list.js.handlebars | 55 +++++ .../templates/list/list.js.handlebars | 4 +- .../search/category_result.js.handlebars | 9 +- .../search/topic_result.js.handlebars | 9 +- .../search/user_result.js.handlebars | 11 +- .../templates/suggested_topic.js.handlebars | 43 ---- .../discourse/templates/topic.js.handlebars | 17 +- .../templates/user/activity.js.handlebars | 5 +- .../templates/user/stream_item.js.handlebars | 43 ++-- .../templates/user/topics_list.js.handlebars | 1 + .../discourse/views/embedded_post_view.js | 5 + .../views/list/basic_topic_list_view.js | 12 ++ .../discourse/views/list/list_topics_view.js | 30 +-- .../discourse/views/list/list_view.js | 32 --- .../views/list/paginated_topic_list_view.js | 20 ++ .../views/list/topic_list_item_view.js | 4 +- .../views/search/search_results_type_view.js | 17 +- .../discourse/views/suggested_topic_view.js | 13 -- .../views/user/activity_filter_view.js | 2 +- .../discourse/views/user/user_stream_view.js | 37 ++-- app/assets/javascripts/main_include.js | 1 + .../stylesheets/application/topic.css.scss | 8 +- .../stylesheets/application/user.css.scss | 102 +++++----- app/controllers/list_controller.rb | 10 +- config/routes.rb | 1 + lib/tasks/integration.rake | 2 +- lib/topic_query.rb | 8 + test/javascripts/fixtures/list_fixtures.js | 6 +- test/javascripts/fixtures/static_fixtures.js | 4 +- test/javascripts/fixtures/topic_fixtures.js | 2 +- test/javascripts/fixtures/user_fixtures.js | 16 +- test/javascripts/integration/user_test.js | 2 +- 57 files changed, 743 insertions(+), 650 deletions(-) create mode 100644 app/assets/javascripts/discourse/mixins/load_more.js create mode 100644 app/assets/javascripts/discourse/routes/preferences_routes.js delete mode 100644 app/assets/javascripts/discourse/routes/user_invited_route.js delete mode 100644 app/assets/javascripts/discourse/routes/user_route.js create mode 100644 app/assets/javascripts/discourse/routes/user_routes.js create mode 100644 app/assets/javascripts/discourse/templates/list.js.handlebars create mode 100644 app/assets/javascripts/discourse/templates/list/basic_topic_list.js.handlebars delete mode 100644 app/assets/javascripts/discourse/templates/suggested_topic.js.handlebars create mode 100644 app/assets/javascripts/discourse/templates/user/topics_list.js.handlebars create mode 100644 app/assets/javascripts/discourse/views/list/basic_topic_list_view.js delete mode 100644 app/assets/javascripts/discourse/views/list/list_view.js create mode 100644 app/assets/javascripts/discourse/views/list/paginated_topic_list_view.js delete mode 100644 app/assets/javascripts/discourse/views/suggested_topic_view.js diff --git a/app/assets/javascripts/admin/templates/site_settings.js.handlebars b/app/assets/javascripts/admin/templates/site_settings.js.handlebars index 14ac8847d67..cb8270b8ba3 100644 --- a/app/assets/javascripts/admin/templates/site_settings.js.handlebars +++ b/app/assets/javascripts/admin/templates/site_settings.js.handlebars @@ -13,5 +13,3 @@ {{collection contentBinding="filteredContent" classNames="form-horizontal settings" itemViewClass="Discourse.SiteSettingView"}} - -

Diagnostics: last_message_processed {{diags.last_message_processed}}

diff --git a/app/assets/javascripts/admin/templates/site_settings/setting_bool.js.handlebars b/app/assets/javascripts/admin/templates/site_settings/setting_bool.js.handlebars index fec6d5f39b4..53282604f1d 100644 --- a/app/assets/javascripts/admin/templates/site_settings/setting_bool.js.handlebars +++ b/app/assets/javascripts/admin/templates/site_settings/setting_bool.js.handlebars @@ -1,11 +1,9 @@ -{{#with view.content}} -
-

{{unbound setting}}

-
-
- -
-{{/with}} +
+

{{unbound setting}}

+
+
+ +
diff --git a/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars b/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars index b8e8addd955..710505e110c 100644 --- a/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars +++ b/app/assets/javascripts/admin/templates/site_settings/setting_enum.js.handlebars @@ -1,19 +1,17 @@ -{{#with view.content}} -
-

{{unbound setting}}

+
+

{{unbound setting}}

+
+
+ {{combobox valueAttribute="value" content=validValues value=value none=allowsNone}} +
{{unbound description}}
+
+{{#if dirty}} +
+ +
-
- {{combobox valueAttribute="value" content=validValues value=value none=allowsNone}} -
{{unbound description}}
-
- {{#if dirty}} -
- - -
- {{else}} - {{#if overridden}} - - {{/if}} +{{else}} + {{#if overridden}} + {{/if}} -{{/with}} \ No newline at end of file +{{/if}} diff --git a/app/assets/javascripts/admin/templates/site_settings/setting_string.js.handlebars b/app/assets/javascripts/admin/templates/site_settings/setting_string.js.handlebars index 935875be57d..647644cf9a1 100644 --- a/app/assets/javascripts/admin/templates/site_settings/setting_string.js.handlebars +++ b/app/assets/javascripts/admin/templates/site_settings/setting_string.js.handlebars @@ -1,19 +1,17 @@ -{{#with view.content}} -
-

{{unbound setting}}

+
+

{{unbound setting}}

+
+
+ {{textField value=value classNames="input-xxlarge"}} +
{{unbound description}}
+
+{{#if dirty}} +
+ +
-
- {{textField value=value classNames="input-xxlarge"}} -
{{unbound description}}
-
- {{#if dirty}} -
- - -
- {{else}} - {{#if overridden}} - - {{/if}} +{{else}} + {{#if overridden}} + {{/if}} -{{/with}} \ No newline at end of file +{{/if}} diff --git a/app/assets/javascripts/discourse/components/url.js b/app/assets/javascripts/discourse/components/url.js index 6589e1a836f..3eeae173754 100644 --- a/app/assets/javascripts/discourse/components/url.js +++ b/app/assets/javascripts/discourse/components/url.js @@ -64,6 +64,9 @@ Discourse.URL = Em.Object.createWithMixins({ if (this.navigatedToListMore(oldPath, path)) { return; } if (this.navigatedToHome(oldPath, path)) { return; } + if (path.match(/^\/?users\/[^\/]+$/)) { + path += "/activity"; + } // Be wary of looking up the router. In this case, we have links in our // HTML, say form compiled markdown posts, that need to be routed. var router = this.get('router'); diff --git a/app/assets/javascripts/discourse/components/utilities.js b/app/assets/javascripts/discourse/components/utilities.js index ce3bf0af612..ce603061632 100644 --- a/app/assets/javascripts/discourse/components/utilities.js +++ b/app/assets/javascripts/discourse/components/utilities.js @@ -87,7 +87,7 @@ Discourse.Utilities = { }, userUrl: function(username) { - return Discourse.getURL("/users/" + username); + return Discourse.getURL("/users/" + username.toLowerCase()); }, emailValid: function(email) { diff --git a/app/assets/javascripts/discourse/controllers/list_controller.js b/app/assets/javascripts/discourse/controllers/list_controller.js index 7e8405c3141..0fb4fd9292e 100644 --- a/app/assets/javascripts/discourse/controllers/list_controller.js +++ b/app/assets/javascripts/discourse/controllers/list_controller.js @@ -24,6 +24,16 @@ Discourse.ListController = Discourse.Controller.extend({ }); }.property(), + createTopicText: function() { + if (this.get('category.name')) { + return I18n.t("topic.create_in", { + categoryName: this.get('category.name') + }); + } else { + return I18n.t("topic.create"); + } + }.property('category.name'), + /** Refresh our current topic list diff --git a/app/assets/javascripts/discourse/controllers/list_topics_controller.js b/app/assets/javascripts/discourse/controllers/list_topics_controller.js index 827d95b8430..511d39669b7 100644 --- a/app/assets/javascripts/discourse/controllers/list_topics_controller.js +++ b/app/assets/javascripts/discourse/controllers/list_topics_controller.js @@ -81,11 +81,11 @@ Discourse.ListTopicsController = Discourse.ObjectController.extend({ }.property('allLoaded', 'topics.length'), loadMore: function() { - this.set('loadingMore', true); - var listTopicsController = this; - return this.get('model').loadMoreTopics().then(function(hasMoreTopics) { - listTopicsController.set('loadingMore', false); - return hasMoreTopics; + var topicList = this.get('model'); + return topicList.loadMoreTopics().then(function(moreUrl) { + if (!Em.isEmpty(moreUrl)) { + Discourse.URL.replaceState(Discourse.getURL("/") + topicList.get('filter') + "/more"); + } }); } diff --git a/app/assets/javascripts/discourse/controllers/preferences_about_controller.js b/app/assets/javascripts/discourse/controllers/preferences_about_controller.js index 20ff80bde49..bb80f52889d 100644 --- a/app/assets/javascripts/discourse/controllers/preferences_about_controller.js +++ b/app/assets/javascripts/discourse/controllers/preferences_about_controller.js @@ -1,51 +1,3 @@ -/** - The route for editing a user's "About Me" bio. - - @class PreferencesAboutRoute - @extends Discourse.RestrictedUserRoute - @namespace Discourse - @module Discourse -**/ -Discourse.PreferencesAboutRoute = Discourse.RestrictedUserRoute.extend({ - model: function() { - return this.modelFor('user'); - }, - - renderTemplate: function() { - this.render({ into: 'user', outlet: 'userOutlet' }); - }, - - setupController: function(controller, model) { - controller.setProperties({ model: model, newBio: model.get('bio_raw') }); - }, - - // A bit odd, but if we leave to /preferences we need to re-render that outlet - exit: function() { - this._super(); - this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); - }, - - events: { - changeAbout: function() { - var route = this; - var controller = route.controllerFor('preferencesAbout'); - - controller.setProperties({ saving: true }); - return controller.get('model').save().then(function() { - controller.set('saving', false); - route.transitionTo('user.index'); - }, function() { - // model failed to save - controller.set('saving', false); - alert(I18n.t('generic_error')); - }); - } - } - -}); - - - /** This controller supports actions related to updating your "About Me" bio diff --git a/app/assets/javascripts/discourse/controllers/preferences_controller.js b/app/assets/javascripts/discourse/controllers/preferences_controller.js index 99c817df05b..69c4618d791 100644 --- a/app/assets/javascripts/discourse/controllers/preferences_controller.js +++ b/app/assets/javascripts/discourse/controllers/preferences_controller.js @@ -1,21 +1,3 @@ -/** - The common route stuff for a user's preference - - @class PreferencesRoute - @extends Discourse.RestrictedUserRoute - @namespace Discourse - @module Discourse -**/ -Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({ - model: function() { - return this.modelFor('user'); - }, - - renderTemplate: function() { - this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); - } -}); - /** This controller supports actions related to updating one's preferences diff --git a/app/assets/javascripts/discourse/controllers/preferences_email_controller.js b/app/assets/javascripts/discourse/controllers/preferences_email_controller.js index 0a272995836..e07506f8676 100644 --- a/app/assets/javascripts/discourse/controllers/preferences_email_controller.js +++ b/app/assets/javascripts/discourse/controllers/preferences_email_controller.js @@ -1,32 +1,3 @@ -/** - The route for editing a user's email - - @class PreferencesEmailRoute - @extends Discourse.RestrictedUserRoute - @namespace Discourse - @module Discourse -**/ -Discourse.PreferencesEmailRoute = Discourse.RestrictedUserRoute.extend({ - model: function() { - return this.modelFor('user'); - }, - - renderTemplate: function() { - this.render({ into: 'user', outlet: 'userOutlet' }); - }, - - setupController: function(controller, model) { - controller.setProperties({ model: model, newEmail: model.get('email') }); - }, - - // A bit odd, but if we leave to /preferences we need to re-render that outlet - exit: function() { - this._super(); - this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); - } -}); - - /** This controller supports actions related to updating one's email address diff --git a/app/assets/javascripts/discourse/controllers/preferences_username_controller.js b/app/assets/javascripts/discourse/controllers/preferences_username_controller.js index d0b59895c9b..e011feeb0c1 100644 --- a/app/assets/javascripts/discourse/controllers/preferences_username_controller.js +++ b/app/assets/javascripts/discourse/controllers/preferences_username_controller.js @@ -1,32 +1,3 @@ -/** - The route for updating a user's username - - @class PreferencesUsernameRoute - @extends Discourse.RestrictedUserRoute - @namespace Discourse - @module Discourse -**/ -Discourse.PreferencesUsernameRoute = Discourse.RestrictedUserRoute.extend({ - model: function() { - return this.modelFor('user'); - }, - - renderTemplate: function() { - return this.render({ into: 'user', outlet: 'userOutlet' }); - }, - - // A bit odd, but if we leave to /preferences we need to re-render that outlet - exit: function() { - this._super(); - this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); - }, - - setupController: function(controller, user) { - controller.setProperties({ model: user, newUsername: user.get('username') }); - } -}); - - /** This controller supports actions related to updating one's username diff --git a/app/assets/javascripts/discourse/controllers/user_activity_controller.js b/app/assets/javascripts/discourse/controllers/user_activity_controller.js index e07c1b9de0c..e6d86742c3e 100644 --- a/app/assets/javascripts/discourse/controllers/user_activity_controller.js +++ b/app/assets/javascripts/discourse/controllers/user_activity_controller.js @@ -1,82 +1,3 @@ -/** - The base route for showing an activity stream. - - @class UserActivityRoute - @extends Discourse.Route - @namespace Discourse - @module Discourse -**/ -Discourse.UserActivityRoute = Discourse.Route.extend({ - renderTemplate: function() { - this.render('user_activity', {into: 'user', outlet: 'userOutlet' }); - }, - - model: function() { - return this.modelFor('user'); - }, - - setupController: function(controller, user) { - this.controllerFor('userActivity').set('model', user); - - var composerController = this.controllerFor('composer'); - controller.set('model', user); - if (Discourse.User.current()) { - Discourse.Draft.get('new_private_message').then(function(data) { - if (data.draft) { - composerController.open({ - draft: data.draft, - draftKey: 'new_private_message', - ignoreIfChanged: true, - draftSequence: data.draft_sequence - }); - } - }); - } - } -}); - -Discourse.UserActivityIndexRoute = Discourse.Route.extend({ - model: function() { - return this.modelFor('user').findStream(this.get('userActionType')); - }, - - renderTemplate: function() { - this.render('user_stream', {into: 'user_activity', outlet: 'activity'}); - }, - - setupController: function() { - this.controllerFor('user_activity').set('userActionType', this.get('userActionType')); - } -}); - -Discourse.UserIndexRoute = Discourse.UserActivityRoute.extend({ - renderTemplate: function() { - this._super(); - this.render('user_stream', {into: 'user_activity', outlet: 'activity'}); - }, - - model: function() { - return this.modelFor('user').findStream(); - }, - - setupController: function(controller, model) { - this.controllerFor('userActivity').set('model', this.modelFor('user')); - this.set('model', model); - } -}); - -// Build all the filter routes -Object.keys(Discourse.UserAction.TYPES).forEach(function (userAction) { - Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityIndexRoute.extend({ - userActionType: Discourse.UserAction.TYPES[userAction] - }); -}); - -// // Build the private message routes -Discourse.UserPrivateMessagesRoute = Discourse.UserActivityRoute.extend({}); -Discourse.UserPrivateMessagesIndexRoute = Discourse.UserActivityMessagesReceivedRoute; -Discourse.UserPrivateMessagesSentRoute = Discourse.UserActivityMessagesSentRoute; - /** This controller supports all actions on a user's activity stream diff --git a/app/assets/javascripts/discourse/mixins/load_more.js b/app/assets/javascripts/discourse/mixins/load_more.js new file mode 100644 index 00000000000..388fc2e938a --- /dev/null +++ b/app/assets/javascripts/discourse/mixins/load_more.js @@ -0,0 +1,39 @@ +/** + This mixin provides the ability to load more items for a view which is + scrolled to the bottom. + + @class Discourse.LoadMore + @extends Ember.Mixin + @uses Discourse.Scrolling + @namespace Discourse + @module Discourse +**/ +Discourse.LoadMore = Em.Mixin.create(Discourse.Scrolling, { + + scrolled: function(e) { + var eyeline = this.get('eyeline'); + if (eyeline) { eyeline.update(); } + }, + + loadMore: function() { + console.error('loadMore() not defined'); + }, + + didInsertElement: function() { + this._super(); + var eyeline = new Discourse.Eyeline(this.get('eyelineSelector')); + this.set('eyeline', eyeline); + + var paginatedTopicListView = this; + eyeline.on('sawBottom', function() { + paginatedTopicListView.loadMore(); + }); + this.bindScrolling(); + }, + + willRemoveElement: function() { + this._super(); + this.unbindScrolling(); + } + +}); diff --git a/app/assets/javascripts/discourse/models/topic_list.js b/app/assets/javascripts/discourse/models/topic_list.js index 808b6a8b410..52d09a94098 100644 --- a/app/assets/javascripts/discourse/models/topic_list.js +++ b/app/assets/javascripts/discourse/models/topic_list.js @@ -23,32 +23,37 @@ Discourse.TopicList = Discourse.Model.extend({ }, loadMoreTopics: function() { - var moreUrl, _this = this; - if (moreUrl = this.get('more_topics_url')) { - Discourse.URL.replaceState(Discourse.getURL("/") + (this.get('filter')) + "/more"); + if (this.get('loadingMore')) { return Ember.RSVP.reject(); } + + var moreUrl = this.get('more_topics_url'); + if (moreUrl) { + + var topicList = this; + this.set('loadingMore', true); + return Discourse.ajax({url: moreUrl}).then(function (result) { - var newTopics, topics, topicsAdded = 0; + var topicsAdded = 0; if (result) { // the new topics loaded from the server - newTopics = Discourse.TopicList.topicsFrom(result); - topics = _this.get("topics"); + var newTopics = Discourse.TopicList.topicsFrom(result); + var topics = topicList.get("topics"); - _this.forEachNew(newTopics, function(t) { + topicList.forEachNew(newTopics, function(t) { t.set('highlight', topicsAdded++ === 0); topics.pushObject(t); }); - _this.set('more_topics_url', result.topic_list.more_topics_url); - Discourse.set('transient.topicsList', _this); + topicList.set('more_topics_url', result.topic_list.more_topics_url); + Discourse.set('transient.topicsList', topicList); + topicList.set('loadingMore', false); + + return result.topic_list.more_topics_url; } - return result.topic_list.more_topics_url; }); } else { // Return a promise indicating no more results - return Ember.Deferred.promise(function (p) { - p.resolve(false); - }); + return Ember.RSVP.reject(); } }, @@ -109,6 +114,9 @@ Discourse.TopicList.reopenClass({ categories = this.extractByKey(result.categories, Discourse.Category); users = this.extractByKey(result.users, Discourse.User); topics = Em.A(); + + console.log(result.topic_list); + _.each(result.topic_list.topics,function(ft) { ft.category = categories[ft.category_id]; _.each(ft.posters,function(p) { diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js index 898bd881c7a..a21ffeb93c9 100644 --- a/app/assets/javascripts/discourse/models/user.js +++ b/app/assets/javascripts/discourse/models/user.js @@ -264,6 +264,7 @@ Discourse.User = Discourse.Model.extend({ json.user.invited_by = Discourse.User.create(json.user.invited_by); } + user.setProperties(json.user); return user; }); diff --git a/app/assets/javascripts/discourse/models/user_action.js b/app/assets/javascripts/discourse/models/user_action.js index 1dfd4375736..975e6b92a40 100644 --- a/app/assets/javascripts/discourse/models/user_action.js +++ b/app/assets/javascripts/discourse/models/user_action.js @@ -99,7 +99,11 @@ Discourse.UserAction = Discourse.Model.extend({ }.property('target_username'), targetUserUrl: Discourse.computed.url('target_username', '/users/%@'), - userUrl: Discourse.computed.url('username', '/users/%@'), + usernameLower: function() { + return this.get('username').toLowerCase(); + }.property('username'), + + userUrl: Discourse.computed.url('usernameLower', '/users/%@'), postUrl: function() { return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number')); diff --git a/app/assets/javascripts/discourse/models/user_stream.js b/app/assets/javascripts/discourse/models/user_stream.js index a10193fff11..3a15cece1c5 100644 --- a/app/assets/javascripts/discourse/models/user_stream.js +++ b/app/assets/javascripts/discourse/models/user_stream.js @@ -18,7 +18,7 @@ Discourse.UserStream = Discourse.Model.extend({ findItems: function() { var me = this; - if(this.get("loading")) { return; } + if(this.get("loading")) { return Ember.RSVP.reject(); } this.set("loading",true); var url = Discourse.getURL("/user_actions.json?offset=") + this.get('itemsLoaded') + "&username=" + (this.get('user.username_lower')); diff --git a/app/assets/javascripts/discourse/routes/filtered_list_route.js b/app/assets/javascripts/discourse/routes/filtered_list_route.js index 402546d2fea..163a08400a9 100644 --- a/app/assets/javascripts/discourse/routes/filtered_list_route.js +++ b/app/assets/javascripts/discourse/routes/filtered_list_route.js @@ -47,5 +47,3 @@ Discourse.FilteredListRoute = Discourse.Route.extend({ Discourse.ListController.filters.forEach(function(filter) { Discourse["List" + (filter.capitalize()) + "Route"] = Discourse.FilteredListRoute.extend({ filter: filter }); }); - - diff --git a/app/assets/javascripts/discourse/routes/preferences_routes.js b/app/assets/javascripts/discourse/routes/preferences_routes.js new file mode 100644 index 00000000000..6e6e14160ee --- /dev/null +++ b/app/assets/javascripts/discourse/routes/preferences_routes.js @@ -0,0 +1,119 @@ +/** + The common route stuff for a user's preference + + @class PreferencesRoute + @extends Discourse.RestrictedUserRoute + @namespace Discourse + @module Discourse +**/ +Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({ + model: function() { + return this.modelFor('user'); + }, + + renderTemplate: function() { + this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); + } +}); + +/** + The route for editing a user's "About Me" bio. + + @class PreferencesAboutRoute + @extends Discourse.RestrictedUserRoute + @namespace Discourse + @module Discourse +**/ +Discourse.PreferencesAboutRoute = Discourse.RestrictedUserRoute.extend({ + model: function() { + return this.modelFor('user'); + }, + + renderTemplate: function() { + this.render({ into: 'user', outlet: 'userOutlet' }); + }, + + setupController: function(controller, model) { + controller.setProperties({ model: model, newBio: model.get('bio_raw') }); + }, + + // A bit odd, but if we leave to /preferences we need to re-render that outlet + exit: function() { + this._super(); + this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); + }, + + events: { + changeAbout: function() { + var route = this; + var controller = route.controllerFor('preferencesAbout'); + + controller.setProperties({ saving: true }); + return controller.get('model').save().then(function() { + controller.set('saving', false); + route.transitionTo('user.index'); + }, function() { + // model failed to save + controller.set('saving', false); + alert(I18n.t('generic_error')); + }); + } + } + +}); + +/** + The route for editing a user's email + + @class PreferencesEmailRoute + @extends Discourse.RestrictedUserRoute + @namespace Discourse + @module Discourse +**/ +Discourse.PreferencesEmailRoute = Discourse.RestrictedUserRoute.extend({ + model: function() { + return this.modelFor('user'); + }, + + renderTemplate: function() { + this.render({ into: 'user', outlet: 'userOutlet' }); + }, + + setupController: function(controller, model) { + controller.setProperties({ model: model, newEmail: model.get('email') }); + }, + + // A bit odd, but if we leave to /preferences we need to re-render that outlet + exit: function() { + this._super(); + this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); + } +}); + +/** + The route for updating a user's username + + @class PreferencesUsernameRoute + @extends Discourse.RestrictedUserRoute + @namespace Discourse + @module Discourse +**/ +Discourse.PreferencesUsernameRoute = Discourse.RestrictedUserRoute.extend({ + model: function() { + return this.modelFor('user'); + }, + + renderTemplate: function() { + return this.render({ into: 'user', outlet: 'userOutlet' }); + }, + + // A bit odd, but if we leave to /preferences we need to re-render that outlet + exit: function() { + this._super(); + this.render('preferences', { into: 'user', outlet: 'userOutlet', controller: 'preferences' }); + }, + + setupController: function(controller, user) { + controller.setProperties({ model: user, newUsername: user.get('username') }); + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/discourse/routes/user_invited_route.js b/app/assets/javascripts/discourse/routes/user_invited_route.js deleted file mode 100644 index 53fd4e0f4c1..00000000000 --- a/app/assets/javascripts/discourse/routes/user_invited_route.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - This route shows who a user has invited - - @class UserInvitedRoute - @extends Discourse.Route - @namespace Discourse - @module Discourse -**/ -Discourse.UserInvitedRoute = Discourse.Route.extend({ - - renderTemplate: function() { - this.render({ into: 'user', outlet: 'userOutlet' }); - }, - - model: function() { - return Discourse.InviteList.findInvitedBy(this.modelFor('user')); - } - -}); - - diff --git a/app/assets/javascripts/discourse/routes/user_route.js b/app/assets/javascripts/discourse/routes/user_route.js deleted file mode 100644 index 52c4d048837..00000000000 --- a/app/assets/javascripts/discourse/routes/user_route.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - Handles routes related to users. - - @class UserRoute - @extends Discourse.Route - @namespace Discourse - @module Discourse -**/ -Discourse.UserRoute = Discourse.Route.extend({ - - model: function(params) { - - // If we're viewing the currently logged in user, return that object - // instead. - var currentUser = Discourse.User.current(); - if (currentUser && (params.username.toLowerCase() === currentUser.get('username_lower'))) { - return currentUser; - } - - return Discourse.User.create({username: params.username}); - }, - - afterModel: function() { - return this.modelFor('user').findDetails(); - }, - - serialize: function(params) { - if (!params) return {}; - return { username: Em.get(params, 'username').toLowerCase() }; - }, - - setupController: function(controller, user) { - controller.set('model', user); - - // Add a search context - this.controllerFor('search').set('searchContext', user.get('searchContext')); - }, - - activate: function() { - this._super(); - var user = this.modelFor('user'); - Discourse.MessageBus.subscribe("/users/" + user.get('username_lower'), function(data) { - user.loadUserAction(data); - }); - }, - - deactivate: function() { - this._super(); - Discourse.MessageBus.unsubscribe("/users/" + this.modelFor('user').get('username_lower')); - - // Remove the search context - this.controllerFor('search').set('searchContext', null); - } - - -}); diff --git a/app/assets/javascripts/discourse/routes/user_routes.js b/app/assets/javascripts/discourse/routes/user_routes.js new file mode 100644 index 00000000000..f3977032db1 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/user_routes.js @@ -0,0 +1,192 @@ +/** + Handles routes related to users. + + @class UserRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.UserRoute = Discourse.Route.extend({ + + model: function(params) { + + // If we're viewing the currently logged in user, return that object + // instead. + var currentUser = Discourse.User.current(); + if (currentUser && (params.username.toLowerCase() === currentUser.get('username_lower'))) { + return currentUser; + } + + return Discourse.User.create({username: params.username}); + }, + + afterModel: function() { + return this.modelFor('user').findDetails(); + }, + + serialize: function(params) { + if (!params) return {}; + return { username: Em.get(params, 'username').toLowerCase() }; + }, + + setupController: function(controller, user) { + controller.set('model', user); + + // Add a search context + this.controllerFor('search').set('searchContext', user.get('searchContext')); + }, + + activate: function() { + this._super(); + var user = this.modelFor('user'); + Discourse.MessageBus.subscribe("/users/" + user.get('username_lower'), function(data) { + user.loadUserAction(data); + }); + }, + + deactivate: function() { + this._super(); + Discourse.MessageBus.unsubscribe("/users/" + this.modelFor('user').get('username_lower')); + + // Remove the search context + this.controllerFor('search').set('searchContext', null); + } + +}); + +/** + This route shows who a user has invited + + @class UserInvitedRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.UserInvitedRoute = Discourse.Route.extend({ + renderTemplate: function() { + this.render({ into: 'user', outlet: 'userOutlet' }); + }, + + model: function() { + return Discourse.InviteList.findInvitedBy(this.modelFor('user')); + } +}); + + +/** + The base route for showing a user's activity + + @class UserActivityRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.UserActivityRoute = Discourse.Route.extend({ + renderTemplate: function() { + this.render('user_activity', {into: 'user', outlet: 'userOutlet' }); + }, + + model: function() { + return this.modelFor('user'); + }, + + setupController: function(controller, user) { + this.controllerFor('userActivity').set('model', user); + + var composerController = this.controllerFor('composer'); + controller.set('model', user); + if (Discourse.User.current()) { + Discourse.Draft.get('new_private_message').then(function(data) { + if (data.draft) { + composerController.open({ + draft: data.draft, + draftKey: 'new_private_message', + ignoreIfChanged: true, + draftSequence: data.draft_sequence + }); + } + }); + } + } +}); +Discourse.UserPrivateMessagesRoute = Discourse.UserActivityRoute.extend({}); + +/** + If we request /user/eviltrout without a sub route. + + @class UserIndexRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.UserIndexRoute = Discourse.UserActivityRoute.extend({ + redirect: function() { + this.transitionTo('userActivity', this.modelFor('user')); + } +}); + +/** + The base route for showing an activity stream. + + @class UserActivityStreamRoute + @extends Discourse.Route + @namespace Discourse + @module Discourse +**/ +Discourse.UserActivityStreamRoute = Discourse.Route.extend({ + model: function() { + return this.modelFor('user').findStream(this.get('userActionType')); + }, + + renderTemplate: function() { + this.render('user_stream', {into: 'user_activity', outlet: 'activity'}); + }, + + setupController: function(controller, model) { + controller.set('model', model); + this.controllerFor('user_activity').set('userActionType', this.get('userActionType')); + } +}); + +// Build all activity stream routes +['bookmarks', 'edits', 'likes_given', 'likes_received', 'replies', 'posts', 'index'].forEach(function (userAction) { + Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityStreamRoute.extend({ + userActionType: Discourse.UserAction.TYPES[userAction] + }); +}); + +Discourse.UserPrivateMessagesIndexRoute = Discourse.UserActivityStreamRoute.extend({ + userActionType: Discourse.UserAction.TYPES.messages_received +}); +Discourse.UserPrivateMessagesSentRoute = Discourse.UserActivityStreamRoute.extend({ + userActionType: Discourse.UserAction.TYPES.messages_sent +}); + +//Discourse.UserTopicsListView = Em.View.extend({ templateName: 'user/topics_list' }); +Discourse.UserTopicListRoute = Discourse.Route.extend({ + + renderTemplate: function() { + this.render('paginated_topic_list', {into: 'user_activity', outlet: 'activity'}); + }, + + setupController: function(controller, model) { + this.controllerFor('user_activity').set('userActionType', this.get('userActionType')); + controller.set('model', model); + } +}); + +Discourse.UserActivityTopicsRoute = Discourse.UserTopicListRoute.extend({ + userActionType: Discourse.UserAction.TYPES.topics, + + model: function() { + return Discourse.TopicList.find('topics/created-by/' + this.modelFor('user').get('username_lower')); + } +}); + +Discourse.UserActivityFavoritesRoute = Discourse.UserTopicListRoute.extend({ + userActionType: Discourse.UserAction.TYPES.favorites, + + model: function() { + return Discourse.TopicList.find('favorited'); + } +}); diff --git a/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars b/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars index b0d5e339670..0b1d9a70f09 100644 --- a/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars +++ b/app/assets/javascripts/discourse/templates/embedded_post.js.handlebars @@ -1,20 +1,18 @@ -{{#with view.content}} -
-