2015-09-28 14:01:16 -04:00
|
|
|
import componentTest from 'helpers/component-test';
|
2016-02-18 12:42:15 -05:00
|
|
|
import { withPluginApi } from 'discourse/lib/plugin-api';
|
2015-09-28 14:01:16 -04:00
|
|
|
|
|
|
|
moduleForComponent('d-editor', {integration: true});
|
|
|
|
|
|
|
|
componentTest('preview updates with markdown', {
|
|
|
|
template: '{{d-editor value=value}}',
|
|
|
|
|
|
|
|
test(assert) {
|
|
|
|
assert.ok(this.$('.d-editor-button-bar').length);
|
|
|
|
fillIn('.d-editor-input', 'hello **world**');
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), 'hello **world**');
|
|
|
|
assert.equal(this.$('.d-editor-preview').html().trim(), '<p>hello <strong>world</strong></p>');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-10-20 12:09:59 -04:00
|
|
|
componentTest('preview sanitizes HTML', {
|
|
|
|
template: '{{d-editor value=value}}',
|
|
|
|
|
|
|
|
test(assert) {
|
2017-06-08 18:02:30 -04:00
|
|
|
fillIn('.d-editor-input', `"><svg onload="prompt(/xss/)"></svg>`);
|
2015-10-20 12:09:59 -04:00
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('.d-editor-preview').html().trim(), '<p>\"></p>');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
componentTest('updating the value refreshes the preview', {
|
|
|
|
template: '{{d-editor value=value}}',
|
|
|
|
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2015-09-28 14:01:16 -04:00
|
|
|
this.set('value', 'evil trout');
|
|
|
|
},
|
|
|
|
|
|
|
|
test(assert) {
|
|
|
|
assert.equal(this.$('.d-editor-preview').html().trim(), '<p>evil trout</p>');
|
|
|
|
|
|
|
|
andThen(() => this.set('value', 'zogstrip'));
|
|
|
|
andThen(() => assert.equal(this.$('.d-editor-preview').html().trim(), '<p>zogstrip</p>'));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-11-06 16:44:38 -05:00
|
|
|
function jumpEnd(textarea) {
|
|
|
|
textarea.selectionStart = textarea.value.length;
|
|
|
|
textarea.selectionEnd = textarea.value.length;
|
|
|
|
return textarea;
|
|
|
|
}
|
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
function testCase(title, testFunc) {
|
|
|
|
componentTest(title, {
|
|
|
|
template: '{{d-editor value=value}}',
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2015-09-28 14:01:16 -04:00
|
|
|
this.set('value', 'hello world.');
|
|
|
|
},
|
|
|
|
test(assert) {
|
2015-11-06 16:44:38 -05:00
|
|
|
const textarea = jumpEnd(this.$('textarea.d-editor-input')[0]);
|
2015-09-28 14:01:16 -04:00
|
|
|
testFunc.call(this, assert, textarea);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-05-05 12:59:34 -04:00
|
|
|
function composerTestCase(title, testFunc) {
|
|
|
|
componentTest(title, {
|
|
|
|
template: '{{d-editor value=value composerEvents=true}}',
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2017-05-05 12:59:34 -04:00
|
|
|
this.set('value', 'hello world.');
|
|
|
|
},
|
|
|
|
test(assert) {
|
|
|
|
const textarea = jumpEnd(this.$('textarea.d-editor-input')[0]);
|
|
|
|
testFunc.call(this, assert, textarea);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-03-10 06:43:08 -05:00
|
|
|
testCase(`selecting the space before a word`, function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 5;
|
|
|
|
textarea.selectionEnd = 7;
|
|
|
|
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello **w**orld.`);
|
|
|
|
assert.equal(textarea.selectionStart, 8);
|
|
|
|
assert.equal(textarea.selectionEnd, 9);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-24 13:41:56 -05:00
|
|
|
testCase(`selecting the space after a word`, function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 6;
|
|
|
|
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `**hello** world.`);
|
|
|
|
assert.equal(textarea.selectionStart, 2);
|
|
|
|
assert.equal(textarea.selectionEnd, 7);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
testCase(`bold button with no selection`, function(assert, textarea) {
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
const example = I18n.t(`composer.bold_text`);
|
|
|
|
assert.equal(this.get('value'), `hello world.**${example}**`);
|
|
|
|
assert.equal(textarea.selectionStart, 14);
|
|
|
|
assert.equal(textarea.selectionEnd, 14 + example.length);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`bold button with a selection`, function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 11;
|
|
|
|
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello **world**.`);
|
|
|
|
assert.equal(textarea.selectionStart, 8);
|
|
|
|
assert.equal(textarea.selectionEnd, 13);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), 'hello world.');
|
|
|
|
assert.equal(textarea.selectionStart, 6);
|
|
|
|
assert.equal(textarea.selectionEnd, 11);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`bold with a multiline selection`, function (assert, textarea) {
|
|
|
|
this.set('value', "hello\n\nworld\n\ntest.");
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 12;
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `**hello**\n\n**world**\n\ntest.`);
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 20);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bold`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello\n\nworld\n\ntest.`);
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 12);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`italic button with no selection`, function(assert, textarea) {
|
|
|
|
click(`button.italic`);
|
|
|
|
andThen(() => {
|
|
|
|
const example = I18n.t(`composer.italic_text`);
|
2016-01-18 14:54:37 -05:00
|
|
|
assert.equal(this.get('value'), `hello world._${example}_`);
|
2015-09-28 14:01:16 -04:00
|
|
|
|
|
|
|
assert.equal(textarea.selectionStart, 13);
|
|
|
|
assert.equal(textarea.selectionEnd, 13 + example.length);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`italic button with a selection`, function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 11;
|
|
|
|
|
|
|
|
click(`button.italic`);
|
|
|
|
andThen(() => {
|
2016-01-18 14:54:37 -05:00
|
|
|
assert.equal(this.get('value'), `hello _world_.`);
|
2015-09-28 14:01:16 -04:00
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 12);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.italic`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), 'hello world.');
|
|
|
|
assert.equal(textarea.selectionStart, 6);
|
|
|
|
assert.equal(textarea.selectionEnd, 11);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`italic with a multiline selection`, function (assert, textarea) {
|
|
|
|
this.set('value', "hello\n\nworld\n\ntest.");
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 12;
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.italic`);
|
|
|
|
andThen(() => {
|
2016-01-18 14:54:37 -05:00
|
|
|
assert.equal(this.get('value'), `_hello_\n\n_world_\n\ntest.`);
|
2015-09-28 14:01:16 -04:00
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 16);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.italic`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello\n\nworld\n\ntest.`);
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 12);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase('link modal (cancel)', function(assert) {
|
|
|
|
assert.equal(this.$('.insert-link.hidden').length, 1);
|
|
|
|
|
|
|
|
click('button.link');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('.insert-link.hidden').length, 0);
|
|
|
|
});
|
|
|
|
|
|
|
|
click('.insert-link button.btn-danger');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('.insert-link.hidden').length, 1);
|
|
|
|
assert.equal(this.get('value'), 'hello world.');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-17 13:26:34 -05:00
|
|
|
testCase('link modal (simple link)', function(assert, textarea) {
|
2015-09-28 14:01:16 -04:00
|
|
|
click('button.link');
|
2016-04-08 16:13:29 -04:00
|
|
|
|
|
|
|
const url = 'http://eviltrout.com';
|
|
|
|
|
|
|
|
fillIn('.insert-link input.link-url', url);
|
2015-09-28 14:01:16 -04:00
|
|
|
click('.insert-link button.btn-primary');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('.insert-link.hidden').length, 1);
|
2016-04-08 16:13:29 -04:00
|
|
|
assert.equal(this.get('value'), `hello world.[${url}](${url})`);
|
2015-11-17 13:26:34 -05:00
|
|
|
assert.equal(textarea.selectionStart, 13);
|
2016-04-08 16:13:29 -04:00
|
|
|
assert.equal(textarea.selectionEnd, 13 + url.length);
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-03-10 02:25:02 -05:00
|
|
|
testCase('link modal auto http addition', function(assert) {
|
|
|
|
click('button.link');
|
2016-04-08 16:13:29 -04:00
|
|
|
fillIn('.insert-link input.link-url', 'sam.com');
|
2016-03-10 02:25:02 -05:00
|
|
|
click('.insert-link button.btn-primary');
|
|
|
|
andThen(() => {
|
2016-04-08 16:13:29 -04:00
|
|
|
assert.equal(this.get('value'), `hello world.[sam.com](http://sam.com)`);
|
2016-03-10 02:25:02 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-07 07:33:24 -05:00
|
|
|
testCase('link modal (simple link) with selected text', function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 12;
|
|
|
|
|
|
|
|
click('button.link');
|
2018-01-23 15:32:12 -05:00
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('input.link-text')[0].value, 'hello world.');
|
|
|
|
});
|
2016-04-08 16:13:29 -04:00
|
|
|
fillIn('.insert-link input.link-url', 'http://eviltrout.com');
|
2015-11-07 07:33:24 -05:00
|
|
|
click('.insert-link button.btn-primary');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('.insert-link.hidden').length, 1);
|
|
|
|
assert.equal(this.get('value'), '[hello world.](http://eviltrout.com)');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
testCase('link modal (link with description)', function(assert) {
|
|
|
|
click('button.link');
|
2016-04-08 16:13:29 -04:00
|
|
|
fillIn('.insert-link input.link-url', 'http://eviltrout.com');
|
|
|
|
fillIn('.insert-link input.link-text', 'evil trout');
|
2015-09-28 14:01:16 -04:00
|
|
|
click('.insert-link button.btn-primary');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.$('.insert-link.hidden').length, 1);
|
|
|
|
assert.equal(this.get('value'), 'hello world.[evil trout](http://eviltrout.com)');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-24 13:03:37 -05:00
|
|
|
componentTest('advanced code', {
|
|
|
|
template: '{{d-editor value=value}}',
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2016-06-26 14:30:45 -04:00
|
|
|
this.siteSettings.code_formatting_style = '4-spaces-indent';
|
2015-11-24 13:03:37 -05:00
|
|
|
this.set('value',
|
2016-08-22 21:51:01 -04:00
|
|
|
`
|
|
|
|
function xyz(x, y, z) {
|
2015-11-24 13:03:37 -05:00
|
|
|
if (y === z) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-08-22 21:51:01 -04:00
|
|
|
}
|
|
|
|
` );
|
2015-11-24 13:03:37 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
test(assert) {
|
|
|
|
const textarea = this.$('textarea.d-editor-input')[0];
|
2015-11-24 13:41:56 -05:00
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = textarea.value.length;
|
2015-11-24 13:03:37 -05:00
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
2016-08-22 21:51:01 -04:00
|
|
|
`
|
|
|
|
function xyz(x, y, z) {
|
2015-11-24 13:03:37 -05:00
|
|
|
if (y === z) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-08-22 21:51:01 -04:00
|
|
|
}
|
|
|
|
`
|
|
|
|
);
|
2015-11-24 13:03:37 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
componentTest('code button', {
|
|
|
|
template: '{{d-editor value=value}}',
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2016-06-26 14:30:45 -04:00
|
|
|
this.siteSettings.code_formatting_style = '4-spaces-indent';
|
2015-09-28 14:01:16 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
test(assert) {
|
2015-11-06 16:44:38 -05:00
|
|
|
const textarea = jumpEnd(this.$('textarea.d-editor-input')[0]);
|
2015-09-28 14:01:16 -04:00
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
2016-08-23 02:56:08 -04:00
|
|
|
assert.equal(this.get('value'),
|
|
|
|
` ${I18n.t('composer.code_text')}`
|
|
|
|
);
|
|
|
|
|
|
|
|
this.set('value', "first line\n\nsecond line\n\nthird line");
|
|
|
|
|
|
|
|
textarea.selectionStart = 11;
|
|
|
|
textarea.selectionEnd = 11;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
|
|
|
`first line
|
|
|
|
${I18n.t('composer.code_text')}
|
|
|
|
second line
|
|
|
|
|
|
|
|
third line`
|
|
|
|
);
|
|
|
|
|
|
|
|
this.set('value', "first line\n\nsecond line\n\nthird line");
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
|
|
|
`first line
|
|
|
|
|
|
|
|
second line
|
|
|
|
|
|
|
|
third line\`${I18n.t('composer.code_title')}\``
|
|
|
|
);
|
|
|
|
this.set('value', "first line\n\nsecond line\n\nthird line");
|
|
|
|
});
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 5;
|
|
|
|
textarea.selectionEnd = 5;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
|
|
|
`first\`${I18n.t('composer.code_title')}\` line
|
|
|
|
|
|
|
|
second line
|
|
|
|
|
|
|
|
third line`
|
|
|
|
);
|
2015-09-28 14:01:16 -04:00
|
|
|
this.set('value', "first line\n\nsecond line\n\nthird line");
|
|
|
|
});
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 10;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "first `line`\n\nsecond line\n\nthird line");
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 11);
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "first line\n\nsecond line\n\nthird line");
|
|
|
|
assert.equal(textarea.selectionStart, 6);
|
|
|
|
assert.equal(textarea.selectionEnd, 10);
|
|
|
|
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 23;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), " first line\n\n second line\n\nthird line");
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 31);
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "first line\n\nsecond line\n\nthird line");
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 23);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-08-22 21:51:01 -04:00
|
|
|
componentTest('code fences', {
|
|
|
|
template: '{{d-editor value=value}}',
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2016-08-22 21:51:01 -04:00
|
|
|
this.set('value', '');
|
|
|
|
},
|
|
|
|
|
|
|
|
test(assert) {
|
|
|
|
const textarea = jumpEnd(this.$('textarea.d-editor-input')[0]);
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
|
|
|
`\`\`\`
|
|
|
|
${I18n.t("composer.paste_code_text")}
|
2016-08-23 02:56:08 -04:00
|
|
|
\`\`\``
|
2016-08-22 21:51:01 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
assert.equal(textarea.selectionStart, 4);
|
|
|
|
assert.equal(textarea.selectionEnd, 27);
|
|
|
|
|
|
|
|
this.set('value', 'first line\nsecond line\nthird line');
|
|
|
|
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = textarea.value.length;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
|
|
|
`\`\`\`
|
|
|
|
first line
|
|
|
|
second line
|
|
|
|
third line
|
|
|
|
\`\`\`
|
|
|
|
`
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.equal(textarea.selectionStart, textarea.value.length);
|
|
|
|
assert.equal(textarea.selectionEnd, textarea.value.length);
|
|
|
|
|
|
|
|
this.set('value', 'first line\nsecond line\nthird line');
|
|
|
|
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
2016-08-23 02:56:08 -04:00
|
|
|
`\`${I18n.t('composer.code_title')}\`first line
|
2016-08-22 21:51:01 -04:00
|
|
|
second line
|
|
|
|
third line`
|
|
|
|
);
|
|
|
|
|
2016-08-23 02:56:08 -04:00
|
|
|
assert.equal(textarea.selectionStart, 1);
|
|
|
|
assert.equal(textarea.selectionEnd, I18n.t('composer.code_title').length + 1);
|
2016-08-22 21:51:01 -04:00
|
|
|
|
|
|
|
this.set('value', 'first line\nsecond line\nthird line');
|
|
|
|
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 10;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
2016-08-23 02:56:08 -04:00
|
|
|
`\`first line\`
|
2016-08-22 21:51:01 -04:00
|
|
|
second line
|
|
|
|
third line`
|
|
|
|
);
|
|
|
|
|
2016-08-23 02:56:08 -04:00
|
|
|
assert.equal(textarea.selectionStart, 1);
|
|
|
|
assert.equal(textarea.selectionEnd, 11);
|
2016-08-22 21:51:01 -04:00
|
|
|
|
|
|
|
this.set('value', 'first line\nsecond line\nthird line');
|
|
|
|
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 23;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'),
|
|
|
|
`\`\`\`
|
|
|
|
first line
|
|
|
|
second line
|
|
|
|
\`\`\`
|
|
|
|
third line`
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.equal(textarea.selectionStart, 30);
|
|
|
|
assert.equal(textarea.selectionEnd, 30);
|
|
|
|
|
|
|
|
this.set('value', 'first line\nsecond line\nthird line');
|
|
|
|
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 17;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.code');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `first \n\`\`\`\nline\nsecond\n\`\`\`\n line\nthird line`);
|
|
|
|
|
|
|
|
assert.equal(textarea.selectionStart, 27);
|
|
|
|
assert.equal(textarea.selectionEnd, 27);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2017-07-21 16:32:10 -04:00
|
|
|
componentTest("quote button - empty lines", {
|
|
|
|
template: '{{d-editor value=value composerEvents=true}}',
|
|
|
|
beforeEach() {
|
|
|
|
this.set('value', "one\n\ntwo\n\nthree");
|
|
|
|
},
|
|
|
|
test(assert) {
|
|
|
|
const textarea = jumpEnd(this.$('textarea.d-editor-input')[0]);
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.quote');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "> one\n> \n> two\n> \n> three");
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 25);
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.quote');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "one\n\ntwo\n\nthree");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-11-20 13:46:19 -05:00
|
|
|
componentTest("quote button - selecting empty lines", {
|
|
|
|
template: '{{d-editor value=value composerEvents=true}}',
|
|
|
|
beforeEach() {
|
|
|
|
this.set('value', "one\n\n\n\ntwo");
|
|
|
|
},
|
|
|
|
test(assert) {
|
|
|
|
const textarea = jumpEnd(this.$('textarea.d-editor-input')[0]);
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 10;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.quote');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "one\n\n\n> \n> two");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
testCase('quote button', function(assert, textarea) {
|
2017-06-27 13:32:20 -04:00
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
andThen(() => {
|
2017-06-27 13:32:20 -04:00
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 9;
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
|
2017-06-27 13:32:20 -04:00
|
|
|
click('button.quote');
|
2015-09-28 14:01:16 -04:00
|
|
|
andThen(() => {
|
2017-06-27 13:32:20 -04:00
|
|
|
assert.equal(this.get('value'), 'hello\n\n> wor\n\nld.');
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 12);
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
click('button.quote');
|
2017-06-27 13:32:20 -04:00
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
andThen(() => {
|
2017-06-27 13:32:20 -04:00
|
|
|
assert.equal(this.get('value'), 'hello\n\nwor\n\nld.');
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 10);
|
|
|
|
});
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 15;
|
|
|
|
textarea.selectionEnd = 15;
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
click('button.quote');
|
|
|
|
andThen(() => {
|
2017-06-27 13:32:20 -04:00
|
|
|
assert.equal(this.get('value'), 'hello\n\nwor\n\nld.\n\n> Blockquote');
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
2017-06-27 13:32:20 -04:00
|
|
|
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`bullet button with no selection`, function(assert, textarea) {
|
|
|
|
const example = I18n.t('composer.list_item');
|
|
|
|
|
|
|
|
click(`button.bullet`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello world.\n\n* ${example}`);
|
|
|
|
assert.equal(textarea.selectionStart, 14);
|
|
|
|
assert.equal(textarea.selectionEnd, 16 + example.length);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bullet`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello world.\n\n${example}`);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`bullet button with a selection`, function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 11;
|
|
|
|
|
|
|
|
click(`button.bullet`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello\n\n* world\n\n.`);
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 14);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bullet`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello\n\nworld\n\n.`);
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 12);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`bullet button with a multiple line selection`, function(assert, textarea) {
|
|
|
|
this.set('value', "* Hello\n\nWorld\n\nEvil");
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 20;
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bullet`);
|
|
|
|
andThen(() => {
|
2015-11-24 13:03:37 -05:00
|
|
|
assert.equal(this.get('value'), "Hello\n\nWorld\n\nEvil");
|
2015-09-28 14:01:16 -04:00
|
|
|
assert.equal(textarea.selectionStart, 0);
|
2015-11-24 13:03:37 -05:00
|
|
|
assert.equal(textarea.selectionEnd, 18);
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.bullet`);
|
|
|
|
andThen(() => {
|
2015-11-24 13:03:37 -05:00
|
|
|
assert.equal(this.get('value'), "* Hello\n\n* World\n\n* Evil");
|
2015-09-28 14:01:16 -04:00
|
|
|
assert.equal(textarea.selectionStart, 0);
|
2015-11-24 13:03:37 -05:00
|
|
|
assert.equal(textarea.selectionEnd, 24);
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`list button with no selection`, function(assert, textarea) {
|
|
|
|
const example = I18n.t('composer.list_item');
|
|
|
|
|
|
|
|
click(`button.list`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello world.\n\n1. ${example}`);
|
|
|
|
assert.equal(textarea.selectionStart, 14);
|
|
|
|
assert.equal(textarea.selectionEnd, 17 + example.length);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.list`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello world.\n\n${example}`);
|
|
|
|
assert.equal(textarea.selectionStart, 14);
|
|
|
|
assert.equal(textarea.selectionEnd, 14 + example.length);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`list button with a selection`, function(assert, textarea) {
|
|
|
|
textarea.selectionStart = 6;
|
|
|
|
textarea.selectionEnd = 11;
|
|
|
|
|
|
|
|
click(`button.list`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello\n\n1. world\n\n.`);
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 15);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.list`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), `hello\n\nworld\n\n.`);
|
|
|
|
assert.equal(textarea.selectionStart, 7);
|
|
|
|
assert.equal(textarea.selectionEnd, 12);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
testCase(`list button with line sequence`, function(assert, textarea) {
|
|
|
|
this.set('value', "Hello\n\nWorld\n\nEvil");
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
textarea.selectionStart = 0;
|
|
|
|
textarea.selectionEnd = 18;
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.list`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "1. Hello\n\n2. World\n\n3. Evil");
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 27);
|
|
|
|
});
|
|
|
|
|
|
|
|
click(`button.list`);
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), "Hello\n\nWorld\n\nEvil");
|
|
|
|
assert.equal(textarea.selectionStart, 0);
|
|
|
|
assert.equal(textarea.selectionEnd, 18);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-01-29 20:42:19 -05:00
|
|
|
componentTest('clicking the toggle-direction button toggles the direction', {
|
|
|
|
template: '{{d-editor value=value}}',
|
|
|
|
beforeEach() {
|
|
|
|
this.siteSettings.support_mixed_text_direction = true;
|
|
|
|
this.siteSettings.default_locale = "en";
|
|
|
|
},
|
|
|
|
|
|
|
|
test(assert) {
|
|
|
|
const textarea = this.$('textarea.d-editor-input');
|
|
|
|
click('button.toggle-direction');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(textarea.attr('dir'), 'rtl');
|
|
|
|
});
|
|
|
|
click('button.toggle-direction');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(textarea.attr('dir'), 'ltr');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-12-29 14:59:12 -05:00
|
|
|
testCase(`doesn't jump to bottom with long text`, function(assert, textarea) {
|
|
|
|
|
|
|
|
let longText = 'hello world.';
|
|
|
|
for (let i=0; i<8; i++) {
|
|
|
|
longText = longText + longText;
|
|
|
|
}
|
|
|
|
this.set('value', longText);
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
$(textarea).scrollTop(0);
|
|
|
|
textarea.selectionStart = 3;
|
|
|
|
textarea.selectionEnd = 3;
|
|
|
|
});
|
|
|
|
|
|
|
|
click('button.bold');
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal($(textarea).scrollTop(), 0, 'it stays scrolled up');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-02 16:05:40 -05:00
|
|
|
componentTest('emoji', {
|
|
|
|
template: '{{d-editor value=value}}',
|
2017-06-14 13:57:58 -04:00
|
|
|
beforeEach() {
|
2015-11-02 16:05:40 -05:00
|
|
|
// Test adding a custom button
|
2016-02-18 12:42:15 -05:00
|
|
|
withPluginApi('0.1', api => {
|
|
|
|
api.onToolbarCreate(toolbar => {
|
|
|
|
toolbar.addButton({
|
|
|
|
id: 'emoji',
|
|
|
|
group: 'extras',
|
|
|
|
icon: 'smile-o',
|
|
|
|
action: 'emoji'
|
|
|
|
});
|
2015-11-02 16:05:40 -05:00
|
|
|
});
|
|
|
|
});
|
|
|
|
this.set('value', 'hello world.');
|
|
|
|
},
|
|
|
|
test(assert) {
|
2015-11-06 16:44:38 -05:00
|
|
|
jumpEnd(this.$('textarea.d-editor-input')[0]);
|
2015-11-02 16:05:40 -05:00
|
|
|
click('button.emoji');
|
2015-09-28 14:01:16 -04:00
|
|
|
|
2017-07-21 13:42:46 -04:00
|
|
|
click('.emoji-picker .section[data-section="people"] button.emoji[title="grinning"]');
|
2015-11-02 16:05:40 -05:00
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), 'hello world.:grinning:');
|
|
|
|
});
|
|
|
|
}
|
2015-09-28 14:01:16 -04:00
|
|
|
});
|
2016-07-25 15:31:21 -04:00
|
|
|
|
2017-05-05 12:59:34 -04:00
|
|
|
testCase("replace-text event by default", function(assert) {
|
|
|
|
this.set('value', "red green blue");
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
this.container.lookup('app-events:main').trigger('composer:replace-text', 'green', 'yellow');
|
|
|
|
});
|
2016-07-25 15:31:21 -04:00
|
|
|
|
2017-05-05 12:59:34 -04:00
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), 'red green blue');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
composerTestCase("replace-text event for composer", function(assert) {
|
2016-07-25 15:31:21 -04:00
|
|
|
this.set('value', "red green blue");
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
this.container.lookup('app-events:main').trigger('composer:replace-text', 'green', 'yellow');
|
|
|
|
});
|
|
|
|
|
|
|
|
andThen(() => {
|
|
|
|
assert.equal(this.get('value'), 'red yellow blue');
|
|
|
|
});
|
|
|
|
});
|
2016-12-29 03:54:15 -05:00
|
|
|
|
2017-05-05 12:59:34 -04:00
|
|
|
|
2016-12-29 03:54:15 -05:00
|
|
|
(() => {
|
|
|
|
// Tests to check cursor/selection after replace-text event.
|
|
|
|
const BEFORE = 'red green blue';
|
|
|
|
const NEEDLE = 'green';
|
|
|
|
const REPLACE = 'yellow';
|
|
|
|
const AFTER = BEFORE.replace(NEEDLE, REPLACE);
|
|
|
|
|
|
|
|
const CASES = [
|
|
|
|
{
|
|
|
|
description: 'cursor at start remains there',
|
|
|
|
before: [0, 0],
|
|
|
|
after: [0, 0]
|
|
|
|
},{
|
|
|
|
description: 'cursor before needle becomes cursor before replacement',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE), 0],
|
|
|
|
after: [AFTER.indexOf(REPLACE), 0]
|
|
|
|
},{
|
|
|
|
description: 'cursor at needle start + 1 moves behind replacement',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE) + 1, 0],
|
|
|
|
after: [AFTER.indexOf(REPLACE) + REPLACE.length, 0]
|
|
|
|
},{
|
|
|
|
description: 'cursor at needle end - 1 stays behind replacement',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE) + NEEDLE.length - 1, 0],
|
|
|
|
after: [AFTER.indexOf(REPLACE) + REPLACE.length, 0]
|
|
|
|
},{
|
|
|
|
description: 'cursor behind needle becomes cursor behind replacement',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE) + NEEDLE.length, 0],
|
|
|
|
after: [AFTER.indexOf(REPLACE) + REPLACE.length, 0]
|
|
|
|
},{
|
|
|
|
description: 'cursor at end remains there',
|
|
|
|
before: [BEFORE.length, 0],
|
|
|
|
after: [AFTER.length, 0]
|
|
|
|
},{
|
|
|
|
description: 'selection spanning needle start becomes selection until replacement start',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE) - 1, 2],
|
|
|
|
after: [AFTER.indexOf(REPLACE) - 1, 1]
|
|
|
|
},{
|
|
|
|
description: 'selection spanning needle end becomes selection from replacement end',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE) + NEEDLE.length - 1, 2],
|
|
|
|
after: [AFTER.indexOf(REPLACE) + REPLACE.length, 1]
|
|
|
|
},{
|
|
|
|
description: 'selection spanning needle becomes selection spanning replacement',
|
|
|
|
before: [BEFORE.indexOf(NEEDLE) - 1, NEEDLE.length + 2],
|
|
|
|
after: [AFTER.indexOf(REPLACE) - 1, REPLACE.length + 2]
|
|
|
|
},{
|
|
|
|
description: 'complete selection remains complete',
|
|
|
|
before: [0, BEFORE.length],
|
|
|
|
after: [0, AFTER.length]
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
function setSelection(textarea, [start, len]) {
|
|
|
|
textarea.selectionStart = start;
|
|
|
|
textarea.selectionEnd = start + len;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getSelection(textarea) {
|
|
|
|
const start = textarea.selectionStart;
|
2016-12-29 04:05:07 -05:00
|
|
|
const end = textarea.selectionEnd;
|
2016-12-29 03:54:15 -05:00
|
|
|
return [start, end - start];
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatTextWithSelection(text, [start, len]) {
|
|
|
|
return [
|
|
|
|
'"',
|
|
|
|
text.substr(0, start),
|
|
|
|
'<',
|
|
|
|
text.substr(start, len),
|
|
|
|
'>',
|
|
|
|
text.substr(start+len),
|
|
|
|
'"',
|
|
|
|
].join('');
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < CASES.length; i++) {
|
|
|
|
const CASE = CASES[i];
|
2017-05-05 12:59:34 -04:00
|
|
|
composerTestCase(`replace-text event: ${CASE.description}`, function(assert, textarea) {
|
2016-12-29 03:54:15 -05:00
|
|
|
this.set('value', BEFORE);
|
|
|
|
setSelection(textarea, CASE.before);
|
|
|
|
andThen(() => {
|
|
|
|
this.container.lookup('app-events:main').trigger('composer:replace-text', 'green', 'yellow');
|
|
|
|
});
|
|
|
|
andThen(() => {
|
|
|
|
let expect = formatTextWithSelection(AFTER, CASE.after);
|
|
|
|
let actual = formatTextWithSelection(this.get('value'), getSelection(textarea));
|
|
|
|
assert.equal(actual, expect);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
})();
|