Add predefined avatars

This commit is contained in:
aignatov-bio 2019-10-02 09:52:37 +02:00
parent 1f43f35073
commit 521a367960
7 changed files with 83 additions and 90 deletions

View file

@ -1,12 +1,24 @@
/* global initInlineEditing PerfectScrollbar */
/* eslint-disable no-restricted-globals, no-alert */
var avatarsModal = (function() {
var modal = '.modal-user-avatar'
var modal = '.modal-user-avatar';
function initUploadPhotoButton() {
$(modal).find('.upload-photo').click(() => {
$(modal).find('#raw_avatar').click()
})
$(modal).find('#raw_avatar').click();
});
}
function getBase64Image(img) {
var ctx;
var dataURL;
var canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
dataURL = canvas.toDataURL('image/png');
return dataURL;
}
function initCropTool() {
@ -18,8 +30,10 @@ var avatarsModal = (function() {
$(modal).find('.current-avatar').hide();
reader.readAsDataURL(inputField.files[0]);
reader.onload = function() {
var avatarContainer = $(modal).find('.avatar-preview-container');
$(modal).find('.save-button').removeClass('disabled');
$(modal).find('#new_avatar').val(reader.result);
var avatarContainer = $(modal).find('.avatar-preview-container')
avatarContainer.show().children().remove();
$('<img class="avatar-cropping-preview" src="' + reader.result + '"></img>').appendTo(avatarContainer);
croppieContainer = $('.avatar-cropping-preview');
@ -36,29 +50,48 @@ var avatarsModal = (function() {
function initPredefinedAvatars() {
$(modal).find('.avatar-collection .avatar').click(function() {
$(modal).find('.save-button').removeClass('disabled');
$(modal).find('#raw_avatar')[0].value = null;
$(modal).find('.avatar-preview-container').hide();
$(modal).find('.current-avatar').show().find('img')
.attr('src',$(this).find('img').attr('src'));
$(modal).find('#new_avatar').val(getBase64Image($(this).find('img')[0]))
})
.attr('src', $(this).find('img').attr('src'));
$(modal).find('#new_avatar').val(getBase64Image($(this).find('img')[0]));
});
}
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL;
function initUpdateButton() {
$(modal).find('.save-button').click(function() {
if ($(this).hasClass('disabled')) return;
$(this).addClass('disabled');
$.ajax({
url: $(modal).data('update-url'),
type: 'PUT',
data: {
'user[avatar]': $(modal).find('#new_avatar').val(),
'user[change_avatar]': true
},
dataType: 'json',
success: () => {
location.reload();
},
error: () => {
$(this).removeClass('disabled');
}
});
});
}
return {
init: (mode) => {
init: () => {
if ($('.modal-user-avatar').length > 0) {
initUploadPhotoButton()
initCropTool()
initPredefinedAvatars()
initUploadPhotoButton();
initCropTool();
initPredefinedAvatars();
initUpdateButton();
$('.user-settings-edit-avatar').click(() => {
$(modal).modal('show');
});
}
}
};

View file

@ -68,27 +68,6 @@
$(this).renderFormErrors('user', data.responseJSON);
});
/*$('#user_raw_avatar').change(function() {
var reader = new FileReader();
var inputField = this;
var croppieContainer;
reader.readAsDataURL(inputField.files[0]);
reader.onload = function() {
$('#user_avatar').val(reader.result);
$('.new-avatar-preview-container').css('display', '').children().remove();
$('<img class="new-avatar-cropping-preview" src="' + reader.result + '"></img>').appendTo('.new-avatar-preview-container');
croppieContainer = $('.new-avatar-cropping-preview');
croppieContainer.croppie({ viewport: { width: 150, height: 150, type: 'circle' } });
$('.new-avatar-preview-container').off('update.croppie').on('update.croppie', function() {
croppieContainer.croppie('result', { type: 'base64', format: 'jpeg', circle: false })
.then(function(image) {
$('#user_avatar').val(image);
});
});
};
});*/
$('#user-avatar-field :submit').click(function(ev) {
var $form = $(ev.target.form);
var $fileInput = $form.find('input[type=file]');

View file

@ -1,3 +1,6 @@
// scss-lint:disable SelectorDepth SelectorFormat QualifyingElement
// scss-lint:disable NestingDepth ImportantRule
@import "constants";
@import "mixins";
@ -47,7 +50,7 @@
height: 100px;
margin-bottom: 5px;
transition: $md-transaction;
width:80px;
width: 80px;
&:hover {
box-shadow: $md-shadow;
@ -69,7 +72,7 @@
.current-avatar {
height: 150px;
margin: 35px 0;
margin: 25px 0 45px;
width: 150px;
img {
@ -93,6 +96,6 @@
}
.modal-footer {
text-align: center
text-align: center;
}
}
}

View file

@ -37,10 +37,11 @@ class Users::RegistrationsController < Devise::RegistrationsController
else
temp_file = Tempfile.new('avatar', Rails.root.join('tmp'))
begin
check_extension = params[:avatar].split(';')[0].split('/')[1]
temp_file.binmode
temp_file.write(Base64.decode64(params[:avatar].sub(%r{^data:image\/jpeg\;base64,}, '')))
temp_file.write(Base64.decode64(params[:avatar].split(',')[1]))
temp_file.rewind
resource.avatar.attach(io: temp_file, filename: 'avatar.jpg')
resource.avatar.attach(io: temp_file, filename: "avatar.#{check_extension}")
ensure
temp_file.close
temp_file.unlink

View file

@ -16,46 +16,23 @@
<%= devise_error_messages! %>
</div>
<% end %>
<%= form_for(resource,
as: resource_name,
url: registration_path(resource_name),
html: { method: :put, "data-for" => "avatar", id: 'user-avatar-field' }) do |f| %>
<%= hidden_field_tag "user[change_avatar]", "true" %>
<div data-part="view">
<div class="form-group">
<%= f.label t("users.registrations.edit.avatar_label") %><br />
<div class="form-group user-settings-edit-avatar">
<%= t("users.registrations.edit.avatar_label") %><br>
<% @user_avatar_url ||= avatar_path(current_user, :thumb) %>
<div class="avatar-container">
<a href="#" data-action="edit">
<div class="avatar-image">
<div class="avatar-image">
<%= image_tag @user_avatar_url %>
</div>
<div class="avatar-edit">
</div>
<div class="avatar-edit">
<div class="btn btn-grey btn-sm">
<span class="fas fa-pencil-alt"></span>
<%=t "users.registrations.edit.avatar_btn" %>
</div>
<%=t "users.registrations.edit.avatar_btn" %>
</div>
</a>
</div>
</div>
</div>
</div>
<div data-part="edit" style="display: none;">
<div class="well">
<h4><%=t "users.registrations.edit.avatar_title" %></h4>
<div class="new-avatar-preview-container" style="display:none"></div>
<div class="form-group avatar-file-upload">
<%= f.label :avatar, t("users.registrations.edit.avatar_edit_label") %>
<%= f.file_field :raw_avatar, class: "btn btn-default" %>
<%= hidden_field_tag "user[avatar]", "" %>
</div>
<div class="align-right">
<a href="#" class="btn btn-default" data-action="cancel"><%=t "general.cancel" %></a>
<%= f.submit t("users.registrations.edit.avatar_submit"), class: 'btn btn-success' %>
</div>
</div>
</div>
<% end %>
<%= form_for(resource,
as: resource_name,
url: registration_path(resource_name, format: :json),
@ -236,9 +213,6 @@
</div>
<%= render partial: 'users/shared/user_avatars_modal' %>
<script>
$('.modal-user-avatar').modal('show')
</script>
<%= javascript_pack_tag 'custom/croppie' %>
<%= stylesheet_pack_tag 'custom/croppie_styles' %>

View file

@ -1,10 +1,12 @@
<div class="modal modal-user-avatar" tabindex="-1" role="dialog" >
<div class="modal modal-user-avatar" tabindex="-1" role="dialog"
data-update-url="<%= registration_path(resource_name) %>"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<button type="button" class="close" data-dismiss="modal" aria-label="<%= t('general.close') %>"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">
Change your profile photo
<%= t('users.registrations.edit.avatar_modal.title') %>
</h4>
</div>
<div class="modal-body">
@ -15,10 +17,10 @@
<%= hidden_field_tag :new_avatar, "" %>
</div>
<div class="avatar-preview-container" style="display:none"></div>
<div class="btn btn-default upload-photo">Upload a photo</div>
<div class="btn btn-default upload-photo"><%= t('users.registrations.edit.avatar_modal.upload_button') %></div>
</div>
<div class="option-text">
or<br>Select a profile icon below
<%= t('users.registrations.edit.avatar_modal.option_text_html') %>
</div>
<div class="avatar-collection perfect-scrollbar">
<% Dir["public/images/avatars/*.png"].each do |avatar| %>
@ -30,7 +32,7 @@
</div>
</div>
<div class="modal-footer">
<div class="btn btn-primary">Save</div>
<div class="btn btn-primary save-button disabled"><%= t('general.save') %></div>
</div>
</div>
</div>

View file

@ -91,6 +91,7 @@ en:
initials: "Initials"
avatar: "Avatar"
head:
title: "SciNote | %{title}"
@ -1411,10 +1412,10 @@ en:
title: "My profile"
avatar_label: "Avatar"
avatar_btn: "Edit Avatar"
avatar_title: "Change avatar"
avatar_edit_label: "Upload new avatar file"
avatar_submit: "Upload"
avatar_total_size: "Your avatar file cannot be larger than 0.2 MB. (Please try again with a smaller file.)"
avatar_modal:
title: 'Change your profile photo'
upload_button: 'Upload a photo'
option_text_html: 'or<br>Select a profile icon below'
name_label: "Full name"
name_title: "Change name"
initials_label: "Initials"