TinyMCE: update the tests for version 4.5.6. Remove default plugins tests, it is quite pointless to keep repeating them at this point.

See #40305.


git-svn-id: https://develop.svn.wordpress.org/trunk@40399 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Andrew Ozz 2017-04-09 23:10:15 +00:00
parent 860363337f
commit d37198f240
61 changed files with 1950 additions and 7999 deletions

View File

@ -40,6 +40,9 @@
<script src="tinymce/caret/LineUtils.js"></script>
<script src="tinymce/caret/LineWalker.js"></script>
<!-- tinymce.content.* -->
<script src="tinymce/content/LinkTargets.js"></script>
<!-- tinymce.geom.* -->
<script src="tinymce/geom/Rect.js"></script>
<script src="tinymce/geom/ClientRect.js"></script>
@ -51,6 +54,8 @@
<!-- tinymce.fmt.* -->
<script src="tinymce/fmt/Hooks.js"></script>
<script src="tinymce/fmt/Preview.js"></script>
<script src="tinymce/fmt/FontInfo.js"></script>
<!-- tinymce.text.* -->
<script src="tinymce/text/ExtendingChar.js"></script>
@ -86,6 +91,7 @@
<script src="tinymce/ui/Collection.js"></script>
<script src="tinymce/ui/ColorButton.js"></script>
<script src="tinymce/ui/Control.js"></script>
<!--<script src="tinymce/ui/FilePicker.js"></script>-->
<script src="tinymce/ui/FitLayout.js"></script>
<script src="tinymce/ui/FlexLayout.js"></script>
<script src="tinymce/ui/GridLayout.js"></script>
@ -97,6 +103,12 @@
<script src="tinymce/ui/TextBox.js"></script>
<script src="tinymce/ui/Window.js"></script>
<!-- tinymce.undo.* -->
<script src="tinymce/undo/Diff.js"></script>
<script src="tinymce/undo/Fragments.js"></script>
<script src="tinymce/undo/Levels.js"></script>
<script src="tinymce/undo/ForcedRootBlock.js"></script>
<!-- tinymce.util.* -->
<script src="tinymce/util/Color.js"></script>
<script src="tinymce/util/EventDispatcher.js"></script>
@ -115,12 +127,15 @@
<!-- tinymce.* -->
<script src="tinymce/AddOnManager.js"></script>
<script src="tinymce/options.js"></script>
<script src="tinymce/Editor.js"></script>
<script src="tinymce/Editor_rtl.js"></script>
<script src="tinymce/EditorCustomTheme.js"></script>
<script src="tinymce/EditorUpload.js"></script>
<script src="tinymce/EditorCommands.js"></script>
<script src="tinymce/EditorManager.js"></script>
<script src="tinymce/EnterKey.js"></script>
<script src="tinymce/FocusManager.js"></script>
<script src="tinymce/ForceBlocks.js"></script>
<script src="tinymce/Formatter_apply.js"></script>
<script src="tinymce/Formatter_check.js"></script>
@ -130,29 +145,11 @@
<script src="tinymce/SelectionOverrides.js"></script>
<script src="tinymce/WindowManager.js"></script>
<script src="tinymce/InsertContent.js"></script>
<script src="tinymce/InsertContentForcedRootFalse.js"></script>
<script src="tinymce/InsertList.js"></script>
<script src="tinymce/NotificationManager.js"></script>
<!-- tinymce.plugins.* -->
<!--<script src="plugins/autolink.js"></script>-->
<script src="plugins/charmap.js"></script>
<!--<script src="plugins/autosave.js"></script>-->
<!--<script src="plugins/fullpage.js"></script>-->
<script src="plugins/image.js"></script>
<!--<script src="plugins/importcss.js"></script>-->
<!--<script src="plugins/jquery_plugin.js"></script>-->
<!--<script src="plugins/jquery_initialization.js"></script>-->
<!--<script src="plugins/legacyoutput.js"></script>-->
<!--<script src="plugins/link.js"></script>-->
<script src="plugins/lists.js"></script>
<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>-->
<!--<script src="plugins/textpattern.js"></script>-->
<!--<script src="plugins/wordcount.js"></script>-->
</body>
</html>

View File

@ -4,7 +4,7 @@
QUnit.config.reorder = false;
QUnit.config.hidepassed = true;
window.editor = window.inlineEditor = null;
window.editor = window.inlineEditor = null;
var oldModule = module;
@ -23,12 +23,12 @@
// Sauce labs
QUnit.testStart(function(testDetails) {
QUnit.log = function(details) {
QUnit.log(function(details) {
if (!details.result) {
details.name = currentModule + ':' + testDetails.name;
log.push(details);
}
};
});
});
QUnit.done(function(results) {

View File

@ -571,6 +571,11 @@ if ( !defined.document || document.readyState === "complete" ) {
config.autorun = true;
}
if (document.location.search.indexOf('bedrock') !== -1) {
config.autorun = false;
config.autostart = false;
}
QUnit.load = function() {
runLoggingCallbacks( "begin", QUnit, {} );

View File

@ -4,4 +4,6 @@ document.write('<script src="../../../src/wp-includes/js/tinymce/tinymce.js"></s
var wpPlugins = 'charmap colorpicker hr lists media paste tabfocus textcolor ' +
'fullscreen wordpress wpautoresize wpeditimage wpgallery wplink wpdialogs wpview';
var $ = window.jQuery;
getUserSetting = setUserSetting = function() {}

View File

@ -1,80 +0,0 @@
(function() {
module("tinymce.plugins.Autolink", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
plugins: 'autolink',
autosave_ask_before_unload: false,
indent: false,
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
function typeUrl(url) {
editor.setContent('<p>' + url + '</p>');
Utils.setSelection('p', url.length);
Utils.type(' ');
return editor.getContent();
}
function typeAnEclipsedURL(url) {
url = "(" + url;
editor.setContent('<p>' + url + '</p>');
Utils.setSelection('p', url.length);
Utils.type(')');
return editor.getContent();
}
function typeNewlineURL(url) {
editor.setContent('<p>' + url + '</p>');
Utils.setSelection('p', url.length);
Utils.type('\n');
return editor.getContent();
}
if (tinymce.Env.ie) {
test("Skipped on IE since it has built in logic for autolink", function() {
ok(true);
});
return;
}
test("Urls ended with space", function() {
equal(typeUrl('http://www.domain.com'), '<p><a href="http://www.domain.com">http://www.domain.com</a></p>');
equal(typeUrl('https://www.domain.com'), '<p><a href="https://www.domain.com">https://www.domain.com</a></p>');
equal(typeUrl('ssh://www.domain.com'), '<p><a href="ssh://www.domain.com">ssh://www.domain.com</a></p>');
equal(typeUrl('ftp://www.domain.com'), '<p><a href="ftp://www.domain.com">ftp://www.domain.com</a></p>');
equal(typeUrl('www.domain.com'), '<p><a href="http://www.domain.com">www.domain.com</a></p>');
equal(typeUrl('www.domain.com.'), '<p><a href="http://www.domain.com">www.domain.com</a>.</p>');
equal(typeUrl('user@domain.com'), '<p><a href="mailto:user@domain.com">user@domain.com</a></p>');
equal(typeUrl('mailto:user@domain.com'), '<p><a href="mailto:user@domain.com">mailto:user@domain.com</a></p>');
equal(typeUrl('first-last@domain.com'), '<p><a href="mailto:first-last@domain.com">first-last@domain.com</a></p>');
});
test("Urls ended with )", function() {
equal(typeAnEclipsedURL('http://www.domain.com'), '<p>(<a href="http://www.domain.com">http://www.domain.com</a>)</p>');
equal(typeAnEclipsedURL('https://www.domain.com'), '<p>(<a href="https://www.domain.com">https://www.domain.com</a>)</p>');
equal(typeAnEclipsedURL('ssh://www.domain.com'), '<p>(<a href="ssh://www.domain.com">ssh://www.domain.com</a>)</p>');
equal(typeAnEclipsedURL('ftp://www.domain.com'), '<p>(<a href="ftp://www.domain.com">ftp://www.domain.com</a>)</p>');
equal(typeAnEclipsedURL('www.domain.com'), '<p>(<a href="http://www.domain.com">www.domain.com</a>)</p>');
equal(typeAnEclipsedURL('www.domain.com.'), '<p>(<a href="http://www.domain.com">www.domain.com</a>.)</p>');
});
test("Urls ended with new line", function() {
equal(typeNewlineURL('http://www.domain.com'), '<p><a href="http://www.domain.com">http://www.domain.com</a></p><p>&nbsp;</p>');
equal(typeNewlineURL('https://www.domain.com'), '<p><a href="https://www.domain.com">https://www.domain.com</a></p><p>&nbsp;</p>');
equal(typeNewlineURL('ssh://www.domain.com'), '<p><a href="ssh://www.domain.com">ssh://www.domain.com</a></p><p>&nbsp;</p>');
equal(typeNewlineURL('ftp://www.domain.com'), '<p><a href="ftp://www.domain.com">ftp://www.domain.com</a></p><p>&nbsp;</p>');
equal(typeNewlineURL('www.domain.com'), '<p><a href="http://www.domain.com">www.domain.com</a></p><p>&nbsp;</p>');
equal(typeNewlineURL('www.domain.com.'), '<p><a href="http://www.domain.com">www.domain.com</a>.</p><p>&nbsp;</p>');
});
})();

View File

@ -1,74 +0,0 @@
module("tinymce.plugins.Autosave", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
plugins: 'autosave',
autosave_ask_before_unload: false,
init_instance_callback: function(ed) {
window.editor = ed;
editor.plugins.autosave.removeDraft();
QUnit.start();
}
});
}
});
test("isEmpty true", function() {
ok(editor.plugins.autosave.isEmpty(''));
ok(editor.plugins.autosave.isEmpty(' '));
ok(editor.plugins.autosave.isEmpty('\t\t\t'));
ok(editor.plugins.autosave.isEmpty('<p id="x"></p>'));
ok(editor.plugins.autosave.isEmpty('<p></p>'));
ok(editor.plugins.autosave.isEmpty('<p> </p>'));
ok(editor.plugins.autosave.isEmpty('<p>\t</p>'));
ok(editor.plugins.autosave.isEmpty('<p><br></p>'));
ok(editor.plugins.autosave.isEmpty('<p><br /></p>'));
ok(editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" /></p>'));
ok(editor.plugins.autosave.isEmpty('<p><br><br></p>'));
ok(editor.plugins.autosave.isEmpty('<p><br /><br /></p>'));
ok(editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" /><br data-mce-bogus="true" /></p>'));
});
test("isEmpty false", function() {
ok(!editor.plugins.autosave.isEmpty('X'));
ok(!editor.plugins.autosave.isEmpty(' X'));
ok(!editor.plugins.autosave.isEmpty('\t\t\tX'));
ok(!editor.plugins.autosave.isEmpty('<p>X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p> X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p>\tX</p>'));
ok(!editor.plugins.autosave.isEmpty('<p><br>X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p><br />X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" />X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p><br><br>X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p><br /><br />X</p>'));
ok(!editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" /><br data-mce-bogus="true" />X</p>'));
ok(!editor.plugins.autosave.isEmpty('<h1></h1>'));
ok(!editor.plugins.autosave.isEmpty('<img src="x" />'));
});
test("hasDraft/storeDraft/restoreDraft", function() {
ok(!editor.plugins.autosave.hasDraft());
editor.setContent('X');
editor.undoManager.add();
editor.plugins.autosave.storeDraft();
ok(editor.plugins.autosave.hasDraft());
editor.setContent('Y');
editor.undoManager.add();
editor.plugins.autosave.restoreDraft();
equal(editor.getContent(), '<p>X</p>');
});

View File

@ -1,91 +0,0 @@
ModuleLoader.require([
], function() {
module("tinymce.plugins.CharMap", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
plugins: "charmap",
add_unload_trigger: false,
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
test('Replace characters by array', function() {
editor.settings.charmap = [
[65, 'Latin A'],
[66, 'Latin B']
];
deepEqual(editor.plugins.charmap.getCharMap(), [
[65, 'Latin A'],
[66, 'Latin B']
]);
});
test('Replace characters by function', function() {
editor.settings.charmap = function() {
return [
[65, 'Latin A fun'],
[66, 'Latin B fun']
];
};
deepEqual(editor.plugins.charmap.getCharMap(), [
[65, 'Latin A fun'],
[66, 'Latin B fun']
]);
});
test('Append characters by array', function() {
editor.settings.charmap = [
[67, 'Latin C']
];
editor.settings.charmap_append = [
[65, 'Latin A'],
[66, 'Latin B']
];
deepEqual(editor.plugins.charmap.getCharMap(), [
[67, 'Latin C'],
[65, 'Latin A'],
[66, 'Latin B']
]);
});
test('Append characters by function', function() {
editor.settings.charmap = [
[67, 'Latin C']
];
editor.settings.charmap_append = function() {
return [
[65, 'Latin A fun'],
[66, 'Latin B fun']
];
};
deepEqual(editor.plugins.charmap.getCharMap(), [
[67, 'Latin C'],
[65, 'Latin A fun'],
[66, 'Latin B fun']
]);
});
test('Insert character', function() {
var lastEvt;
editor.on('insertCustomChar', function(e) {
lastEvt = e;
});
editor.plugins.charmap.insertChar('A');
equal(lastEvt.chr, 'A');
});
});

View File

@ -1,125 +0,0 @@
module("tinymce.plugins.Fullpage", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
plugins: "fullpage",
add_unload_trigger: false,
skin: false,
valid_styles: {
'*': 'text-align,padding-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'
},
indent: 0,
setup: function(ed) {
ed.on('NodeChange', false);
},
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
editor.getBody().dir = 'ltr';
}
});
test('Keep header/footer intact', function() {
expect(2);
function normalizeHTML(html) {
return html.replace(/\s/g, '');
}
editor.setContent('<html><body><p>Test</p>');
equal(normalizeHTML(editor.getContent()), '<html><body><p>Test</p>', 'Invalid HTML content is still editable.');
editor.setContent('<html><body><p>Test</p></body></html>');
equal(normalizeHTML(editor.getContent()), '<html><body><p>Test</p></body></html>', 'Header/footer is intact.');
});
test('Default header/footer', function() {
expect(1);
editor.setContent('<p>Test</p>');
equal(editor.getContent(), '<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body>\n<p>Test</p>\n</body>\n</html>', 'Invalid HTML content is still editable.');
});
test('Parse body attributes', function() {
expect(9);
editor.setContent('<html><body><p>Test</p></body></html>');
equal(editor.getBody().style.color, '', 'No color on body.');
equal(editor.getBody().dir, '', 'No dir on body.');
equal(editor.dom.getStyle(editor.getBody().firstChild, 'display', true), 'block', 'No styles added to iframe document');
editor.setContent('<html><body style="color:#FF0000"><p>Test</p></body></html>');
ok(editor.getBody().style.color.length > 0, 'Color added to body');
editor.setContent('<html><body dir="rtl"><p>Test</p></body></html>');
equal(editor.getBody().dir, 'rtl', 'Dir added to body');
editor.setContent('<html><head><style>p {text-align:right}</style></head><body dir="rtl"><p>Test</p></body></html>');
equal(editor.dom.getStyle(editor.getBody().firstChild, 'text-align', true), 'right', 'Styles added to iframe document');
editor.setContent('<html><body><p>Test</p></body></html>');
equal(editor.getBody().style.color, '', 'No color on body.');
equal(editor.getBody().dir, '', 'No dir on body.');
equal(editor.dom.getStyle(editor.getBody().firstChild, 'display', true), 'block', 'No styles added to iframe document');
});
test('fullpage_hide_in_source_view: false', function() {
editor.settings.fullpage_hide_in_source_view = false;
editor.setContent('<html><body><p>1</p></body></html>');
equal(editor.getContent({source_view: true}), '<html><body>\n<p>1</p>\n</body></html>');
});
test('fullpage_hide_in_source_view: false', function() {
editor.settings.fullpage_hide_in_source_view = true;
editor.setContent('<html><body><p>1</p></body></html>');
equal(editor.getContent({source_view: true}), '<p>1</p>');
});
test('link elements', function() {
editor.setContent('<html><head><link rel="stylesheet" href="a.css"><link rel="something"></head><body><p>c</p></body></html>');
equal(editor.getContent(), '<html><head><link rel="stylesheet" href="a.css"><link rel="something"></head><body>\n<p>c</p>\n</body></html>');
});
test('add/remove stylesheets', function() {
function hasLink(href) {
var links = editor.getDoc().getElementsByTagName('link');
for (var i = 0; i < links.length; i++) {
if (links[i].href.indexOf('/' + href) != -1) {
return true;
}
}
}
editor.setContent('<html><head><link rel="stylesheet" href="a.css"></head><body><p>c</p></body></html>');
ok(hasLink("a.css"));
ok(!hasLink("b.css"));
ok(!hasLink("c.css"));
editor.setContent('<html><head><link rel="stylesheet" href="a.css"><link rel="stylesheet" href="b.css"></head><body><p>c</p></body></html>');
ok(hasLink("a.css"));
ok(hasLink("b.css"));
ok(!hasLink("c.css"));
editor.setContent('<html><head><link rel="stylesheet" href="a.css"><link rel="stylesheet" href="b.css"><link rel="stylesheet" href="c.css"></head><body><p>c</p></body></html>');
ok(hasLink("a.css"));
ok(hasLink("b.css"));
ok(hasLink("c.css"));
editor.setContent('<html><head><link rel="stylesheet" href="a.css"></head><body><p>c</p></body></html>');
ok(hasLink("a.css"));
ok(!hasLink("b.css"));
ok(!hasLink("c.css"));
editor.setContent('<html><head></head><body><p>c</p></body></html>');
ok(!hasLink("a.css"));
ok(!hasLink("b.css"));
ok(!hasLink("c.css"));
});

View File

@ -1,641 +0,0 @@
(function() {
module("tinymce.plugins.Image", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: 'textarea',
add_unload_trigger: false,
skin: false,
plugins: "image",
disable_nodechange: true,
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
delete editor.settings.image_dimensions;
delete editor.settings.file_browser_callback;
delete editor.settings.image_list;
delete editor.settings.image_class_list;
delete editor.settings.document_base_url;
delete editor.settings.image_advtab;
delete editor.settings.image_caption;
var win = Utils.getFrontmostWindow();
if (win) {
win.close();
}
}
});
function cleanHtml(html) {
return Utils.cleanHtml(html).replace(/<p>(&nbsp;|<br[^>]+>)<\/p>$/, '');
}
function fillAndSubmitWindowForm(data) {
var win = Utils.getFrontmostWindow();
win.fromJSON(data);
win.find('form')[0].submit();
win.close();
}
test('Default image dialog on empty editor', function() {
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"constrain": true,
"height": "",
"src": "",
"width": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"height": "100",
"src": "src",
"width": "200"
});
equal(
cleanHtml(editor.getContent()),
'<p><img src="src" alt="alt" width="200" height="100" /></p>'
);
});
test('Image dialog image_dimensions: false', function() {
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"src": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"src": "src"
});
equal(
cleanHtml(editor.getContent()),
'<p><img src="src" alt="alt" /></p>'
);
});
if (tinymce.Env.ceFalse) {
test('All image dialog ui options on empty editor', function() {
editor.settings.image_caption = true;
editor.settings.image_list = [
{title: 'link1', value: 'link1'},
{title: 'link2', value: 'link2'}
];
editor.settings.image_class_list = [
{title: 'class1', value: 'class1'},
{title: 'class2', value: 'class2'}
];
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"class": "class1",
"constrain": true,
"caption": false,
"height": "",
"src": "",
"width": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"class": "class1",
"constrain": true,
"caption": true,
"height": "200",
"src": "src",
"width": "100"
});
equal(
cleanHtml(editor.getContent()),
'<figure class="image"><img class="class1" src="src" alt="alt" width="100" height="200" /><figcaption>caption</figcaption></figure>'
);
});
} else {
test('All image dialog ui options on empty editor (old IE)', function() {
editor.settings.image_caption = true;
editor.settings.image_list = [
{title: 'link1', value: 'link1'},
{title: 'link2', value: 'link2'}
];
editor.settings.image_class_list = [
{title: 'class1', value: 'class1'},
{title: 'class2', value: 'class2'}
];
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"class": "class1",
"constrain": true,
"height": "",
"src": "",
"width": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"class": "class1",
"constrain": true,
"caption": true,
"height": "200",
"src": "src",
"width": "100"
});
equal(
cleanHtml(editor.getContent()),
'<p><img class="class1" src="src" alt="alt" width="100" height="200" /></p>'
);
});
}
test("Image recognizes relative src url and prepends relative image_prepend_url setting.", function() {
var win, elementId, element;
editor.settings.image_prepend_url = 'testing/images/';
editor.setContent('');
editor.execCommand('mceImage', true);
var data = {
"src": "src",
"alt": "alt"
};
win = Utils.getFrontmostWindow();
elementId = win.find('#src')[0]._id;
element = document.getElementById(elementId).childNodes[0];
win.fromJSON(data);
Utils.triggerElementChange(element);
win.find('form')[0].submit();
win.close();
equal(
cleanHtml(editor.getContent()),
'<p><img src="' + editor.settings.image_prepend_url + 'src" alt="alt" /></p>'
);
});
test("Image recognizes relative src url and prepends absolute image_prepend_url setting.", function() {
var win, elementId, element;
editor.settings.image_prepend_url = 'http://localhost/images/';
editor.setContent('');
editor.execCommand('mceImage', true);
var data = {
"src": "src",
"alt": "alt"
};
win = Utils.getFrontmostWindow();
elementId = win.find('#src')[0]._id;
element = document.getElementById(elementId).childNodes[0];
win.fromJSON(data);
Utils.triggerElementChange(element);
win.find('form')[0].submit();
win.close();
equal(
cleanHtml(editor.getContent()),
'<p><img src="' + editor.settings.image_prepend_url + 'src" alt="alt" /></p>'
);
});
test('Advanced image dialog border option on empty editor', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"border": "10px",
"src": "src"
});
equal(
cleanHtml(editor.getContent()),
'<p><img style="border-width: 10px;" src="src" alt="alt" /></p>'
);
});
test('Advanced image dialog margin space options on empty editor', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"hspace": "10",
"src": "src",
"vspace": "10"
});
equal(
cleanHtml(editor.getContent()),
'<p><img style="margin: 10px;" src="src" alt="alt" /></p>'
);
});
test('Advanced image dialog border style only options on empty editor', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"src": "src",
"style": "border-width: 10px;"
});
equal(
cleanHtml(editor.getContent()),
'<p><img style="border-width: 10px;" src="src" alt="alt" /></p>'
);
});
test('Advanced image dialog margin style only options on empty editor', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"src": "src",
"style": "margin: 10px;"
});
equal(
cleanHtml(editor.getContent()),
'<p><img style="margin: 10px;" src="src" alt="alt" /></p>'
);
});
test('Advanced image dialog overriden border style options on empty editor', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"border": "10",
"src": "src",
"style": "border-width: 15px;"
});
equal(
cleanHtml(editor.getContent()),
'<p><img style="border-width: 10px;" src="src" alt="alt" /></p>'
);
});
test('Advanced image dialog overriden margin style options on empty editor', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
fillAndSubmitWindowForm({
"alt": "alt",
"hspace": "10",
"src": "src",
"style": "margin-left: 15px; margin-top: 20px;",
"vspace": "10"
});
equal(
cleanHtml(editor.getContent()),
'<p><img style="margin: 10px;" src="src" alt="alt" /></p>'
);
});
test('Advanced image dialog non-shorthand horizontal margin style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin-left: 15px; margin-right: 15px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "15",
"src": "",
"style": "margin-left: 15px; margin-right: 15px;",
"vspace": ""
});
});
test('Advanced image dialog non-shorthand vertical margin style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin-top: 15px; margin-bottom: 15px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "margin-top: 15px; margin-bottom: 15px;",
"vspace": "15"
});
});
test('Advanced image dialog shorthand margin 1 value style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin: 5px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "5",
"src": "",
"style": "margin: 5px;",
"vspace": "5"
});
});
test('Advanced image dialog shorthand margin 2 value style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin: 5px 10px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "10",
"src": "",
"style": "margin: 5px 10px 5px 10px;",
"vspace": "5"
});
});
test('Advanced image dialog shorthand margin 2 value style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin: 5px 10px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "10",
"src": "",
"style": "margin: 5px 10px 5px 10px;",
"vspace": "5"
});
});
test('Advanced image dialog shorthand margin 3 value style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin: 5px 10px 15px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "10",
"src": "",
"style": "margin: 5px 10px 15px 10px;",
"vspace": ""
});
});
test('Advanced image dialog shorthand margin 4 value style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin: 5px 10px 15px 20px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "margin: 5px 10px 15px 20px;",
"vspace": ""
});
});
test('Advanced image dialog shorthand margin 4 value style change test', function(){
editor.settings.image_advtab = true;
editor.settings.image_dimensions = false;
editor.setContent('');
editor.execCommand('mceImage', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "",
"vspace": ""
});
Utils.getFrontmostWindow().find('#style').value('margin: 5px 10px 15px 20px; margin-top: 15px;').fire('change');
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"alt": "",
"border": "",
"hspace": "",
"src": "",
"style": "margin: 15px 10px 15px 20px;",
"vspace": "15"
});
});
})();

View File

@ -1,350 +0,0 @@
(function() {
var menuCtrl;
module("tinymce.plugins.ImportCSS", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
plugins: 'importcss',
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
if (menuCtrl) {
menuCtrl.remove();
menuCtrl = null;
}
editor.contentCSS = [];
delete editor.settings.importcss_file_filter;
delete editor.settings.importcss_merge_classes;
delete editor.settings.importcss_append;
delete editor.settings.importcss_selector_filter;
delete editor.settings.importcss_groups;
delete editor.settings.importcss_exclusive;
delete editor.settings.importcss_selector_converter;
}
});
function fireFormatsMenuEvent(styleSheets, items) {
menuCtrl = tinymce.ui.Factory.create('menu', {
items: items
}).renderTo(document.getElementById('view'));
return editor.fire('renderFormatsMenu', {
control: menuCtrl,
doc: {
styleSheets: styleSheets
}
});
}
function getMenuItemFormat(item) {
return editor.formatter.get(item.settings.format)[0];
}
test("Import content_css files", function() {
editor.contentCSS.push("test1.css");
editor.contentCSS.push("test2.css");
var evt = fireFormatsMenuEvent([
{
href: 'test1.css',
cssRules: [
{selectorText: '.a'},
{selectorText: 'p.b'},
{selectorText: 'img.c'}
]
},
{href: 'test2.css', cssRules: [{selectorText: '.d'}]},
{href: 'test3.css', cssRules: [{selectorText: '.e'}]}
]);
equal(evt.control.items().length, 4);
equal(evt.control.items()[0].text(), 'a');
equal(getMenuItemFormat(evt.control.items()[0]).classes, 'a');
equal(evt.control.items()[1].text(), 'p.b');
equal(getMenuItemFormat(evt.control.items()[1]).block, 'p');
equal(getMenuItemFormat(evt.control.items()[1]).classes, 'b');
equal(evt.control.items()[2].text(), 'img.c');
equal(getMenuItemFormat(evt.control.items()[2]).selector, 'img');
equal(getMenuItemFormat(evt.control.items()[2]).classes, 'c');
equal(evt.control.items()[3].text(), 'd');
});
test("Import custom importcss_merge_classes: false", function() {
editor.contentCSS.push("test.css");
editor.settings.importcss_merge_classes = false;
var evt = fireFormatsMenuEvent([
{href: 'test.css', cssRules: [{selectorText: '.a'}]}
]);
equal(evt.control.items().length, 1);
deepEqual(getMenuItemFormat(evt.control.items()[0]).attributes, {"class": "a"});
});
test("Import custom importcss_append: true", function() {
editor.contentCSS.push("test.css");
editor.settings.importcss_append = true;
var evt = fireFormatsMenuEvent([
{href: 'test.css', cssRules: [{selectorText: '.b'}]}
], {text: 'a'});
equal(evt.control.items().length, 2);
equal(evt.control.items()[0].text(), 'a');
equal(evt.control.items()[1].text(), 'b');
});
test("Import custom importcss_selector_filter (string)", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_selector_filter = ".a";
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'}
]}
]);
equal(evt.control.items().length, 1);
equal(evt.control.items()[0].text(), 'a');
});
test("Import custom importcss_selector_filter (function)", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_selector_filter = function(selector) {
return selector === ".a";
};
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'}
]}
]);
equal(evt.control.items().length, 1);
equal(evt.control.items()[0].text(), 'a');
});
test("Import custom importcss_selector_filter (regexp)", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_selector_filter = /a/;
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'}
]}
]);
equal(evt.control.items().length, 1);
equal(evt.control.items()[0].text(), 'a');
});
test("Import custom importcss_groups", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_groups = [
{title: 'g1', filter: /a/},
{title: 'g2', filter: /b/},
{title: 'g3'}
];
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'},
{selectorText: '.c'}
]}
]);
equal(evt.control.items().length, 3);
equal(evt.control.items()[0].text(), 'g1');
equal(evt.control.items()[0].settings.menu[0].text, 'a');
equal(evt.control.items()[1].text(), 'g2');
equal(evt.control.items()[1].settings.menu[0].text, 'b');
equal(evt.control.items()[2].text(), 'g3');
equal(evt.control.items()[2].settings.menu[0].text, 'c');
});
test("Import custom importcss_file_filter (string)", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_file_filter = "test2.css";
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [{selectorText: '.a'}]},
{href: 'test2.css', cssRules: [{selectorText: '.b'}]}
]);
equal(evt.control.items().length, 1);
equal(evt.control.items()[0].text(), 'b');
});
test("Import custom importcss_file_filter (function)", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_file_filter = function(href) {
return href === "test2.css";
};
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [{selectorText: '.a'}]},
{href: 'test2.css', cssRules: [{selectorText: '.b'}]}
]);
equal(evt.control.items().length, 1);
equal(evt.control.items()[0].text(), 'b');
});
test("Import custom importcss_file_filter (regexp)", function() {
editor.contentCSS.push("test1.css");
editor.settings.importcss_file_filter = /test2\.css/;
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [{selectorText: '.a'}]},
{href: 'test2.css', cssRules: [{selectorText: '.b'}]}
]);
equal(evt.control.items().length, 1);
equal(evt.control.items()[0].text(), 'b');
});
test("Import custom importcss_selector_converter", function() {
editor.settings.importcss_groups = [
{title: 'g1', filter: /\.a/, custom: 'A'},
{title: 'g2', filter: /\.b/, custom: 'B'},
{title: 'g3', custom: 'C'}
];
editor.contentCSS.push("test1.css");
editor.settings.importcss_selector_converter = function (selector, group) {
return {
title: selector + group.custom,
inline: 'span'
};
};
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'},
{selectorText: '.c'}
]}
]);
var items = evt.control.items();
equal(items.length, 3);
equal(items[0].text(), 'g1');
equal(items[0].settings.menu[0].text, '.aA');
equal(items[1].text(), 'g2');
equal(items[1].settings.menu[0].text, '.bB');
equal(items[2].text(), 'g3');
equal(items[2].settings.menu[0].text, '.cC');
});
test("Import custom group selector_converter", function() {
var constant = function (format) {
return function () {
return format;
};
};
var formatA = {
title: 'my format a',
selector: 'p'
};
var formatB = {
title: 'my format b',
selector: 'h1'
};
editor.settings.importcss_groups = [
{title: 'g1', filter: /\.a/, selector_converter: constant(formatA)},
{title: 'g2', filter: /\.b/, selector_converter: constant(formatB)},
{title: 'g3', custom: 'C'}
];
editor.contentCSS.push("test1.css");
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'},
{selectorText: '.c'}
]}
]);
var items = evt.control.items();
equal(items.length, 3);
equal(items[0].text(), 'g1');
equal(items[0].settings.menu[0].text, 'my format a');
equal(items[1].text(), 'g2');
equal(items[1].settings.menu[0].text, 'my format b');
equal(items[2].text(), 'g3');
equal(items[2].settings.menu[0].text, 'c');
});
test("Import custom importcss_exclusive: true", function() {
editor.settings.importcss_exclusive = true;
editor.settings.importcss_groups = [
{title: 'g1'},
{title: 'g2'}
];
editor.contentCSS.push("test1.css");
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'},
{selectorText: '.c'}
]}
]);
var items = evt.control.items();
equal(items.length, 1);
equal(items[0].text(), 'g1');
equal(items[0].settings.menu[0].text, 'a');
equal(items[0].settings.menu[1].text, 'b');
});
test("Import custom importcss_exclusive: false", function() {
editor.settings.importcss_exclusive = false;
editor.settings.importcss_groups = [
{title: 'g1'},
{title: 'g2'}
];
editor.contentCSS.push("test1.css");
var evt = fireFormatsMenuEvent([
{href: 'test1.css', cssRules: [
{selectorText: '.a'},
{selectorText: '.b'},
{selectorText: '.c'}
]}
]);
var items = evt.control.items();
equal(items.length, 2);
equal(items[0].text(), 'g1');
equal(items[0].settings.menu[0].text, 'a');
equal(items[0].settings.menu[1].text, 'b');
equal(items[1].text(), 'g2');
equal(items[1].settings.menu[0].text, 'a');
equal(items[1].settings.menu[1].text, 'b');
});
})();

View File

@ -1,40 +0,0 @@
module("tinymce.plugins.jQueryInitialization", {
setupModule: function() {
document.getElementById('view').innerHTML = (
'<textarea id="elm1"></textarea>' +
'<textarea id="elm2"></textarea>'
);
this.val = $.fn.val;
QUnit.stop();
$(function() {
QUnit.start();
});
},
teardown: function() {
$.fn.val = this.val;
}
});
test("applyPatch is only called once", function() {
expect(1);
var options = {plugins: [
"pagebreak,layer,table,save,emoticons,insertdatetime,preview,media,searchreplace",
"print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,template"
]},
oldValFn;
$('#elm1').tinymce(options);
oldValFn = $.fn.val = function() {
// no-op
};
$('#elm2').tinymce(options);
equal($.fn.val, oldValFn);
});

View File

@ -1,96 +0,0 @@
module("tinymce.plugins.jQuery", {
setupModule: function() {
document.getElementById('view').innerHTML = (
'<textarea id="elm1"></textarea>' +
'<textarea id="elm2"></textarea>' +
'<textarea id="elm3">Textarea</textarea>'
);
QUnit.stop();
$(function() {
$('#elm1,#elm2').tinymce({
plugins: [
"pagebreak,layer,table,save,emoticons,insertdatetime,preview,media,searchreplace",
"print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,template"
],
init_instance_callback: function() {
var ed1 = tinymce.get('elm1'), ed2 = tinymce.get('elm2');
// When both editors are initialized
if (ed1 && ed1.initialized && ed2 && ed2.initialized) {
QUnit.start();
}
}
});
});
}
});
test("Get editor instance", function() {
equal($('#elm1').tinymce().id, 'elm1');
equal($('#elm2').tinymce().id, 'elm2');
equal($('#elm3').tinymce(), null);
});
test("Get contents using jQuery", function() {
expect(4);
tinymce.get('elm1').setContent('<p>Editor 1</p>');
equal($('#elm1').html(), '<p>Editor 1</p>');
equal($('#elm1').val(), '<p>Editor 1</p>');
equal($('#elm1').attr('value'), '<p>Editor 1</p>');
equal($('#elm1').text(), 'Editor 1');
});
test("Set contents using jQuery", function() {
expect(4);
$('#elm1').html('Test 1');
equal($('#elm1').html(), '<p>Test 1</p>');
$('#elm1').val('Test 2');
equal($('#elm1').html(), '<p>Test 2</p>');
$('#elm1').text('Test 3');
equal($('#elm1').html(), '<p>Test 3</p>');
$('#elm1').attr('value', 'Test 4');
equal($('#elm1').html(), '<p>Test 4</p>');
});
test("append/prepend contents using jQuery", function() {
expect(2);
tinymce.get('elm1').setContent('<p>Editor 1</p>');
$('#elm1').append('<p>Test 1</p>');
equal($('#elm1').html(), '<p>Editor 1</p>\n<p>Test 1</p>');
$('#elm1').prepend('<p>Test 2</p>');
equal($('#elm1').html(), '<p>Test 2</p>\n<p>Editor 1</p>\n<p>Test 1</p>');
});
test("Find using :tinymce selector", function() {
expect(1);
equal($('textarea:tinymce').length, 2);
});
test("Set contents using :tinymce selector", function() {
expect(3);
$('textarea:tinymce').val('Test 1');
equal($('#elm1').val(), '<p>Test 1</p>');
equal($('#elm2').val(), '<p>Test 1</p>');
equal($('#elm3').val(), 'Textarea');
});
test("Get contents using :tinymce selector", function() {
expect(1);
$('textarea:tinymce').val('Test get');
equal($('textarea:tinymce').val(), '<p>Test get</p>');
});

View File

@ -1,93 +0,0 @@
module("tinymce.plugins.Legacyoutput", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
plugins: 'legacyoutput',
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
test("Font color", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('forecolor', false, '#FF0000');
equal(editor.getContent().toLowerCase(), '<p><font color="#ff0000">text</font></p>');
});
test("Font size", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('fontsize', false, 7);
equal(editor.getContent(), '<p><font size="7">text</font></p>');
});
test("Font face", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('fontname', false, "times");
equal(editor.getContent(), '<p><font face="times">text</font></p>');
});
test("Bold", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('bold');
equal(editor.getContent(), '<p><b>text</b></p>');
});
test("Italic", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('italic');
equal(editor.getContent(), '<p><i>text</i></p>');
});
test("Underline", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('underline');
equal(editor.getContent(), '<p><u>text</u></p>');
});
test("Strikethrough", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('strikethrough');
equal(editor.getContent(), '<p><strike>text</strike></p>');
});
test("Justifyleft", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('justifyleft');
equal(editor.getContent(), '<p align="left">text</p>');
});
test("Justifycenter", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('justifycenter');
equal(editor.getContent(), '<p align="center">text</p>');
});
test("Justifyright", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('justifyright');
equal(editor.getContent(), '<p align="right">text</p>');
});
test("Justifyfull", function() {
editor.setContent('<p>text</p>');
Utils.setSelection('p', 0, 'p', 4);
editor.execCommand('justifyfull');
equal(editor.getContent(), '<p align="justify">text</p>');
});

View File

@ -1,182 +0,0 @@
(function() {
var nonRelativeRegex = /^\w+:/i;
module("tinymce.plugins.Link", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: 'textarea',
add_unload_trigger: false,
skin: false,
indent: false,
plugins: "link",
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
delete editor.settings.file_browser_callback;
delete editor.settings.link_list;
delete editor.settings.link_class_list;
delete editor.settings.link_target_list;
delete editor.settings.rel_list;
var win = Utils.getFrontmostWindow();
if (win) {
win.close();
}
}
});
function cleanHtml(html) {
return Utils.cleanHtml(html).replace(/<p>(&nbsp;|<br[^>]+>)<\/p>$/, '');
}
function fillAndSubmitWindowForm(data) {
var win = Utils.getFrontmostWindow();
win.fromJSON(data);
win.find('form')[0].submit();
win.close();
}
test('Default link dialog on empty editor', function() {
editor.setContent('');
editor.execCommand('mceLink', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"href": "",
"target": "",
"text": "",
"title": ""
});
fillAndSubmitWindowForm({
"href": "href",
"target": "_blank",
"text": "text",
"title": "title"
});
equal(
cleanHtml(editor.getContent()),
'<p><a title="title" href="href" target="_blank">text</a></p>'
);
});
test('Default link dialog on text selection', function() {
editor.setContent('<p>abc</p>');
Utils.setSelection('p', 1, 'p', 2);
editor.execCommand('mceLink', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"href": "",
"target": "",
"text": "b",
"title": ""
});
fillAndSubmitWindowForm({
"href": "href",
"target": "_blank",
"title": "title"
});
equal(
cleanHtml(editor.getContent()),
'<p>a<a title="title" href="href" target="_blank">b</a>c</p>'
);
});
test('Default link dialog on non pure text selection', function() {
editor.setContent('<p>a</p><p>bc</p>');
Utils.setSelection('p:nth-child(1)', 0, 'p:nth-child(2)', 2);
editor.execCommand('mceLink', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"href": "",
"target": "",
"title": ""
});
fillAndSubmitWindowForm({
"href": "href",
"target": "_blank",
"title": "title"
});
equal(
cleanHtml(editor.getContent()),
'<p><a title="title" href="href" target="_blank">a</a></p>' +
'<p><a title="title" href="href" target="_blank">bc</a></p>'
);
});
test('All lists link dialog on empty editor', function() {
editor.settings.link_list = [
{title: 'link1', value: 'link1'},
{title: 'link2', value: 'link2'}
];
editor.settings.link_class_list = [
{title: 'class1', value: 'class1'},
{title: 'class2', value: 'class2'}
];
editor.settings.target_list = [
{title: 'target1', value: 'target1'},
{title: 'target2', value: 'target2'}
];
editor.settings.rel_list = [
{title: 'rel1', value: 'rel1'},
{title: 'rel2', value: 'rel2'}
];
editor.setContent('');
editor.execCommand('mceLink', true);
deepEqual(Utils.getFrontmostWindow().toJSON(), {
"class": "class1",
"href": "",
"rel": "rel1",
"target": "target1",
"text": "",
"title": ""
});
fillAndSubmitWindowForm({
"href": "href",
"text": "text",
"title": "title"
});
equal(
cleanHtml(editor.getContent()),
'<p><a class="class1" title="title" href="href" target="target1" rel="rel1">text</a></p>'
);
});
//Since there's no capability to use the confirm dialog with unit tests, simply test the regex we're using
test('Test new regex for non relative link setting ftp', function() {
equal(nonRelativeRegex.test('ftp://testftp.com'), true);
});
test('Test new regex for non relative link setting http', function() {
equal(nonRelativeRegex.test('http://testhttp.com'), true);
});
test('Test new regex for non relative link setting relative', function() {
equal(nonRelativeRegex.test('testhttp.com'), false);
});
test('Test new regex for non relative link setting relative base', function() {
equal(nonRelativeRegex.test('/testjpg.jpg'), false);
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -1,205 +0,0 @@
module("tinymce.plugins.Media", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
plugins: 'media',
live_embeds: false,
document_base_url: '/tinymce/tinymce/trunk/tests/',
extended_valid_elements: 'script[src|type]',
media_scripts: [
{filter: 'http://media1.tinymce.com'},
{filter: 'http://media2.tinymce.com', width: 100, height: 200}
],
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
delete editor.settings.media_filter_html;
delete editor.settings.media_live_embeds;
}
});
function fillAndSubmitWindowForm(data) {
var win = Utils.getFrontmostWindow();
win.fromJSON(data);
win.find('form')[0].submit();
win.close();
}
test('Default media dialog on empty editor', function() {
editor.settings.media_live_embeds = false;
editor.setContent('');
editor.plugins.media.showDialog();
deepEqual(Utils.getFrontmostWindow().toJSON(), {
constrain: true,
embed: "",
height: "",
poster: "",
source1: "",
source2: "",
width: ""
});
fillAndSubmitWindowForm({
"source1": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
});
equal(
editor.getContent(),
'<p><iframe src=\"//www.youtube.com/embed/dQw4w9WgXcQ\" width=\"560\" height=\"314\" allowfullscreen=\"allowfullscreen\"></iframe></p>'
);
});
test("Object retain as is", function() {
editor.setContent(
'<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="355">' +
'<param name="movie" value="someurl">' +
'<param name="wmode" value="transparent">' +
'<embed src="someurl" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355" />' +
'</object>'
);
equal(editor.getContent(),
'<p><object width="425" height="355" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">' +
'<param name="movie" value="someurl" />' +
'<param name="wmode" value="transparent" />' +
'<embed src="someurl" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355" />' +
'</object></p>'
);
});
test("Embed retain as is", function() {
editor.setContent(
'<embed src="320x240.ogg" width="100" height="200">text<a href="#">link</a></embed>'
);
equal(
editor.getContent(),
'<p><embed src="320x240.ogg" width="100" height="200"></embed>text<a href="#">link</a></p>'
);
});
test("Video retain as is", function() {
editor.setContent(
'<video src="320x240.ogg" autoplay loop controls>text<a href="#">link</a></video>'
);
equal(
editor.getContent(),
'<p><video src="320x240.ogg" autoplay="autoplay" loop="loop" controls="controls" width="300" height="150">text<a href="#">link</a></video></p>'
);
});
test("Iframe retain as is", function() {
editor.setContent(
'<iframe src="320x240.ogg" allowfullscreen>text<a href="#">link</a></iframe>'
);
equal(editor.getContent(),
'<p><iframe src="320x240.ogg" width="300" height="150" allowfullscreen="allowfullscreen">text<a href="#">link</a></iframe></p>'
);
});
test("Audio retain as is", function() {
editor.setContent(
'<audio src="sound.mp3">' +
'<track kind="captions" src="foo.en.vtt" srclang="en" label="English">' +
'<track kind="captions" src="foo.sv.vtt" srclang="sv" label="Svenska">' +
'text<a href="#">link</a>' +
'</audio>'
);
equal(editor.getContent(),
'<p>' +
'<audio src="sound.mp3">' +
'<track kind="captions" src="foo.en.vtt" srclang="en" label="English" />' +
'<track kind="captions" src="foo.sv.vtt" srclang="sv" label="Svenska" />' +
'text<a href="#">link</a>' +
'</audio>' +
'</p>'
);
});
test("Resize complex object", function() {
editor.setContent(
'<video width="300" height="150" controls="controls">' +
'<source src="s" />' +
'<object type="application/x-shockwave-flash" data="../../js/tinymce/plugins/media/moxieplayer.swf" width="300" height="150">' +
'<param name="allowfullscreen" value="true" />' +
'<param name="allowscriptaccess" value="always" />' +
'<param name="flashvars" value="video_src=s" />' +
'<!--[if IE]><param name="movie" value="../../js/tinymce/plugins/media/moxieplayer.swf" /><![endif]-->' +
'</object>' +
'</video>'
);
var placeholderElm = editor.getBody().firstChild.firstChild;
placeholderElm.width = 100;
placeholderElm.height = 200;
editor.fire('objectResized', {target: placeholderElm, width: placeholderElm.width, height: placeholderElm.height});
editor.settings.media_filter_html = false;
equal(editor.getContent(),
'<p>' +
'<video controls="controls" width="100" height="200">' +
'<source src="s" />' +
'<object type="application/x-shockwave-flash" data="../../js/tinymce/plugins/media/moxieplayer.swf" width="100" height="200">' +
'<param name="allowfullscreen" value="true" />' +
'<param name="allowscriptaccess" value="always" />' +
'<param name="flashvars" value="video_src=s" />' +
'<!--[if IE]>' +
'<param name="movie" value="../../js/tinymce/plugins/media/moxieplayer.swf" />' +
'<![endif]-->' +
'</object>' +
'</video>' +
'</p>'
);
});
test("Media script elements", function() {
editor.setContent(
'<script src="http://media1.tinymce.com/123456"></sc' + 'ript>' +
'<script src="http://media2.tinymce.com/123456"></sc' + 'ript>'
);
equal(editor.getBody().getElementsByTagName('img')[0].className, 'mce-object mce-object-script');
equal(editor.getBody().getElementsByTagName('img')[0].width, 300);
equal(editor.getBody().getElementsByTagName('img')[0].height, 150);
equal(editor.getBody().getElementsByTagName('img')[1].className, 'mce-object mce-object-script');
equal(editor.getBody().getElementsByTagName('img')[1].width, 100);
equal(editor.getBody().getElementsByTagName('img')[1].height, 200);
equal(editor.getContent(),
'<p>\n' +
'<script src="http://media1.tinymce.com/123456" type="text/javascript"></sc' + 'ript>\n' +
'<script src="http://media2.tinymce.com/123456" type="text/javascript"></sc' + 'ript>\n' +
'</p>'
);
});
test("XSS content", function() {
function testXss(input, expectedOutput) {
editor.setContent(input);
equal(editor.getContent(), expectedOutput);
}
testXss('<video><a href="javascript:alert(1);">a</a></video>', '<p><video width="300" height="150"><a>a</a></video></p>');
testXss('<video><img src="x" onload="alert(1)"></video>', '<p><video width="300" height=\"150\"></video></p>');
testXss('<video><img src="x"></video>', '<p><video width="300" height="150"><img src="x" /></video></p>');
testXss('<video><!--[if IE]><img src="x"><![endif]--></video>', '<p><video width="300" height="150"><!-- [if IE]><img src="x"><![endif]--></video></p>');
testXss('<p><p><audio><audio src=x onerror=alert(1)>', '<p><audio></audio></p>');
testXss('<p><html><audio><br /><audio src=x onerror=alert(1)></p>', '');
testXss('<p><audio><img src="javascript:alert(1)"></audio>', '<p><audio><img /></audio></p>');
testXss('<p><audio><img src="x" style="behavior:url(x); width: 1px"></audio>', '<p><audio><img src="x" style="width: 1px;" /></audio></p>');
});

View File

@ -1,45 +0,0 @@
module("tinymce.plugins.Noneditable", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
indent: false,
noneditable_regexp: [/\{[^\}]+\}/g],
plugins: 'noneditable',
convert_fonts_to_spans: false,
entities: 'raw',
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'
},
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
// Ignore on IE 7, 8 this is a known bug not worth fixing
if (tinymce.Env.ceFalse) {
test('noneditable class', function() {
editor.setContent('<p><span class="mceNonEditable">abc</span></p>');
equal(editor.dom.select('span')[0].contentEditable, "false");
});
test('editable class', function() {
editor.setContent('<p><span class="mceEditable">abc</span></p>');
equal(editor.dom.select('span')[0].contentEditable, "true");
});
test('noneditable regexp', function() {
editor.setContent('<p>{test1}{test2}</p>');
equal(editor.dom.select('span').length, 2);
equal(editor.dom.select('span')[0].contentEditable, "false");
equal(editor.dom.select('span')[1].contentEditable, "false");
equal(editor.getContent(), '<p>{test1}{test2}</p>');
});
}

File diff suppressed because one or more lines are too long

View File

@ -1,188 +0,0 @@
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);
});
});

View File

@ -1,88 +0,0 @@
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) {
delete ed.settings.smart_paste;
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('https://www.site.com/dir-name/file.gif?query=%42#a'), true);
equal(SmartPaste.isAbsoluteUrl('https://www.site.com/~abc'), 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.jpeg'), true);
equal(SmartPaste.isImageUrl('http://www.site.com/dir-name/file.jpg'), true);
equal(SmartPaste.isImageUrl('http://www.site.com/dir-name/file.png'), true);
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'), 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);
});
test('smart paste option disabled', function() {
editor.focus();
editor.undoManager.clear();
editor.setContent('<p>abc</p>');
Utils.setSelection('p', 1);
editor.undoManager.add();
editor.settings.smart_paste = false;
editor.execCommand('mceInsertClipboardContent', false, {content: 'http://www.site.com/my.jpg'});
equal(editor.getContent(), '<p>ahttp://www.site.com/my.jpgbc</p>');
equal(editor.undoManager.data.length, 2);
});
});

View File

@ -1,122 +0,0 @@
module("tinymce.plugins.SearchReplace", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
plugins: "searchreplace",
elements: "elm1",
add_unload_trigger: false,
skin: false,
indent: false,
disable_nodechange: true,
valid_elements: 'b,i',
init_instance_callback : function(ed) {
window.editor = ed;
tinymce.util.Delay.setTimeout(function() {
QUnit.start();
}, 0);
}
});
}
});
test('Find no match', function() {
editor.getBody().innerHTML = 'a';
equal(0, editor.plugins.searchreplace.find('x'));
});
test('Find single match', function() {
editor.getBody().innerHTML = 'a';
equal(1, editor.plugins.searchreplace.find('a'));
});
test('Find single match in multiple elements', function() {
editor.getBody().innerHTML = 't<b>e</b><i>xt</i>';
equal(1, editor.plugins.searchreplace.find('text'));
});
test('Find single match, match case: true', function() {
editor.getBody().innerHTML = 'a A';
equal(1, editor.plugins.searchreplace.find('A', true));
});
test('Find single match, whole words: true', function() {
editor.getBody().innerHTML = 'a Ax';
equal(1, editor.plugins.searchreplace.find('a', false, true));
});
test('Find multiple matches', function() {
editor.getBody().innerHTML = 'a b A';
equal(2, editor.plugins.searchreplace.find('a'));
});
test('Find and replace single match', function() {
editor.getBody().innerHTML = 'a';
editor.plugins.searchreplace.find('a');
ok(!editor.plugins.searchreplace.replace('x'));
equal("<p>x</p>", editor.getContent());
});
test('Find and replace first in multiple matches', function() {
editor.getBody().innerHTML = 'a b a';
editor.plugins.searchreplace.find('a');
ok(editor.plugins.searchreplace.replace('x'));
equal("<p>x b a</p>", editor.getContent());
});
test('Find and replace all in multiple matches', function() {
editor.getBody().innerHTML = 'a b a';
editor.plugins.searchreplace.find('a');
ok(!editor.plugins.searchreplace.replace('x', true, true));
equal("<p>x b x</p>", editor.getContent());
});
test('Find multiple matches, move to next and replace', function() {
editor.getBody().innerHTML = 'a a';
equal(2, editor.plugins.searchreplace.find('a'));
editor.plugins.searchreplace.next();
ok(!editor.plugins.searchreplace.replace('x'));
equal("<p>a x</p>", editor.getContent());
});
test('Find and replace fragmented match', function() {
editor.getBody().innerHTML = '<b>te<i>s</i>t</b><b>te<i>s</i>t</b>';
editor.plugins.searchreplace.find('test');
ok(editor.plugins.searchreplace.replace('abc'));
equal(editor.getContent(), "<p><b>abc</b><b>te<i>s</i>t</b></p>");
});
test('Find and replace all fragmented matches', function() {
editor.getBody().innerHTML = '<b>te<i>s</i>t</b><b>te<i>s</i>t</b>';
editor.plugins.searchreplace.find('test');
ok(!editor.plugins.searchreplace.replace('abc', true, true));
equal(editor.getContent(), "<p><b>abc</b><b>abc</b></p>");
});
test('Find multiple matches, move to next and replace backwards', function() {
editor.getBody().innerHTML = 'a a';
equal(2, editor.plugins.searchreplace.find('a'));
editor.plugins.searchreplace.next();
ok(editor.plugins.searchreplace.replace('x', false));
ok(!editor.plugins.searchreplace.replace('y', false));
equal("<p>y x</p>", editor.getContent());
});
test('Find multiple matches and unmark them', function() {
editor.getBody().innerHTML = 'a b a';
equal(2, editor.plugins.searchreplace.find('a'));
editor.plugins.searchreplace.done();
equal('a', editor.selection.getContent());
equal(0, editor.getBody().getElementsByTagName('span').length);
});
test('Find multiple matches with pre blocks', function() {
editor.getBody().innerHTML = 'abc<pre> abc </pre>abc';
equal(3, editor.plugins.searchreplace.find('b'));
equal(Utils.normalizeHtml(editor.getBody().innerHTML), (
'a<span class="mce-match-marker mce-match-marker-selected" data-mce-bogus="1" data-mce-index="0">b</span>c' +
'<pre> a<span class="mce-match-marker" data-mce-bogus="1" data-mce-index="1">b</span>c </pre>' +
'a<span class="mce-match-marker" data-mce-bogus="1" data-mce-index="2">b</span>c'
));
});

View File

@ -1,95 +0,0 @@
(function() {
var count = 0;
module("tinymce.plugins.Spellchecker", {
setupModule: function() {
document.getElementById('view').innerHTML = (
'<textarea id="no_lang"></textarea>' +
'<textarea id="one_lang"></textarea>' +
'<textarea id="many_lang"></textarea>'
);
QUnit.stop();
function wait() {
if (++count == 3) {
QUnit.start();
}
}
tinymce.init({
selector: '#no_lang',
plugins: "spellchecker",
add_unload_trigger: false,
skin: false,
disable_nodechange: true,
toolbar: 'spellchecker',
init_instance_callback: function(ed) {
window.editor = ed;
wait();
}
});
tinymce.init({
selector: '#one_lang',
plugins: "spellchecker",
add_unload_trigger: false,
skin: false,
spellchecker_languages: 'English=en',
disable_nodechange: true,
toolbar: 'spellchecker',
init_instance_callback: function(ed) {
window.editor = ed;
wait();
}
});
tinymce.init({
selector: '#many_lang',
plugins: "spellchecker",
add_unload_trigger: false,
skin: false,
spellchecker_languages: 'English=en,French=fr,German=de',
disable_nodechange: true,
toolbar: 'spellchecker',
init_instance_callback: function(ed) {
window.editor = ed;
wait();
}
});
},
teardown: function() {
editor.settings.forced_root_block = 'p';
}
});
// Default spellchecker language should match editor language
test('Check default language', function() {
var mainLanguage = tinymce.get('no_lang').settings.language || 'en';
equal(tinymce.get('no_lang').settings.spellchecker_language, mainLanguage);
});
// Spellchecker button may include a language menu
// When no languages are specified, the default list of languages should be
// used, matching the list in the old TinyMCE 3 spellchecker plugin.
test('Check spellcheck button is a splitbutton (no languages)', function() {
var spellcheckButton = tinymce.get('no_lang').buttons.spellchecker;
equal(spellcheckButton.type, 'splitbutton');
});
// When exactly one spellchecker language is specified, there's no need to
// display a selection menu.
test('Check spellcheck button is a normal button (one language)', function() {
var spellcheckButton = tinymce.get('one_lang').buttons.spellchecker;
equal(spellcheckButton.type, 'button');
});
// When more than one spellchecker language is specified, a selection menu
// should be provided to choose between them.
test('Check spellcheck button is a splitbutton (many languages)', function() {
var spellcheckButton = tinymce.get('many_lang').buttons.spellchecker;
equal(spellcheckButton.type, 'splitbutton');
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -1,126 +0,0 @@
(function() {
module("tinymce.plugins.TextPattern", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: 'textarea',
add_unload_trigger: false,
skin: false,
indent: false,
plugins: "textpattern",
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
},
teardown: function() {
delete editor.settings.textpattern_patterns;
}
});
test('Italic format on single word using space', function() {
editor.setContent('<p>*abc*\u00a0</p>');
Utils.setSelection('p', 6);
editor.fire('keyup', {keyCode: 32});
equal(
editor.getContent(),
'<p><em>abc</em>&nbsp;</p>'
);
});
test('Bold format on single word using space', function() {
editor.setContent('<p>**abc**\u00a0</p>');
Utils.setSelection('p', 8);
editor.fire('keyup', {keyCode: 32});
equal(
editor.getContent(),
'<p><strong>abc</strong>&nbsp;</p>'
);
});
test('Bold format on multiple words using space', function() {
editor.setContent('<p>**abc 123**\u00a0</p>');
Utils.setSelection('p', 12);
editor.fire('keyup', {keyCode: 32});
equal(
editor.getContent(),
'<p><strong>abc 123</strong>&nbsp;</p>'
);
});
test('Bold format on single word using enter', function() {
editor.setContent('<p>**abc**</p>');
Utils.setSelection('p', 7);
editor.fire('keydown', {keyCode: 13});
equal(
editor.getContent(),
'<p><strong>abc</strong></p><p>&nbsp;</p>'
);
});
test('H1 format on single word node using enter', function() {
editor.setContent('<p>#abc</p>');
Utils.setSelection('p', 4);
editor.fire('keydown', {keyCode: 13});
equal(
editor.getContent(),
'<h1>abc</h1><p>&nbsp;</p>'
);
});
test('OL format on single word node using enter', function() {
editor.setContent('<p>1. abc</p>');
Utils.setSelection('p', 6);
editor.fire('keydown', {keyCode: 13});
equal(
editor.getContent(),
'<ol><li>abc</li><li></li></ol>'
);
});
test('UL format on single word node using enter', function() {
editor.setContent('<p>* abc</p>');
Utils.setSelection('p', 5);
editor.fire('keydown', {keyCode: 13});
equal(
editor.getContent(),
'<ul><li>abc</li><li></li></ul>'
);
});
test('getPatterns/setPatterns', function() {
editor.plugins.textpattern.setPatterns([
{start: '#', format: 'h1'},
{start: '##', format: 'h2'},
{start: '###', format: 'h3'}
]);
deepEqual(
editor.plugins.textpattern.getPatterns(),
[
{
"format": "h3",
"start": "###"
},
{
"format": "h2",
"start": "##"
},
{
"format": "h1",
"start": "#"
}
]
);
});
})();

View File

@ -1,81 +0,0 @@
module("tinymce.plugins.Wordcount", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
skin: false,
wordcount_target_id: 'current-count',
plugins: 'wordcount',
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
test("Blank document has 0 words", function() {
expect(1);
editor.setContent('');
var result = editor.plugins.wordcount.getCount();
equal(result, 0);
});
test("Simple word count", function() {
expect(1);
editor.setContent('<p>My sentence is this.</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 4);
});
test("Does not count dashes", function() {
expect(1);
editor.setContent('<p>Something -- ok</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 2);
});
test("Does not count asterisks, non-word characters", function() {
expect(1);
editor.setContent('<p>* something\n\u00b7 something else</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 3);
});
test("Does not count numbers", function() {
expect(1);
editor.setContent('<p>Something 123 ok</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 2);
});
test("Does not count htmlentities", function() {
expect(1);
editor.setContent('<p>It&rsquo;s my life &ndash; &#8211; &#x2013; don\'t you forget.</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 6);
});
test("Counts hyphenated words as one word", function() {
expect(1);
editor.setContent('<p>Hello some-word here.</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 3);
});
test("Counts words between blocks as two words", function() {
expect(1);
editor.setContent('<p>Hello</p><p>world</p>');
var result = editor.plugins.wordcount.getCount();
equal(result, 2);
});

View File

@ -492,7 +492,36 @@ test('translate', function() {
equal(editor.translate('input i18n'), 'output i18n');
});
test('Treat some paragraphs as empty contents', function() {
editor.setContent('<p><br /></p>');
equal(editor.getContent(), '');
editor.setContent('<p>\u00a0</p>');
equal(editor.getContent(), '');
});
test('kamer word bounderies', function() {
editor.setContent('<p>!\u200b!\u200b!</p>');
equal(editor.getContent(), '<p>!\u200b!\u200b!</p>');
});
});
test('Padd empty elements with br', function() {
editor.settings.padd_empty_with_br = true;
editor.setContent('<p>a</p><p></p>');
equal(editor.getContent(), '<p>a</p><p><br /></p>');
delete editor.settings.padd_empty_with_br;
});
test('Padd empty elements with br on insert at caret', function() {
editor.settings.padd_empty_with_br = true;
editor.setContent('<p>a</p>');
Utils.setSelection('p', 1);
editor.insertContent('<p>b</p><p></p>');
equal(editor.getContent(), '<p>a</p><p>b</p><p><br /></p>');
delete editor.settings.padd_empty_with_br;
});
test('Preserve whitespace pre elements', function() {
editor.setContent('<pre> </pre>');
equal(editor.getContent(), '<pre> </pre>');
});

View File

@ -750,6 +750,13 @@ test('unlink', function() {
equal(editor.getContent(), '<p>test 123</p>');
});
test('unlink - unselected a[href] with childNodes', function() {
editor.setContent('<p><a href="test"><strong><em>test</em></strong></a></p>');
Utils.setSelection('em', 0);
editor.execCommand('unlink');
equal(editor.getContent(), '<p><strong><em>test</em></strong></p>');
});
test('subscript/superscript', function() {
expect(4);
@ -803,6 +810,33 @@ test('indent/outdent', function() {
equal(editor.getContent(), '<p>test 123</p>');
});
test('indent/outdent table always uses margin', function () {
expect(4);
editor.setContent('<table><tbody><tr><td>test</td></tr></tbody></table>');
editor.execCommand('SelectAll');
editor.execCommand('Indent');
equal(editor.getContent(), '<table style="margin-left: 30px;"><tbody><tr><td>test</td></tr></tbody></table>');
editor.setContent('<table><tbody><tr><td>test</td></tr></tbody></table>');
editor.execCommand('SelectAll');
editor.execCommand('Indent');
editor.execCommand('Indent');
equal(editor.getContent(), '<table style="margin-left: 60px;"><tbody><tr><td>test</td></tr></tbody></table>');
editor.setContent('<table><tbody><tr><td>test</td></tr></tbody></table>');
editor.execCommand('SelectAll');
editor.execCommand('Indent');
editor.execCommand('Indent');
editor.execCommand('Outdent');
equal(editor.getContent(), '<table style="margin-left: 30px;"><tbody><tr><td>test</td></tr></tbody></table>');
editor.setContent('<table><tbody><tr><td>test</td></tr></tbody></table>');
editor.execCommand('SelectAll');
editor.execCommand('Outdent');
equal(editor.getContent(), '<table><tbody><tr><td>test</td></tr></tbody></table>');
});
test('RemoveFormat', function() {
expect(4);
@ -827,6 +861,17 @@ test('RemoveFormat', function() {
equal(editor.getContent(), '<p>dfn tag code tag samp tag kbd tag var tag cite tag mark tag q tag</p>');
});
if (tinymce.Env.ceFalse) {
test('SelectAll', function() {
editor.setContent('<p>a</p><div contenteditable="false"><div contenteditable="true">b</div><p>c</p>');
Utils.setSelection('div div', 0);
editor.execCommand('SelectAll');
equal(editor.selection.getStart().nodeName, 'DIV');
equal(editor.selection.getEnd().nodeName, 'DIV');
equal(editor.selection.isCollapsed(), false);
});
}
test('InsertLineBreak', function() {
editor.setContent('<p>123</p>');
Utils.setSelection('p', 2);

View File

@ -0,0 +1,43 @@
ModuleLoader.require([
], function() {
module("tinymce.EditorCustomTheme", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
disable_nodechange: true,
skin: false,
entities: 'raw',
indent: false,
theme: function (editor, targetnode) {
var editorContainer = document.createElement('div');
editorContainer.id = 'editorContainer';
var iframeContainer = document.createElement('div');
iframeContainer.id = 'iframeContainer';
editorContainer.appendChild(iframeContainer);
targetnode.parentNode.insertBefore(editorContainer, targetnode);
return {
iframeContainer: iframeContainer,
editorContainer: editorContainer
};
},
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
test('getContainer/getContentAreaContainer', function() {
QUnit.equal(editor.getContainer().id, 'editorContainer', 'Should be the new editorContainer element');
QUnit.equal(editor.getContainer().nodeType, 1, 'Should be an element');
QUnit.equal(editor.getContentAreaContainer().id, 'iframeContainer', 'Should be the new iframeContainer element');
QUnit.equal(editor.getContentAreaContainer().nodeType, 1, 'Should be an element');
});
});

View File

@ -98,12 +98,16 @@ asyncTest('Init/remove on same id', function() {
});
asyncTest('Init editor async with proper editors state', function() {
var unloadTheme = function(name) {
var url = tinymce.baseURI.toAbsolute('themes/' + name + '/theme.js');
var unloadUrl = function (url) {
tinymce.dom.ScriptLoader.ScriptLoader.remove(url);
tinymce.ThemeManager.remove(name);
};
var unloadTheme = function(name) {
unloadUrl(tinymce.baseURI.toAbsolute('themes/' + name + '/theme.min.js'));
unloadUrl(tinymce.baseURI.toAbsolute('themes/' + name + '/theme.js'));
};
tinymce.remove();
var init = function() {
@ -141,6 +145,9 @@ test('overrideDefaults', function() {
external_plugins: {
"plugina": "//domain/plugina.js",
"pluginb": "//domain/pluginb.js"
},
plugin_base_urls: {
testplugin: 'http://custom.ephox.com/dir/testplugin'
}
});
@ -148,11 +155,15 @@ test('overrideDefaults', function() {
strictEqual(tinymce.baseURL, "http://www.tinymce.com/base");
strictEqual(tinymce.suffix, "x");
strictEqual(new tinymce.Editor('ed1', {}, tinymce).settings.test, 42);
strictEqual(tinymce.PluginManager.urls.testplugin, 'http://custom.ephox.com/dir/testplugin');
deepEqual(new tinymce.Editor('ed2', {
external_plugins: {
"plugina": "//domain/plugina2.js",
"pluginc": "//domain/pluginc.js"
},
plugin_base_urls: {
testplugin: 'http://custom.ephox.com/dir/testplugin'
}
}, tinymce).settings.external_plugins, {
"plugina": "//domain/plugina2.js",

View File

@ -235,7 +235,8 @@ ModuleLoader.require([
if (callCount == 2) {
QUnit.start();
equal(uploadCount, 1, 'Should only be one upload.');
// This is in exact since the status of the image can be pending or failed meaing it should try again
ok(uploadCount >= 1, 'Should at least be one.');
}
equal(result[0].element, editor.$('img')[0]);

View File

@ -1098,3 +1098,24 @@ if (window.getSelection) {
notEqual(rng.startContainer.data, ' ');
});
}
if (tinymce.Env.ceFalse) {
test('Enter before cE=false div', function() {
editor.getBody().innerHTML = '<div contenteditable="false">x</div>';
editor.selection.select(editor.dom.select('div')[0]);
editor.selection.collapse(true);
Utils.pressEnter();
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><br data-mce-bogus="1"></p><div contenteditable="false">x</div>');
equal(editor.selection.getNode().nodeName, 'P');
});
test('Enter after cE=false div', function() {
editor.getBody().innerHTML = '<div contenteditable="false">x</div>';
editor.selection.select(editor.dom.select('div')[0]);
editor.selection.collapse(false);
Utils.pressEnter();
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<div contenteditable="false">x</div><p><br data-mce-bogus="1"></p>');
equal(editor.selection.getNode().nodeName, 'P');
});
}

View File

@ -0,0 +1,46 @@
ModuleLoader.require([
"tinymce/FocusManager",
"tinymce/dom/DOMUtils"
], function (FocusManager, DOMUtils) {
var DOM = DOMUtils.DOM;
module("tinymce.FocusManager", {
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();
}
});
}
});
test('isEditorUIElement on valid element', function () {
var uiElm = DOM.create('div', {'class': 'mce-abc'}, null);
equal(FocusManager.isEditorUIElement(uiElm), true, 'Should be true since mce- is a ui prefix');
});
test('isEditorUIElement on invalid element', function () {
var noUiElm = DOM.create('div', {'class': 'mcex-abc'}, null);
equal(FocusManager.isEditorUIElement(noUiElm), false, 'Should be true since mcex- is not a ui prefix');
});
test('_isUIElement on valid element', function () {
var uiElm1 = DOM.create('div', {'class': 'mce-abc'}, null);
var uiElm2 = DOM.create('div', {'class': 'mcex-abc'}, null);
var noUiElm = DOM.create('div', {'class': 'mcey-abc'}, null);
editor.settings.custom_ui_selector = '.mcex-abc';
equal(FocusManager._isUIElement(editor, uiElm1), true, 'Should be true since mce- is a ui prefix');
equal(FocusManager._isUIElement(editor, uiElm2), true, 'Should be true since mcex- is a ui prefix');
equal(FocusManager._isUIElement(editor, noUiElm), false, 'Should be true since mcey- is not a ui prefix');
delete editor.settings.custom_ui_selector;
});
});

View File

@ -1,6 +1,6 @@
module("tinymce.Formatter - Apply", {
setupModule: function() {
document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea><div id="elm2"></div>';
document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea><div id="elm2"></div><textarea id="elm3"></textarea>';
QUnit.stop();
tinymce.init({
@ -18,32 +18,8 @@ module("tinymce.Formatter - Apply", {
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,text-align'
},
init_instance_callback: function(ed) {
QUnit.start();
window.editor = ed;
if (inlineEditor) {
QUnit.start();
}
}
});
tinymce.init({
selector: "#elm2",
inline: true,
add_unload_trigger: false,
skin: false,
indent: false,
convert_fonts_to_spans: false,
disable_nodechange: true,
entities: 'raw',
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,text-align'
},
init_instance_callback: function(ed) {
window.inlineEditor = ed;
if (editor) {
QUnit.start();
}
}
});
}
@ -1291,6 +1267,16 @@ test('Caret format inside single block word', function() {
equal(editor.getContent(), '<p><b>abc</b></p>');
});
test('Caret format inside non-ascii single block word', function() {
editor.setContent('<p>noël</p>');
editor.formatter.register('format', {
inline: 'b'
});
Utils.setSelection('p', 2, 'p', 2);
editor.formatter.apply('format');
equal(editor.getContent(), '<p><b>noël</b></p>');
});
test('Caret format inside first block word', function() {
editor.setContent('<p>abc 123</p>');
editor.formatter.register('format', {
@ -1679,39 +1665,51 @@ test('Bug #6471 - Merge left/right style properties', function() {
equal(editor.getContent(), '<p><span style="font-weight: bold;">abc</span></p>');
});
test('Bug #6518 - Apply div blocks to inline editor paragraph', function() {
inlineEditor.setContent('<p>a</p><p>b</p>');
inlineEditor.selection.select(inlineEditor.getBody().firstChild, true);
inlineEditor.selection.collapse(true);
inlineEditor.formatter.register('format', {
block: 'div'
asyncTest('Bug #6518 - Apply div blocks to inline editor paragraph', function() {
tinymce.init({
selector: "#elm2",
inline: true,
add_unload_trigger: false,
skin: false,
indent: false,
convert_fonts_to_spans: false,
disable_nodechange: true,
entities: 'raw',
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,text-align'
},
init_instance_callback: function(ed) {
QUnit.start();
ed.setContent('<p>a</p><p>b</p>');
ed.selection.select(ed.getBody().firstChild, true);
ed.selection.collapse(true);
ed.formatter.register('format', {
block: 'div'
});
ed.formatter.apply('format');
equal(ed.getContent(), '<div>a</div><p>b</p>');
}
});
inlineEditor.formatter.apply('format');
equal(inlineEditor.getContent(), '<div>a</div><p>b</p>');
});
asyncTest('Bug #7412 - valid_styles affects the Bold and Italic buttons, although it shouldn\'t', function() {
tinymce.remove();
document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea>';
tinymce.init({
selector: "#elm1",
selector: "#elm3",
add_unload_trigger: false,
valid_styles: {
span: 'color,background-color,font-size,text-decoration,padding-left'
},
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
editor.getBody().innerHTML = '<p>1 <span style="text-decoration: underline;">1234</span> 1</p>';
var rng = editor.dom.createRng();
rng.setStart(editor.dom.select('span')[0], 0);
rng.setEnd(editor.dom.select('span')[0], 1);
editor.selection.setRng(rng);
editor.formatter.toggle('bold');
equal(getContent(), '<p>1 <strong><span style="text-decoration: underline;">1234</span></strong> 1</p>');
ed.getBody().innerHTML = '<p>1 <span style="text-decoration: underline;">1234</span> 1</p>';
var rng = ed.dom.createRng();
rng.setStart(ed.dom.select('span')[0], 0);
rng.setEnd(ed.dom.select('span')[0], 1);
ed.selection.setRng(rng);
ed.formatter.toggle('bold');
equal(ed.getContent(), '<p>1 <strong><span style="text-decoration: underline;">1234</span></strong> 1</p>');
}
});
});
@ -1721,12 +1719,77 @@ test('Format selection from with end at beginning of block', function(){
editor.focus();
Utils.setSelection('#a', 0, '#b', 0);
editor.execCommand('formatBlock', false, 'h1');
equal(getContent(), '<h1 id="a">one</h1>\n<div id="b">two</div>');
equal(getContent(), '<h1 id="a">one</h1><div id="b">two</div>');
});
test('Format selection over fragments', function(){
editor.setContent("<strong>a</strong>bc<em>d</em>");
editor.setContent("<p><strong>a</strong>bc<em>d</em></p>");
Utils.setSelection('strong', 1, 'em', 0);
editor.formatter.apply('underline');
equal(getContent(), '<p><strong>a</strong><span style="text-decoration: underline;">bc</span><em>d</em></p>');
});
test("Wrapper with fontSize should retain priority within a branch of nested inline format wrappers", function() {
editor.setContent("<p>abc</p>");
Utils.setSelection('p', 0, 'p', 3);
editor.formatter.apply('fontsize', {value: '18px'});
editor.formatter.apply('bold');
editor.formatter.apply('underline');
editor.formatter.apply('forecolor', {value: '#ff0000'});
equal(getContent(), '<p><span style="color: #ff0000; font-size: 18px; text-decoration: underline;"><strong>abc</strong></span></p>');
});
test("Child wrapper having the same format as the immediate parent, shouldn't be removed if it also has other formats merged", function() {
editor.getBody().innerHTML = '<p><span style="font-family: verdana;">a <span style="color: #ff0000;">b</span>c</span></p>';
Utils.setSelection('span span', 0, 'span span', 1);
editor.formatter.apply('fontname', {value: "verdana"});
equal(getContent(), '<p><span style="font-family: verdana;">a <span style="color: #ff0000;">b</span>c</span></p>');
});
test("When format with backgroundColor is applied, all the nested childNodes having fontSize should receive backgroundColor as well", function() {
editor.getBody().innerHTML = '<p>a <span style="font-size: 36pt;">b</span> c</p>';
editor.selection.select(editor.dom.select('p')[0]);
editor.formatter.apply('hilitecolor', {value: "#ff0000"});
equal(getContent(), '<p><span style="background-color: #ff0000;">a <span style="font-size: 36pt; background-color: #ff0000;">b</span> c</span></p>');
editor.formatter.remove('hilitecolor', {value: "#ff0000"});
equal(getContent(), '<p>a <span style="font-size: 36pt;">b</span> c</p>');
});
test("TINY-782: Can't apply sub/sup to word on own line with large font", function() {
editor.getBody().innerHTML = '<p><span style="font-size: 18px;">abc</p>';
Utils.setSelection('span', 0, 'span', 3);
editor.formatter.apply('superscript');
equal(getContent(), '<p><span style="font-size: 18px;"><sup>abc</sup></span></p>');
});
test("TINY-671: Background color on nested font size bug", function() {
editor.getBody().innerHTML = '<p><strong><span style="font-size: 18px;">abc</span></strong></p>';
Utils.setSelection('span', 0, 'span', 3);
editor.formatter.apply('hilitecolor', {value: '#ff0000'});
equal(getContent(), '<p><span style="font-size: 18px; background-color: #ff0000;"><strong>abc</strong></span></p>');
});
test("TINY-865: Font size removed when changing background color", function() {
editor.getBody().innerHTML = '<p><span style="background-color: #ffff00;"><span style="font-size: 8pt;">a</span> <span style="font-size: 36pt;">b</span> <span style="font-size: 8pt;">c</span></span></p>';
Utils.setSelection('span span:nth-child(2)', 0, 'span span:nth-child(2)', 1);
editor.formatter.apply('hilitecolor', {value: '#ff0000'});
equal(getContent(), '<p><span style="background-color: #ffff00;"><span style="font-size: 8pt;">a</span> <span style="font-size: 36pt; background-color: #ff0000;">b</span> <span style="font-size: 8pt;">c</span></span></p>');
});
test("TINY-935: Text color, then size, then change color wraps span doesn't change color", function() {
editor.getBody().innerHTML = '<p><span style="color: #00ff00; font-size: 14pt;">text</span></p>';
Utils.setSelection('span', 0, 'span', 4);
editor.formatter.apply('forecolor', {value: '#ff0000'});
equal(getContent(), '<p><span style="color: #ff0000; font-size: 14pt;">text</span></p>');
});
test("GH-3519: Font family selection does not work after changing font size", function() {
editor.getBody().innerHTML = '<p><span style="font-size: 14pt; font-family: \'comic sans ms\', sans-serif;">text</span></p>';
Utils.setSelection('span', 0, 'span', 4);
editor.formatter.apply('fontname', {value: "verdana"});
equal(getContent(), '<p><span style="font-size: 14pt; font-family: verdana;">text</span></p>');
});

View File

@ -228,8 +228,3 @@ 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');
});

View File

@ -0,0 +1,47 @@
ModuleLoader.require([
"tinymce/InsertContent"
], function(InsertContent) {
module("tinymce.InsertContentForcedRootFalse", {
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();
},
forced_root_block: false
});
}
});
var trimBrs = function(string) {
return string.replace(/<br>/g, '');
};
test('insertAtCaret - selected image with bogus div', function() {
editor.getBody().innerHTML = '<img src="about:blank" /><div data-mce-bogus="all">x</div>';
editor.focus();
// editor.selection.setCursorLocation(editor.getBody(), 0);
editor.selection.select(editor.dom.select('img')[0]);
InsertContent.insertAtCaret(editor, 'a');
equal(trimBrs(editor.getBody().innerHTML), 'a<div data-mce-bogus="all">x</div>');
});
test('insertAtCaret - selected text with bogus div', function() {
editor.getBody().innerHTML = 'a<div data-mce-bogus="all">x</div>';
editor.focus();
var rng = editor.dom.createRng();
rng.setStart(editor.getBody().firstChild, 0);
rng.setEnd(editor.getBody().firstChild, 1);
editor.selection.setRng(rng);
InsertContent.insertAtCaret(editor, 'b');
equal(trimBrs(editor.getBody().innerHTML), 'b<div data-mce-bogus="all">x</div>');
});
});

View File

@ -0,0 +1,109 @@
ModuleLoader.require([
'tinymce/util/Tools'
], function(Tools) {
module("tinymce.NotificationManager", {
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();
}
});
},
teardown: function() {
var notifications = [].concat(editor.notificationManager.notifications);
Tools.each(notifications, function(notification) {
notification.close();
});
}
});
test('Should not add duplicate text message', function() {
expect(4);
var testMsg1 = {type: 'default', text: 'test default message'};
var testMsg2 = {type: 'warning', text: 'test warning message'};
var testMsg3 = {type: 'error', text: 'test error message'};
var testMsg4 = {type: 'info', text: 'test info message'};
var notifications = editor.notificationManager.notifications;
editor.notificationManager.open(testMsg1);
equal(notifications.length, 1, 'Should have one message after one added.');
editor.notificationManager.open(testMsg1);
equal(notifications.length, 1, 'Should not add message if duplicate.');
editor.notificationManager.open(testMsg2);
editor.notificationManager.open(testMsg3);
editor.notificationManager.open(testMsg4);
equal(notifications.length, 4, 'Non duplicate messages should get added.');
editor.notificationManager.open(testMsg2);
editor.notificationManager.open(testMsg3);
editor.notificationManager.open(testMsg4);
equal(notifications.length, 4, 'Should work for all text message types.');
});
test('Should add duplicate progressBar messages', function() {
expect(2);
var testMsg1 = {text: 'test progressBar message', progressBar: true};
var notifications = editor.notificationManager.notifications;
editor.notificationManager.open(testMsg1);
equal(notifications.length, 1, 'Should have one message after one added.');
editor.notificationManager.open(testMsg1);
editor.notificationManager.open(testMsg1);
editor.notificationManager.open(testMsg1);
equal(notifications.length, 4, 'Duplicate should be added for progressBar message.');
});
asyncTest('Should add duplicate timeout messages', function() {
expect(2);
var checkClosed = function () {
if (notifications.length === 0) {
start();
}
};
var testMsg1 = {text: 'test timeout message', timeout: 1};
var notifications = editor.notificationManager.notifications;
editor.notificationManager.open(testMsg1).on('close', checkClosed);
equal(notifications.length, 1, 'Should have one message after one added.');
editor.notificationManager.open(testMsg1).on('close', checkClosed);
equal(notifications.length, 2, 'Duplicate should be added for timeout message.');
});
test('Should not open notifcation if editor is removed', function() {
var testMsg1 = {type: 'default', text: 'test progressBar message'};
editor.remove();
try {
editor.notificationManager.open(testMsg1);
ok(true, 'Should execute without throwing.')
} catch (e) {
ok(false, 'Should never throw exception.');
}
});
});

View File

@ -47,7 +47,7 @@ ModuleLoader.require([
function assertCaretInCaretBlockContainer() {
var beforeRng = editor.selection.getRng();
equal(CaretContainer.isCaretContainerBlock(beforeRng.startContainer.parentNode), true, 'Not in caret block container.');
equal(CaretContainer.isCaretContainerBlock(beforeRng.startContainer), true, 'Not in caret block container.');
}
var leftArrow = pressKey(VK.LEFT);
@ -224,7 +224,7 @@ ModuleLoader.require([
equal(editor.getContent(), '<p contenteditable="false">1</p><p contenteditable="false">2</p>');
assertCaretInCaretBlockContainer();
equal(rng.startContainer.parentNode.previousSibling, editor.dom.select('p')[0]);
equal(rng.startContainer.previousSibling, editor.dom.select('p')[0]);
});
test('delete from after cE=false block to text', function() {
@ -263,7 +263,7 @@ ModuleLoader.require([
equal(editor.getContent(), '<p contenteditable="false">1</p><p contenteditable="false">2</p>');
assertCaretInCaretBlockContainer();
equal(rng.startContainer.parentNode.nextSibling, editor.dom.select('p')[2]);
equal(rng.startContainer.nextSibling, editor.dom.select('p')[2]);
});
test('delete from block to before cE=false inline', function() {
@ -328,4 +328,30 @@ ModuleLoader.require([
// 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);
});
test('offscreen copy of cE=false block remains offscreen', function() {
if (tinymce.isIE || tinymce.isGecko || tinymce.isOpera) {
editor.setContent(
'<table contenteditable="false" style="width: 100%; table-layout: fixed">' +
'<tbody><tr><td>1</td><td>2</td></tr></tbody>' +
'</table>'
);
editor.selection.select(editor.dom.select('table')[0]);
var offscreenSelection = editor.dom.select('.mce-offscreen-selection')[0];
ok(offscreenSelection.offsetLeft !== undefined, 'The offscreen selection\'s left border is undefined');
ok(offscreenSelection.offsetLeft < 0, 'The offscreen selection\'s left border is onscreen');
ok(offscreenSelection.offsetWidth + offscreenSelection.offsetLeft < 0,
'The cE=false offscreen selection is visible on-screen. Right edge: ' +
offscreenSelection.offsetLeft + '+' + offscreenSelection.offsetWidth + '=' +
(offscreenSelection.offsetLeft + offscreenSelection.offsetWidth) + 'px'
);
} else {
// Chrome and Safari behave correctly, and PhantomJS also declares itself as WebKit but does not
// put the off-screen selection off-screen, so fails the above tests. However, it has no visible UI,
// so everything is off-screen anyway :-)
ok(true, 'Not a tested browser - Chrome & Safari work, PhantomJS does not put the selection off screen');
}
});
});

View File

@ -96,7 +96,7 @@ test('Typing state', function() {
editor.dom.fire(editor.getBody(), 'keydown', {keyCode: 65});
ok(editor.undoManager.typing);
editor.dom.fire(editor.getBody(), 'keyup', {keyCode: 13});
editor.dom.fire(editor.getBody(), 'keydown', {keyCode: 13});
ok(!editor.undoManager.typing);
selectAllFlags = {keyCode: 65, ctrlKey: false, altKey: false, shiftKey: false};
@ -451,3 +451,41 @@ test('Dirty state type AltGr+letter', function() {
equal(editor.getContent(), "<p>aB</p>");
ok(editor.isDirty(), "Dirty state should be true");
});
test('ExecCommand while typing should produce undo level', function() {
editor.undoManager.clear();
editor.setDirty(false);
editor.setContent('<p>a</p>');
Utils.setSelection('p', 1);
equal(editor.undoManager.typing, false);
Utils.type({keyCode: 66, charCode: 66});
equal(editor.undoManager.typing, true);
equal(editor.getContent(), '<p>aB</p>');
editor.execCommand('mceInsertContent', false, 'C');
equal(editor.undoManager.typing, false);
equal(editor.undoManager.data.length, 3);
equal(editor.undoManager.data[0].content, '<p>a</p>');
equal(editor.undoManager.data[1].content, '<p>aB</p>');
equal(editor.undoManager.data[2].content, '<p>aBC</p>');
});
test('transact while typing should produce undo level', function() {
editor.undoManager.clear();
editor.setDirty(false);
editor.setContent('<p>a</p>');
Utils.setSelection('p', 1);
equal(editor.undoManager.typing, false);
Utils.type({keyCode: 66, charCode: 66});
equal(editor.undoManager.typing, true);
equal(editor.getContent(), '<p>aB</p>');
editor.undoManager.transact(function () {
editor.getBody().firstChild.firstChild.data = 'aBC';
});
equal(editor.undoManager.typing, false);
equal(editor.undoManager.data.length, 3);
equal(editor.undoManager.data[0].content, '<p>a</p>');
equal(editor.undoManager.data[1].content, '<p>aB</p>');
equal(editor.undoManager.data[2].content, '<p>aBC</p>');
});

View File

@ -118,4 +118,20 @@ ModuleLoader.require([
setViewHtml('abc' + Zwsp.ZWSP);
equal(CaretContainer.endsWithCaretContainer(getRoot().firstChild), true);
});
test('hasContent', function() {
setViewHtml('<span contentEditable="false">1</span>');
var caretContainerBlock = CaretContainer.insertBlock('p', getRoot().firstChild, true);
equal(CaretContainer.hasContent(caretContainerBlock), false);
caretContainerBlock.insertBefore(document.createTextNode('a'), caretContainerBlock.firstChild);
equal(CaretContainer.hasContent(caretContainerBlock), true);
});
test('showCaretContainerBlock', function() {
setViewHtml('<span contentEditable="false">1</span>');
var caretContainerBlock = CaretContainer.insertBlock('p', getRoot().firstChild, true);
caretContainerBlock.insertBefore(document.createTextNode('a'), caretContainerBlock.firstChild);
CaretContainer.showCaretContainerBlock(caretContainerBlock);
equal(caretContainerBlock.outerHTML, '<p>a</p>');
});
});

View File

@ -34,7 +34,7 @@ ModuleLoader.require([
equal($fakeCaretElm[0].nodeName, 'P');
equal($fakeCaretElm.attr('data-mce-caret'), 'before');
Utils.assertRange(rng, Utils.createRange($fakeCaretElm[0].firstChild, 0, $fakeCaretElm[0].firstChild, 1));
Utils.assertRange(rng, Utils.createRange($fakeCaretElm[0], 0, $fakeCaretElm[0], 0));
fakeCaret.hide();
equal($('#view *[data-mce-caret]').length, 0);
@ -50,7 +50,7 @@ ModuleLoader.require([
equal($fakeCaretElm[1].nodeName, 'P');
equal($fakeCaretElm.eq(1).attr('data-mce-caret'), 'after');
Utils.assertRange(rng, Utils.createRange($fakeCaretElm[1].firstChild, 0, $fakeCaretElm[1].firstChild, 1));
Utils.assertRange(rng, Utils.createRange($fakeCaretElm[1], 0, $fakeCaretElm[1], 0));
fakeCaret.hide();
equal($('#view *[data-mce-caret]').length, 0);

View File

@ -0,0 +1,104 @@
ModuleLoader.require([
"tinymce/content/LinkTargets",
"tinymce/util/Arr"
], function(LinkTargets, Arr) {
module("tinymce.content.LinkTargets", {});
var createFromHtml = function (html) {
var elm = document.createElement('div');
elm.contentEditable = true;
elm.innerHTML = html;
return elm;
};
var targetsIn = function (html) {
return LinkTargets.find(createFromHtml(html));
};
var equalTargets = function (actualTargets, expectedTargets, message) {
var nonAttachedTargets = Arr.map(actualTargets, function (target) {
return {
level: target.level,
title: target.title,
type: target.type,
url: target.url
};
});
deepEqual(nonAttachedTargets, expectedTargets, message);
};
test('Non link targets', function() {
equal(targetsIn('a').length, 0, 'Text has no targets');
equal(targetsIn('<p>a</p>').length, 0, 'Paragraph has no targets');
equal(targetsIn('<a href="#1">a</a>').length, 0, 'Link has no targets');
});
test('Anchor targets', function() {
equalTargets(targetsIn('<a id="a"></a>'), [{level: 0, title: '#a', type: 'anchor', url: '#a'}], 'Anchor with id');
equalTargets(targetsIn('<a name="a"></a>'), [{level: 0, title: '#a', type: 'anchor', url: '#a'}], 'Anchor with name');
equalTargets(targetsIn('<a name="a" contentEditable="false"></a>'), [], 'cE=false anchor');
equalTargets(targetsIn('<div contentEditable="false"><a name="a"></a></div>'), [], 'Anchor in cE=false');
equalTargets(targetsIn('<a name=""></a>'), [], 'Empty anchor name should not produce a target');
equalTargets(targetsIn('<a id=""></a>'), [], 'Empty anchor id should not produce a target');
});
test('Header targets', function() {
equalTargets(targetsIn('<h1 id="a">a</h1>'), [{level: 1, title: 'a', type: 'header', url: '#a'}], 'Header 1 with id');
equalTargets(targetsIn('<h2 id="a">a</h2>'), [{level: 2, title: 'a', type: 'header', url: '#a'}], 'Header 2 with id');
equalTargets(targetsIn('<h3 id="a">a</h3>'), [{level: 3, title: 'a', type: 'header', url: '#a'}], 'Header 3 with id');
equalTargets(targetsIn('<h4 id="a">a</h4>'), [{level: 4, title: 'a', type: 'header', url: '#a'}], 'Header 4 with id');
equalTargets(targetsIn('<h5 id="a">a</h5>'), [{level: 5, title: 'a', type: 'header', url: '#a'}], 'Header 5 with id');
equalTargets(targetsIn('<h6 id="a">a</h6>'), [{level: 6, title: 'a', type: 'header', url: '#a'}], 'Header 6 with id');
equalTargets(targetsIn('<h1 id="a"></h1>'), [], 'Empty header should not produce a target');
equalTargets(targetsIn('<div contentEditable="false"><h1 id="a">a</h1></div>'), [], 'Header in cE=false');
equalTargets(targetsIn('<h1 id="a" contentEditable="false">a</h1>'), [], 'cE=false header');
});
test('Mixed targets', function() {
equalTargets(
targetsIn('<h1 id="a">a</h1><a id="b"></a>'),
[
{level: 1, title: 'a', type: 'header', url: '#a'},
{level: 0, title: '#b', type: 'anchor', url: '#b'}
],
'Header 1 with id and anchor with id'
);
});
test('Anchor attach', function() {
var elm = createFromHtml('<a id="a"></a>');
var targets = LinkTargets.find(elm);
targets[0].attach();
equal(elm.innerHTML, '<a id="a"></a>', 'Should remain the same as before attach');
});
test('Header attach on header with id', function() {
var elm = createFromHtml('<h1 id="a">a</h1>');
var targets = LinkTargets.find(elm);
targets[0].attach();
equal(elm.innerHTML, '<h1 id="a">a</h1>', 'Should remain the same as before attach');
});
test('Header attach on headers without ids', function() {
var elm = createFromHtml('<h1>a</h1><h2>b</h2>');
var targets = LinkTargets.find(elm);
targets[0].attach();
targets[1].attach();
var idA = elm.firstChild.id;
var idB = elm.lastChild.id;
var afterAttachHtml = elm.innerHTML;
equal(afterAttachHtml, '<h1 id="' + idA + '">a</h1><h2 id="' + idB + '">b</h2>', 'Should have unique id:s');
ok(idA !== idB, 'Should not be equal id:s');
targets[0].attach();
targets[1].attach();
equal(elm.innerHTML, afterAttachHtml, 'Should be the same id:s regardless of how many times you attach');
});
});

View File

@ -35,7 +35,7 @@
dom.serializeStyle(dom.parseStyle('border-width: 1pt 1pt 1pt 1pt; border-style: none none none none; border-color: black black black black;')),
'border: 1pt none black;'
);
equal(
dom.serializeStyle(dom.parseStyle('border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;')),
'border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;'
@ -339,15 +339,21 @@
DOM.remove('test');
});
var eqNodeName = function(name) {
return function (n) {
return n.nodeName === name;
};
};
test('getParent', 6, function() {
DOM.add(document.body, 'div', {id : 'test'});
DOM.get('test').innerHTML = '<div><span>ab<a id="test2" href="">abc</a>c</span></div>';
equal(DOM.getParent('test2', function(n) {return n.nodeName == 'SPAN';}).nodeName, 'SPAN');
equal(DOM.getParent('test2', function(n) {return n.nodeName == 'BODY';}).nodeName, 'BODY');
equal(DOM.getParent('test2', function(n) {return n.nodeName == 'BODY';}, document.body), null);
equal(DOM.getParent('test2', function() {return false;}), null);
equal(DOM.getParent('test2', eqNodeName('SPAN')).nodeName, 'SPAN');
equal(DOM.getParent('test2', eqNodeName('BODY')).nodeName, 'BODY');
equal(DOM.getParent('test2', eqNodeName('BODY'), document.body), null);
equal(DOM.getParent('test2', eqNodeName('X')), null);
equal(DOM.getParent('test2', 'SPAN').nodeName, 'SPAN');
equal(DOM.getParent('test2', 'body', DOM.get('test')), null);
@ -360,7 +366,7 @@
DOM.add(document.body, 'div', {id : 'test'});
DOM.get('test').innerHTML = '<div><span class="test">ab<span><a id="test2" href="">abc</a>c</span></span></div>';
equal(DOM.getParents('test2', function(n) {return n.nodeName == 'SPAN';}).length, 2);
equal(DOM.getParents('test2', eqNodeName('SPAN')).length, 2);
equal(DOM.getParents('test2', 'span').length, 2);
equal(DOM.getParents('test2', 'span.test').length, 1);
equal(DOM.getParents('test2', 'body', DOM.get('test')).length, 0);
@ -433,7 +439,7 @@
equal(DOM.getNext(DOM.get('test').firstChild, 'em').nodeName, 'EM');
equal(DOM.getNext(DOM.get('test').firstChild, 'div'), null);
equal(DOM.getNext(null, 'div'), null);
equal(DOM.getNext(DOM.get('test').firstChild, function(n) {return n.nodeName == 'EM';}).nodeName, 'EM');
equal(DOM.getNext(DOM.get('test').firstChild, eqNodeName('EM')).nodeName, 'EM');
DOM.remove('test');
});
@ -446,7 +452,7 @@
equal(DOM.getPrev(DOM.get('test').lastChild, 'strong').nodeName, 'STRONG');
equal(DOM.getPrev(DOM.get('test').lastChild, 'div'), null);
equal(DOM.getPrev(null, 'div'), null);
equal(DOM.getPrev(DOM.get('test').lastChild, function(n) {return n.nodeName == 'STRONG';}).nodeName, 'STRONG');
equal(DOM.getPrev(DOM.get('test').lastChild, eqNodeName('STRONG')).nodeName, 'STRONG');
DOM.remove('test');
});
@ -581,7 +587,7 @@
DOM.remove('test');
});
test('isEmpty', 14, function() {
test('isEmpty', function() {
DOM.schema = new tinymce.html.Schema(); // A schema will be added when used within a editor instance
DOM.add(document.body, 'div', {id : 'test'}, '');
@ -626,6 +632,30 @@
DOM.setHTML('test', '<div><!-- comment --></div>');
ok(!DOM.isEmpty(DOM.get('test')), 'Element with comment.');
DOM.setHTML('test', '<span data-mce-bogus="1"></span>');
ok(DOM.isEmpty(DOM.get('test')), 'Contains just a bogus element.');
DOM.setHTML('test', '<span data-mce-bogus="1">a</span>');
ok(!DOM.isEmpty(DOM.get('test')), 'Contains a text node in a bogus element.');
DOM.setHTML('test', '<span data-mce-bogus="all">a</span>');
ok(DOM.isEmpty(DOM.get('test')), 'Contains just a bogus all element.');
DOM.setHTML('test', '<span data-mce-bogus="all">a</span>b');
ok(!DOM.isEmpty(DOM.get('test')), 'Contains a bogus all element but some text as well.');
DOM.setHTML('test', '<code> </code>');
ok(!DOM.isEmpty(DOM.get('test')), 'Contains a code element should be treated as content.');
DOM.setHTML('test', '<pre> </pre>');
ok(!DOM.isEmpty(DOM.get('test')), 'Contains a pre element should be treated as content.');
DOM.setHTML('test', '<code></code>');
ok(!DOM.isEmpty(DOM.get('test')), 'Contains a code element should be treated as content.');
DOM.setHTML('test', '<pre></pre>');
ok(!DOM.isEmpty(DOM.get('test')), 'Contains a pre element should be treated as content.');
DOM.remove('test');
});
@ -634,6 +664,11 @@
equal(false, DOM.isEmpty(elm, {img: true}));
});
test('isEmpty on pre', function() {
var elm = DOM.create('pre', null, ' ');
equal(false, DOM.isEmpty(elm));
});
test('isEmpty with list of elements considered non-empty without schema', function() {
var domWithoutSchema = new tinymce.dom.DOMUtils(document, {keep_values: true});
@ -645,7 +680,7 @@
var elm = DOM.create('p', null, '<em><br></em>');
ok(DOM.isEmpty(elm, 'No children'));
});
test('isEmpty on P with two BR in EM', function() {
var elm = DOM.create('p', null, '<em><br><br></em>');
equal(false, DOM.isEmpty(elm));
@ -654,13 +689,18 @@
test('bind/unbind/fire', function() {
var count = 0;
DOM.bind(document, 'click', function() {count++;});
DOM.bind(document, 'click', function() {
count++;
});
DOM.fire(document, 'click');
DOM.unbind(document, 'click');
equal(count, 1);
count = 0;
DOM.bind([document, window], 'click', function(e) {e.stopPropagation(); count++;});
DOM.bind([document, window], 'click', function(e) {
e.stopPropagation();
count++;
});
DOM.fire(document, 'click');
DOM.fire(window, 'click');
DOM.unbind([document, window], 'click');

View File

@ -1,7 +1,8 @@
ModuleLoader.require([
"tinymce/caret/CaretContainer",
"tinymce/text/Zwsp",
"tinymce/Env"
], function(CaretContainer, Env) {
], function(CaretContainer, Zwsp, Env) {
module("tinymce.dom.Selection", {
setupModule: function() {
QUnit.stop();
@ -503,8 +504,8 @@ ModuleLoader.require([
editor.setContent('<p contentEditable="false">1</p>');
CaretContainer.insertBlock('p', editor.$('p')[0], true);
rng = editor.dom.createRng();
rng.setStart(editor.$('p')[0].firstChild, 0);
rng.setEnd(editor.$('p')[0].firstChild, 1);
rng.setStart(editor.$('p')[0], 0);
rng.setEnd(editor.$('p')[0], 0);
editor.selection.setRng(rng);
bookmark = editor.selection.getBookmark(2);
editor.setContent('<p contentEditable="false">1</p>');
@ -846,6 +847,21 @@ ModuleLoader.require([
equal(rng.startOffset, 0);
});
test('normalize lean left from br into formatter caret container', function() {
var rng;
editor.getBody().innerHTML = '<p><span id="_mce_caret">' + Zwsp.ZWSP + '</span><br /></p>';
rng = editor.dom.createRng();
rng.setStartBefore(editor.getBody().firstChild.lastChild);
rng.setEndBefore(editor.getBody().firstChild.lastChild);
editor.selection.setRng(rng);
editor.selection.normalize();
rng = editor.selection.getRng(true);
equal(rng.startContainer.nodeType, 3);
equal(rng.startOffset, 1);
});
test('normalize don\'t lean left into empty inline elements if there is a br element after caret', function() {
var rng;
@ -1055,5 +1071,71 @@ ModuleLoader.require([
equal(rng.endContainer.nodeName, '#text');
equal(rng.endOffset, 1);
});
test('getRng should return null if win.document is not defined or null', function() {
var win = editor.selection.win,
rng = editor.dom.createRng();
editor.setContent('<p>x</p>');
rng.setStart(editor.$('p')[0].firstChild, 0);
rng.setEnd(editor.$('p')[0].firstChild, 1);
editor.selection.setRng(rng);
editor.selection.setRng(null);
editor.selection.win = {};
rng = editor.selection.getRng(true);
equal(rng, null);
editor.selection.win = {document:null};
rng = editor.selection.getRng(true);
equal(rng, null);
editor.selection.win = win;
});
test('image selection webkit bug', function() {
var testImageSelection = function (inputHtml, expectedContainerName, expectedOffset) {
editor.setContent(inputHtml);
editor.selection.select(editor.dom.select('img')[0]);
var rng = editor.selection.getRng(true);
equal(rng.startContainer.nodeName, 'P');
equal(rng.startOffset, expectedOffset);
equal(rng.startContainer.nodeName, 'P');
equal(rng.endOffset, expectedOffset + 1);
equal(editor.selection.getNode().nodeName, 'IMG');
equal(editor.selection.getStart().nodeName, 'IMG');
equal(editor.selection.getEnd().nodeName, 'IMG');
var nativeRng = editor.selection.getSel().getRangeAt(0);
equal(nativeRng.startContainer.nodeName, 'P');
equal(nativeRng.startOffset, expectedOffset);
equal(nativeRng.startContainer.nodeName, 'P');
equal(nativeRng.endOffset, expectedOffset + 1);
};
testImageSelection('<p><img src="#"></p>', 'P', 0);
testImageSelection('<p><img src="#">abc</p>', 'P', 0);
testImageSelection('<p>abc<img src="#"></p>', 'P', 1);
testImageSelection('<p>abc<img src="#">def</p>', 'P', 1);
testImageSelection('<p><img style="float: right;" src="#"></p>', 'P', 0);
testImageSelection('<p><img style="float: right;" src="#">abc</p>', 'P', 0);
testImageSelection('<p>abc<img style="float: right;" src="#"></p>', 'P', 1);
testImageSelection('<p>abc<img style="float: right;" src="#">def</p>', 'P', 1);
testImageSelection('<p><img style="float: left;" src="#"></p>', 'P', 0);
testImageSelection('<p><img style="float: left;" src="#">abc</p>', 'P', 0);
testImageSelection('<p>abc<img style="float: left;" src="#"></p>', 'P', 1);
testImageSelection('<p>abc<img style="float: left;" src="#">def</p>', 'P', 1);
testImageSelection('<p dir="rtl"><img style="float: right;" src="#"></p>', 'P', 0);
testImageSelection('<p dir="rtl"><img style="float: right;" src="#">abc</p>', 'P', 0);
testImageSelection('<p dir="rtl">abc<img style="float: right;" src="#"></p>', 'P', 1);
testImageSelection('<p dir="rtl">abc<img style="float: right;" src="#">def</p>', 'P', 1);
testImageSelection('<p dir="rtl"><img style="float: left;" src="#"></p>', 'P', 0);
testImageSelection('<p dir="rtl"><img style="float: left;" src="#">abc</p>', 'P', 0);
testImageSelection('<p dir="rtl">abc<img style="float: left;" src="#"></p>', 'P', 1);
testImageSelection('<p dir="rtl">abc<img style="float: left;" src="#">def</p>', 'P', 1);
});
});

View File

@ -25,7 +25,7 @@ test('Schema rules', function() {
ser.setRules('a[href|target<_blank?_top|title:forced value]');
DOM.setHTML('test', '<a href="file.htm" data-mce-href="file.htm" target="_blank" title="title">link</a><a href="#" data-mce-href="#" target="test">test2</a>');
equal(ser.serialize(DOM.get('test')), '<a href="file.htm" target="_blank" title="forced value">link</a><a href="#" title="forced value">test2</a>');
equal(ser.serialize(DOM.get('test')), '<a href="file.htm" target="_blank" title="forced value" rel="noopener noreferrer">link</a><a href="#" title="forced value">test2</a>');
ser.setRules('img[src|border=0|alt=]');
DOM.setHTML('test', '<img src="tinymce/ui/img/raster.gif" data-mce-src="tinymce/ui/img/raster.gif" border="0" alt="" />');
@ -234,6 +234,17 @@ test('Padd empty elements', function() {
equal(ser.serialize(DOM.get('test')), '<p>test</p><p>&nbsp;</p>');
});
test('Padd empty elements with BR', function() {
var ser = new tinymce.dom.Serializer({padd_empty_with_br: true});
ser.setRules('#p,table,tr,#td,br');
DOM.setHTML('test', '<p>a</p><p></p>');
equal(ser.serialize(DOM.get('test')), '<p>a</p><p><br /></p>');
DOM.setHTML('test', '<p>a</p><table><tr><td><br></td></tr></table>');
equal(ser.serialize(DOM.get('test')), '<p>a</p><table><tr><td><br /></td></tr></table>');
});
test('Remove empty elements', function() {
var ser = new tinymce.dom.Serializer({fix_list_elements : true});
@ -346,6 +357,14 @@ test('Script whitespace in beginning/end and cdata', 1, function() {
equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s' + 'cript>// <![CDATA[\n1 < 2;\n// ]]></s' + 'cript>');
});
test('Whitespace preserve in pre', function() {
var ser = new tinymce.dom.Serializer({fix_list_elements : true});
ser.setRules('pre');
DOM.setHTML('test', '<pre> </pre>');
equal(ser.serialize(DOM.get('test')), '<pre> </pre>');
});
test('Script with src attr', 1, function() {
var ser = new tinymce.dom.Serializer({fix_list_elements : true});
ser.setRules('script[type|language|src]');
@ -524,3 +543,17 @@ test('addTempAttr', function() {
equal(ser.serialize(DOM.get('test'), {getInner: 1}), '<p data-z="3">a</p>');
equal(ser.trimHtml('<p data-x="1" data-y="2" data-z="3">a</p>'), '<p data-z="3">a</p>');
});
test('addTempAttr same attr twice', function() {
var ser1 = new tinymce.dom.Serializer({});
var ser2 = new tinymce.dom.Serializer({});
ser1.addTempAttr('data-x');
ser2.addTempAttr('data-x');
DOM.setHTML('test', '<p data-x="1" data-z="3">a</p>');
equal(ser1.serialize(DOM.get('test'), {getInner: 1}), '<p data-z="3">a</p>');
equal(ser1.trimHtml('<p data-x="1" data-z="3">a</p>'), '<p data-z="3">a</p>');
equal(ser2.serialize(DOM.get('test'), {getInner: 1}), '<p data-z="3">a</p>');
equal(ser2.trimHtml('<p data-x="1" data-z="3">a</p>'), '<p data-z="3">a</p>');
});

View File

@ -2,21 +2,31 @@ ModuleLoader.require([
"tinymce/file/ImageScanner",
"tinymce/file/UploadStatus",
"tinymce/file/BlobCache",
"tinymce/file/Conversions",
"tinymce/Env"
], function(ImageScanner, UploadStatus, BlobCache, Env) {
], function(ImageScanner, UploadStatus, BlobCache, Conversions, Env) {
if (!tinymce.Env.fileApi) {
return;
}
QUnit.config.autostart = false;
module("tinymce.file.ImageScanner");
var base64Src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
var blobUriSrc;
Conversions.uriToBlob(base64Src).then(function(blob) {
blobUriSrc = URL.createObjectURL(blob);
QUnit.start();
});
QUnit.asyncTest("findAll", function() {
var imageScanner = new ImageScanner(new UploadStatus(), new BlobCache());
document.getElementById('view').innerHTML = (
'<img src="' + base64Src + '">' +
'<img src="' + blobUriSrc + '">' +
'<img src="' + Env.transparentSrc + '">' +
'<img src="' + base64Src + '" data-mce-bogus="1">' +
'<img src="' + base64Src + '" data-mce-placeholder="1">'
@ -24,8 +34,9 @@ ModuleLoader.require([
imageScanner.findAll(document.getElementById('view')).then(function(result) {
QUnit.start();
equal(result.length, 1);
equal('data:image/gif;base64,' + result[0].blobInfo.base64(), base64Src);
var blobInfo = result[0].blobInfo;
equal(result.length, 2);
equal('data:image/gif;base64,' + blobInfo.base64(), base64Src);
strictEqual(result[0].image, document.getElementById('view').firstChild);
});
});

View File

@ -0,0 +1,75 @@
ModuleLoader.require(["tinymce/fmt/FontInfo"], function(FontInfo) {
module("tinymce.fmt.FontInfo", {});
var assertComputedFontProp = function (fontProp, html, expected) {
var div = document.createElement('div');
var fontGetProp = fontProp === 'fontSize' ? FontInfo.getFontSize : FontInfo.getFontFamily;
document.body.appendChild(div);
div.style[fontProp] = expected;
div.innerHTML = html;
equal(fontGetProp(div, div.getElementsByTagName('mark')[0]), expected, 'Doesn\'t match the expected computed runtime style');
div.parentNode.removeChild(div);
};
var assertSpecificFontProp = function (fontProp, html, expected) {
var div = document.createElement('div');
var fontGetProp = fontProp === 'fontSize' ? FontInfo.getFontSize : FontInfo.getFontFamily;
document.body.appendChild(div);
div.innerHTML = html;
equal(fontGetProp(div, div.getElementsByTagName('mark')[0]), expected, 'Doesn\'t match the expected specific element style');
div.parentNode.removeChild(div);
};
test('toPt', function() {
equal(FontInfo.toPt('10px'), '8pt');
equal(FontInfo.toPt('11px'), '8pt');
equal(FontInfo.toPt('12.5px'), '9pt');
equal(FontInfo.toPt('13px'), '10pt');
equal(FontInfo.toPt('36px'), '27pt');
});
test('getFontSize', function() {
assertComputedFontProp('fontSize', '<mark></mark>', '10px');
assertComputedFontProp('fontSize', '<span><mark></mark></span>', '10px');
assertSpecificFontProp('fontSize', '<mark style="font-size: 10px"></mark>', '10px');
assertSpecificFontProp('fontSize', '<mark style="font-size: 14px"></mark>', '14px');
assertSpecificFontProp('fontSize', '<mark style="font-size: 14pt"></mark>', '14pt');
assertSpecificFontProp('fontSize', '<mark style="font-size: 14em"></mark>', '14em');
assertSpecificFontProp('fontSize', '<span style="font-size: 10px"><mark></mark></span>', '10px');
assertSpecificFontProp('fontSize', '<span style="font-size: 14px"><mark></mark></span>', '14px');
assertSpecificFontProp('fontSize', '<span style="font-size: 10px"><span><mark></mark></span></span>', '10px');
assertSpecificFontProp('fontSize', '<span style="font-size: 14px"><span><mark></mark></span></span>', '14px');
});
test('getFontFamily', function() {
assertComputedFontProp('fontFamily', '<mark></mark>', 'Arial,Verdana');
assertComputedFontProp('fontFamily', '<span><mark></mark></span>', 'Arial,Helvetica,Verdana');
assertSpecificFontProp('fontFamily', '<mark style="font-family: Arial, Verdana"></mark>', 'Arial,Verdana');
assertSpecificFontProp('fontFamily', '<mark style="font-family: Arial, Helvetica, Verdana"></mark>', 'Arial,Helvetica,Verdana');
assertSpecificFontProp('fontFamily', '<span style="font-family: Arial, Verdana"><mark></mark></span>', 'Arial,Verdana');
assertSpecificFontProp('fontFamily', '<span style="font-family: Arial, Helvetica, Verdana"><mark></mark></span>', 'Arial,Helvetica,Verdana');
assertSpecificFontProp('fontFamily', '<span style="font-family: Arial, Verdana"><span><mark></mark></span>', 'Arial,Verdana');
assertSpecificFontProp('fontFamily', '<span style="font-family: Arial, Helvetica, Verdana"><span><mark></mark></span></span>', 'Arial,Helvetica,Verdana');
});
asyncTest('getFontFamily should always return string even if display: none (firefox specific bug)', function() {
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.addEventListener('load', function () {
QUnit.start();
var fontFamily = FontInfo.getFontFamily(iframe.contentDocument.body, iframe.contentDocument.body.firstChild);
equal(typeof fontFamily, 'string', 'Should always be a string');
iframe.parentNode.removeChild(iframe);
}, false);
iframe.contentDocument.open();
iframe.contentDocument.write('<html><body><p>a</p></body></html>');
iframe.contentDocument.close();
});
});

View File

@ -0,0 +1,247 @@
ModuleLoader.require(["tinymce/fmt/Preview"], function(Preview) {
module("tinymce.fmt.Preview", {
setupModule: function () {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
disable_nodechange: true,
skin: false,
entities: 'raw',
indent: false,
custom_elements: '~custom',
extended_valid_elements: 'custom',
init_instance_callback: function (ed) {
editor = ed;
QUnit.start();
}
});
}
});
test('Get preview css text for formats', function () {
function getCssText(format) {
return Preview.getCssText(editor, format);
}
ok(/font-weight\:(bold|700)/.test(getCssText('bold')),
'Bold not found in preview style');
ok(/font-weight\:(bold|700)/.test(getCssText({inline: 'b'})),
'Bold not found in preview style');
ok(!/font-weight\:(bold|700)/.test(getCssText({inline: 'b', preview: 'font-size'})),
'Bold should not be when we only preview font-size');
ok(/color\:rgb\(255, 0, 0\)/.test(getCssText({inline: 'custom', styles: {color: '#ff0000'}})),
'Test preview of a custom element.');
editor.dom.addStyle(
'table .preview {' +
'color: rgb(0, 255, 0);' + // green
'}' +
'ol .preview {' +
'color: rgb(0, 0, 255);' + // blue
'}' +
'.preview {' +
'color: rgb(255, 0, 0);' + // red
'}'
);
ok(/color\:rgb\(0, 255, 0\)/.test(getCssText({selector: 'tr', classes: ['preview']})),
'Style is properly inherited in preview for partial element (like TR).');
ok(/color\:rgb\(255, 0, 0\)/.test(getCssText({selector: 'li', classes: ['preview']})),
'For LI element default required parent is UL.');
ok(/color\:rgb\(0, 0, 255\)/.test(getCssText({selector: 'ol li', classes: ['preview']})),
'Parent explicitly present in the selector will have preference.');
ok(/color\:rgb\(0, 0, 255\)/.test(getCssText({selector: 'ol > li', classes: ['preview']})),
'ol > li previewed properly.');
ok(/color\:rgb\(0, 0, 255\)/.test(getCssText({
selector: 'ol.someClass > li#someId[title="someTitle"]',
classes: ['preview']
})),
'ol.someClass > li#someId[title="someTitle"] previewed properly.');
ok(/color\:rgb\(0, 0, 255\)/.test(getCssText({
selector: 'ul + ol.someClass > li#someId',
classes: ['preview']
})),
'ul + ol.someClass > li#someId previewed properly.');
ok(/color\:rgb\(0, 0, 255\)/.test(getCssText({selector: 'ul li ol li', classes: ['preview']})),
'ul li ol li previewed properly.');
});
test('Preview.parseSelector()', function() {
deepEqual(Preview.parseSelector('li.class1.class2#id1[attr1="1"]:disabled'), [
{
name: 'li',
selector: 'li.class1.class2#id1[attr1="1"]:disabled',
classes: ['class1', 'class2'],
attrs: {
id: 'id1',
attr1: '1',
disabled: 'disabled'
}
}
], 'li.class1.class2#id1 ok');
deepEqual(Preview.parseSelector('ul.parent1 > li.class1.class2#id1'), [
{
name: 'li',
selector: 'li.class1.class2#id1',
classes: ['class1', 'class2'],
attrs: {
id: 'id1'
}
},
{
name: 'ul',
selector: 'ul.parent1',
classes: ['parent1'],
attrs: {}
}
], 'ul.parent1 > li.class1.class2#id1 ok');
deepEqual(Preview.parseSelector('div.class1 > ol.class2 + ul > li:hover'), [
{
name: 'li',
selector: 'li:hover',
classes: [],
attrs: {}
},
{
name: 'ul',
selector: 'ul',
classes: [],
attrs: {},
siblings: [
{
name: 'ol',
selector: 'ol.class2',
classes: ['class2'],
attrs: {}
}
]
},
{
name: 'div',
selector: 'div.class1',
classes: ['class1'],
attrs: {}
}
], 'div.class1 > ol.class2 + ul > li:hover ok');
deepEqual(Preview.parseSelector('.class > *'), [
{
name: "div",
selector: "*",
attrs: {},
classes: []
},
{
name: "div",
selector: ".class",
classes: ["class"],
attrs: {}
}
], '.class > * ok');
deepEqual(Preview.parseSelector('p + *'), [
{
name: "div",
selector: "*",
attrs: {},
classes: [],
siblings: [
{
name: "p",
selector: "p",
attrs: {},
classes: []
}
]
}
], 'p + * ok');
deepEqual(Preview.parseSelector('*.test'), [
{
name: "*",
selector: "*.test",
attrs: {},
classes: ['test']
}
], '*.test ok');
});
test('Preview.selectorToHtml()', function() {
function trimSpaces(str) {
return str.replace(/>\s+</g, '><').replace(/^\s*|\s*$/g, '');
}
function selectorToHtml(selector) {
return Utils.normalizeHtml(Preview.selectorToHtml(selector).outerHTML);
}
equal(selectorToHtml('ul > li.class1'), trimSpaces([
'<div>',
'<ul>',
'<li class="class1"></li>',
'</ul>',
'</div>'
].join('')), 'ul > li.class1 ok');
equal(selectorToHtml('ol + ul#id1 > li.class1[title="Some Title"]'), trimSpaces([
'<div>',
'<div>',
'<ol></ol>',
'<ul id="id1">',
' <li class="class1" title="Some Title"></li>',
'</ul>',
'</div>',
'</div>'
].join('')), 'ol + ul#id1 > li.class1[title="Some Title"] ok');
equal(selectorToHtml('tr > th + td'), trimSpaces([
'<div>',
'<table>',
'<tbody>',
'<tr>',
'<th></th>',
'<td></td>',
'</tr>',
'</tbody>',
'</table>',
'</div>'
].join('')), 'tr > th + td (required parental structure properly rebuilt) ok');
equal(selectorToHtml('p li[title="Some Title"][alt="Some Alt"]'), trimSpaces([
'<div>',
'<p>',
'<ul>',
'<li alt="Some Alt" title="Some Title"></li>',
'</ul>',
'</p>',
'</div>'
].join('')), 'p li[title="Some Title"][alt="Some Alt"] (test multiple spaced attributes) ok');
});
});

View File

@ -99,6 +99,13 @@
deepEqual(countNodes(root), {body:1, pre:1, '#text':1}, 'Whitespace around and inside PRE (count)');
});
test('Whitespace preserved in PRE', function() {
parser = new tinymce.html.DomParser({}, schema);
root = parser.parse('<PRE> </PRE>');
equal(serializer.serialize(root), '<pre> </pre>', 'Whitespace around and inside PRE');
deepEqual(countNodes(root), {body:1, pre:1, '#text':1}, 'Whitespace around and inside PRE (count)');
});
test('Whitespace preserved in SPAN inside PRE', function() {
parser = new tinymce.html.DomParser({}, schema);
root = parser.parse(' \t\r\n <PRE> \t\r\n <span> test </span> \t\r\n </PRE> \t\r\n ');
@ -106,6 +113,20 @@
deepEqual(countNodes(root), {body:1, pre:1, span:1, '#text':3}, 'Whitespace around and inside PRE (count)');
});
test('Whitespace preserved in code', function() {
parser = new tinymce.html.DomParser({}, schema);
root = parser.parse('<code> a </code>');
equal(serializer.serialize(root), '<code> a </code>', 'Whitespace inside code');
deepEqual(countNodes(root), {body:1, code:1, '#text':1}, 'Whitespace inside code (count)');
});
test('Whitespace preserved in code', function() {
parser = new tinymce.html.DomParser({}, schema);
root = parser.parse('<code> </code>');
equal(serializer.serialize(root), '<code> </code>', 'Whitespace inside code');
deepEqual(countNodes(root), {body:1, code:1, '#text':1}, 'Whitespace inside code (count)');
});
test('Parse invalid contents', function() {
var parser, root;
@ -422,6 +443,14 @@
'Mixed text nodes, inline elements and blocks.');
});
test('Parse html4 lists into html5 lists', function() {
var parser, root, schema = new tinymce.html.Schema();
parser = new tinymce.html.DomParser({fix_list_elements: true}, schema);
root = parser.parse('<ul><ul><li>a</li></ul></ul><ul><li>a</li><ul><li>b</li></ul></ul>');
equal(serializer.serialize(root), '<ul><li style="list-style-type: none"><ul><li>a</li></ul></li></ul><ul><li>a<ul><li>b</li></ul></li></ul>');
});
test('Parse contents with html4 anchors and allow_html_in_named_anchor: false', function() {
var parser, root, schema = new tinymce.html.Schema();
@ -510,6 +539,14 @@
equal(serializer.serialize(root), '');
});
test('Padd empty with br', function() {
var schema = new tinymce.html.Schema();
var parser = new tinymce.html.DomParser({padd_empty_with_br: true}, schema);
var serializer = new tinymce.html.Serializer({padd_empty_with_br: true}, schema);
var root = parser.parse('<p>a</p><p></p>');
equal(serializer.serialize(root), '<p>a</p><p><br /></p>');
});
test('Preserve space in inline span', function() {
var parser, root, schema = new tinymce.html.Schema();

View File

@ -139,7 +139,7 @@ test('remove middle node', function() {
ok(root.lastChild === node3, 'root.lastChild');
ok(node.next === node3, 'node.next');
equal(node.prev, undefined, 'node.prev');
ok(node3.prev, node, 'node3.prev');
equal(node3.prev, node, 'node3.prev');
equal(node3.next, undefined, 'node3.next');
});

View File

@ -604,6 +604,10 @@
writer.reset();
parser.parse('<!--[if !IE]>alert(1)<![endif]-->');
equal(writer.getContent(), '<!-- [if !IE]>alert(1)<![endif]-->');
writer.reset();
parser.parse('<!--[iF !IE]>alert(1)<![endif]-->');
equal(writer.getContent(), '<!-- [iF !IE]>alert(1)<![endif]-->');
});
test('Parse script urls (allowed)', function() {

View File

@ -13,27 +13,27 @@ test('Whildcard element rule', function() {
expect(17);
schema = new tinymce.html.Schema({valid_elements: '*[id|class]'});
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
schema = new tinymce.html.Schema({valid_elements: 'b*[id|class]'});
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('body').attributesOrder, ["id", "class"]);
equal(schema.getElementRule('img'), undefined);
schema = new tinymce.html.Schema({valid_elements: 'b?[id|class]'});
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('bx').attributesOrder, ["id", "class"]);
equal(schema.getElementRule('body'), undefined);
schema = new tinymce.html.Schema({valid_elements: 'b+[id|class]'});
deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('body').attributesOrder, ["id", "class"]);
deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('bx').attributesOrder, ["id", "class"]);
equal(schema.getElementRule('b'), undefined);
});
@ -44,19 +44,19 @@ test('Whildcard attribute rule', function() {
expect(13);
schema = new tinymce.html.Schema({valid_elements: 'b[id|class|*]'});
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
ok(schema.getElementRule('b').attributePatterns[0].pattern.test('x'));
schema = new tinymce.html.Schema({valid_elements: 'b[id|class|x?]'});
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xy'));
ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('xba'));
ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('a'));
schema = new tinymce.html.Schema({valid_elements: 'b[id|class|x+]'});
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('x'));
ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xb'));
@ -119,6 +119,15 @@ test('Required attribute values', function() {
deepEqual(schema.getElementRule('span'), {"attributes": {"dir": {"validValues": {"rtl": {}, "ltr": {}}}}, "attributesOrder": ["dir"]});
});
test('Required parents', function() {
var schema;
schema = new tinymce.html.Schema();
deepEqual(schema.getElementRule('tr').parentsRequired, ['tbody', 'thead', 'tfoot']);
deepEqual(schema.getElementRule('li').parentsRequired, ['ul', 'ol']);
deepEqual(schema.getElementRule('div').parentsRequired, undefined);
});
test('Remove empty elements', function() {
var schema;
@ -220,11 +229,11 @@ test('getNonEmptyElements', function() {
"EMBED": {}, "PARAM": {}, "META": {}, "LINK": {}, "ISINDEX": {},
"INPUT": {}, "IMG": {}, "HR": {}, "FRAME": {}, "COL": {}, "BR": {},
"BASEFONT": {}, "BASE": {}, "AREA": {}, "SOURCE" : {},
"TD": {}, "TH": {}, "IFRAME": {}, "VIDEO": {}, "AUDIO": {}, "OBJECT": {}, "WBR": {}, "TRACK" : {}, "SCRIPT" : {},
"TD": {}, "TH": {}, "IFRAME": {}, "VIDEO": {}, "AUDIO": {}, "OBJECT": {}, "WBR": {}, "TRACK" : {}, "SCRIPT" : {}, "PRE": {}, "CODE": {},
"embed": {}, "param": {}, "meta": {}, "link": {}, "isindex": {},
"input": {}, "img": {}, "hr": {}, "frame": {}, "col": {}, "br": {},
"basefont": {}, "base": {}, "area": {}, "source" : {},
"td": {}, "th": {}, "iframe": {}, "video": {}, "audio": {}, "object": {}, "wbr" : {}, "track" : {}, "script" : {}
"td": {}, "th": {}, "iframe": {}, "video": {}, "audio": {}, "object": {}, "wbr" : {}, "track" : {}, "script" : {}, "pre": {}, "code": {}
});
});
@ -235,9 +244,9 @@ test('getWhiteSpaceElements', function() {
schema = new tinymce.html.Schema();
deepEqual(schema.getWhiteSpaceElements(), {
"IFRAME": {}, "NOSCRIPT": {}, "OBJECT": {}, "PRE": {},
"IFRAME": {}, "NOSCRIPT": {}, "OBJECT": {}, "PRE": {}, "CODE": {},
"SCRIPT": {}, "STYLE": {}, "TEXTAREA": {}, "VIDEO": {}, "AUDIO": {},
"iframe": {}, "noscript": {}, "object": {}, "pre": {},
"iframe": {}, "noscript": {}, "object": {}, "pre": {}, "code": {},
"script": {}, "style": {}, "textarea": {}, "video": {}, "audio": {}
});
});

View File

@ -3,7 +3,7 @@ module("tinymce.html.Styles");
test('Basic parsing/serializing', function() {
var styles = new tinymce.html.Styles();
expect(11);
expect(12);
equal(styles.serialize(styles.parse('FONT-SIZE:10px')), "font-size: 10px;");
equal(styles.serialize(styles.parse('FONT-SIZE:10px;COLOR:red')), "font-size: 10px; color: red;");
@ -16,6 +16,7 @@ test('Basic parsing/serializing', function() {
equal(styles.serialize(styles.parse('value: "&amp;"')), "value: '&amp;';");
equal(styles.serialize(styles.parse('value: "&"')), "value: '&';");
equal(styles.serialize(styles.parse('value: ')), "");
equal(styles.serialize(styles.parse("background: url('http://www.site.com/(foo)');")), "background: url('http://www.site.com/(foo)');");
});
test('Colors force hex and lowercase', function() {
@ -61,7 +62,7 @@ test('Compress styles', function() {
styles.serialize(styles.parse('border-width: 1pt 1pt 1pt 1pt; border-style: none none none none; border-color: black black black black;')),
'border: 1pt none black;'
);
equal(
styles.serialize(styles.parse('border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;')),
'border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;'
@ -137,10 +138,19 @@ test('Invalid styles', function() {
equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px; margin-right: 10px;'), 'a'), "margin-right: 10px;");
});
test('Suspicious (XSS) property names', function() {
var styles = new tinymce.html.Styles();
equal(styles.serialize(styles.parse('font-fa"on-load\\3dxss\\28\\29\\20mily:\'arial\'')), "");
equal(styles.serialize(styles.parse('font-fa\\"on-load\\3dxss\\28\\29\\20mily:\'arial\'')), "");
equal(styles.serialize(styles.parse('font-fa\\22on-load\\3dxss\\28\\29\\20mily:\'arial\'')), "");
});
test('Script urls denied', function() {
var styles = new tinymce.html.Styles();
equal(styles.serialize(styles.parse('behavior:url(test.htc)')), "");
equal(styles.serialize(styles.parse('b\\65havior:url(test.htc)')), "");
equal(styles.serialize(styles.parse('color:expression(alert(1))')), "");
equal(styles.serialize(styles.parse('color:\\65xpression(alert(1))')), "");
equal(styles.serialize(styles.parse('color:exp/**/ression(alert(1))')), "");
@ -148,9 +158,20 @@ test('Script urls denied', function() {
equal(styles.serialize(styles.parse('color: expression ( alert(1))')), "");
equal(styles.serialize(styles.parse('background:url(jAvaScript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(javascript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(j\\61vascript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(\\6a\\61vascript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(\\6A\\61vascript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url\\28\\6A\\61vascript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:\\75rl(j\\61vascript:alert(1)')), "");
equal(styles.serialize(styles.parse('b\\61ckground:\\75rl(j\\61vascript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(vbscript:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(j\navas\u0000cr\tipt:alert(1)')), "");
equal(styles.serialize(styles.parse('background:url(data:image/svg+xml,%3Csvg/%3E)')), "");
equal(styles.serialize(styles.parse('background:url( data:image/svg+xml,%3Csvg/%3E)')), "");
equal(styles.serialize(styles.parse('background:url\\28 data:image/svg+xml,%3Csvg/%3E)')), "");
equal(styles.serialize(styles.parse('background:url("data: image/svg+xml,%3Csvg/%3E")')), "");
equal(styles.serialize(styles.parse('background:url("data: ima ge/svg+xml,%3Csvg/%3E")')), "");
equal(styles.serialize(styles.parse('background:url("data: image /svg+xml,%3Csvg/%3E")')), "");
});
test('Script urls allowed', function() {

View File

@ -0,0 +1,94 @@
module("tinymce.options", {
setup: function() {
var i, htmlReset = '';
for (i = 1; i < 9; i++) {
htmlReset += '<textarea id="elm-' + i + '" class="' + (i&1 ? 'elm-odd' : 'elm-even') + '"></textarea>';
}
document.getElementById('view').innerHTML = htmlReset;
},
teardown: function() {
var ed;
while ((ed = tinymce.editors.pop())) {
ed.remove();
}
}
});
test("target (initialised properly)", function() {
var elm1 = document.getElementById('elm-1');
QUnit.stop();
tinymce.init({
target: elm1,
init_instance_callback: function(ed) {
QUnit.start();
equal(ed.targetElm, elm1);
}
});
});
test("target (initialise on element without id)", function() {
var elm = document.createElement('textarea');
document.getElementById('view').appendChild(elm);
QUnit.stop();
tinymce.init({
target: elm,
init_instance_callback: function(ed) {
QUnit.start();
ok(ed.id, "editors id set to: " + ed.id);
equal(ed.targetElm, elm);
}
});
});
test("target (selector option takes precedence over target option)", function() {
var elm1 = document.getElementById('elm-1');
var elm2 = document.getElementById('elm-2');
QUnit.stop();
tinymce.init({
selector: '#elm-2',
target: elm1,
init_instance_callback: function(ed) {
QUnit.start();
equal(ed.targetElm, elm2);
}
});
});
test("target (each editor should have a different target)", function() {
var maxCount = $('.elm-even').length;
var elm1 = document.getElementById('elm-1');
var count = 0;
var targets = [];
QUnit.stop();
tinymce.init({
selector: '.elm-even',
target: elm1,
init_instance_callback: function(ed) {
notEqual(ed.targetElm, elm1, "target option ignored");
ok($.inArray(ed.targetElm, targets) === -1);
targets.push(ed.targetElm);
if (++count >= maxCount) {
QUnit.start();
}
}
});
});

View File

@ -0,0 +1,260 @@
ModuleLoader.require([
'tinymce/util/VK',
'tinymce/util/Promise'
], function(VK, Promise) {
module("tinymce.ui.FilePicker", {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: "textarea",
add_unload_trigger: false,
disable_nodechange: true,
skin: false,
entities: 'raw',
indent: false,
plugins: 'link',
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
},
filepicker_validator_handler: function (query, success) {
setTimeout(function () {
var valid = query.url.indexOf('fake') === -1;
success({
status: valid ? 'valid' : 'invalid',
message: valid ? 'Valid message' : 'Invalid message'
});
}, 0);
}
});
},
teardown: function() {
delete editor.settings.anchor_top;
delete editor.settings.anchor_bottom;
delete editor.settings.typeahead_urls;
}
});
var getFilePickerCtrl = function () {
var win = editor.windowManager.getWindows()[0];
return win ? win.find('filepicker')[0] : null;
};
var keydownOnCtrl = function (pickerCtrl, keyCode) {
return new Promise(function (resolve) {
pickerCtrl.fire('keydown', {target: pickerCtrl.getEl('inp'), keyCode: keyCode});
resolve(pickerCtrl);
});
};
var downOnMenu = function () {
return keydownOnCtrl(getFilePickerCtrl().menu, VK.DOWN);
};
var enterOnMenu = function () {
return keydownOnCtrl(getFilePickerCtrl().menu, VK.ENTER);
};
var downOnPicker = function () {
return keydownOnCtrl(getFilePickerCtrl(), VK.DOWN);
};
var enterOnPicker = function () {
return keydownOnCtrl(getFilePickerCtrl(), VK.ENTER);
};
var setContent = function (content) {
return function () {
return new Promise(function (resolve) {
editor.setContent(content);
resolve(true);
});
};
};
var execCommand = function (cmd) {
return function () {
return new Promise(function (resolve) {
editor.execCommand(cmd);
resolve(true);
});
};
};
var assertContent = function (exceptedContent) {
return function () {
return new Promise(function (resolve) {
equal(editor.getContent(), exceptedContent, 'Should have the expected content');
resolve(true);
});
};
};
var waitFor = function (predicate, poll, timeout) {
return function () {
var start = new Date().getTime();
return new Promise(function (resolve, reject) {
var check = function () {
if (predicate()) {
resolve();
return;
}
if (new Date().getTime() - start > timeout) {
reject(new Error('Timeout while waiting for predicate'));
return;
}
setTimeout(check, poll);
};
check();
});
};
};
var waitForMenu = waitFor(
function () {
var pickerCtrl = getFilePickerCtrl();
return pickerCtrl && pickerCtrl.menu;
},
100,
1000
);
var setCaret = function (selector, index) {
return function () {
return new Promise(function (resolve) {
Utils.setSelection(selector, index);
resolve(true);
});
};
};
var assertValue = function (expectedValue) {
return function () {
return new Promise(function (resolve) {
var pickerCtrl = getFilePickerCtrl();
equal(pickerCtrl.value(), expectedValue, 'Should have the correct file picker value');
resolve(pickerCtrl);
});
};
};
var setPickerValue = function (value) {
return function () {
return new Promise(function (resolve) {
var pickerCtrl = getFilePickerCtrl();
pickerCtrl.value(value);
resolve(pickerCtrl);
});
};
};
var waitForStatusChange = waitFor(
function () {
var pickerCtrl = getFilePickerCtrl();
var msg = pickerCtrl.statusMessage();
return msg && msg.length > 0;
},
100,
1000
);
var assertStatus = function (level, message) {
return function () {
return new Promise(function (resolve) {
var pickerCtrl = getFilePickerCtrl();
equal(pickerCtrl.statusLevel(), level);
equal(pickerCtrl.statusMessage(), message);
resolve(pickerCtrl);
});
};
};
var sequence = function (fs) {
return new Promise(function (resolve) {
var result = [];
var next = function () {
var f = fs.shift();
if (f) {
f().then(function (res) {
result.push(res);
next();
});
} else {
resolve(result);
}
};
next();
});
};
asyncTest('pick first anchor <top>', function() {
sequence([
setContent(''),
execCommand('mceLink'),
downOnPicker,
waitForMenu,
enterOnMenu,
assertValue('#top'),
enterOnPicker,
assertContent('<p><a href="#top">&lt;top&gt;</a></p>')
]).then(function () {
QUnit.start();
});
});
asyncTest('pick second anchor <bottom>', function() {
sequence([
setContent(''),
execCommand('mceLink'),
downOnPicker,
waitForMenu,
downOnMenu,
enterOnMenu,
assertValue('#bottom'),
enterOnPicker,
assertContent('<p><a href="#bottom">&lt;bottom&gt;</a></p>')
]).then(function () {
QUnit.start();
});
});
asyncTest('pick first header', function() {
sequence([
setContent('<p>x</p><h1 id="h1">header</h1>'),
setCaret('p', 0),
execCommand('mceLink'),
downOnPicker,
waitForMenu,
enterOnMenu,
assertValue('#h1'),
enterOnPicker,
assertContent('<p><a href="#h1">header</a>x</p><h1 id="h1">header</h1>')
]).then(function () {
QUnit.start();
});
});
asyncTest('filepicker_validator_handler', function() {
sequence([
setContent('<p>abc</p>'),
setCaret('p', 0),
execCommand('mceLink'),
setPickerValue('http://www.site.com'),
waitForStatusChange,
assertStatus('ok', 'Valid message'),
enterOnPicker
]).then(function () {
QUnit.start();
});
});
});

View File

@ -36,7 +36,16 @@
});
test("title, no buttonbar, autoResize, title is widest", function() {
var win = createWindow({
var win1 = createWindow({
x: 100,
y: 120,
title: "XXXXXXXXXXXXXXXXXXX",
items: [
{type: 'spacer', classes: 'red', flex: 1}
]
});
var win2 = createWindow({
x: 100,
y: 120,
title: "XXXXXXXXXXXXXXXXXXXXXX",
@ -45,8 +54,8 @@
]
});
Utils.nearlyEqualRects(Utils.size(win), [326, 61], 60);
Utils.nearlyEqualRects(Utils.size(win.find("spacer")[0]), [324, 20], 60);
equal(Utils.size(win2)[0] > Utils.size(win1)[0], true, 'Window 2 should be wider since the title spaces out the window');
equal(Utils.size(win2.find("spacer")[0]) > Utils.size(win1.find("spacer")[0]), true, 'Window 2 spacer should be widger than window 1');
});
test("buttonbar, autoResize, buttonbar is widest", function() {

View File

@ -0,0 +1,17 @@
ModuleLoader.require(["tinymce/undo/Diff"], function(Diff) {
module("tinymce.undo.Diff");
var KEEP = Diff.KEEP, INSERT = Diff.INSERT, DELETE = Diff.DELETE;
test('diff', function() {
deepEqual(Diff.diff([], []), []);
deepEqual(Diff.diff([1], []), [[DELETE, 1]]);
deepEqual(Diff.diff([1, 2], []), [[DELETE, 1], [DELETE, 2]]);
deepEqual(Diff.diff([], [1]), [[INSERT, 1]]);
deepEqual(Diff.diff([], [1, 2]), [[INSERT, 1], [INSERT, 2]]);
deepEqual(Diff.diff([1], [1]), [[KEEP, 1]]);
deepEqual(Diff.diff([1, 2], [1, 2]), [[KEEP, 1], [KEEP, 2]]);
deepEqual(Diff.diff([1], [2]), [[INSERT, 2], [DELETE, 1]]);
deepEqual(Diff.diff([1], [2, 3]), [[INSERT, 2], [INSERT, 3], [DELETE, 1]]);
});
});

View File

@ -0,0 +1,54 @@
ModuleLoader.require([
'tinymce/undo/Levels'
], function(Levels) {
module('tinymce.undo.ForcedRootBlock', {
setupModule: function() {
QUnit.stop();
tinymce.init({
selector: 'textarea',
add_unload_trigger: false,
disable_nodechange: true,
skin: false,
entities: 'raw',
indent: false,
forced_root_block: false,
init_instance_callback: function(ed) {
window.editor = ed;
QUnit.start();
}
});
}
});
test('createFromEditor forced_root_block: false', function() {
editor.getBody().innerHTML = '<strong>a</strong> <span>b</span>';
deepEqual(Levels.createFromEditor(editor), {
'beforeBookmark': null,
'bookmark': null,
'content': '<strong>a</strong> <span>b</span>',
'fragments': null,
'type': 'complete'
});
});
test('createFromEditor forced_root_block: false', function() {
editor.getBody().innerHTML = '<iframe src="about:blank"></iframe> <strong>a</strong> <span>b</span>';
deepEqual(Levels.createFromEditor(editor), {
'beforeBookmark': null,
'bookmark': null,
'content': '',
'fragments': [
"<iframe src=\"about:blank\"></iframe>",
" ",
"<strong>a</strong>",
" ",
"<span>b</span>"
],
'type': 'fragmented'
});
});
});

View File

@ -0,0 +1,32 @@
ModuleLoader.require(['tinymce/undo/Fragments'], function(Fragments) {
module('tinymce.undo.Fragments');
var div = function (html) {
var div = document.createElement('div');
div.innerHTML = html;
return div;
};
var html = function (elm) {
return elm.innerHTML;
};
test('read', function() {
deepEqual(Fragments.read(div('')), []);
deepEqual(Fragments.read(div('a')), ['a']);
deepEqual(Fragments.read(div('<!--a-->')), ['<!--a-->']);
deepEqual(Fragments.read(div('<b>a</b>')), ['<b>a</b>']);
deepEqual(Fragments.read(div('a<!--b--><b>c</b>')), ['a', '<!--b-->', '<b>c</b>']);
});
test('write', function() {
deepEqual(html(Fragments.write([], div(''))), '');
deepEqual(html(Fragments.write([], div('a'))), '');
deepEqual(html(Fragments.write(['a'], div(''))), 'a');
deepEqual(html(Fragments.write(['a'], div('a'))), 'a');
deepEqual(html(Fragments.write(['a'], div('b'))), 'a');
deepEqual(html(Fragments.write(['a', '<b>c</b>'], div('a<b>b</b>'))), 'a<b>c</b>');
deepEqual(html(Fragments.write(['<b>c</b>', '<b>d</b>'], div('a<b>b</b>'))), '<b>c</b><b>d</b>');
deepEqual(html(Fragments.write(['<b>c</b>', '<b>d</b>', '<!--e-->'], div('a<b>b</b>'))), '<b>c</b><b>d</b><!--e-->');
});
});

View File

@ -0,0 +1,142 @@
ModuleLoader.require([
'tinymce/undo/Levels',
'tinymce/Env'
], function(Levels, Env) {
module('tinymce.undo.Levels', {
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();
}
});
}
});
var getBookmark = function (editor) {
return editor.selection.getBookmark(2, true);
};
test('createFragmentedLevel', function() {
deepEqual(Levels.createFragmentedLevel(['a', 'b']), {
'beforeBookmark': null,
'bookmark': null,
'content': '',
'fragments': ['a', 'b'],
'type': 'fragmented'
});
});
test('createCompleteLevel', function() {
deepEqual(Levels.createCompleteLevel('a'), {
'beforeBookmark': null,
'bookmark': null,
'content': 'a',
'fragments': null,
'type': 'complete'
});
});
test('createFromEditor', function() {
deepEqual(Levels.createFromEditor(editor), {
'beforeBookmark': null,
'bookmark': null,
'content': Env.ie && Env.ie < 11 ? '<p></p>' : '<p><br data-mce-bogus="1"></p>',
'fragments': null,
'type': 'complete'
});
editor.getBody().innerHTML = '<iframe src="about:blank"></iframe>a<!--b-->c';
deepEqual(Levels.createFromEditor(editor), {
'beforeBookmark': null,
'bookmark': null,
'content': '',
'fragments': ['<iframe src="about:blank"></iframe>', 'a', '<!--b-->', 'c'],
'type': 'fragmented'
});
});
test('createFromEditor removes bogus=al', function() {
editor.getBody().innerHTML = '<p data-mce-bogus="all">a</p> <span>b</span>';
deepEqual(Levels.createFromEditor(editor), {
'beforeBookmark': null,
'bookmark': null,
'content': ' <span>b</span>',
'fragments': null,
'type': 'complete'
});
});
test('createFromEditor removes bogus=all', function() {
editor.getBody().innerHTML = '<iframe src="about:blank"></iframe> <p data-mce-bogus="all">a</p> <span>b</span>';
deepEqual(Levels.createFromEditor(editor), {
'beforeBookmark': null,
'bookmark': null,
'content': '',
'fragments':[
"<iframe src=\"about:blank\"></iframe>",
" ",
"",
" ",
"<span>b</span>"
],
'type': 'fragmented'
});
});
test('applyToEditor to equal content with complete level', function() {
var level = Levels.createCompleteLevel('<p>a</p>');
level.bookmark = {start: [1, 0, 0]};
editor.getBody().innerHTML = '<p>a</p>';
Utils.setSelection('p', 0);
Levels.applyToEditor(editor, level, false);
strictEqual(editor.getBody().innerHTML, '<p>a</p>');
deepEqual(getBookmark(editor), {start: [1, 0, 0]});
});
test('applyToEditor to different content with complete level', function() {
var level = Levels.createCompleteLevel('<p>b</p>');
level.bookmark = {start: [1, 0, 0]};
editor.getBody().innerHTML = '<p>a</p>';
Utils.setSelection('p', 0);
Levels.applyToEditor(editor, level, false);
strictEqual(editor.getBody().innerHTML, '<p>b</p>');
deepEqual(getBookmark(editor), {start: [1, 0, 0]});
});
test('applyToEditor to different content with fragmented level', function() {
var level = Levels.createFragmentedLevel(['<p>a</p>', '<p>b</p>']);
level.bookmark = {start: [1, 0, 0]};
editor.getBody().innerHTML = '<p>c</p>';
Utils.setSelection('p', 0);
Levels.applyToEditor(editor, level, false);
strictEqual(editor.getBody().innerHTML, '<p>a</p><p>b</p>');
deepEqual(getBookmark(editor), {start: [1, 0, 0]});
});
test('isEq', function() {
strictEqual(Levels.isEq(Levels.createFragmentedLevel(['a', 'b']), Levels.createFragmentedLevel(['a', 'b'])), true);
strictEqual(Levels.isEq(Levels.createFragmentedLevel(['a', 'b']), Levels.createFragmentedLevel(['a', 'c'])), false);
strictEqual(Levels.isEq(Levels.createCompleteLevel('a'), Levels.createCompleteLevel('a')), true);
strictEqual(Levels.isEq(Levels.createCompleteLevel('a'), Levels.createCompleteLevel('b')), false);
strictEqual(Levels.isEq(Levels.createFragmentedLevel(['a']), Levels.createCompleteLevel('a')), true);
strictEqual(Levels.isEq(Levels.createCompleteLevel('a'), Levels.createFragmentedLevel(['a'])), true);
});
});

View File

@ -5,20 +5,51 @@ module("tinymce.util.I18n", {
});
test("Translate strings", function() {
var undef;
var translate = tinymce.util.I18n.translate;
tinymce.util.I18n.add("code", {
"text": "text translation",
"value:{0}{1}": "value translation:{0}{1}",
"text{context:something}": "text translation with context",
"value:{0}{1}{context:something}": "value translation:{0}{1} with context"
"value:{0}{1}{context:something}": "value translation:{0}{1} with context",
"empty string": ""
});
equal(tinymce.util.I18n.translate("text"), "text translation");
equal(tinymce.util.I18n.translate("untranslated text"), "untranslated text");
equal(tinymce.util.I18n.translate(["untranslated value:{0}{1}", "a", "b"]), "untranslated value:ab");
equal(tinymce.util.I18n.translate(["value:{0}{1}", "a", "b"]), "value translation:ab");
equal(tinymce.util.I18n.translate("untranslated text{context:context}"), "untranslated text");
equal(tinymce.util.I18n.translate(["untranslated value:{0}{1}{context:something}", "a", "b"]), "untranslated value:ab");
equal(tinymce.util.I18n.translate(["value:{0}{1}{context:something}", "a", "b"]), "value translation:ab with context");
equal(translate("text"), "text translation");
equal(translate("untranslated text"), "untranslated text");
equal(translate(["untranslated value:{0}{1}", "a", "b"]), "untranslated value:ab");
equal(translate(["value:{0}{1}", "a", "b"]), "value translation:ab");
equal(translate("untranslated text{context:context}"), "untranslated text");
equal(translate(["untranslated value:{0}{1}{context:something}", "a", "b"]), "untranslated value:ab");
equal(translate(["value:{0}{1}{context:something}", "a", "b"]), "value translation:ab with context");
// check if translate survives some awkward cases
deepEqual(translate("empty string"), "");
equal(translate(["untranslated value:{0}{1}", "a"]), "untranslated value:a{1}",
"Do not strip tokens that weren't replaced.");
equal(translate([{}]), "[object Object]");
equal(translate(function(){}), "[object Function]");
equal(translate(null), "");
equal(translate(0), 0, "0");
equal(translate(true), "true", "true");
equal(translate(false), "false", "false");
equal(translate({}), "[object Object]", "[object Object]");
equal(translate({raw:""}), "", "empty string");
equal(translate({raw:false}), "false", "false");
equal(translate({raw:undef}), "");
equal(translate({raw:null}), "");
// https://github.com/tinymce/tinymce/issues/3029
equal(translate("hasOwnProperty"), "hasOwnProperty");
tinymce.util.I18n.add("code", {
"hasOwnProperty": "good"
});
equal(translate("hasOwnProperty"), "good");
});
test("Switch language", function() {

View File

@ -125,6 +125,17 @@ if (tinymce.isWebKit) {
equal(editor.selection.getStart().nodeName, 'H1');
});
test('Delete from after image to paragraph', function() {
editor.getBody().innerHTML = '<p>a</p><p><img src="about:blank"></p>';
var rng = editor.dom.createRng();
rng.setStartAfter(editor.dom.select('img')[0]);
rng.setEndAfter(editor.dom.select('img')[0]);
editor.selection.setRng(rng);
editor.execCommand('Delete');
equal(Utils.normalizeHtml(Utils.cleanHtml(editor.getBody().innerHTML)), '<p>a</p>');
equal(editor.selection.getStart().nodeName, 'P');
});
test('ForwardDelete from end of H1 to P with style span', function() {
editor.getBody().innerHTML = '<h1>a</h1><p><span style="color:red">b</span></p>';
Utils.setSelection('h1', 1);
@ -334,6 +345,14 @@ if (tinymce.isWebKit) {
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><br data-mce-bogus="1"></p>');
equal(editor.selection.getStart(true).nodeName, 'P');
});
test('Delete with similar sibling nodes', function() {
editor.getBody().innerHTML = '<p>Test test</p><p>a</p><p>a</p><p id="t1">a</p><p>test1</p><p id="t2">test2</p>';
Utils.setSelection('p#t1', 1, 'p#t2', 5);
editor.fire('keydown', {keyCode: 8});
equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p>test test</p><p>a</p><p>a</p><p id="t1">a</p>');
equal(editor.selection.getStart(true).nodeName, 'P');
});
} else {
test("Skipped since the browser isn't WebKit", function() {
ok(true, "Skipped");