🐛 Fixed pasting newlines in post titles (#15794)

fixes https://github.com/TryGhost/Team/issues/2193

- When pasting a title with a newline, we now trim the string and clear newslines before pasting.
- When sending the slug to the backend to generate a unique slug, we now sluggify it in the frontend before adding it to the URL to prevent issues with unsupported characters (causing possible routing problems in Pro).
This commit is contained in:
Simon Backx 2022-11-10 14:43:15 +01:00 committed by GitHub
parent 23c29d0674
commit 7c3d75ade7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 4 deletions

View File

@ -32,6 +32,7 @@
{{on "blur" (fn (mut this.titleIsFocused) false)}}
{{on "mouseover" (fn (mut this.titleIsHovered) true)}}
{{on "mouseleave" (fn (mut this.titleIsHovered) false)}}
{{on "paste" this.cleanPastedTitle}}
data-test-editor-title-input={{true}}
/>

View File

@ -56,6 +56,20 @@ export default class GhKoenigEditorReactComponent extends Component {
this.args.onTitleChange?.(event.target.value);
}
@action
cleanPastedTitle(event) {
const pastedText = (event.clipboardData || window.clipboardData).getData('text');
if (!pastedText) {
return;
}
event.preventDefault();
const cleanValue = pastedText.replace(/(\n|\r)+/g, ' ').trim();
document.execCommand('insertText', false, cleanValue);
}
@action
focusTitle() {
this.titleElement.focus();

View File

@ -32,6 +32,7 @@
{{on "blur" (fn (mut this.titleIsFocused) false)}}
{{on "mouseover" (fn (mut this.titleIsHovered) true)}}
{{on "mouseleave" (fn (mut this.titleIsHovered) false)}}
{{on "paste" this.cleanPastedTitle}}
data-test-editor-title-input={{true}}
/>

View File

@ -43,6 +43,20 @@ export default class GhKoenigEditorComponent extends Component {
this.args.onTitleChange?.(event.target.value);
}
@action
cleanPastedTitle(event) {
const pastedText = (event.clipboardData || window.clipboardData).getData('text');
if (!pastedText) {
return;
}
event.preventDefault();
const cleanValue = pastedText.replace(/(\n|\r)+/g, ' ').trim();
document.execCommand('insertText', false, cleanValue);
}
@action
focusTitle() {
this.titleElement.focus();

View File

@ -1,6 +1,7 @@
import RSVP from 'rsvp';
import Service, {inject as service} from '@ember/service';
import classic from 'ember-classic-decorator';
import {slugify} from '@tryghost/string';
const {resolve} = RSVP;
@ -16,7 +17,8 @@ export default class SlugGeneratorService extends Service {
return resolve('');
}
url = this.get('ghostPaths.url').api('slugs', slugType, encodeURIComponent(textToSlugify));
// We already do a partial slugify at the client side to prevent issues with Pro returning a 404 page because of invalid (encoded) characters (a newline, %0A, for example)
url = this.get('ghostPaths.url').api('slugs', slugType, encodeURIComponent(slugify(textToSlugify)));
return this.ajax.request(url).then((response) => {
let [firstSlug] = response.slugs;

View File

@ -42,7 +42,7 @@ describe('Integration: Service: slug-generator', function () {
it('calls correct endpoint and returns correct data', function (done) {
let rawSlug = 'a test post';
stubSlugEndpoint(server, 'post', rawSlug);
stubSlugEndpoint(server, 'post', 'a-test-post');
let service = this.owner.lookup('service:slug-generator');