mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-02 08:13:34 +03:00
cb59388c5b
no issue - adds `eslint-plugin-sort-imports-es6-autofix` dependency - implements ESLint's base `sort-imports` rule but has a distinction in that `import {foo} from 'bar';` is considered `multiple` rather than `single` - fixes ESLint's autofix behaviour so `eslint --fix` will actually fix the sort order - updates all unordered import rules by using `eslint --fix` With the increased number of `import` statements since Ember+ecosystem started moving towards es6 modules I've found it frustrating at times trying to search through randomly ordered import statements. Recently I've been sorting imports manually when I've added new code or touched old code so I thought I'd add an ESLint rule to codify it.
138 lines
5.2 KiB
JavaScript
138 lines
5.2 KiB
JavaScript
import AjaxService from 'ember-ajax/services/ajax';
|
|
import Component from 'ember-component';
|
|
import computed, {notEmpty} from 'ember-computed';
|
|
import injectService from 'ember-service/inject';
|
|
import run from 'ember-runloop';
|
|
import {htmlSafe} from 'ember-string';
|
|
import {isBlank} from 'ember-utils';
|
|
import {isNotFoundError} from 'ember-ajax/errors';
|
|
|
|
/**
|
|
* 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,
|
|
|
|
validEmail: '',
|
|
hasUploadedImage: false,
|
|
ajax: AjaxService.create(),
|
|
|
|
config: injectService(),
|
|
ghostPaths: injectService(),
|
|
|
|
displayGravatar: notEmpty('validEmail'),
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
// Fire this immediately in case we're initialized with a valid email
|
|
this.trySetValidEmail();
|
|
},
|
|
|
|
defaultImage: computed('ghostPaths', function () {
|
|
let url = `${this.get('ghostPaths.assetRoot')}/img/user-image.png`;
|
|
return htmlSafe(`background-image: url(${url})`);
|
|
}),
|
|
|
|
trySetValidEmail() {
|
|
if (!this.get('isDestroyed')) {
|
|
let email = this.get('email');
|
|
this.set('validEmail', validator.isEmail(email) ? email : '');
|
|
}
|
|
},
|
|
|
|
didReceiveAttrs() {
|
|
this._super(...arguments);
|
|
let timeout = parseInt(this.get('throttle') || this.get('debounce'));
|
|
run.debounce(this, 'trySetValidEmail', timeout);
|
|
},
|
|
|
|
imageBackground: computed('validEmail', 'size', function () {
|
|
let email = this.get('validEmail');
|
|
let size = this.get('size');
|
|
let style = '';
|
|
|
|
if (!isBlank(email)) {
|
|
let gravatarUrl = `//www.gravatar.com/avatar/${window.md5(email)}?s=${size}&d=404`;
|
|
|
|
this.get('ajax').request(gravatarUrl)
|
|
.catch((error) => {
|
|
let defaultImageUrl = `url("${this.get('ghostPaths.assetRoot')}/img/user-image.png")`;
|
|
|
|
if (isNotFoundError(error)) {
|
|
this.$('.placeholder-img')[0].style.backgroundImage = htmlSafe(defaultImageUrl);
|
|
} else {
|
|
this.$('.placeholder-img')[0].style.backgroundImage = 'url()';
|
|
}
|
|
});
|
|
|
|
style = `background-image: url(${gravatarUrl})`;
|
|
}
|
|
return htmlSafe(style);
|
|
}),
|
|
|
|
didInsertElement() {
|
|
let size = this.get('size');
|
|
let uploadElement = this.$('.js-file-input');
|
|
|
|
this._super(...arguments);
|
|
|
|
// while theoretically the 'add' and 'processalways' functions could be
|
|
// added as properties of the hash passed to fileupload(), for some reason
|
|
// they needed to be placed in an on() call for the add method to work correctly
|
|
uploadElement.fileupload({
|
|
url: this.get('ghostPaths.url').api('uploads'),
|
|
dropZone: this.$('.js-img-dropzone'),
|
|
previewMaxHeight: size,
|
|
previewMaxWidth: size,
|
|
previewCrop: true,
|
|
maxNumberOfFiles: 1,
|
|
autoUpload: false
|
|
})
|
|
.on('fileuploadadd', run.bind(this, this.queueFile))
|
|
.on('fileuploadprocessalways', run.bind(this, this.triggerPreview));
|
|
},
|
|
|
|
willDestroyElement() {
|
|
let $input = this.$('.js-file-input');
|
|
|
|
this._super(...arguments);
|
|
|
|
if ($input.length && $input.data()['blueimp-fileupload']) {
|
|
$input.fileupload('destroy');
|
|
}
|
|
},
|
|
|
|
queueFile(e, data) {
|
|
let fileName = data.files[0].name;
|
|
|
|
if ((/\.(gif|jpe?g|png|svg?z)$/i).test(fileName)) {
|
|
this.sendAction('setImage', data);
|
|
}
|
|
},
|
|
|
|
triggerPreview(e, data) {
|
|
let file = data.files[data.index];
|
|
|
|
if (file.preview) {
|
|
this.set('hasUploadedImage', true);
|
|
// necessary jQuery code because file.preview is a raw DOM object
|
|
// potential todo: rename 'gravatar-img' class in the CSS to be something
|
|
// that both the gravatar and the image preview can use that's not so confusing
|
|
this.$('.js-img-preview').empty().append(this.$(file.preview).addClass('gravatar-img'));
|
|
}
|
|
}
|
|
});
|