REFACTOR: Convert profile background uploader to be an ember component

This commit is contained in:
Robin Ward 2014-06-26 11:43:44 -04:00
parent 06880c28f8
commit 4088fba4f2
16 changed files with 118 additions and 107 deletions

View file

@ -0,0 +1,61 @@
export default Em.Component.extend({
uploading: false,
uploadProgress: 0,
backgroundStyle: function() {
var imageUrl = this.get('imageUrl');
if (Em.isNone(imageUrl)) { return; }
return "background-image: url(" + imageUrl + ")";
}.property('imageUrl'),
_initializeUploader: function() {
var $upload = this.$('input[type=file]'), // note: we can't cache this as fileupload replaces the input after upload
self = this;
$upload.fileupload({
url: this.get('uploadUrl'),
dataType: "json",
fileInput: $upload,
formData: { image_type: this.get('type') }
});
$upload.on('fileuploadsubmit', function (e, data) {
var result = Discourse.Utilities.validateUploadedFiles(data.files, true);
self.setProperties({ uploadProgress: 0, uploading: result });
return result;
});
$upload.on("fileuploadprogressall", function(e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
self.set("uploadProgress", progress);
});
$upload.on("fileuploaddone", function(e, data) {
if(data.result.url) {
self.set('imageUrl', data.result.url);
} else {
bootbox.alert(I18n.t('post.errors.upload'));
}
});
$upload.on("fileuploadfail", function(e, data) {
Discourse.Utilities.displayErrorForUpload(data);
});
$upload.on("fileuploadalways", function() {
self.setProperties({ uploading: false, uploadProgress: 0});
});
}.on('didInsertElement'),
_destroyUploader: function() {
this.$('input[type=file]').fileupload('destroy');
}.on('willDestroyElement'),
actions: {
selectFile: function() {
this.$('input[type=file]').click();
},
trash: function() {
this.set('imageUrl', null);
this.sendAction('clear');
}
}
});

View file

@ -66,7 +66,14 @@ export default Discourse.ObjectController.extend({
return this.get('saving') ? I18n.t('saving') : I18n.t('save');
}.property('saving'),
imageUploadUrl: Discourse.computed.url('username', '/users/%@/preferences/user_image'),
actions: {
clearProfileBackground: function() {
this.get('model').clearProfileBackground();
},
save: function() {
var self = this;
this.setProperties({ saving: true, saved: false });

View file

@ -354,8 +354,6 @@ Discourse.User = Discourse.Model.extend({
return Discourse.ajax("/users/" + this.get("username_lower") + "/preferences/profile_background/clear", {
type: 'PUT',
data: { }
}).then(function() {
user.set('profile_background', null);
});
},

View file

@ -63,12 +63,6 @@ Discourse.PreferencesRoute = Discourse.RestrictedUserRoute.extend({
avatarSelector.send('closeModal');
},
showProfileBackgroundFileSelector: function() {
$("#profile-background-input").click();
},
clearProfileBackground: function() {
this.modelFor('user').clearProfileBackground();
}
}
});

View file

@ -0,0 +1,10 @@
<input type="file" accept="image/*" style="display:none" />
<div class="uploaded-image-preview" class="input-xxlarge" {{bind-attr style="backgroundStyle"}}>
<div class="image-upload-controls">
<button {{action selectFile}} class="btn pad-left no-text"><i class="fa fa-picture-o"></i></button>
{{#if backgroundStyle}}
<button {{action trash}} class="btn btn-danger pad-left no-text"><i class="fa fa-trash-o"></i></button>
{{/if}}
<span {{bind-attr class=":btn uploading::hidden"}}>{{i18n upload_selector.uploading}} {{uploadProgress}}%</span>
</div>
</div>

View file

@ -4,6 +4,7 @@
{{#unless isUncategorizedCategory}}
{{edit-category-tab selectedTab=selectedTab tab="security"}}
{{edit-category-tab selectedTab=selectedTab tab="settings"}}
{{edit-category-tab selectedTab=selectedTab tab="images"}}
{{/unless}}
</ul>

View file

@ -92,18 +92,10 @@
<div class="control-group pref-profile-bg">
<label class="control-label">{{i18n user.change_profile_background.title}}</label>
<div class="controls">
<input type="file" id="profile-background-input" accept="image/*" style="display:none" />
<div id="profile-background-preview" class="input-xxlarge" {{bind-attr style="profileBackground"}}>
<div id="profile-background-controls">
<button {{action showProfileBackgroundFileSelector}} class="btn pad-left no-text"><i class="fa fa-picture-o"></i></button>
{{#if profileBackground}}
<button {{action clearProfileBackground}} class="btn btn-danger pad-left no-text"><i class="fa fa-trash-o"></i></button>
{{/if}}
{{#if view.uploading}}
<span class="btn">{{i18n upload_selector.uploading}} {{view.uploadProgress}}%</span>
{{/if}}
</div>
</div>
{{image-uploader uploadUrl=imageUploadUrl
imageUrl=profile_background
type="profile_background"
clear="clearProfileBackground"}}
</div>
</div>
{{/if}}

View file

@ -37,7 +37,7 @@ Discourse.AvatarSelectorView = Discourse.ModalBodyView.extend({
url: Discourse.getURL("/users/" + this.get("controller.username") + "/preferences/user_image"),
dataType: "json",
fileInput: $upload,
formData: { user_image_type: "avatar" }
formData: { image_type: "avatar" }
});
// when a file has been selected

View file

@ -1,55 +1,4 @@
/**
This view handles rendering of a user's preferences
@class PreferencesView
@extends Discourse.View
@namespace Discourse
@module Discourse
**/
Discourse.PreferencesView = Discourse.View.extend({
templateName: 'user/preferences',
classNames: ['user-preferences'],
uploading: false,
uploadProgress: 0,
didInsertElement: function() {
var self = this;
var $upload = $("#profile-background-input");
this._super();
$upload.fileupload({
url: Discourse.getURL("/users/" + this.get('controller.model.username') + "/preferences/user_image"),
dataType: "json",
fileInput: $upload,
formData: { user_image_type: "profile_background" }
});
$upload.on('fileuploadsubmit', function (e, data) {
var result = Discourse.Utilities.validateUploadedFiles(data.files, true);
self.setProperties({ uploadProgress: 0, uploading: result });
return result;
});
$upload.on("fileuploadprogressall", function(e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
self.set("uploadProgress", progress);
});
$upload.on("fileuploaddone", function(e, data) {
if(data.result.url) {
self.set("controller.model.profile_background", data.result.url);
} else {
bootbox.alert(I18n.t('post.errors.upload'));
}
});
$upload.on("fileuploadfail", function(e, data) {
Discourse.Utilities.displayErrorForUpload(data);
});
$upload.on("fileuploadalways", function() {
self.setProperties({ uploading: false, uploadProgress: 0});
});
},
willDestroyElement: function() {
$("#profile-background-input").fileupload("destroy");
}
classNames: ['user-preferences']
});

View file

@ -29,3 +29,14 @@
height: 20px;
}
}
.uploaded-image-preview {
height: 270px;
background-position: center center;
background-size: cover;
background-color: $primary;
}
.image-upload-controls {
padding: 10px;
}

View file

@ -43,19 +43,6 @@
display: none;
}
#profile-background-preview {
height: 270px;
background-position: center center;
background-size: cover;
background-color: $primary;
}
#profile-background-controls {
padding: 10px;
}
.static {
color: $primary;
display: inline-block;

View file

@ -10,3 +10,10 @@
color: scale-color($primary, $lightness: 50%);
}
}
.uploaded-image-preview {
height: 150px;
background-position: center center;
background-size: cover;
background-color: $primary;
}

View file

@ -63,13 +63,6 @@
padding: 5px 8px;
}
#profile-background-preview {
height: 150px;
background-position: center center;
background-size: cover;
background-color: $primary;
}
.bio-composer #wmd-quote-post {
display: none;
}

View file

@ -333,12 +333,12 @@ class UsersController < ApplicationController
# LEGACY: used by the API
def upload_avatar
params[:user_image_type] = "avatar"
params[:image_type] = "avatar"
upload_user_image
end
def upload_user_image
params.require(:user_image_type)
params.require(:image_type)
user = fetch_user_from_params
guardian.ensure_can_edit!(user)
@ -353,7 +353,7 @@ class UsersController < ApplicationController
upload = Upload.create_for(user.id, image.file, image.filename, image.filesize)
if upload.errors.empty?
case params[:user_image_type]
case params[:image_type]
when "avatar"
upload_avatar_for(user, upload)
when "profile_background"

View file

@ -1158,6 +1158,7 @@ en:
change_in_category_topic: "Edit Description"
already_used: 'This color has been used by another category'
security: "Security"
images: "Images"
auto_close_label: "Auto-close topics after:"
auto_close_units: "hours"
email_in: "Custom incoming email address:"

View file

@ -1126,7 +1126,7 @@ describe UsersController do
ActionDispatch::Http::UploadedFile.new({ filename: 'logo.png', tempfile: logo })
end
it 'raises an error without a user_image_type param' do
it 'raises an error without a image_type param' do
lambda { xhr :put, :upload_user_image, username: user.username }.should raise_error(ActionController::ParameterMissing)
end
@ -1134,19 +1134,19 @@ describe UsersController do
it 'raises an error when you don\'t have permission to upload an user image' do
Guardian.any_instance.expects(:can_edit?).with(user).returns(false)
xhr :post, :upload_user_image, username: user.username, user_image_type: "avatar"
xhr :post, :upload_user_image, username: user.username, image_type: "avatar"
response.should be_forbidden
end
it 'rejects large images' do
SiteSetting.stubs(:max_image_size_kb).returns(1)
xhr :post, :upload_user_image, username: user.username, file: user_image, user_image_type: "avatar"
xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "avatar"
response.status.should eq 422
end
it 'rejects unauthorized images' do
SiteSetting.stubs(:authorized_extensions).returns(".txt")
xhr :post, :upload_user_image, username: user.username, file: user_image, user_image_type: "avatar"
xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "avatar"
response.status.should eq 422
end
@ -1154,7 +1154,7 @@ describe UsersController do
upload = Fabricate(:upload)
Upload.expects(:create_for).returns(upload)
# enqueues the user_image generator job
xhr :post, :upload_user_image, username: user.username, file: user_image, user_image_type: "avatar"
xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "avatar"
# returns the url, width and height of the uploaded image
json = JSON.parse(response.body)
json['url'].should == "/uploads/default/1/1234567890123456.png"
@ -1166,7 +1166,7 @@ describe UsersController do
it 'is successful for profile backgrounds' do
upload = Fabricate(:upload)
Upload.expects(:create_for).returns(upload)
xhr :post, :upload_user_image, username: user.username, file: user_image, user_image_type: "profile_background"
xhr :post, :upload_user_image, username: user.username, file: user_image, image_type: "profile_background"
user.reload
user.user_profile.profile_background.should == "/uploads/default/1/1234567890123456.png"
@ -1191,13 +1191,13 @@ describe UsersController do
it 'rejects large images' do
SiteSetting.stubs(:max_image_size_kb).returns(1)
xhr :post, :upload_user_image, username: user.username, file: user_image_url, user_image_type: "profile_background"
xhr :post, :upload_user_image, username: user.username, file: user_image_url, image_type: "profile_background"
response.status.should eq 422
end
it 'rejects unauthorized images' do
SiteSetting.stubs(:authorized_extensions).returns(".txt")
xhr :post, :upload_user_image, username: user.username, file: user_image_url, user_image_type: "profile_background"
xhr :post, :upload_user_image, username: user.username, file: user_image_url, image_type: "profile_background"
response.status.should eq 422
end
@ -1205,7 +1205,7 @@ describe UsersController do
upload = Fabricate(:upload)
Upload.expects(:create_for).returns(upload)
# enqueues the user_image generator job
xhr :post, :upload_avatar, username: user.username, file: user_image_url, user_image_type: "avatar"
xhr :post, :upload_avatar, username: user.username, file: user_image_url, image_type: "avatar"
json = JSON.parse(response.body)
json['url'].should == "/uploads/default/1/1234567890123456.png"
json['width'].should == 100
@ -1216,7 +1216,7 @@ describe UsersController do
it 'is successful for profile backgrounds' do
upload = Fabricate(:upload)
Upload.expects(:create_for).returns(upload)
xhr :post, :upload_user_image, username: user.username, file: user_image_url, user_image_type: "profile_background"
xhr :post, :upload_user_image, username: user.username, file: user_image_url, image_type: "profile_background"
user.reload
user.user_profile.profile_background.should == "/uploads/default/1/1234567890123456.png"
@ -1229,7 +1229,7 @@ describe UsersController do
end
it "should handle malformed urls" do
xhr :post, :upload_user_image, username: user.username, file: "foobar", user_image_type: "profile_background"
xhr :post, :upload_user_image, username: user.username, file: "foobar", image_type: "profile_background"
response.status.should eq 422
end