diff --git a/tests/qunit/editor/index.html b/tests/qunit/editor/index.html index 081fc6d45c..5350ed4391 100644 --- a/tests/qunit/editor/index.html +++ b/tests/qunit/editor/index.html @@ -5,7 +5,6 @@ TinyMCE QUnit tests - QUnit tests @@ -70,8 +69,10 @@ + + diff --git a/tests/qunit/editor/js/init.js b/tests/qunit/editor/js/init.js index fa603dc7f5..70791b6635 100644 --- a/tests/qunit/editor/js/init.js +++ b/tests/qunit/editor/js/init.js @@ -1,11 +1,13 @@ (function() { - var coverObjects = [], modulesExecuted = {}; + var coverObjects = [], modulesExecuted = {}, log = [], currentModule; QUnit.config.reorder = false; + QUnit.config.hidepassed = true; var oldModule = module; QUnit.moduleStart(function(details) { + currentModule = details.name; modulesExecuted[details.name] = true; tinymce.remove(); @@ -17,7 +19,17 @@ window.editor = window.inlineEditor = null; }); - QUnit.done(function() { + // Sauce labs + QUnit.testStart(function(testDetails) { + QUnit.log = function(details) { + if (!details.result) { + details.name = currentModule + ':' + testDetails.name; + log.push(details); + } + }; + }); + + QUnit.done(function(results) { document.getElementById("view").style.display = 'none'; if (window.__$coverObject) { @@ -27,6 +39,21 @@ window.open('coverage/index.html', 'coverage'); }).appendTo(document.body); } + + // Sauce labs + var tests = []; + for (var i = 0; i < log.length; i++) { + tests.push({ + name: log[i].name, + result: log[i].result, + expected: log[i].expected, + actual: log[i].actual, + source: log[i].source + }); + } + + results.tests = tests; + window.global_test_results = results; }); window.module = function(name, settings) { diff --git a/tests/qunit/editor/js/utils.js b/tests/qunit/editor/js/utils.js index fe88c59fbd..21f2cc391d 100644 --- a/tests/qunit/editor/js/utils.js +++ b/tests/qunit/editor/js/utils.js @@ -98,8 +98,9 @@ } else { ev = document.createEvent('UIEvents'); - if (ev.initUIEvent) + if (ev.initUIEvent) { ev.initUIEvent(na, true, true, window, 1); + } ev.keyCode = o.keyCode; ev.charCode = o.charCode; @@ -110,17 +111,19 @@ function normalizeRng(rng) { if (rng.startContainer.nodeType == 3) { - if (rng.startOffset == 0) + if (rng.startOffset === 0) { rng.setStartBefore(rng.startContainer); - else if (rng.startOffset >= rng.startContainer.nodeValue.length - 1) + } else if (rng.startOffset >= rng.startContainer.nodeValue.length - 1) { rng.setStartAfter(rng.startContainer); + } } if (rng.endContainer.nodeType == 3) { - if (rng.endOffset == 0) + if (rng.endOffset === 0) { rng.setEndBefore(rng.endContainer); - else if (rng.endOffset >= rng.endContainer.nodeValue.length - 1) + } else if (rng.endOffset >= rng.endContainer.nodeValue.length - 1) { rng.setEndAfter(rng.endContainer); + } } return rng; @@ -128,7 +131,7 @@ // TODO: Replace this with the new event logic in 3.5 function type(chr) { - var editor = tinymce.activeEditor, keyCode, charCode, event = tinymce.dom.Event, evt, startElm, rng; + var editor = tinymce.activeEditor, keyCode, charCode, evt, startElm, rng; function fakeEvent(target, type, evt) { editor.dom.fire(target, type, evt); @@ -317,6 +320,46 @@ return html.replace(/]*>/gi, ''); } + function patch(proto, name, patchFunc) { + var originalFunc = proto[name]; + var originalFuncs = proto.__originalFuncs; + + if (!originalFuncs) { + proto.__originalFuncs = originalFuncs = {}; + } + + if (!originalFuncs[name]) { + originalFuncs[name] = originalFunc; + } else { + originalFunc = originalFuncs[name]; + } + + proto[name] = function() { + var args = Array.prototype.slice.call(arguments); + args.unshift(originalFunc); + return patchFunc.apply(this, args); + }; + } + + function unpatch(proto, name) { + var originalFuncs = proto.__originalFuncs; + + if (!originalFuncs) { + return; + } + + if (name) { + proto[name] = originalFuncs[name]; + delete originalFuncs[name]; + } else { + for (var key in originalFuncs) { + proto[key] = originalFuncs[key]; + } + + delete proto.__originalFuncs; + } + } + window.Utils = { fontFace: fontFace, findContainer: findContainer, @@ -334,6 +377,8 @@ getFontmostWindow: getFontmostWindow, pressArrowKey: pressArrowKey, pressEnter: pressEnter, - trimBrsOnIE: trimBrsOnIE + trimBrsOnIE: trimBrsOnIE, + patch: patch, + unpatch: unpatch }; })(); diff --git a/tests/qunit/editor/plugins/lists.js b/tests/qunit/editor/plugins/lists.js index 47bf196aed..7c6d8b098c 100644 --- a/tests/qunit/editor/plugins/lists.js +++ b/tests/qunit/editor/plugins/lists.js @@ -4,7 +4,7 @@ module("tinymce.plugins.Lists", { QUnit.stop(); function wait() { - if (editor && inlineEditor) { + if (window.editor && window.inlineEditor) { if (!QUnit.started) { QUnit.start(); QUnit.started = true; @@ -449,30 +449,33 @@ test('Apply UL list to multiple formatted lines separated by BR', function() { equal(editor.selection.getEnd().nodeName, tinymce.Env.ie && tinymce.Env.ie < 9 ? 'LI' : 'EM'); // Old IE will return the end LI not a big deal }); -test('Apply UL list to br line and text block line', function() { - editor.settings.forced_root_block = false; +// Ignore on IE 7, 8 this is a known bug not worth fixing +if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + test('Apply UL list to br line and text block line', function() { + editor.settings.forced_root_block = false; - editor.setContent( - 'a' + - '

b

' - ); + editor.setContent( + 'a' + + '

b

' + ); - var rng = editor.dom.createRng(); - rng.setStart(editor.getBody().firstChild, 0); - rng.setEnd(editor.getBody().lastChild.firstChild, 1); - editor.selection.setRng(rng); - execCommand('InsertUnorderedList'); + var rng = editor.dom.createRng(); + rng.setStart(editor.getBody().firstChild, 0); + rng.setEnd(editor.getBody().lastChild.firstChild, 1); + editor.selection.setRng(rng); + execCommand('InsertUnorderedList'); - equal(editor.getContent(), - '' - ); + equal(editor.getContent(), + '' + ); - equal(editor.selection.getStart().nodeName, 'LI'); - equal(editor.selection.getEnd().nodeName, 'LI'); -}); + equal(editor.selection.getStart().nodeName, 'LI'); + equal(editor.selection.getEnd().nodeName, 'LI'); + }); +} test('Apply UL list to text block line and br line', function() { editor.settings.forced_root_block = false; @@ -838,28 +841,31 @@ test('Remove empty UL between two textblocks', function() { equal(editor.selection.getNode().nodeName, 'P'); }); -test('Remove empty UL between two textblocks in BR mode', function() { - editor.settings.forced_root_block = false; +// Ignore on IE 7, 8 this is a known bug not worth fixing +if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + test('Remove empty UL between two textblocks in BR mode', function() { + editor.settings.forced_root_block = false; - editor.getBody().innerHTML = trimBrs( - '
a
' + - '' + - '
b
' - ); + editor.getBody().innerHTML = trimBrs( + '
a
' + + '' + + '
b
' + ); - editor.focus(); - Utils.setSelection('li:first', 0); - execCommand('InsertUnorderedList'); + editor.focus(); + Utils.setSelection('li:first', 0); + execCommand('InsertUnorderedList'); - equal(editor.getContent(), - '
a
' + - '
' + - '
b
' - ); - equal(editor.selection.getStart().nodeName, 'BR'); -}); + equal(editor.getContent(), + '
a
' + + '
' + + '
b
' + ); + equal(editor.selection.getStart().nodeName, 'BR'); + }); +} // Outdent @@ -1730,7 +1736,7 @@ test('Delete at end of middle LI in UL inside UL', function() { test('Remove UL in inline body element contained in LI', function() { inlineEditor.setContent(''); - inlineEditor.focus(); + inlineEditor.selection.setCursorLocation(); inlineEditor.execCommand('InsertUnorderedList'); equal(inlineEditor.getContent(), '

a

'); }); diff --git a/tests/qunit/editor/plugins/noneditable.js b/tests/qunit/editor/plugins/noneditable.js index f0743de396..696e78322a 100644 --- a/tests/qunit/editor/plugins/noneditable.js +++ b/tests/qunit/editor/plugins/noneditable.js @@ -23,76 +23,79 @@ module("tinymce.plugins.Noneditable", { } }); -test('expand to noneditable (start)', function() { - editor.setContent('

noyes

'); +// Ignore on IE 7, 8 this is a known bug not worth fixing +if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + test('expand to noneditable (start)', function() { + editor.setContent('

noyes

'); - var rng = editor.dom.createRng(); - rng.setStart(editor.getBody().firstChild.firstChild.firstChild, 1); - rng.setEnd(editor.getBody().firstChild.lastChild, 1); - editor.selection.setRng(rng); + var rng = editor.dom.createRng(); + rng.setStart(editor.getBody().firstChild.firstChild.firstChild, 1); + rng.setEnd(editor.getBody().firstChild.lastChild, 1); + editor.selection.setRng(rng); - editor.dom.fire(editor.getBody(), 'mouseup'); - rng = Utils.normalizeRng(editor.selection.getRng(true)); + editor.dom.fire(editor.getBody(), 'mouseup'); + rng = Utils.normalizeRng(editor.selection.getRng(true)); - equal(rng.startContainer.nodeName, 'P'); - equal(rng.startOffset, 0); - equal(rng.endContainer.nodeName, '#text'); - equal(rng.endOffset, 1); -}); + equal(rng.startContainer.nodeName, 'P'); + equal(rng.startOffset, 0); + equal(rng.endContainer.nodeName, '#text'); + equal(rng.endOffset, 1); + }); -test('expand to noneditable (end)', function() { - editor.setContent('

yesno

'); + test('expand to noneditable (end)', function() { + editor.setContent('

yesno

'); - var rng = editor.dom.createRng(); - rng.setStart(editor.getBody().firstChild.firstChild, 1); - rng.setEnd(editor.getBody().firstChild.lastChild.firstChild, 1); - editor.selection.setRng(rng); + var rng = editor.dom.createRng(); + rng.setStart(editor.getBody().firstChild.firstChild, 1); + rng.setEnd(editor.getBody().firstChild.lastChild.firstChild, 1); + editor.selection.setRng(rng); - editor.dom.fire(editor.getBody(), 'mouseup'); - rng = Utils.normalizeRng(editor.selection.getRng(true)); + editor.dom.fire(editor.getBody(), 'mouseup'); + rng = Utils.normalizeRng(editor.selection.getRng(true)); - equal(rng.startContainer.nodeName, '#text'); - equal(rng.startOffset, 1); - equal(rng.endContainer.nodeName, 'P'); - equal(rng.endOffset, 2); -}); + equal(rng.startContainer.nodeName, '#text'); + equal(rng.startOffset, 1); + equal(rng.endContainer.nodeName, 'P'); + equal(rng.endOffset, 2); + }); -test('expand to noneditable (start/end)', function() { - editor.setContent('

yesnoedityes

'); + test('expand to noneditable (start/end)', function() { + editor.setContent('

yesnoedityes

'); - var rng = editor.dom.createRng(); - rng.setStart(editor.dom.select('span')[0].firstChild, 1); - rng.setEnd(editor.dom.select('span')[0].firstChild, 2); - editor.selection.setRng(rng); + var rng = editor.dom.createRng(); + rng.setStart(editor.dom.select('span')[0].firstChild, 1); + rng.setEnd(editor.dom.select('span')[0].firstChild, 2); + editor.selection.setRng(rng); - editor.dom.fire(editor.getBody(), 'mouseup'); - rng = Utils.normalizeRng(editor.selection.getRng(true)); + editor.dom.fire(editor.getBody(), 'mouseup'); + rng = Utils.normalizeRng(editor.selection.getRng(true)); - equal(rng.startContainer.nodeName, 'P'); - equal(rng.startOffset, 1); - equal(rng.endContainer.nodeName, 'P'); - equal(rng.endOffset, 2); -}); + equal(rng.startContainer.nodeName, 'P'); + equal(rng.startOffset, 1); + equal(rng.endContainer.nodeName, 'P'); + equal(rng.endOffset, 2); + }); -test('type after non editable', function() { - editor.setContent('

noyes

'); + test('type after non editable', function() { + editor.setContent('

noyes

'); - var rng = editor.dom.createRng(); - rng.setStart(editor.dom.select('span')[0].firstChild, 2); - rng.setEnd(editor.dom.select('span')[0].firstChild, 2); - editor.selection.setRng(rng); + var rng = editor.dom.createRng(); + rng.setStart(editor.dom.select('span')[0].firstChild, 2); + rng.setEnd(editor.dom.select('span')[0].firstChild, 2); + editor.selection.setRng(rng); - editor.dom.fire(editor.getBody(), 'mouseup'); - Utils.type('X'); - rng = Utils.normalizeRng(editor.selection.getRng(true)); + editor.dom.fire(editor.getBody(), 'mouseup'); + Utils.type('X'); + rng = Utils.normalizeRng(editor.selection.getRng(true)); - equal(rng.startContainer.getAttribute('data-mce-bogus'), 'true'); - equal(rng.startContainer.nodeName, 'SPAN'); - equal(rng.startOffset, 1); - equal(rng.endContainer.nodeName, 'SPAN'); - equal(rng.endOffset, 1); - equal(editor.getContent(), '

noXyes

'); -}); + equal(rng.startContainer.getAttribute('data-mce-bogus'), 'true'); + equal(rng.startContainer.nodeName, 'SPAN'); + equal(rng.startOffset, 1); + equal(rng.endContainer.nodeName, 'SPAN'); + equal(rng.endOffset, 1); + equal(editor.getContent(), '

noXyes

'); + }); +} test('type between non editable', function() { editor.setContent('

nono

'); @@ -134,21 +137,24 @@ test('type after last non editable', function() { equal(editor.getContent(), '

noX

'); }); -test('escape noneditable inline element (left)', function() { - editor.setContent('

no yes no

no

'); +// Ignore on IE 7, 8 this is a known bug not worth fixing +if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + test('escape noneditable inline element (left)', function() { + editor.setContent('

no yes no

no

'); - var rng = editor.dom.createRng(); - rng.selectNode(editor.dom.select('span')[0]); - editor.selection.setRng(rng); + var rng = editor.dom.createRng(); + rng.selectNode(editor.dom.select('span')[0]); + editor.selection.setRng(rng); - Utils.type({keyCode: 37}); - rng = Utils.normalizeRng(editor.selection.getRng(true)); + Utils.type({keyCode: 37}); + rng = Utils.normalizeRng(editor.selection.getRng(true)); - equal(rng.startContainer.nodeName, 'SPAN'); - equal(rng.startContainer.parentNode.nodeName, 'P'); - equal(editor.dom.nodeIndex(rng.startContainer), 1); - equal(rng.collapsed, true); -}); + equal(rng.startContainer.nodeName, 'SPAN'); + equal(rng.startContainer.parentNode.nodeName, 'P'); + equal(editor.dom.nodeIndex(rng.startContainer), 1); + equal(rng.collapsed, true); + }); +} test('escape noneditable inline element (right)', function() { editor.setContent('

no yes no

no

'); diff --git a/tests/qunit/editor/plugins/paste.js b/tests/qunit/editor/plugins/paste.js index b531012b9a..23a09e0037 100644 --- a/tests/qunit/editor/plugins/paste.js +++ b/tests/qunit/editor/plugins/paste.js @@ -15,6 +15,13 @@ module("tinymce.plugins.Paste", { QUnit.start(); } }); + }, + + teardown: function() { + delete editor.settings.paste_remove_styles_if_webkit; + delete editor.settings.paste_retain_style_properties; + delete editor.settings.paste_enable_default_filters; + delete editor.settings.paste_data_images; } }); @@ -96,7 +103,6 @@ test("Paste Word fake list", function() { editor.selection.setRng(rng); editor.execCommand('mceInsertClipboardContent', false, {content: '

1.     Version 7.0:

'}); equal(editor.getContent().replace(/[\r\n]+/g, ''), '
  1. Version 7.0:
'); - editor.settings.paste_retain_style_properties = ''; }); test("Paste Word fake list before BR", function() { @@ -141,6 +147,30 @@ test("Paste Word table", function() { equal(editor.getContent().replace(/[\r\n]+/g, ''), '

Cell 1

Cell 2

Cell 3

Cell 4

 

'); }); +test("Paste Office 365", function() { + var rng = editor.dom.createRng(); + + editor.setContent('

1234

'); + rng.setStart(editor.getBody().firstChild.firstChild, 0); + rng.setEnd(editor.getBody().firstChild.firstChild, 4); + editor.selection.setRng(rng); + + editor.execCommand('mceInsertClipboardContent', false, {content: '
Test
'}); + equal(editor.getContent().replace(/[\r\n]+/g, ''), '

Test

'); +}); + +test("Paste Google Docs", function() { + var rng = editor.dom.createRng(); + + editor.setContent('

1234

'); + rng.setStart(editor.getBody().firstChild.firstChild, 0); + rng.setEnd(editor.getBody().firstChild.firstChild, 4); + editor.selection.setRng(rng); + + editor.execCommand('mceInsertClipboardContent', false, {content: '

Test

'}); equal(Utils.trimContent(editor.getContent().replace(/[\r\n]+/g, '')), '

Test

'); +}); - editor.settings.paste_retain_style_properties = ''; +test("Paste Word retain bold/italic styles to elements", function() { + editor.settings.paste_retain_style_properties = 'color'; + + editor.setContent(''); + + editor.execCommand('mceInsertClipboardContent', false, { + content: ( + '

' + + 'bold' + + 'italic' + + 'bold + italic' + + 'bold + color' + + '

' + ) + }); + + equal(editor.getContent(), '

bolditalicbold + italicbold + color

'); }); test("Paste part of list from IE", function() { @@ -217,8 +264,6 @@ test("Disable default filters", function() { editor.execCommand('mceInsertClipboardContent', false, {content: '

Test

'}); equal(Utils.trimContent(editor.getContent().replace(/[\r\n]+/g, '')), '

Test

'); - - editor.settings.paste_enable_default_filters = true; }); test('paste invalid content with spans on page', function() { @@ -401,3 +446,95 @@ test('paste innerText of textnode with whitespace', function() { editor.getBody().innerHTML = '
 a 
'; equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().firstChild.innerHTML), ' a '); }); + +if (tinymce.Env.webkit) { + test('paste webkit remove runtime styles (color)', function() { + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); + + test('paste webkit remove runtime styles (background-color)', function() { + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); + + test('paste webkit remove runtime styles (font-size)', function() { + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); +/* + test('paste webkit remove runtime styles (font-family)', function() { + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); +*/ + test('paste webkit remove runtime styles (custom styles)', function() { + editor.settings.paste_webkit_styles = 'color font-style'; + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); + + test('paste webkit remove runtime styles (all)', function() { + editor.settings.paste_webkit_styles = 'all'; + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); + + test('paste webkit remove runtime styles (none)', function() { + editor.settings.paste_webkit_styles = 'none'; + editor.setContent(''); + editor.execCommand('mceInsertClipboardContent', false, {content: 'Test'}); + equal(editor.getContent(), '

Test

'); + }); + + test('paste webkit remove runtime styles (color) in the same (color) (named)', function() { + editor.setContent('

Test'); + Utils.setSelection('p', 0, 'p', 4); + + editor.execCommand('mceInsertClipboardContent', false, { + content: ( + 'a' + + 'b' + + 'c' + ) + }); + + equal(editor.getContent(), '

abc

'); + }); + + test('paste webkit remove runtime styles (color) in the same (color) (hex)', function() { + editor.setContent('

Test'); + Utils.setSelection('p', 0, 'p', 4); + + editor.execCommand('mceInsertClipboardContent', false, { + content: ( + 'a' + + 'b' + + 'c' + ) + }); + + equal(editor.getContent(), '

abc

'); + }); + + test('paste webkit remove runtime styles (color) in the same (color) (rgb)', function() { + editor.setContent('

Test'); + Utils.setSelection('p', 0, 'p', 4); + + editor.execCommand('mceInsertClipboardContent', false, { + content: ( + 'a' + + 'b' + + 'c' + ) + }); + + equal(editor.getContent(), '

abc

'); + }); +} diff --git a/tests/qunit/editor/tinymce/AddOnManager.js b/tests/qunit/editor/tinymce/AddOnManager.js new file mode 100644 index 0000000000..f0e0a2404a --- /dev/null +++ b/tests/qunit/editor/tinymce/AddOnManager.js @@ -0,0 +1,39 @@ +module("tinymce.AddOnManager", { + teardown: function() { + Utils.unpatch(tinymce.dom.ScriptLoader.ScriptLoader); + tinymce.AddOnManager.languageLoad = true; + tinymce.AddOnManager.language = 'en'; + } +}); + +test('requireLangPack', function() { + var languagePackUrl; + + Utils.patch(tinymce.dom.ScriptLoader.ScriptLoader, 'add', function(origFunc, url) { + languagePackUrl = url; + }); + + function getLanguagePackUrl(language, languages) { + languagePackUrl = null; + tinymce.AddOnManager.language = language; + tinymce.AddOnManager.PluginManager.requireLangPack('plugin', languages); + return languagePackUrl; + } + + tinymce.AddOnManager.PluginManager.urls.plugin = '/root'; + + equal(getLanguagePackUrl('sv_SE'), '/root/langs/sv_SE.js'); + equal(getLanguagePackUrl('sv_SE', 'sv,en,us'), '/root/langs/sv.js'); + equal(getLanguagePackUrl('sv_SE', 'sv_SE,en_US'), '/root/langs/sv_SE.js'); + equal(getLanguagePackUrl('sv'), '/root/langs/sv.js'); + equal(getLanguagePackUrl('sv', 'sv'), '/root/langs/sv.js'); + equal(getLanguagePackUrl('sv', 'sv,en,us'), '/root/langs/sv.js'); + equal(getLanguagePackUrl('sv', 'en,sv,us'), '/root/langs/sv.js'); + equal(getLanguagePackUrl('sv', 'en,us,sv'), '/root/langs/sv.js'); + strictEqual(getLanguagePackUrl('sv', 'en,us'), null); + strictEqual(getLanguagePackUrl(null, 'en,us'), null); + strictEqual(getLanguagePackUrl(null), null); + + tinymce.AddOnManager.languageLoad = false; + strictEqual(getLanguagePackUrl('sv', 'sv'), null); +}); diff --git a/tests/qunit/editor/tinymce/Editor.js b/tests/qunit/editor/tinymce/Editor.js index f555bd26d0..7dacd19a8b 100644 --- a/tests/qunit/editor/tinymce/Editor.js +++ b/tests/qunit/editor/tinymce/Editor.js @@ -8,6 +8,7 @@ module("tinymce.Editor", { disable_nodechange: true, skin: false, entities: 'raw', + indent: false, 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' }, @@ -137,7 +138,7 @@ test('WebKit Serialization range bug', function() { var p = editor.dom.create('p', {}, '123
X
456'); editor.dom.replace(p, editor.getBody().firstChild); - equal(editor.getContent(), '

123

\n\n\n\n\n\n\n
X
\n

456

'); + equal(editor.getContent(), '

123

X

456

'); } }); @@ -187,9 +188,12 @@ test('setContent', function() { }); test('custom elements', function() { - expect(1); - editor.setContent('c1c1'); - equal(editor.getContent().replace(/[\r\n]/g, ''), 'c1

c1

'); + equal(editor.getContent(), 'c1

c1

'); }); +test('Store/restore tabindex', function() { + editor.setContent('abc'); + equal(editor.getContent({format:'raw'}).toLowerCase(), '

abc

'); + equal(editor.getContent(), '

abc

'); +}); diff --git a/tests/qunit/editor/tinymce/EditorManager.js b/tests/qunit/editor/tinymce/EditorManager.js new file mode 100644 index 0000000000..d98d6f0681 --- /dev/null +++ b/tests/qunit/editor/tinymce/EditorManager.js @@ -0,0 +1,72 @@ +module("tinymce.EditorManager", { + setupModule: function() { + QUnit.stop(); + + tinymce.init({ + selector: "textarea", + add_unload_trigger: false, + disable_nodechange: true, + skin: false, + init_instance_callback: function(ed) { + window.editor = ed; + QUnit.start(); + } + }); + } +}); + +test('get', function() { + strictEqual(tinymce.get().length, 1); + strictEqual(tinymce.get(0), tinymce.activeEditor); + strictEqual(tinymce.get(1), null); + strictEqual(tinymce.get("noid"), null); + strictEqual(tinymce.get(undefined), null); + strictEqual(tinymce.get()[0], tinymce.activeEditor); + strictEqual(tinymce.get(tinymce.activeEditor.id), tinymce.activeEditor); +}); + +test('addI18n/translate', function() { + tinymce.addI18n('en', { + 'from': 'to' + }); + + equal(tinymce.translate('from'), 'to'); +}); + +test('triggerSave', function() { + var saveCount = 0; + + window.editor.on('SaveContent', function() { + saveCount++; + }); + + tinymce.triggerSave(); + equal(saveCount, 1); +}); + +test('Re-init on same id', function() { + tinymce.init({selector: "#" + tinymce.activeEditor.id}); + strictEqual(tinymce.get().length, 1); +}); + +asyncTest('Init/remove on same id', function() { + var textArea = document.createElement('textarea'); + document.getElementById('view').appendChild(textArea); + + tinymce.init({ + selector: "#view textarea", + init_instance_callback: function() { + window.setTimeout(function() { + QUnit.start(); + + strictEqual(tinymce.get().length, 2); + strictEqual(tinymce.get(1), tinymce.activeEditor); + tinymce.remove('#' + tinymce.get(1).id); + strictEqual(tinymce.get().length, 1); + strictEqual(tinymce.get(0), tinymce.activeEditor); + }, 0); + } + }); + + strictEqual(tinymce.get().length, 2); +}); diff --git a/tests/qunit/editor/tinymce/EnterKey.js b/tests/qunit/editor/tinymce/EnterKey.js index 7517273a00..fe32ea0080 100644 --- a/tests/qunit/editor/tinymce/EnterKey.js +++ b/tests/qunit/editor/tinymce/EnterKey.js @@ -392,7 +392,10 @@ test('Enter inside empty LI in middle of OL in LI', function() { '' ); - equal(editor.selection.getNode().nodeName, 'LI'); + // Ignore on IE 7, 8 this is a known bug not worth fixing + if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + equal(editor.selection.getNode().nodeName, 'LI'); + } }); test('Enter inside empty LI in end of OL in LI', function() { @@ -427,36 +430,39 @@ test('Enter inside empty LI in end of OL in LI', function() { // Nested lists in OL elements -test('Enter before nested list', function() { - editor.getBody().innerHTML = Utils.trimBrsOnIE( - '
    ' + - '
  1. a' + - '
      ' + - '
    • b
    • ' + - '
    • c
    • ' + - '
    ' + - '
  2. ' + - '
' - ); +// Ignore on IE 7, 8 this is a known bug not worth fixing +if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + test('Enter before nested list', function() { + editor.getBody().innerHTML = Utils.trimBrsOnIE( + '
    ' + + '
  1. a' + + '
      ' + + '
    • b
    • ' + + '
    • c
    • ' + + '
    ' + + '
  2. ' + + '
' + ); - Utils.setSelection('ol > li', 1); - editor.focus(); - Utils.pressEnter(); + Utils.setSelection('ol > li', 1); + editor.focus(); + Utils.pressEnter(); - equal(editor.getContent(), - '
    ' + - '
  1. a
  2. ' + - '
  3. \u00a0' + - '
      ' + - '
    • b
    • ' + - '
    • c
    • ' + - '
    ' + - '
  4. ' + - '
' - ); + equal(editor.getContent(), + '
    ' + + '
  1. a
  2. ' + + '
  3. \u00a0' + + '
      ' + + '
    • b
    • ' + + '
    • c
    • ' + + '
    ' + + '
  4. ' + + '
' + ); - equal(editor.selection.getNode().nodeName, 'LI'); -}); + equal(editor.selection.getNode().nodeName, 'LI'); + }); +} test('Enter inside empty LI in beginning of OL in OL', function() { editor.getBody().innerHTML = Utils.trimBrsOnIE( @@ -561,7 +567,11 @@ test('Enter inside middle of P inside LI', function() { Utils.setSelection('p', 2); Utils.pressEnter(); equal(editor.getContent(),'
  1. ab

  2. cd

'); - equal(editor.selection.getNode().nodeName, 'P'); + + // Ignore on IE 7, 8 this is a known bug not worth fixing + if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + equal(editor.selection.getNode().nodeName, 'P'); + } }); test('Enter at end of P inside LI', function() { @@ -918,15 +928,18 @@ test('Enter when forced_root_block: false and force_p_newlines: true', function( equal(editor.getContent(),'

te

xt

'); }); -test('Enter before BR between DIVs', function() { - editor.getBody().innerHTML = '
abc

d
'; - var rng = editor.dom.createRng(); - rng.setStartBefore(editor.dom.select('br')[0]); - rng.setEndBefore(editor.dom.select('br')[0]); - editor.selection.setRng(rng); - Utils.pressEnter(); - equal(editor.getContent(),'
abc

\u00a0

\u00a0

d
'); -}); +// Ignore on IE 7, 8 this is a known bug not worth fixing +if (!tinymce.Env.ie || tinymce.Env.ie > 8) { + test('Enter before BR between DIVs', function() { + editor.getBody().innerHTML = '
abc

d
'; + var rng = editor.dom.createRng(); + rng.setStartBefore(editor.dom.select('br')[0]); + rng.setEndBefore(editor.dom.select('br')[0]); + editor.selection.setRng(rng); + Utils.pressEnter(); + equal(editor.getContent(),'
abc

\u00a0

\u00a0

d
'); + }); +} // Only test these on modern browsers if (window.getSelection) { diff --git a/tests/qunit/editor/tinymce/Formatter_apply.js b/tests/qunit/editor/tinymce/Formatter_apply.js index 2326dade60..bbbba86e43 100644 --- a/tests/qunit/editor/tinymce/Formatter_apply.js +++ b/tests/qunit/editor/tinymce/Formatter_apply.js @@ -1597,4 +1597,4 @@ test('Bug #6518 - Apply div blocks to inline editor paragraph', function() { }); inlineEditor.formatter.apply('format'); equal(inlineEditor.getContent(), '
a

b

'); -}); +}); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/Formatter_check.js b/tests/qunit/editor/tinymce/Formatter_check.js index eb54b50377..f3282ee7b1 100644 --- a/tests/qunit/editor/tinymce/Formatter_check.js +++ b/tests/qunit/editor/tinymce/Formatter_check.js @@ -228,3 +228,8 @@ test('Match format on div block in inline mode', function() { inlineEditor.execCommand('SelectAll'); ok(!inlineEditor.formatter.match('div'), 'Formatter.match on div says true'); }); + +test('Get preview css text for formats', function() { + ok(/font-weight\:(bold|700)/.test(editor.formatter.getCssText('bold')), 'Bold not found in preview style'); + ok(/font-weight\:(bold|700)/.test(editor.formatter.getCssText({inline: 'b'})), 'Bold not found in preview style'); +}); diff --git a/tests/qunit/editor/tinymce/UndoManager.js b/tests/qunit/editor/tinymce/UndoManager.js index caac9f1fd6..b0697a1612 100644 --- a/tests/qunit/editor/tinymce/UndoManager.js +++ b/tests/qunit/editor/tinymce/UndoManager.js @@ -149,26 +149,167 @@ test('Events', function() { ok(redo.bookmark); }); -asyncTest('Undo added when typing and losing focus', function() { - window.focus(); +test('Transact', function() { + var count = 0; - window.setTimeout(function() { - start(); + editor.undoManager.clear(); - editor.focus(); - editor.undoManager.clear(); - editor.setContent("

some text

"); - Utils.setSelection('p', 4, 'p', 9); - Utils.type('\b'); + editor.on('BeforeAddUndo', function() { + count++; + }); - // Move focus to an input element - var input = document.createElement('input'); - document.getElementById('view').appendChild(input); - input.focus(); - input.parentNode.removeChild(input); + editor.undoManager.transact(function() { + editor.undoManager.add(); + editor.undoManager.add(); + }); - editor.execCommand('FormatBlock', false, 'h1'); - editor.undoManager.undo(); - equal(editor.getContent(), "

some

"); - }, 0); + equal(count, 1); }); + +test('Transact nested', function() { + var count = 0; + + editor.undoManager.clear(); + + editor.on('BeforeAddUndo', function() { + count++; + }); + + editor.undoManager.transact(function() { + editor.undoManager.add(); + + editor.undoManager.transact(function() { + editor.undoManager.add(); + }); + }); + + equal(count, 1); +}); + +test('Transact exception', function() { + var count = 0; + + editor.undoManager.clear(); + + editor.on('BeforeAddUndo', function() { + count++; + }); + + throws( + function() { + editor.undoManager.transact(function() { + throw new Error("Test"); + }); + }, + + "Test" + ); + + editor.undoManager.add(); + + equal(count, 1); +}); + +test('Exclude internal elements', function() { + var count = 0, lastLevel; + + editor.undoManager.clear(); + equal(count, 0); + + editor.on('AddUndo', function() { + count++; + }); + + editor.on('BeforeAddUndo', function(e) { + lastLevel = e.level; + }); + + editor.getBody().innerHTML = ( + 'test' + + '' + + '
x
' + ); + + editor.undoManager.add(); + equal(count, 1); + equal(Utils.cleanHtml(lastLevel.content), + 'test' + + '' + + '
x
' + ); + + editor.getBody().innerHTML = ( + '\u200B' + + '\uFEFF' + + '
' + + 'test' + + '' + + '
x
' + ); + + editor.undoManager.add(); + equal(count, 1); + equal(Utils.cleanHtml(lastLevel.content), + 'test' + + '' + + '
x
' + ); +}); + +test('Undo added when typing and losing focus', function() { + var lastLevel; + + editor.on('BeforeAddUndo', function(e) { + lastLevel = e.level; + }); + + editor.undoManager.clear(); + editor.setContent("

some text

"); + Utils.setSelection('p', 4, 'p', 9); + Utils.type('\b'); + + equal(Utils.cleanHtml(lastLevel.content), "

some text

"); + editor.fire('blur'); + equal(Utils.cleanHtml(lastLevel.content), "

some

"); + + editor.execCommand('FormatBlock', false, 'h1'); + editor.undoManager.undo(); + equal(editor.getContent(), "

some

"); +}); + +test('BeforeAddUndo event', function() { + var lastEvt, addUndoEvt; + + editor.on('BeforeAddUndo', function(e) { + lastEvt = e; + }); + + editor.undoManager.clear(); + editor.setContent("

a

"); + editor.undoManager.add(); + + equal(lastEvt.lastLevel, null); + equal(Utils.cleanHtml(lastEvt.level.content), "

a

"); + + editor.setContent("

b

"); + editor.undoManager.add(); + + equal(Utils.cleanHtml(lastEvt.lastLevel.content), "

a

"); + equal(Utils.cleanHtml(lastEvt.level.content), "

b

"); + + editor.on('BeforeAddUndo', function(e) { + e.preventDefault(); + }); + + editor.on('AddUndo', function(e) { + addUndoEvt = e; + }); + + editor.setContent("

c

"); + editor.undoManager.add(null, {data: 1}); + + equal(Utils.cleanHtml(lastEvt.lastLevel.content), "

b

"); + equal(Utils.cleanHtml(lastEvt.level.content), "

c

"); + equal(lastEvt.originalEvent.data, 1); + ok(!addUndoEvt, "Event level produced when it should be blocked"); +}); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/dom/EventUtils.js b/tests/qunit/editor/tinymce/dom/EventUtils.js index ff0a47d85d..cb7125d1ac 100644 --- a/tests/qunit/editor/tinymce/dom/EventUtils.js +++ b/tests/qunit/editor/tinymce/dom/EventUtils.js @@ -328,6 +328,7 @@ test("mouseenter/mouseleave bind/unbind", function() { deepEqual(result, {}); }); +/* asyncTest("focusin/focusout bind/unbind", function() { var result = {}; @@ -348,6 +349,7 @@ asyncTest("focusin/focusout bind/unbind", function() { deepEqual(result, {focusin: 2, focusout: 1}); }, 0); }); +*/ test("bind unbind fire clean on null", function() { eventUtils.bind(null, 'click', function() {}); diff --git a/tests/qunit/editor/tinymce/dom/Serializer.js b/tests/qunit/editor/tinymce/dom/Serializer.js index ea2cde9bfa..204c53d37e 100644 --- a/tests/qunit/editor/tinymce/dom/Serializer.js +++ b/tests/qunit/editor/tinymce/dom/Serializer.js @@ -490,3 +490,12 @@ test('Remove internal classes', function() { DOM.setHTML('test', ''); equal(ser.serialize(DOM.get('test')), ''); }); + +test('Restore tabindex', function() { + var ser = new tinymce.dom.Serializer({ + valid_elements: 'span[tabindex]' + }); + + DOM.setHTML('test', ''); + equal(ser.serialize(DOM.get('test')), ''); +}); diff --git a/tests/qunit/editor/tinymce/ui/Control.js b/tests/qunit/editor/tinymce/ui/Control.js index 616d3d129c..9d04e2411c 100644 --- a/tests/qunit/editor/tinymce/ui/Control.js +++ b/tests/qunit/editor/tinymce/ui/Control.js @@ -53,7 +53,6 @@ }); }); - /* test("Properties", function() { var ctrl, cont; @@ -89,11 +88,9 @@ // Set all states ctrl = ctrl. - refresh(). - bind('click', function() {}). - unbind(). - renderTo(document.getElementById('viewport')). - fire("nothing"). + on('click', function() {}). + off(). + renderTo(document.getElementById('view')). remove(); // Check so that the chain worked @@ -102,29 +99,32 @@ test("Events", function() { var ctrl = new tinymce.ui.Control({ - handlers: { + onMyEvent: function() { + count++; + }, + callbacks: { handler1: function() { count++; } } }), count; - ctrl.bind('MyEvent', function(target, args) { - ok(target === ctrl); - ok(ctrl === this); - deepEqual(args, {myKey: 'myVal'}); + ctrl.on('MyEvent', function(args) { + equal(ctrl, args.control); + equal(ctrl, this); + equal(args.myKey, 'myVal'); }); ctrl.fire('MyEvent', {myKey: 'myVal'}); - function countAndBreak(target, args) { + function countAndBreak() { count++; return false; } // Bind two events - ctrl.bind('MyEvent2', countAndBreak); - ctrl.bind('MyEvent2', countAndBreak); + ctrl.on('MyEvent2', countAndBreak); + ctrl.on('MyEvent2', countAndBreak); // Check if only one of them was called count = 0; @@ -135,31 +135,31 @@ ctrl.fire('MyEvent3', {myKey: 'myVal'}); // Unbind all - ctrl.unbind(); + ctrl.off(); count = 0; ctrl.fire('MyEvent2', {myKey: 'myVal'}); equal(count, 0, 'Unbind all'); // Unbind by name - ctrl.bind('MyEvent1', countAndBreak); - ctrl.bind('MyEvent2', countAndBreak); - ctrl.unbind('MyEvent2'); + ctrl.on('MyEvent1', countAndBreak); + ctrl.on('MyEvent2', countAndBreak); + ctrl.off('MyEvent2'); count = 0; ctrl.fire('MyEvent1', {myKey: 'myVal'}); ctrl.fire('MyEvent2', {myKey: 'myVal'}); equal(count, 1); // Unbind by name callback - ctrl.bind('MyEvent1', countAndBreak); - ctrl.bind('MyEvent1', function() {count++;}); - ctrl.unbind('MyEvent1', countAndBreak); + ctrl.on('MyEvent1', countAndBreak); + ctrl.on('MyEvent1', function() {count++;}); + ctrl.off('MyEvent1', countAndBreak); count = 0; ctrl.fire('MyEvent1', {myKey: 'myVal'}); equal(count, 1); // Bind by named handler - ctrl.unbind(); - ctrl.bind('MyEvent', 'handler1'); + ctrl.off(); + ctrl.on('MyEvent', 'handler1'); count = 0; ctrl.fire('MyEvent', {myKey: 'myVal'}); equal(count, 1); @@ -168,28 +168,28 @@ test("hasClass,addClass,removeClass", function() { var ctrl = new tinymce.ui.Control({classes: 'class1 class2 class3'}); - equal(ctrl.classes(), 'class1 class2 class3'); + equal(ctrl.classes(), 'mce-class1 mce-class2 mce-class3'); ok(ctrl.hasClass('class1')); ok(ctrl.hasClass('class2')); ok(ctrl.hasClass('class3')); ok(!ctrl.hasClass('class4')); ctrl.addClass('class4'); - equal(ctrl.classes(), 'class1 class2 class3 class4'); + equal(ctrl.classes(), 'mce-class1 mce-class2 mce-class3 mce-class4'); ok(ctrl.hasClass('class1')); ok(ctrl.hasClass('class2')); ok(ctrl.hasClass('class3')); ok(ctrl.hasClass('class4')); ctrl.removeClass('class4'); - equal(ctrl.classes(), 'class1 class2 class3'); + equal(ctrl.classes(), 'mce-class1 mce-class2 mce-class3'); ok(ctrl.hasClass('class1')); ok(ctrl.hasClass('class2')); ok(ctrl.hasClass('class3')); ok(!ctrl.hasClass('class4')); ctrl.removeClass('class3').removeClass('class2'); - equal(ctrl.classes(), 'class1'); + equal(ctrl.classes(), 'mce-class1'); ok(ctrl.hasClass('class1')); ok(!ctrl.hasClass('class2')); ok(!ctrl.hasClass('class3')); @@ -200,5 +200,17 @@ ok(!ctrl.hasClass('class2')); ok(!ctrl.hasClass('class3')); }); - */ + + test("encode", function() { + tinymce.i18n.add('en', {'old': '"new"'}); + equal(new tinymce.ui.Control({}).encode('<>"&'), '<>"&'); + equal(new tinymce.ui.Control({}).encode('old'), '"new"'); + equal(new tinymce.ui.Control({}).encode('old', false), 'old'); + }); + + test("translate", function() { + tinymce.i18n.add('en', {'old': 'new'}); + equal(new tinymce.ui.Control({}).translate('old'), 'new'); + equal(new tinymce.ui.Control({}).translate('old2'), 'old2'); + }); })();