2016-01-20 05:17:22 +01:00
|
|
|
( function( $, QUnit, tinymce, setTimeout ) {
|
2015-06-08 00:15:47 +02:00
|
|
|
var editor,
|
|
|
|
count = 0;
|
2015-06-06 22:07:00 +02:00
|
|
|
|
2015-06-07 00:37:13 +02:00
|
|
|
if ( tinymce.Env.ie && tinymce.Env.ie < 9 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-09 21:06:25 +02:00
|
|
|
function mceType( chr, noKeyUp ) {
|
2016-01-20 05:17:22 +01:00
|
|
|
var editor = tinymce.activeEditor, keyCode, charCode, evt, startElm, rng, startContainer, startOffset, textNode;
|
|
|
|
|
|
|
|
function charCodeToKeyCode(charCode) {
|
|
|
|
var lookup = {
|
|
|
|
'0': 48, '1': 49, '2': 50, '3': 51, '4': 52, '5': 53, '6': 54, '7': 55, '8': 56, '9': 57,'a': 65, 'b': 66, 'c': 67,
|
|
|
|
'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73, 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81,
|
|
|
|
'r': 82, 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, ' ': 32, ',': 188, '-': 189, '.': 190, '/': 191, '\\': 220,
|
2016-02-23 09:32:34 +01:00
|
|
|
'[': 219, ']': 221, '\'': 222, ';': 186, '=': 187, ')': 41,
|
2016-03-25 14:30:10 +01:00
|
|
|
'`': 48 // Anything will do.
|
2016-01-20 05:17:22 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
return lookup[String.fromCharCode(charCode)];
|
|
|
|
}
|
|
|
|
|
|
|
|
function fakeEvent(target, type, evt) {
|
|
|
|
editor.dom.fire(target, type, evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Numeric keyCode
|
|
|
|
if (typeof(chr) === 'number') {
|
|
|
|
charCode = chr;
|
|
|
|
keyCode = charCodeToKeyCode(charCode);
|
|
|
|
} else if (typeof(chr) === 'string') {
|
|
|
|
// String value
|
|
|
|
if (chr === '\b') {
|
|
|
|
keyCode = 8;
|
|
|
|
charCode = chr.charCodeAt(0);
|
|
|
|
} else if (chr === '\n') {
|
|
|
|
keyCode = 13;
|
|
|
|
charCode = chr.charCodeAt(0);
|
|
|
|
} else {
|
|
|
|
charCode = chr.charCodeAt(0);
|
|
|
|
keyCode = charCodeToKeyCode(charCode);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
evt = chr;
|
|
|
|
|
|
|
|
if (evt.charCode) {
|
|
|
|
chr = String.fromCharCode(evt.charCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt.keyCode) {
|
|
|
|
keyCode = evt.keyCode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
evt = evt || {keyCode: keyCode, charCode: charCode};
|
|
|
|
|
|
|
|
startElm = editor.selection.getStart();
|
|
|
|
fakeEvent(startElm, 'keydown', evt);
|
|
|
|
fakeEvent(startElm, 'keypress', evt);
|
|
|
|
|
|
|
|
if (!evt.isDefaultPrevented()) {
|
|
|
|
if (keyCode === 8) {
|
|
|
|
if (editor.getDoc().selection) {
|
|
|
|
rng = editor.getDoc().selection.createRange();
|
|
|
|
|
|
|
|
if (rng.text.length === 0) {
|
|
|
|
rng.moveStart('character', -1);
|
|
|
|
rng.select();
|
|
|
|
}
|
|
|
|
|
|
|
|
rng.execCommand('Delete', false, null);
|
|
|
|
} else {
|
|
|
|
rng = editor.selection.getRng();
|
|
|
|
startContainer = rng.startContainer;
|
|
|
|
|
|
|
|
if (startContainer.nodeType === 1 && rng.collapsed) {
|
|
|
|
var nodes = rng.startContainer.childNodes;
|
|
|
|
startContainer = nodes[nodes.length - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If caret is at <p>abc|</p> and after the abc text node then move it to the end of the text node
|
|
|
|
// Expand the range to include the last char <p>ab[c]</p> since IE 11 doesn't delete otherwise
|
|
|
|
if ( rng.collapsed && startContainer && startContainer.nodeType === 3 && startContainer.data.length > 0) {
|
|
|
|
rng.setStart(startContainer, startContainer.data.length - 1);
|
|
|
|
rng.setEnd(startContainer, startContainer.data.length);
|
|
|
|
editor.selection.setRng(rng);
|
|
|
|
}
|
|
|
|
|
|
|
|
editor.getDoc().execCommand('Delete', false, null);
|
|
|
|
}
|
|
|
|
} else if (typeof(chr) === 'string') {
|
|
|
|
rng = editor.selection.getRng(true);
|
|
|
|
|
|
|
|
if (rng.startContainer.nodeType === 3 && rng.collapsed) {
|
|
|
|
// `insertData` may alter the range.
|
|
|
|
startContainer = rng.startContainer;
|
|
|
|
startOffset = rng.startOffset;
|
|
|
|
rng.startContainer.insertData( rng.startOffset, chr );
|
|
|
|
rng.setStart( startContainer, startOffset + 1 );
|
|
|
|
} else {
|
|
|
|
textNode = editor.getDoc().createTextNode(chr);
|
|
|
|
rng.insertNode(textNode);
|
|
|
|
rng.setStart(textNode, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
rng.collapse(true);
|
|
|
|
editor.selection.setRng(rng);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-09 21:06:25 +02:00
|
|
|
if ( ! noKeyUp ) {
|
|
|
|
fakeEvent(startElm, 'keyup', evt);
|
|
|
|
}
|
2016-01-20 05:17:22 +01:00
|
|
|
}
|
|
|
|
|
2015-06-06 22:07:00 +02:00
|
|
|
function type() {
|
|
|
|
var args = arguments;
|
|
|
|
|
2016-06-09 21:06:25 +02:00
|
|
|
// Wait once for conversions to be triggered,
|
|
|
|
// and once for the `canUndo` flag to be set.
|
|
|
|
setTimeout( function() {
|
2015-06-06 22:07:00 +02:00
|
|
|
setTimeout( function() {
|
|
|
|
if ( typeof args[0] === 'string' ) {
|
|
|
|
args[0] = args[0].split( '' );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( typeof args[0] === 'function' ) {
|
|
|
|
args[0]();
|
|
|
|
} else {
|
2016-01-20 05:17:22 +01:00
|
|
|
mceType( args[0].shift() );
|
2015-06-06 22:07:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! args[0].length ) {
|
|
|
|
[].shift.call( args );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( args.length ) {
|
|
|
|
type.apply( null, args );
|
|
|
|
}
|
|
|
|
} );
|
2016-06-09 21:06:25 +02:00
|
|
|
} );
|
2015-06-06 22:07:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QUnit.module( 'tinymce.plugins.wptextpattern', {
|
|
|
|
beforeEach: function( assert ) {
|
2015-06-08 00:15:47 +02:00
|
|
|
var done;
|
|
|
|
|
|
|
|
if ( ! editor ) {
|
|
|
|
done = assert.async();
|
|
|
|
|
|
|
|
$( document.body ).append( '<textarea id="editor">' );
|
|
|
|
|
|
|
|
tinymce.init( {
|
|
|
|
selector: '#editor',
|
|
|
|
skin: false,
|
|
|
|
plugins: 'wptextpattern',
|
2016-11-01 21:05:48 +01:00
|
|
|
wptextpattern: {
|
|
|
|
inline: [
|
2016-11-07 00:37:09 +01:00
|
|
|
{ delimiter: '`', format: 'code' },
|
|
|
|
{ delimiter: '``', format: 'bold' },
|
|
|
|
{ delimiter: '```', format: 'italic' }
|
2016-11-01 21:05:48 +01:00
|
|
|
]
|
|
|
|
},
|
2015-06-08 00:15:47 +02:00
|
|
|
init_instance_callback: function() {
|
|
|
|
editor = arguments[0];
|
|
|
|
editor.focus();
|
|
|
|
editor.selection.setCursorLocation();
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
} else {
|
|
|
|
editor.setContent( '' );
|
|
|
|
editor.selection.setCursorLocation();
|
|
|
|
}
|
2015-06-06 22:07:00 +02:00
|
|
|
},
|
2015-06-08 00:15:47 +02:00
|
|
|
afterEach: function( assert ) {
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if ( count === assert.test.module.tests.length ) {
|
|
|
|
editor.remove();
|
|
|
|
$( '#editor' ).remove();
|
|
|
|
}
|
2015-06-06 22:07:00 +02:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Unordered list.', function( assert ) {
|
2015-06-08 00:15:47 +02:00
|
|
|
type( '* a', function() {
|
|
|
|
assert.equal( editor.getContent(), '<ul>\n<li>a</li>\n</ul>' );
|
2015-06-06 22:07:00 +02:00
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2016-06-09 21:06:25 +02:00
|
|
|
QUnit.test( 'Unordered list. (fast)', function( assert ) {
|
|
|
|
type( '*', function() {
|
|
|
|
mceType( ' ', true );
|
|
|
|
}, 'a', function() {
|
|
|
|
assert.equal( editor.getContent(), '<ul>\n<li>a</li>\n</ul>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2015-06-06 22:07:00 +02:00
|
|
|
QUnit.test( 'Ordered list.', function( assert ) {
|
2015-06-08 00:15:47 +02:00
|
|
|
type( '1. a', function() {
|
|
|
|
assert.equal( editor.getContent(), '<ol>\n<li>a</li>\n</ol>' );
|
2015-06-06 22:07:00 +02:00
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2015-06-18 13:33:11 +02:00
|
|
|
QUnit.test( 'Ordered list with content. (1)', function( assert ) {
|
2015-06-06 22:07:00 +02:00
|
|
|
editor.setContent( '<p><strong>test</strong></p>' );
|
|
|
|
editor.selection.setCursorLocation();
|
|
|
|
|
|
|
|
type( '* ', function() {
|
|
|
|
assert.equal( editor.getContent(), '<ul>\n<li><strong>test</strong></li>\n</ul>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2015-06-18 13:33:11 +02:00
|
|
|
QUnit.test( 'Ordered list with content. (2)', function( assert ) {
|
|
|
|
editor.setContent( '<p><strong>test</strong></p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0], 0 );
|
|
|
|
|
|
|
|
type( '* ', function() {
|
|
|
|
assert.equal( editor.getContent(), '<ul>\n<li><strong>test</strong></li>\n</ul>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2015-06-06 22:07:00 +02:00
|
|
|
QUnit.test( 'Only transform inside a P tag.', function( assert ) {
|
|
|
|
editor.setContent( '<h1>test</h1>' );
|
|
|
|
editor.selection.setCursorLocation();
|
|
|
|
|
|
|
|
type( '* ', function() {
|
|
|
|
assert.equal( editor.getContent(), '<h1>* test</h1>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Only transform at the start of a P tag.', function( assert ) {
|
|
|
|
editor.setContent( '<p>test <strong>test</strong></p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'strong' )[0].firstChild, 0 );
|
|
|
|
|
|
|
|
type( '* ', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>test <strong>* test</strong></p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Only transform when at the cursor is at the start.', function( assert ) {
|
|
|
|
editor.setContent( '<p>* test</p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 6 );
|
|
|
|
|
2015-06-08 00:15:47 +02:00
|
|
|
type( ' a', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>* test a</p>' );
|
2015-06-06 22:07:00 +02:00
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Backspace should undo the transformation.', function( assert ) {
|
|
|
|
editor.setContent( '<p>test</p>' );
|
|
|
|
editor.selection.setCursorLocation();
|
|
|
|
|
|
|
|
type( '* \b', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>* test</p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 2 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Backspace should undo the transformation only right after it happened.', function( assert ) {
|
|
|
|
editor.setContent( '<p>test</p>' );
|
|
|
|
editor.selection.setCursorLocation();
|
|
|
|
|
|
|
|
type( '* ', function() {
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'li' )[0].firstChild, 4 );
|
|
|
|
// Gecko.
|
|
|
|
editor.fire( 'click' );
|
|
|
|
}, '\b', function() {
|
|
|
|
assert.equal( editor.getContent(), '<ul>\n<li>tes</li>\n</ul>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
2015-07-28 01:15:15 +02:00
|
|
|
|
|
|
|
QUnit.test( 'Heading 3', function( assert ) {
|
|
|
|
editor.setContent( '<p>### test</p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 8 );
|
|
|
|
|
|
|
|
type( '\n', function() {
|
2015-08-04 00:06:25 +02:00
|
|
|
assert.equal( editor.$( 'h3' )[0].firstChild.data, 'test' );
|
2015-07-28 01:15:15 +02:00
|
|
|
assert.equal( editor.getContent(), '<h3>test</h3>\n<p> </p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Heading 3 with elements.', function( assert ) {
|
|
|
|
editor.setContent( '<p>###<del>test</del></p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'del' )[0].firstChild, 4 );
|
|
|
|
|
|
|
|
type( '\n', function() {
|
|
|
|
assert.equal( editor.getContent(), '<h3><del>test</del></h3>\n<p> </p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Don\'t convert without content', function( assert ) {
|
|
|
|
editor.setContent( '<p>### </p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 4 );
|
|
|
|
|
|
|
|
type( '\n', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>### </p>\n<p> </p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
2016-02-23 09:32:34 +01:00
|
|
|
|
2016-02-26 01:51:01 +01:00
|
|
|
QUnit.test( 'Horizontal Rule', function( assert ) {
|
2016-03-17 01:46:26 +01:00
|
|
|
type( '---\n', function() {
|
2016-02-26 01:51:01 +01:00
|
|
|
assert.equal( editor.getContent(), '<hr />\n<p> </p>' );
|
2016-02-23 09:32:34 +01:00
|
|
|
}, assert.async() );
|
|
|
|
} );
|
2016-03-25 14:30:10 +01:00
|
|
|
|
2016-11-01 21:05:48 +01:00
|
|
|
QUnit.test( 'Inline: single character.', function( assert ) {
|
2016-03-25 14:30:10 +01:00
|
|
|
type( '`test`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p><code>test</code></p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 1 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2016-11-01 21:05:48 +01:00
|
|
|
QUnit.test( 'Inline: two characters.', function( assert ) {
|
|
|
|
type( '``test``', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p><strong>test</strong></p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 1 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2016-11-07 00:37:09 +01:00
|
|
|
QUnit.test( 'Inline: allow spaces within text.', function( assert ) {
|
|
|
|
type( '`a a`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p><code>a a</code></p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 1 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Inline: disallow \\S-delimiter-\\s.', function( assert ) {
|
|
|
|
type( 'a` a`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>a` a`</p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 5 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Inline: allow \\s-delimiter-\\s.', function( assert ) {
|
|
|
|
type( 'a ` a`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>a <code> a</code></p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 1 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Inline: allow \\S-delimiter-\\S.', function( assert ) {
|
|
|
|
type( 'a`a`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>a<code>a</code></p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 1 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2016-03-25 14:30:10 +01:00
|
|
|
QUnit.test( 'Inline: after typing.', function( assert ) {
|
|
|
|
editor.setContent( '<p>test test test</p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 5 );
|
|
|
|
|
|
|
|
type( '`', function() {
|
2016-11-01 21:05:48 +01:00
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 10 );
|
2016-03-25 14:30:10 +01:00
|
|
|
}, '`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>test <code>test</code> test</p>' );
|
|
|
|
assert.equal( editor.selection.getRng().startOffset, 1 );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
2016-11-07 00:37:09 +01:00
|
|
|
QUnit.test( 'Inline: no change without content.', function( assert ) {
|
|
|
|
type( 'test `` ``` ````', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>test `` ``` ````</p>' );
|
2016-03-25 14:30:10 +01:00
|
|
|
}, assert.async() );
|
|
|
|
} );
|
2016-11-01 21:05:48 +01:00
|
|
|
|
2016-11-07 00:37:09 +01:00
|
|
|
QUnit.test( 'Inline: convert with previously unconverted pattern.', function( assert ) {
|
2016-11-01 21:05:48 +01:00
|
|
|
editor.setContent( '<p>`test` test </p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 12 );
|
|
|
|
|
|
|
|
type( '`test`', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>`test` test <code>test</code></p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
2016-11-07 00:37:09 +01:00
|
|
|
|
|
|
|
QUnit.test( 'Inline: convert with previous pattern characters.', function( assert ) {
|
|
|
|
editor.setContent( '<p>test``` 123</p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 11 );
|
|
|
|
|
|
|
|
type( '``456``', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>test``` 123<strong>456</strong></p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'Inline: disallow after previous pattern characters and leading space.', function( assert ) {
|
|
|
|
editor.setContent( '<p>test``` 123</p>' );
|
|
|
|
editor.selection.setCursorLocation( editor.$( 'p' )[0].firstChild, 11 );
|
|
|
|
|
|
|
|
type( '``` 456```', function() {
|
|
|
|
assert.equal( editor.getContent(), '<p>test``` 123``` 456```</p>' );
|
|
|
|
}, assert.async() );
|
|
|
|
} );
|
2016-01-20 05:17:22 +01:00
|
|
|
} )( window.jQuery, window.QUnit, window.tinymce, window.setTimeout );
|