Ghost/ghost/admin/app/components/gh-profile-image.js
Kevin Ansfield 327cbdf7a2 Remove usage of jquery-file-upload (#815)
closes https://github.com/TryGhost/Ghost/issues/6661
- refactor `gh-profile-image` component to use native browser functionality
- remove `jquery-file-upload` bower dependency
2017-08-18 10:27:42 +07:00

166 lines
5.5 KiB
JavaScript

import $ from 'jquery';
import Component from 'ember-component';
import injectService from 'ember-service/inject';
import request from 'ember-ajax/request';
import {htmlSafe} from 'ember-string';
import {task, timeout} from 'ember-concurrency';
const ANIMATION_TIMEOUT = 1000;
/**
* A component to manage a user profile image. By default it just handles picture uploads,
* but if passed a bound 'email' property it will render the user's gravatar image
*
* Example: {{gh-profile-image email=controllerEmailProperty setImage="controllerActionName" debounce=500}}
*
* @param {int} size The size of the image to render
* @param {String} email Reference to a bound email object if gravatar image behavior is desired.
* @param {String|action} setImage The string name of the action on the controller to be called when an image is added.
* @param {int} debounce Period to wait after changes to email before attempting to load gravatar
* @property {Boolean} hasUploadedImage Whether or not the user has uploaded an image (whether or not to show the default image/gravatar image)
* @property {String} defaultImage String containing the background-image css property of the default user profile image
* @property {String} imageBackground String containing the background-image css property with the gravatar url
*/
export default Component.extend({
email: '',
size: 180,
debounce: 300,
imageFile: null,
hasUploadedImage: false,
// closure actions
setImage() {},
config: injectService(),
ghostPaths: injectService(),
placeholderStyle: htmlSafe('background-image: url()'),
avatarStyle: htmlSafe('display: none'),
_defaultImageUrl: '',
init() {
this._super(...arguments);
this._defaultImageUrl = `${this.get('ghostPaths.assetRoot')}img/user-image.png`;
this._setPlaceholderImage(this._defaultImageUrl);
},
didReceiveAttrs() {
this._super(...arguments);
if (this.get('config.useGravatar')) {
this.get('setGravatar').perform();
}
},
dragOver(event) {
if (!event.dataTransfer) {
return;
}
// this is needed to work around inconsistencies with dropping files
// from Chrome's downloads bar
let eA = event.dataTransfer.effectAllowed;
event.dataTransfer.dropEffect = (eA === 'move' || eA === 'linkMove') ? 'move' : 'copy';
event.stopPropagation();
event.preventDefault();
},
dragLeave(event) {
event.preventDefault();
},
drop(event) {
event.preventDefault();
if (event.dataTransfer.files) {
this.send('imageSelected', event.dataTransfer.files);
}
},
setGravatar: task(function* () {
yield timeout(this.get('debounce'));
let email = this.get('email');
if (validator.isEmail(email)) {
let size = this.get('size');
let gravatarUrl = `//www.gravatar.com/avatar/${window.md5(email)}?s=${size}&d=404`;
try {
// HEAD request is needed otherwise jquery attempts to process
// binary data as JSON and throws an error
yield request(gravatarUrl, {type: 'HEAD'});
// gravatar exists so switch style and let browser load it
this._setAvatarImage(gravatarUrl);
// wait for fade-in animation to finish before removing placeholder
yield timeout(ANIMATION_TIMEOUT);
this._setPlaceholderImage('');
} catch (e) {
// gravatar doesn't exist so make sure we're still showing the placeholder
this._setPlaceholderImage(this._defaultImageUrl);
// then make sure the avatar isn't visible
this._setAvatarImage('');
}
}
}).restartable(),
_setPlaceholderImage(url) {
this.set('placeholderStyle', htmlSafe(`background-image: url(${url});`));
},
_setAvatarImage(url) {
let display = url ? 'block' : 'none';
this.set('avatarStyle', htmlSafe(`background-image: url(${url}); display: ${display}`));
},
queueFile(e, data) {
let fileName = data.files[0].name;
if ((/\.(gif|jpe?g|png|svg?z)$/i).test(fileName)) {
this.sendAction('setImage', data);
}
},
actions: {
imageSelected(fileList) {
// eslint-disable-next-line
let imageFile = fileList[0];
if (imageFile) {
let reader = new FileReader();
this.set('imageFile', imageFile);
this.setImage(imageFile);
reader.addEventListener('load', () => {
let dataURL = reader.result;
this.set('previewDataURL', dataURL);
}, false);
reader.readAsDataURL(imageFile);
}
},
openFileDialog(event) {
let fileInput = $(event.target)
.closest('figure')
.find('input[type="file"]');
if (fileInput.length > 0) {
// reset file input value before clicking so that the same image
// can be selected again
fileInput.value = '';
// simulate click to open file dialog
// using jQuery because IE11 doesn't support MouseEvent
$(fileInput).click();
}
}
}
});