TinyMCE: update to 4.4.0, changelog: https://github.com/tinymce/tinymce/blob/master/changelog.txt. Includes two bugfixes for #36434.

Fixes #37327.

git-svn-id: https://develop.svn.wordpress.org/trunk@38034 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Andrew Ozz
2016-07-12 00:19:47 +00:00
parent 68cff6ac40
commit f11d5ef4d8
33 changed files with 3506 additions and 143 deletions
+6
View File
@@ -22,6 +22,7 @@
<script src="js/qunit/qunit.js"></script>
<script src="js/tinymce_loader.js"></script>
<!--<script src="../js/tinymce/classes/jquery.tinymce.js"></script> -->
<script src="../../../src/wp-includes/js/tinymce/plugins/paste/plugin.js"></script>
<script src="js/utils.js"></script>
<script src="js/init.js"></script>
@@ -46,6 +47,7 @@
<!-- tinymce.file.* -->
<script src="tinymce/file/Conversions.js"></script>
<script src="tinymce/file/ImageScanner.js"></script>
<script src="tinymce/file/UploadStatus.js"></script>
<!-- tinymce.fmt.* -->
<script src="tinymce/fmt/Hooks.js"></script>
@@ -126,6 +128,8 @@
<script src="tinymce/UndoManager.js"></script>
<script src="tinymce/SelectionOverrides.js"></script>
<script src="tinymce/WindowManager.js"></script>
<script src="tinymce/InsertContent.js"></script>
<script src="tinymce/InsertList.js"></script>
<!-- tinymce.plugins.* -->
<!--<script src="plugins/autolink.js"></script>-->
@@ -142,6 +146,8 @@
<script src="plugins/media.js"></script>
<!--<script src="plugins/noneditable.js"></script> -->
<script src="plugins/paste.js"></script>
<script src="plugins/paste_images.js"></script>
<script src="plugins/paste_smart.js"></script>
<!--<script src="plugins/searchreplace.js"></script>-->
<!--<script src="plugins/spellchecker.js"></script>-->
<!--<script src="plugins/table.js"></script>-->
+199 -6
View File
@@ -35,9 +35,9 @@ ModuleLoader.require([
indent: false,
schema: 'html5',
entities: 'raw',
valid_elements: 'li,ol,ul,dl,dt,dd,em,strong,span,#p,div,br',
valid_elements: 'li,ol[style],ul[style],dl,dt,dd,em,strong,span,#p,div,br',
valid_styles: {
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left'
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left,list-style-type'
},
disable_nodechange: true,
init_instance_callback: function(ed) {
@@ -56,7 +56,11 @@ ModuleLoader.require([
init_instance_callback: function(ed) {
window.inlineEditor = ed;
wait();
}
},
valid_styles: {
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left,list-style-type'
},
});
tinymce.init({
@@ -69,7 +73,11 @@ ModuleLoader.require([
init_instance_callback: function(ed) {
inlineEditor2 = ed;
wait();
}
},
valid_styles: {
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left,list-style-type'
},
});
},
@@ -87,9 +95,9 @@ ModuleLoader.require([
return html.toLowerCase().replace(/<br[^>]*>|[\r\n]+/gi, '');
}
function execCommand(cmd) {
function execCommand(cmd, ui, obj) {
if (editor.editorCommands.hasCustomCommand(cmd)) {
editor.execCommand(cmd);
editor.execCommand(cmd, ui, obj);
}
}
@@ -379,6 +387,166 @@ ModuleLoader.require([
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply OL to UL and DO not merge with adjacent lists because styles are different (exec has style)', function() {
editor.getBody().innerHTML = trimBrs(
'<ol>' +
'<li>a</li>' +
'</ol>' +
'<ul><li>b</li></ul>' +
'<ol>' +
'<li>c</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('ul li', 1);
execCommand('InsertOrderedList', null, { 'list-style-type': 'lower-alpha' });
equal(editor.getContent(),
'<ol>' +
'<li>a</li>' +
'</ol>' +
'<ol style="list-style-type: lower-alpha;"><li>b</li></ol>' +
'<ol>' +
'<li>c</li>' +
'</ol>'
);
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply OL to P and DO not merge with adjacent lists because styles are different (exec has style)', function() {
editor.getBody().innerHTML = trimBrs(
'<ol>' +
'<li>a</li>' +
'</ol>' +
'<p>b</p>' +
'<ol>' +
'<li>c</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('p', 1);
execCommand('InsertOrderedList', null, { 'list-style-type': 'lower-alpha' });
equal(editor.getContent(),
'<ol>' +
'<li>a</li>' +
'</ol>' +
'<ol style="list-style-type: lower-alpha;"><li>b</li></ol>' +
'<ol>' +
'<li>c</li>' +
'</ol>'
);
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply OL to UL and DO not merge with adjacent lists because styles are different (original has style)', function() {
editor.getBody().innerHTML = trimBrs(
'<ol style="list-style-type: upper-roman;">' +
'<li>a</li>' +
'</ol>' +
'<ul><li>b</li></ul>' +
'<ol style="list-style-type: upper-roman;">' +
'<li>c</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('ul li', 1);
execCommand('InsertOrderedList');
equal(editor.getContent(),
'<ol style="list-style-type: upper-roman;">' +
'<li>a</li>' +
'</ol>' +
'<ol><li>b</li></ol>' +
'<ol style="list-style-type: upper-roman;">' +
'<li>c</li>' +
'</ol>'
);
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply OL to UL should merge with adjacent lists because styles are the same (both have roman)', function() {
editor.getBody().innerHTML = trimBrs(
'<ol style="list-style-type: upper-roman;">' +
'<li>a</li>' +
'</ol>' +
'<ul><li>b</li></ul>' +
'<ol style="list-style-type: upper-roman;">' +
'<li>c</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('ul li', 1);
execCommand('InsertOrderedList', false, { 'list-style-type': 'upper-roman' });
equal(editor.getContent(),
'<ol style="list-style-type: upper-roman;">' +
'<li>a</li>' +
'<li>b</li>' +
'<li>c</li>' +
'</ol>'
);
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply OL to UL should merge with above list because styles are the same (both have lower-roman), but not below list', function() {
editor.getBody().innerHTML = trimBrs(
'<ol style="list-style-type: lower-roman;">' +
'<li>a</li>' +
'</ol>' +
'<ul><li>b</li></ul>' +
'<ol style="list-style-type: upper-roman;">' +
'<li>c</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('ul li', 1);
execCommand('InsertOrderedList', false, { 'list-style-type': 'lower-roman' });
equal(editor.getContent(),
'<ol style="list-style-type: lower-roman;">' +
'<li>a</li>' +
'<li>b</li>' +
'</ol>' +
'<ol style="list-style-type: upper-roman;">' +
'<li>c</li>' +
'</ol>'
);
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply OL to UL should merge with below lists because styles are the same (both have roman), but not above list', function() {
editor.getBody().innerHTML = trimBrs(
'<ol style="list-style-type: upper-roman;">' +
'<li>a</li>' +
'</ol>' +
'<ul><li>b</li></ul>' +
'<ol style="list-style-type: lower-roman;">' +
'<li>c</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('ul li', 1);
execCommand('InsertOrderedList', false, { 'list-style-type': 'lower-roman' });
equal(editor.getContent(),
'<ol style="list-style-type: upper-roman;">' +
'<li>a</li>' +
'</ol>' +
'<ol style="list-style-type: lower-roman;">' +
'<li>b</li>' +
'<li>c</li>' +
'</ol>'
);
equal(editor.selection.getStart().nodeName, 'LI');
});
test('Apply UL list to single text line', function() {
editor.settings.forced_root_block = false;
@@ -1302,6 +1470,31 @@ ModuleLoader.require([
equal(editor.selection.getNode().nodeName, 'LI');
});
test('Indent single LI in OL and retain OLs list style in the new OL', function() {
editor.getBody().innerHTML = trimBrs(
'<ol style="list-style-type: lower-alpha;">' +
'<li>a</li>' +
'<li>b</li>' +
'</ol>'
);
editor.focus();
Utils.setSelection('li:nth-child(2)', 0);
execCommand('Indent');
equal(editor.getContent(),
'<ol style="list-style-type: lower-alpha;">' +
'<li>a' +
'<ol style="list-style-type: lower-alpha;">' +
'<li>b</li>' +
'</ol>' +
'</li>' +
'</ol>'
);
});
test('Indent last LI in OL', function() {
editor.getBody().innerHTML = trimBrs(
'<ol>' +
+188
View File
@@ -0,0 +1,188 @@
ModuleLoader.require([
"tinymce/pasteplugin/Clipboard",
"tinymce/Env",
"tinymce/util/Delay",
"tinymce/util/Promise"
], function(Clipboard, Env, Delay, Promise) {
var base64ImgSrc = [
'R0lGODdhZABkAHcAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQECgAAACwAAAAAZABkAIEAAAD78jY/',
'P3SsMjIC/4SPqcvtD6OctNqLs968+w+G4kiW5ommR8C27gvHrxrK9g3TIM7f+tcL5n4doZFFLB6F',
'Sc6SCRFIp9SqVTp6BiPXbjer5XG95Ck47IuWy2e0bLz2tt3DR5w8p7vgd2tej6TW5ycCGMM3aFZo',
'OCOYqFjDuOf4KPAHiPh4qZeZuEnXOfjpFto3ilZ6dxqWGreq1br2+hTLtigZaFcJuYOb67DLC+Qb',
'UIt3i2sshyzZtEFc7JwBLT1NXI2drb3N3e39DR4uPk5ebn6Onq6+zu488A4fLz9P335Aj58fb2+g',
'71/P759AePwADBxY8KDAhAr9MWyY7yFEgPYmRgxokWK7jEYa2XGcJ/HjgJAfSXI0mRGlRZUTWUJ0',
'2RCmQpkHaSLEKPKdzYU4c+78VzCo0KFEixo9ijSp0qVMmzp9CjWq1KlUq1q9eqEAADs='
].join('');
if (!Env.fileApi) {
return;
}
module("tinymce.plugins.Paste - Images", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
disable_nodechange: true,
skin: false,
entities: 'raw',
indent: false,
automatic_uploads: false,
plugins: "paste",
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
delete editor.settings.paste_data_images;
delete editor.settings.images_dataimg_filter;
editor.editorUpload.destroy();
}
});
var base64ToBlob = function (base64, type) {
var buff = atob(base64);
var bytes = new Uint8Array(buff.length);
for (var i = 0; i < bytes.length; i++) {
bytes[i] = buff.charCodeAt(i);
}
return new Blob([bytes], {type: type});
};
var noop = function () {
};
var mockEvent = function (type) {
var event, transferName;
event = {
type: type,
preventDefault: noop
};
transferName = type === 'drop' ? 'dataTransfer' : 'clipboardData';
event[transferName] = {
files: [
base64ToBlob(base64ImgSrc, 'image/gif')
]
};
return event;
};
var setupContent = function () {
editor.setContent('<p>a</p>');
Utils.setSelection('p', 0);
return editor.selection.getRng();
};
var waitForSelector = function (selector) {
return new Promise(function (resolve, reject) {
var check = function (time, count) {
var result = editor.dom.select(selector);
if (result.length > 0) {
resolve(result);
} else {
if (count === 0) {
reject();
} else {
Delay.setTimeout(function () {
check(time, count--);
}, time);
}
}
};
check(10, 100);
});
};
var fail = function () {
ok(false, 'Failed to get image due to timeout.');
QUnit.start();
};
asyncTest('dropImages', function() {
var rng, event, clipboard = new Clipboard(editor);
editor.settings.paste_data_images = true;
rng = setupContent();
event = mockEvent('drop');
clipboard.pasteImageData(event, rng);
waitForSelector('img').then(function () {
equal(editor.getContent(), '<p><img src=\"data:image/gif;base64,' + base64ImgSrc + '" />a</p>');
strictEqual(editor.dom.select('img')[0].src.indexOf('blob:'), 0);
QUnit.start();
}, fail);
});
asyncTest('pasteImages', function() {
var rng, event, clipboard = new Clipboard(editor);
editor.settings.paste_data_images = true;
rng = setupContent();
event = mockEvent('paste');
clipboard.pasteImageData(event, rng);
waitForSelector('img').then(function () {
equal(editor.getContent(), '<p><img src=\"data:image/gif;base64,' + base64ImgSrc + '" />a</p>');
strictEqual(editor.dom.select('img')[0].src.indexOf('blob:'), 0);
QUnit.start();
}, fail);
});
asyncTest('dropImages - images_dataimg_filter', function() {
var rng, event, clipboard = new Clipboard(editor);
editor.settings.paste_data_images = true;
editor.settings.images_dataimg_filter = function (img) {
strictEqual(img.src, 'data:image/gif;base64,' + base64ImgSrc);
return false;
};
rng = setupContent();
event = mockEvent('drop');
clipboard.pasteImageData(event, rng);
waitForSelector('img').then(function () {
equal(editor.getContent(), '<p><img src=\"data:image/gif;base64,' + base64ImgSrc + '" />a</p>');
strictEqual(editor.dom.select('img')[0].src.indexOf('data:'), 0);
QUnit.start();
}, fail);
});
asyncTest('pasteImages - images_dataimg_filter', function() {
var rng, event, clipboard = new Clipboard(editor);
editor.settings.paste_data_images = true;
editor.settings.images_dataimg_filter = function (img) {
strictEqual(img.src, 'data:image/gif;base64,' + base64ImgSrc);
return false;
};
rng = setupContent();
event = mockEvent('paste');
clipboard.pasteImageData(event, rng);
waitForSelector('img').then(function () {
equal(editor.getContent(), '<p><img src=\"data:image/gif;base64,' + base64ImgSrc + '" />a</p>');
strictEqual(editor.dom.select('img')[0].src.indexOf('data:'), 0);
QUnit.start();
}, fail);
});
});
+68
View File
@@ -0,0 +1,68 @@
ModuleLoader.require([
"tinymce/pasteplugin/SmartPaste"
], function (SmartPaste) {
module("tinymce.plugins.Paste_smart", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
indent: false,
plugins: 'paste',
setup: function(ed) {
ed.on('NodeChange', false);
},
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
test('isAbsoluteUrl', function() {
equal(SmartPaste.isAbsoluteUrl('http://www.site.com'), true);
equal(SmartPaste.isAbsoluteUrl('https://www.site.com'), true);
equal(SmartPaste.isAbsoluteUrl('http://www.site.com/dir-name/file.gif?query=%42'), true);
equal(SmartPaste.isAbsoluteUrl('https://www.site.com/dir-name/file.gif?query=%42'), true);
equal(SmartPaste.isAbsoluteUrl('file.gif'), false);
equal(SmartPaste.isAbsoluteUrl(''), false);
});
test('isImageUrl', function() {
equal(SmartPaste.isImageUrl('http://www.site.com'), false);
equal(SmartPaste.isImageUrl('https://www.site.com'), false);
equal(SmartPaste.isImageUrl('http://www.site.com/dir-name/file.gif'), true);
equal(SmartPaste.isImageUrl('https://www.site.com/dir-name/file.gif'), true);
equal(SmartPaste.isImageUrl('https://www.site.com/dir-name/file.gif?query=%42'), false);
equal(SmartPaste.isImageUrl('https://www.site.com/dir-name/file.html?query=%42'), false);
equal(SmartPaste.isImageUrl('file.gif'), false);
equal(SmartPaste.isImageUrl(''), false);
});
test('smart paste url on selection', function() {
editor.focus();
editor.undoManager.clear();
editor.setContent('<p>abc</p>');
Utils.setSelection('p', 0, 'p', 3);
editor.undoManager.add();
editor.execCommand('mceInsertClipboardContent', false, {content: 'http://www.site.com'});
equal(editor.getContent(), '<p><a href="http://www.site.com">abc</a></p>');
equal(editor.undoManager.data.length, 3);
});
test('smart paste image url', function() {
editor.focus();
editor.undoManager.clear();
editor.setContent('<p>abc</p>');
Utils.setSelection('p', 1);
editor.undoManager.add();
editor.execCommand('mceInsertClipboardContent', false, {content: 'http://www.site.com/my.jpg'});
equal(editor.getContent(), '<p>a<img src="http://www.site.com/my.jpg" />bc</p>');
equal(editor.undoManager.data.length, 3);
});
});
+263 -1
View File
@@ -505,6 +505,157 @@
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td>2</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr></tbody></table>');
});
test("mceTableInsertRowAfter command on merged cells", function() {
editor.setContent(
'<table>' +
'<tr><td>1</td><td>2</td><td>3</td></tr>' +
'<tr><td>4</td><td colspan="2" rowspan="2">5</td></tr>' +
'<tr><td>6</td></tr>' +
'</table>'
);
Utils.setSelection('tr:nth-child(2) td', 0);
editor.execCommand('mceTableInsertRowAfter');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1</td><td>2</td><td>3</td></tr>' +
'<tr><td>4</td><td colspan="2" rowspan="3">5</td></tr>' +
'<tr><td>&nbsp;</td></tr>' +
'<tr><td>6</td></tr>' +
'</tbody>' +
'</table>'
);
});
test("mceTablePasteRowBefore command", function() {
editor.setContent(
'<table>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'</table>'
);
Utils.setSelection('tr:nth-child(1) td', 0);
editor.execCommand('mceTableCopyRow');
Utils.setSelection('tr:nth-child(2) td', 0);
editor.execCommand('mceTablePasteRowBefore');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'</tbody>' +
'</table>'
);
Utils.setSelection('tr:nth-child(2) td', 0);
editor.execCommand('mceTablePasteRowBefore');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'</tbody>' +
'</table>'
);
});
test("mceTablePasteRowAfter command", function() {
editor.setContent(
'<table>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'</table>'
);
Utils.setSelection('tr:nth-child(1) td', 0);
editor.execCommand('mceTableCopyRow');
Utils.setSelection('tr:nth-child(2) td', 0);
editor.execCommand('mceTablePasteRowAfter');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'</tbody>' +
'</table>'
);
Utils.setSelection('tr:nth-child(2) td', 0);
editor.execCommand('mceTablePasteRowAfter');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'</tbody>' +
'</table>'
);
});
test("row clipboard api", function() {
var clipboardRows;
editor.setContent(
'<table>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'</table>'
);
Utils.setSelection('tr:nth-child(1) td', 0);
editor.execCommand('mceTableCopyRow');
clipboardRows = editor.plugins.table.getClipboardRows();
equal(clipboardRows.length, 1);
equal(clipboardRows[0].tagName, 'TR');
editor.plugins.table.setClipboardRows(clipboardRows.concat([
editor.dom.create('tr', {}, '<td>a</td><td>b</td>'),
editor.dom.create('tr', {}, '<td>c</td><td>d</td>')
]));
Utils.setSelection('tr:nth-child(2) td', 0);
editor.execCommand('mceTablePasteRowAfter');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>2</td><td>3</td></tr>' +
'<tr><td>1</td><td>2</td></tr>' +
'<tr><td>a</td><td>b</td></tr>' +
'<tr><td>c</td><td>d</td></tr>' +
'</tbody>' +
'</table>'
);
});
test("mceTableInsertRowBefore command", function() {
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
Utils.setSelection('td', 0);
@@ -516,7 +667,55 @@
editor.getBody().innerHTML = '<table><tr><td data-mce-selected="1">1</td><td data-mce-selected="1">2</td></tr></table>';
Utils.setSelection('td', 0);
editor.execCommand('mceTableMergeCells');
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>12</td></tr></tbody></table>');
});
test("mceTableMergeCells command with all cells selected", function() {
editor.getBody().innerHTML = (
'<table>' +
'<tbody>' +
'<tr><td data-mce-selected="1">1</td><td data-mce-selected="1">2</td></tr>' +
'<tr><td data-mce-selected="1">3</td><td data-mce-selected="1">4</td></tr>' +
'</tbody>' +
'</table>'
);
Utils.setSelection('td', 0);
editor.execCommand('mceTableMergeCells');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td>1234</td></tr>' +
'</tbody>' +
'</table>'
);
});
test("mceTableMergeCells command with whole rows selected", function() {
editor.getBody().innerHTML = (
'<table>' +
'<tbody>' +
'<tr><td data-mce-selected="1">1</td><td data-mce-selected="1">2</td></tr>' +
'<tr><td data-mce-selected="1">3</td><td data-mce-selected="1">4</td></tr>' +
'<tr><td>5</td><td>6</td></tr>' +
'</tbody>' +
'</table>'
);
Utils.setSelection('td', 0);
editor.execCommand('mceTableMergeCells');
equal(
cleanTableHtml(editor.getContent()),
'<table>' +
'<tbody>' +
'<tr><td colspan="2">1234</td></tr>' +
'<tr><td>5</td><td>6</td></tr>' +
'</tbody>' +
'</table>'
);
});
test("mceTableSplitCells command", function() {
@@ -1022,4 +1221,67 @@
equal(cells[cells.length - 1].getAttribute('data-counter'), "8");
equal(rows[rows.length - 1].getAttribute('data-counter'), "6");
});
function assertTableSelection(tableHtml, selectCells, cellContents) {
function selectRangeXY(table, startTd, endTd) {
editor.fire('mousedown', {target: startTd});
editor.fire('mouseover', {target: endTd});
editor.fire('mouseup', {target: endTd});
}
function getCells(table) {
return editor.$(table).find('td').toArray();
}
function getSelectedCells(table) {
return editor.$(table).find('td[data-mce-selected]').toArray();
}
editor.setContent(tableHtml);
var table = editor.$('table')[0];
var cells = getCells(table);
var startTd = tinymce.grep(cells, function(elm) {
return elm.innerHTML === selectCells[0];
})[0];
var endTd = tinymce.grep(cells, function(elm) {
return elm.innerHTML === selectCells[1];
})[0];
selectRangeXY(table, startTd, endTd);
var selection = getSelectedCells(table);
selection = tinymce.map(selection, function(elm) {
return elm.innerHTML;
});
deepEqual(selection, cellContents);
}
test("Table grid selection", function() {
assertTableSelection('<table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>', ['1', '2'], ['1', '2']);
assertTableSelection('<table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>', ['1', '3'], ['1', '3']);
assertTableSelection('<table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>', ['1', '4'], ['1', '2', '3', '4']);
assertTableSelection('<table><tr><td colspan="2" rowspan="2">1</td><td>3</td></tr><tr><td>6</td></tr></table>', ['1', '6'], ['1', '3', '6']);
assertTableSelection(
'<table>' +
'<tr>' +
'<td>1</td>' +
'<td>2</td>' +
'<td>3</td>' +
'</tr>' +
'<tr>' +
'<td colspan="2" rowspan="2">4</td>' +
'<td>5</td>' +
'</tr>' +
'<tr>' +
'<td>6</td>' +
'</tr>' +
'</table>',
['2', '6'],
['2', '3', '4', '5', '6']
);
});
})();
+8
View File
@@ -482,4 +482,12 @@ test('setMode', function() {
editor.dom.fire(editor.getBody(), 'click');
equal(editor.theme.panel.find('button:last')[2].disabled(), false);
equal(clickCount, 2);
});
test('translate', function() {
tinymce.addI18n('en_US', {
'input i18n': 'output i18n'
});
equal(editor.translate('input i18n'), 'output i18n');
});
+19 -1
View File
@@ -78,7 +78,25 @@ test('mceInsertContent HR at end of H1 with P sibling', function() {
equal(getContent(), '<h1>abc</h1><hr /><p>def</p>');
});
test('mceInsertContent HR at end of H1 with P sibling', function() {
test('mceInsertContent HR at end of H1 with inline elements with P sibling', function() {
editor.setContent('<h1><strong>abc</strong></h1><p>def</p>');
Utils.setSelection('strong', 3);
editor.execCommand('mceInsertContent', false, '<hr>');
equal(editor.selection.getNode(), editor.getBody().lastChild);
equal(editor.selection.getNode().nodeName, 'P');
equal(getContent(), '<h1><strong>abc</strong></h1><hr /><p>def</p>');
});
test('mceInsertContent empty block', function() {
editor.setContent('<h1>abc</h1>');
Utils.setSelection('h1', 1);
editor.execCommand('mceInsertContent', false, '<p></p>');
equal(editor.selection.getNode(), editor.getBody().childNodes[1]);
equal(editor.selection.getNode().nodeName, 'P');
equal(getContent(), '<h1>a</h1><p>\u00a0</p><h1>bc</h1>');
});
test('mceInsertContent table at end of H1 with P sibling', function() {
editor.setContent('<h1>abc</h1><p>def</p>');
Utils.setSelection('h1', 3);
editor.execCommand('mceInsertContent', false, '<table><tr><td></td></tr></table>');
+55 -1
View File
@@ -89,6 +89,7 @@ asyncTest('Init/remove on same id', function() {
tinymce.remove('#' + tinymce.get(1).id);
strictEqual(tinymce.get().length, 1);
strictEqual(tinymce.get(0), tinymce.activeEditor);
textArea.parentNode.removeChild(textArea);
}, 0);
}
});
@@ -96,6 +97,36 @@ asyncTest('Init/remove on same id', function() {
strictEqual(tinymce.get().length, 2);
});
asyncTest('Init editor async with proper editors state', function() {
var unloadTheme = function(name) {
var url = tinymce.baseURI.toAbsolute('themes/' + name + '/theme.js');
tinymce.dom.ScriptLoader.ScriptLoader.remove(url);
tinymce.ThemeManager.remove(name);
};
tinymce.remove();
var init = function() {
tinymce.init({
selector: "textarea",
init_instance_callback: function() {
tinymce.util.Delay.setTimeout(function() {
QUnit.start();
}, 0);
}
});
};
unloadTheme("modern");
strictEqual(tinymce.get().length, 0);
init();
strictEqual(tinymce.get().length, 1);
init();
strictEqual(tinymce.get().length, 1);
});
test('overrideDefaults', function() {
var oldBaseURI, oldBaseUrl, oldSuffix;
@@ -139,4 +170,27 @@ test('overrideDefaults', function() {
tinymce.suffix = oldSuffix;
tinymce.overrideDefaults({});
});
});
test('Init inline editor on invalid targets', function() {
var invalidNames;
invalidNames = (
'area base basefont br col frame hr img input isindex link meta param embed source wbr track ' +
'colgroup option tbody tfoot thead tr script noscript style textarea video audio iframe object menu'
);
tinymce.remove();
tinymce.each(invalidNames.split(' '), function (invalidName) {
var elm = tinymce.DOM.add(document.body, invalidName, {'class': 'targetEditor'}, null);
tinymce.init({
selector: invalidName + '.targetEditor',
inline: true
});
strictEqual(tinymce.get().length, 0, 'Should not have created an editor');
tinymce.DOM.remove(elm);
});
});
+137 -4
View File
@@ -51,6 +51,7 @@ ModuleLoader.require([
teardown: function() {
editor.editorUpload.destroy();
editor.settings.automatic_uploads = false;
delete editor.settings.images_replace_blob_uris;
delete editor.settings.images_dataimg_filter;
}
});
@@ -59,6 +60,19 @@ ModuleLoader.require([
return tinymce.DOM.createHTML('img', {src: uri});
}
function assertResult(uploadedBlobInfo, result) {
QUnit.strictEqual(result.length, 1);
QUnit.strictEqual(result[0].status, true);
QUnit.ok(result[0].element.src.indexOf(uploadedBlobInfo.id() + '.png') !== -1);
QUnit.equal('<p><img src="' + uploadedBlobInfo.filename() + '" /></p>', editor.getContent());
return result;
}
function hasBlobAsSource(elm) {
return elm.src.indexOf('blob:') === 0;
}
asyncTest('_scanForImages', function() {
editor.setContent(imageHtml(testBlobDataUri));
@@ -72,12 +86,94 @@ ModuleLoader.require([
}).then(QUnit.start);
});
asyncTest('uploadImages', function() {
asyncTest('replace uploaded blob uri with result uri (copy/paste of an uploaded blob uri)', function() {
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_upload_handler = function(data, success) {
success('file.png');
};
editor._scanForImages().then(function(result) {
var blobUri = result[0].blobInfo.blobUri();
editor.uploadImages(function() {
editor.setContent(imageHtml(blobUri));
QUnit.strictEqual(hasBlobAsSource(editor.$('img')[0]), false);
QUnit.strictEqual(editor.getContent(), '<p><img src="file.png" /></p>');
QUnit.start();
});
});
});
asyncTest('don\'t replace uploaded blob uri with result uri (copy/paste of an uploaded blob uri) since blob uris are retained', function() {
editor.settings.images_replace_blob_uris = false;
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_upload_handler = function(data, success) {
success('file.png');
};
editor._scanForImages().then(function(result) {
var blobUri = result[0].blobInfo.blobUri();
editor.uploadImages(function() {
editor.setContent(imageHtml(blobUri));
QUnit.strictEqual(hasBlobAsSource(editor.$('img')[0]), true);
QUnit.strictEqual(editor.getContent(), '<p><img src="file.png" /></p>');
QUnit.start();
});
});
});
asyncTest('uploadImages (callback)', function() {
var uploadedBlobInfo;
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_upload_handler = function(data, success) {
uploadedBlobInfo = data;
success(data.id() + '.png');
};
editor.uploadImages(function(result) {
assertResult(uploadedBlobInfo, result);
editor.uploadImages(function(result) {
QUnit.strictEqual(result.length, 0);
QUnit.start();
});
});
});
asyncTest('uploadImages (promise)', function() {
var uploadedBlobInfo;
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_upload_handler = function(data, success) {
uploadedBlobInfo = data;
success(data.id() + '.png');
};
editor.uploadImages().then(function(result) {
assertResult(uploadedBlobInfo, result);
}).then(function() {
uploadedBlobInfo = null;
return editor.uploadImages().then(function(result) {
QUnit.strictEqual(result.length, 0);
QUnit.strictEqual(uploadedBlobInfo, null);
QUnit.start();
});
});
});
asyncTest('uploadImages retain blob urls after upload', function() {
var uploadedBlobInfo;
function assertResult(result) {
QUnit.strictEqual(result[0].status, true);
QUnit.ok(result[0].element.src.indexOf(uploadedBlobInfo.id() + '.png') !== -1);
QUnit.ok(hasBlobAsSource(result[0].element), 'Not a blob url');
QUnit.equal('<p><img src="' + uploadedBlobInfo.filename() + '" /></p>', editor.getContent());
return result;
@@ -85,6 +181,7 @@ ModuleLoader.require([
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_replace_blob_uris = false;
editor.settings.images_upload_handler = function(data, success) {
uploadedBlobInfo = data;
success(data.id() + '.png');
@@ -103,20 +200,56 @@ ModuleLoader.require([
asyncTest('uploadConcurrentImages', function() {
var uploadCount = 0, callCount = 0;
function done() {
function done(result) {
callCount++;
if (callCount == 2) {
QUnit.start();
equal(uploadCount, 1, 'Should only be one upload.');
}
equal(editor.getContent(), '<p><img src="myimage.png" /></p>');
equal(result[0].element, editor.$('img')[0]);
equal(result[0].status, true);
}
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_upload_handler = function(data, success) {
uploadCount++;
success(data.id() + '.png');
setTimeout(function() {
success('myimage.png');
}, 0);
};
editor.uploadImages(done);
editor.uploadImages(done);
});
asyncTest('uploadConcurrentImages (fail)', function() {
var uploadCount = 0, callCount = 0;
function done(result) {
callCount++;
if (callCount == 2) {
QUnit.start();
equal(uploadCount, 1, 'Should only be one upload.');
}
equal(result[0].element, editor.$('img')[0]);
equal(result[0].status, false);
}
editor.setContent(imageHtml(testBlobDataUri));
editor.settings.images_upload_handler = function(data, success, failure) {
uploadCount++;
setTimeout(function() {
failure('Error');
}, 0);
};
editor.uploadImages(done);
+110
View File
@@ -0,0 +1,110 @@
ModuleLoader.require([
"tinymce/InsertContent"
], function(InsertContent) {
module("tinymce.InsertContent", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
disable_nodechange: true,
skin: false,
entities: 'raw',
indent: false,
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
function assertSelection(selector, offset) {
var node = editor.$(selector)[0];
var rng = editor.selection.getRng();
equal(rng.startContainer, node.firstChild);
equal(rng.startOffset, offset);
equal(rng.collapsed, true);
}
test('insertAtCaret - i inside text, converts to em', function() {
editor.setContent('<p>1234</p>');
editor.focus();
Utils.setSelection('p', 2);
InsertContent.insertAtCaret(editor, '<i>a</i>');
equal(editor.getContent(), '<p>12<em>a</em>34</p>');
});
test('insertAtCaret - ul at beginning of li', function() {
editor.setContent('<ul><li>12</li></ul>');
editor.focus();
Utils.setSelection('li', 0);
InsertContent.insertAtCaret(editor, '<ul><li>a</li></ul>');
equal(editor.getContent(), '<ul><li>a</li><li>12</li></ul>');
assertSelection('li:nth-child(2)', 0);
});
test('insertAtCaret - ul with multiple items at beginning of li', function() {
editor.setContent('<ul><li>12</li></ul>');
editor.focus();
Utils.setSelection('li', 0);
InsertContent.insertAtCaret(editor, '<ul><li>a</li><li>b</li></ul>');
equal(editor.getContent(), '<ul><li>a</li><li>b</li><li>12</li></ul>');
assertSelection('li:nth-child(3)', 0);
});
test('insertAtCaret - ul at end of li', function() {
editor.setContent('<ul><li>12</li></ul>');
editor.focus();
Utils.setSelection('li', 2);
InsertContent.insertAtCaret(editor, '<ul><li>a</li></ul>');
equal(editor.getContent(), '<ul><li>12</li><li>a</li></ul>');
assertSelection('li:nth-child(2)', 1);
});
test('insertAtCaret - ul with multiple items at end of li', function() {
editor.setContent('<ul><li>12</li></ul>');
editor.focus();
Utils.setSelection('li', 2);
InsertContent.insertAtCaret(editor, '<ul><li>a</li><li>b</li><li>c</li></ul>');
equal(editor.getContent(), '<ul><li>12</li><li>a</li><li>b</li><li>c</li></ul>');
assertSelection('li:nth-child(4)', 1);
});
test('insertAtCaret - ul with multiple items in middle of li', function() {
editor.setContent('<ul><li>12</li></ul>');
editor.focus();
Utils.setSelection('li', 1);
InsertContent.insertAtCaret(editor, '<ul><li>a</li><li>b</li></ul>');
equal(editor.getContent(), '<ul><li>1</li><li>a</li><li>b</li><li>2</li></ul>');
assertSelection('li:nth-child(4)', 1);
});
test('insertAtCaret - ul in middle of li with formatting', function() {
editor.setContent('<ul><li><em><strong>12</strong></em></li></ul>');
editor.focus();
Utils.setSelection('strong', 1);
InsertContent.insertAtCaret(editor, '<ul><li>a</li></ul>');
equal(editor.getContent(), '<ul><li><em><strong>1</strong></em></li><li>a</li><li><em><strong>2</strong></em></li></ul>');
assertSelection('li:nth-child(3) strong', 1);
});
test('insertAtCaret - ul at beginning of li with empty end li', function() {
editor.setContent('<ul><li>12</li></ul>');
editor.focus();
Utils.setSelection('li', 0);
InsertContent.insertAtCaret(editor, '<ul><li>a</li><li></li></ul>');
equal(editor.getContent(), '<ul><li>a</li><li>12</li></ul>');
assertSelection('li:nth-child(2)', 0);
});
test('insertAtCaret - merge inline elements', function() {
editor.setContent('<strong><em>abc</em></strong>');
editor.focus();
Utils.setSelection('em', 1);
InsertContent.insertAtCaret(editor, {content: '<em><strong>123</strong></em>', merge: true});
equal(editor.getContent(), '<p><strong><em>a123bc</em></strong></p>');
});
});
+41
View File
@@ -0,0 +1,41 @@
ModuleLoader.require([
"tinymce/InsertList",
"tinymce/html/Node",
"tinymce/html/DomParser",
"tinymce/dom/DOMUtils"
], function(InsertList, Node, DomParser, DOMUtils) {
module("tinymce.InsertList", {});
var createFragment = function(html) {
var parser = new DomParser({validate: false});
var fragment = parser.parse(html);
return fragment;
};
var createDomFragment = function(html) {
return DOMUtils.DOM.createFragment(html);
};
test('isListFragment', function() {
equal(InsertList.isListFragment(createFragment('<ul><li>x</li></ul>')), true);
equal(InsertList.isListFragment(createFragment('<ol><li>x</li></ol>')), true);
equal(InsertList.isListFragment(createFragment('<meta><ul><li>x</li></ul>')), true);
equal(InsertList.isListFragment(createFragment('<ul><li>x</li></ul><span id="mce_marker"></span>')), true);
equal(InsertList.isListFragment(createFragment('<div></div>')), false);
});
test('listItems', function() {
var list = createDomFragment('<ul><li>a</li><li>b</li><li>c</li></ul>').firstChild;
equal(InsertList.listItems(list).length, 3);
equal(InsertList.listItems(list)[0].nodeName, 'LI');
});
test('trimListItems', function() {
var list = createDomFragment('<ul><li>a</li><li>b</li><li></li></ul>').firstChild;
equal(InsertList.listItems(list).length, 3);
equal(InsertList.trimListItems(InsertList.listItems(list)).length, 2);
});
});
@@ -1,8 +1,9 @@
ModuleLoader.require([
"tinymce/caret/CaretPosition",
"tinymce/caret/CaretContainer",
"tinymce/util/VK"
], function(CaretPosition, CaretContainer, VK) {
"tinymce/util/VK",
"tinymce/text/Zwsp"
], function(CaretPosition, CaretContainer, VK, Zwsp) {
module("tinymce.SelectionOverrides", {
setupModule: function() {
QUnit.stop();
@@ -44,6 +45,11 @@ ModuleLoader.require([
};
}
function assertCaretInCaretBlockContainer() {
var beforeRng = editor.selection.getRng();
equal(CaretContainer.isCaretContainerBlock(beforeRng.startContainer.parentNode), true, 'Not in caret block container.');
}
var leftArrow = pressKey(VK.LEFT);
var rightArrow = pressKey(VK.RIGHT);
var backspace = pressKey(VK.BACKSPACE);
@@ -160,8 +166,148 @@ ModuleLoader.require([
equal(editor.selection.getRng().startContainer, editor.$('div div')[0]);
});
test('backspace from block to after cE=false inline', function() {
editor.setContent('<p>1<span contenteditable="false">2</span></p><p>3</p>');
Utils.setSelection('p:nth-child(2)', 0);
Utils.type('\b');
equal(editor.getContent(), '<p>1<span contenteditable="false">2</span>3</p>');
ok(Zwsp.isZwsp(editor.selection.getRng().startContainer.data));
equal(editor.selection.getRng().startContainer.previousSibling.nodeName, 'SPAN');
});
test('delete from block to before cE=false inline', function() {
editor.setContent('<p>1</p><p><span contenteditable="false">2</span>3</p>');
Utils.setSelection('p:nth-child(1)', 1);
forwardDelete();
equal(editor.getContent(), '<p>1<span contenteditable="false">2</span>3</p>');
ok(Zwsp.isZwsp(editor.selection.getRng().startContainer.data));
equal(editor.selection.getRng().startContainer.nextSibling.nodeName, 'SPAN');
});
test('backspace from before cE=false block to text', function() {
editor.setContent('<p>1</p><p contenteditable="false">2</p><p>3</p>');
editor.selection.select(editor.dom.select('p')[1]);
editor.selection.collapse(true);
assertCaretInCaretBlockContainer();
Utils.type('\b');
var rng = editor.selection.getRng();
equal(editor.getContent(), '<p>1</p><p contenteditable="false">2</p><p>3</p>');
equal(rng.startContainer, editor.dom.select('p')[0].firstChild);
equal(rng.startOffset, 1);
equal(rng.collapsed, true);
});
test('backspace from before first cE=false block', function() {
editor.setContent('<p contenteditable="false">1</p><p>2</p>');
editor.selection.select(editor.dom.select('p')[0]);
editor.selection.collapse(true);
assertCaretInCaretBlockContainer();
Utils.type('\b');
equal(editor.getContent(), '<p contenteditable="false">1</p><p>2</p>');
assertCaretInCaretBlockContainer();
});
test('backspace from before cE=false block to after cE=false block', function() {
editor.setContent('<p contenteditable="false">1</p><p contenteditable="false">2</p>');
editor.selection.select(editor.dom.select('p')[1]);
editor.selection.collapse(true);
assertCaretInCaretBlockContainer();
Utils.type('\b');
var rng = editor.selection.getRng();
equal(editor.getContent(), '<p contenteditable="false">1</p><p contenteditable="false">2</p>');
assertCaretInCaretBlockContainer();
equal(rng.startContainer.parentNode.previousSibling, editor.dom.select('p')[0]);
});
test('delete from after cE=false block to text', function() {
editor.setContent('<p>1</p><p contenteditable="false">2</p><p>3</p>');
editor.selection.select(editor.dom.select('p')[1]);
editor.selection.collapse(false);
assertCaretInCaretBlockContainer();
forwardDelete();
var rng = editor.selection.getRng();
equal(editor.getContent(), '<p>1</p><p contenteditable="false">2</p><p>3</p>');
equal(rng.startContainer, editor.dom.select('p')[2].firstChild);
equal(rng.startOffset, 0);
equal(rng.collapsed, true);
});
test('delete from after last cE=false block', function() {
editor.setContent('<p>1</p><p contenteditable="false">2</p>');
editor.selection.select(editor.dom.select('p')[1]);
editor.selection.collapse(false);
assertCaretInCaretBlockContainer();
forwardDelete();
equal(editor.getContent(), '<p>1</p><p contenteditable="false">2</p>');
assertCaretInCaretBlockContainer();
});
test('delete from after cE=false block to before cE=false block', function() {
editor.setContent('<p contenteditable="false">1</p><p contenteditable="false">2</p>');
editor.selection.select(editor.dom.select('p')[0]);
rightArrow();
assertCaretInCaretBlockContainer();
forwardDelete();
var rng = editor.selection.getRng();
equal(editor.getContent(), '<p contenteditable="false">1</p><p contenteditable="false">2</p>');
assertCaretInCaretBlockContainer();
equal(rng.startContainer.parentNode.nextSibling, editor.dom.select('p')[2]);
});
test('delete from block to before cE=false inline', function() {
editor.setContent('<p>1</p><p><span contenteditable="false">2</span>3</p>');
Utils.setSelection('p:nth-child(1)', 1);
forwardDelete();
equal(editor.getContent(), '<p>1<span contenteditable="false">2</span>3</p>');
ok(Zwsp.isZwsp(editor.selection.getRng().startContainer.data));
equal(editor.selection.getRng().startContainer.nextSibling.nodeName, 'SPAN');
});
test('exit pre block (up)', exitPreTest(upArrow, 0, '<p>\u00a0</p><pre>abc</pre>'));
test('exit pre block (left)', exitPreTest(leftArrow, 0, '<p>\u00a0</p><pre>abc</pre>'));
test('exit pre block (down)', exitPreTest(downArrow, 3, '<pre>abc</pre><p>\u00a0</p>'));
test('exit pre block (right)', exitPreTest(rightArrow, 3, '<pre>abc</pre><p>\u00a0</p>'));
test('click on link in cE=false', function() {
editor.setContent('<p contentEditable="false"><a href="#"><strong>link</strong></a></p>');
var evt = editor.fire('click', {target: editor.$('strong')[0]});
equal(evt.isDefaultPrevented(), true);
});
test('click next to cE=false block', function() {
editor.setContent(
'<table style="width: 100%">' +
'<tr>' +
'<td style="vertical-align: top">1</td>' +
'<td><div contentEditable="false" style="width: 100px; height: 100px">2</div></td>' +
'</tr>' +
'</table>'
);
var firstTd = editor.dom.select('td')[0];
var rect = editor.dom.getRect(firstTd);
editor.fire('mousedown', {
target: firstTd,
clientX: rect.x + rect.w,
clientY: rect.y + 10
});
// Since we can't do a real click we need to check if it gets sucked in towards the cE=false block
equal(editor.selection.getNode().nodeName !== 'P', true);
});
});
+50 -2
View File
@@ -193,7 +193,7 @@ test('No undo/redo cmds on Undo/Redo shortcut', function() {
});
test('Transact', function() {
var count = 0;
var count = 0, level;
editor.undoManager.clear();
@@ -201,12 +201,32 @@ test('Transact', function() {
count++;
});
editor.undoManager.transact(function() {
level = editor.undoManager.transact(function() {
editor.undoManager.add();
editor.undoManager.add();
});
equal(count, 1);
equal(level !== null, true);
});
test('Transact no change', function() {
editor.undoManager.add();
var level = editor.undoManager.transact(function() {
});
equal(level, null);
});
test('Transact with change', function() {
editor.undoManager.add();
var level = editor.undoManager.transact(function() {
editor.setContent('x');
});
equal(level !== null, true);
});
test('Transact nested', function() {
@@ -253,6 +273,34 @@ test('Transact exception', function() {
equal(count, 1);
});
test('Extra with changes', function() {
var data;
editor.undoManager.clear();
editor.setContent('<p>abc</p>');
editor.undoManager.add();
editor.undoManager.extra(function() {
Utils.setSelection('p', 1, 'p', 2);
editor.insertContent('1');
}, function () {
Utils.setSelection('p', 1, 'p', 2);
editor.insertContent('2');
});
data = editor.undoManager.data;
equal(data.length, 3);
equal(data[0].content, '<p>abc</p>');
deepEqual(data[0].bookmark, {start: [0]});
deepEqual(data[0].beforeBookmark, {start: [0]});
equal(data[1].content, '<p>a1c</p>');
deepEqual(data[1].bookmark, {start: [2, 0, 0]});
deepEqual(data[1].beforeBookmark, {start: [2, 0, 0]});
equal(data[2].content, '<p>a2c</p>');
deepEqual(data[2].bookmark, {start: [2, 0, 0]});
deepEqual(data[1].beforeBookmark, data[2].bookmark);
});
test('Exclude internal elements', function() {
var count = 0, lastLevel;
+6 -4
View File
@@ -1,4 +1,6 @@
(function() {
ModuleLoader.require([
"tinymce/dom/Range"
], function(Range) {
module("tinymce.dom.Range", {
setup: function() {
document.getElementById('view').innerHTML = (
@@ -23,7 +25,7 @@
});
function createRng() {
return document.createRange ? document.createRange() : new tinymce.dom.Range(tinymce.DOM);
return document.createRange ? document.createRange() : new Range(tinymce.DOM);
}
function getHTML(co) {
@@ -477,7 +479,7 @@
test("test_compareBoundaryPoints", function() {
var r1 = createRng(), r2 = createRng(), START_TO_START = 0, START_TO_END = 1, END_TO_END = 2, END_TO_START = 3;
r1.setStartBefore(document.getElementById('strong'));
r1.setEndAfter(document.getElementById('strong'));
r2.setStartBefore(document.getElementById('strong'));
@@ -545,4 +547,4 @@
equal(rng.toString().replace(/\r\n/g, ''), "strong second em strong.barsome text");
});
}
})();
});
+26 -1
View File
@@ -646,6 +646,11 @@ ModuleLoader.require([
equal(rng.collapsed, true);
equal(rng.startContainer.nodeType, 3);
equal(rng.startContainer.data, 'b');
// WebKit is in some state state here, so lets restore it
rng.setStart(editor.getBody(), 0);
rng.setEnd(editor.getBody(), 0);
editor.selection.setRng(rng);
});
test('normalize with contentEditable:true parent and contentEditable:false child element', function() {
@@ -657,7 +662,7 @@ ModuleLoader.require([
if (Env.ie && Env.ie < 12) {
// IE automatically normalizes
equal(rng.startContainer.data, 'a');
ok(rng.startContainer.parentNode.contentEditable != 'false');
} else {
equal(CaretContainer.isCaretContainer(rng.startContainer), true);
}
@@ -939,6 +944,26 @@ ModuleLoader.require([
equal(rng.endOffset, 0, 'endOffset offset');
});
test('normalize after table should not move', function() {
var rng;
if (tinymce.isOpera || tinymce.isIE) {
ok(true, "Skipped on Opera/IE since Opera doesn't let you to set the range to document and IE will steal focus.");
return;
}
editor.setContent('a<table><tr><td>b</td></tr></table>');
rng = editor.dom.createRng();
rng.setStart(editor.getBody(), 0);
rng.setEnd(editor.getBody(), 1);
editor.selection.setRng(rng);
editor.selection.normalize();
rng = editor.selection.getRng(true);
equal(rng.endContainer, editor.getBody());
equal(rng.endOffset, 1);
});
/*
test('normalize caret after last BR in block', function() {
var rng;
@@ -1,8 +1,9 @@
ModuleLoader.require([
"tinymce/file/ImageScanner",
"tinymce/file/UploadStatus",
"tinymce/file/BlobCache",
"tinymce/Env"
], function(ImageScanner, BlobCache, Env) {
], function(ImageScanner, UploadStatus, BlobCache, Env) {
if (!tinymce.Env.fileApi) {
return;
}
@@ -12,7 +13,7 @@ ModuleLoader.require([
var base64Src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
QUnit.asyncTest("findAll", function() {
var imageScanner = new ImageScanner(new BlobCache());
var imageScanner = new ImageScanner(new UploadStatus(), new BlobCache());
document.getElementById('view').innerHTML = (
'<img src="' + base64Src + '">' +
@@ -30,7 +31,7 @@ ModuleLoader.require([
});
QUnit.asyncTest("findAll (filtered)", function() {
var imageScanner = new ImageScanner(new BlobCache());
var imageScanner = new ImageScanner(new UploadStatus(), new BlobCache());
function predicate(img) {
return !img.hasAttribute('data-skip');
@@ -0,0 +1,32 @@
ModuleLoader.require([
"tinymce/file/UploadStatus"
], function(UploadStatus) {
module("tinymce.file.UploadStatus");
QUnit.test("hasBlobUri/markPending", function() {
var status = new UploadStatus();
strictEqual(status.hasBlobUri("nonexisting_uri"), false);
status.markPending("existing_uri");
strictEqual(status.isPending("existing_uri"), true);
strictEqual(status.isUploaded("existing_uri"), false);
strictEqual(status.hasBlobUri("existing_uri"), true);
status.markUploaded("existing_uri", "uri");
strictEqual(status.isPending("existing_uri"), false);
strictEqual(status.isUploaded("existing_uri"), true);
strictEqual(status.hasBlobUri("existing_uri"), true);
strictEqual(status.getResultUri("existing_uri"), "uri");
status.markUploaded("existing_uri2", "uri2");
strictEqual(status.isPending("existing_uri"), false);
strictEqual(status.isUploaded("existing_uri"), true);
strictEqual(status.hasBlobUri("existing_uri2"), true);
strictEqual(status.getResultUri("existing_uri2"), "uri2");
status.markPending("existing_uri");
strictEqual(status.hasBlobUri("existing_uri"), true);
status.removeFailed("existing_uri");
strictEqual(status.hasBlobUri("existing_uri"), false);
});
});
+3 -2
View File
@@ -16,9 +16,10 @@
}
test("textbox text, size chars: 5", function() {
var textBox = createTextBox({text: 'X', size: 5});
var textBox1 = createTextBox({text: 'X', size: 5});
var textBox2 = createTextBox({text: 'X', size: 6});
Utils.nearlyEqualRects(Utils.size(textBox), [69, 30], 30);
ok(Utils.size(textBox1)[0] < Utils.size(textBox2)[0]);
});
test("textbox text, size 100x100", function() {
@@ -245,10 +245,10 @@ if (tinymce.isWebKit) {
});
test('Type over bold text in fully selected block and keep bold', function() {
editor.getBody().innerHTML = '<p><i><b>x</b></i></p>';
editor.getBody().innerHTML = '<p><i><b>x</b></i></p><p>y</p>';
Utils.setSelection('b', 0, 'b', 1);
editor.fire("keypress", {keyCode: 65, charCode: 65});
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><i><b>a</b></i></p>');
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><i><b>a</b></i></p><p>y</p>');
equal(editor.selection.getStart().nodeName, 'B');
});
@@ -309,6 +309,31 @@ if (tinymce.isWebKit) {
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p>a</p><p><b><i><br></i></b></p>');
equal(editor.selection.getStart(true).nodeName, 'I');
});
test('Type over all contents', function() {
editor.getBody().innerHTML = '<p>abc</p>';
Utils.setSelection('p', 0, 'p', 3);
editor.fire('keypress', {charCode: 97});
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p>a</p>');
equal(editor.selection.getRng().startContainer.data, 'a');
equal(editor.selection.getRng().startOffset, 1);
});
test('ForwardDelete all contents', function() {
editor.getBody().innerHTML = '<p>abc</p>';
Utils.setSelection('p', 0, 'p', 3);
editor.fire('keydown', {keyCode: 46});
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><br data-mce-bogus="1"></p>');
equal(editor.selection.getStart(true).nodeName, 'P');
});
test('Delete all contents', function() {
editor.getBody().innerHTML = '<p>abc</p>';
Utils.setSelection('p', 0, 'p', 3);
editor.fire('keydown', {keyCode: 8});
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><br data-mce-bogus="1"></p>');
equal(editor.selection.getStart(true).nodeName, 'P');
});
} else {
test("Skipped since the browser isn't WebKit", function() {
ok(true, "Skipped");
+14
View File
@@ -102,3 +102,17 @@ test('isSameOrigin', function() {
ok(new tinymce.util.URI('https://www.site.com:8080').isSameOrigin(new tinymce.util.URI('https://www.site.com')) == false);
ok(new tinymce.util.URI('ftp://www.site.com:1021').isSameOrigin(new tinymce.util.URI('ftp://www.site.com')) == false);
});
test('getDocumentBaseUrl', function() {
var getDocumentBaseUrl = tinymce.util.URI.getDocumentBaseUrl;
equal(getDocumentBaseUrl({protocol: 'file:', host: '', pathname: '/dir/path1/path2'}), 'file:///dir/path1/');
equal(getDocumentBaseUrl({protocol: 'http:', host: 'localhost', pathname: '/dir/path1/path2'}), 'http://localhost/dir/path1/');
equal(getDocumentBaseUrl({protocol: 'https:', host: 'localhost', pathname: '/dir/path1/path2'}), 'https://localhost/dir/path1/');
equal(getDocumentBaseUrl({protocol: 'https:', host: 'localhost', pathname: '/dir/path1/path2/'}), 'https://localhost/dir/path1/path2/');
equal(getDocumentBaseUrl({protocol: 'http:', host: 'localhost:8080', pathname: '/dir/path1/path2'}), 'http://localhost:8080/dir/path1/');
equal(getDocumentBaseUrl({protocol: 'http:', host: 'localhost', pathname: '/dir/path1/path2/file.html'}), 'http://localhost/dir/path1/path2/');
equal(getDocumentBaseUrl({protocol: 'http:', host: 'localhost', pathname: '/'}), 'http://localhost/');
equal(getDocumentBaseUrl({protocol: 'applewebdata:', href: 'applewebdata://something//dir/path1#hash'}), 'applewebdata://something//dir/');
equal(getDocumentBaseUrl({protocol: 'applewebdata:', href: 'applewebdata://something//dir/path1'}), 'applewebdata://something//dir/');
});