mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-13 14:39:52 +03:00
Merge pull request #6017 from kevinansfield/finalize-debounced-gravatar
Finish changes in #5807 (debounced gravatar load in gh-profile-image)
This commit is contained in:
commit
54532e7e88
@ -5,36 +5,52 @@ import Ember from 'ember';
|
||||
* 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"}}
|
||||
* 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} setImage The string name of the action on the controller to be called when an image is added.
|
||||
* @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
|
||||
* @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 Ember.Component.extend({
|
||||
email: '',
|
||||
size: 90,
|
||||
debounce: 300,
|
||||
|
||||
validEmail: '',
|
||||
hasUploadedImage: false,
|
||||
fileStorage: true,
|
||||
|
||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||
hasEmail: Ember.computed.notEmpty('email'),
|
||||
displayGravatar: Ember.computed.notEmpty('validEmail'),
|
||||
|
||||
defaultImage: Ember.computed('ghostPaths', function () {
|
||||
var url = this.get('ghostPaths.url').asset('/shared/img/user-image.png');
|
||||
return `background-image: url(${url})`.htmlSafe();
|
||||
const url = this.get('ghostPaths.url').asset('/shared/img/user-image.png');
|
||||
return Ember.String.htmlSafe(`background-image: url(${url})`);
|
||||
}),
|
||||
|
||||
imageBackground: Ember.computed('email', 'size', function () {
|
||||
var email = this.get('email'),
|
||||
size = this.get('size'),
|
||||
url;
|
||||
trySetValidEmail: function () {
|
||||
if (!this.get('isDestroyed')) {
|
||||
const email = this.get('email');
|
||||
this.set('validEmail', validator.isEmail(email) ? email : '');
|
||||
}
|
||||
},
|
||||
|
||||
didReceiveAttrs: function (attrs) {
|
||||
const timeout = parseInt(attrs.newAttrs.throttle || this.get('debounce'));
|
||||
Ember.run.debounce(this, 'trySetValidEmail', timeout);
|
||||
},
|
||||
|
||||
imageBackground: Ember.computed('validEmail', 'size', function () {
|
||||
const email = this.get('validEmail'),
|
||||
size = this.get('size');
|
||||
|
||||
if (email) {
|
||||
url = 'http://www.gravatar.com/avatar/' + md5(email) + '?s=' + size + '&d=blank';
|
||||
return `background-image: url(${url})`.htmlSafe();
|
||||
let url = `http://www.gravatar.com/avatar/${md5(email)}?s=${size}&d=blank`;
|
||||
return Ember.String.htmlSafe(`background-image: url(${url})`);
|
||||
}
|
||||
}),
|
||||
|
||||
@ -42,6 +58,9 @@ export default Ember.Component.extend({
|
||||
var size = this.get('size'),
|
||||
uploadElement = this.$('.js-file-input');
|
||||
|
||||
// Fire this immediately in case we're initialized with a valid email
|
||||
this.trySetValidEmail();
|
||||
|
||||
// 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
|
||||
@ -59,11 +78,13 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
willDestroyElement: function () {
|
||||
this.$('.js-file-input').fileupload('destroy');
|
||||
if (this.$('.js-file-input').data()['blueimp-fileupload']) {
|
||||
this.$('.js-file-input').fileupload('destroy');
|
||||
}
|
||||
},
|
||||
|
||||
queueFile: function (e, data) {
|
||||
var fileName = data.files[0].name;
|
||||
const fileName = data.files[0].name;
|
||||
|
||||
if ((/\.(gif|jpe?g|png|svg?z)$/i).test(fileName)) {
|
||||
this.sendAction('setImage', data);
|
||||
@ -71,7 +92,7 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
triggerPreview: function (e, data) {
|
||||
var file = data.files[data.index];
|
||||
const file = data.files[data.index];
|
||||
if (file.preview) {
|
||||
this.set('hasUploadedImage', true);
|
||||
// necessary jQuery code because file.preview is a raw DOM object
|
||||
|
@ -7,7 +7,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
blogTitle: null,
|
||||
name: null,
|
||||
email: '',
|
||||
validEmail: '',
|
||||
password: null,
|
||||
image: null,
|
||||
blogCreated: false,
|
||||
@ -53,9 +52,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
preValidate: function (model) {
|
||||
// Only triggers validation if a value has been entered, preventing empty errors on focusOut
|
||||
if (this.get(model)) {
|
||||
if (model === 'email') {
|
||||
this.send('handleEmail');
|
||||
}
|
||||
this.validate({property: model});
|
||||
}
|
||||
},
|
||||
@ -119,13 +115,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
},
|
||||
setImage: function (image) {
|
||||
this.set('image', image);
|
||||
},
|
||||
handleEmail: function () {
|
||||
var self = this;
|
||||
|
||||
this.validate({property: 'email'}).then(function () {
|
||||
self.set('validEmail', self.get('email'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -9,7 +9,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
submitting: false,
|
||||
flowErrors: '',
|
||||
image: null,
|
||||
validEmail: '',
|
||||
|
||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||
config: Ember.inject.service(),
|
||||
@ -88,13 +87,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
},
|
||||
setImage: function (image) {
|
||||
this.set('image', image);
|
||||
},
|
||||
handleEmail: function () {
|
||||
var self = this;
|
||||
|
||||
this.validate({property: 'email'}).then(function () {
|
||||
self.set('validEmail', self.get('email'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
{{#unless hasUploadedImage}}
|
||||
<div class="placeholder-img" style={{defaultImage}}></div>
|
||||
|
||||
{{#if hasEmail}}
|
||||
{{#if displayGravatar}}
|
||||
<div id="account-image" class="gravatar-img" style={{imageBackground}}>
|
||||
<span class="sr-only">User image</span>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
||||
<input style="display:none;" type="password" name="fakepasswordremembered"/>
|
||||
|
||||
{{gh-profile-image fileStorage=config.fileStorage email=validEmail setImage="setImage"}}
|
||||
{{gh-profile-image fileStorage=config.fileStorage email=email setImage="setImage"}}
|
||||
{{#gh-form-group errors=errors hasValidated=hasValidated property="email"}}
|
||||
<label for="email-address">Email address</label>
|
||||
<span class="input-icon icon-mail">
|
||||
|
@ -11,11 +11,11 @@
|
||||
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
||||
<input style="display:none;" type="password" name="fakepasswordremembered"/>
|
||||
|
||||
{{gh-profile-image fileStorage=config.fileStorage email=validEmail setImage="setImage"}}
|
||||
{{gh-profile-image fileStorage=config.fileStorage email=model.email setImage="setImage"}}
|
||||
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="email"}}
|
||||
<label for="email-address">Email address</label>
|
||||
<span class="input-icon icon-mail">
|
||||
{{gh-input type="email" name="email" placeholder="Eg. john@example.com" enter=(action "signup") disabled="disabled" autocorrect="off" value=model.email focusOut=(action "handleEmail")}}
|
||||
{{gh-input type="email" name="email" placeholder="Eg. john@example.com" enter=(action "signup") disabled="disabled" autocorrect="off" value=model.email focusOut=(action "validate" "email")}}
|
||||
</span>
|
||||
{{gh-error-message errors=model.errors property="email"}}
|
||||
{{/gh-form-group}}
|
||||
|
@ -8,7 +8,7 @@
|
||||
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
|
||||
"ember-cli-test-loader": "0.1.3",
|
||||
"ember-data": "1.13.13",
|
||||
"ember-mocha": "0.8.4",
|
||||
"ember-mocha": "0.8.6",
|
||||
"ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5",
|
||||
"ember-resolver": "0.1.18",
|
||||
"fastclick": "1.0.6",
|
||||
|
@ -0,0 +1,91 @@
|
||||
/* jshint expr:true */
|
||||
/* global md5 */
|
||||
import { expect } from 'chai';
|
||||
import {
|
||||
describeComponent,
|
||||
it
|
||||
} from 'ember-mocha';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import Ember from 'ember';
|
||||
|
||||
const {run} = Ember,
|
||||
pathsStub = Ember.Service.extend({
|
||||
url: {
|
||||
api: function () {
|
||||
return '';
|
||||
},
|
||||
asset: function (src) {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
describeComponent(
|
||||
'gh-profile-image',
|
||||
'Integration: Component: gh-profile-image',
|
||||
{
|
||||
integration: true
|
||||
},
|
||||
function () {
|
||||
beforeEach(function () {
|
||||
this.register('service:ghost-paths', pathsStub);
|
||||
this.inject.service('ghost-paths', {as: 'ghost-paths'});
|
||||
});
|
||||
|
||||
it('renders', function () {
|
||||
this.set('email', '');
|
||||
|
||||
this.render(hbs`
|
||||
{{gh-profile-image email=email}}
|
||||
`);
|
||||
|
||||
expect(this.$()).to.have.length(1);
|
||||
});
|
||||
|
||||
it('immediately renders the gravatar if valid email supplied', function () {
|
||||
let email = 'test@example.com',
|
||||
expectedUrl = `http://www.gravatar.com/avatar/${md5(email)}?s=100&d=blank`;
|
||||
|
||||
this.set('email', email);
|
||||
|
||||
this.render(hbs`
|
||||
{{gh-profile-image email=email size=100 debounce=300}}
|
||||
`);
|
||||
|
||||
expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
|
||||
.to.equal(`background-image: url(${expectedUrl})`);
|
||||
});
|
||||
|
||||
it('throttles gravatar loading as email is changed', function (done) {
|
||||
let email = 'test@example.com',
|
||||
expectedUrl = `http://www.gravatar.com/avatar/${md5(email)}?s=100&d=blank`;
|
||||
|
||||
this.set('email', 'test');
|
||||
|
||||
this.render(hbs`
|
||||
{{gh-profile-image email=email size=100 debounce=300}}
|
||||
`);
|
||||
|
||||
expect(this.$('.gravatar-img').length, '.gravatar-img not shown for invalid email')
|
||||
.to.equal(0);
|
||||
|
||||
run(() => {
|
||||
this.set('email', email);
|
||||
});
|
||||
|
||||
expect(this.$('.gravatar-img').length, '.gravatar-img not immediately changed on email change')
|
||||
.to.equal(0);
|
||||
|
||||
Ember.run.later(this, function () {
|
||||
expect(this.$('.gravatar-img').length, '.gravatar-img still not shown before throttle timeout')
|
||||
.to.equal(0);
|
||||
}, 250);
|
||||
|
||||
Ember.run.later(this, function () {
|
||||
expect(this.$('.gravatar-img').attr('style'), '.gravatar-img style after timeout')
|
||||
.to.equal(`background-image: url(${expectedUrl})`);
|
||||
done();
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
);
|
@ -1,48 +0,0 @@
|
||||
/* jshint expr:true */
|
||||
/* global md5 */
|
||||
import { expect } from 'chai';
|
||||
import {
|
||||
describeComponent,
|
||||
it
|
||||
} from 'ember-mocha';
|
||||
|
||||
describeComponent(
|
||||
'gh-profile-image',
|
||||
'Unit: Component: gh-profile-image',
|
||||
{
|
||||
unit: true,
|
||||
needs: ['service:ghost-paths']
|
||||
},
|
||||
function () {
|
||||
it('renders', function () {
|
||||
// creates the component instance
|
||||
var component = this.subject();
|
||||
expect(component._state).to.equal('preRender');
|
||||
|
||||
// renders the component on the page
|
||||
this.render();
|
||||
expect(component._state).to.equal('inDOM');
|
||||
});
|
||||
it('renders the gravatar image background if email is supplied', function () {
|
||||
var component = this.subject(),
|
||||
testEmail = 'test@example.com',
|
||||
style, size;
|
||||
|
||||
component.set('email', testEmail);
|
||||
this.render();
|
||||
|
||||
size = component.get('size');
|
||||
|
||||
style = 'url(http://www.gravatar.com/avatar/' + md5(testEmail) + '?s=' + size + '&d=blank)';
|
||||
|
||||
expect(component.$('#account-image').css('background-image')).to.equal(style);
|
||||
});
|
||||
it('doesn\'t render the gravatar image background if email isn\'t supplied', function () {
|
||||
var component = this.subject();
|
||||
|
||||
this.render();
|
||||
|
||||
expect(component.$('#account-image').length).to.equal(0);
|
||||
});
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue
Block a user