2018-06-07 13:34:50 +03:00
|
|
|
import Component from '@ember/component';
|
|
|
|
import layout from '../templates/components/koenig-card-embed';
|
2018-06-13 17:19:24 +03:00
|
|
|
import noframe from 'noframe.js';
|
2018-06-07 13:34:50 +03:00
|
|
|
import {NO_CURSOR_MOVEMENT} from './koenig-editor';
|
|
|
|
import {isBlank} from '@ember/utils';
|
|
|
|
import {run} from '@ember/runloop';
|
|
|
|
import {inject as service} from '@ember/service';
|
|
|
|
import {set} from '@ember/object';
|
|
|
|
import {task} from 'ember-concurrency';
|
|
|
|
|
|
|
|
export default Component.extend({
|
|
|
|
ajax: service(),
|
|
|
|
ghostPaths: service(),
|
|
|
|
|
|
|
|
layout,
|
|
|
|
|
|
|
|
// attrs
|
|
|
|
payload: null,
|
|
|
|
isSelected: false,
|
|
|
|
isEditing: false,
|
|
|
|
|
|
|
|
// internal properties
|
|
|
|
hasError: false,
|
|
|
|
|
|
|
|
// closure actions
|
|
|
|
selectCard() {},
|
|
|
|
deselectCard() {},
|
|
|
|
editCard() {},
|
|
|
|
saveCard() {},
|
2018-06-12 20:08:27 +03:00
|
|
|
deleteCard() {},
|
|
|
|
moveCursorToNextSection() {},
|
|
|
|
moveCursorToPrevSection() {},
|
|
|
|
addParagraphAfterCard() {},
|
2018-06-07 13:34:50 +03:00
|
|
|
|
|
|
|
init() {
|
|
|
|
this._super(...arguments);
|
|
|
|
if (this.payload.url && !this.payload.html) {
|
|
|
|
this.convertUrl.perform(this.payload.url);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
didInsertElement() {
|
|
|
|
this._super(...arguments);
|
2018-06-13 17:19:24 +03:00
|
|
|
this._populateIframe();
|
2018-06-13 13:14:34 +03:00
|
|
|
this._focusInput();
|
2018-06-07 13:34:50 +03:00
|
|
|
},
|
|
|
|
|
2018-06-13 17:19:24 +03:00
|
|
|
willDestroyElement() {
|
|
|
|
this._super(...arguments);
|
|
|
|
|
|
|
|
run.cancel(this._resizeDebounce);
|
|
|
|
|
|
|
|
if (this._iframeMutationObserver) {
|
|
|
|
this._iframeMutationObserver.disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
window.removeEventListener('resize', this._windowResizeHandler);
|
|
|
|
},
|
|
|
|
|
2018-06-07 13:34:50 +03:00
|
|
|
actions: {
|
|
|
|
onDeselect() {
|
|
|
|
if (this.payload.url && !this.payload.html && !this.hasError) {
|
|
|
|
this.convertUrl.perform(this.payload.url);
|
|
|
|
} else {
|
|
|
|
this._deleteIfEmpty();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
updateUrl(event) {
|
|
|
|
let url = event.target.value;
|
|
|
|
set(this.payload, 'url', url);
|
|
|
|
},
|
|
|
|
|
|
|
|
urlKeydown(event) {
|
|
|
|
if (event.key === 'Enter') {
|
|
|
|
event.preventDefault();
|
|
|
|
this.convertUrl.perform(this.payload.url);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.key === 'Escape') {
|
|
|
|
this.deleteCard();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
updateCaption(caption) {
|
|
|
|
set(this.payload, 'caption', caption);
|
|
|
|
this.saveCard(this.payload, false);
|
|
|
|
},
|
|
|
|
|
|
|
|
retry() {
|
|
|
|
this.set('hasError', false);
|
|
|
|
},
|
|
|
|
|
|
|
|
insertAsLink() {
|
|
|
|
this.editor.run((postEditor) => {
|
|
|
|
let {builder} = postEditor;
|
|
|
|
let cardSection = this.env.postModel;
|
|
|
|
let p = builder.createMarkupSection('p');
|
|
|
|
let link = builder.createMarkup('a', {href: this.payload.url});
|
|
|
|
|
|
|
|
postEditor.replaceSection(cardSection, p);
|
|
|
|
postEditor.insertTextWithMarkup(p.toRange().head, this.payload.url, [link]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
convertUrl: task(function* (url) {
|
|
|
|
if (isBlank(url)) {
|
|
|
|
this.deleteCard();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
let oembedEndpoint = this.ghostPaths.url.api('oembed');
|
|
|
|
let response = yield this.ajax.request(oembedEndpoint, {
|
|
|
|
data: {
|
|
|
|
url
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!response.html) {
|
|
|
|
throw 'No HTML returned';
|
|
|
|
}
|
|
|
|
|
|
|
|
set(this.payload, 'html', response.html);
|
|
|
|
set(this.payload, 'type', response.type);
|
|
|
|
this.saveCard(this.payload, false);
|
|
|
|
|
2018-06-13 17:19:24 +03:00
|
|
|
run.schedule('afterRender', this, this._populateIframe);
|
2018-06-07 13:34:50 +03:00
|
|
|
} catch (err) {
|
|
|
|
this.set('hasError', true);
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
2018-06-13 13:14:34 +03:00
|
|
|
_focusInput() {
|
|
|
|
let urlInput = this.element.querySelector('[name="url"]');
|
|
|
|
|
|
|
|
if (urlInput) {
|
|
|
|
urlInput.focus();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-06-13 17:19:24 +03:00
|
|
|
_populateIframe() {
|
|
|
|
let iframe = this.element.querySelector('iframe');
|
|
|
|
if (iframe) {
|
|
|
|
iframe.contentWindow.document.open();
|
|
|
|
iframe.contentWindow.document.write(this.payload.html);
|
|
|
|
iframe.contentWindow.document.close();
|
|
|
|
|
|
|
|
iframe.contentDocument.body.style.display = 'flex';
|
|
|
|
iframe.contentDocument.body.style.margin = '0';
|
|
|
|
iframe.contentDocument.body.style.justifyContent = 'center';
|
|
|
|
|
|
|
|
let nestedIframe = iframe.contentDocument.body.firstChild;
|
|
|
|
if (nestedIframe.nodeName === 'IFRAME') {
|
|
|
|
noframe(nestedIframe, '[data-kg-embed]');
|
|
|
|
this._resizeIframe(iframe);
|
2018-06-07 13:34:50 +03:00
|
|
|
}
|
|
|
|
|
2018-06-13 17:19:24 +03:00
|
|
|
this._iframeResizeHandler = run.bind(this, this._resizeIframe, iframe);
|
|
|
|
this._iframeMutationObserver = this._createMutationObserver(
|
|
|
|
iframe.contentWindow.document,
|
|
|
|
this._iframeResizeHandler
|
|
|
|
);
|
|
|
|
|
|
|
|
this._setupWindowResizeHandler(iframe);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_createMutationObserver(target, callback) {
|
|
|
|
function addImageLoadListeners(mutation) {
|
|
|
|
function addImageLoadListener(element) {
|
|
|
|
if (element.complete === false) {
|
|
|
|
element.addEventListener('load', imageEventTriggered, false);
|
|
|
|
element.addEventListener('error', imageEventTriggered, false);
|
|
|
|
imageElements.push(element);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
|
|
|
|
addImageLoadListener(mutation.target);
|
|
|
|
} else if (mutation.type === 'childList') {
|
|
|
|
Array.prototype.forEach.call(
|
|
|
|
mutation.target.querySelectorAll('img'),
|
|
|
|
addImageLoadListener
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function removeFromElements(element) {
|
|
|
|
imageElements.splice(imageElements.indexOf(element), 1);
|
2018-06-07 13:34:50 +03:00
|
|
|
}
|
2018-06-13 17:19:24 +03:00
|
|
|
|
|
|
|
function removeImageLoadListener(element) {
|
|
|
|
element.removeEventListener('load', imageEventTriggered, false);
|
|
|
|
element.removeEventListener('error', imageEventTriggered, false);
|
|
|
|
removeFromElements(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
function imageEventTriggered(event) {
|
|
|
|
removeImageLoadListener(event.target);
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
|
|
|
|
function mutationObserved(mutations) {
|
|
|
|
callback();
|
|
|
|
|
|
|
|
// deal with async image loads when tags are injected into the page
|
|
|
|
mutations.forEach(addImageLoadListeners);
|
|
|
|
}
|
|
|
|
|
|
|
|
function createMutationObserver(target) {
|
|
|
|
let config = {
|
|
|
|
attributes: true,
|
|
|
|
attributeOldValue: false,
|
|
|
|
characterData: true,
|
|
|
|
characterDataOldValue: false,
|
|
|
|
childList: true,
|
|
|
|
subtree: true
|
|
|
|
};
|
|
|
|
|
|
|
|
let observer = new MutationObserver(mutationObserved);
|
|
|
|
observer.observe(target, config); // eslint-disable-line ghost/ember/no-observers
|
|
|
|
return observer;
|
|
|
|
}
|
|
|
|
|
|
|
|
let imageElements = [];
|
|
|
|
let observer = createMutationObserver(target);
|
|
|
|
|
|
|
|
return {
|
|
|
|
disconnect() {
|
|
|
|
if ('disconnect' in observer) {
|
|
|
|
observer.disconnect(); // eslint-disable-line ghost/ember/no-observers
|
|
|
|
imageElements.forEach(removeImageLoadListener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
_resizeIframe(iframe) {
|
|
|
|
this._resizeDebounce = run.debounce(this, this.__debouncedResizeIframe, iframe, 66);
|
|
|
|
},
|
|
|
|
|
|
|
|
__debouncedResizeIframe(iframe) {
|
|
|
|
iframe.style.height = null;
|
|
|
|
let height = iframe.contentDocument.scrollingElement.scrollHeight;
|
|
|
|
iframe.style.height = `${height}px`;
|
|
|
|
},
|
|
|
|
|
|
|
|
_setupWindowResizeHandler(iframe) {
|
|
|
|
this._windowResizeHandler = run.bind(this, this._resizeIframe, iframe);
|
|
|
|
window.addEventListener('resize', this._windowResizeHandler, {passive: true});
|
2018-06-07 13:34:50 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
_deleteIfEmpty() {
|
|
|
|
if (isBlank(this.payload.html) && !this.convertUrl.isRunning && !this.hasError) {
|
|
|
|
this.deleteCard(NO_CURSOR_MOVEMENT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|