mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
🐝 Strip HTML from title (#665)
closes https://github.com/TryGhost/Ghost/issues/8353 - if a user pastes or inserts HTML into the title in some other way (modifying the dom, having a plugin mutate the dom, etc) then strip the HTML and insure that the title is always unstyled and plain text
This commit is contained in:
parent
535f24545c
commit
99000a74fa
3 changed files with 48 additions and 15 deletions
|
@ -115,12 +115,19 @@ export default Component.extend({
|
||||||
title.addClass('no-content');
|
title.addClass('no-content');
|
||||||
}
|
}
|
||||||
|
|
||||||
let {textContent} = title[0]; // eslint-disable-line
|
// there is no consistency in how characters like nbsp and zwd are handled across browsers
|
||||||
// // sanity check if there is formatting reset it.
|
// so we replace every whitespace character with a ' '
|
||||||
// if (title[0].innerHTML !== textContent && title[0].innerHTML) {
|
// note: this means that we can't have tabs in the title.
|
||||||
// title[0].innerHTML = textContent;
|
let textContent = title[0].textContent.replace(/\s/g, ' ');
|
||||||
// // todo: retain the range position.
|
let innerHTML = title[0].innerHTML.replace(/( |\s)/g, ' ');
|
||||||
// }
|
|
||||||
|
// sanity check if there is formatting reset it.
|
||||||
|
if (innerHTML && innerHTML !== textContent) {
|
||||||
|
// run in next runloop so that we don't get stuck in infinite loops.
|
||||||
|
run.next(() => {
|
||||||
|
title[0].innerHTML = textContent;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.get('val') !== textContent) {
|
if (this.get('val') !== textContent) {
|
||||||
this.set('_cachedVal', textContent);
|
this.set('_cachedVal', textContent);
|
||||||
|
@ -211,14 +218,12 @@ export default Component.extend({
|
||||||
title.focus();
|
title.focus();
|
||||||
let selection = window.getSelection();
|
let selection = window.getSelection();
|
||||||
|
|
||||||
window.requestAnimationFrame(() => {
|
run.next(() => {
|
||||||
run.join(() => {
|
|
||||||
if (selection.modify) {
|
if (selection.modify) {
|
||||||
for (let i = 0; i < offset; i++) {
|
for (let i = 0; i < offset; i++) {
|
||||||
selection.modify('move', 'forward', 'character');
|
selection.modify('move', 'forward', 'character');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {invalidateSession, authenticateSession} from 'ghost-admin/tests/helpers/
|
||||||
import Mirage from 'ember-cli-mirage';
|
import Mirage from 'ember-cli-mirage';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import testSelector from 'ember-test-selectors';
|
import testSelector from 'ember-test-selectors';
|
||||||
import {titleRendered} from '../helpers/editor-helpers';
|
import {titleRendered, replaceTitleHTML} from '../helpers/editor-helpers';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
describe('Acceptance: Editor', function() {
|
describe('Acceptance: Editor', function() {
|
||||||
|
@ -347,7 +347,7 @@ describe('Acceptance: Editor', function() {
|
||||||
).to.match(/Title cannot be longer than 150 characters/);
|
).to.match(/Title cannot be longer than 150 characters/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('if title is blank it correctly shows the placeholder', async function () {
|
it('inserts a placeholder if the title is blank', async function () {
|
||||||
server.createList('post', 1);
|
server.createList('post', 1);
|
||||||
|
|
||||||
// post id 1 is a draft, checking for draft behaviour now
|
// post id 1 is a draft, checking for draft behaviour now
|
||||||
|
@ -369,6 +369,22 @@ describe('Acceptance: Editor', function() {
|
||||||
expect(title.hasClass('no-content')).to.be.false;
|
expect(title.hasClass('no-content')).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes HTML from the title.', async function () {
|
||||||
|
server.createList('post', 1);
|
||||||
|
|
||||||
|
// post id 1 is a draft, checking for draft behaviour now
|
||||||
|
await visit('/editor/1');
|
||||||
|
|
||||||
|
expect(currentURL(), 'currentURL')
|
||||||
|
.to.equal('/editor/1');
|
||||||
|
|
||||||
|
titleRendered();
|
||||||
|
|
||||||
|
let title = find('#gh-editor-title div');
|
||||||
|
await replaceTitleHTML('<div>TITLE 	    TEST</div> ');
|
||||||
|
expect(title.html()).to.equal('TITLE TEST ');
|
||||||
|
});
|
||||||
|
|
||||||
it('renders first countdown notification before scheduled time', async function () {
|
it('renders first countdown notification before scheduled time', async function () {
|
||||||
let clock = sinon.useFakeTimers(moment().valueOf());
|
let clock = sinon.useFakeTimers(moment().valueOf());
|
||||||
let compareDate = moment().tz('Etc/UTC').add(4, 'minutes');
|
let compareDate = moment().tz('Etc/UTC').add(4, 'minutes');
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import run from 'ember-runloop';
|
||||||
|
import wait from 'ember-test-helpers/wait';
|
||||||
|
import {findWithAssert} from 'ember-native-dom-helpers';
|
||||||
|
|
||||||
// polls the editor until it's started.
|
// polls the editor until it's started.
|
||||||
export function editorRendered() {
|
export function editorRendered() {
|
||||||
return Ember.Test.promise(function (resolve) { // eslint-disable-line
|
return Ember.Test.promise(function (resolve) { // eslint-disable-line
|
||||||
|
@ -29,6 +33,14 @@ export function titleRendered() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replaces the title text content with HTML and returns once the HTML has been placed.
|
||||||
|
// takes into account converting to plaintext.
|
||||||
|
export function replaceTitleHTML(HTML) {
|
||||||
|
let el = findWithAssert('#gh-editor-title div');
|
||||||
|
run(() => el.innerHTML = HTML);
|
||||||
|
return (window.wait || wait)();
|
||||||
|
}
|
||||||
|
|
||||||
// simulates text inputs into the editor, unfortunately the helper Ember helper functions
|
// simulates text inputs into the editor, unfortunately the helper Ember helper functions
|
||||||
// don't work on content editable so we have to manipuate the text input event manager
|
// don't work on content editable so we have to manipuate the text input event manager
|
||||||
// in mobiledoc-kit directly. This is a private API.
|
// in mobiledoc-kit directly. This is a private API.
|
||||||
|
|
Loading…
Add table
Reference in a new issue