diff --git a/app/assets/javascripts/admin/templates/user_index.hbs b/app/assets/javascripts/admin/templates/user_index.hbs index e6347ff68c2..4dff9338a43 100644 --- a/app/assets/javascripts/admin/templates/user_index.hbs +++ b/app/assets/javascripts/admin/templates/user_index.hbs @@ -455,7 +455,7 @@ {{#unless anonymizeForbidden}} {{d-button label="admin.user.anonymize" icon="exclamation-triangle" - class="btn btn-danger" + class="btn-danger" disabled=anonymizeForbidden action="anonymize"}} {{/unless}} @@ -463,7 +463,7 @@ {{#unless deleteForbidden}} {{d-button label="admin.user.delete" icon="exclamation-triangle" - class="btn btn-danger" + class="btn-danger" disabled=deleteForbidden action="destroy"}} {{/unless}} diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 index b67da9c65fe..f00f6742806 100644 --- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 @@ -1,19 +1,19 @@ import UploadMixin from 'discourse/mixins/upload'; export default Em.Component.extend(UploadMixin, { + type: 'avatar', tagName: 'span', imageIsNotASquare: false, - type: 'avatar', uploadUrl: Discourse.computed.url('username', '/users/%@/preferences/user_image'), uploadButtonText: function() { - return this.get("uploading") ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture"); + return this.get("uploading") ? + I18n.t("uploading") : + I18n.t("user.change_avatar.upload_picture"); }.property("uploading"), - uploadDone: function(data) { - var self = this; - + uploadDone(data) { // display a warning whenever the image is not a square this.set("imageIsNotASquare", data.result.width !== data.result.height); @@ -21,13 +21,13 @@ export default Em.Component.extend(UploadMixin, { // indeed, the server gives us back the url to the file we've just uploaded // often, this file is not a square, so we need to crop it properly // this will also capture the first frame of animated avatars when they're not allowed - Discourse.Utilities.cropAvatar(data.result.url, data.files[0].type).then(function(avatarTemplate) { - self.set("uploadedAvatarTemplate", avatarTemplate); + Discourse.Utilities.cropAvatar(data.result.url, data.files[0].type).then(avatarTemplate => { + this.set("uploadedAvatarTemplate", avatarTemplate); // indicates the users is using an uploaded avatar (must happen after cropping, otherwise // we will attempt to load an invalid avatar and cache a redirect to old one, uploadedAvatarTemplate // trumps over custom avatar upload id) - self.set("custom_avatar_upload_id", data.result.upload_id); + this.set("custom_avatar_upload_id", data.result.upload_id); }); // the upload is now done diff --git a/app/assets/javascripts/discourse/components/d-button.js.es6 b/app/assets/javascripts/discourse/components/d-button.js.es6 index 21ebedc8e82..973405128f3 100644 --- a/app/assets/javascripts/discourse/components/d-button.js.es6 +++ b/app/assets/javascripts/discourse/components/d-button.js.es6 @@ -32,5 +32,6 @@ export default Ember.Component.extend({ click() { this.sendAction("action", this.get("actionParam")); + return false; } }); diff --git a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 index e856b5a09f8..3909f31aff4 100644 --- a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 @@ -2,8 +2,10 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import DiscourseController from 'discourse/controllers/controller'; export default DiscourseController.extend(ModalFunctionality, { + uploadedAvatarTemplate: null, + hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'custom_avatar_upload_id'), - selectedUploadId: function(){ + selectedUploadId: function() { switch (this.get("selected")) { case "system": return this.get("system_avatar_upload_id"); case "gravatar": return this.get("gravatar_avatar_upload_id"); @@ -12,18 +14,16 @@ export default DiscourseController.extend(ModalFunctionality, { }.property('selected', 'system_avatar_upload_id', 'gravatar_avatar_upload_id', 'custom_avatar_upload_id'), actions: { - useUploadedAvatar: function() { this.set("selected", "uploaded"); }, - useGravatar: function() { this.set("selected", "gravatar"); }, - useSystem: function() { this.set("selected", "system"); }, - refreshGravatar: function() { - var self = this; - self.set("gravatarRefreshDisabled", true); - Discourse - .ajax("/user_avatar/" + this.get("username") + "/refresh_gravatar", {method: 'POST'}) - .then(function(result){ - self.set("gravatarRefreshDisabled", false); - self.set("gravatar_avatar_upload_id", result.upload_id); - }); + useUploadedAvatar() { this.set("selected", "uploaded"); }, + useGravatar() { this.set("selected", "gravatar"); }, + useSystem() { this.set("selected", "system"); }, + + refreshGravatar() { + this.set("gravatarRefreshDisabled", true); + return Discourse + .ajax("/user_avatar/" + this.get("username") + "/refresh_gravatar.json", { method: 'POST' }) + .then(result => this.set("gravatar_avatar_upload_id", result.upload_id)) + .finally(() => this.set("gravatarRefreshDisabled", false)); } } diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index 667a344ddda..7fac8a1158e 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -1,4 +1,4 @@ -export default function showModal(name, model) { +export default (name, model) => { // We use the container here because modals are like singletons // in Discourse. Only one can be shown with a particular state. const route = Discourse.__container__.lookup('route:application'); @@ -12,5 +12,4 @@ export default function showModal(name, model) { if (controller.onShow) { controller.onShow(); } controller.set('flashMessage', null); } - return controller; -} +}; diff --git a/app/assets/javascripts/discourse/mixins/show-footer.js.es6 b/app/assets/javascripts/discourse/mixins/show-footer.js.es6 index a83fdbcf2d0..b97014153af 100644 --- a/app/assets/javascripts/discourse/mixins/show-footer.js.es6 +++ b/app/assets/javascripts/discourse/mixins/show-footer.js.es6 @@ -1,14 +1,13 @@ export default Em.Mixin.create({ actions: { - didTransition: function() { - var self = this; - Em.run.schedule("afterRender", function() { - self.controllerFor("application").set("showFooter", true); + didTransition() { + Em.run.schedule("afterRender", () => { + this.controllerFor("application").set("showFooter", true); }); return true; }, - willTransition: function() { + willTransition() { this.controllerFor("application").set("showFooter", false); return true; } diff --git a/app/assets/javascripts/discourse/routes/preferences.js.es6 b/app/assets/javascripts/discourse/routes/preferences.js.es6 index 79712f495eb..7fb2ba4a41f 100644 --- a/app/assets/javascripts/discourse/routes/preferences.js.es6 +++ b/app/assets/javascripts/discourse/routes/preferences.js.es6 @@ -8,7 +8,10 @@ export default RestrictedUserRoute.extend(ShowFooter, { }, setupController(controller, user) { - controller.setProperties({ model: user, newNameInput: user.get('name') }); + controller.setProperties({ + model: user, + newNameInput: user.get('name') + }); }, actions: { @@ -16,15 +19,15 @@ export default RestrictedUserRoute.extend(ShowFooter, { showModal('avatar-selector'); // all the properties needed for displaying the avatar selector modal - const controller = this.controllerFor('avatar-selector'); - const user = this.modelFor('user'); - const props = user.getProperties( - 'username', 'email', - 'uploaded_avatar_id', - 'system_avatar_upload_id', - 'gravatar_avatar_upload_id', - 'custom_avatar_upload_id' - ); + const controller = this.controllerFor('avatar-selector'), + props = this.modelFor('user').getProperties( + 'email', + 'username', + 'uploaded_avatar_id', + 'system_avatar_upload_id', + 'gravatar_avatar_upload_id', + 'custom_avatar_upload_id' + ); switch (props.uploaded_avatar_id) { case props.system_avatar_upload_id: @@ -40,20 +43,20 @@ export default RestrictedUserRoute.extend(ShowFooter, { controller.setProperties(props); }, - saveAvatarSelection: function() { - const user = this.modelFor('user'); - const avatarSelector = this.controllerFor('avatar-selector'); + saveAvatarSelection() { + const user = this.modelFor('user'), + avatarSelector = this.controllerFor('avatar-selector'); // sends the information to the server if it has changed if (avatarSelector.get('selectedUploadId') !== user.get('uploaded_avatar_id')) { user.pickAvatar(avatarSelector.get('selectedUploadId')) - .then(function(){ - user.setProperties(avatarSelector.getProperties( - 'system_avatar_upload_id', - 'gravatar_avatar_upload_id', - 'custom_avatar_upload_id' - )); - }); + .then(() => { + user.setProperties(avatarSelector.getProperties( + 'system_avatar_upload_id', + 'gravatar_avatar_upload_id', + 'custom_avatar_upload_id' + )); + }); } // saves the data back diff --git a/app/assets/javascripts/discourse/routes/restricted-user.js.es6 b/app/assets/javascripts/discourse/routes/restricted-user.js.es6 index ad9cb411efd..46cc1fe6fe3 100644 --- a/app/assets/javascripts/discourse/routes/restricted-user.js.es6 +++ b/app/assets/javascripts/discourse/routes/restricted-user.js.es6 @@ -2,9 +2,8 @@ export default Discourse.Route.extend({ - afterModel: function() { - var user = this.modelFor('user'); - if (!user.get('can_edit')) { + afterModel() { + if (!this.modelFor('user').get('can_edit')) { this.replaceWith('userActivity'); } } diff --git a/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs b/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs index caad9187acd..0e375179c2b 100644 --- a/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs +++ b/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs @@ -7,14 +7,14 @@ <div> <input type="radio" id="gravatar" name="avatar" value="gravatar" {{action "useGravatar"}}> <label class="radio" for="gravatar">{{bound-avatar controller "large" gravatar_avatar_upload_id}} {{{i18n 'user.change_avatar.gravatar'}}} {{email}}</label> - <button href {{action "refreshGravatar"}} title="{{i18n 'user.change_avatar.refresh_gravatar_title'}}" {{bind-attr enabled="view.gravatarRefreshEnabled"}} class="btn no-text"><i class="fa fa-refresh"></i></button> + {{d-button action="refreshGravatar" title="user.change_avatar.refresh_gravatar_title" disabled=gravatarRefreshDisabled class="no-text" icon="refresh"}} </div> <div> <input type="radio" id="uploaded_avatar" name="avatar" value="uploaded" {{action "useUploadedAvatar"}}> <label class="radio" for="uploaded_avatar"> - {{#if view.hasUploadedAvatar}} - {{#if view.uploadedAvatarTemplate}} - {{bound-avatar-template view.uploadedAvatarTemplate "large"}} + {{#if hasUploadedAvatar}} + {{#if uploadedAvatarTemplate}} + {{bound-avatar-template uploadedAvatarTemplate "large"}} {{else}} {{bound-avatar controller "large" custom_avatar_upload_id}} {{i18n 'user.change_avatar.uploaded_avatar'}} {{/if}} @@ -23,14 +23,14 @@ {{/if}} </label> {{avatar-uploader username=username - uploadedAvatarTemplate=view.uploadedAvatarTemplate - custom_avatar_upload_id=controller.custom_avatar_upload_id + uploadedAvatarTemplate=uploadedAvatarTemplate + custom_avatar_upload_id=custom_avatar_upload_id done="useUploadedAvatar"}} </div> </div> </div> <div class="modal-footer"> - <button class="btn btn-primary" {{action "saveAvatarSelection"}} {{bind-attr disabled="view.saveDisabled"}}>{{i18n 'save'}}</button> + {{d-button action="saveAvatarSelection" class="btn-primary" disabled=saveDisabled label="save"}} <a {{action "closeModal"}}>{{i18n 'cancel'}}</a> </div> diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index 4a617f999a3..d7cc7b20c34 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -54,7 +54,7 @@ <div class="controls"> <span class='static'>{{email}}</span> {{#if can_edit_email}} - {{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}<i class="fa fa-pencil"></i>{{/link-to}} + {{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}{{fa-icon "pencil"}}{{/link-to}} {{/if}} </div> <div class='instructions'> @@ -62,7 +62,7 @@ </div> {{else}} <div class="controls"> - <button class="btn" title="{{i18n 'admin.users.check_email.title'}}" {{action "checkEmail" this}}>{{fa-icon "envelope-o"}} {{i18n 'admin.users.check_email.text'}}</button> + {{d-button action="checkEmail" actionParam=this title="admin.users.check_email.title" icon="envelope-o" label="admin.users.check_email.text"}} </div> {{/if}} </div> @@ -72,7 +72,8 @@ <div class="control-group pref-password"> <label class="control-label">{{i18n 'user.password.title'}}</label> <div class="controls"> - <a href="#" {{action "changePassword"}} class='btn'><i class="fa fa-envelope"></i> + <a href="#" {{action "changePassword"}} class='btn'> + {{fa-icon "envelope"}} {{#if no_password}} {{i18n 'user.change_password.set_password'}} {{else}} @@ -87,9 +88,10 @@ <div class="control-group pref-avatar"> <label class="control-label">{{i18n 'user.avatar.title'}}</label> <div class="controls"> - {{bound-avatar model "large"}} + {{! we want the "huge" version even though we're downsizing it to "large" in CSS }} + {{bound-avatar model "huge"}} {{#if allowAvatarUpload}} - <button {{action "showAvatarSelector"}} class="btn pad-left no-text">{{fa-icon "pencil"}}</button> + {{d-button action="showAvatarSelector" class="pad-left no-text" icon="pencil"}} {{else}} {{#unless ssoOverridesAvatar}} <a href="//gravatar.com/emails" target="_blank" title="{{i18n 'user.change_avatar.gravatar_title'}}" class="btn no-text">{{fa-icon "pencil"}}</a> @@ -245,7 +247,7 @@ <div class="control-group delete-account"> <hr/> <div class="controls"> - <button {{action "delete"}} {{bind-attr disabled="deleteDisabled"}} class="btn btn-danger"><i class="fa fa-trash-o"></i> {{i18n 'user.delete_account'}}</button> + {{d-button action="delete" disabled="deleteDisabled" class="btn-danger" icon="trash-o" label="user.delete_account"}} </div> </div> {{/if}} diff --git a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 index 40414660a6d..ed60610505b 100644 --- a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 @@ -4,9 +4,6 @@ export default ModalBodyView.extend({ templateName: 'modal/avatar_selector', classNames: ['avatar-selector'], title: I18n.t('user.change_avatar.title'), - saveDisabled: false, - gravatarRefreshEnabled: Em.computed.not('controller.gravatarRefreshDisabled'), - hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'controller.custom_avatar_upload_id'), // *HACK* used to select the proper radio button, cause {{action}} // stops the default behavior diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index cc3fe231583..6936c8d6055 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -170,6 +170,13 @@ border-bottom: 1px solid scale-color-diff(); } } + + .pref-avatar { + .avatar { + max-width: 45px; + max-height: 45px; + } + } } .about { diff --git a/test/javascripts/controllers/avatar-selector-test.js.es6 b/test/javascripts/controllers/avatar-selector-test.js.es6 index 8d7441d6e24..3f2f0af811e 100644 --- a/test/javascripts/controllers/avatar-selector-test.js.es6 +++ b/test/javascripts/controllers/avatar-selector-test.js.es6 @@ -3,7 +3,8 @@ moduleFor("controller:avatar-selector", "controller:avatar-selector", { }); test("avatarTemplate", function() { - var avatarSelectorController = this.subject(); + const avatarSelectorController = this.subject(); + avatarSelectorController.setProperties({ selected: "system", system_avatar_upload_id:1, @@ -11,17 +12,11 @@ test("avatarTemplate", function() { custom_avatar_upload_id: 3 }); - equal(avatarSelectorController.get("selectedUploadId"), 1, - "we are using system by default"); + equal(avatarSelectorController.get("selectedUploadId"), 1, "we are using system by default"); avatarSelectorController.set('selected', 'gravatar'); - - equal(avatarSelectorController.get("selectedUploadId"), 2, - "we are using gravatar when set"); + equal(avatarSelectorController.get("selectedUploadId"), 2, "we are using gravatar when set"); avatarSelectorController.set("selected", "custom"); - - equal(avatarSelectorController.get("selectedUploadId"), 3, - "we are using custom when set"); - + equal(avatarSelectorController.get("selectedUploadId"), 3, "we are using custom when set"); });