0
Fork 0
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:
Ryan McCarvill 2017-04-24 23:37:30 +12:00 committed by Kevin Ansfield
parent 535f24545c
commit 99000a74fa
3 changed files with 48 additions and 15 deletions

View file

@ -115,12 +115,19 @@ export default Component.extend({
title.addClass('no-content');
}
let {textContent} = title[0]; // eslint-disable-line
// // sanity check if there is formatting reset it.
// if (title[0].innerHTML !== textContent && title[0].innerHTML) {
// title[0].innerHTML = textContent;
// // todo: retain the range position.
// }
// there is no consistency in how characters like nbsp and zwd are handled across browsers
// so we replace every whitespace character with a ' '
// note: this means that we can't have tabs in the title.
let textContent = title[0].textContent.replace(/\s/g, ' ');
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) {
this.set('_cachedVal', textContent);
@ -211,14 +218,12 @@ export default Component.extend({
title.focus();
let selection = window.getSelection();
window.requestAnimationFrame(() => {
run.join(() => {
run.next(() => {
if (selection.modify) {
for (let i = 0; i < offset; i++) {
selection.modify('move', 'forward', 'character');
}
}
});
});
}
});

View file

@ -12,7 +12,7 @@ import {invalidateSession, authenticateSession} from 'ghost-admin/tests/helpers/
import Mirage from 'ember-cli-mirage';
import sinon from 'sinon';
import testSelector from 'ember-test-selectors';
import {titleRendered} from '../helpers/editor-helpers';
import {titleRendered, replaceTitleHTML} from '../helpers/editor-helpers';
import moment from 'moment';
describe('Acceptance: Editor', function() {
@ -347,7 +347,7 @@ describe('Acceptance: Editor', function() {
).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);
// 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;
});
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&nbsp;&#09;&nbsp;&thinsp;&ensp;&emsp;TEST</div>&nbsp;');
expect(title.html()).to.equal('TITLE TEST ');
});
it('renders first countdown notification before scheduled time', async function () {
let clock = sinon.useFakeTimers(moment().valueOf());
let compareDate = moment().tz('Etc/UTC').add(4, 'minutes');

View file

@ -1,5 +1,9 @@
import Ember from 'ember';
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.
export function editorRendered() {
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
// 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.