0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Koenig - Auto-convert URLs pasted on blank lines to embed cards

refs https://github.com/TryGhost/Ghost/issues/9724
- if a URL is pasted in a blank paragraph, insert an embed card configured to switch immediately to a link if the embed fails
- if <kbd>Shift</kbd> is pressed when pasting insert a linked URL with no auto-embed
- added `payload.linkOnError` handling to the embed card
  - if that option is set, immediately convert the embed card section to a linked URL on embed failure
  - skip adding an undo step when auto-converting to a URL so that no undo loop is created. Without this an undo would convert from link to embed card which would automatically look up the url then convert back to a link meaning it's impossible to undo back past the URL paste
  - ensure that the cursor position doesn't jump if the user has continued writing whilst the oembed lookup is in progress
This commit is contained in:
Kevin Ansfield 2018-08-02 13:09:32 +01:00
parent b46d60b820
commit 54cc17707f
2 changed files with 52 additions and 6 deletions

View file

@ -104,7 +104,9 @@ export default Component.extend({
this.set('hasError', false);
},
insertAsLink() {
insertAsLink(options = {linkOnError: false}) {
let {range} = this.editor;
this.editor.run((postEditor) => {
let {builder} = postEditor;
let cardSection = this.env.postModel;
@ -113,6 +115,20 @@ export default Component.extend({
postEditor.replaceSection(cardSection, p);
postEditor.insertTextWithMarkup(p.toRange().head, this.payload.url, [link]);
// if a user is typing further on in the doc (possible if embed
// was created automatically via paste of URL) then return the
// cursor so the card->link change doesn't cause a cursor jump
if (range.headSection !== cardSection) {
postEditor.setRange(range);
}
// avoid adding an extra undo step when automatically creating
// link after an error so that an Undo after pasting a URL
// doesn't get stuck in a loop going through link->embed->link
if (options.linkOnError) {
postEditor.cancelSnapshot();
}
});
}
},
@ -135,12 +151,17 @@ export default Component.extend({
throw 'No HTML returned';
}
set(this.payload.linkOnError, undefined);
set(this.payload, 'html', response.html);
set(this.payload, 'type', response.type);
this.saveCard(this.payload, false);
run.schedule('afterRender', this, this._populateIframe);
} catch (err) {
if (this.payload.linkOnError) {
this.send('insertAsLink', {linkOnError: true});
return;
}
this.set('hasError', true);
}
}),

View file

@ -176,7 +176,6 @@ function insertImageCards(files, postEditor) {
export default Component.extend({
layout,
tagName: 'article',
classNames: ['koenig-editor', 'w-100', 'flex-grow', 'relative', 'center', 'mb0', 'mt0'],
@ -784,14 +783,40 @@ export default Component.extend({
let range = editor.range;
let {html, text} = getContentFromPasteEvent(event);
// if a URL is pasted and we have a selection, make that selection a link
if (range && !range.isCollapsed && range.headSection === range.tailSection && range.headSection.isMarkerable) {
if (text && validator.isURL(text)) {
// if we have a text selection, make that selection a link
if (range && !range.isCollapsed && range.headSection === range.tailSection && range.headSection.isMarkerable) {
let linkMarkup = editor.builder.createMarkup('a', {href: text});
editor.run((postEditor) => {
postEditor.addMarkupToRange(range, linkMarkup);
});
editor.selectRange(range.tail);
// prevent mobiledoc's default paste event handler firing
event.preventDefault();
event.stopImmediatePropagation();
return;
}
// if there's no selection and cursor is on an empty paragraph,
// insert the url as an embed card, unless SHIFT is pressed. Setting
// the `linkOnError` option results in an immediate switch to a
// plain link if the embed fails for any reason (eg, unknown provider)
if (range && range.isCollapsed && range.headSection.isBlank && !range.headSection.isListItem) {
if (!this._modifierKeys.shift) {
editor.run((postEditor) => {
let payload = {url: text, linkOnError: true};
let card = postEditor.builder.createCardSection('embed', payload);
postEditor.replaceSection(range.headSection, card);
});
} else {
// ensure the pasted URL is still auto-linked when Shift is pressed
editor.run((postEditor) => {
let linkMarkup = editor.builder.createMarkup('a', {href: text});
postEditor.insertTextWithMarkup(range.head, text, [linkMarkup]);
});
}
// prevent mobiledoc's default paste event handler firing
event.preventDefault();
event.stopImmediatePropagation();
@ -802,7 +827,7 @@ export default Component.extend({
// if plain text is pasted we run it through our markdown parser so that
// we get better output than mobiledoc's default text parsing and we can
// provide an easier MD->Mobiledoc conversion route
// NOTE: will not work in IE/Edge which only ever expose `html`
// NOTE: will not work in Edge which only ever exposes `html`
if (text && !html && !this._modifierKeys.shift) {
// prevent mobiledoc's default paste event handler firing
event.preventDefault();