From 0552cae1ab821d4426a4a42a4a9775650912cf8c Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Tue, 3 Feb 2015 17:02:46 +1030 Subject: [PATCH] Add alert messages --- ember/app/components/alert-message.js | 45 ++++++++++++-- ember/app/controllers/application.js | 11 ++++ ember/app/controllers/discussion.js | 60 ++++++++++++++----- ember/app/styles/app.less | 1 + ember/app/styles/flarum/alerts.less | 57 ++++++++++++++++++ ember/app/styles/flarum/components.less | 6 ++ ember/app/styles/flarum/login.less | 32 ---------- ember/app/templates/application.hbs | 4 +- .../templates/components/alert-message.hbs | 11 +--- 9 files changed, 166 insertions(+), 61 deletions(-) create mode 100644 ember/app/styles/flarum/alerts.less delete mode 100644 ember/app/styles/flarum/login.less diff --git a/ember/app/components/alert-message.js b/ember/app/components/alert-message.js index b9fd2042e..7da7232db 100755 --- a/ember/app/components/alert-message.js +++ b/ember/app/components/alert-message.js @@ -1,9 +1,44 @@ import Ember from 'ember'; -export default Ember.Component.extend({ - - close: function() { - this.sendAction('closeAction'); - } +import TaggedArray from '../utils/tagged-array'; +import ActionButton from 'flarum/components/ui/controls/action-button'; +export default Ember.Component.extend(Ember.Evented, { + message: '', + type: '', + dismissable: true, + + layoutName: 'components/alert-message', + classNames: ['alert'], + classNameBindings: ['classForType'], + + classForType: function() { + return 'alert-'+this.get('type'); + }.property('type'), + + didInsertElement: function() { + var controls = TaggedArray.create(); + this.trigger('populateControls', controls); + this.set('controls', controls); + }, + + populateControls: function(controls) { + if (this.get('dismissable')) { + var component = this; + var dismiss = ActionButton.create({ + icon: 'times', + className: 'btn btn-icon btn-link', + action: function() { + component.send('dismiss'); + } + }); + controls.pushObjectWithTag(dismiss, 'dismiss'); + } + }, + + actions: { + dismiss: function() { + this.sendAction('dismiss', this); + } + } }); diff --git a/ember/app/controllers/application.js b/ember/app/controllers/application.js index 087a33aaf..ed8209808 100644 --- a/ember/app/controllers/application.js +++ b/ember/app/controllers/application.js @@ -27,9 +27,20 @@ export default Ember.Controller.extend({ searchQuery: '', searchActive: false, + alerts: [], + actions: { search: function(query) { this.transitionToRoute('index', {queryParams: {searchQuery: query, sort: query ? 'relevance' : 'recent'}}); + }, + alert: function(message) { + this.get('alerts').pushObject(message); + }, + dismissAlert: function(message) { + this.get('alerts').removeObject(message); + }, + clearAlerts: function() { + this.get('alerts').clear(); } } }); diff --git a/ember/app/controllers/discussion.js b/ember/app/controllers/discussion.js index ee35f0939..b6f4be3a6 100644 --- a/ember/app/controllers/discussion.js +++ b/ember/app/controllers/discussion.js @@ -3,6 +3,7 @@ import Ember from 'ember'; import PostStream from '../models/post-stream'; import ComposerReply from '../components/discussions/composer-reply'; import ActionButton from '../components/ui/controls/action-button'; +import AlertMessage from '../components/alert-message'; export default Ember.ObjectController.extend(Ember.Evented, { @@ -40,35 +41,62 @@ export default Ember.ObjectController.extend(Ember.Evented, { }); }, + // Save a reply. This may be called by a composer-reply component that was + // set up on a different discussion, so we require a discussion model to + // be explicitly passed rather than using the controller's implicit one. saveReply: function(discussion, content) { var controller = this; var composer = this.get('controllers.composer'); var stream = this.get('stream'); composer.set('content.loading', true); + controller.get('controllers.application').send('clearAlerts'); var post = this.store.createRecord('post', { content: content, discussion: discussion }); - var promise = post.save().then(function(post) { - if (discussion == controller.get('model')) { - discussion.set('posts', discussion.get('posts')+','+post.get('id')); - stream.set('ids', controller.get('model.postIds')); - stream.addPostToEnd(post); - } + return post.save().then(function(post) { composer.send('hide'); - }, function(reason) { - var error = reason.errors[0].detail; - alert(error); - }); - promise.finally(function() { + // If we're currently viewing the discussion which this reply was + // made in, then we can add the post to the end of the post + // stream. + discussion.set('posts', discussion.get('posts')+','+post.get('id')); + if (discussion == controller.get('model')) { + stream.set('ids', discussion.get('postIds')); + stream.addPostToEnd(post); + } else { + // Otherwise, we'll create an alert message to inform the user + // that their reply has been posted, containing a button which + // will transition to their new post when clicked. + var message = AlertMessage.create({ + type: 'success', + message: 'Your reply was posted.' + }); + message.on('populateControls', function(controls) { + controls.pushObjectWithTag(ActionButton.extend({ + label: 'View', + action: function() { + controller.transitionToRoute('discussion', post.get('discussion'), {queryParams: {start: post.get('number')}}); + message.send('dismiss'); + } + }), 'view'); + }); + controller.get('controllers.application').send('alert', message); + } + }, + function(reason) { + var message = AlertMessage.create({ + type: 'warning', + message: reason.errors[0].detail + }); + controller.get('controllers.application').send('alert', message); + }) + .finally(function() { composer.set('content.loading', false); }); - - return promise; }, actions: { @@ -76,15 +104,19 @@ export default Ember.ObjectController.extend(Ember.Evented, { var controller = this; var discussion = this.get('model'); var composer = this.get('controllers.composer'); + + // If the composer is already set up for this discussion, then we + // don't need to change its content - we can just show it. if (composer.get('content.discussion') != discussion) { composer.switchContent(ComposerReply.create({ user: controller.get('session.user'), discussion: discussion, submit: function(value) { - controller.saveReply(this.get('discussion'), value); + controller.saveReply(discussion, value); } })); } + composer.send('show'); }, diff --git a/ember/app/styles/app.less b/ember/app/styles/app.less index 1f472f609..6d8d88787 100644 --- a/ember/app/styles/app.less +++ b/ember/app/styles/app.less @@ -18,6 +18,7 @@ // Finally, with our vendor CSS loaded, we can import Flarum-specific stuff. @import "@{flarum-base}components.less"; +@import "@{flarum-base}alerts.less"; @import "@{flarum-base}modals.less"; @import "@{flarum-base}layout.less"; @import "@{flarum-base}composer.less"; diff --git a/ember/app/styles/flarum/alerts.less b/ember/app/styles/flarum/alerts.less new file mode 100644 index 000000000..16b05c6fd --- /dev/null +++ b/ember/app/styles/flarum/alerts.less @@ -0,0 +1,57 @@ +.alerts { + position: fixed; + bottom: 20px; + left: 20px; + + & .alert { + display: inline-block; + .box-shadow(0 2px 6px rgba(0, 0, 0, 0.3)); + margin-top: 20px; + } +} +.alert { + padding: 12px 16px; + border-radius: @border-radius-base; + background: #FFF2AE; + &, & a, & a:hover { + color: #AD6C00; + } +} +.alert-warning { + background: #D83E3E; + &, & a, & a:hover { + color: #fff; + } +} +.alert-controls { + list-style-type: none; + padding: 0; + margin: 0 -8px 0 8px; + display: inline-block; + + & li { + display: inline-block; + margin: 0 5px; + } + & a { + text-transform: uppercase; + font-size: 12px; + font-weight: bold; + } + & .btn { + margin: -10px; + } +} +.form-group { // probably move this elsewhere + position: relative; +} +.form-alert { + position: absolute; + bottom: 100%; + left: 0; + right: 0; + margin-bottom: 12px; + & .alert { + display: inline-block; + } +} diff --git a/ember/app/styles/flarum/components.less b/ember/app/styles/flarum/components.less index 636611791..e42af637a 100644 --- a/ember/app/styles/flarum/components.less +++ b/ember/app/styles/flarum/components.less @@ -31,6 +31,12 @@ display: none; } } +.btn-user { + & .avatar { + margin: -2px 5px -2px -5px; + .avatar-size(24px); + } +} // Redefine Bootstrap's mixin to make some general changes .button-variant(@color; @background; @border) { diff --git a/ember/app/styles/flarum/login.less b/ember/app/styles/flarum/login.less deleted file mode 100644 index 1be6cf121..000000000 --- a/ember/app/styles/flarum/login.less +++ /dev/null @@ -1,32 +0,0 @@ -.modal-login { - & .form-group { - margin-bottom: 12px; - } -} -.form-group { - position: relative; -} -.form-alert { - position: absolute; - bottom: 100%; - left: 0; - right: 0; - margin-bottom: 12px; - & .alert { - display: inline-block; - } -} -.alert-warning { - background: #D83E3E; - .box-shadow(0 2px 6px rgba(0, 0, 0, 0.3)); - color: #fff; - padding: 12px 16px; - border-radius: @border-radius-base; -} - -.btn-user { - & .avatar { - margin: -2px 5px -2px -5px; - .avatar-size(24px); - } -} \ No newline at end of file diff --git a/ember/app/templates/application.hbs b/ember/app/templates/application.hbs index 597c9f483..42e35ff08 100644 --- a/ember/app/templates/application.hbs +++ b/ember/app/templates/application.hbs @@ -51,6 +51,8 @@
{{#each alert in alerts}} - {{alert-message message=alert}} +
+ {{view alert dismiss="dismissAlert"}} +
{{/each}}
\ No newline at end of file diff --git a/ember/app/templates/components/alert-message.hbs b/ember/app/templates/components/alert-message.hbs index 6e0fdeb4b..d9ca9ed89 100644 --- a/ember/app/templates/components/alert-message.hbs +++ b/ember/app/templates/components/alert-message.hbs @@ -1,9 +1,2 @@ -
- {{alert.text}} - - Undo - {{#if alert.dismissable}} - {{fa-icon "times"}} - {{/if}} - -
+{{message}} +{{ui/controls/item-list items=controls class="alert-controls"}} \ No newline at end of file