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:
Kevin Ansfield 2018-08-09 17:55:11 +01:00
parent 9a81a80706
commit 4463f975e3
14 changed files with 96 additions and 40 deletions

View File

@ -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');
},

View File

@ -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]);

View File

@ -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) {

View File

@ -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();
},

View File

@ -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);
}
},

View File

@ -28,7 +28,7 @@
{{#if _showUnsplash}}
{{gh-unsplash
insert=(action "addUnsplashPhoto")
select=(action "addUnsplashPhoto")
close=(action (toggle "_showUnsplash" this))
}}
{{/if}}

View File

@ -23,7 +23,7 @@
{{#if _showUnsplash}}
{{gh-unsplash
insert=(action "insertUnsplashPhoto")
select=(action "insertUnsplashPhoto")
close=(action "toggleUnsplash")}}
{{/if}}

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
},

View File

@ -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();

View File

@ -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];
});

View File

@ -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',

View File

@ -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}}