Просмотр исходного кода

Refactored flash-message into toast service.

* added helper for reading toast message in test
Rafał Pitoń 10 лет назад
Родитель
Сommit
0bc1acddfd

+ 0 - 56
misago/emberapp/app/controllers/flash-message.js

@@ -1,56 +0,0 @@
-import Ember from 'ember';
-import ENV from '../config/environment';
-
-var HIDE_ANIMATION_LENGTH = 200;
-
-export default Ember.Controller.extend({
-  id: null,
-  type: null,
-  message: null,
-  isVisible: false,
-
-  isInfo: function() {
-    return this.get('type') === 'info';
-  }.property('type'),
-
-  isSuccess: function() {
-    return this.get('type') === 'success';
-  }.property('type'),
-
-  isWarning: function() {
-    return this.get('type') === 'warning';
-  }.property('type'),
-
-  isError: function() {
-    return this.get('type') === 'error';
-  }.property('type'),
-
-  showFlash: function(type, message) {
-    var flashId = this.incrementProperty('id');
-    this.set('type', type);
-    this.set('message', message);
-    this.set('isVisible', true);
-
-    var self = this;
-    Ember.run.later(function () {
-      if (self.get('id') === flashId) {
-        self.set('isVisible', false);
-      }
-    }, ENV.APP.FLASH_MIN_DISPLAY_TIME);
-  },
-
-  actions: {
-    setFlash: function(type, message) {
-      var self = this;
-
-      if (this.get('isVisible')) {
-        this.set('isVisible', false);
-        Ember.run.later(function () {
-          self.showFlash(type, message);
-        }, HIDE_ANIMATION_LENGTH);
-      } else {
-        this.showFlash(type, message);
-      }
-    }
-  }
-});

+ 4 - 4
misago/emberapp/app/controllers/forgotten-password/change-form.js

@@ -14,7 +14,7 @@ export default Ember.ObjectController.extend({
       var password = Ember.$.trim(this.get('password'));
 
       if (password === "") {
-        this.send('flashWarning', gettext("Enter new password."));
+        this.get('toast').warning(gettext("Enter new password."));
         return;
       }
 
@@ -27,17 +27,17 @@ export default Ember.ObjectController.extend({
         self.set('password', '');
 
         self.send('openLoginModal');
-        self.send('flashSuccess', gettext("Your password has been changed."));
+        self.get('toast').success(gettext("Your password has been changed."));
 
       }, function(jqXHR) {
         var rejection = jqXHR.responseJSON;
         if (jqXHR.status === 400){
-          self.send('flashError', rejection.detail);
+          self.get('toast').error(rejection.detail);
         } else {
           self.set('password', '');
 
           if (jqXHR.status === 404) {
-            self.send('flashError', rejection.detail);
+            self.get('toast').error(rejection.detail);
             self.transitionTo('forgotten-password');
           } else {
             self.send("error", jqXHR);

+ 2 - 2
misago/emberapp/app/controllers/forgotten-password/request-link.js

@@ -14,7 +14,7 @@ export default Ember.ObjectController.extend({
       var email = Ember.$.trim(this.get('email'));
 
       if (email === "") {
-        this.send('flashWarning', gettext("Enter e-mail address."));
+        this.get('toast').warning(gettext("Enter e-mail address."));
         return;
       }
 
@@ -34,7 +34,7 @@ export default Ember.ObjectController.extend({
             self.send('showBan', rejection.detail);
             self.set('email', '');
           } else {
-            self.send('flashError', rejection.detail);
+            self.get('toast').error(rejection.detail);
           }
         } else {
           self.send("error", jqXHR);

+ 4 - 4
misago/emberapp/app/controllers/index.js

@@ -3,19 +3,19 @@ import Ember from 'ember';
 export default Ember.Controller.extend({
   actions: {
     testInfo: function() {
-      this.send('flashInfo', this.get('newFlash'));
+      this.get('toast').info(this.get('newFlash'));
     },
 
     testSuccess: function() {
-      this.send('flashSuccess', this.get('newFlash'));
+      this.get('toast').success(this.get('newFlash'));
     },
 
     testWarning: function() {
-      this.send('flashWarning', this.get('newFlash'));
+      this.get('toast').warning(this.get('newFlash'));
     },
 
     testError: function() {
-      this.send('flashError', this.get('newFlash'));
+      this.get('toast').error(this.get('newFlash'));
     }
   }
 });

+ 4 - 4
misago/emberapp/app/controllers/login-modal.js

@@ -52,7 +52,7 @@ export default Ember.Controller.extend({
       };
 
       if (!credentials.username || !credentials.password) {
-        this.send('flashWarning', gettext("Fill out both fields."));
+        this.get('toast').warning(gettext("Fill out both fields."));
         return;
       }
 
@@ -78,9 +78,9 @@ export default Ember.Controller.extend({
           self.send("error", rejection);
         } else {
           if (rejection.code === 'inactive_admin') {
-            self.send('flashInfo', rejection.detail);
+            self.get('toast').info(rejection.detail);
           } else if (rejection.code === 'inactive_user') {
-            self.send('flashInfo', rejection.detail);
+            self.get('toast').info(rejection.detail);
             self.set('showActivation', true);
           } else if (rejection.code === 'banned') {
             self.send('showBan', rejection.detail);
@@ -88,7 +88,7 @@ export default Ember.Controller.extend({
               Ember.$('#loginModal').modal('hide');
             });
           } else {
-            self.send('flashError', rejection.detail);
+            self.get('toast').error(rejection.detail);
           }
         }
 

+ 14 - 0
misago/emberapp/app/initializers/toast-message-service.js

@@ -0,0 +1,14 @@
+import ToastMessageService from 'misago/services/toast-message';
+
+export function initialize(_container, application) {
+  application.register('service:toast-message', ToastMessageService, { singleton: true });
+
+  [ 'route', 'controller', 'component' ].forEach((factory) => {
+    application.inject(factory, 'toast', 'service:toast-message');
+  });
+}
+
+export default {
+  name: 'toast-message-service',
+  initialize: initialize
+};

+ 0 - 22
misago/emberapp/app/routes/application.js

@@ -62,28 +62,6 @@ export default Ember.Route.extend({
       return false;
     },
 
-    // Flashes
-
-    flashInfo: function(message) {
-      this.controllerFor("flashMessage").send('setFlash', 'info', message);
-      return false;
-    },
-
-    flashSuccess: function(message) {
-      this.controllerFor("flashMessage").send('setFlash', 'success', message);
-      return false;
-    },
-
-    flashWarning: function(message) {
-      this.controllerFor("flashMessage").send('setFlash', 'warning', message);
-      return false;
-    },
-
-    flashError: function(message) {
-      this.controllerFor("flashMessage").send('setFlash', 'error', message);
-      return false;
-    },
-
     // Auth
 
     openLoginModal: function() {

+ 1 - 1
misago/emberapp/app/routes/forgotten-password/change-form.js

@@ -15,7 +15,7 @@ export default Ember.Route.extend(ResetScroll, {
 
     error: function(reason) {
       if (reason.status === 404) {
-        this.send('flashError', reason.responseJSON.detail);
+        this.get('toast').error(reason.responseJSON.detail);
         return this.transitionTo('forgotten-password');
       }
 

+ 1 - 1
misago/emberapp/app/services/auth.js

@@ -1,6 +1,6 @@
 import Ember from 'ember';
 
-export default Ember.Object.extend({
+export default Ember.Service.extend({
   isAnonymous: function() {
     return !this.get('isAuthenticated');
   }.property('isAuthenticated'),

+ 3 - 1
misago/emberapp/app/services/clock.js

@@ -1,7 +1,9 @@
 import Ember from 'ember';
 import ENV from '../config/environment';
 
-export default Ember.Object.extend({
+export default Ember.Service.extend({
+  availableIn: ['controllers'],
+
   tick: Ember.computed.oneWay('_tick').readOnly(),
 
   doTick: function () {

+ 61 - 0
misago/emberapp/app/services/toast-message.js

@@ -0,0 +1,61 @@
+import Ember from 'ember';
+import ENV from '../config/environment';
+
+var HIDE_ANIMATION_LENGTH = 200;
+
+export default Ember.Service.extend({
+  id: null,
+  type: null,
+  message: null,
+  isVisible: false,
+
+  isInfo: Ember.computed.equal('type', 'info'),
+  isSuccess: Ember.computed.equal('type', 'success'),
+  isWarning: Ember.computed.equal('type', 'warning'),
+  isError: Ember.computed.equal('type', 'error'),
+
+  _showToast: function(type, message) {
+    var toastId = this.incrementProperty('id');
+    this.set('type', type);
+    this.set('message', message);
+    this.set('isVisible', true);
+
+    var self = this;
+    Ember.run.later(function () {
+      if (self.get('id') === toastId) {
+        self.set('isVisible', false);
+      }
+    }, ENV.APP.TOAST_BASE_DISPLAY_TIME + (message.length * 110));
+  },
+
+  _setToast: function(type, message) {
+    var self = this;
+
+    if (this.get('isVisible')) {
+      this.set('isVisible', false);
+      Ember.run.later(function () {
+        self._showToast(type, message);
+      }, HIDE_ANIMATION_LENGTH);
+    } else {
+      this._showToast(type, message);
+    }
+  },
+
+  // Public api
+
+  info: function(message) {
+    this._setToast('info', message);
+  },
+
+  success: function(message) {
+    this._setToast('success', message);
+  },
+
+  warning: function(message) {
+    this._setToast('warning', message);
+  },
+
+  error: function(message) {
+    this._setToast('error', message);
+  }
+});

+ 1 - 1
misago/emberapp/app/styles/misago/misago.less

@@ -1,6 +1,6 @@
 // Components
 @import "buttons.less";
-@import "flash-message.less";
+@import "toast-message.less";
 @import "footer.less";
 @import "form-panel.less";
 @import "inputs.less";

+ 7 - 7
misago/emberapp/app/styles/misago/flash-message.less → misago/emberapp/app/styles/misago/toast-message.less

@@ -1,9 +1,9 @@
 //
-// Flash Message
+// Toast Message
 // --------------------------------------------------
 
 
-.flash-message-style(@color-bg, @color-border, @color-text) {
+.toast-message-style(@color-bg, @color-border, @color-text) {
   background: @color-bg;
   border: 1px solid @color-border;
   border-top: none;
@@ -18,7 +18,7 @@
 }
 
 
-.flash-message {
+.toast-message {
   position: fixed;
   top: -100%;
   width: 100%;
@@ -35,19 +35,19 @@
   }
 
   .message-success {
-    .flash-message-style(@alert-success-bg, @alert-success-border, @alert-success-text);
+    .toast-message-style(@alert-success-bg, @alert-success-border, @alert-success-text);
   }
 
   .message-info {
-    .flash-message-style(@alert-info-bg, @alert-info-border, @alert-info-text);
+    .toast-message-style(@alert-info-bg, @alert-info-border, @alert-info-text);
   }
 
   .message-warning {
-    .flash-message-style(@alert-warning-bg, @alert-warning-border, @alert-warning-text);
+    .toast-message-style(@alert-warning-bg, @alert-warning-border, @alert-warning-text);
   }
 
   .message-danger {
-    .flash-message-style(@alert-danger-bg, @alert-danger-border, @alert-danger-text);
+    .toast-message-style(@alert-danger-bg, @alert-danger-border, @alert-danger-text);
   }
 
   /* Small devices (tablets, 768px and up) */

+ 4 - 4
misago/emberapp/app/styles/misago/variables.less

@@ -14,10 +14,10 @@
 @gray-light:             lighten(@gray-base, 46.7%); // #777
 @gray-lighter:           lighten(@gray-base, 93.5%); // #eee
 
-@brand-info:             #f44336; // misago uses info state for accents
+@brand-info:             #ff5722; // misago uses info state for accents
 
 @brand-primary:          #29b6f6;
-@brand-success:          #66bb6a;
+@brand-success:          #2ecc71;
 @brand-warning:          #ffab40;
 @brand-danger:           #ef5350;
 
@@ -137,8 +137,8 @@
 
 @alert-border-radius:         @border-radius-large;
 
-@alert-success-bg:            #66bb6a;
-@alert-success-border:        #66bb6a;
+@alert-success-bg:            #2ecc71;
+@alert-success-border:        #2ecc71;
 @alert-success-text:          #fff;
 
 @alert-info-bg:               #42a5f5;

+ 1 - 1
misago/emberapp/app/templates/application.hbs

@@ -1,5 +1,5 @@
 {{render "navbar"}}
-{{render "flash-message"}}
+{{render "toast-message"}}
 
 <div class="main-outlet">
   {{outlet}}

+ 0 - 6
misago/emberapp/app/templates/flash-message.hbs

@@ -1,6 +0,0 @@
-<div {{bind-attr class=":flash-message isVisible:visible"}}>
-  <p {{bind-attr class="isInfo:message-info isSuccess:message-success isWarning:message-warning isError:message-danger"}}>
-    <span {{bind-attr class=":fa :fa-lg isInfo:fa-info isSuccess:fa-check isWarning:fa-exclamation isError:fa-times"}}></span>
-    {{message}}
-  </p>
-</div>

+ 5 - 0
misago/emberapp/app/templates/toast-message.hbs

@@ -0,0 +1,5 @@
+<div {{bind-attr class=":toast-message toast.isVisible:visible"}}>
+  <p {{bind-attr class="toast.isInfo:message-info toast.isSuccess:message-success toast.isWarning:message-warning toast.isError:message-danger"}}>
+    {{toast.message}}
+  </p>
+</div>

+ 6 - 3
misago/emberapp/config/environment.js

@@ -26,8 +26,9 @@ module.exports = function(environment) {
       // Misago ticks frequency (in ms, used for refreshing timestamps)
       TICK_FREQUENCY: 15000,
 
-      // Min time flash is displayed for (in ms)
-      FLASH_MIN_DISPLAY_TIME: 4500
+      // Base time toast is displayed for (in ms)
+      // This time is increased by message length
+      TOAST_BASE_DISPLAY_TIME: 4000
     }
   };
 
@@ -61,7 +62,9 @@ module.exports = function(environment) {
     ENV.APP.LOG_VIEW_LOOKUPS = false;
 
     ENV.APP.rootElement = '#ember-testing';
-    ENV.APP.FLASH_MIN_DISPLAY_TIME = 500;
+
+    // Reduce base toast display time for test runner
+    ENV.APP.TOAST_BASE_DISPLAY_TIME = 500;
   }
 
   if (environment === 'production') {

+ 10 - 27
misago/emberapp/tests/acceptance/forgotten-password-test.js

@@ -1,6 +1,7 @@
 import Ember from 'ember';
 import { module, test } from 'qunit';
 import startApp from '../helpers/start-app';
+import getToastMessage from '../helpers/toast-message';
 
 var application;
 
@@ -32,9 +33,7 @@ test('request password change link without entering e-mail', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.index');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, 'Enter e-mail address.');
+    assert.equal(getToastMessage(), 'Enter e-mail address.');
   });
 });
 
@@ -55,9 +54,7 @@ test('request password change link with invalid e-mail', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.index');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -78,9 +75,7 @@ test('request password change link with non-existing e-mail', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.index');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -101,9 +96,7 @@ test('request password change link with user-activated account', function(assert
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.index');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -124,9 +117,7 @@ test('request password change link with admin-activated account', function(asser
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.index');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -199,9 +190,7 @@ test('invalid token is handled', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.index');
-
-    var errorMessage = Ember.$.trim(find('.flash-message>p').text());
-    assert.equal(errorMessage, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -259,9 +248,7 @@ test('no new password is entered', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.change-form');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, 'Enter new password.');
+    assert.equal(getToastMessage(), 'Enter new password.');
   });
 });
 
@@ -291,9 +278,7 @@ test('new password is invalid', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.change-form');
-
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -320,9 +305,7 @@ test('new password is accepted', function(assert) {
 
   andThen(function() {
     assert.equal(currentPath(), 'forgotten-password.change-form');
+    assert.equal(getToastMessage(), "Your password has been changed.");
     assert.ok(find('#loginModal').hasClass('in'));
-
-    var message = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(message, "Your password has been changed.");
   });
 });

+ 7 - 10
misago/emberapp/tests/acceptance/login-test.js

@@ -1,6 +1,7 @@
 import Ember from 'ember';
 import { module, test } from 'qunit';
 import startApp from '../helpers/start-app';
+import getToastMessage from '../helpers/toast-message';
 
 var application;
 
@@ -28,8 +29,7 @@ test('login with empty credentials', function(assert) {
   click('#loginModal .btn-primary');
 
   andThen(function() {
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, 'Fill out both fields.');
+    assert.equal(getToastMessage(), 'Fill out both fields.');
   });
 });
 
@@ -52,8 +52,7 @@ test('login with invalid credentials', function(assert) {
   click('#loginModal .btn-primary');
 
   andThen(function() {
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -76,8 +75,7 @@ test('login to user-activated account', function(assert) {
   click('#loginModal .btn-primary');
 
   andThen(function() {
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -100,8 +98,7 @@ test('login to admin-activated account', function(assert) {
   click('#loginModal .btn-primary');
 
   andThen(function() {
-    var error = Ember.$.trim(find('.flash-message p').text());
-    assert.equal(error, message);
+    assert.equal(getToastMessage(), message);
   });
 });
 
@@ -130,8 +127,8 @@ test('login to banned account', function(assert) {
   click('#loginModal .btn-primary');
 
   andThen(function() {
-    var errorMessage = find('.lead p').text();
-    assert.equal(errorMessage, 'You are banned for trolling.');
+    var banMessage = find('.lead p').text();
+    assert.equal(banMessage, 'You are banned for trolling.');
 
     var expirationMessage = find('.error-message>p').text();
     assert.equal(expirationMessage, 'This ban is permanent.');

+ 5 - 0
misago/emberapp/tests/helpers/toast-message.js

@@ -0,0 +1,5 @@
+import Ember from 'ember';
+
+export default function getToastMessage() {
+  return Ember.$.trim(find('.toast-message p').text());
+}

+ 0 - 79
misago/emberapp/tests/unit/controllers/flash-message-test.js

@@ -1,79 +0,0 @@
-import {
-  moduleFor,
-  test
-} from 'ember-qunit';
-
-moduleFor('controller:flash-message', 'FlashMessageController');
-
-test('it exists', function(assert) {
-  var controller = this.subject();
-  assert.ok(controller);
-});
-
-test('isInfo', function(assert) {
-  var controller = this.subject();
-
-  controller.set('type', 'info');
-
-  assert.ok(controller.get('isInfo'));
-  assert.ok(!controller.get('isSuccess'));
-  assert.ok(!controller.get('isWarning'));
-  assert.ok(!controller.get('isError'));
-});
-
-test('isSuccess', function(assert) {
-  var controller = this.subject();
-
-  controller.set('type', 'success');
-
-  assert.ok(!controller.get('isInfo'));
-  assert.ok(controller.get('isSuccess'));
-  assert.ok(!controller.get('isWarning'));
-  assert.ok(!controller.get('isError'));
-});
-
-test('isWarning', function(assert) {
-  var controller = this.subject();
-
-  controller.set('type', 'warning');
-
-  assert.ok(!controller.get('isInfo'));
-  assert.ok(!controller.get('isSuccess'));
-  assert.ok(controller.get('isWarning'));
-  assert.ok(!controller.get('isError'));
-});
-
-test('isError', function(assert) {
-  var controller = this.subject();
-
-  controller.set('type', 'error');
-
-  assert.ok(!controller.get('isInfo'));
-  assert.ok(!controller.get('isSuccess'));
-  assert.ok(!controller.get('isWarning'));
-  assert.ok(controller.get('isError'));
-});
-
-test('setFlash', function(assert) {
-  var controller = this.subject();
-
-  var testMessage = "I'm test flash!";
-
-  controller.send('setFlash', 'success', testMessage);
-
-  assert.ok(controller.get('isVisible'));
-  assert.ok(controller.get('isSuccess'));
-  assert.equal(controller.get('message'), testMessage);
-});
-
-test('showFlash', function(assert) {
-  var controller = this.subject();
-
-  var testMessage = "I'm test flash!";
-
-  controller.showFlash('success', testMessage);
-
-  assert.ok(controller.get('isVisible'));
-  assert.ok(controller.get('isSuccess'));
-  assert.equal(controller.get('message'), testMessage);
-});

+ 79 - 0
misago/emberapp/tests/unit/controllers/toast-message-test.js

@@ -0,0 +1,79 @@
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+moduleFor('service:toast-message', 'ToastMessageService');
+
+test('it exists', function(assert) {
+  var service = this.subject();
+  assert.ok(service);
+});
+
+test('isInfo', function(assert) {
+  var service = this.subject();
+
+  service.set('type', 'info');
+
+  assert.ok(service.get('isInfo'));
+  assert.ok(!service.get('isSuccess'));
+  assert.ok(!service.get('isWarning'));
+  assert.ok(!service.get('isError'));
+});
+
+test('isSuccess', function(assert) {
+  var service = this.subject();
+
+  service.set('type', 'success');
+
+  assert.ok(!service.get('isInfo'));
+  assert.ok(service.get('isSuccess'));
+  assert.ok(!service.get('isWarning'));
+  assert.ok(!service.get('isError'));
+});
+
+test('isWarning', function(assert) {
+  var service = this.subject();
+
+  service.set('type', 'warning');
+
+  assert.ok(!service.get('isInfo'));
+  assert.ok(!service.get('isSuccess'));
+  assert.ok(service.get('isWarning'));
+  assert.ok(!service.get('isError'));
+});
+
+test('isError', function(assert) {
+  var service = this.subject();
+
+  service.set('type', 'error');
+
+  assert.ok(!service.get('isInfo'));
+  assert.ok(!service.get('isSuccess'));
+  assert.ok(!service.get('isWarning'));
+  assert.ok(service.get('isError'));
+});
+
+test('_setToast', function(assert) {
+  var service = this.subject();
+
+  var testMessage = "I'm test toast!";
+
+  service._setToast('success', testMessage);
+
+  assert.ok(service.get('isVisible'));
+  assert.ok(service.get('isSuccess'));
+  assert.equal(service.get('message'), testMessage);
+});
+
+test('_showToast', function(assert) {
+  var service = this.subject();
+
+  var testMessage = "I'm test toast!";
+
+  service._showToast('success', testMessage);
+
+  assert.ok(service.get('isVisible'));
+  assert.ok(service.get('isSuccess'));
+  assert.equal(service.get('message'), testMessage);
+});