diff --git a/app/assets/javascripts/discourse/components/notification-item.js.es6 b/app/assets/javascripts/discourse/components/notification-item.js.es6 index 4942a90ca66..0b4e3695e5f 100644 --- a/app/assets/javascripts/discourse/components/notification-item.js.es6 +++ b/app/assets/javascripts/discourse/components/notification-item.js.es6 @@ -1,22 +1,55 @@ +const INVITED_TYPE = 8; + export default Ember.Component.extend({ tagName: 'li', classNameBindings: ['notification.read', 'notification.is_warning'], + scope: function() { + return "notifications." + this.site.get("notificationLookup")[this.get("notification.notification_type")]; + }.property("notification.notification_type"), + + url: function() { + const it = this.get('notification'); + const badgeId = it.get("data.badge_id"); + if (badgeId) { + const badgeName = it.get("data.badge_name"); + return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase()); + } + + const topicId = it.get('topic_id'); + if (topicId) { + return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number")); + } + + if (it.get('notification_type') === INVITED_TYPE) { + return Discourse.getURL('/my/invited'); + } + }.property("notification.data.{badge_id,badge_name}", "model.slug", "model.topic_id", "model.post_number"), + + description: function() { + const badgeName = this.get("notification.data.badge_name"); + if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); } + + const title = this.get('notification.data.topic_title'); + return Ember.isEmpty(title) ? "" : Handlebars.Utils.escapeExpression(title); + }.property("notification.data.{badge_name,topic_title}"), + _markRead: function(){ - var self = this; - this.$('a').click(function(){ - self.set('notification.read', true); + this.$('a').click(() => { + this.set('notification.read', true); return true; }); }.on('didInsertElement'), - render: function(buffer) { - var notification = this.get('notification'), - text = I18n.t(this.get('scope'), Em.getProperties(notification, 'description', 'username')); + render(buffer) { + const notification = this.get('notification'); + const description = this.get('description'); + const username = notification.get('data.display_username'); + const text = I18n.t(this.get('scope'), {description, username}); - var url = notification.get('url'); + const url = this.get('url'); if (url) { - buffer.push('' + text + ''); + buffer.push('' + text + ''); } else { buffer.push(text); } diff --git a/app/assets/javascripts/discourse/controllers/header.js.es6 b/app/assets/javascripts/discourse/controllers/header.js.es6 index c0c4cb17dd5..c772114448a 100644 --- a/app/assets/javascripts/discourse/controllers/header.js.es6 +++ b/app/assets/javascripts/discourse/controllers/header.js.es6 @@ -41,10 +41,11 @@ const HeaderController = DiscourseController.extend({ if (self.get("loadingNotifications")) { return; } self.set("loadingNotifications", true); - Discourse.NotificationContainer.loadRecent().then(function(result) { + + this.store.find('notification', {recent: true}).then(function(notifications) { self.setProperties({ 'currentUser.unread_notifications': 0, - notifications: result + notifications }); }).catch(function() { self.setProperties({ diff --git a/app/assets/javascripts/discourse/controllers/notification.js.es6 b/app/assets/javascripts/discourse/controllers/notification.js.es6 deleted file mode 100644 index e13377d69e6..00000000000 --- a/app/assets/javascripts/discourse/controllers/notification.js.es6 +++ /dev/null @@ -1,40 +0,0 @@ -import ObjectController from 'discourse/controllers/object'; - -const INVITED_TYPE = 8; - -export default ObjectController.extend({ - - notificationUrl: function(it) { - var badgeId = it.get("data.badge_id"); - if (badgeId) { - var badgeName = it.get("data.badge_name"); - return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase()); - } - - var topicId = it.get('topic_id'); - if (topicId) { - return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number")); - } - - if (it.get('notification_type') === INVITED_TYPE) { - return Discourse.getURL('/my/invited'); - } - }, - - scope: function() { - return "notifications." + this.site.get("notificationLookup")[this.get("notification_type")]; - }.property("notification_type"), - - username: Em.computed.alias("data.display_username"), - - url: function() { - return this.notificationUrl(this); - }.property("data.{badge_id,badge_name}", "slug", "topic_id", "post_number"), - - description: function() { - const badgeName = this.get("data.badge_name"); - if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); } - return this.blank("data.topic_title") ? "" : Handlebars.Utils.escapeExpression(this.get("data.topic_title")); - }.property("data.{badge_name,topic_title}") - -}); diff --git a/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 b/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 index 3943daa8688..85865c16e50 100644 --- a/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 @@ -1,43 +1,21 @@ - export default Ember.ArrayController.extend({ - needs: ['user-notifications', 'application'], - loading: false, + needs: ['application'], _showFooter: function() { - this.set("controllers.application.showFooter", !this.get("canLoadMore")); - }.observes("canLoadMore"), + this.set("controllers.application.showFooter", !this.get("model.canLoadMore")); + }.observes("model.canLoadMore"), - showDismissButton: function() { - return this.get('user').total_unread_notifications > 0; - }.property('user'), + showDismissButton: Ember.computed.gt('user.total_unread_notifications', 0), actions: { resetNew: function() { - var self = this; - Discourse.NotificationContainer.resetNew().then(function() { - self.get('controllers.user-notifications').setEach('read', true); + Discourse.ajax('/notifications/mark-read', { method: 'PUT' }).then(() => { + this.setEach('read', true); }); }, loadMore: function() { - if (this.get('canLoadMore') && !this.get('loading')) { - this.set('loading', true); - var self = this; - Discourse.NotificationContainer.loadHistory( - self.get('model.lastObject.created_at'), - self.get('user.username')).then(function(result) { - self.set('loading', false); - var notifications = result.get('content'); - self.pushObjects(notifications); - // Stop trying if it's the end - if (notifications && (notifications.length === 0 || notifications.length < 60)) { - self.set('canLoadMore', false); - } - }).catch(function(error) { - self.set('loading', false); - Em.Logger.error(error); - }); - } + this.get('model').loadMore(); } } }); diff --git a/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 b/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 index 66592eb59d7..2a3eded1dd8 100644 --- a/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 +++ b/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 @@ -38,13 +38,13 @@ export default { app.register('session:main', Session.current(), { instantiate: false }); injectAll(app, 'session'); + app.register('store:main', Store); + inject(app, 'store', 'route', 'controller'); + app.register('current-user:main', Discourse.User.current(), { instantiate: false }); inject(app, 'currentUser', 'component', 'route', 'controller'); app.register('message-bus:main', window.MessageBus, { instantiate: false }); inject(app, 'messageBus', 'route', 'controller', 'view'); - - app.register('store:main', Store); - inject(app, 'store', 'route', 'controller'); } }; diff --git a/app/assets/javascripts/discourse/mixins/load-more.js.es6 b/app/assets/javascripts/discourse/mixins/load-more.js.es6 index 136c5aeca41..0726b13bd76 100644 --- a/app/assets/javascripts/discourse/mixins/load-more.js.es6 +++ b/app/assets/javascripts/discourse/mixins/load-more.js.es6 @@ -1,22 +1,15 @@ -/** - Provides the ability to load more items for a view which is scrolled to the bottom. -**/ - +// Provides the ability to load more items for a view which is scrolled to the bottom. export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrolling, { scrolled: function() { - var eyeline = this.get('eyeline'); + const eyeline = this.get('eyeline'); if (eyeline) { eyeline.update(); } }, _bindEyeline: function() { - var eyeline = new Discourse.Eyeline(this.get('eyelineSelector') + ":last"); + const eyeline = new Discourse.Eyeline(this.get('eyelineSelector') + ":last"); this.set('eyeline', eyeline); - - var self = this; - eyeline.on('sawBottom', function() { - self.send('loadMore'); - }); + eyeline.on('sawBottom', () => this.send('loadMore')); this.bindScrolling(); }.on('didInsertElement'), diff --git a/app/assets/javascripts/discourse/models/notification.js b/app/assets/javascripts/discourse/models/notification.js deleted file mode 100644 index 469a1f2db04..00000000000 --- a/app/assets/javascripts/discourse/models/notification.js +++ /dev/null @@ -1,54 +0,0 @@ -Discourse.NotificationContainer = Ember.ArrayProxy.extend({ - -}); - -Discourse.NotificationContainer.reopenClass({ - - createFromJson: function(json_array) { - return Discourse.NotificationContainer.create({content: json_array}); - }, - - createFromError: function(error) { - return Discourse.NotificationContainer.create({ - content: [], - error: true, - forbidden: error.status === 403 - }); - }, - - loadRecent: function() { - // TODO - add .json (breaks tests atm) - return Discourse.ajax('/notifications').then(function(result) { - return Discourse.NotificationContainer.createFromJson(result); - }).catch(function(error) { - // TODO HeaderController can't handle a createFromError - // just throw for now - throw error; - }); - }, - - loadHistory: function(beforeDate, username) { - var url = '/notifications/history.json', - params = [ - beforeDate ? ('before=' + beforeDate) : null, - username ? ('user=' + username) : null - ]; - - // Remove nulls - params = params.filter(function(param) { return !!param; }); - // Build URL - params.forEach(function(param, idx) { - url = url + (idx === 0 ? '?' : '&') + param; - }); - - return Discourse.ajax(url).then(function(result) { - return Discourse.NotificationContainer.createFromJson(result); - }).catch(function(error) { - return Discourse.NotificationContainer.createFromError(error); - }); - }, - - resetNew: function() { - return Discourse.ajax("/notifications/reset-new", {type: 'PUT'}); - } -}); diff --git a/app/assets/javascripts/discourse/models/result-set.js.es6 b/app/assets/javascripts/discourse/models/result-set.js.es6 index cda174b609d..754fdadd200 100644 --- a/app/assets/javascripts/discourse/models/result-set.js.es6 +++ b/app/assets/javascripts/discourse/models/result-set.js.es6 @@ -4,6 +4,10 @@ export default Ember.ArrayProxy.extend({ totalRows: 0, refreshing: false, + canLoadMore: function() { + return this.get('length') < this.get('totalRows'); + }.property('totalRows', 'length'), + loadMore() { const loadMoreUrl = this.get('loadMoreUrl'); if (!loadMoreUrl) { return; } diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 4fc9d1a8f5f..d03ca5b000e 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -434,16 +434,13 @@ User.reopenClass(Discourse.Singleton, { return user.findDetails(options); }, - /** - The current singleton will retrieve its attributes from the `PreloadStore` - if it exists. Otherwise, no instance is created. - - @method createCurrent - @returns {Discourse.User} the user, if logged in. - **/ + // TODO: Use app.register and junk Discourse.Singleton createCurrent: function() { var userJson = PreloadStore.get('currentUser'); - if (userJson) { return Discourse.User.create(userJson); } + if (userJson) { + const store = Discourse.__container__.lookup('store:main'); + return store.createRecord('user', userJson); + } return null; }, diff --git a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications.js.es6 index d5d942417f9..a90c131af24 100644 --- a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-notifications.js.es6 @@ -1,31 +1,22 @@ import ShowFooter from "discourse/mixins/show-footer"; +import ViewingActionType from "discourse/mixins/viewing-action-type"; -export default Discourse.Route.extend(ShowFooter, { +export default Discourse.Route.extend(ShowFooter, ViewingActionType, { actions: { - didTransition: function() { - this.controllerFor("user_notifications")._showFooter(); + didTransition() { + this.controllerFor("user-notifications")._showFooter(); return true; } }, - model: function() { + model() { var user = this.modelFor('user'); - return Discourse.NotificationContainer.loadHistory(undefined, user.get('username')); + return this.store.find('notification', {username: user.get('username')}); }, - setupController: function(controller, model) { + setupController(controller, model) { controller.set('model', model); controller.set('user', this.modelFor('user')); - - if (this.controllerFor('user_activity').get('content')) { - this.controllerFor('user_activity').set('userActionType', -1); - } - - // properly initialize "canLoadMore" - controller.set("canLoadMore", model.get("length") === 60); - }, - - renderTemplate: function() { - this.render('user-notification-history', {into: 'user'}); + this.viewingActionType(-1); } }); diff --git a/app/assets/javascripts/discourse/templates/notifications.hbs b/app/assets/javascripts/discourse/templates/notifications.hbs index 83681a72d20..8e646bf6b8f 100644 --- a/app/assets/javascripts/discourse/templates/notifications.hbs +++ b/app/assets/javascripts/discourse/templates/notifications.hbs @@ -2,8 +2,8 @@ {{#conditional-loading-spinner condition=loadingNotifications}} {{#if content}}