mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
✨ Blog icon uplod (#397)
refs TryGhost/Ghost#7688 - Adds new upload functionality for a blog icon in general settings. - Icons will be uploaded to a new endpoint `uploads/icons` to trigger different validations.
This commit is contained in:
parent
c16d633d4b
commit
66f7bad47b
9 changed files with 105 additions and 16 deletions
|
@ -24,8 +24,10 @@ export default Component.extend({
|
||||||
text: '',
|
text: '',
|
||||||
altText: '',
|
altText: '',
|
||||||
saveButton: true,
|
saveButton: true,
|
||||||
accept: 'image/gif,image/jpg,image/jpeg,image/png,image/svg+xml',
|
accept: null,
|
||||||
extensions: ['gif', 'jpg', 'jpeg', 'png', 'svg'],
|
extensions: null,
|
||||||
|
uploadUrl: null,
|
||||||
|
allowUrlInput: true,
|
||||||
validate: null,
|
validate: null,
|
||||||
|
|
||||||
dragClass: null,
|
dragClass: null,
|
||||||
|
@ -39,6 +41,10 @@ export default Component.extend({
|
||||||
config: injectService(),
|
config: injectService(),
|
||||||
notifications: injectService(),
|
notifications: injectService(),
|
||||||
|
|
||||||
|
_defaultAccept: 'image/gif,image/jpg,image/jpeg,image/png,image/svg+xml',
|
||||||
|
_defaultExtensions: ['gif', 'jpg', 'jpeg', 'png', 'svg'],
|
||||||
|
_defaultUploadUrl: '/uploads/',
|
||||||
|
|
||||||
// TODO: this wouldn't be necessary if the server could accept direct
|
// TODO: this wouldn't be necessary if the server could accept direct
|
||||||
// file uploads
|
// file uploads
|
||||||
formData: computed('file', function () {
|
formData: computed('file', function () {
|
||||||
|
@ -83,6 +89,16 @@ export default Component.extend({
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
let image = this.get('image');
|
let image = this.get('image');
|
||||||
this.set('url', image);
|
this.set('url', image);
|
||||||
|
|
||||||
|
if (!this.get('accept')) {
|
||||||
|
this.set('accept', this.get('_defaultAccept'));
|
||||||
|
}
|
||||||
|
if (!this.get('extensions')) {
|
||||||
|
this.set('extensions', this.get('_defaultExtensions'));
|
||||||
|
}
|
||||||
|
if (!this.get('uploadUrl')) {
|
||||||
|
this.set('uploadUrl', this.get('_defaultUploadUrl'));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
dragOver(event) {
|
dragOver(event) {
|
||||||
|
@ -161,7 +177,10 @@ export default Component.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnsupportedMediaTypeError(error)) {
|
if (isUnsupportedMediaTypeError(error)) {
|
||||||
message = 'The image type you uploaded is not supported. Please use .PNG, .JPG, .GIF, .SVG.';
|
let validExtensions = this.get('extensions').join(', .').toUpperCase();
|
||||||
|
validExtensions = `.${validExtensions}`;
|
||||||
|
|
||||||
|
message = `The image type you uploaded is not supported. Please use ${validExtensions}`;
|
||||||
} else if (isRequestEntityTooLargeError(error)) {
|
} else if (isRequestEntityTooLargeError(error)) {
|
||||||
message = 'The image you uploaded was larger than the maximum file size your server allows.';
|
message = 'The image you uploaded was larger than the maximum file size your server allows.';
|
||||||
} else if (error.errors && !isBlank(error.errors[0].message)) {
|
} else if (error.errors && !isBlank(error.errors[0].message)) {
|
||||||
|
@ -177,7 +196,9 @@ export default Component.extend({
|
||||||
generateRequest() {
|
generateRequest() {
|
||||||
let ajax = this.get('ajax');
|
let ajax = this.get('ajax');
|
||||||
let formData = this.get('formData');
|
let formData = this.get('formData');
|
||||||
let url = `${ghostPaths().apiRoot}/uploads/`;
|
let uploadUrl = this.get('uploadUrl');
|
||||||
|
// CASE: we want to upload an icon and we have to POST it to a different endpoint, expecially for icons
|
||||||
|
let url = `${ghostPaths().apiRoot}${uploadUrl}`;
|
||||||
|
|
||||||
this._uploadStarted();
|
this._uploadStarted();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ export default Controller.extend(SettingsSaveMixin, {
|
||||||
|
|
||||||
showUploadLogoModal: false,
|
showUploadLogoModal: false,
|
||||||
showUploadCoverModal: false,
|
showUploadCoverModal: false,
|
||||||
|
showUploadIconModal: false,
|
||||||
showDeleteThemeModal: notEmpty('themeToDelete'),
|
showDeleteThemeModal: notEmpty('themeToDelete'),
|
||||||
|
|
||||||
ajax: injectService(),
|
ajax: injectService(),
|
||||||
|
@ -24,10 +25,17 @@ export default Controller.extend(SettingsSaveMixin, {
|
||||||
_scratchFacebook: null,
|
_scratchFacebook: null,
|
||||||
_scratchTwitter: null,
|
_scratchTwitter: null,
|
||||||
|
|
||||||
|
iconMimeTypes: 'image/png,image/x-icon',
|
||||||
|
iconExtensions: ['ico', 'png'],
|
||||||
|
|
||||||
logoImageSource: computed('model.logo', function () {
|
logoImageSource: computed('model.logo', function () {
|
||||||
return this.get('model.logo') || '';
|
return this.get('model.logo') || '';
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
iconImageSource: computed('model.icon', function () {
|
||||||
|
return this.get('model.icon') || '';
|
||||||
|
}),
|
||||||
|
|
||||||
coverImageSource: computed('model.cover', function () {
|
coverImageSource: computed('model.cover', function () {
|
||||||
return this.get('model.cover') || '';
|
return this.get('model.cover') || '';
|
||||||
}),
|
}),
|
||||||
|
@ -131,6 +139,10 @@ export default Controller.extend(SettingsSaveMixin, {
|
||||||
this.toggleProperty('showUploadLogoModal');
|
this.toggleProperty('showUploadLogoModal');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleUploadIconModal() {
|
||||||
|
this.toggleProperty('showUploadIconModal');
|
||||||
|
},
|
||||||
|
|
||||||
validateFacebookUrl() {
|
validateFacebookUrl() {
|
||||||
let newUrl = this.get('_scratchFacebook');
|
let newUrl = this.get('_scratchFacebook');
|
||||||
let oldUrl = this.get('model.facebook');
|
let oldUrl = this.get('model.facebook');
|
||||||
|
|
|
@ -10,6 +10,7 @@ export default Model.extend(ValidationEngine, {
|
||||||
description: attr('string'),
|
description: attr('string'),
|
||||||
logo: attr('string'),
|
logo: attr('string'),
|
||||||
cover: attr('string'),
|
cover: attr('string'),
|
||||||
|
icon: attr('string'),
|
||||||
defaultLang: attr('string'),
|
defaultLang: attr('string'),
|
||||||
postsPerPage: attr('number'),
|
postsPerPage: attr('number'),
|
||||||
forceI18n: attr('boolean'),
|
forceI18n: attr('boolean'),
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
<div class="description">{{description}}</div>
|
<div class="description">{{description}}</div>
|
||||||
{{/gh-file-input}}
|
{{/gh-file-input}}
|
||||||
</div>
|
</div>
|
||||||
|
{{#if allowUrlInput}}
|
||||||
<a class="image-url" {{action "switchForm" "url-input"}}>
|
<a class="image-url" {{action "switchForm" "url-input"}}>
|
||||||
<i class="icon-link"><span class="hidden">URL</span></i>
|
<i class="icon-link"><span class="hidden">URL</span></i>
|
||||||
</a>
|
</a>
|
||||||
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{!-- URL input --}}
|
{{!-- URL input --}}
|
||||||
<form class="url-form">
|
<form class="url-form">
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
saveButton=false
|
saveButton=false
|
||||||
update=(action 'fileUploaded')
|
update=(action 'fileUploaded')
|
||||||
onInput=(action (mut newUrl))
|
onInput=(action (mut newUrl))
|
||||||
|
accept=model.accept
|
||||||
|
extensions=model.extensions
|
||||||
|
allowUrlInput=model.allowUrlInput
|
||||||
|
uploadUrl=model.uploadUrl
|
||||||
}}
|
}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -39,12 +39,31 @@
|
||||||
|
|
||||||
{{#if showUploadLogoModal}}
|
{{#if showUploadLogoModal}}
|
||||||
{{gh-fullscreen-modal "upload-image"
|
{{gh-fullscreen-modal "upload-image"
|
||||||
model=(hash model=model imageProperty="logo")
|
model=(hash model=model imageProperty="logo" allowUrlInput=true)
|
||||||
close=(action "toggleUploadLogoModal")
|
close=(action "toggleUploadLogoModal")
|
||||||
modifier="action wide"}}
|
modifier="action wide"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if config.fileStorage}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Blog Icon</label>
|
||||||
|
{{#if model.icon}}
|
||||||
|
<img class="blog-icon" src="{{model.icon}}" alt="icon" role="button" {{action "toggleUploadIconModal"}}>
|
||||||
|
{{else}}
|
||||||
|
<button type="button" class="btn btn-green js-modal-logo" {{action "toggleUploadIconModal"}}>Upload Image</button>
|
||||||
|
{{/if}}
|
||||||
|
<p>Upload a square blog icon ('.ico' or '.png', max. 100kb, 32px * 32px up to 1,000px * 1,000px) for your publication</p>
|
||||||
|
|
||||||
|
{{#if showUploadIconModal}}
|
||||||
|
{{gh-fullscreen-modal "upload-image"
|
||||||
|
model=(hash model=model imageProperty="icon" accept=iconMimeTypes extensions=iconExtensions allowUrlInput=false uploadUrl="/uploads/icon/")
|
||||||
|
close=(action "toggleUploadIconModal")
|
||||||
|
modifier="action wide"}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Blog Cover</label>
|
<label>Blog Cover</label>
|
||||||
{{#if model.cover}}
|
{{#if model.cover}}
|
||||||
|
@ -56,7 +75,7 @@
|
||||||
|
|
||||||
{{#if showUploadCoverModal}}
|
{{#if showUploadCoverModal}}
|
||||||
{{gh-fullscreen-modal "upload-image"
|
{{gh-fullscreen-modal "upload-image"
|
||||||
model=(hash model=model imageProperty="cover")
|
model=(hash model=model imageProperty="cover" allowUrlInput=true)
|
||||||
close=(action "toggleUploadCoverModal")
|
close=(action "toggleUploadCoverModal")
|
||||||
modifier="action wide"}}
|
modifier="action wide"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<button class="btn btn-default user-cover-edit" {{action "toggleUploadCoverModal"}}>Change Cover</button>
|
<button class="btn btn-default user-cover-edit" {{action "toggleUploadCoverModal"}}>Change Cover</button>
|
||||||
{{#if showUploadCoverModal}}
|
{{#if showUploadCoverModal}}
|
||||||
{{gh-fullscreen-modal "upload-image"
|
{{gh-fullscreen-modal "upload-image"
|
||||||
model=(hash model=user imageProperty="cover")
|
model=(hash model=user imageProperty="cover" allowUrlInput=true)
|
||||||
close=(action "toggleUploadCoverModal")
|
close=(action "toggleUploadCoverModal")
|
||||||
modifier="action wide"}}
|
modifier="action wide"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
<button type="button" {{action "toggleUploadImageModal"}} class="edit-user-image">Edit Picture</button>
|
<button type="button" {{action "toggleUploadImageModal"}} class="edit-user-image">Edit Picture</button>
|
||||||
{{#if showUploadImageModal}}
|
{{#if showUploadImageModal}}
|
||||||
{{gh-fullscreen-modal "upload-image"
|
{{gh-fullscreen-modal "upload-image"
|
||||||
model=(hash model=user imageProperty="image")
|
model=(hash model=user imageProperty="image" allowUrlInput=true)
|
||||||
close=(action "toggleUploadImageModal")
|
close=(action "toggleUploadImageModal")
|
||||||
modifier="action wide"}}
|
modifier="action wide"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -227,5 +227,15 @@ export default [
|
||||||
updated_at: '2017-01-09T08:49:42.991Z',
|
updated_at: '2017-01-09T08:49:42.991Z',
|
||||||
updated_by: 1,
|
updated_by: 1,
|
||||||
value: 'true'
|
value: 'true'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 22,
|
||||||
|
key: 'icon',
|
||||||
|
value: '/content/images/2014/Feb/favicon.ico',
|
||||||
|
type: 'blog',
|
||||||
|
created_at: '2013-11-25T14:48:11.000Z',
|
||||||
|
created_by: 1,
|
||||||
|
updated_at: '2015-10-27T17:39:58.276Z',
|
||||||
|
updated_by: 1
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -16,11 +16,11 @@ import mockThemes from 'ghost-admin/mirage/config/themes';
|
||||||
describe('Acceptance: Settings - General', function () {
|
describe('Acceptance: Settings - General', function () {
|
||||||
let application;
|
let application;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
application = startApp();
|
application = startApp();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function () {
|
||||||
destroyApp(application);
|
destroyApp(application);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ describe('Acceptance: Settings - General', function () {
|
||||||
invalidateSession(application);
|
invalidateSession(application);
|
||||||
visit('/settings/general');
|
visit('/settings/general');
|
||||||
|
|
||||||
andThen(function() {
|
andThen(function () {
|
||||||
expect(currentURL(), 'currentURL').to.equal('/signin');
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -104,6 +104,27 @@ describe('Acceptance: Settings - General', function () {
|
||||||
|
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
expect(find('.fullscreen-modal .modal-content .gh-image-uploader .description').text()).to.equal('Upload an image');
|
expect(find('.fullscreen-modal .modal-content .gh-image-uploader .description').text()).to.equal('Upload an image');
|
||||||
|
expect(find('.fullscreen-modal .modal-content .gh-image-uploader .image-url').length, 'url upload').to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// click cancel button
|
||||||
|
click('.fullscreen-modal .modal-footer .btn.btn-minor');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
expect(find('.fullscreen-modal').length).to.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
click('.blog-icon');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
expect(find('.fullscreen-modal .modal-content .gh-image-uploader').length, 'modal selector').to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
click('.fullscreen-modal .modal-content .gh-image-uploader .image-cancel');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
expect(find('.fullscreen-modal .modal-content .gh-image-uploader .description').text()).to.equal('Upload an image');
|
||||||
|
expect(find('.fullscreen-modal .modal-content .gh-image-uploader .image-url').length, 'url upload').to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// click cancel button
|
// click cancel button
|
||||||
|
|
Loading…
Add table
Reference in a new issue