mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 20:03:12 +03:00
✨ Koenig - Unsplash integration
refs https://github.com/TryGhost/Ghost/issues/9724 - standardised `{{gh-unsplash}}` actions and action arguments to better represent a generic "image source" - added `{{gh-unsplash searchTerm="ghosts"}}` parameter - added `payload` param to `card` definitions used for plus/slash menus so that default payload params can be passed to cards - added a concept of "image selectors" to image card - if a `payload.imageSelector` param is received by the card it will look it up in it's list of known selectors and display the appropriate image selection component - if the card was created with an image selector param and the image selector is closed without selecting an image then the card will be removed - delete image cards during cleanup if they were created via selector but have no src
This commit is contained in:
parent
9a81a80706
commit
4463f975e3
@ -128,8 +128,8 @@ export default Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
addUnsplashPhoto(photo) {
|
||||
this.set('url', photo.urls.regular);
|
||||
addUnsplashPhoto({src}) {
|
||||
this.set('url', src);
|
||||
this.send('saveUrl');
|
||||
},
|
||||
|
||||
|
@ -363,11 +363,11 @@ export default Component.extend(ShortcutsMixin, {
|
||||
this.toggleProperty('_showUnsplash');
|
||||
},
|
||||
|
||||
insertUnsplashPhoto(photo) {
|
||||
insertUnsplashPhoto({src, alt, caption}) {
|
||||
let image = {
|
||||
alt: photo.description || '',
|
||||
url: photo.urls.regular,
|
||||
credit: `<small>Photo by [${photo.user.name}](${photo.user.links.html}?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit) / [Unsplash](https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit)</small>`
|
||||
alt,
|
||||
url: src,
|
||||
credit: `<small>${caption}</small>`
|
||||
};
|
||||
|
||||
this._insertImages([image]);
|
||||
|
@ -13,7 +13,7 @@ export default Component.extend({
|
||||
zoomed: false,
|
||||
|
||||
// closure actions
|
||||
insert() {},
|
||||
select() {},
|
||||
zoom() {},
|
||||
|
||||
style: computed('zoomed', function () {
|
||||
@ -78,10 +78,10 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
insert(event) {
|
||||
select(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.insert(this.get('photo'));
|
||||
this.select(this.get('photo'));
|
||||
},
|
||||
|
||||
zoom(event) {
|
||||
|
@ -16,10 +16,11 @@ export default Component.extend(ShortcutsMixin, {
|
||||
shortcuts: null,
|
||||
tagName: '',
|
||||
zoomedPhoto: null,
|
||||
searchTerm: null,
|
||||
|
||||
// closure actions
|
||||
close() {},
|
||||
insert() {},
|
||||
select() {},
|
||||
|
||||
sideNavHidden: or('ui.{autoNav,isFullScreen,showMobileMenu}'),
|
||||
|
||||
@ -31,6 +32,16 @@ export default Component.extend(ShortcutsMixin, {
|
||||
};
|
||||
},
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.searchTerm !== this._searchTerm) {
|
||||
this.unsplash.updateSearch(this.searchTerm);
|
||||
}
|
||||
|
||||
this._searchTerm = this.searchTerm;
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this._resizeCallback = bind(this, this._handleResize);
|
||||
@ -63,9 +74,16 @@ export default Component.extend(ShortcutsMixin, {
|
||||
this.set('zoomedPhoto', null);
|
||||
},
|
||||
|
||||
insert(photo) {
|
||||
select(photo) {
|
||||
this.get('unsplash').triggerDownload(photo);
|
||||
this.insert(photo);
|
||||
|
||||
let selectParams = {
|
||||
src: photo.urls.regular,
|
||||
alt: photo.description || '',
|
||||
caption: `Photo by <a href="${photo.user.links.html}?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">${photo.user.name}</a> / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Unsplash</a>`
|
||||
};
|
||||
this.select(selectParams);
|
||||
|
||||
this.close();
|
||||
},
|
||||
|
||||
|
@ -54,6 +54,21 @@ export default Service.extend({
|
||||
return reject();
|
||||
},
|
||||
|
||||
updateSearch(term) {
|
||||
if (term === this.get('searchTerm')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('searchTerm', term);
|
||||
this._reset();
|
||||
|
||||
if (term) {
|
||||
return this.get('_search').perform(term);
|
||||
} else {
|
||||
return this.get('_loadNew').perform();
|
||||
}
|
||||
},
|
||||
|
||||
retryLastRequest() {
|
||||
return this.get('_retryLastRequest').perform();
|
||||
},
|
||||
@ -75,18 +90,7 @@ export default Service.extend({
|
||||
|
||||
actions: {
|
||||
updateSearch(term) {
|
||||
if (term === this.get('searchTerm')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('searchTerm', term);
|
||||
this._reset();
|
||||
|
||||
if (term) {
|
||||
return this.get('_search').perform(term);
|
||||
} else {
|
||||
return this.get('_loadNew').perform();
|
||||
}
|
||||
return this.updateSearch(term);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
{{#if _showUnsplash}}
|
||||
{{gh-unsplash
|
||||
insert=(action "addUnsplashPhoto")
|
||||
select=(action "addUnsplashPhoto")
|
||||
close=(action (toggle "_showUnsplash" this))
|
||||
}}
|
||||
{{/if}}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
{{#if _showUnsplash}}
|
||||
{{gh-unsplash
|
||||
insert=(action "insertUnsplashPhoto")
|
||||
select=(action "insertUnsplashPhoto")
|
||||
close=(action "toggleUnsplash")}}
|
||||
{{/if}}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
{{photo.user.name}}
|
||||
</a>
|
||||
</div>
|
||||
<a class="gh-unsplash-button" href="#" onclick={{action "insert"}}>Insert image</a>
|
||||
<a class="gh-unsplash-button" href="#" onclick={{action "select"}}>Insert image</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,7 +40,7 @@
|
||||
{{#each unsplash.columns as |photos|}}
|
||||
<div class="gh-unsplash-grid-column">
|
||||
{{#each photos as |photo|}}
|
||||
{{gh-unsplash-photo photo=photo zoom=(action "zoomPhoto") insert=(action "insert")}}
|
||||
{{gh-unsplash-photo photo=photo zoom=(action "zoomPhoto") select=(action "select")}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
@ -73,17 +73,12 @@
|
||||
|
||||
{{!-- zoomed image overlay --}}
|
||||
{{#if zoomedPhoto}}
|
||||
<<<<<<< HEAD
|
||||
<div class="absolute top-0 right-0 bottom-0 left-0 pr20 pb10 pl20 bg-white" {{action "closeZoom"}}>
|
||||
{{gh-unsplash-photo photo=zoomedPhoto zoomed=true zoom=(action "closeZoom") insert=(action "insert")}}
|
||||
=======
|
||||
<div class="absolute flex justify-center top-0 right-0 bottom-0 left-0 pr20 pb10 pl20 bg-white overflow-hidden" {{action "closeZoom"}}>
|
||||
{{gh-unsplash-photo
|
||||
photo=zoomedPhoto
|
||||
zoomed=true
|
||||
zoom=(action "closeZoom")
|
||||
select=(action "select")}}
|
||||
>>>>>>> 419884354... fixed zoom layout
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
IMAGE_EXTENSIONS,
|
||||
IMAGE_MIME_TYPES
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {computed, set} from '@ember/object';
|
||||
import {computed, set, setProperties} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/string';
|
||||
import {isEmpty} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
@ -32,11 +32,21 @@ export default Component.extend({
|
||||
deselectCard() {},
|
||||
editCard() {},
|
||||
saveCard() {},
|
||||
deleteCard() {},
|
||||
moveCursorToNextSection() {},
|
||||
moveCursorToPrevSection() {},
|
||||
addParagraphAfterCard() {},
|
||||
registerComponent() {},
|
||||
|
||||
imageSelector: computed('payload.imageSelector', function () {
|
||||
let selector = this.payload.imageSelector;
|
||||
let imageSelectors = {
|
||||
unsplash: 'gh-unsplash'
|
||||
};
|
||||
|
||||
return imageSelectors[selector];
|
||||
}),
|
||||
|
||||
counts: computed('payload.{src,caption}', function () {
|
||||
let wordCount = 0;
|
||||
let imageCount = 0;
|
||||
@ -168,6 +178,23 @@ export default Component.extend({
|
||||
resetSrcs() {
|
||||
this.set('previewSrc', null);
|
||||
this._updatePayloadAttr('src', null);
|
||||
},
|
||||
|
||||
selectFromImageSelector({src, caption, alt}) {
|
||||
let {payload, saveCard} = this;
|
||||
let imageSelector, searchTerm;
|
||||
|
||||
setProperties(payload, {src, caption, alt, imageSelector, searchTerm});
|
||||
|
||||
saveCard(payload, false);
|
||||
},
|
||||
|
||||
closeImageSelector() {
|
||||
if (!this.payload.src) {
|
||||
return this.deleteCard();
|
||||
}
|
||||
|
||||
set(this.payload, 'imageSelector', undefined);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -96,7 +96,7 @@ export default Component.extend({
|
||||
let range = this._editorRange;
|
||||
|
||||
if (item.type === 'card') {
|
||||
this.replaceWithCardSection(item.replaceArg, range);
|
||||
this.replaceWithCardSection(item.replaceArg, range, item.payload);
|
||||
}
|
||||
|
||||
this._hideButton();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../templates/components/koenig-slash-menu';
|
||||
import {CARD_MENU} from '../options/cards';
|
||||
import {assign} from '@ember/polyfills';
|
||||
import {computed, set} from '@ember/object';
|
||||
import {copy} from '@ember/object/internals';
|
||||
import {htmlSafe} from '@ember/string';
|
||||
@ -91,7 +92,7 @@ export default Component.extend({
|
||||
itemClicked(item, event) {
|
||||
let range = this._openRange.head.section.toRange();
|
||||
let [, ...params] = this._query.split(/\s/);
|
||||
let payload;
|
||||
let payload = assign({}, item.payload);
|
||||
|
||||
// make sure the click doesn't propagate and get picked up by the
|
||||
// newly inserted card which can then remove itself because it
|
||||
@ -103,7 +104,6 @@ export default Component.extend({
|
||||
|
||||
// params are order-dependent and listed in CARD_MENU for each card
|
||||
if (!isEmpty(item.params) && !isEmpty(params)) {
|
||||
payload = {};
|
||||
item.params.forEach((param, i) => {
|
||||
payload[param] = params[i];
|
||||
});
|
||||
|
@ -8,7 +8,9 @@ export default [
|
||||
createComponentCard('embed', {hasEditMode: false, deleteIfEmpty: 'payload.html'}),
|
||||
createComponentCard('hr', {hasEditMode: false, selectAfterInsert: false}),
|
||||
createComponentCard('html', {deleteIfEmpty: 'payload.html'}),
|
||||
createComponentCard('image', {hasEditMode: false}),
|
||||
createComponentCard('image', {hasEditMode: false, deleteIfEmpty(card) {
|
||||
return card.payload.imageSelector && !card.payload.src;
|
||||
}}),
|
||||
createComponentCard('markdown', {deleteIfEmpty: 'payload.markdown'})
|
||||
];
|
||||
|
||||
@ -89,8 +91,11 @@ export const CARD_MENU = [
|
||||
iconClass: 'kg-card-type-unsplash',
|
||||
matches: ['unsplash'],
|
||||
type: 'card',
|
||||
replaceArg: 'embed',
|
||||
params: ['url']
|
||||
replaceArg: 'image',
|
||||
params: ['searchTerm'],
|
||||
payload: {
|
||||
imageSelector: 'unsplash'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Vimeo',
|
||||
|
@ -71,4 +71,11 @@
|
||||
placeholder="Type caption for image (optional)"
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{#if imageSelector}}
|
||||
{{component imageSelector
|
||||
searchTerm=payload.searchTerm
|
||||
select=(action "selectFromImageSelector")
|
||||
close=(action "closeImageSelector")}}
|
||||
{{/if}}
|
||||
{{/koenig-card}}
|
||||
|
Loading…
Reference in New Issue
Block a user