diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 index f00f6742806..d5e983ccf8c 100644 --- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 @@ -1,33 +1,29 @@ -import UploadMixin from 'discourse/mixins/upload'; +import UploadMixin from "discourse/mixins/upload"; export default Em.Component.extend(UploadMixin, { - type: 'avatar', - tagName: 'span', + type: "avatar", + tagName: "span", imageIsNotASquare: false, - 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(data) { + uploadDone(upload) { // display a warning whenever the image is not a square - this.set("imageIsNotASquare", data.result.width !== data.result.height); + this.set("imageIsNotASquare", upload.width !== upload.height); // in order to be as much responsive as possible, we're cheating a bit here // 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(avatarTemplate => { + Discourse.Utilities.cropAvatar(upload.url, upload.original_filename).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) - this.set("custom_avatar_upload_id", data.result.upload_id); + this.set("custom_avatar_upload_id", upload.id); }); // the upload is now done diff --git a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 index 59f65b3d556..b43bea04103 100644 --- a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 @@ -1,4 +1,4 @@ -import UploadMixin from 'discourse/mixins/upload'; +import UploadMixin from "discourse/mixins/upload"; export default Em.Component.extend(UploadMixin, { type: "emoji", @@ -11,9 +11,9 @@ export default Em.Component.extend(UploadMixin, { return Ember.isBlank(this.get("name")) ? {} : { name: this.get("name") }; }.property("name"), - uploadDone: function (data) { + uploadDone(upload) { this.set("name", null); - this.sendAction("done", data.result); + this.sendAction("done", upload); } }); diff --git a/app/assets/javascripts/discourse/components/image-uploader.js.es6 b/app/assets/javascripts/discourse/components/image-uploader.js.es6 index 2301242fbd7..4ca6bfdab22 100644 --- a/app/assets/javascripts/discourse/components/image-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/image-uploader.js.es6 @@ -1,32 +1,21 @@ -import UploadMixin from 'discourse/mixins/upload'; +import UploadMixin from "discourse/mixins/upload"; export default Em.Component.extend(UploadMixin, { - classNames: ['image-uploader'], + classNames: ["image-uploader"], backgroundStyle: function() { - const imageUrl = this.get('imageUrl'); + const imageUrl = this.get("imageUrl"); if (Em.isNone(imageUrl)) { return; } - return ("background-image: url(" + imageUrl + ")").htmlSafe(); - }.property('imageUrl'), + }.property("imageUrl"), - uploadDone: function(data) { - this.set('imageUrl', data.result.url); + uploadDone(upload) { + this.set("imageUrl", upload.url); }, actions: { trash() { - this.set('imageUrl', null); - - // Do we want to signal the delete to the server right away? - if (this.get('instantDelete')) { - Discourse.ajax(this.get('uploadUrl'), { - type: 'DELETE', - data: { image_type: this.get('type') } - }).then(null, function() { - bootbox.alert(I18n.t('generic_error')); - }); - } + this.set("imageUrl", null); } } }); diff --git a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 b/app/assets/javascripts/discourse/controllers/edit-category.js.es6 index e667d447d56..ca15eda2496 100644 --- a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 +++ b/app/assets/javascripts/discourse/controllers/edit-category.js.es6 @@ -5,7 +5,7 @@ import { categoryBadgeHTML } from 'discourse/helpers/category-link'; // Modal for editing / creating a category export default ObjectController.extend(ModalFunctionality, { foregroundColors: ['FFFFFF', '000000'], - categoryUploadUrl: '/category/uploads', + categoryUploadUrl: '/uploads', editingPermissions: false, selectedTab: null, saving: false, diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6 index ecd9033de8c..0cc11e05e95 100644 --- a/app/assets/javascripts/discourse/controllers/preferences.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6 @@ -91,7 +91,6 @@ export default ObjectController.extend(CanCheckEmails, { }.property('model.isSaving'), passwordProgress: null, - imageUploadUrl: Discourse.computed.url('model.username', '/users/%@/preferences/user_image'), actions: { diff --git a/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 b/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 index 2a3eded1dd8..16e4a4b2c43 100644 --- a/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 +++ b/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 @@ -45,6 +45,6 @@ export default { inject(app, 'currentUser', 'component', 'route', 'controller'); app.register('message-bus:main', window.MessageBus, { instantiate: false }); - inject(app, 'messageBus', 'route', 'controller', 'view'); + inject(app, 'messageBus', 'route', 'controller', 'view', 'component'); } }; diff --git a/app/assets/javascripts/discourse/lib/utilities.js b/app/assets/javascripts/discourse/lib/utilities.js index f51fd4d46f3..d85e474132e 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js +++ b/app/assets/javascripts/discourse/lib/utilities.js @@ -296,6 +296,8 @@ Discourse.Utilities = { } return; } + } else if (data.errors) { + bootbox.alert(data.errors.join("\n")); } // otherwise, display a generic error message bootbox.alert(I18n.t('post.errors.upload')); diff --git a/app/assets/javascripts/discourse/mixins/upload.js.es6 b/app/assets/javascripts/discourse/mixins/upload.js.es6 index ac91a056de1..2914d72849f 100644 --- a/app/assets/javascripts/discourse/mixins/upload.js.es6 +++ b/app/assets/javascripts/discourse/mixins/upload.js.es6 @@ -2,27 +2,35 @@ export default Em.Mixin.create({ uploading: false, uploadProgress: 0, - uploadDone: function() { + uploadDone() { Em.warn("You should implement `uploadDone`"); }, - deleteDone: function() { + deleteDone() { Em.warn("You should implement `deleteDone`"); }, - _initializeUploader: function() { - var $upload = this.$(), - self = this, - csrf = Discourse.Session.currentProp("csrfToken"); + _initialize: function() { + const $upload = this.$(), + csrf = Discourse.Session.currentProp("csrfToken"), + uploadUrl = this.getWithDefault("uploadUrl", "/uploads"); + + this.messageBus.subscribe("/uploads/" + this.get("type"), upload => { + if (upload && upload.url) { + this.uploadDone(upload); + } else { + Discourse.Utilities.displayErrorForUpload(upload); + } + }); $upload.fileupload({ - url: this.get('uploadUrl') + ".json?authenticity_token=" + encodeURIComponent(csrf), + url: uploadUrl + ".json?authenticity_token=" + encodeURIComponent(csrf), dataType: "json", dropZone: $upload, pasteZone: $upload }); - $upload.on("fileuploaddrop", function (e, data) { + $upload.on("fileuploaddrop", (e, data) => { if (data.files.length > 10) { bootbox.alert(I18n.t("post.errors.too_many_dragged_and_dropped_files")); return false; @@ -31,51 +39,34 @@ export default Em.Mixin.create({ } }); - $upload.on('fileuploadsubmit', function (e, data) { - var isValid = Discourse.Utilities.validateUploadedFiles(data.files, true); - var form = { image_type: self.get('type') }; - if (self.get("data")) { form = $.extend(form, self.get("data")); } + $upload.on("fileuploadsubmit", (e, data) => { + const isValid = Discourse.Utilities.validateUploadedFiles(data.files, true); + let form = { type: this.get("type") }; + if (this.get("data")) { form = $.extend(form, this.get("data")); } data.formData = form; - self.setProperties({ uploadProgress: 0, uploading: isValid }); + this.setProperties({ uploadProgress: 0, uploading: isValid }); return isValid; }); - $upload.on("fileuploadprogressall", function(e, data) { - var progress = parseInt(data.loaded / data.total * 100, 10); - self.set("uploadProgress", progress); + $upload.on("fileuploadprogressall", (e, data) => { + const progress = parseInt(data.loaded / data.total * 100, 10); + this.set("uploadProgress", progress); }); - $upload.on("fileuploaddone", function(e, data) { - if (data.result) { - if (data.result.url) { - self.uploadDone(data); - } else { - if (data.result.message) { - bootbox.alert(data.result.message); - } else if (data.result.length > 0) { - bootbox.alert(data.result.join("\n")); - } else { - bootbox.alert(I18n.t('post.errors.upload')); - } - } - } else { - bootbox.alert(I18n.t('post.errors.upload')); - } - }); - - $upload.on("fileuploadfail", function(e, data) { + $upload.on("fileuploadfail", (e, data) => { Discourse.Utilities.displayErrorForUpload(data); }); - $upload.on("fileuploadalways", function() { - self.setProperties({ uploading: false, uploadProgress: 0}); + $upload.on("fileuploadalways", () => { + this.setProperties({ uploading: false, uploadProgress: 0}); }); - }.on('didInsertElement'), + }.on("didInsertElement"), - _destroyUploader: function() { - var $upload = this.$(); - try { $upload.fileupload('destroy'); } + _destroy: function() { + this.messageBus.unsubscribe("/uploads/" + this.get("type")); + const $upload = this.$(); + try { $upload.fileupload("destroy"); } catch (e) { /* wasn't initialized yet */ } $upload.off(); - }.on('willDestroyElement') + }.on("willDestroyElement") }); diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 8322097ec46..aecb9cbc4c5 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -171,27 +171,31 @@ const User = RestModel.extend({ @returns {Promise} the result of the operation **/ save: function() { - var self = this, - data = this.getProperties('auto_track_topics_after_msecs', - 'bio_raw', - 'website', - 'location', - 'name', - 'locale', - 'email_digests', - 'email_direct', - 'email_always', - 'email_private_messages', - 'dynamic_favicon', - 'digest_after_days', - 'new_topic_duration_minutes', - 'external_links_in_new_tab', - 'mailing_list_mode', - 'enable_quoting', - 'disable_jump_reply', - 'custom_fields', - 'user_fields', - 'muted_usernames'); + const self = this, + data = this.getProperties( + 'auto_track_topics_after_msecs', + 'bio_raw', + 'website', + 'location', + 'name', + 'locale', + 'email_digests', + 'email_direct', + 'email_always', + 'email_private_messages', + 'dynamic_favicon', + 'digest_after_days', + 'new_topic_duration_minutes', + 'external_links_in_new_tab', + 'mailing_list_mode', + 'enable_quoting', + 'disable_jump_reply', + 'custom_fields', + 'user_fields', + 'muted_usernames', + 'profile_background', + 'card_background' + ); ['muted','watched','tracked'].forEach(function(s){ var cats = self.get(s + 'Categories').map(function(c){ return c.get('id')}); diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index ed94f9f4507..f561b20f642 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -1,18 +1,6 @@ {{#if visible}} - -{{!-- -note this spinner is NEVER turned "off" when the composer is open -so I'm going to stop rendering it until we figure out what's up - -