<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[40399] trunk/tests/qunit/editor: TinyMCE: update the tests for version 4.5.6.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/40399">40399</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/40399","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>azaozz</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2017-04-09 23:10:15 +0000 (Sun, 09 Apr 2017)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>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 <a href="https://core.trac.wordpress.org/ticket/40305">#40305</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunktestsquniteditorindexhtml">trunk/tests/qunit/editor/index.html</a></li>
<li><a href="#trunktestsquniteditorjsinitjs">trunk/tests/qunit/editor/js/init.js</a></li>
<li><a href="#trunktestsquniteditorjsqunitqunitjs">trunk/tests/qunit/editor/js/qunit/qunit.js</a></li>
<li><a href="#trunktestsquniteditorjstinymce_loaderjs">trunk/tests/qunit/editor/js/tinymce_loader.js</a></li>
<li><a href="#trunktestsquniteditortinymceEditorjs">trunk/tests/qunit/editor/tinymce/Editor.js</a></li>
<li><a href="#trunktestsquniteditortinymceEditorCommandsjs">trunk/tests/qunit/editor/tinymce/EditorCommands.js</a></li>
<li><a href="#trunktestsquniteditortinymceEditorManagerjs">trunk/tests/qunit/editor/tinymce/EditorManager.js</a></li>
<li><a href="#trunktestsquniteditortinymceEditorUploadjs">trunk/tests/qunit/editor/tinymce/EditorUpload.js</a></li>
<li><a href="#trunktestsquniteditortinymceEnterKeyjs">trunk/tests/qunit/editor/tinymce/EnterKey.js</a></li>
<li><a href="#trunktestsquniteditortinymceFormatter_applyjs">trunk/tests/qunit/editor/tinymce/Formatter_apply.js</a></li>
<li><a href="#trunktestsquniteditortinymceFormatter_checkjs">trunk/tests/qunit/editor/tinymce/Formatter_check.js</a></li>
<li><a href="#trunktestsquniteditortinymceSelectionOverridesjs">trunk/tests/qunit/editor/tinymce/SelectionOverrides.js</a></li>
<li><a href="#trunktestsquniteditortinymceUndoManagerjs">trunk/tests/qunit/editor/tinymce/UndoManager.js</a></li>
<li><a href="#trunktestsquniteditortinymcecaretCaretContainerjs">trunk/tests/qunit/editor/tinymce/caret/CaretContainer.js</a></li>
<li><a href="#trunktestsquniteditortinymcecaretFakeCaretjs">trunk/tests/qunit/editor/tinymce/caret/FakeCaret.js</a></li>
<li><a href="#trunktestsquniteditortinymcedomDOMUtilsjs">trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js</a></li>
<li><a href="#trunktestsquniteditortinymcedomSelectionjs">trunk/tests/qunit/editor/tinymce/dom/Selection.js</a></li>
<li><a href="#trunktestsquniteditortinymcedomSerializerjs">trunk/tests/qunit/editor/tinymce/dom/Serializer.js</a></li>
<li><a href="#trunktestsquniteditortinymcefileImageScannerjs">trunk/tests/qunit/editor/tinymce/file/ImageScanner.js</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlDomParserjs">trunk/tests/qunit/editor/tinymce/html/DomParser.js</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlNodejs">trunk/tests/qunit/editor/tinymce/html/Node.js</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlSaxParserjs">trunk/tests/qunit/editor/tinymce/html/SaxParser.js</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlSchemajs">trunk/tests/qunit/editor/tinymce/html/Schema.js</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlStylesjs">trunk/tests/qunit/editor/tinymce/html/Styles.js</a></li>
<li><a href="#trunktestsquniteditortinymceuiWindowjs">trunk/tests/qunit/editor/tinymce/ui/Window.js</a></li>
<li><a href="#trunktestsquniteditortinymceutilI18njs">trunk/tests/qunit/editor/tinymce/util/I18n.js</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_webkitjs">trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunktestsquniteditortinymceEditorCustomThemejs">trunk/tests/qunit/editor/tinymce/EditorCustomTheme.js</a></li>
<li><a href="#trunktestsquniteditortinymceFocusManagerjs">trunk/tests/qunit/editor/tinymce/FocusManager.js</a></li>
<li><a href="#trunktestsquniteditortinymceInsertContentForcedRootFalsejs">trunk/tests/qunit/editor/tinymce/InsertContentForcedRootFalse.js</a></li>
<li><a href="#trunktestsquniteditortinymceNotificationManagerjs">trunk/tests/qunit/editor/tinymce/NotificationManager.js</a></li>
<li>trunk/tests/qunit/editor/tinymce/content/</li>
<li><a href="#trunktestsquniteditortinymcecontentLinkTargetsjs">trunk/tests/qunit/editor/tinymce/content/LinkTargets.js</a></li>
<li><a href="#trunktestsquniteditortinymcefmtFontInfojs">trunk/tests/qunit/editor/tinymce/fmt/FontInfo.js</a></li>
<li><a href="#trunktestsquniteditortinymcefmtPreviewjs">trunk/tests/qunit/editor/tinymce/fmt/Preview.js</a></li>
<li><a href="#trunktestsquniteditortinymceoptionsjs">trunk/tests/qunit/editor/tinymce/options.js</a></li>
<li><a href="#trunktestsquniteditortinymceuiFilePickerjs">trunk/tests/qunit/editor/tinymce/ui/FilePicker.js</a></li>
<li>trunk/tests/qunit/editor/tinymce/undo/</li>
<li><a href="#trunktestsquniteditortinymceundoDiffjs">trunk/tests/qunit/editor/tinymce/undo/Diff.js</a></li>
<li><a href="#trunktestsquniteditortinymceundoForcedRootBlockjs">trunk/tests/qunit/editor/tinymce/undo/ForcedRootBlock.js</a></li>
<li><a href="#trunktestsquniteditortinymceundoFragmentsjs">trunk/tests/qunit/editor/tinymce/undo/Fragments.js</a></li>
<li><a href="#trunktestsquniteditortinymceundoLevelsjs">trunk/tests/qunit/editor/tinymce/undo/Levels.js</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li>trunk/tests/qunit/editor/plugins/</li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunktestsquniteditorindexhtml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/index.html</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/index.html       2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/index.html 2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40,6 +40,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/caret/LineUtils.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/caret/LineWalker.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <!-- tinymce.content.* -->
+       <script src="tinymce/content/LinkTargets.js"></script>
+
</ins><span class="cx" style="display: block; padding: 0 10px">         <!-- tinymce.geom.* -->
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/geom/Rect.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/geom/ClientRect.js"></script>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51,6 +54,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <!-- tinymce.fmt.* -->
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/fmt/Hooks.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="tinymce/fmt/Preview.js"></script>
+       <script src="tinymce/fmt/FontInfo.js"></script>
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <!-- tinymce.text.* -->
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/text/ExtendingChar.js"></script>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -86,6 +91,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/Collection.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/ColorButton.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/Control.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<!--<script src="tinymce/ui/FilePicker.js"></script>-->
</ins><span class="cx" style="display: block; padding: 0 10px">         <script src="tinymce/ui/FitLayout.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/FlexLayout.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/GridLayout.js"></script>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -97,6 +103,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/TextBox.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/ui/Window.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <!-- 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>
+
</ins><span class="cx" style="display: block; padding: 0 10px">         <!-- tinymce.util.* -->
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/util/Color.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/util/EventDispatcher.js"></script>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -115,12 +127,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <!-- tinymce.* -->
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/AddOnManager.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="tinymce/options.js"></script>
</ins><span class="cx" style="display: block; padding: 0 10px">         <script src="tinymce/Editor.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/Editor_rtl.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="tinymce/EditorCustomTheme.js"></script>
</ins><span class="cx" style="display: block; padding: 0 10px">         <script src="tinymce/EditorUpload.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/EditorCommands.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/EditorManager.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/EnterKey.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="tinymce/FocusManager.js"></script>
</ins><span class="cx" style="display: block; padding: 0 10px">         <script src="tinymce/ForceBlocks.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/Formatter_apply.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/Formatter_check.js"></script>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -130,29 +145,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/SelectionOverrides.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/WindowManager.js"></script>
</span><span class="cx" style="display: block; padding: 0 10px">        <script src="tinymce/InsertContent.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="tinymce/InsertContentForcedRootFalse.js"></script>
</ins><span class="cx" style="display: block; padding: 0 10px">         <script src="tinymce/InsertList.js"></script>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <script src="tinymce/NotificationManager.js"></script>
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <!-- tinymce.plugins.* -->
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<!--<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>-->
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> </body>
</span><span class="cx" style="display: block; padding: 0 10px"> </html>
</span></span></pre></div>
<a id="trunktestsquniteditorjsinitjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/js/init.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/js/init.js       2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/js/init.js 2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4,7 +4,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        QUnit.config.reorder = false;
</span><span class="cx" style="display: block; padding: 0 10px">        QUnit.config.hidepassed = true;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        window.editor = window.inlineEditor = null; 
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ window.editor = window.inlineEditor = null;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        var oldModule = module;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -23,12 +23,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // Sauce labs
</span><span class="cx" style="display: block; padding: 0 10px">        QUnit.testStart(function(testDetails) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                QUnit.log = function(details) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         QUnit.log(function(details) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         if (!details.result) {
</span><span class="cx" style="display: block; padding: 0 10px">                                details.name = currentModule + ':' + testDetails.name;
</span><span class="cx" style="display: block; padding: 0 10px">                                log.push(details);
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         });
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        QUnit.done(function(results) {
</span></span></pre></div>
<a id="trunktestsquniteditorjsqunitqunitjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/js/qunit/qunit.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/js/qunit/qunit.js        2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/js/qunit/qunit.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -571,6 +571,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        config.autorun = true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+if (document.location.search.indexOf('bedrock') !== -1) {
+       config.autorun = false;
+       config.autostart = false;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> QUnit.load = function() {
</span><span class="cx" style="display: block; padding: 0 10px">        runLoggingCallbacks( "begin", QUnit, {} );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsquniteditorjstinymce_loaderjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/js/tinymce_loader.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/js/tinymce_loader.js     2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/js/tinymce_loader.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4,4 +4,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> var wpPlugins = 'charmap colorpicker hr lists media paste tabfocus textcolor ' +
</span><span class="cx" style="display: block; padding: 0 10px">                        'fullscreen wordpress wpautoresize wpeditimage wpgallery wplink wpdialogs wpview';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+var $ = window.jQuery;
+
</ins><span class="cx" style="display: block; padding: 0 10px"> getUserSetting = setUserSetting = function() {}
</span></span></pre></div>
<a id="trunktestsquniteditortinymceEditorjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/Editor.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/Editor.js        2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/Editor.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -492,7 +492,36 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.translate('input i18n'), 'output i18n');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+test('Treat some paragraphs as empty contents', function() {
+       editor.setContent('<p><br /></p>');
+       equal(editor.getContent(), '');
+
+       editor.setContent('<p>\u00a0</p>');
+       equal(editor.getContent(), '');
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('kamer word bounderies', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        editor.setContent('<p>!\u200b!\u200b!</p>');
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), '<p>!\u200b!\u200b!</p>');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-});
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+});
+
+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>');
+});
</ins></span></pre></div>
<a id="trunktestsquniteditortinymceEditorCommandsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/EditorCommands.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/EditorCommands.js        2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/EditorCommands.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -750,6 +750,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), '<p>test 123</p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('subscript/superscript', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        expect(4);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -803,6 +810,33 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), '<p>test 123</p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('RemoveFormat', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        expect(4);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -827,6 +861,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), '<p>dfn tag code tag samp tag kbd tag var tag cite tag mark tag q tag</p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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);
+       });
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('InsertLineBreak', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        editor.setContent('<p>123</p>');
</span><span class="cx" style="display: block; padding: 0 10px">        Utils.setSelection('p', 2);
</span></span></pre></div>
<a id="trunktestsquniteditortinymceEditorCustomThemejs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/EditorCustomTheme.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/EditorCustomTheme.js                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/EditorCustomTheme.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,43 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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');
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/EditorCustomTheme.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceEditorManagerjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/EditorManager.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/EditorManager.js 2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/EditorManager.js   2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -98,12 +98,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> asyncTest('Init editor async with proper editors state', function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var unloadTheme = function(name) {
-               var url = tinymce.baseURI.toAbsolute('themes/' + name + '/theme.js');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ var unloadUrl = function (url) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 tinymce.dom.ScriptLoader.ScriptLoader.remove(url);
</span><span class="cx" style="display: block; padding: 0 10px">                tinymce.ThemeManager.remove(name);
</span><span class="cx" style="display: block; padding: 0 10px">        };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var unloadTheme = function(name) {
+               unloadUrl(tinymce.baseURI.toAbsolute('themes/' + name + '/theme.min.js'));
+               unloadUrl(tinymce.baseURI.toAbsolute('themes/' + name + '/theme.js'));
+       };
+
</ins><span class="cx" style="display: block; padding: 0 10px">         tinymce.remove();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        var init = function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -141,6 +145,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                external_plugins: {
</span><span class="cx" style="display: block; padding: 0 10px">                        "plugina": "//domain/plugina.js",
</span><span class="cx" style="display: block; padding: 0 10px">                        "pluginb": "//domain/pluginb.js"
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                },
+               plugin_base_urls: {
+                       testplugin: 'http://custom.ephox.com/dir/testplugin'
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -148,11 +155,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">        strictEqual(tinymce.baseURL, "http://www.tinymce.com/base");
</span><span class="cx" style="display: block; padding: 0 10px">        strictEqual(tinymce.suffix, "x");
</span><span class="cx" style="display: block; padding: 0 10px">        strictEqual(new tinymce.Editor('ed1', {}, tinymce).settings.test, 42);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        strictEqual(tinymce.PluginManager.urls.testplugin, 'http://custom.ephox.com/dir/testplugin');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        deepEqual(new tinymce.Editor('ed2', {
</span><span class="cx" style="display: block; padding: 0 10px">                external_plugins: {
</span><span class="cx" style="display: block; padding: 0 10px">                        "plugina": "//domain/plugina2.js",
</span><span class="cx" style="display: block; padding: 0 10px">                        "pluginc": "//domain/pluginc.js"
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                },
+               plugin_base_urls: {
+                       testplugin: 'http://custom.ephox.com/dir/testplugin'
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        }, tinymce).settings.external_plugins, {
</span><span class="cx" style="display: block; padding: 0 10px">                "plugina": "//domain/plugina2.js",
</span></span></pre></div>
<a id="trunktestsquniteditortinymceEditorUploadjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/EditorUpload.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/EditorUpload.js  2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/EditorUpload.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -235,7 +235,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        if (callCount == 2) {
</span><span class="cx" style="display: block; padding: 0 10px">                                QUnit.start();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                equal(uploadCount, 1, 'Should only be one upload.');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // 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.');
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        equal(result[0].element, editor.$('img')[0]);
</span></span></pre></div>
<a id="trunktestsquniteditortinymceEnterKeyjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/EnterKey.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/EnterKey.js      2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/EnterKey.js        2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1098,3 +1098,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">                notEqual(rng.startContainer.data, ' ');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+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');
+       });
+}
+
</ins></span></pre></div>
<a id="trunktestsquniteditortinymceFocusManagerjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/FocusManager.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/FocusManager.js                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/FocusManager.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,46 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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;
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/FocusManager.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceFormatter_applyjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/Formatter_apply.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/Formatter_apply.js       2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/Formatter_apply.js 2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,6 +1,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> module("tinymce.Formatter - Apply", {
</span><span class="cx" style="display: block; padding: 0 10px">        setupModule: function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea><div id="elm2"></div>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea><div id="elm2"></div><textarea id="elm3"></textarea>';
</ins><span class="cx" style="display: block; padding: 0 10px">                 QUnit.stop();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                tinymce.init({
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18,34 +18,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                '*': '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'
</span><span class="cx" style="display: block; padding: 0 10px">                        },
</span><span class="cx" style="display: block; padding: 0 10px">                        init_instance_callback: function(ed) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                QUnit.start();
</ins><span class="cx" style="display: block; padding: 0 10px">                                 window.editor = ed;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-                               if (inlineEditor) {
-                                       QUnit.start();
-                               }
</del><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-               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();
-                               }
-                       }
-               });
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1291,6 +1267,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), '<p><b>abc</b></p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('Caret format inside first block word', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        editor.setContent('<p>abc 123</p>');
</span><span class="cx" style="display: block; padding: 0 10px">        editor.formatter.register('format', {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1679,39 +1665,51 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), '<p><span style="font-weight: bold;">abc</span></p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-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'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        inlineEditor.formatter.apply('format');
-       equal(inlineEditor.getContent(), '<div>a</div><p>b</p>');
</del><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> asyncTest('Bug #7412 - valid_styles affects the Bold and Italic buttons, although it shouldn\'t', function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    tinymce.remove();
-
-    document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea>';
-
</del><span class="cx" style="display: block; padding: 0 10px">     tinymce.init({
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        selector: "#elm1",
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        selector: "#elm3",
</ins><span class="cx" style="display: block; padding: 0 10px">         add_unload_trigger: false,
</span><span class="cx" style="display: block; padding: 0 10px">         valid_styles: {
</span><span class="cx" style="display: block; padding: 0 10px">             span: 'color,background-color,font-size,text-decoration,padding-left'
</span><span class="cx" style="display: block; padding: 0 10px">         },
</span><span class="cx" style="display: block; padding: 0 10px">         init_instance_callback: function(ed) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            window.editor = ed;
</del><span class="cx" style="display: block; padding: 0 10px">             QUnit.start();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            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>');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            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>');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1721,12 +1719,77 @@
</span><span class="cx" style="display: block; padding: 0 10px">        editor.focus();
</span><span class="cx" style="display: block; padding: 0 10px">        Utils.setSelection('#a', 0, '#b', 0);
</span><span class="cx" style="display: block; padding: 0 10px">        editor.execCommand('formatBlock', false, 'h1');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        equal(getContent(), '<h1 id="a">one</h1>\n<div id="b">two</div>');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ equal(getContent(), '<h1 id="a">one</h1><div id="b">two</div>');
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> test('Format selection over fragments', function(){
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        editor.setContent("<strong>a</strong>bc<em>d</em>");
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ editor.setContent("<p><strong>a</strong>bc<em>d</em></p>");
</ins><span class="cx" style="display: block; padding: 0 10px">         Utils.setSelection('strong', 1, 'em', 0);
</span><span class="cx" style="display: block; padding: 0 10px">        editor.formatter.apply('underline');
</span><span class="cx" style="display: block; padding: 0 10px">        equal(getContent(), '<p><strong>a</strong><span style="text-decoration: underline;">bc</span><em>d</em></p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+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>');
+});
</ins></span></pre></div>
<a id="trunktestsquniteditortinymceFormatter_checkjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/Formatter_check.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/Formatter_check.js       2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/Formatter_check.js 2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -228,8 +228,3 @@
</span><span class="cx" style="display: block; padding: 0 10px">        inlineEditor.execCommand('SelectAll');
</span><span class="cx" style="display: block; padding: 0 10px">        ok(!inlineEditor.formatter.match('div'), 'Formatter.match on div says true');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-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');
-});
</del></span></pre></div>
<a id="trunktestsquniteditortinymceInsertContentForcedRootFalsejs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/InsertContentForcedRootFalse.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/InsertContentForcedRootFalse.js                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/InsertContentForcedRootFalse.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,47 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/InsertContentForcedRootFalse.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceNotificationManagerjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/NotificationManager.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/NotificationManager.js                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/NotificationManager.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,109 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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.');
+               }
+       });
+
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/NotificationManager.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceSelectionOverridesjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/SelectionOverrides.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/SelectionOverrides.js    2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/SelectionOverrides.js      2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47,7 +47,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function assertCaretInCaretBlockContainer() {
</span><span class="cx" style="display: block; padding: 0 10px">                var beforeRng = editor.selection.getRng();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                equal(CaretContainer.isCaretContainerBlock(beforeRng.startContainer.parentNode), true, 'Not in caret block container.');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         equal(CaretContainer.isCaretContainerBlock(beforeRng.startContainer), true, 'Not in caret block container.');
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        var leftArrow = pressKey(VK.LEFT);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -224,7 +224,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                equal(editor.getContent(), '<p contenteditable="false">1</p><p contenteditable="false">2</p>');
</span><span class="cx" style="display: block; padding: 0 10px">                assertCaretInCaretBlockContainer();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                equal(rng.startContainer.parentNode.previousSibling, editor.dom.select('p')[0]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         equal(rng.startContainer.previousSibling, editor.dom.select('p')[0]);
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        test('delete from after cE=false block to text', function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -263,7 +263,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                equal(editor.getContent(), '<p contenteditable="false">1</p><p contenteditable="false">2</p>');
</span><span class="cx" style="display: block; padding: 0 10px">                assertCaretInCaretBlockContainer();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                equal(rng.startContainer.parentNode.nextSibling, editor.dom.select('p')[2]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         equal(rng.startContainer.nextSibling, editor.dom.select('p')[2]);
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        test('delete from block to before cE=false inline', function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -328,4 +328,30 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Since we can't do a real click we need to check if it gets sucked in towards the cE=false block
</span><span class="cx" style="display: block; padding: 0 10px">                equal(editor.selection.getNode().nodeName !== 'P', true);
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       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');
+               }
+       });
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span></span></pre></div>
<a id="trunktestsquniteditortinymceUndoManagerjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/UndoManager.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/UndoManager.js   2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/UndoManager.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -96,7 +96,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        editor.dom.fire(editor.getBody(), 'keydown', {keyCode: 65});
</span><span class="cx" style="display: block; padding: 0 10px">        ok(editor.undoManager.typing);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        editor.dom.fire(editor.getBody(), 'keyup', {keyCode: 13});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ editor.dom.fire(editor.getBody(), 'keydown', {keyCode: 13});
</ins><span class="cx" style="display: block; padding: 0 10px">         ok(!editor.undoManager.typing);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        selectAllFlags = {keyCode: 65, ctrlKey: false, altKey: false, shiftKey: false};
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -451,3 +451,41 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(editor.getContent(), "<p>aB</p>");
</span><span class="cx" style="display: block; padding: 0 10px">        ok(editor.isDirty(), "Dirty state should be true");
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+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>');
+});
</ins></span></pre></div>
<a id="trunktestsquniteditortinymcecaretCaretContainerjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/caret/CaretContainer.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/caret/CaretContainer.js  2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/caret/CaretContainer.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -118,4 +118,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">                setViewHtml('abc' + Zwsp.ZWSP);
</span><span class="cx" style="display: block; padding: 0 10px">                equal(CaretContainer.endsWithCaretContainer(getRoot().firstChild), true);
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       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>');
+       });
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span></span></pre></div>
<a id="trunktestsquniteditortinymcecaretFakeCaretjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/caret/FakeCaret.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/caret/FakeCaret.js       2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/caret/FakeCaret.js 2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -34,7 +34,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                equal($fakeCaretElm[0].nodeName, 'P');
</span><span class="cx" style="display: block; padding: 0 10px">                equal($fakeCaretElm.attr('data-mce-caret'), 'before');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                Utils.assertRange(rng, Utils.createRange($fakeCaretElm[0].firstChild, 0, $fakeCaretElm[0].firstChild, 1));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         Utils.assertRange(rng, Utils.createRange($fakeCaretElm[0], 0, $fakeCaretElm[0], 0));
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                fakeCaret.hide();
</span><span class="cx" style="display: block; padding: 0 10px">                equal($('#view *[data-mce-caret]').length, 0);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50,7 +50,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                equal($fakeCaretElm[1].nodeName, 'P');
</span><span class="cx" style="display: block; padding: 0 10px">                equal($fakeCaretElm.eq(1).attr('data-mce-caret'), 'after');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                Utils.assertRange(rng, Utils.createRange($fakeCaretElm[1].firstChild, 0, $fakeCaretElm[1].firstChild, 1));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         Utils.assertRange(rng, Utils.createRange($fakeCaretElm[1], 0, $fakeCaretElm[1], 0));
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                fakeCaret.hide();
</span><span class="cx" style="display: block; padding: 0 10px">                equal($('#view *[data-mce-caret]').length, 0);
</span></span></pre></div>
<a id="trunktestsquniteditortinymcecontentLinkTargetsjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/content/LinkTargets.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/content/LinkTargets.js                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/content/LinkTargets.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,104 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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');
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/content/LinkTargets.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomDOMUtilsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js  2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -35,7 +35,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        dom.serializeStyle(dom.parseStyle('border-width: 1pt 1pt 1pt 1pt; border-style: none none none none; border-color: black black black black;')),
</span><span class="cx" style="display: block; padding: 0 10px">                        'border: 1pt none black;'
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                 equal(
</span><span class="cx" style="display: block; padding: 0 10px">                        dom.serializeStyle(dom.parseStyle('border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;')),
</span><span class="cx" style="display: block; padding: 0 10px">                        'border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;'
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -339,15 +339,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.remove('test');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var eqNodeName = function(name) {
+               return function (n) {
+                       return n.nodeName === name;
+               };
+       };
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('getParent', 6, function() {
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.add(document.body, 'div', {id : 'test'});
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.get('test').innerHTML = '<div><span>ab<a id="test2" href="">abc</a>c</span></div>';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                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);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         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);
</ins><span class="cx" style="display: block; padding: 0 10px">                 equal(DOM.getParent('test2', 'SPAN').nodeName, 'SPAN');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getParent('test2', 'body', DOM.get('test')), null);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -360,7 +366,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.add(document.body, 'div', {id : 'test'});
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.get('test').innerHTML = '<div><span class="test">ab<span><a id="test2" href="">abc</a>c</span></span></div>';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                equal(DOM.getParents('test2', function(n) {return n.nodeName == 'SPAN';}).length, 2);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         equal(DOM.getParents('test2', eqNodeName('SPAN')).length, 2);
</ins><span class="cx" style="display: block; padding: 0 10px">                 equal(DOM.getParents('test2', 'span').length, 2);
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getParents('test2', 'span.test').length, 1);
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getParents('test2', 'body', DOM.get('test')).length, 0);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -433,7 +439,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getNext(DOM.get('test').firstChild, 'em').nodeName, 'EM');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getNext(DOM.get('test').firstChild, 'div'), null);
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getNext(null, 'div'), null);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                equal(DOM.getNext(DOM.get('test').firstChild, function(n) {return n.nodeName == 'EM';}).nodeName, 'EM');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         equal(DOM.getNext(DOM.get('test').firstChild, eqNodeName('EM')).nodeName, 'EM');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.remove('test');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -446,7 +452,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getPrev(DOM.get('test').lastChild, 'strong').nodeName, 'STRONG');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getPrev(DOM.get('test').lastChild, 'div'), null);
</span><span class="cx" style="display: block; padding: 0 10px">                equal(DOM.getPrev(null, 'div'), null);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                equal(DOM.getPrev(DOM.get('test').lastChild, function(n) {return n.nodeName == 'STRONG';}).nodeName, 'STRONG');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         equal(DOM.getPrev(DOM.get('test').lastChild, eqNodeName('STRONG')).nodeName, 'STRONG');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.remove('test');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -581,7 +587,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.remove('test');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        test('isEmpty', 14, function() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ test('isEmpty', function() {
</ins><span class="cx" style="display: block; padding: 0 10px">                 DOM.schema = new tinymce.html.Schema(); // A schema will be added when used within a editor instance
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.add(document.body, 'div', {id : 'test'}, '');
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -626,6 +632,30 @@
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.setHTML('test', '<div><!-- comment --></div>');
</span><span class="cx" style="display: block; padding: 0 10px">                ok(!DOM.isEmpty(DOM.get('test')), 'Element with comment.');
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                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.');
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 DOM.remove('test');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -634,6 +664,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(false, DOM.isEmpty(elm, {img: true}));
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        test('isEmpty on pre', function() {
+               var elm = DOM.create('pre', null, '  ');
+               equal(false, DOM.isEmpty(elm));
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('isEmpty with list of elements considered non-empty without schema', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var domWithoutSchema = new tinymce.dom.DOMUtils(document, {keep_values: true});
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -645,7 +680,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                var elm = DOM.create('p', null, '<em><br></em>');
</span><span class="cx" style="display: block; padding: 0 10px">                ok(DOM.isEmpty(elm, 'No children'));
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('isEmpty on P with two BR in EM', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var elm = DOM.create('p', null, '<em><br><br></em>');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(false, DOM.isEmpty(elm));
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -654,13 +689,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">        test('bind/unbind/fire', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var count = 0;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                DOM.bind(document, 'click', function() {count++;});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         DOM.bind(document, 'click', function() {
+                       count++;
+               });
</ins><span class="cx" style="display: block; padding: 0 10px">                 DOM.fire(document, 'click');
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.unbind(document, 'click');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(count, 1);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                count = 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                DOM.bind([document, window], 'click', function(e) {e.stopPropagation(); count++;});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         DOM.bind([document, window], 'click', function(e) {
+                       e.stopPropagation();
+                       count++;
+               });
</ins><span class="cx" style="display: block; padding: 0 10px">                 DOM.fire(document, 'click');
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.fire(window, 'click');
</span><span class="cx" style="display: block; padding: 0 10px">                DOM.unbind([document, window], 'click');
</span></span></pre></div>
<a id="trunktestsquniteditortinymcedomSelectionjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/dom/Selection.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/dom/Selection.js 2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/dom/Selection.js   2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,7 +1,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> ModuleLoader.require([
</span><span class="cx" style="display: block; padding: 0 10px">        "tinymce/caret/CaretContainer",
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        "tinymce/text/Zwsp",
</ins><span class="cx" style="display: block; padding: 0 10px">         "tinymce/Env"
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-], function(CaretContainer, Env) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+], function(CaretContainer, Zwsp, Env) {
</ins><span class="cx" style="display: block; padding: 0 10px">         module("tinymce.dom.Selection", {
</span><span class="cx" style="display: block; padding: 0 10px">                setupModule: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        QUnit.stop();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -503,8 +504,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                editor.setContent('<p contentEditable="false">1</p>');
</span><span class="cx" style="display: block; padding: 0 10px">                CaretContainer.insertBlock('p', editor.$('p')[0], true);
</span><span class="cx" style="display: block; padding: 0 10px">                rng = editor.dom.createRng();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                rng.setStart(editor.$('p')[0].firstChild, 0);
-               rng.setEnd(editor.$('p')[0].firstChild, 1);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         rng.setStart(editor.$('p')[0], 0);
+               rng.setEnd(editor.$('p')[0], 0);
</ins><span class="cx" style="display: block; padding: 0 10px">                 editor.selection.setRng(rng);
</span><span class="cx" style="display: block; padding: 0 10px">                bookmark = editor.selection.getBookmark(2);
</span><span class="cx" style="display: block; padding: 0 10px">                editor.setContent('<p contentEditable="false">1</p>');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -846,6 +847,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        equal(rng.startOffset, 0);
</span><span class="cx" style="display: block; padding: 0 10px">                });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                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);
+               });
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 test('normalize don\'t lean left into empty inline elements if there is a br element after caret', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var rng;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1055,5 +1071,71 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(rng.endContainer.nodeName, '#text');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(rng.endOffset, 1);
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       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);
+       });
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsquniteditortinymcedomSerializerjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/dom/Serializer.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/dom/Serializer.js        2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/dom/Serializer.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25,7 +25,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        ser.setRules('a[href|target<_blank?_top|title:forced value]');
</span><span class="cx" style="display: block; padding: 0 10px">        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>');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        equal(ser.serialize(DOM.get('test')), '<a href="file.htm" target="_blank" title="forced value">link</a><a href="#" title="forced value">test2</a>');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 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>');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        ser.setRules('img[src|border=0|alt=]');
</span><span class="cx" style="display: block; padding: 0 10px">        DOM.setHTML('test', '<img src="tinymce/ui/img/raster.gif" data-mce-src="tinymce/ui/img/raster.gif" border="0" alt="" />');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -234,6 +234,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(ser.serialize(DOM.get('test')), '<p>test</p><p>&nbsp;</p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('Remove empty elements', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        var ser = new tinymce.dom.Serializer({fix_list_elements : true});
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -346,6 +357,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s' + 'cript>// <![CDATA[\n1 < 2;\n// ]]></s' + 'cript>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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>');
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('Script with src attr', 1, function() {
</span><span class="cx" style="display: block; padding: 0 10px">        var ser = new tinymce.dom.Serializer({fix_list_elements : true});
</span><span class="cx" style="display: block; padding: 0 10px">        ser.setRules('script[type|language|src]');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -524,3 +543,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(ser.serialize(DOM.get('test'), {getInner: 1}), '<p data-z="3">a</p>');
</span><span class="cx" style="display: block; padding: 0 10px">        equal(ser.trimHtml('<p data-x="1" data-y="2" data-z="3">a</p>'), '<p data-z="3">a</p>');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+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>');
+});
</ins></span></pre></div>
<a id="trunktestsquniteditortinymcefileImageScannerjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/file/ImageScanner.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/file/ImageScanner.js     2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/file/ImageScanner.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2,21 +2,31 @@
</span><span class="cx" style="display: block; padding: 0 10px">        "tinymce/file/ImageScanner",
</span><span class="cx" style="display: block; padding: 0 10px">        "tinymce/file/UploadStatus",
</span><span class="cx" style="display: block; padding: 0 10px">        "tinymce/file/BlobCache",
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        "tinymce/file/Conversions",
</ins><span class="cx" style="display: block; padding: 0 10px">         "tinymce/Env"
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-], function(ImageScanner, UploadStatus, BlobCache, Env) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+], function(ImageScanner, UploadStatus, BlobCache, Conversions, Env) {
</ins><span class="cx" style="display: block; padding: 0 10px">         if (!tinymce.Env.fileApi) {
</span><span class="cx" style="display: block; padding: 0 10px">                return;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        QUnit.config.autostart = false;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         module("tinymce.file.ImageScanner");
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        var base64Src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var blobUriSrc;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        Conversions.uriToBlob(base64Src).then(function(blob) {
+               blobUriSrc = URL.createObjectURL(blob);
+               QUnit.start();
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         QUnit.asyncTest("findAll", function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var imageScanner = new ImageScanner(new UploadStatus(), new BlobCache());
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                document.getElementById('view').innerHTML = (
</span><span class="cx" style="display: block; padding: 0 10px">                        '<img src="' + base64Src + '">' +
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        '<img src="' + blobUriSrc + '">' +
</ins><span class="cx" style="display: block; padding: 0 10px">                         '<img src="' + Env.transparentSrc + '">' +
</span><span class="cx" style="display: block; padding: 0 10px">                        '<img src="' + base64Src + '" data-mce-bogus="1">' +
</span><span class="cx" style="display: block; padding: 0 10px">                        '<img src="' + base64Src + '" data-mce-placeholder="1">'
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -24,8 +34,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                imageScanner.findAll(document.getElementById('view')).then(function(result) {
</span><span class="cx" style="display: block; padding: 0 10px">                        QUnit.start();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        equal(result.length, 1);
-                       equal('data:image/gif;base64,' + result[0].blobInfo.base64(), base64Src);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 var blobInfo = result[0].blobInfo;
+                       equal(result.length, 2);
+                       equal('data:image/gif;base64,' + blobInfo.base64(), base64Src);
</ins><span class="cx" style="display: block; padding: 0 10px">                         strictEqual(result[0].image, document.getElementById('view').firstChild);
</span><span class="cx" style="display: block; padding: 0 10px">                });
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span></span></pre></div>
<a id="trunktestsquniteditortinymcefmtFontInfojs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/fmt/FontInfo.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/fmt/FontInfo.js                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/fmt/FontInfo.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,75 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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();
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/fmt/FontInfo.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcefmtPreviewjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/fmt/Preview.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/fmt/Preview.js                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/fmt/Preview.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,247 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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');
+
+    });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/fmt/Preview.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlDomParserjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/html/DomParser.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/html/DomParser.js        2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/html/DomParser.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -99,6 +99,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                deepEqual(countNodes(root), {body:1, pre:1, '#text':1}, 'Whitespace around and inside PRE (count)');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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)');
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('Whitespace preserved in SPAN inside PRE', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                parser = new tinymce.html.DomParser({}, schema);
</span><span class="cx" style="display: block; padding: 0 10px">                root = parser.parse('  \t\r\n  <PRE>  \t\r\n  <span>    test    </span> \t\r\n   </PRE>   \t\r\n  ');
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -106,6 +113,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">                deepEqual(countNodes(root), {body:1, pre:1, span:1, '#text':3}, 'Whitespace around and inside PRE (count)');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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)');
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('Parse invalid contents', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var parser, root;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -422,6 +443,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'Mixed text nodes, inline elements and blocks.');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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>');
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('Parse contents with html4 anchors and allow_html_in_named_anchor: false', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var parser, root, schema = new tinymce.html.Schema();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -510,6 +539,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(serializer.serialize(root), '');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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>');
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('Preserve space in inline span', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                var parser, root, schema = new tinymce.html.Schema();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsquniteditortinymcehtmlNodejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/html/Node.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/html/Node.js     2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/html/Node.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -139,7 +139,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        ok(root.lastChild === node3, 'root.lastChild');
</span><span class="cx" style="display: block; padding: 0 10px">        ok(node.next === node3, 'node.next');
</span><span class="cx" style="display: block; padding: 0 10px">        equal(node.prev, undefined, 'node.prev');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        ok(node3.prev, node, 'node3.prev');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ equal(node3.prev, node, 'node3.prev');
</ins><span class="cx" style="display: block; padding: 0 10px">         equal(node3.next, undefined, 'node3.next');
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunktestsquniteditortinymcehtmlSaxParserjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/html/SaxParser.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/html/SaxParser.js        2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/html/SaxParser.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -604,6 +604,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                writer.reset();
</span><span class="cx" style="display: block; padding: 0 10px">                parser.parse('<!--[if !IE]>alert(1)<![endif]-->');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(writer.getContent(), '<!-- [if !IE]>alert(1)<![endif]-->');
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               writer.reset();
+               parser.parse('<!--[iF !IE]>alert(1)<![endif]-->');
+               equal(writer.getContent(), '<!-- [iF !IE]>alert(1)<![endif]-->');
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        test('Parse script urls (allowed)', function() {
</span></span></pre></div>
<a id="trunktestsquniteditortinymcehtmlSchemajs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/html/Schema.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/html/Schema.js   2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/html/Schema.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13,27 +13,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">        expect(17);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: '*[id|class]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: 'b*[id|class]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('body').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px">        equal(schema.getElementRule('img'), undefined);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: 'b?[id|class]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('bx').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px">        equal(schema.getElementRule('body'), undefined);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: 'b+[id|class]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('body').attributesOrder, ["id", "class"]);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('bx').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px">        equal(schema.getElementRule('b'), undefined);
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44,19 +44,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">        expect(13);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: 'b[id|class|*]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px">        ok(schema.getElementRule('b').attributePatterns[0].pattern.test('x'));
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: 'b[id|class|x?]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px">        ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xy'));
</span><span class="cx" style="display: block; padding: 0 10px">        ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('xba'));
</span><span class="cx" style="display: block; padding: 0 10px">        ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('a'));
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema({valid_elements: 'b[id|class|x+]'});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {}});
</ins><span class="cx" style="display: block; padding: 0 10px">         deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
</span><span class="cx" style="display: block; padding: 0 10px">        ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('x'));
</span><span class="cx" style="display: block; padding: 0 10px">        ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xb'));
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -119,6 +119,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">        deepEqual(schema.getElementRule('span'), {"attributes": {"dir": {"validValues": {"rtl": {}, "ltr": {}}}}, "attributesOrder": ["dir"]});
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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);
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('Remove empty elements', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        var schema;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -220,11 +229,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                "EMBED": {}, "PARAM": {}, "META": {}, "LINK": {}, "ISINDEX": {},
</span><span class="cx" style="display: block; padding: 0 10px">                "INPUT": {}, "IMG": {}, "HR": {}, "FRAME": {}, "COL": {}, "BR": {},
</span><span class="cx" style="display: block; padding: 0 10px">                "BASEFONT": {}, "BASE": {}, "AREA": {}, "SOURCE" : {},
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "TD": {}, "TH": {}, "IFRAME": {}, "VIDEO": {}, "AUDIO": {}, "OBJECT": {}, "WBR": {}, "TRACK" : {}, "SCRIPT" : {},
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "TD": {}, "TH": {}, "IFRAME": {}, "VIDEO": {}, "AUDIO": {}, "OBJECT": {}, "WBR": {}, "TRACK" : {}, "SCRIPT" : {}, "PRE": {}, "CODE": {},
</ins><span class="cx" style="display: block; padding: 0 10px">                 "embed": {}, "param": {}, "meta": {}, "link": {}, "isindex": {},
</span><span class="cx" style="display: block; padding: 0 10px">                "input": {}, "img": {}, "hr": {}, "frame": {}, "col": {}, "br": {},
</span><span class="cx" style="display: block; padding: 0 10px">                "basefont": {}, "base": {}, "area": {}, "source" : {},
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "td": {}, "th": {}, "iframe": {}, "video": {}, "audio": {}, "object": {}, "wbr" : {}, "track" : {},  "script" : {}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "td": {}, "th": {}, "iframe": {}, "video": {}, "audio": {}, "object": {}, "wbr" : {}, "track" : {}, "script" : {}, "pre": {}, "code": {}
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -235,9 +244,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        schema = new tinymce.html.Schema();
</span><span class="cx" style="display: block; padding: 0 10px">        deepEqual(schema.getWhiteSpaceElements(), {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "IFRAME": {}, "NOSCRIPT": {}, "OBJECT": {}, "PRE": {},
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "IFRAME": {}, "NOSCRIPT": {}, "OBJECT": {}, "PRE": {}, "CODE": {},
</ins><span class="cx" style="display: block; padding: 0 10px">                 "SCRIPT": {}, "STYLE": {}, "TEXTAREA": {}, "VIDEO": {}, "AUDIO": {},
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "iframe": {}, "noscript": {}, "object": {}, "pre": {},
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "iframe": {}, "noscript": {}, "object": {}, "pre": {}, "code": {},
</ins><span class="cx" style="display: block; padding: 0 10px">                 "script": {}, "style": {}, "textarea": {}, "video": {}, "audio": {}
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span></span></pre></div>
<a id="trunktestsquniteditortinymcehtmlStylesjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/html/Styles.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/html/Styles.js   2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/html/Styles.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3,7 +3,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> test('Basic parsing/serializing', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        var styles = new tinymce.html.Styles();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        expect(11);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ expect(12);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('FONT-SIZE:10px')), "font-size: 10px;");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('FONT-SIZE:10px;COLOR:red')), "font-size: 10px; color: red;");
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -16,6 +16,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('value: "&amp;"')), "value: '&amp;';");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('value: "&"')), "value: '&';");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('value: ')), "");
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        equal(styles.serialize(styles.parse("background: url('http://www.site.com/(foo)');")), "background: url('http://www.site.com/(foo)');");
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> test('Colors force hex and lowercase', function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -61,7 +62,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                styles.serialize(styles.parse('border-width: 1pt 1pt 1pt 1pt; border-style: none none none none; border-color: black black black black;')),
</span><span class="cx" style="display: block; padding: 0 10px">                'border: 1pt none black;'
</span><span class="cx" style="display: block; padding: 0 10px">        );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">         equal(
</span><span class="cx" style="display: block; padding: 0 10px">                styles.serialize(styles.parse('border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;')),
</span><span class="cx" style="display: block; padding: 0 10px">                'border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;'
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -137,10 +138,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px; margin-right: 10px;'), 'a'), "margin-right: 10px;");
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 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\'')), "");
+});
+
</ins><span class="cx" style="display: block; padding: 0 10px"> test('Script urls denied', function() {
</span><span class="cx" style="display: block; padding: 0 10px">        var styles = new tinymce.html.Styles();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('behavior:url(test.htc)')), "");
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        equal(styles.serialize(styles.parse('b\\65havior:url(test.htc)')), "");
</ins><span class="cx" style="display: block; padding: 0 10px">         equal(styles.serialize(styles.parse('color:expression(alert(1))')), "");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('color:\\65xpression(alert(1))')), "");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('color:exp/**/ression(alert(1))')), "");
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -148,9 +158,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('color:  expression  (  alert(1))')), "");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('background:url(jAvaScript:alert(1)')), "");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('background:url(javascript:alert(1)')), "");
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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)')), "");
</ins><span class="cx" style="display: block; padding: 0 10px">         equal(styles.serialize(styles.parse('background:url(vbscript:alert(1)')), "");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('background:url(j\navas\u0000cr\tipt:alert(1)')), "");
</span><span class="cx" style="display: block; padding: 0 10px">        equal(styles.serialize(styles.parse('background:url(data:image/svg+xml,%3Csvg/%3E)')), "");
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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")')), "");
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> test('Script urls allowed', function() {
</span></span></pre></div>
<a id="trunktestsquniteditortinymceoptionsjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/options.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/options.js                               (rev 0)
+++ trunk/tests/qunit/editor/tinymce/options.js 2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,94 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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();
+            }
+        }
+    });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/options.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFilePickerjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/ui/FilePicker.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/ui/FilePicker.js                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FilePicker.js   2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,260 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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();
+               });
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FilePicker.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiWindowjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/ui/Window.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/ui/Window.js     2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/ui/Window.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36,17 +36,26 @@
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        test("title, no buttonbar, autoResize, title is widest", function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                var win = createWindow({
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         var win1 = createWindow({
</ins><span class="cx" style="display: block; padding: 0 10px">                         x: 100,
</span><span class="cx" style="display: block; padding: 0 10px">                        y: 120,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        title: "XXXXXXXXXXXXXXXXXXX",
+                       items: [
+                               {type: 'spacer', classes: 'red', flex: 1}
+                       ]
+               });
+
+               var win2 = createWindow({
+                       x: 100,
+                       y: 120,
</ins><span class="cx" style="display: block; padding: 0 10px">                         title: "XXXXXXXXXXXXXXXXXXXXXX",
</span><span class="cx" style="display: block; padding: 0 10px">                        items: [
</span><span class="cx" style="display: block; padding: 0 10px">                                {type: 'spacer', classes: 'red', flex: 1}
</span><span class="cx" style="display: block; padding: 0 10px">                        ]
</span><span class="cx" style="display: block; padding: 0 10px">                });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                Utils.nearlyEqualRects(Utils.size(win), [326, 61], 60);
-               Utils.nearlyEqualRects(Utils.size(win.find("spacer")[0]), [324, 20], 60);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         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');
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        test("buttonbar, autoResize, buttonbar is widest", function() {
</span></span></pre></div>
<a id="trunktestsquniteditortinymceundoDiffjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/undo/Diff.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/undo/Diff.js                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/undo/Diff.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,17 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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]]);
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/undo/Diff.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceundoForcedRootBlockjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/undo/ForcedRootBlock.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/undo/ForcedRootBlock.js                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/undo/ForcedRootBlock.js    2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,54 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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'
+               });
+       });
+
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/undo/ForcedRootBlock.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceundoFragmentsjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/undo/Fragments.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/undo/Fragments.js                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/undo/Fragments.js  2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,32 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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-->');
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/undo/Fragments.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceundoLevelsjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/qunit/editor/tinymce/undo/Levels.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/undo/Levels.js                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/undo/Levels.js     2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,142 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+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);
+       });
+});
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/qunit/editor/tinymce/undo/Levels.js
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilI18njs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/util/I18n.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/util/I18n.js     2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/util/I18n.js       2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5,20 +5,51 @@
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> test("Translate strings", function() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var undef;
+       var translate = tinymce.util.I18n.translate;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         tinymce.util.I18n.add("code", {
</span><span class="cx" style="display: block; padding: 0 10px">                "text": "text translation",
</span><span class="cx" style="display: block; padding: 0 10px">                "value:{0}{1}": "value translation:{0}{1}",
</span><span class="cx" style="display: block; padding: 0 10px">                "text{context:something}": "text translation with context",
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "value:{0}{1}{context:something}": "value translation:{0}{1} with context"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "value:{0}{1}{context:something}": "value translation:{0}{1} with context",
+               "empty string": ""
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        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");
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 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");
+
</ins><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> test("Switch language", function() {
</span></span></pre></div>
<a id="trunktestsquniteditortinymceutilQuirks_webkitjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.js    2017-04-09 23:00:47 UTC (rev 40398)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.js      2017-04-09 23:10:15 UTC (rev 40399)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -125,6 +125,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(editor.selection.getStart().nodeName, 'H1');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        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');
+       });
+
</ins><span class="cx" style="display: block; padding: 0 10px">         test('ForwardDelete from end of H1 to P with style span', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                editor.getBody().innerHTML = '<h1>a</h1><p><span style="color:red">b</span></p>';
</span><span class="cx" style="display: block; padding: 0 10px">                Utils.setSelection('h1', 1);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -334,6 +345,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                equal(Utils.cleanHtml(editor.getBody().innerHTML), '<p><br data-mce-bogus="1"></p>');
</span><span class="cx" style="display: block; padding: 0 10px">                equal(editor.selection.getStart(true).nodeName, 'P');
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       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');
+       });
</ins><span class="cx" style="display: block; padding: 0 10px"> } else {
</span><span class="cx" style="display: block; padding: 0 10px">        test("Skipped since the browser isn't WebKit", function() {
</span><span class="cx" style="display: block; padding: 0 10px">                ok(true, "Skipped");
</span></span></pre>
</div>
</div>

</body>
</html>