mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-13 22:53:32 +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,11 +5,12 @@ import Ember from 'ember';
|
|||||||
* A component to manage a user profile image. By default it just handles picture uploads,
|
* 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
|
* 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 {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} 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.
|
* @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 {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} 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
|
* @property {String} imageBackground String containing the background-image css property with the gravatar url
|
||||||
@ -17,24 +18,39 @@ import Ember from 'ember';
|
|||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
email: '',
|
email: '',
|
||||||
size: 90,
|
size: 90,
|
||||||
|
debounce: 300,
|
||||||
|
|
||||||
|
validEmail: '',
|
||||||
hasUploadedImage: false,
|
hasUploadedImage: false,
|
||||||
fileStorage: true,
|
fileStorage: true,
|
||||||
|
|
||||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||||
hasEmail: Ember.computed.notEmpty('email'),
|
displayGravatar: Ember.computed.notEmpty('validEmail'),
|
||||||
|
|
||||||
defaultImage: Ember.computed('ghostPaths', function () {
|
defaultImage: Ember.computed('ghostPaths', function () {
|
||||||
var url = this.get('ghostPaths.url').asset('/shared/img/user-image.png');
|
const url = this.get('ghostPaths.url').asset('/shared/img/user-image.png');
|
||||||
return `background-image: url(${url})`.htmlSafe();
|
return Ember.String.htmlSafe(`background-image: url(${url})`);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
imageBackground: Ember.computed('email', 'size', function () {
|
trySetValidEmail: function () {
|
||||||
var email = this.get('email'),
|
if (!this.get('isDestroyed')) {
|
||||||
size = this.get('size'),
|
const email = this.get('email');
|
||||||
url;
|
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) {
|
if (email) {
|
||||||
url = 'http://www.gravatar.com/avatar/' + md5(email) + '?s=' + size + '&d=blank';
|
let url = `http://www.gravatar.com/avatar/${md5(email)}?s=${size}&d=blank`;
|
||||||
return `background-image: url(${url})`.htmlSafe();
|
return Ember.String.htmlSafe(`background-image: url(${url})`);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -42,6 +58,9 @@ export default Ember.Component.extend({
|
|||||||
var size = this.get('size'),
|
var size = this.get('size'),
|
||||||
uploadElement = this.$('.js-file-input');
|
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
|
// while theoretically the 'add' and 'processalways' functions could be
|
||||||
// added as properties of the hash passed to fileupload(), for some reason
|
// 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
|
// 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 () {
|
willDestroyElement: function () {
|
||||||
|
if (this.$('.js-file-input').data()['blueimp-fileupload']) {
|
||||||
this.$('.js-file-input').fileupload('destroy');
|
this.$('.js-file-input').fileupload('destroy');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
queueFile: function (e, data) {
|
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)) {
|
if ((/\.(gif|jpe?g|png|svg?z)$/i).test(fileName)) {
|
||||||
this.sendAction('setImage', data);
|
this.sendAction('setImage', data);
|
||||||
@ -71,7 +92,7 @@ export default Ember.Component.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
triggerPreview: function (e, data) {
|
triggerPreview: function (e, data) {
|
||||||
var file = data.files[data.index];
|
const file = data.files[data.index];
|
||||||
if (file.preview) {
|
if (file.preview) {
|
||||||
this.set('hasUploadedImage', true);
|
this.set('hasUploadedImage', true);
|
||||||
// necessary jQuery code because file.preview is a raw DOM object
|
// necessary jQuery code because file.preview is a raw DOM object
|
||||||
|
@ -7,7 +7,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
|||||||
blogTitle: null,
|
blogTitle: null,
|
||||||
name: null,
|
name: null,
|
||||||
email: '',
|
email: '',
|
||||||
validEmail: '',
|
|
||||||
password: null,
|
password: null,
|
||||||
image: null,
|
image: null,
|
||||||
blogCreated: false,
|
blogCreated: false,
|
||||||
@ -53,9 +52,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
|||||||
preValidate: function (model) {
|
preValidate: function (model) {
|
||||||
// Only triggers validation if a value has been entered, preventing empty errors on focusOut
|
// Only triggers validation if a value has been entered, preventing empty errors on focusOut
|
||||||
if (this.get(model)) {
|
if (this.get(model)) {
|
||||||
if (model === 'email') {
|
|
||||||
this.send('handleEmail');
|
|
||||||
}
|
|
||||||
this.validate({property: model});
|
this.validate({property: model});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -119,13 +115,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
|||||||
},
|
},
|
||||||
setImage: function (image) {
|
setImage: function (image) {
|
||||||
this.set('image', 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,
|
submitting: false,
|
||||||
flowErrors: '',
|
flowErrors: '',
|
||||||
image: null,
|
image: null,
|
||||||
validEmail: '',
|
|
||||||
|
|
||||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||||
config: Ember.inject.service(),
|
config: Ember.inject.service(),
|
||||||
@ -88,13 +87,6 @@ export default Ember.Controller.extend(ValidationEngine, {
|
|||||||
},
|
},
|
||||||
setImage: function (image) {
|
setImage: function (image) {
|
||||||
this.set('image', 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}}
|
{{#unless hasUploadedImage}}
|
||||||
<div class="placeholder-img" style={{defaultImage}}></div>
|
<div class="placeholder-img" style={{defaultImage}}></div>
|
||||||
|
|
||||||
{{#if hasEmail}}
|
{{#if displayGravatar}}
|
||||||
<div id="account-image" class="gravatar-img" style={{imageBackground}}>
|
<div id="account-image" class="gravatar-img" style={{imageBackground}}>
|
||||||
<span class="sr-only">User image</span>
|
<span class="sr-only">User image</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
||||||
<input style="display:none;" type="password" name="fakepasswordremembered"/>
|
<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"}}
|
{{#gh-form-group errors=errors hasValidated=hasValidated property="email"}}
|
||||||
<label for="email-address">Email address</label>
|
<label for="email-address">Email address</label>
|
||||||
<span class="input-icon icon-mail">
|
<span class="input-icon icon-mail">
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
<input style="display:none;" type="text" name="fakeusernameremembered"/>
|
||||||
<input style="display:none;" type="password" name="fakepasswordremembered"/>
|
<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"}}
|
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="email"}}
|
||||||
<label for="email-address">Email address</label>
|
<label for="email-address">Email address</label>
|
||||||
<span class="input-icon icon-mail">
|
<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>
|
</span>
|
||||||
{{gh-error-message errors=model.errors property="email"}}
|
{{gh-error-message errors=model.errors property="email"}}
|
||||||
{{/gh-form-group}}
|
{{/gh-form-group}}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
|
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
|
||||||
"ember-cli-test-loader": "0.1.3",
|
"ember-cli-test-loader": "0.1.3",
|
||||||
"ember-data": "1.13.13",
|
"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-load-initializers": "ember-cli/ember-load-initializers#0.1.5",
|
||||||
"ember-resolver": "0.1.18",
|
"ember-resolver": "0.1.18",
|
||||||
"fastclick": "1.0.6",
|
"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