<!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>[27155] trunk: Incorporate the TinyMCE tests into our JS tests:</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">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/27155">27155</a></dd>
<dt>Author</dt> <dd>azaozz</dd>
<dt>Date</dt> <dd>2014-02-10 01:11:25 +0000 (Mon, 10 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Incorporate the TinyMCE tests into our JS tests:
- Modified the original tests so TinyMCE can be loaded from /src/wp-includes/js/tinymce.
- Added "WP" option to the UI to select only tests relevant to our integration (excludes most of the default plugins tests).
- Added tests for obsolete HTML elements and attributes (html4 back-compat).
See <a href="http://core.trac.wordpress.org/ticket/27014">#27014</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkGruntfilejs">trunk/Gruntfile.js</a></li>
<li><a href="#trunktestsqunitindexhtml">trunk/tests/qunit/index.html</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/tests/qunit/editor/</li>
<li>trunk/tests/qunit/editor/coverage/</li>
<li><a href="#trunktestsquniteditorcoverageindexhtml">trunk/tests/qunit/editor/coverage/index.html</a></li>
<li>trunk/tests/qunit/editor/coverage/js/</li>
<li><a href="#trunktestsquniteditorcoveragejsJSCovReporterjs">trunk/tests/qunit/editor/coverage/js/JSCovReporter.js</a></li>
<li><a href="#trunktestsquniteditorcoveragejsbackboneminjs">trunk/tests/qunit/editor/coverage/js/backbone-min.js</a></li>
<li><a href="#trunktestsquniteditorcoveragejsreportercss">trunk/tests/qunit/editor/coverage/js/reporter.css</a></li>
<li><a href="#trunktestsquniteditorcoveragejsreporterjs">trunk/tests/qunit/editor/coverage/js/reporter.js</a></li>
<li><a href="#trunktestsquniteditorcoveragejsunderscoreminjs">trunk/tests/qunit/editor/coverage/js/underscore-min.js</a></li>
<li>trunk/tests/qunit/editor/external-plugins/</li>
<li>trunk/tests/qunit/editor/external-plugins/noneditable/</li>
<li><a href="#trunktestsquniteditorexternalpluginsnoneditablepluginjs">trunk/tests/qunit/editor/external-plugins/noneditable/plugin.js</a></li>
<li><a href="#trunktestsquniteditorexternalpluginsnoneditablepluginminjs">trunk/tests/qunit/editor/external-plugins/noneditable/plugin.min.js</a></li>
<li>trunk/tests/qunit/editor/external-plugins/table/</li>
<li><a href="#trunktestsquniteditorexternalpluginstablepluginjs">trunk/tests/qunit/editor/external-plugins/table/plugin.js</a></li>
<li><a href="#trunktestsquniteditorexternalpluginstablepluginminjs">trunk/tests/qunit/editor/external-plugins/table/plugin.min.js</a></li>
<li><a href="#trunktestsquniteditorindexhtml">trunk/tests/qunit/editor/index.html</a></li>
<li>trunk/tests/qunit/editor/js/</li>
<li>trunk/tests/qunit/editor/js/qunit/</li>
<li><a href="#trunktestsquniteditorjsqunitQUnitLICENSE">trunk/tests/qunit/editor/js/qunit/QUnit.LICENSE</a></li>
<li><a href="#trunktestsquniteditorjsqunitqunitcss">trunk/tests/qunit/editor/js/qunit/qunit.css</a></li>
<li><a href="#trunktestsquniteditorjsqunitqunitjs">trunk/tests/qunit/editor/js/qunit/qunit.js</a></li>
<li><a href="#trunktestsquniteditorjsqunitreporterjs">trunk/tests/qunit/editor/js/qunit/reporter.js</a></li>
<li><a href="#trunktestsquniteditorjsqunittestrunnercss">trunk/tests/qunit/editor/js/qunit/testrunner.css</a></li>
<li><a href="#trunktestsquniteditorjsqunittestrunnerjs">trunk/tests/qunit/editor/js/qunit/testrunner.js</a></li>
<li><a href="#trunktestsquniteditorjstinymce_loaderjs">trunk/tests/qunit/editor/js/tinymce_loader.js</a></li>
<li><a href="#trunktestsquniteditorjsutilsjs">trunk/tests/qunit/editor/js/utils.js</a></li>
<li>trunk/tests/qunit/editor/plugins/</li>
<li><a href="#trunktestsquniteditorpluginsautolinkhtml">trunk/tests/qunit/editor/plugins/autolink.html</a></li>
<li><a href="#trunktestsquniteditorpluginsautosavehtml">trunk/tests/qunit/editor/plugins/autosave.html</a></li>
<li><a href="#trunktestsquniteditorpluginsfullpagehtml">trunk/tests/qunit/editor/plugins/fullpage.html</a></li>
<li><a href="#trunktestsquniteditorpluginsjquery_pluginhtml">trunk/tests/qunit/editor/plugins/jquery_plugin.html</a></li>
<li>trunk/tests/qunit/editor/plugins/js/</li>
<li><a href="#trunktestsquniteditorpluginsjsautolinkactionsjs">trunk/tests/qunit/editor/plugins/js/autolink.actions.js</a></li>
<li><a href="#trunktestsquniteditorpluginsjsdsljs">trunk/tests/qunit/editor/plugins/js/dsl.js</a></li>
<li><a href="#trunktestsquniteditorpluginsjsstatesjs">trunk/tests/qunit/editor/plugins/js/states.js</a></li>
<li><a href="#trunktestsquniteditorpluginslegacyoutputhtml">trunk/tests/qunit/editor/plugins/legacyoutput.html</a></li>
<li><a href="#trunktestsquniteditorpluginslistshtml">trunk/tests/qunit/editor/plugins/lists.html</a></li>
<li><a href="#trunktestsquniteditorpluginsmediahtml">trunk/tests/qunit/editor/plugins/media.html</a></li>
<li><a href="#trunktestsquniteditorpluginsnoneditablehtml">trunk/tests/qunit/editor/plugins/noneditable.html</a></li>
<li><a href="#trunktestsquniteditorpluginspastehtml">trunk/tests/qunit/editor/plugins/paste.html</a></li>
<li><a href="#trunktestsquniteditorpluginsplugin_dependency_chainhtml">trunk/tests/qunit/editor/plugins/plugin_dependency_chain.html</a></li>
<li><a href="#trunktestsquniteditorpluginsplugin_dependency_chain_legacyhtml">trunk/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html</a></li>
<li><a href="#trunktestsquniteditorpluginsplugin_dependency_init_call_orderhtml">trunk/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html</a></li>
<li><a href="#trunktestsquniteditorpluginsplugin_dependency_simplehtml">trunk/tests/qunit/editor/plugins/plugin_dependency_simple.html</a></li>
<li><a href="#trunktestsquniteditorpluginsplugin_dependency_specific_locationhtml">trunk/tests/qunit/editor/plugins/plugin_dependency_specific_location.html</a></li>
<li><a href="#trunktestsquniteditorpluginssearchreplacehtml">trunk/tests/qunit/editor/plugins/searchreplace.html</a></li>
<li><a href="#trunktestsquniteditorpluginsspellcheckerhtml">trunk/tests/qunit/editor/plugins/spellchecker.html</a></li>
<li><a href="#trunktestsquniteditorpluginstablehtml">trunk/tests/qunit/editor/plugins/table.html</a></li>
<li><a href="#trunktestsquniteditorpluginstable_robothtml">trunk/tests/qunit/editor/plugins/table_robot.html</a></li>
<li><a href="#trunktestsquniteditorpluginstestsjs">trunk/tests/qunit/editor/plugins/tests.js</a></li>
<li><a href="#trunktestsquniteditorpluginswordcounthtml">trunk/tests/qunit/editor/plugins/wordcount.html</a></li>
<li><a href="#trunktestsquniteditortestgif">trunk/tests/qunit/editor/test.gif</a></li>
<li>trunk/tests/qunit/editor/tinymce/</li>
<li><a href="#trunktestsquniteditortinymceEditorhtml">trunk/tests/qunit/editor/tinymce/Editor.html</a></li>
<li><a href="#trunktestsquniteditortinymceEditorCommandshtml">trunk/tests/qunit/editor/tinymce/EditorCommands.html</a></li>
<li><a href="#trunktestsquniteditortinymceEnterKeyhtml">trunk/tests/qunit/editor/tinymce/EnterKey.html</a></li>
<li><a href="#trunktestsquniteditortinymceForceBlockshtml">trunk/tests/qunit/editor/tinymce/ForceBlocks.html</a></li>
<li><a href="#trunktestsquniteditortinymceFormatter_applyhtml">trunk/tests/qunit/editor/tinymce/Formatter_apply.html</a></li>
<li><a href="#trunktestsquniteditortinymceFormatter_checkhtml">trunk/tests/qunit/editor/tinymce/Formatter_check.html</a></li>
<li><a href="#trunktestsquniteditortinymceFormatter_removehtml">trunk/tests/qunit/editor/tinymce/Formatter_remove.html</a></li>
<li><a href="#trunktestsquniteditortinymceFormatter_robothtml">trunk/tests/qunit/editor/tinymce/Formatter_robot.html</a></li>
<li><a href="#trunktestsquniteditortinymceUndoManagerhtml">trunk/tests/qunit/editor/tinymce/UndoManager.html</a></li>
<li><a href="#trunktestsquniteditortinymceUndoManager_robothtml">trunk/tests/qunit/editor/tinymce/UndoManager_robot.html</a></li>
<li>trunk/tests/qunit/editor/tinymce/dom/</li>
<li><a href="#trunktestsquniteditortinymcedomDOMUtilshtml">trunk/tests/qunit/editor/tinymce/dom/DOMUtils.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomDOMUtilsjs">trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js</a></li>
<li><a href="#trunktestsquniteditortinymcedomDOMUtils_jqueryhtml">trunk/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomEventUtilshtml">trunk/tests/qunit/editor/tinymce/dom/EventUtils.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomRangehtml">trunk/tests/qunit/editor/tinymce/dom/Range.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomSelectionhtml">trunk/tests/qunit/editor/tinymce/dom/Selection.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomSerializerhtml">trunk/tests/qunit/editor/tinymce/dom/Serializer.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomTridentSelectionhtml">trunk/tests/qunit/editor/tinymce/dom/TridentSelection.html</a></li>
<li><a href="#trunktestsquniteditortinymcedomtestcss">trunk/tests/qunit/editor/tinymce/dom/test.css</a></li>
<li><a href="#trunktestsquniteditortinymcedomtestsjs">trunk/tests/qunit/editor/tinymce/dom/tests.js</a></li>
<li>trunk/tests/qunit/editor/tinymce/html/</li>
<li><a href="#trunktestsquniteditortinymcehtmlDomParserhtml">trunk/tests/qunit/editor/tinymce/html/DomParser.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlEntitieshtml">trunk/tests/qunit/editor/tinymce/html/Entities.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlNodehtml">trunk/tests/qunit/editor/tinymce/html/Node.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlSaxParserhtml">trunk/tests/qunit/editor/tinymce/html/SaxParser.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlSchemahtml">trunk/tests/qunit/editor/tinymce/html/Schema.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlSerializerhtml">trunk/tests/qunit/editor/tinymce/html/Serializer.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlStyleshtml">trunk/tests/qunit/editor/tinymce/html/Styles.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlWriterhtml">trunk/tests/qunit/editor/tinymce/html/Writer.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmlobsoletehtml">trunk/tests/qunit/editor/tinymce/html/obsolete.html</a></li>
<li><a href="#trunktestsquniteditortinymcehtmltestsjs">trunk/tests/qunit/editor/tinymce/html/tests.js</a></li>
<li><a href="#trunktestsquniteditortinymcetestsjs">trunk/tests/qunit/editor/tinymce/tests.js</a></li>
<li>trunk/tests/qunit/editor/tinymce/ui/</li>
<li><a href="#trunktestsquniteditortinymceuiAbsoluteLayouthtml">trunk/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiButtonhtml">trunk/tests/qunit/editor/tinymce/ui/Button.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiButtonGrouphtml">trunk/tests/qunit/editor/tinymce/ui/ButtonGroup.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiCheckboxhtml">trunk/tests/qunit/editor/tinymce/ui/Checkbox.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiCollectionhtml">trunk/tests/qunit/editor/tinymce/ui/Collection.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiColorButtonhtml">trunk/tests/qunit/editor/tinymce/ui/ColorButton.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiComboBoxhtml">trunk/tests/qunit/editor/tinymce/ui/ComboBox.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiContainerhtml">trunk/tests/qunit/editor/tinymce/ui/Container.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiControlhtml">trunk/tests/qunit/editor/tinymce/ui/Control.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiDragHelperhtml">trunk/tests/qunit/editor/tinymce/ui/DragHelper.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiElementPathhtml">trunk/tests/qunit/editor/tinymce/ui/ElementPath.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFactoryhtml">trunk/tests/qunit/editor/tinymce/ui/Factory.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFieldSethtml">trunk/tests/qunit/editor/tinymce/ui/FieldSet.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFilePickerhtml">trunk/tests/qunit/editor/tinymce/ui/FilePicker.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFitLayouthtml">trunk/tests/qunit/editor/tinymce/ui/FitLayout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFlexLayouthtml">trunk/tests/qunit/editor/tinymce/ui/FlexLayout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFloatPanelhtml">trunk/tests/qunit/editor/tinymce/ui/FloatPanel.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFlowLayouthtml">trunk/tests/qunit/editor/tinymce/ui/FlowLayout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFormhtml">trunk/tests/qunit/editor/tinymce/ui/Form.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiFormItemhtml">trunk/tests/qunit/editor/tinymce/ui/FormItem.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiGridLayouthtml">trunk/tests/qunit/editor/tinymce/ui/GridLayout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiIframehtml">trunk/tests/qunit/editor/tinymce/ui/Iframe.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiKeyboardNavigationhtml">trunk/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiLabelhtml">trunk/tests/qunit/editor/tinymce/ui/Label.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiLayouthtml">trunk/tests/qunit/editor/tinymce/ui/Layout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiListBoxhtml">trunk/tests/qunit/editor/tinymce/ui/ListBox.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiMenuhtml">trunk/tests/qunit/editor/tinymce/ui/Menu.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiMenuBarhtml">trunk/tests/qunit/editor/tinymce/ui/MenuBar.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiMenuButtonhtml">trunk/tests/qunit/editor/tinymce/ui/MenuButton.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiMenuItemhtml">trunk/tests/qunit/editor/tinymce/ui/MenuItem.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiMessageBoxhtml">trunk/tests/qunit/editor/tinymce/ui/MessageBox.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiMovablehtml">trunk/tests/qunit/editor/tinymce/ui/Movable.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiPanelhtml">trunk/tests/qunit/editor/tinymce/ui/Panel.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiPanelButtonhtml">trunk/tests/qunit/editor/tinymce/ui/PanelButton.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiPathhtml">trunk/tests/qunit/editor/tinymce/ui/Path.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiRadiohtml">trunk/tests/qunit/editor/tinymce/ui/Radio.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiResizablehtml">trunk/tests/qunit/editor/tinymce/ui/Resizable.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiResizeHandlehtml">trunk/tests/qunit/editor/tinymce/ui/ResizeHandle.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiScrollablehtml">trunk/tests/qunit/editor/tinymce/ui/Scrollable.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiSelectorhtml">trunk/tests/qunit/editor/tinymce/ui/Selector.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiSpacerhtml">trunk/tests/qunit/editor/tinymce/ui/Spacer.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiSplitButtonhtml">trunk/tests/qunit/editor/tinymce/ui/SplitButton.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiStackLayouthtml">trunk/tests/qunit/editor/tinymce/ui/StackLayout.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiTabPanelhtml">trunk/tests/qunit/editor/tinymce/ui/TabPanel.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiTextBoxhtml">trunk/tests/qunit/editor/tinymce/ui/TextBox.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiThrobberhtml">trunk/tests/qunit/editor/tinymce/ui/Throbber.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiToolbarhtml">trunk/tests/qunit/editor/tinymce/ui/Toolbar.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiTooltiphtml">trunk/tests/qunit/editor/tinymce/ui/Tooltip.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiWidgethtml">trunk/tests/qunit/editor/tinymce/ui/Widget.html</a></li>
<li><a href="#trunktestsquniteditortinymceuiWindowhtml">trunk/tests/qunit/editor/tinymce/ui/Window.html</a></li>
<li>trunk/tests/qunit/editor/tinymce/ui/css/</li>
<li><a href="#trunktestsquniteditortinymceuicssuioverridescss">trunk/tests/qunit/editor/tinymce/ui/css/ui-overrides.css</a></li>
<li>trunk/tests/qunit/editor/tinymce/ui/img/</li>
<li><a href="#trunktestsquniteditortinymceuiimgrastergif">trunk/tests/qunit/editor/tinymce/ui/img/raster.gif</a></li>
<li><a href="#trunktestsquniteditortinymceuitestsjs">trunk/tests/qunit/editor/tinymce/ui/tests.js</a></li>
<li>trunk/tests/qunit/editor/tinymce/util/</li>
<li><a href="#trunktestsquniteditortinymceutilJSONhtml">trunk/tests/qunit/editor/tinymce/util/JSON.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilJSONRequesthtml">trunk/tests/qunit/editor/tinymce/util/JSONRequest.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilLocalStoragehtml">trunk/tests/qunit/editor/tinymce/util/LocalStorage.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_allhtml">trunk/tests/qunit/editor/tinymce/util/Quirks_all.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_firefoxhtml">trunk/tests/qunit/editor/tinymce/util/Quirks_firefox.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_ie8html">trunk/tests/qunit/editor/tinymce/util/Quirks_ie8.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_removehtml">trunk/tests/qunit/editor/tinymce/util/Quirks_remove.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_webkithtml">trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilQuirks_webkit_jsrobothtml">trunk/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilURIhtml">trunk/tests/qunit/editor/tinymce/util/URI.html</a></li>
<li><a href="#trunktestsquniteditortinymceutilXHRhtml">trunk/tests/qunit/editor/tinymce/util/XHR.html</a></li>
<li><a href="#trunktestsquniteditortinymceutiljson_rpc_errorjs">trunk/tests/qunit/editor/tinymce/util/json_rpc_error.js</a></li>
<li><a href="#trunktestsquniteditortinymceutiljson_rpc_okjs">trunk/tests/qunit/editor/tinymce/util/json_rpc_ok.js</a></li>
<li><a href="#trunktestsquniteditortinymceutiltestxml">trunk/tests/qunit/editor/tinymce/util/test.xml</a></li>
<li><a href="#trunktestsquniteditortinymceutiltestsjs">trunk/tests/qunit/editor/tinymce/util/tests.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkGruntfilejs"></a>
<div class="modfile"><h4>Modified: trunk/Gruntfile.js (27154 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Gruntfile.js       2014-02-09 22:33:56 UTC (rev 27154)
+++ trunk/Gruntfile.js  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -160,7 +160,8 @@
</span><span class="cx">                  tests: {
</span><span class="cx">                          src: [
</span><span class="cx">                                  'tests/qunit/**/*.js',
</span><del>-                                       '!tests/qunit/vendor/qunit.js'
</del><ins>+                                        '!tests/qunit/vendor/qunit.js',
+                                       '!tests/qunit/editor/**'
</ins><span class="cx">                           ],
</span><span class="cx">                          options: grunt.file.readJSON('tests/qunit/.jshintrc')
</span><span class="cx">                  },
</span><span class="lines">@@ -228,7 +229,10 @@
</span><span class="cx">                  }
</span><span class="cx">          },
</span><span class="cx">          qunit: {
</span><del>-                       files: ['tests/qunit/**/*.html']
</del><ins>+                        files: [
+                               'tests/qunit/**/*.html',
+                               '!tests/qunit/editor/**'
+                       ]
</ins><span class="cx">           },
</span><span class="cx">          phpunit: {
</span><span class="cx">                  'default': {
</span><span class="lines">@@ -340,7 +344,10 @@
</span><span class="cx">                          }
</span><span class="cx">                  },
</span><span class="cx">                  test: {
</span><del>-                               files: ['tests/qunit/**'],
</del><ins>+                                files: [
+                                       'tests/qunit/**',
+                                       '!tests/qunit/editor/**'
+                               ],
</ins><span class="cx">                           tasks: ['qunit']
</span><span class="cx">                  }
</span><span class="cx">          }
</span></span></pre></div>
<a id="trunktestsquniteditorcoverageindexhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/coverage/index.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/coverage/index.html                             (rev 0)
+++ trunk/tests/qunit/editor/coverage/index.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8" />
+<title>Code Coverage</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+
+<!-- coverage -->
+<link rel="stylesheet" href="js/reporter.css" type="text/css" />
+<script src="js/underscore-min.js"></script>
+<script src="js/backbone-min.js"></script>
+<script src="js/reporter.js"></script>
+<script src="js/JSCovReporter.js"></script>
+
+</head>
+<body>
+    <div id="coverage"></div>
+    <div id="menu"></div>
+    
+    <script>
+       if (top != window && top.TestRunner) {
+               new JSCovReporter({ coverObject: top.TestRunner.getCoverObject() });
+               //onsole.info(top.TestRunner.getCoverObject());
+       }
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/coverage/index.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorcoveragejsJSCovReporterjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/coverage/js/JSCovReporter.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/coverage/js/JSCovReporter.js                            (rev 0)
+++ trunk/tests/qunit/editor/coverage/js/JSCovReporter.js       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,194 @@
</span><ins>+JSCovFileReporter = Backbone.View.extend({
+    initialize: function () {
+        _.bindAll(this);
+        this.open  = '<tr class="{class}"><td class="line">{line_number}</td><td class="hits">{count}</td><td class="source">';
+        this.close = '</td></tr>';
+
+        this.coverObject = this.options.coverObject;
+
+        this.error = 0;
+        this.pass = 0;
+        this.total = 0;
+    },
+
+    // substitute credits: MooTools
+    substitute: function(string, object){
+        return string.replace(/\\?\{([^{}]+)\}/g, function(match, name){
+            if (match.charAt(0) == '\\') return match.slice(1);
+            return (object[name] !== null) ? object[name] : '';
+        });
+    },
+
+    generateClose: function(count){
+        return this.substitute(this.close, {
+            count: count
+        });
+    },
+
+    generateOpen: function(hit_count, line_number){
+        return this.substitute(this.open, {
+            'count': hit_count,
+            'line_number': line_number,
+            'class': hit_count ? 'hit' : 'miss'
+        });
+    },
+
+    report: function () {
+        var thisview = this;
+        var i, l, k;
+
+        var code = this.coverObject.__code;
+
+        // generate array of all tokens
+        var codez = [];
+        for (i = 0, l = code.length; i < l; i++){
+            codez.push({
+                pos: i,
+                value: code.slice(i, i + 1)
+            });
+        }
+
+        // CoverObject has keys like "12:200" which means from char 12 to 200
+        // This orders all first gaps in a list of dictionaries to ease drawing table lines
+        var gaps = Object.keys(this.coverObject);
+        gaps = _.without(gaps, '__code');
+        var first_gaps = _.map(gaps, function ( gap ) {
+            return {
+                gap: parseInt(gap.split(':')[0], 10),
+                hit_count: thisview.coverObject[gap]
+            };
+        }).sort(function (a, b) {
+            if (a['gap'] > b['gap']) return 1;
+            if (b['gap'] > a['gap']) return -1;
+            return 0;
+        });
+
+        var second_gaps = _.map(gaps, function ( gap ) {
+            return {
+                gap: parseInt(gap.split(':')[1], 10),
+                hit_count: thisview.coverObject[gap]
+            };
+        }).sort(function (a, b) {
+            if (a['gap'] > b['gap']) return 1;
+            if (b['gap'] > a['gap']) return -1;
+            return 0;
+        });
+
+
+        // If it doesn't start from 0 it's because there are comments in the beginning
+        // We add a initial gap with one hit
+        if (first_gaps[0] !== 0) {
+            first_gaps.splice(0, 0, {gap: 0, hit_count: 1});
+        }
+
+        var result = '';
+        var number_trailing_whitespaces = 0;
+        var trailing_whitespaces = '';
+
+
+        // We will go from one gap to the next wrapping them in table lines
+        for (i=0, l = first_gaps.length; i < l; i++){
+
+            var hit_count = first_gaps[i]['hit_count'];
+
+            this.total++;
+            if (hit_count) this.pass++;
+            else this.error++;
+
+            var limit = null;
+            if (i+1 >= l) {
+                limit = codez.length;
+            }
+            else {
+                limit = first_gaps[i+1]['gap'];
+            }
+
+            // Table line opening
+            result += this.generateOpen(hit_count, this.total);
+
+            // Add trailing white space if it existed from previous line without carriage returns
+            if (number_trailing_whitespaces > 0 ) {
+                result += trailing_whitespaces.replace(/(\r\n|\n|\r)/gm,"");
+            }
+
+            // Add lines of code without initial white spaces, and replacing conflictive chars
+            result += _.map(codez.slice(first_gaps[i]['gap'], limit), function (loc) {
+                return loc['value'];
+            }).join('').trimLeft().replace(/</g, '&lt;').replace(/>/g, '&gt;');
+
+            // Count trailing white spaces for future line, then remove them
+            var matches = result.match(/(\s+)$/);
+            result = result.trimRight();
+
+            if (matches !== null) {
+                number_trailing_whitespaces = matches[0].length;
+                trailing_whitespaces = matches[0];
+            }
+            else {
+                number_trailing_whitespaces = 0;
+            }
+
+            // Generate table line closing
+            result += this.generateClose(hit_count);
+        }
+
+        return result;
+    }
+});
+
+
+JSCovReporter = Backbone.View.extend({
+    initialize: function () {
+        this.coverObject = this.options.coverObject;
+
+        // Generate the report
+        this.report();
+
+        // Activate reporter.js scrolling UX
+        onload();
+    },
+
+    report: function () {
+        var result = '';
+        var index = '';
+
+        for (var file in this.coverObject) {
+            var fileReporter = new JSCovFileReporter({ coverObject: this.coverObject[file] });
+
+            var fileReport = fileReporter.report();
+            var percentage = Math.round(fileReporter.pass / fileReporter.total * 100);
+
+            this.error += fileReporter.error;
+            this.pass  += fileReporter.pass;
+            this.total += fileReporter.total;
+
+            var type_coverage = "high";
+            if (percentage < 75 && percentage >= 50) {
+                type_coverage = 'medium';
+            }
+            else if (percentage < 50 && percentage >= 25) {
+                type_coverage = 'low';
+            }
+            else if (percentage < 25) {
+                type_coverage = 'terrible';
+            }
+
+            // Title
+            result += '<h2 id="' + file + '" class="file-title">' + file + '</h2>';
+            // Stats
+            result += '<div class="stats ' + type_coverage + '"><div class="percentage">'+ percentage + '%</div>';
+            result += '<div class="sloc">' + fileReporter.total + '</div><div class="hits">' + fileReporter.pass + '</div>';
+            result += '<div class="misses">' + fileReporter.error + '</div></div>';
+            // Report
+            result += '<div class="file-report">';
+            result += '<table id="source"><tbody>' + fileReport + '</tbody></table>';
+            result += '</div>';
+
+            // Menu index
+            index += '<li><span class="cov ' + type_coverage + '">' + percentage + '</span><a href="#' + file+ '">' + file + '</a></li>';
+        }
+
+        $('#coverage').html(result);
+        $('#menu').html('<ul id="toc">' + index + '</ul>');
+    }
+});
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/coverage/js/JSCovReporter.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorcoveragejsbackboneminjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/coverage/js/backbone-min.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/coverage/js/backbone-min.js                             (rev 0)
+++ trunk/tests/qunit/editor/coverage/js/backbone-min.js        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.0.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this
 }a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o<u;o++){t=a[o];if(n=this._events[t]){this._events[t]=r=[];if(e||i){for(c=0,f=n.length;c<f;c++){s=n[c];if(e&&e!==s.callback&&e!==s.callback._callback||i&&i!==s.context){r.push(s)}}}if(!r.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=s.call(arguments,1);if(!l(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)c(i,e);if(r)c(r,arguments);return this},stopListening:function(t,e,i){var r=this._listeners;if(!r)return this;var s=!e&&!i;if(typeof e==="object")i=this;if(t)(r={})[t._listenerId]=t;for(var n in r){r[n].off(e,i,this);if(s)delete this._listeners[n]}return this}};var u=/\s+/;var l=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(u.test(i)){var n=i.split(u);for(var a=0,h=n.length;a<h;a++){t[e].apply(t,[n[a]
 ].concat(r))}return false}return true};var c=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],h=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,h);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e)}};var f={listenTo:"on",listenToOnce:"once"};h.each(f,function(t,e){o[e]=function(e,i,r){var s=this._listeners||(this._listeners={});var n=e._listenerId||(e._listenerId=h.uniqueId("l"));s[n]=e;if(typeof i==="object")r=this;e[t](i,r,this);return this}});o.bind=o.on;o.unbind=o.off;h.extend(a,o);var d=a.Model=function(t,e){var i;var r=t||{};e||(e={});this.cid=h.uniqueId("c");this.attributes={};h.extend(this,h.pick(e,p));if(e.parse)r=this.parse(r,e)||{};if(i=h.result(this,"defaults")){r=h.defaults({},r,i)}this.set
 (r,e);this.changed={};this.initialize.apply(this,arguments)};var p=["url","urlRoot","collection"];h.extend(d.prototype,o,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return h.clone(this.attributes)},sync:function(){return a.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return h.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,i){var r,s,n,a,o,u,l,c;if(t==null)return this;if(typeof t==="object"){s=t;i=e}else{(s={})[t]=e}i||(i={});if(!this._validate(s,i))return false;n=i.unset;o=i.silent;a=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=h.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in s)this.id=s[this.idAttribute];for(r in s){e=s[r];if(!h.isEqual(c[r],e))a.push(r);if(!h.isEqual(l[r],e)){this.changed[r]=e}else{delete this.changed[r
 ]}n?delete c[r]:c[r]=e}if(!o){if(a.length)this._pending=true;for(var f=0,d=a.length;f<d;f++){this.trigger("change:"+a[f],this,c[a[f]],i)}}if(u)return this;if(!o){while(this._pending){this._pending=false;this.trigger("change",this,i)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,h.extend({},e,{unset:true}))},clear:function(t){var e={};for(var i in this.attributes)e[i]=void 0;return this.set(e,h.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!h.isEmpty(this.changed);return h.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?h.clone(this.changed):false;var e,i=false;var r=this._changing?this._previousAttributes:this.attributes;for(var s in t){if(h.isEqual(r[s],e=t[s]))continue;(i||(i={}))[s]=e}return i},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return h.clone(this.
 _previousAttributes)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var i=t.success;t.success=function(r){if(!e.set(e.parse(r,t),t))return false;if(i)i(e,r,t);e.trigger("sync",e,r,t)};R(this,t);return this.sync("read",this,t)},save:function(t,e,i){var r,s,n,a=this.attributes;if(t==null||typeof t==="object"){r=t;i=e}else{(r={})[t]=e}if(r&&(!i||!i.wait)&&!this.set(r,i))return false;i=h.extend({validate:true},i);if(!this._validate(r,i))return false;if(r&&i.wait){this.attributes=h.extend({},a,r)}if(i.parse===void 0)i.parse=true;var o=this;var u=i.success;i.success=function(t){o.attributes=a;var e=o.parse(t,i);if(i.wait)e=h.extend(r||{},e);if(h.isObject(e)&&!o.set(e,i)){return false}if(u)u(o,t,i);o.trigger("sync",o,t,i)};R(this,i);s=this.isNew()?"create":i.patch?"patch":"update";if(s==="patch")i.attrs=r;n=this.sync(s,this,i);if(r&&i.wai
 t)this.attributes=a;return n},destroy:function(t){t=t?h.clone(t):{};var e=this;var i=t.success;var r=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(s){if(t.wait||e.isNew())r();if(i)i(e,s,t);if(!e.isNew())e.trigger("sync",e,s,t)};if(this.isNew()){t.success();return false}R(this,t);var s=this.sync("delete",this,t);if(!t.wait)r();return s},url:function(){var t=h.result(this,"urlRoot")||h.result(this.collection,"url")||U();if(this.isNew())return t;return t+(t.charAt(t.length-1)==="/"?"":"/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return this.id==null},isValid:function(t){return this._validate({},h.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=h.extend({},this.attributes,t);var i=this.validationError=this.validate(t,e)||null;if(!i)retu
 rn true;this.trigger("invalid",this,i,h.extend(e||{},{validationError:i}));return false}});var v=["keys","values","pairs","invert","pick","omit"];h.each(v,function(t){d.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.attributes);return h[t].apply(h,e)}});var g=a.Collection=function(t,e){e||(e={});if(e.url)this.url=e.url;if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,h.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,merge:false,remove:false};h.extend(g.prototype,o,{model:d,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return a.sync.apply(this,arguments)},add:function(t,e){return this.set(t,h.defaults(e||{},y))},remove:function(t,e){t=h.isArray(t)?t.slice():[t];e||(e={});var i,r,s,n;for(i=0,r=t.length
 ;i<r;i++){n=this.get(t[i]);if(!n)continue;delete this._byId[n.id];delete this._byId[n.cid];s=this.indexOf(n);this.models.splice(s,1);this.length--;if(!e.silent){e.index=s;n.trigger("remove",n,this,e)}this._removeReference(n)}return this},set:function(t,e){e=h.defaults(e||{},m);if(e.parse)t=this.parse(t,e);if(!h.isArray(t))t=t?[t]:[];var i,s,a,o,u,l;var c=e.at;var f=this.comparator&&c==null&&e.sort!==false;var d=h.isString(this.comparator)?this.comparator:null;var p=[],v=[],g={};for(i=0,s=t.length;i<s;i++){if(!(a=this._prepareModel(t[i],e)))continue;if(u=this.get(a)){if(e.remove)g[u.cid]=true;if(e.merge){u.set(a.attributes,e);if(f&&!l&&u.hasChanged(d))l=true}}else if(e.add){p.push(a);a.on("all",this._onModelEvent,this);this._byId[a.cid]=a;if(a.id!=null)this._byId[a.id]=a}}if(e.remove){for(i=0,s=this.length;i<s;++i){if(!g[(a=this.models[i]).cid])v.push(a)}if(v.length)this.remove(v,e)}if(p.length){if(f)l=true;this.length+=p.l
 ength;if(c!=null){n.apply(this.models,[c,0].concat(p))}else{r.apply(this.models,p)}}if(l)this.sort({silent:true});if(e.silent)return this;for(i=0,s=p.length;i<s;i++){(a=p[i]).trigger("add",a,this,e)}if(l)this.trigger("sort",this,e);return this},reset:function(t,e){e||(e={});for(var i=0,r=this.models.length;i<r;i++){this._removeReference(this.models[i])}e.previousModels=this.models;this._reset();this.add(t,h.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return this},push:function(t,e){t=this._prepareModel(t,e);this.add(t,h.extend({at:this.length},e));return t},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){t=this._prepareModel(t,e);this.add(t,h.extend({at:0},e));return t},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(t,e){return this.models.slice(t,e)},get:function(t){if(t==null)return void 0;return this._byId[t.id!=null?t.id:t.cid||t]},at:function(t)
 {return this.models[t]},where:function(t,e){if(h.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(h.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(h.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},sortedIndex:function(t,e,i){e||(e=this.comparator);var r=h.isFunction(e)?e:function(t){return t.get(e)};return h.sortedIndex(this.models,t,r,i)},pluck:function(t){return h.invoke(this.models,"get",t)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var i=this;t.success=function(r){var s=t.reset?"reset":"set";i[s](r,t);if(e)e(i,r,t);i.tri
 gger("sync",i,r,t)};R(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?h.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var i=this;var r=e.success;e.success=function(s){if(e.wait)i.add(t,e);if(r)r(t,s,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof d){if(!t.collection)t.collection=this;return t}e||(e={});e.collection=this;var i=new this.model(t,e);if(!i._validate(t,e)){this.trigger("invalid",this,t,e);return false}return i},_removeReference:function(t){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.i
 dAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","indexOf","shuffle","lastIndexOf","isEmpty","chain"];h.each(_,function(t){g.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.models);return h[t].apply(h,e)}});var w=["groupB
 y","countBy","sortBy"];h.each(w,function(t){g.prototype[t]=function(e,i){var r=h.isFunction(e)?e:function(t){return t.get(e)};return h[t](this.models,r,i)}});var b=a.View=function(t){this.cid=h.uniqueId("view");this._configure(t||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\S+)\s*(.*)$/;var E=["model","collection","el","id","attributes","className","tagName","events"];h.extend(b.prototype,o,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,e){if(this.$el)this.undelegateEvents();this.$el=t instanceof a.$?t:a.$(t);this.el=this.$el[0];if(e!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=h.result(this,"events"))))return th
 is;this.undelegateEvents();for(var e in t){var i=t[e];if(!h.isFunction(i))i=this[t[e]];if(!i)continue;var r=e.match(x);var s=r[1],n=r[2];i=h.bind(i,this);s+=".delegateEvents"+this.cid;if(n===""){this.$el.on(s,i)}else{this.$el.on(s,n,i)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_configure:function(t){if(this.options)t=h.extend({},h.result(this,"options"),t);h.extend(this,h.pick(t,E));this.options=t},_ensureElement:function(){if(!this.el){var t=h.extend({},h.result(this,"attributes"));if(this.id)t.id=h.result(this,"id");if(this.className)t["class"]=h.result(this,"className");var e=a.$("<"+h.result(this,"tagName")+">").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=k[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON}
 );var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&window.ActiveXObject&&!(window.external&&window.external.msActiveXFilteringEnabled)){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(
 h.extend(s,i));e.trigger("request",e,o,i);return o};var k={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var S=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var $=/\((.*?)\)/g;var T=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(S.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes
 =h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace($,"(?:$1)?").replace(T,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var P=/^\/+|\/+$/g;var O=/msie [\w.]+/;var C=/\/$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=th
 is.root.replace(C,"");if(!t.indexOf(i))t=t.substr(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({},{root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=O.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(P,"/");if(r&&this._wantsHashChange){this.iframe=a.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;this.navigate(e)}if(this._hasPushState){a.$(window).on("popstate",this.checkU
 rl)}else if(this._wantsHashChange&&"onhashchange"in window&&!r){a.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=e;var s=this.location;var n=s.pathname.replace(/[^\/]$/,"$&/")===this.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!n){this.fragment=this.getFragment(null,true);this.location.replace(this.root+this.location.search+"#"+this.fragment);return true}else if(this._wantsPushState&&this._hasPushState&&n&&s.hash){this.fragment=this.getHash().replace(N,"");this.history.replaceState({},document.title,this.root+this.fragment+s.search)}if(!this.options.silent)return this.loadUrl()},stop:function(){a.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);I.started=fa
 lse},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(t){var e=this.fragment=this.getFragment(t);var i=h.any(this.handlers,function(t){if(t.route.test(e)){t.callback(e);return true}});return i},navigate:function(t,e){if(!I.started)return false;if(!e||e===true)e={trigger:e};t=this.getFragment(t||"");if(this.fragment===t)return;this.fragment=t;var i=this.root+t;if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.loc
 ation,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});a.history=new I;var j=function(t,e){var i=this;var r;if(t&&h.has(t,"constructor")){r=t.constructor}else{r=function(){return i.apply(this,arguments)}}h.extend(r,i,e);var s=function(){this.constructor=r};s.prototype=i.prototype;r.prototype=new s;if(t)h.extend(r.prototype,t);r.__super__=i.prototype;return r};d.extend=g.extend=S.extend=b.extend=I.extend=j;var U=function(){throw new Error('A "url" property or function must be specified')};var R=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}}}).call(this);
+/*
+//@ sourceMappingURL=backbone-min.map
+*/
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/coverage/js/backbone-min.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorcoveragejsreportercss"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/coverage/js/reporter.css (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/coverage/js/reporter.css                                (rev 0)
+++ trunk/tests/qunit/editor/coverage/js/reporter.css   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,310 @@
</span><ins>+body {
+  font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
+  margin: 0;
+  color: #2C2C2C;
+  border-top: 2px solid #ddd;
+}
+
+#coverage {
+  padding: 10px 0;
+}
+
+h1 a {
+  color: inherit;
+  font-weight: inherit;
+}
+
+h1 a:hover {
+  text-decoration: none;
+}
+
+.onload h1 {
+  opacity: 1;
+}
+
+#menu h2 {
+  width: 80%;
+  margin-top: 80px;
+  margin-bottom: 0;
+  font-weight: 100;
+  letter-spacing: 1px;
+  border-bottom: 1px solid #eee;
+}
+
+a {
+  color: #8A6343;
+  font-weight: bold;
+  text-decoration: none;
+}
+
+#menu a:hover {
+  text-decoration: underline;
+}
+
+code {
+  font: 12px monaco, monospace;
+}
+
+pre {
+  margin: 30px;
+  padding: 30px;
+  border: 1px solid #eee;
+  border-bottom-color: #ddd;
+  -webkit-border-radius: 2px;
+  -moz-border-radius: 2px;
+  -webkit-box-shadow: inset 0 0 10px #eee;
+  -moz-box-shadow: inset 0 0 10px #eee;
+  overflow-x: auto;
+}
+
+img {
+  margin: 30px;
+  padding: 1px;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  -webkit-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+  -moz-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+  max-width: 100%;
+}
+
+footer {
+  background: #eee;
+  width: 100%;
+  padding: 50px 0;
+  text-align: right;
+  border-top: 1px solid #ddd;
+}
+
+footer span {
+  display: block;
+  margin-right: 30px;
+  color: #888;
+  font-size: 12px;
+}
+
+#menu {
+  position: fixed;
+  overflow: auto;
+  top: 0;
+  right: 0;
+  margin: 0;
+  height: 100%;
+  padding: 15px 0 15px 0;
+  min-width: 285px;
+  border-left: 1px solid #eee;
+
+  text-align: right;
+  font-size: 12px;
+
+  -moz-box-shadow: 0 0 2px #888
+     , inset 5px 0 20px rgba(0,0,0,.5)
+     , inset 5px 0 3px rgba(0,0,0,.3);
+  -webkit-box-shadow: 0 0 2px #888
+     , inset 5px 0 20px rgba(0,0,0,.5)
+     , inset 5px 0 3px rgba(0,0,0,.3);
+  -webkit-font-smoothing: antialiased;
+  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGYAAABmCAMAAAAOARRQAAABelBMVEUjJSU6OzshIyM5OjoqKy02NjgsLS01NTYjJCUzNTUgISMlJSc0NTUvMDA6PDwlJyg1NjYoKis2NjYrLS02ODkpKyw0NDYrLC04ODovLzA4Ojo0NDUtLy86OjwjIyU4OTosLS82ODgtLS8hIyQvMTEnKCooKSsrKy0qLCwkJSUnKCkrLCwpKiwwMjIxMzMqLC0tLS0pKissLC00NTYwMDIwMTQpKysoKSovMDEtLzA2OTkxMzUrKywvLy8qKyszNTY5OzsqKiw6OjswMDExNDUoKiozNDUvMDIyNDY1Njg2Njk5OTozMzU0NjY4ODkiIyUiIyQ4OTkuMDEmKCowMjQwMTErLS4qKywwMTMhIiMpKiopKy0tLjAkJScxNDQvLzExNDYyNDQmKCk5OTslJig5OjskJSYxMzQrLS8gISIwMTIoKCk1NTUlJSUnJygwMDA4ODgiIiMhISI8PDw6Ojo5OTkpKSojIyQ7OzsyMjIpKSssLCw6Ozw1NjlrfLakAAAg2UlEQVR42jR6i3ea6rYvPgANIAhVXh8WvkQlioUiFlFcBtAmoiRNdzxqu9p0J7vrdK29zuPeex77nnvO/35n1r1ndHRktI0jTOacv/l7lCBK5UqVpOha/YxmWK7BC4TQFKVXrbYsnimqxuuMVlOQ0XltWjUdCwRJ1M+tC1KudOs9q6+da2adUewG0SC0SwELfHtgDds93VEuydEbl3QMWeNoYkR7b/0x1ZRobGI3mLwzAhePqTAwhg6aogjNsGy7/jwQ4rkdqe7CWLxF8k9LfMVFyRS7VJqtkrW8Vt/bkR8FZJao16ipknbC3Yw2lM7laO6HBEOadEZ2tpf65c4v8e3u7FyU6qbiNNyCuzXZ6pawgnwgmrpTT/Q7w2EZmiI
 J0dzWDI7mhQ80IfRnMu2kzA5r5r1pIFoia+/d93HRYp1GV8TbrkWoU/+jdI0Ff6yGwTjT1Hn8J+8m1rKpGiYPuNiHnMtNMIv+zpsk84MYTNW1/+DpwXLvckdOCMYowVNPREe0QlM8xRHXXFhcNDzupwsSmb5pH+0t0RP2Qk+QtI7F1Qm6JRC6ZPBtPq/dq/kH+jxtCljn9TIpW6rQIgmSVyj6lPICIw4N/taka41PFUInth0je9+jO6Kt1G4/a7V2LEgG02B0pHVuCZrgltSKMuIl5SyufUv9mYuQi+mFgzbBEtFo2g+Dh4sSTrLNu8JPh00sQydpb00tqXBvqRN7Q7kqzcnIxCGnvZt/WmJacoOEO6Dcn8Qre03pOCSQxbMOXUuDNx9SxuLz4W1I18gvjViQ67zV0rxdWL8Te/TQkuo8STS41DR48W7L6YP2uWIqiUV8rd6Gbf/rnegKZeG8TpAM6afhGze9JAOxbLjsnUXEbrZ9vLYd7MT32cPF5mKKxmjy7huaoD9n62GOxni3iIJwv0IzZAZjdZkUtolCNLVfYZNaquFjGszVVf+J0vrz4CawoKdHnOzb0NMH7CDBOybfYNJ4rfeMyFNjkFYVTzMFs87rnPGXLUOeNKRVc0LnU7/UIgelzsy3CMuth0YfvnY0wsD3vODUL3eJcKqHQpm8yM3XZQWJxO6Un9iYloyyLpOwN2obHy6W6gbpcb44XmyC+mg+itAcaprGcrwZCqMj/GmtKn0zPvpTz/Cv1dw21XwP3cRupg3H3MF/S71eTKj1YrdwKdc2Mw0fRmb2sFf8lW3aU6JbIZSEPqvXvjM7G/aApyXlXeqKfMq0g/Su3rUGJPSPrtGElgknrZM3xUXqsAP6zMCNVn5u8aJnSNpJv2uru7t2jfRziW2+GuhqfldUNbPk71olwo+46ePUo1U3WKk/e5YK07F/wGRgcpODmQnIlVeHCWBE4puBi2jq28UKpqiN1/4UOrGz
 59TNYrrQHtd+11sG40BGD+pXdelNqGOg4NXe8W4eacJV/NS9/2Umtym6WQqveqR9xdCMElpxnbkalM4Vf9uaEcWZaKdyibEIjWKxJZPN95niCL3GiaXyssIrHxoLkqkzLCXULN46/f2h3tQJgyip+Tk9EAjJ9aJshq7t8X45aowSKspMSvPf7r9R8yxNptIaHS5ozuEm6luPDApugyNP8OaqiQ4BjaequXA54SLC83eHIY2r+CZp4409Xqw8Aa2oI7XkCrQi+in0w5AqF/kLNrcUz+qkl/lAobY1jSnx5OJNhyXIz3qfNFlXc0TKaglNwdWkWYt9QQ1Kr6W8zue21iNrdJk+N5oCr2O9nEtWKC7IS5J/zdDEYrmnAYfg6agCy+qcgz7ZofeDc4PbUWSvkshWuAc7OjiUyLkj+RAtdlwXJcjxdpkTTHDhK8lBCi8+JtvDVL1W6elmOM++YS0LuSlaP1oUvAeiW3cFnvTr8EbTz1tsSMYdGeZe40sRWu5uAfj7q+ZoKv2FNQ0p5XY1lmlcigHZqTPpabufEVrNuNPi165w3uCVQJHyJqmSJ7ZHnguqwtCmwViIJijj04ba2JNYtB+yORf5gg1/9t9iw4vUpeqiunSAbf+IBdj/b+iG2qrHvuNP0Vd/+ThVZT/lrvHYjjgDbbyxaqgHNM2uhxa1GW3UedZYhMMwM4mQhltouK+IV4NdbIQNM+8Yv311RZk9kT4tiYR4LkyFcuPpdcjuhUuFqBAWRZa11lcZ3gEBlXywsNhrt+plISZP5DlsV9l4EgY6J3yZPTUcMrgaWAT3oI79eSbGEbcJpr6BD8kyDiVt+G0/hXosQN4NFXKlfWIfsIs0BHODVok1/IGnKFHJYIquh8Xo+2+bkQNTGgWmN/fZ0Y33LSj6lr1GyV7mWIKg7ZTRZPGuhF/zjRNcQ1UPtSYgnWQxSs0yrVhwNDcdGMNSNe2JT3WuzbAM3HykyAajS3Uphf6STKEqx
 Las9EnmnhA/lyj9Uj+JoY7SVgVmGLl46Rm2u98sbkap2lzAdKBG4r6LgulQOSSjQv1GWdQ0jtDUK/mAaqM1Uqjpu4k3Rvfvxv7YTxLSK+wN3E5jVIzmF23uZ7hiH/sVP49D7tvoKp4S8b1LuvRlivVB/algbhcFITYVXvDpLzpDfplR2uD5V4XJFxpjmIpLc9Y5sB2TpBRix7Bme6GZIq+06v3XzNeTcA4obQIKxrnT4C2JpOqD92dbmSX8MGazly5EsZVMvSU1f4RZwyu8iQXbVdeLlZrjuTT1jrY1uk5c7iZ7RsvhhluqAkq4JpVQAg7RJFtSu+xgJ8Pv6O1j5DkLxT8mkbfyRW5DrQmG7hiDIjCgBsADbjuof6YHLGeV6a5Q1Smx9joUXPpdaaDx97A/Wq00oJkdR7ZYuQRfS533JtxO1erduqWOYIt3wh0wpbLuCNIYkwxbswbikCUu2CDCS+Q+7rgVtfRcm+SOcdKPRlZ/rE7wNVUEE39KTS5uvUKN1PUnkloPkyzhyGQ8qkouEjJ3H/VXdqG6asSRiw3ecMlBvDDt8dDhBHXMwZ2Cajzjr7/76T+IavqPYvz6r7//E/3X3+N//h/0QozbjPgPiir69P/8X3/9F/yv8b/827/++98WItPu5/Hvwd8YPf5bp/2/lX/T/+Of/0MJ/lYTa+L/Ef+d9vN/3/2T6P/+jyTzu/evf6U7vxN7B6pJkRtAF6jUr8I+P8RsP/ptGhfqFk+pQ/DgAy6NJtRYJdXmp4gK7WLqLKJ+MaKhGjOojvL+SnIWrkpy0SLHDe4QuyNzaEA15mLMCcmE8Em+4HdOihW4/ZWuppJEmzeAwcDtv7MuLc9y2V5atvxXNe3S4DUMt5/Qy2LM9kSYKiVWBuKlfp4nxTntpuW03JbIlkiRvBXmT23g1I2OYe6IizUHPIq6zm6mbfsbteKmi/sg9J+ocQBMctGFO7iljo8TPN+z3jxw4do+ZwfqoR9dkN
 TKHyM305GpTkfhcHexVkPVGEbUOjuo9f0UMPHBFlGEx0SLvJvVRKTwW7PSew5oPme+E42+frJa9cGt2njS3dK5kIif2eYbhuSEQXEqMVfUjhGIuin0G0/W5ezJyJQy3SpMLai4M0JUWb5u1k9tny5bd1pPwYBpQuDCXZl62xg4CdVEAtflXHs6JKmP/pH6mOl796Lgopj0o8d5kKh00hxG3OSdEE/QBo9Hgr8JJqAeLDwJohG5j/DGh61Rc/+tf22/8kEnxHNCEjo0ElvvGfESZkqmz2BDcKV1H1buSkhkdg7p1IMGs2s17nYjpblrWuE2K9WEO/hcRp5e9oOF/QBmOaDtgil+oaU6szPrdwW65fOB0KUTsVUn7LFU7J8e6cxJIl9+FHw5MQMzuQJ+4oxMH3iW/5GK+hWuG0T+gTLs+fAjdtUd58TmIUq04EeyRCYCjkldow234aIgR5bqwrtZosZ+6YEqAmDqatJ9lWasz4IquKALPtd92hGI3Z2BdzzZue+REl1Om4DIWD+RrtUTOJLI+S0jHowXXdAxsGLSd40zYNuEUlOGhrwL6c7tcOtUOvpJCP7QBQS19H+GvZn05ewjlVLz+IGKoC9TyfQjLMBNmXCuqqtTdOSukZW48B0HqgSTCBrBnlFvF4CG2Su7yFzqmJFURK3UmTT3ru050r0ptUpMilYnBJWfl2Bv6kPlUuE1kxxpdzui9AubsR2N2boVSu81OulAwBqoSr1LZ0LLYOomyZHmjqnXlP72s8LnDouEJjtodBvdHaG1jMySYO7crWd90MpCRyCG14vb5IE7Arupw/y/RcCm/Tm3zK6zYj8PYNaGldiUfkB/LHWcmf2lVM+mwyU27a0qq2tscrQ/vzBjN26DnntIrOyGizzXK35yKQdYnUABkyN4saz3WD/viF+eCcsXnIajdWYJWaYHRstIis9CS+tqnFGmz2j5uzfr3Z4prqgK4XOT/PyftvjZqIm8lhkfxJ7
 Ol3CJF1piYBGAG8wtAk56Drw1YwmOpcz+NdfkSpSLplRXLXHL0Rquj6YW/gabqgK7Dgr6NwtH0B/AN7XrN+MVJ6AmXmUuqmQulrNNYPmH0RoDogydOKLo/QbfYNARSQQKISRCzRXU+q9WWJFL3LZW6u34CkeG97xC0NNGaJ0bvK6SnZS3zPskr5EtuCgjMWR5o2x5BqhKmDWJPRe7JMEOyRb5uUKlHaGVtq5ivSOaSliSXp9SQm2qk8MRJh10MAp9QQ2H5t59J8rjiwSZtoIfMGjlLPVNdYl/LBR0AO6WLGDmkLkIPRE45Y9MftdAK/yNu1Hn6tzOQTesgQ+8fSzB19wO91vCnO23vOWQdwJ63SJrYjdfKFW6W281PKs2k8iT9ai1cgJ4sa3xqdvmtxR8/+D1B8AKc2u+6JftryRhMWSQtoSBgIyyQGyxcnELuAasXN12oSriU4RMz1DD6RL0TSV+om7i1Yt+jEE/jnawM8cX/UhN4nkiv/w9eALrzNhXuQfOzFL0Fi6SjF7/4Qn8rLYBoa85cvgAnkCEBP+HPbEnquVXCZsMS/yzYw2Vru60P/+nJPYKkzZFjmbykzUoEqV836T5q3fP/L383dF82tx18/AZgZczMAgyeWYKmSZIqtHL+e+O4ZRcq9VI3g/qPeCoiK4pcgEqdbS0S/Be54sbVQOuJVPNBblIghzeasNu7h/g+Sz1IdhI5lCwq1nUb3Ji4OCIcqQZqtqJ5w7rXrg/DA9IgVmEGhDgGecEwnCTHffXcXs0V3OCEVzYDKS1vp/oX+ng+6XVU86UjA6FMO2RXOOOrqY1GgPvrAk9HV/BXtCu5RuwF8qgdGDLsBcui4E33ymdBip1X8uKyhIWT8qNRDsXz+gvO9UiEC0d8RG4Tf2x8H4slljgHtCBcxHLTWOYJm5H/fCPCzOgf9qgOUxTRZ0Pc6ha5yLuLVT9ntvIa6gacE99mCovdUumTQdRP4RPsS9129eEe2uS
 vvGh0bV4Y3QPPhPZMqhZWSMa5R0Hc1SGO4IVOQc0FrirlibTVfKRrYkD8kz3b+X65/QkUNaZdrdl3mCap0Hf3YcCw/LiouJYNbqz88UqeDYv93yO7vvXtgl4XCyAO4ODkY6W+83+LZU//p3/zXNGGrUKClCiOnL27iJZbNWDF02XXAOeFlB7IaADoMH1Yqr+UP9biyZDEa/iJt4MDeIz6GKTdLVBfWGVtRN4fdT2rgReX8UXwF2zOrradm4J0nyTgdPnai3RvzpZvCKDUqjOwD/QA6EDaMCLewX6QWYVnHY1sx1bd8ovYnPm1ZvPH+rE20lWjOCnZ66/xDt0QAl15FjfBcZp+i9OU0RNPQ0t3x2pSNWo8eiYudwsnuP1Hq6iH1LJCJynkYsfgJ0p3pF6SoQk2l+jqE8CPk+ziGJRSKjs+W5AO185umPdkYzlK4wl7TC9NxyyDP7ZoyYVoXiuS6SjnInlLWrwz1i8bGTKXX0AVQWkSfIlglW3zRJRJ8bg5VgE6ZEnqNu9B++0GNQvDQJvFize4ESNKBJP+8vA3LM4AX5SIBq08Mob+7QMTCZx4nwP/64+4BnlZC+8WtlP/CXw6t1PwMwkJ3jhP1FiXLhDF/3I6FGUzO2DSi9ABxKyyL9paZxSEz40ZCPQToDAJu1959k7QdbVxgB4icsu2s4zsTPJhcEDo+N1GX4zSk/wriRh8AqwL62972i9HJHd1ydaLXVzvKvOfGGw5RVcUVMiKXFH4APdkQU/dc5BX0YfKTNZYXCW9mb8bc8mufoQP6BbdQmT99ZjoYfr/go4TgQX9IDgztim7wyFeGMfbNaeqj8Dzs38pgcqwSv2hbqB3oSGKWKy+sesY7p57wAHldqE6NDudk/W7s/zjrK4rZFlFvaGxnSZdHbc1y47qDN6xkoK8O3bfr2j41dlJZ71rB4dlDqapPFa8N6xBrprUdtenUCHwxKNhw1uuTBh+9uU45k4REpQABN2bAO9D
 SLqoIL26gNroWgup5pUMxHUNSq4Gyz47vBPvilpo5f9OYI2ddAqTqmnxXERxQJ3UK8fHbVE9HagHi3+tqNRoNsArdmAxHA5LwtQo9ZAaNKUTljnokljo2x8scqVpEEIPc01fPCdHOCg0DeWBz8D5TVAAfx8aRH5X2ZYNI3ebKDZdeJ+oBDAxmRqJ30Eh2/DaeAy5diVNMpEDmXiPDsGTzBLXy8eVDdJoIafgx/gxMyQi454QrW56nCyeELgSuNNEmYkflF+t3CZQOVRWjKhIuCclmQSlAXT3+4JGG75B4t/5hQ+ldMP4LsAW6z3XmU6IJJwpnGVnsgUZhoY1fZlwTR8wSU7xRejf2uCx9Z5trVTRRJP9KnEb134dEieil6eCOGWgboI7xsqsqM99jfJLTePjygKlH2CVxxsse9QRzTBFjD/Kjqitr/CCTBt/SJ6nLxz7cKP9pFqBpp0lN5y+adKNsZjrPuroemZauH9aTTFD3EKHW8S55XBLFQAt1jgxTQCTwxmx/JyfsZDN1RroN3VaxpSenpIX7K+ZbL8VdlQDcI4Cbzg3QJLa9yVqNxUelu+EtxLVqeekaAvSJkO6sSVqbUajxqhKshNpvZqoeApF0k/0P0ikkwUcbdwc4A1ejN7Oo0O15kG7hTMoK3hZRBCX7YYeLW0wvcXx/18n/u37yLgzBYVBUvORGli+sfRcX/74uD6P4hq+7xu54TlWJLFzT63uwUDwuEDdOjJQqx7JV+ZjaEAPi7t0MMrR4Q8Rkf18uxD6RK0RKh0hL8YU+DeL97i4pa5ZSyAfXKwZRS/8gXcxdZXm62RBDj8U3sN8x95b5PpPs/mCBKYvpaA50pN5Ct/499AFTtwQ5vgeSh+NHrKIi4NVpwM/XzRaNfJD856lPE6M21zWPguFsH7jbLVyEDfRmt4VwrhCJ5VTYmcSPfGgO5clfN+vbaDZ7sakU5+2vZ2WCDY031NxJarVytfDDVtiafcTGO2rJ
 /taoL3zChN2qmjxofczTOYQPPVQPh0JVtYgdUQINcSiNEEy58UdYXX1MpWUCEBx7LbcGtAm8XWRQTVOaoV3ySri4RShhs/B/0m4jX6OAwXOvcA09bNSG4czEGv/Wey6V/jbTCNTW6awXdNTcA1GsPe1E9fZdGl7R0vyoVpIdJtfC6d32NNErrvq/R+d65VG+YOwRXppXxOCYyGNSf1K3x6VxAW/vtz4EC1SgCOSPdN62sLsoIzuDfg8GwZAbquVO8HIuFP/ToVoeUB7nnwMF35a1wK1tI6fkrqFKhQdeJpwyls0pIy8AZde3/6LUUbFaYJthyUJSU/kqDXTLQElnn0Jr4B2RVghNrmNmoEn7pXIeshPguXVsvwoTdmClq49JJU3LWhHyWTrJL9bRP6VKv3tZoA/th77p5Jw++OEENvyvWy/pNeExiDUVQaXIRGh8xySZTI36yueFaSXo1uJY0RnXYgEOoWWOJHeaVuX/bGNhHsh2yinznl/++NJcE9j6fBPRcBdq9hb8awNw8U7Bl6GM7x69EDOIIbX/npZ++amlHR9L/35mE/2Ss4gb0xCcY4VyTFLRE796vHysLAamqcyO+aFQyJIDBNslbH2/MrAvZiSEIedc/cqjmv4fbda2pXbv+F5a2szSsdkm9noiNURXt8edUhGUF6fSZWd1IJaXKFwD+49R6eCXD4Bkef7j9tRtNMVgW8BhRz/Qpy1TmeYk0doyjZoJSbePOReVHgkFsCFuQJ+Lgc4BxeAsK/cOiNDRmdNw0ctYhn/nQ498dYI5znzGLoJi1rav7Cn88rL3wLePVtDK5gl77Tki3gHEsIAQ2+IKgarj7Y8W1IQzV5V9N+0TjLqbg68WfKcOmBCOj3JkwJhVIkwDhc+JorXuZEPMEh0vvH3x7iqf+VAwXgd4diZiaJD1zHL9Snx6Wfg4IugreyhabQkcir+y5XgDtdx3Avs7lkeeCBwDvZoTUCXx5QrZkcEqWfYEi
 EYRs/EphmRALSNGR1Iclgdr5VFoELpzF4++f35w3/j0t5ucW3n2ch4PQCLuUXupsPRR7UA5FjSKrMtPcKAZJfagO4lGE7FH3YKMjorpK0ZxAv+i2JkJhtAMWWWFej4RhPR/cJ3DxwocCvXDi4SGZU4cu+K32XndiFWgopAl+0GApcwf1XvymJcFs39jExIBO4yUjU9MExBLQYc9H+W7+IgdESPRpciT+rKZPebVtaVq+1GYO/5xTAL3HASjNTGIgMvdjWbgc7JvdE1zIFpuC0U9ESiZyzBixzxWxj4Kwh8My34q+FK3KNLtmsA1qyrmKSNQOXCPUZd+ONelBTvFoUI/CYsqa/RhtKiyMf2CgSFqEPk59Y3uqnlZ8gFpswfSYyko23yVZYxzKGxGm49Zqxg1l8oz5Ra9XaRwHkuxepmgyhm0SoNy2KlbcEqK+9QqS9PNx9Ihm9U7gsR55SSJ1FBDNnkuWKxIZ0SDpXuOGwZdoUbOMDPHP4vBAgz2VlSEJAHZGJVbYIg7l/FO5KfIVvxC8pPPxMGcNMoevFDeStt2iqztE10n2TA4dgJH76YS9HDhKHD3iCx6ieFX84BAI3QQnngh76f5ruPQVbr5qZmck/5UjDc26lfrOvUBWy0Ogl8bCoOkMOns81TnC3cuUS9KW8+9A+fe3XYZOFUPG1u5epSSmDLw0s5s2F0W30ANeo+zJkJQz9SPZgzwYpEoktofhGVfmLOAB20boCbW1QWq/NpET/hnMecw/uSyAH4NJc3ECOU4nnkK1fj3S/i5dwb3R7k00AqQQUwt7Ie1qV0aY/VQX0J8hLPy7eBNXMHYZYDNxHZ2Qh6AuXJxq+AeRec/Q+JLhZV6hpXwQEzw7bf5v9uUf2vpq3qlhmy0IIGTkwYdCfSAFmqbdo+3XvDTDjFJde0mbeQLcn2n31xaAqJ0ixO/CLsT4I4G4DoncVTgRGNBtsCcjISWT+oeXZ4Iedw/8OsJI1aPnNKLX/
 60VvcZb94uasRxCkqlPQ11u1Sa2hHvB80WQENxVyzjns0/PiEByyil21Te6oisk3mNCEMrhouCFO3yEZTHHOCMy9eb/4Tmi8cVf3Lf7P53SY2hX3PSN033As3ETIMLHWumWEO9JXHA2y2SIBlIPpLGG2qvNsCIlIr+B1SWAqRKm2w6Blf7U+zCSBwJrfHG5i8J5Gax/cVonMlon7aHJX/gSvucIncRP93XCqkv7D8IFKFsLiBgHqUpXhE3pYjEcV1dk/JD9zFVCfEaQIVX8Jmfz7IIofcBKQ4OaG+C3xC2veX9CD+iAFXDNaGg9eTVxvkbJRJlW4Nk9Wk13kn696jWppRDe/8pDrYMO9ZyxZ98ReKSz9kWKLLyk2zCZgAniCkLJVX3n1M9DYbomyahWiv/KixRIV9hj/oFz87I+HLznbPTjpa+D+bZQnMuRsljTpv90vQUt/pK7jCFnA30B/jtroSF2/m/gpWn1aQs5WeA6ghzF8SdqWI20fghdSeDOCSCmLgTkfaGgGDmw7nHFkRzGtag57IHS2na06I+gzEphXo1w/Zx2BM/jKL2nZoFjHggtFQjYi8nSVRSXIE58RPbBObXk7uuIL9+rs/5Zo7suJInEUxgsiZZAWS25iBtpEiZeBgDtghEoAE0sjcayNq85M4tbu/LF5h51335PsGzQ09O875+vUS89lkWMyNOFoip2PuyWyMP/iU2XIZdfCCJNDjebDoBLQdpy7QQZC7s9c0wjHJervQNDu2jWzBW5MSAJMr7bP+Iv92BkS/GGgzjEn7MF1IRKFwwzbjbS4/slGOmhx9cZrFu7HSEefojNv3r0UaKfKOWzXsq1zEugbzlMDFsacRJJI/iJlK3vtkZ+PLZIVMFlKA32wbq2Kd5T0uCLZ1CPkAfCdzkz2EYscjDcZq2AWfziN2covN4kXE1lQXPPLTNM1xx3tbiepcO/t3SWm4w87qfh99SL0ZnY+LKFPLPeXVM2mIIoVW
 t+9Nk0I7nY4O79iGYqxZ8RVz289an6NVdJWnSKZvJQCAuHNiVaDxPAFoH392t9wot5t0/qmU95eEWNbU2udUW5sN9JVqcYlvAIfLeYC33oUzzxZgSktsv21mA7Uly1FA5VnoJFh6N244Wmv3YJGFv/TCPryaw+ZORlpZjQdq/2DYXr3EZskfed0G61P09ipTKmlTQ1067Rg5+PAk5FlQ9e0SWbGf2B/08kqymOTMVOznsALHHNFH4LFRKl2F/NOiYFl9khNHnSu9Ak5sq26Ynl/i2fdTle29Y1ugqmR5Yj4YT9pvslFyYCbw0mNFr5rVQm1LvkG27QMq9ph3t8fmn6r6SQ4oSbr5tz+J1kIawGzDxb6VYOvvWhobDTXfBeNv3b4aNm5XUinsCGqG2q/45m3+LoCOsddFceYhRx1Tsss9PLdPfJdErFMjYd3gddjiP0+XQjcRadZP6bwNLySvunFf20Czy6JqdEW2a96KxdYdOryBv1BjbuUq2yCHeh+6sk7fGmmPi50pe/1l5TyPe5oHW9oPnhPswLyf2TFDdCyYlhwBCstv5C1HwlW7xWoGT9XZt4qVj5WryLPLLD6h/5cMLEjWzgCeAIKNsLak92aBqBsHl4AJwl2N4jfvbSkBExGimv0nFvv09uDScQbjx+w4kPQjgjlW+g9ws9VEJvI2k8N6XxVu0uIwovgTFdunG24gBtaDi+y1YLQwZ8mwbip5fVlO3k0n0AEr/ETbtu8Vjkm+nNSiEb7X/3fMjBL5A8PdgG+/FnbexbFFExmEfetXAnisEKy5z44WVPpQZjSy/jzeGn4yDRsFGqhh87QPaDBWhlo37IFbe/C0xynS91d2tP/AJoJS0sVF6iwAAAAAElFTkSuQmCC");
+}
+
+#menu ul {
+  margin-bottom: 40px;
+}
+
+#logo {
+  position: fixed;
+  bottom: 10px;
+  right: 10px;
+  background: rgba(255,255,255,.1);
+  font-size: 11px;
+  display: block;
+  width: 20px;
+  height: 20px;
+  line-height: 20px;
+  text-align: center;
+  -webkit-border-radius: 20px;
+  -moz-border-radius: 20px;
+  -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
+  -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
+  color: inherit;
+}
+
+#menu li a {
+  display: block;
+  color: white;
+  padding: 0 35px 0 25px;
+  -webkit-transition: background 300ms;
+  -moz-transition: background 300ms;
+}
+
+#menu li {
+  position: relative;
+  list-style: none;
+}
+
+#menu a:hover,
+#menu a.active {
+  text-decoration: none;
+  background: rgba(255,255,255,.1);
+}
+
+#menu li:hover .cov {
+  opacity: 1;
+}
+
+#menu li .dirname {
+  opacity: .60;
+  padding-right: 2px;
+}
+
+#menu li .basename {
+  opacity: 1;
+}
+
+#menu .cov {
+  background: rgba(0,0,0,.4);
+  position: absolute;
+  top: 0;
+  right: 8px;
+  font-size: 9px;
+  opacity: .6;
+  text-align: left;
+  width: 17px;
+  -webkit-border-radius: 10px;
+  -moz-border-radius: 10px;
+  padding: 2px 3px;
+  text-align: center;
+}
+
+.stats {
+  display: inline-block;
+  margin-top: 15px;
+  border: 1px solid #eee;
+  padding: 10px;
+  -webkit-box-shadow: inset 0 0 2px #eee;
+  -moz-box-shadow: inset 0 0 2px #eee;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+}
+
+.stats div {
+  float: left;
+  padding: 0 5px;
+}
+
+.stats::after {
+  display: block;
+  content: '';
+  clear: both;
+}
+
+.stats .sloc::after {
+  content: ' SLOC';
+  color: #b6b6b6;
+}
+
+.stats .percentage::after {
+  content: ' coverage';
+  color: #b6b6b6;
+}
+
+.stats .hits,
+.stats .misses {
+  display: none;
+}
+
+.high {
+  color: #00d4b4;
+}
+.medium {
+  color: #e87d0d;
+}
+.low {
+  color: #d4081a;
+}
+.terrible {
+  color: #d4081a;
+  font-weight: bold;
+}
+
+table {
+  width: 80%;
+  margin-top: 10px;
+  border-collapse: collapse;
+  border: 1px solid #cbcbcb;
+  color: #363636;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+}
+
+table thead {
+  display: none;
+}
+
+table td.line,
+table td.hits {
+  width: 20px;
+  background: #eaeaea;
+  text-align: center;
+  font-size: 11px;
+  padding: 0 10px;
+  color: #949494;
+}
+
+table td.hits {
+  width: 10px;
+  padding: 2px 5px;
+  color: rgba(0,0,0,.2);
+  background: #f0f0f0;
+}
+
+tr.miss td.line,
+tr.miss td.hits {
+  background: #e6c3c7;
+}
+
+tr.miss td {
+  background: #f8d5d8;
+}
+
+td.source {
+  padding-left: 15px;
+  line-height: 15px;
+  white-space: pre;
+  font: 12px monaco, monospace;
+}
+
+code .comment { color: #ddd }
+code .init { color: #2F6FAD }
+code .string { color: #5890AD }
+code .keyword { color: #8A6343 }
+code .number { color: #2F6FAD }
+
+
+#stats {
+    z-index: 1;
+    color: #BBB;
+}
+#stats em {
+    color: white;
+    font-weight: bold;
+}
+
+.file-title {
+    width: 80%;
+    margin-bottom: 0;
+    font-weight: 100;
+    letter-spacing: 1px;
+    border-bottom: 1px solid #EEE;
+    cursor: pointer;
+    padding-left: 15px;
+}
+.file-title:hover {
+    color: #444;
+    text-shadow: 1px 1px 1px #CCC;
+}
+
+.error { background: #F8D5D8 }
+.count { font-weight: bold; border-radius: 3px }
+.pass .count { background: #BFFFBF;}
+.error .count { background: #F8D5D8; color: red}
+#coverage { font-size: 12px; }
</ins></span></pre></div>
<a id="trunktestsquniteditorcoveragejsreporterjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/coverage/js/reporter.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/coverage/js/reporter.js                         (rev 0)
+++ trunk/tests/qunit/editor/coverage/js/reporter.js    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+headings = [];
+
+onload = function(){
+  headings = document.querySelectorAll('h2');
+};
+
+onscroll = function(e){
+  var heading = find(window.scrollY);
+  if (!heading) return;
+  var links = document.querySelectorAll('#menu a')
+    , link;
+
+  for (var i = 0, len = links.length; i < len; ++i) {
+    link = links[i];
+    link.className = link.getAttribute('href') == '#' + heading.id
+      ? 'active'
+      : '';
+  }
+};
+
+function find(y) {
+  var i = headings.length
+    , heading;
+
+  while (i--) {
+    heading = headings[i];
+    if (y > heading.offsetTop) {
+      return heading;
+    }
+  }
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/coverage/js/reporter.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorcoveragejsunderscoreminjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/coverage/js/underscore-min.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/coverage/js/underscore-min.js                           (rev 0)
+++ trunk/tests/qunit/editor/coverage/js/underscore-min.js      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var 
 O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t
 ,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.
 isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)
 return-1}return n.index<t.index?-1:1}),"value")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail
 =w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);re
 turn r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(argument
 s,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=
 function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.
 call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n
 .source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Arra
 y]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.
 random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N
 =0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p
 +='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"]
 ,function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/coverage/js/underscore-min.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorexternalpluginsnoneditablepluginjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/external-plugins/noneditable/plugin.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/external-plugins/noneditable/plugin.js                          (rev 0)
+++ trunk/tests/qunit/editor/external-plugins/noneditable/plugin.js     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,539 @@
</span><ins>+/**
+ * plugin.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/*jshint loopfunc:true */
+/*global tinymce:true */
+
+tinymce.PluginManager.add('noneditable', function(editor) {
+       var TreeWalker = tinymce.dom.TreeWalker;
+       var externalName = 'contenteditable', internalName = 'data-mce-' + externalName;
+       var VK = tinymce.util.VK;
+
+       // Returns the content editable state of a node "true/false" or null
+       function getContentEditable(node) {
+               var contentEditable;
+
+               // Ignore non elements
+               if (node.nodeType === 1) {
+                       // Check for fake content editable
+                       contentEditable = node.getAttribute(internalName);
+                       if (contentEditable && contentEditable !== "inherit") {
+                               return contentEditable;
+                       }
+
+                       // Check for real content editable
+                       contentEditable = node.contentEditable;
+                       if (contentEditable !== "inherit") {
+                               return contentEditable;
+                       }
+               }
+
+               return null;
+       }
+
+       // Returns the noneditable parent or null if there is a editable before it or if it wasn't found
+       function getNonEditableParent(node) {
+               var state;
+
+               while (node) {
+                       state = getContentEditable(node);
+                       if (state) {
+                               return state  === "false" ? node : null;
+                       }
+
+                       node = node.parentNode;
+               }
+       }
+
+       function handleContentEditableSelection() {
+               var dom = editor.dom, selection = editor.selection, caretContainerId = 'mce_noneditablecaret', invisibleChar = '\uFEFF';
+
+               // Get caret container parent for the specified node
+               function getParentCaretContainer(node) {
+                       while (node) {
+                               if (node.id === caretContainerId) {
+                                       return node;
+                               }
+
+                               node = node.parentNode;
+                       }
+               }
+
+               // Finds the first text node in the specified node
+               function findFirstTextNode(node) {
+                       var walker;
+
+                       if (node) {
+                               walker = new TreeWalker(node, node);
+
+                               for (node = walker.current(); node; node = walker.next()) {
+                                       if (node.nodeType === 3) {
+                                               return node;
+                                       }
+                               }
+                       }
+               }
+
+               // Insert caret container before/after target or expand selection to include block
+               function insertCaretContainerOrExpandToBlock(target, before) {
+                       var caretContainer, rng;
+
+                       // Select block
+                       if (getContentEditable(target) === "false") {
+                               if (dom.isBlock(target)) {
+                                       selection.select(target);
+                                       return;
+                               }
+                       }
+
+                       rng = dom.createRng();
+
+                       if (getContentEditable(target) === "true") {
+                               if (!target.firstChild) {
+                                       target.appendChild(editor.getDoc().createTextNode('\u00a0'));
+                               }
+
+                               target = target.firstChild;
+                               before = true;
+                       }
+
+                       /*
+                       caretContainer = dom.create('span', {
+                               id: caretContainerId,
+                               'data-mce-bogus': true,
+                               style:'border: 1px solid red'
+                       }, invisibleChar);
+                       */
+
+                       caretContainer = dom.create('span', {id: caretContainerId, 'data-mce-bogus': true}, invisibleChar);
+
+                       if (before) {
+                               target.parentNode.insertBefore(caretContainer, target);
+                       } else {
+                               dom.insertAfter(caretContainer, target);
+                       }
+
+                       rng.setStart(caretContainer.firstChild, 1);
+                       rng.collapse(true);
+                       selection.setRng(rng);
+
+                       return caretContainer;
+               }
+
+               // Removes any caret container except the one we might be in
+               function removeCaretContainer(caretContainer) {
+                       var rng, child, currentCaretContainer, lastContainer;
+
+                       if (caretContainer) {
+                                       rng = selection.getRng(true);
+                                       rng.setStartBefore(caretContainer);
+                                       rng.setEndBefore(caretContainer);
+
+                                       child = findFirstTextNode(caretContainer);
+                                       if (child && child.nodeValue.charAt(0) == invisibleChar) {
+                                               child = child.deleteData(0, 1);
+                                       }
+
+                                       dom.remove(caretContainer, true);
+
+                                       selection.setRng(rng);
+                       } else {
+                               currentCaretContainer = getParentCaretContainer(selection.getStart());
+                               while ((caretContainer = dom.get(caretContainerId)) && caretContainer !== lastContainer) {
+                                       if (currentCaretContainer !== caretContainer) {
+                                               child = findFirstTextNode(caretContainer);
+                                               if (child && child.nodeValue.charAt(0) == invisibleChar) {
+                                                       child = child.deleteData(0, 1);
+                                               }
+
+                                               dom.remove(caretContainer, true);
+                                       }
+
+                                       lastContainer = caretContainer;
+                               }
+                       }
+               }
+
+               // Modifies the selection to include contentEditable false elements or insert caret containers
+               function moveSelection() {
+                       var nonEditableStart, nonEditableEnd, isCollapsed, rng, element;
+
+                       // Checks if there is any contents to the left/right side of caret returns the noneditable element or
+                       // any editable element if it finds one inside
+                       function hasSideContent(element, left) {
+                               var container, offset, walker, node, len;
+
+                               container = rng.startContainer;
+                               offset = rng.startOffset;
+
+                               // If endpoint is in middle of text node then expand to beginning/end of element
+                               if (container.nodeType == 3) {
+                                       len = container.nodeValue.length;
+                                       if ((offset > 0 && offset < len) || (left ? offset == len : offset === 0)) {
+                                               return;
+                                       }
+                               } else {
+                                       // Can we resolve the node by index
+                                       if (offset < container.childNodes.length) {
+                                               // Browser represents caret position as the offset at the start of an element. When moving right
+                                               // this is the element we are moving into so we consider our container to be child node at offset-1
+                                               var pos = !left && offset > 0 ? offset-1 : offset;
+                                               container = container.childNodes[pos];
+                                               if (container.hasChildNodes()) {
+                                                       container = container.firstChild;
+                                               }
+                                       } else {
+                                               // If not then the caret is at the last position in it's container and the caret container
+                                               // should be inserted after the noneditable element
+                                               return !left ? element : null;
+                                       }
+                               }
+
+                               // Walk left/right to look for contents
+                               walker = new TreeWalker(container, element);
+                               while ((node = walker[left ? 'prev' : 'next']())) {
+                                       if (node.nodeType === 3 && node.nodeValue.length > 0) {
+                                               return;
+                                       } else if (getContentEditable(node) === "true") {
+                                               // Found contentEditable=true element return this one to we can move the caret inside it
+                                               return node;
+                                       }
+                               }
+
+                               return element;
+                       }
+
+                       // Remove any existing caret containers
+                       removeCaretContainer();
+
+                       // Get noneditable start/end elements
+                       isCollapsed = selection.isCollapsed();
+                       nonEditableStart = getNonEditableParent(selection.getStart());
+                       nonEditableEnd = getNonEditableParent(selection.getEnd());
+
+                       // Is any fo the range endpoints noneditable
+                       if (nonEditableStart || nonEditableEnd) {
+                               rng = selection.getRng(true);
+
+                               // If it's a caret selection then look left/right to see if we need to move the caret out side or expand
+                               if (isCollapsed) {
+                                       nonEditableStart = nonEditableStart || nonEditableEnd;
+
+                                       if ((element = hasSideContent(nonEditableStart, true))) {
+                                               // We have no contents to the left of the caret then insert a caret container before the noneditable element
+                                               insertCaretContainerOrExpandToBlock(element, true);
+                                       } else if ((element = hasSideContent(nonEditableStart, false))) {
+                                               // We have no contents to the right of the caret then insert a caret container after the noneditable element
+                                               insertCaretContainerOrExpandToBlock(element, false);
+                                       } else {
+                                               // We are in the middle of a noneditable so expand to select it
+                                               selection.select(nonEditableStart);
+                                       }
+                               } else {
+                                       rng = selection.getRng(true);
+
+                                       // Expand selection to include start non editable element
+                                       if (nonEditableStart) {
+                                               rng.setStartBefore(nonEditableStart);
+                                       }
+
+                                       // Expand selection to include end non editable element
+                                       if (nonEditableEnd) {
+                                               rng.setEndAfter(nonEditableEnd);
+                                       }
+
+                                       selection.setRng(rng);
+                               }
+                       }
+               }
+
+               function handleKey(e) {
+                       var keyCode = e.keyCode, nonEditableParent, caretContainer, startElement, endElement;
+
+                       function getNonEmptyTextNodeSibling(node, prev) {
+                               while ((node = node[prev ? 'previousSibling' : 'nextSibling'])) {
+                                       if (node.nodeType !== 3 || node.nodeValue.length > 0) {
+                                               return node;
+                                       }
+                               }
+                       }
+
+                       function positionCaretOnElement(element, start) {
+                               selection.select(element);
+                               selection.collapse(start);
+                       }
+
+                       function canDelete(backspace) {
+                               var rng, container, offset, nonEditableParent;
+
+                               function removeNodeIfNotParent(node) {
+                                       var parent = container;
+
+                                       while (parent) {
+                                               if (parent === node) {
+                                                       return;
+                                               }
+
+                                               parent = parent.parentNode;
+                                       }
+
+                                       dom.remove(node);
+                                       moveSelection();
+                               }
+
+                               function isNextPrevTreeNodeNonEditable() {
+                                       var node, walker, nonEmptyElements = editor.schema.getNonEmptyElements();
+
+                                       walker = new tinymce.dom.TreeWalker(container, editor.getBody());
+                                       while ((node = (backspace ? walker.prev() : walker.next()))) {
+                                               // Found IMG/INPUT etc
+                                               if (nonEmptyElements[node.nodeName.toLowerCase()]) {
+                                                       break;
+                                               }
+
+                                               // Found text node with contents
+                                               if (node.nodeType === 3 && tinymce.trim(node.nodeValue).length > 0) {
+                                                       break;
+                                               }
+
+                                               // Found non editable node
+                                               if (getContentEditable(node) === "false") {
+                                                       removeNodeIfNotParent(node);
+                                                       return true;
+                                               }
+                                       }
+
+                                       // Check if the content node is within a non editable parent
+                                       if (getNonEditableParent(node)) {
+                                               return true;
+                                       }
+
+                                       return false;
+                               }
+
+                               if (selection.isCollapsed()) {
+                                       rng = selection.getRng(true);
+                                       container = rng.startContainer;
+                                       offset = rng.startOffset;
+                                       container = getParentCaretContainer(container) || container;
+
+                                       // Is in noneditable parent
+                                       if ((nonEditableParent = getNonEditableParent(container))) {
+                                               removeNodeIfNotParent(nonEditableParent);
+                                               return false;
+                                       }
+
+                                       // Check if the caret is in the middle of a text node
+                                       if (container.nodeType == 3 && (backspace ? offset > 0 : offset < container.nodeValue.length)) {
+                                               return true;
+                                       }
+
+                                       // Resolve container index
+                                       if (container.nodeType == 1) {
+                                               container = container.childNodes[offset] || container;
+                                       }
+
+                                       // Check if previous or next tree node is non editable then block the event
+                                       if (isNextPrevTreeNodeNonEditable()) {
+                                               return false;
+                                       }
+                               }
+
+                               return true;
+                       }
+
+                       startElement = selection.getStart();
+                       endElement = selection.getEnd();
+
+                       // Disable all key presses in contentEditable=false except delete or backspace
+                       nonEditableParent = getNonEditableParent(startElement) || getNonEditableParent(endElement);
+                       if (nonEditableParent && (keyCode < 112 || keyCode > 124) && keyCode != VK.DELETE && keyCode != VK.BACKSPACE) {
+                               // Is Ctrl+c, Ctrl+v or Ctrl+x then use default browser behavior
+                               if ((tinymce.isMac ? e.metaKey : e.ctrlKey) && (keyCode == 67 || keyCode == 88 || keyCode == 86)) {
+                                       return;
+                               }
+
+                               e.preventDefault();
+
+                               // Arrow left/right select the element and collapse left/right
+                               if (keyCode == VK.LEFT || keyCode == VK.RIGHT) {
+                                       var left = keyCode == VK.LEFT;
+                                       // If a block element find previous or next element to position the caret
+                                       if (editor.dom.isBlock(nonEditableParent)) {
+                                               var targetElement = left ? nonEditableParent.previousSibling : nonEditableParent.nextSibling;
+                                               var walker = new TreeWalker(targetElement, targetElement);
+                                               var caretElement = left ? walker.prev() : walker.next();
+                                               positionCaretOnElement(caretElement, !left);
+                                       } else {
+                                               positionCaretOnElement(nonEditableParent, left);
+                                       }
+                               }
+                       } else {
+                               // Is arrow left/right, backspace or delete
+                               if (keyCode == VK.LEFT || keyCode == VK.RIGHT || keyCode == VK.BACKSPACE || keyCode == VK.DELETE) {
+                                       caretContainer = getParentCaretContainer(startElement);
+                                       if (caretContainer) {
+                                               // Arrow left or backspace
+                                               if (keyCode == VK.LEFT || keyCode == VK.BACKSPACE) {
+                                                       nonEditableParent = getNonEmptyTextNodeSibling(caretContainer, true);
+
+                                                       if (nonEditableParent && getContentEditable(nonEditableParent) === "false") {
+                                                               e.preventDefault();
+
+                                                               if (keyCode == VK.LEFT) {
+                                                                       positionCaretOnElement(nonEditableParent, true);
+                                                               } else {
+                                                                       dom.remove(nonEditableParent);
+                                                                       return;
+                                                               }
+                                                       } else {
+                                                               removeCaretContainer(caretContainer);
+                                                       }
+                                               }
+
+                                               // Arrow right or delete
+                                               if (keyCode == VK.RIGHT || keyCode == VK.DELETE) {
+                                                       nonEditableParent = getNonEmptyTextNodeSibling(caretContainer);
+
+                                                       if (nonEditableParent && getContentEditable(nonEditableParent) === "false") {
+                                                               e.preventDefault();
+
+                                                               if (keyCode == VK.RIGHT) {
+                                                                       positionCaretOnElement(nonEditableParent, false);
+                                                               } else {
+                                                                       dom.remove(nonEditableParent);
+                                                                       return;
+                                                               }
+                                                       } else {
+                                                               removeCaretContainer(caretContainer);
+                                                       }
+                                               }
+                                       }
+
+                                       if ((keyCode == VK.BACKSPACE || keyCode == VK.DELETE) && !canDelete(keyCode == VK.BACKSPACE)) {
+                                               e.preventDefault();
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+
+               editor.on('mousedown', function(e) {
+                       var node = editor.selection.getNode();
+
+                       if (getContentEditable(node) === "false" && node == e.target) {
+                               // Expand selection on mouse down we can't block the default event since it's used for drag/drop
+                               moveSelection();
+                       }
+               });
+
+               editor.on('mouseup keyup', moveSelection);
+               editor.on('keydown', handleKey);
+       }
+
+       var editClass, nonEditClass, nonEditableRegExps;
+
+       // Converts configured regexps to noneditable span items
+       function convertRegExpsToNonEditable(e) {
+               var i = nonEditableRegExps.length, content = e.content, cls = tinymce.trim(nonEditClass);
+
+               // Don't replace the variables when raw is used for example on undo/redo
+               if (e.format == "raw") {
+                       return;
+               }
+
+               while (i--) {
+                       content = content.replace(nonEditableRegExps[i], function(match) {
+                               var args = arguments, index = args[args.length - 2];
+
+                               // Is value inside an attribute then don't replace
+                               if (index > 0 && content.charAt(index - 1) == '"') {
+                                       return match;
+                               }
+
+                               return (
+                                       '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' +
+                                       editor.dom.encode(typeof(args[1]) === "string" ? args[1] : args[0]) + '</span>'
+                               );
+                       });
+               }
+
+               e.content = content;
+       }
+
+       editClass = " " + tinymce.trim(editor.getParam("noneditable_editable_class", "mceEditable")) + " ";
+       nonEditClass = " " + tinymce.trim(editor.getParam("noneditable_noneditable_class", "mceNonEditable")) + " ";
+
+       // Setup noneditable regexps array
+       nonEditableRegExps = editor.getParam("noneditable_regexp");
+       if (nonEditableRegExps && !nonEditableRegExps.length) {
+               nonEditableRegExps = [nonEditableRegExps];
+       }
+
+       editor.on('PreInit', function() {
+               handleContentEditableSelection();
+
+               if (nonEditableRegExps) {
+                       editor.on('BeforeSetContent', convertRegExpsToNonEditable);
+               }
+
+               // Apply contentEditable true/false on elements with the noneditable/editable classes
+               editor.parser.addAttributeFilter('class', function(nodes) {
+                       var i = nodes.length, className, node;
+
+                       while (i--) {
+                               node = nodes[i];
+                               className = " " + node.attr("class") + " ";
+
+                               if (className.indexOf(editClass) !== -1) {
+                                       node.attr(internalName, "true");
+                               } else if (className.indexOf(nonEditClass) !== -1) {
+                                       node.attr(internalName, "false");
+                               }
+                       }
+               });
+
+               // Remove internal name
+               editor.serializer.addAttributeFilter(internalName, function(nodes) {
+                       var i = nodes.length, node;
+
+                       while (i--) {
+                               node = nodes[i];
+
+                               if (nonEditableRegExps && node.attr('data-mce-content')) {
+                                       node.name = "#text";
+                                       node.type = 3;
+                                       node.raw = true;
+                                       node.value = node.attr('data-mce-content');
+                               } else {
+                                       node.attr(externalName, null);
+                                       node.attr(internalName, null);
+                               }
+                       }
+               });
+
+               // Convert external name into internal name
+               editor.parser.addAttributeFilter(externalName, function(nodes) {
+                       var i = nodes.length, node;
+
+                       while (i--) {
+                               node = nodes[i];
+                               node.attr(internalName, node.attr(externalName));
+                               node.attr(externalName, null);
+                       }
+               });
+       });
+
+       editor.on('drop', function(e) {
+               if (getNonEditableParent(e.target)) {
+                       e.preventDefault();
+               }
+       });
+});
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/external-plugins/noneditable/plugin.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorexternalpluginsnoneditablepluginminjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/external-plugins/noneditable/plugin.min.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/external-plugins/noneditable/plugin.min.js                              (rev 0)
+++ trunk/tests/qunit/editor/external-plugins/noneditable/plugin.min.js 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+tinymce.PluginManager.add("noneditable",function(e){function t(e){var t;if(1===e.nodeType){if(t=e.getAttribute(u),t&&"inherit"!==t)return t;if(t=e.contentEditable,"inherit"!==t)return t}return null}function n(e){for(var n;e;){if(n=t(e))return"false"===n?e:null;e=e.parentNode}}function r(){function r(e){for(;e;){if(e.id===g)return e;e=e.parentNode}}function a(e){var t;if(e)for(t=new f(e,e),e=t.current();e;e=t.next())if(3===e.nodeType)return e}function i(n,r){var a,i;return"false"===t(n)&&u.isBlock(n)?void s.select(n):(i=u.createRng(),"true"===t(n)&&(n.firstChild||n.appendChild(e.getDoc().createTextNode(" ")),n=n.firstChild,r=!0),a=u.create("span",{id:g,"data-mce-bogus":!0},m),r?n.parentNode.insertBefore(a,n):u.insertAfter(a,n),i.setStart(a.firstChild,1),i.collapse(!0),s.setRng(i),a)}function o(e){var t,n,i,o;if(e)t=s.getRng(!0),t.setStartBefore(e),t.setEndBef
 ore(e),n=a(e),n&&n.nodeValue.charAt(0)==m&&(n=n.deleteData(0,1)),u.remove(e,!0),s.setRng(t);else for(i=r(s.getStart());(e=u.get(g))&&e!==o;)i!==e&&(n=a(e),n&&n.nodeValue.charAt(0)==m&&(n=n.deleteData(0,1)),u.remove(e,!0)),o=e}function l(){function e(e,n){var r,a,i,o,l;if(r=d.startContainer,a=d.startOffset,3==r.nodeType){if(l=r.nodeValue.length,a>0&&l>a||(n?a==l:0===a))return}else{if(!(a<r.childNodes.length))return n?null:e;var u=!n&&a>0?a-1:a;r=r.childNodes[u],r.hasChildNodes()&&(r=r.firstChild)}for(i=new f(r,e);o=i[n?"prev":"next"]();){if(3===o.nodeType&&o.nodeValue.length>0)return;if("true"===t(o))return o}return e}var r,a,l,d,u;o(),l=s.isCollapsed(),r=n(s.getStart()),a=n(s.getEnd()),(r||a)&&(d=s.getRng(!0),l?(r=r||a,(u=e(r,!0))?i(u,!0):(u=e(r,!1))?i(u,!1):s.select(r)):(d=s.getRng(!0),r&&d.setStartBefore(r),a&&d.setEndAfter(a),s.setRn
 g(d)))}function d(a){function i(e,t){for(;e=e[t?"previousSibling":"nextSibling"];)if(3!==e.nodeType||e.nodeValue.length>0)return e}function d(e,t){s.select(e),s.collapse(t)}function g(a){function i(e){for(var t=d;t;){if(t===e)return;t=t.parentNode}u.remove(e),l()}function o(){var r,o,l=e.schema.getNonEmptyElements();for(o=new tinymce.dom.TreeWalker(d,e.getBody());(r=a?o.prev():o.next())&&!l[r.nodeName.toLowerCase()]&&!(3===r.nodeType&&tinymce.trim(r.nodeValue).length>0);)if("false"===t(r))return i(r),!0;return n(r)?!0:!1}var f,d,c,g;if(s.isCollapsed()){if(f=s.getRng(!0),d=f.startContainer,c=f.startOffset,d=r(d)||d,g=n(d))return i(g),!1;if(3==d.nodeType&&(a?c>0:c<d.nodeValue.length))return!0;if(1==d.nodeType&&(d=d.childNodes[c]||d),o())return!1}return!0}var m,p,v,E,h=a.keyCode;if(v=s.getStart(),E=s.getEnd(),m=n(v)||n(E),m&&(112>h||h>124)&&h!=c.DELETE&&h!=c.BACKSPACE){if((ti
 nymce.isMac?a.metaKey:a.ctrlKey)&&(67==h||88==h||86==h))return;if(a.preventDefault(),h==c.LEFT||h==c.RIGHT){var y=h==c.LEFT;if(e.dom.isBlock(m)){var T=y?m.previousSibling:m.nextSibling,C=new f(T,T),b=y?C.prev():C.next();d(b,!y)}else d(m,y)}}else if(h==c.LEFT||h==c.RIGHT||h==c.BACKSPACE||h==c.DELETE){if(p=r(v)){if(h==c.LEFT||h==c.BACKSPACE)if(m=i(p,!0),m&&"false"===t(m)){if(a.preventDefault(),h!=c.LEFT)return void u.remove(m);d(m,!0)}else o(p);if(h==c.RIGHT||h==c.DELETE)if(m=i(p),m&&"false"===t(m)){if(a.preventDefault(),h!=c.RIGHT)return void u.remove(m);d(m,!1)}else o(p)}if((h==c.BACKSPACE||h==c.DELETE)&&!g(h==c.BACKSPACE))return a.preventDefault(),!1}}var u=e.dom,s=e.selection,g="mce_noneditablecaret",m="";e.on("mousedown",function(n){var r=e.selection.getNode();"false"===t(r)&&r==n.target&&l()}),e.on("mouseup keyup",l),e.on("keydown",d)}function a(t){v
 ar n=l.length,r=t.content,a=tinymce.trim(o);if("raw"!=t.format){for(;n--;)r=r.replace(l[n],function(t){var n=arguments,i=n[n.length-2];return i>0&&'"'==r.charAt(i-1)?t:'<span class="'+a+'" data-mce-content="'+e.dom.encode(n[0])+'">'+e.dom.encode("string"==typeof n[1]?n[1]:n[0])+"</span>"});t.content=r}}var i,o,l,f=tinymce.dom.TreeWalker,d="contenteditable",u="data-mce-"+d,c=tinymce.util.VK;i=" "+tinymce.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",o=" "+tinymce.trim(e.getParam("noneditable_noneditable_class","mceNonEditable"))+" ",l=e.getParam("noneditable_regexp"),l&&!l.length&&(l=[l]),e.on("PreInit",function(){r(),l&&e.on("BeforeSetContent",a),e.parser.addAttributeFilter("class",function(e){for(var t,n,r=e.length;r--;)n=e[r
 ],t=" "+n.attr("class")+" ",-1!==t.indexOf(i)?n.attr(u,"true"):-1!==t.indexOf(o)&&n.attr(u,"false")}),e.serializer.addAttributeFilter(u,function(e){for(var t,n=e.length;n--;)t=e[n],l&&t.attr("data-mce-content")?(t.name="#text",t.type=3,t.raw=!0,t.value=t.attr("data-mce-content")):(t.attr(d,null),t.attr(u,null))}),e.parser.addAttributeFilter(d,function(e){for(var t,n=e.length;n--;)t=e[n],t.attr(u,t.attr(d)),t.attr(d,null)})}),e.on("drop",function(e){n(e.target)&&e.preventDefault()})});
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/external-plugins/noneditable/plugin.min.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorexternalpluginstablepluginjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/external-plugins/table/plugin.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/external-plugins/table/plugin.js                                (rev 0)
+++ trunk/tests/qunit/editor/external-plugins/table/plugin.js   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,2170 @@
</span><ins>+/**
+ * Compiled inline version. (Library mode)
+ */
+
+/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
+/*globals $code */
+
+(function(exports, undefined) {
+       "use strict";
+
+       var modules = {};
+
+       function require(ids, callback) {
+               var module, defs = [];
+
+               for (var i = 0; i < ids.length; ++i) {
+                       module = modules[ids[i]] || resolve(ids[i]);
+                       if (!module) {
+                               throw 'module definition dependecy not found: ' + ids[i];
+                       }
+
+                       defs.push(module);
+               }
+
+               callback.apply(null, defs);
+       }
+
+       function define(id, dependencies, definition) {
+               if (typeof id !== 'string') {
+                       throw 'invalid module definition, module id must be defined and be a string';
+               }
+
+               if (dependencies === undefined) {
+                       throw 'invalid module definition, dependencies must be specified';
+               }
+
+               if (definition === undefined) {
+                       throw 'invalid module definition, definition function must be specified';
+               }
+
+               require(dependencies, function() {
+                       modules[id] = definition.apply(null, arguments);
+               });
+       }
+
+       function defined(id) {
+               return !!modules[id];
+       }
+
+       function resolve(id) {
+               var target = exports;
+               var fragments = id.split(/[.\/]/);
+
+               for (var fi = 0; fi < fragments.length; ++fi) {
+                       if (!target[fragments[fi]]) {
+                               return;
+                       }
+
+                       target = target[fragments[fi]];
+               }
+
+               return target;
+       }
+
+       function expose(ids) {
+               for (var i = 0; i < ids.length; i++) {
+                       var target = exports;
+                       var id = ids[i];
+                       var fragments = id.split(/[.\/]/);
+
+                       for (var fi = 0; fi < fragments.length - 1; ++fi) {
+                               if (target[fragments[fi]] === undefined) {
+                                       target[fragments[fi]] = {};
+                               }
+
+                               target = target[fragments[fi]];
+                       }
+
+                       target[fragments[fragments.length - 1]] = modules[id];
+               }
+       }
+
+// Included from: js/tinymce/plugins/table/classes/TableGrid.js
+
+/**
+ * TableGrid.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class creates a grid out of a table element. This
+ * makes it a whole lot easier to handle complex tables with
+ * col/row spans.
+ *
+ * @class tinymce.tableplugin.TableGrid
+ * @private
+ */
+define("tinymce/tableplugin/TableGrid", [
+       "tinymce/util/Tools",
+       "tinymce/Env"
+], function(Tools, Env) {
+       var each = Tools.each;
+
+       function getSpanVal(td, name) {
+               return parseInt(td.getAttribute(name) || 1, 10);
+       }
+
+       return function(editor, table) {
+               var grid, startPos, endPos, selectedCell, selection = editor.selection, dom = selection.dom;
+
+               function buildGrid() {
+                       var startY = 0;
+
+                       grid = [];
+
+                       each(['thead', 'tbody', 'tfoot'], function(part) {
+                               var rows = dom.select('> ' + part + ' tr', table);
+
+                               each(rows, function(tr, y) {
+                                       y += startY;
+
+                                       each(dom.select('> td, > th', tr), function(td, x) {
+                                               var x2, y2, rowspan, colspan;
+
+                                               // Skip over existing cells produced by rowspan
+                                               if (grid[y]) {
+                                                       while (grid[y][x]) {
+                                                               x++;
+                                                       }
+                                               }
+
+                                               // Get col/rowspan from cell
+                                               rowspan = getSpanVal(td, 'rowspan');
+                                               colspan = getSpanVal(td, 'colspan');
+
+                                               // Fill out rowspan/colspan right and down
+                                               for (y2 = y; y2 < y + rowspan; y2++) {
+                                                       if (!grid[y2]) {
+                                                               grid[y2] = [];
+                                                       }
+
+                                                       for (x2 = x; x2 < x + colspan; x2++) {
+                                                               grid[y2][x2] = {
+                                                                       part: part,
+                                                                       real: y2 == y && x2 == x,
+                                                                       elm: td,
+                                                                       rowspan: rowspan,
+                                                                       colspan: colspan
+                                                               };
+                                                       }
+                                               }
+                                       });
+                               });
+
+                               startY += rows.length;
+                       });
+               }
+
+               function cloneNode(node, children) {
+                       node = node.cloneNode(children);
+                       node.removeAttribute('id');
+
+                       return node;
+               }
+
+               function getCell(x, y) {
+                       var row;
+
+                       row = grid[y];
+                       if (row) {
+                               return row[x];
+                       }
+               }
+
+               function setSpanVal(td, name, val) {
+                       if (td) {
+                               val = parseInt(val, 10);
+
+                               if (val === 1) {
+                                       td.removeAttribute(name, 1);
+                               } else {
+                                       td.setAttribute(name, val, 1);
+                               }
+                       }
+               }
+
+               function isCellSelected(cell) {
+                       return cell && (dom.hasClass(cell.elm, 'mce-item-selected') || cell == selectedCell);
+               }
+
+               function getSelectedRows() {
+                       var rows = [];
+
+                       each(table.rows, function(row) {
+                               each(row.cells, function(cell) {
+                                       if (dom.hasClass(cell, 'mce-item-selected') || cell == selectedCell.elm) {
+                                               rows.push(row);
+                                               return false;
+                                       }
+                               });
+                       });
+
+                       return rows;
+               }
+
+               function deleteTable() {
+                       var rng = dom.createRng();
+
+                       rng.setStartAfter(table);
+                       rng.setEndAfter(table);
+
+                       selection.setRng(rng);
+
+                       dom.remove(table);
+               }
+
+               function cloneCell(cell) {
+                       var formatNode, cloneFormats = {};
+
+                       if (editor.settings.table_clone_elements !== false) {
+                               cloneFormats = Tools.makeMap(
+                                       (editor.settings.table_clone_elements || 'strong em b i span font h1 h2 h3 h4 h5 h6 p div').toUpperCase(),
+                                       /[ ,]/
+                               );
+                       }
+
+                       // Clone formats
+                       Tools.walk(cell, function(node) {
+                               var curNode;
+
+                               if (node.nodeType == 3) {
+                                       each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
+                                               if (!cloneFormats[node.nodeName]) {
+                                                       return;
+                                               }
+
+                                               node = cloneNode(node, false);
+
+                                               if (!formatNode) {
+                                                       formatNode = curNode = node;
+                                               } else if (curNode) {
+                                                       curNode.appendChild(node);
+                                               }
+
+                                               curNode = node;
+                                       });
+
+                                       // Add something to the inner node
+                                       if (curNode) {
+                                               curNode.innerHTML = Env.ie ? '&nbsp;' : '<br data-mce-bogus="1" />';
+                                       }
+
+                                       return false;
+                               }
+                       }, 'childNodes');
+
+                       cell = cloneNode(cell, false);
+                       setSpanVal(cell, 'rowSpan', 1);
+                       setSpanVal(cell, 'colSpan', 1);
+
+                       if (formatNode) {
+                               cell.appendChild(formatNode);
+                       } else {
+                               if (!Env.ie) {
+                                       cell.innerHTML = '<br data-mce-bogus="1" />';
+                               }
+                       }
+
+                       return cell;
+               }
+
+               function cleanup() {
+                       var rng = dom.createRng(), row;
+
+                       // Empty rows
+                       each(dom.select('tr', table), function(tr) {
+                               if (tr.cells.length === 0) {
+                                       dom.remove(tr);
+                               }
+                       });
+
+                       // Empty table
+                       if (dom.select('tr', table).length === 0) {
+                               rng.setStartBefore(table);
+                               rng.setEndBefore(table);
+                               selection.setRng(rng);
+                               dom.remove(table);
+                               return;
+                       }
+
+                       // Empty header/body/footer
+                       each(dom.select('thead,tbody,tfoot', table), function(part) {
+                               if (part.rows.length === 0) {
+                                       dom.remove(part);
+                               }
+                       });
+
+                       // Restore selection to start position if it still exists
+                       buildGrid();
+
+                       // Restore the selection to the closest table position
+                       row = grid[Math.min(grid.length - 1, startPos.y)];
+                       if (row) {
+                               selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
+                               selection.collapse(true);
+                       }
+               }
+
+               function fillLeftDown(x, y, rows, cols) {
+                       var tr, x2, r, c, cell;
+
+                       tr = grid[y][x].elm.parentNode;
+                       for (r = 1; r <= rows; r++) {
+                               tr = dom.getNext(tr, 'tr');
+
+                               if (tr) {
+                                       // Loop left to find real cell
+                                       for (x2 = x; x2 >= 0; x2--) {
+                                               cell = grid[y + r][x2].elm;
+
+                                               if (cell.parentNode == tr) {
+                                                       // Append clones after
+                                                       for (c = 1; c <= cols; c++) {
+                                                               dom.insertAfter(cloneCell(cell), cell);
+                                                       }
+
+                                                       break;
+                                               }
+                                       }
+
+                                       if (x2 == -1) {
+                                               // Insert nodes before first cell
+                                               for (c = 1; c <= cols; c++) {
+                                                       tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               function split() {
+                       each(grid, function(row, y) {
+                               each(row, function(cell, x) {
+                                       var colSpan, rowSpan, i;
+
+                                       if (isCellSelected(cell)) {
+                                               cell = cell.elm;
+                                               colSpan = getSpanVal(cell, 'colspan');
+                                               rowSpan = getSpanVal(cell, 'rowspan');
+
+                                               if (colSpan > 1 || rowSpan > 1) {
+                                                       setSpanVal(cell, 'rowSpan', 1);
+                                                       setSpanVal(cell, 'colSpan', 1);
+
+                                                       // Insert cells right
+                                                       for (i = 0; i < colSpan - 1; i++) {
+                                                               dom.insertAfter(cloneCell(cell), cell);
+                                                       }
+
+                                                       fillLeftDown(x, y, rowSpan - 1, colSpan);
+                                               }
+                                       }
+                               });
+                       });
+               }
+
+               function merge(cell, cols, rows) {
+                       var pos, startX, startY, endX, endY, x, y, startCell, endCell, children, count;
+
+                       // Use specified cell and cols/rows
+                       if (cell) {
+                               pos = getPos(cell);
+                               startX = pos.x;
+                               startY = pos.y;
+                               endX = startX + (cols - 1);
+                               endY = startY + (rows - 1);
+                       } else {
+                               startPos = endPos = null;
+
+                               // Calculate start/end pos by checking for selected cells in grid works better with context menu
+                               each(grid, function(row, y) {
+                                       each(row, function(cell, x) {
+                                               if (isCellSelected(cell)) {
+                                                       if (!startPos) {
+                                                               startPos = {x: x, y: y};
+                                                       }
+
+                                                       endPos = {x: x, y: y};
+                                               }
+                                       });
+                               });
+
+                               // Use selection
+                               startX = startPos.x;
+                               startY = startPos.y;
+                               endX = endPos.x;
+                               endY = endPos.y;
+                       }
+
+                       // Find start/end cells
+                       startCell = getCell(startX, startY);
+                       endCell = getCell(endX, endY);
+
+                       // Check if the cells exists and if they are of the same part for example tbody = tbody
+                       if (startCell && endCell && startCell.part == endCell.part) {
+                               // Split and rebuild grid
+                               split();
+                               buildGrid();
+
+                               // Set row/col span to start cell
+                               startCell = getCell(startX, startY).elm;
+                               setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
+                               setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
+
+                               // Remove other cells and add it's contents to the start cell
+                               for (y = startY; y <= endY; y++) {
+                                       for (x = startX; x <= endX; x++) {
+                                               if (!grid[y] || !grid[y][x]) {
+                                                       continue;
+                                               }
+
+                                               cell = grid[y][x].elm;
+
+                                               /*jshint loopfunc:true */
+                                               if (cell != startCell) {
+                                                       // Move children to startCell
+                                                       children = Tools.grep(cell.childNodes);
+                                                       each(children, function(node) {
+                                                               startCell.appendChild(node);
+                                                       });
+
+                                                       // Remove bogus nodes if there is children in the target cell
+                                                       if (children.length) {
+                                                               children = Tools.grep(startCell.childNodes);
+                                                               count = 0;
+                                                               each(children, function(node) {
+                                                                       if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1) {
+                                                                               startCell.removeChild(node);
+                                                                       }
+                                                               });
+                                                       }
+
+                                                       dom.remove(cell);
+                                               }
+                                       }
+                               }
+
+                               // Remove empty rows etc and restore caret location
+                               cleanup();
+                       }
+               }
+
+               function insertRow(before) {
+                       var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
+
+                       // Find first/last row
+                       each(grid, function(row, y) {
+                               each(row, function(cell) {
+                                       if (isCellSelected(cell)) {
+                                               cell = cell.elm;
+                                               rowElm = cell.parentNode;
+                                               newRow = cloneNode(rowElm, false);
+                                               posY = y;
+
+                                               if (before) {
+                                                       return false;
+                                               }
+                                       }
+                               });
+
+                               if (before) {
+                                       return !posY;
+                               }
+                       });
+
+                       for (x = 0; x < grid[0].length; x++) {
+                               // Cell not found could be because of an invalid table structure
+                               if (!grid[posY][x]) {
+                                       continue;
+                               }
+
+                               cell = grid[posY][x].elm;
+
+                               if (cell != lastCell) {
+                                       if (!before) {
+                                               rowSpan = getSpanVal(cell, 'rowspan');
+                                               if (rowSpan > 1) {
+                                                       setSpanVal(cell, 'rowSpan', rowSpan + 1);
+                                                       continue;
+                                               }
+                                       } else {
+                                               // Check if cell above can be expanded
+                                               if (posY > 0 && grid[posY - 1][x]) {
+                                                       otherCell = grid[posY - 1][x].elm;
+                                                       rowSpan = getSpanVal(otherCell, 'rowSpan');
+                                                       if (rowSpan > 1) {
+                                                               setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
+                                                               continue;
+                                                       }
+                                               }
+                                       }
+
+                                       // Insert new cell into new row
+                                       newCell = cloneCell(cell);
+                                       setSpanVal(newCell, 'colSpan', cell.colSpan);
+
+                                       newRow.appendChild(newCell);
+
+                                       lastCell = cell;
+                               }
+                       }
+
+                       if (newRow.hasChildNodes()) {
+                               if (!before) {
+                                       dom.insertAfter(newRow, rowElm);
+                               } else {
+                                       rowElm.parentNode.insertBefore(newRow, rowElm);
+                               }
+                       }
+               }
+
+               function insertCol(before) {
+                       var posX, lastCell;
+
+                       // Find first/last column
+                       each(grid, function(row) {
+                               each(row, function(cell, x) {
+                                       if (isCellSelected(cell)) {
+                                               posX = x;
+
+                                               if (before) {
+                                                       return false;
+                                               }
+                                       }
+                               });
+
+                               if (before) {
+                                       return !posX;
+                               }
+                       });
+
+                       each(grid, function(row, y) {
+                               var cell, rowSpan, colSpan;
+
+                               if (!row[posX]) {
+                                       return;
+                               }
+
+                               cell = row[posX].elm;
+                               if (cell != lastCell) {
+                                       colSpan = getSpanVal(cell, 'colspan');
+                                       rowSpan = getSpanVal(cell, 'rowspan');
+
+                                       if (colSpan == 1) {
+                                               if (!before) {
+                                                       dom.insertAfter(cloneCell(cell), cell);
+                                                       fillLeftDown(posX, y, rowSpan - 1, colSpan);
+                                               } else {
+                                                       cell.parentNode.insertBefore(cloneCell(cell), cell);
+                                                       fillLeftDown(posX, y, rowSpan - 1, colSpan);
+                                               }
+                                       } else {
+                                               setSpanVal(cell, 'colSpan', cell.colSpan + 1);
+                                       }
+
+                                       lastCell = cell;
+                               }
+                       });
+               }
+
+               function deleteCols() {
+                       var cols = [];
+
+                       // Get selected column indexes
+                       each(grid, function(row) {
+                               each(row, function(cell, x) {
+                                       if (isCellSelected(cell) && Tools.inArray(cols, x) === -1) {
+                                               each(grid, function(row) {
+                                                       var cell = row[x].elm, colSpan;
+
+                                                       colSpan = getSpanVal(cell, 'colSpan');
+
+                                                       if (colSpan > 1) {
+                                                               setSpanVal(cell, 'colSpan', colSpan - 1);
+                                                       } else {
+                                                               dom.remove(cell);
+                                                       }
+                                               });
+
+                                               cols.push(x);
+                                       }
+                               });
+                       });
+
+                       cleanup();
+               }
+
+               function deleteRows() {
+                       var rows;
+
+                       function deleteRow(tr) {
+                               var nextTr, pos, lastCell;
+
+                               nextTr = dom.getNext(tr, 'tr');
+
+                               // Move down row spanned cells
+                               each(tr.cells, function(cell) {
+                                       var rowSpan = getSpanVal(cell, 'rowSpan');
+
+                                       if (rowSpan > 1) {
+                                               setSpanVal(cell, 'rowSpan', rowSpan - 1);
+                                               pos = getPos(cell);
+                                               fillLeftDown(pos.x, pos.y, 1, 1);
+                                       }
+                               });
+
+                               // Delete cells
+                               pos = getPos(tr.cells[0]);
+                               each(grid[pos.y], function(cell) {
+                                       var rowSpan;
+
+                                       cell = cell.elm;
+
+                                       if (cell != lastCell) {
+                                               rowSpan = getSpanVal(cell, 'rowSpan');
+
+                                               if (rowSpan <= 1) {
+                                                       dom.remove(cell);
+                                               } else {
+                                                       setSpanVal(cell, 'rowSpan', rowSpan - 1);
+                                               }
+
+                                               lastCell = cell;
+                                       }
+                               });
+                       }
+
+                       // Get selected rows and move selection out of scope
+                       rows = getSelectedRows();
+
+                       // Delete all selected rows
+                       each(rows.reverse(), function(tr) {
+                               deleteRow(tr);
+                       });
+
+                       cleanup();
+               }
+
+               function cutRows() {
+                       var rows = getSelectedRows();
+
+                       dom.remove(rows);
+                       cleanup();
+
+                       return rows;
+               }
+
+               function copyRows() {
+                       var rows = getSelectedRows();
+
+                       each(rows, function(row, i) {
+                               rows[i] = cloneNode(row, true);
+                       });
+
+                       return rows;
+               }
+
+               function pasteRows(rows, before) {
+                       var selectedRows = getSelectedRows(),
+                               targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
+                               targetCellCount = targetRow.cells.length;
+
+                       // Nothing to paste
+                       if (!rows) {
+                               return;
+                       }
+
+                       // Calc target cell count
+                       each(grid, function(row) {
+                               var match;
+
+                               targetCellCount = 0;
+                               each(row, function(cell) {
+                                       if (cell.real) {
+                                               targetCellCount += cell.colspan;
+                                       }
+
+                                       if (cell.elm.parentNode == targetRow) {
+                                               match = 1;
+                                       }
+                               });
+
+                               if (match) {
+                                       return false;
+                               }
+                       });
+
+                       if (!before) {
+                               rows.reverse();
+                       }
+
+                       each(rows, function(row) {
+                               var i, cellCount = row.cells.length, cell;
+
+                               // Remove col/rowspans
+                               for (i = 0; i < cellCount; i++) {
+                                       cell = row.cells[i];
+                                       setSpanVal(cell, 'colSpan', 1);
+                                       setSpanVal(cell, 'rowSpan', 1);
+                               }
+
+                               // Needs more cells
+                               for (i = cellCount; i < targetCellCount; i++) {
+                                       row.appendChild(cloneCell(row.cells[cellCount - 1]));
+                               }
+
+                               // Needs less cells
+                               for (i = targetCellCount; i < cellCount; i++) {
+                                       dom.remove(row.cells[i]);
+                               }
+
+                               // Add before/after
+                               if (before) {
+                                       targetRow.parentNode.insertBefore(row, targetRow);
+                               } else {
+                                       dom.insertAfter(row, targetRow);
+                               }
+                       });
+
+                       // Remove current selection
+                       dom.removeClass(dom.select('td.mce-item-selected,th.mce-item-selected'), 'mce-item-selected');
+               }
+
+               function getPos(target) {
+                       var pos;
+
+                       each(grid, function(row, y) {
+                               each(row, function(cell, x) {
+                                       if (cell.elm == target) {
+                                               pos = {x : x, y : y};
+                                               return false;
+                                       }
+                               });
+
+                               return !pos;
+                       });
+
+                       return pos;
+               }
+
+               function setStartCell(cell) {
+                       startPos = getPos(cell);
+               }
+
+               function findEndPos() {
+                       var maxX, maxY;
+
+                       maxX = maxY = 0;
+
+                       each(grid, function(row, y) {
+                               each(row, function(cell, x) {
+                                       var colSpan, rowSpan;
+
+                                       if (isCellSelected(cell)) {
+                                               cell = grid[y][x];
+
+                                               if (x > maxX) {
+                                                       maxX = x;
+                                               }
+
+                                               if (y > maxY) {
+                                                       maxY = y;
+                                               }
+
+                                               if (cell.real) {
+                                                       colSpan = cell.colspan - 1;
+                                                       rowSpan = cell.rowspan - 1;
+
+                                                       if (colSpan) {
+                                                               if (x + colSpan > maxX) {
+                                                                       maxX = x + colSpan;
+                                                               }
+                                                       }
+
+                                                       if (rowSpan) {
+                                                               if (y + rowSpan > maxY) {
+                                                                       maxY = y + rowSpan;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               });
+                       });
+
+                       return {x : maxX, y : maxY};
+               }
+
+               function setEndCell(cell) {
+                       var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan, x, y;
+
+                       endPos = getPos(cell);
+
+                       if (startPos && endPos) {
+                               // Get start/end positions
+                               startX = Math.min(startPos.x, endPos.x);
+                               startY = Math.min(startPos.y, endPos.y);
+                               endX = Math.max(startPos.x, endPos.x);
+                               endY = Math.max(startPos.y, endPos.y);
+
+                               // Expand end positon to include spans
+                               maxX = endX;
+                               maxY = endY;
+
+                               // Expand startX
+                               for (y = startY; y <= maxY; y++) {
+                                       cell = grid[y][startX];
+
+                                       if (!cell.real) {
+                                               if (startX - (cell.colspan - 1) < startX) {
+                                                       startX -= cell.colspan - 1;
+                                               }
+                                       }
+                               }
+
+                               // Expand startY
+                               for (x = startX; x <= maxX; x++) {
+                                       cell = grid[startY][x];
+
+                                       if (!cell.real) {
+                                               if (startY - (cell.rowspan - 1) < startY) {
+                                                       startY -= cell.rowspan - 1;
+                                               }
+                                       }
+                               }
+
+                               // Find max X, Y
+                               for (y = startY; y <= endY; y++) {
+                                       for (x = startX; x <= endX; x++) {
+                                               cell = grid[y][x];
+
+                                               if (cell.real) {
+                                                       colSpan = cell.colspan - 1;
+                                                       rowSpan = cell.rowspan - 1;
+
+                                                       if (colSpan) {
+                                                               if (x + colSpan > maxX) {
+                                                                       maxX = x + colSpan;
+                                                               }
+                                                       }
+
+                                                       if (rowSpan) {
+                                                               if (y + rowSpan > maxY) {
+                                                                       maxY = y + rowSpan;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Remove current selection
+                               dom.removeClass(dom.select('td.mce-item-selected,th.mce-item-selected'), 'mce-item-selected');
+
+                               // Add new selection
+                               for (y = startY; y <= maxY; y++) {
+                                       for (x = startX; x <= maxX; x++) {
+                                               if (grid[y][x]) {
+                                                       dom.addClass(grid[y][x].elm, 'mce-item-selected');
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               table = table || dom.getParent(selection.getStart(), 'table');
+
+               buildGrid();
+
+               selectedCell = dom.getParent(selection.getStart(), 'th,td');
+               if (selectedCell) {
+                       startPos = getPos(selectedCell);
+                       endPos = findEndPos();
+                       selectedCell = getCell(startPos.x, startPos.y);
+               }
+
+               Tools.extend(this, {
+                       deleteTable: deleteTable,
+                       split: split,
+                       merge: merge,
+                       insertRow: insertRow,
+                       insertCol: insertCol,
+                       deleteCols: deleteCols,
+                       deleteRows: deleteRows,
+                       cutRows: cutRows,
+                       copyRows: copyRows,
+                       pasteRows: pasteRows,
+                       getPos: getPos,
+                       setStartCell: setStartCell,
+                       setEndCell: setEndCell
+               });
+       };
+});
+
+// Included from: js/tinymce/plugins/table/classes/Quirks.js
+
+/**
+ * Quirks.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class includes fixes for various browser quirks.
+ *
+ * @class tinymce.tableplugin.Quirks
+ * @private
+ */
+define("tinymce/tableplugin/Quirks", [
+       "tinymce/util/VK",
+       "tinymce/Env",
+       "tinymce/util/Tools"
+], function(VK, Env, Tools) {
+       var each = Tools.each;
+
+       function getSpanVal(td, name) {
+               return parseInt(td.getAttribute(name) || 1, 10);
+       }
+
+       return function(editor) {
+               /**
+                * Fixed caret movement around tables on WebKit.
+                */
+               function moveWebKitSelection() {
+                       function eventHandler(e) {
+                               var key = e.keyCode;
+
+                               function handle(upBool, sourceNode) {
+                                       var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
+                                       var currentRow = editor.dom.getParent(sourceNode, 'tr');
+                                       var siblingRow = currentRow[siblingDirection];
+
+                                       if (siblingRow) {
+                                               moveCursorToRow(editor, sourceNode, siblingRow, upBool);
+                                               e.preventDefault();
+                                               return true;
+                                       } else {
+                                               var tableNode = editor.dom.getParent(currentRow, 'table');
+                                               var middleNode = currentRow.parentNode;
+                                               var parentNodeName = middleNode.nodeName.toLowerCase();
+                                               if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
+                                                       var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
+                                                       if (targetParent !== null) {
+                                                               return moveToRowInTarget(upBool, targetParent, sourceNode);
+                                                       }
+                                               }
+                                               return escapeTable(upBool, currentRow, siblingDirection, tableNode);
+                                       }
+                               }
+
+                               function getTargetParent(upBool, topNode, secondNode, nodeName) {
+                                       var tbodies = editor.dom.select('>' + nodeName, topNode);
+                                       var position = tbodies.indexOf(secondNode);
+                                       if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
+                                               return getFirstHeadOrFoot(upBool, topNode);
+                                       } else if (position === -1) {
+                                               var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
+                                               return tbodies[topOrBottom];
+                                       } else {
+                                               return tbodies[position + (upBool ? -1 : 1)];
+                                       }
+                               }
+
+                               function getFirstHeadOrFoot(upBool, parent) {
+                                       var tagName = upBool ? 'thead' : 'tfoot';
+                                       var headOrFoot = editor.dom.select('>' + tagName, parent);
+                                       return headOrFoot.length !== 0 ? headOrFoot[0] : null;
+                               }
+
+                               function moveToRowInTarget(upBool, targetParent, sourceNode) {
+                                       var targetRow = getChildForDirection(targetParent, upBool);
+
+                                       if (targetRow) {
+                                               moveCursorToRow(editor, sourceNode, targetRow, upBool);
+                                       }
+
+                                       e.preventDefault();
+                                       return true;
+                               }
+
+                               function escapeTable(upBool, currentRow, siblingDirection, table) {
+                                       var tableSibling = table[siblingDirection];
+
+                                       if (tableSibling) {
+                                               moveCursorToStartOfElement(tableSibling);
+                                               return true;
+                                       } else {
+                                               var parentCell = editor.dom.getParent(table, 'td,th');
+                                               if (parentCell) {
+                                                       return handle(upBool, parentCell, e);
+                                               } else {
+                                                       var backUpSibling = getChildForDirection(currentRow, !upBool);
+                                                       moveCursorToStartOfElement(backUpSibling);
+                                                       e.preventDefault();
+                                                       return false;
+                                               }
+                                       }
+                               }
+
+                               function getChildForDirection(parent, up) {
+                                       var child =  parent && parent[up ? 'lastChild' : 'firstChild'];
+                                       // BR is not a valid table child to return in this case we return the table cell
+                                       return child && child.nodeName === 'BR' ? editor.dom.getParent(child, 'td,th') : child;
+                               }
+
+                               function moveCursorToStartOfElement(n) {
+                                       editor.selection.setCursorLocation(n, 0);
+                               }
+
+                               function isVerticalMovement() {
+                                       return key == VK.UP || key == VK.DOWN;
+                               }
+
+                               function isInTable(editor) {
+                                       var node = editor.selection.getNode();
+                                       var currentRow = editor.dom.getParent(node, 'tr');
+                                       return currentRow !== null;
+                               }
+
+                               function columnIndex(column) {
+                                       var colIndex = 0;
+                                       var c = column;
+                                       while (c.previousSibling) {
+                                               c = c.previousSibling;
+                                               colIndex = colIndex + getSpanVal(c, "colspan");
+                                       }
+                                       return colIndex;
+                               }
+
+                               function findColumn(rowElement, columnIndex) {
+                                       var c = 0, r = 0;
+
+                                       each(rowElement.children, function(cell, i) {
+                                               c = c + getSpanVal(cell, "colspan");
+                                               r = i;
+                                               if (c > columnIndex) {
+                                                       return false;
+                                               }
+                                       });
+                                       return r;
+                               }
+
+                               function moveCursorToRow(ed, node, row, upBool) {
+                                       var srcColumnIndex = columnIndex(editor.dom.getParent(node, 'td,th'));
+                                       var tgtColumnIndex = findColumn(row, srcColumnIndex);
+                                       var tgtNode = row.childNodes[tgtColumnIndex];
+                                       var rowCellTarget = getChildForDirection(tgtNode, upBool);
+                                       moveCursorToStartOfElement(rowCellTarget || tgtNode);
+                               }
+
+                               function shouldFixCaret(preBrowserNode) {
+                                       var newNode = editor.selection.getNode();
+                                       var newParent = editor.dom.getParent(newNode, 'td,th');
+                                       var oldParent = editor.dom.getParent(preBrowserNode, 'td,th');
+
+                                       return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent);
+                               }
+
+                               function checkSameParentTable(nodeOne, NodeTwo) {
+                                       return editor.dom.getParent(nodeOne, 'TABLE') === editor.dom.getParent(NodeTwo, 'TABLE');
+                               }
+
+                               if (isVerticalMovement() && isInTable(editor)) {
+                                       var preBrowserNode = editor.selection.getNode();
+                                       setTimeout(function() {
+                                               if (shouldFixCaret(preBrowserNode)) {
+                                                       handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
+                                               }
+                                       }, 0);
+                               }
+                       }
+
+                       editor.on('KeyDown', function(e) {
+                               eventHandler(e);
+                       });
+               }
+
+               function fixBeforeTableCaretBug() {
+                       // Checks if the selection/caret is at the start of the specified block element
+                       function isAtStart(rng, par) {
+                               var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
+
+                               rng2.setStartBefore(par);
+                               rng2.setEnd(rng.endContainer, rng.endOffset);
+
+                               elm = doc.createElement('body');
+                               elm.appendChild(rng2.cloneContents());
+
+                               // Check for text characters of other elements that should be treated as content
+                               return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length === 0;
+                       }
+
+                       // Fixes an bug where it's impossible to place the caret before a table in Gecko
+                       // this fix solves it by detecting when the caret is at the beginning of such a table
+                       // and then manually moves the caret infront of the table
+                       editor.on('KeyDown', function(e) {
+                               var rng, table, dom = editor.dom;
+
+                               // On gecko it's not possible to place the caret before a table
+                               if (e.keyCode == 37 || e.keyCode == 38) {
+                                       rng = editor.selection.getRng();
+                                       table = dom.getParent(rng.startContainer, 'table');
+
+                                       if (table && editor.getBody().firstChild == table) {
+                                               if (isAtStart(rng, table)) {
+                                                       rng = dom.createRng();
+
+                                                       rng.setStartBefore(table);
+                                                       rng.setEndBefore(table);
+
+                                                       editor.selection.setRng(rng);
+
+                                                       e.preventDefault();
+                                               }
+                                       }
+                               }
+                       });
+               }
+
+               // Fixes an issue on Gecko where it's impossible to place the caret behind a table
+               // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
+               function fixTableCaretPos() {
+                       editor.on('KeyDown SetContent VisualAid', function() {
+                               var last;
+
+                               // Skip empty text nodes from the end
+                               for (last = editor.getBody().lastChild; last; last = last.previousSibling) {
+                                       if (last.nodeType == 3) {
+                                               if (last.nodeValue.length > 0) {
+                                                       break;
+                                               }
+                                       } else if (last.nodeType == 1 && !last.getAttribute('data-mce-bogus')) {
+                                               break;
+                                       }
+                               }
+
+                               if (last && last.nodeName == 'TABLE') {
+                                       if (editor.settings.forced_root_block) {
+                                               editor.dom.add(
+                                                       editor.getBody(),
+                                                       editor.settings.forced_root_block,
+                                                       editor.settings.forced_root_block_attrs,
+                                                       Env.ie && Env.ie < 11 ? '&nbsp;' : '<br data-mce-bogus="1" />'
+                                               );
+                                       } else {
+                                               editor.dom.add(editor.getBody(), 'br', {'data-mce-bogus': '1'});
+                                       }
+                               }
+                       });
+
+                       editor.on('PreProcess', function(o) {
+                               var last = o.node.lastChild;
+
+                               if (last && (last.nodeName == "BR" || (last.childNodes.length == 1 &&
+                                       (last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0'))) &&
+                                       last.previousSibling && last.previousSibling.nodeName == "TABLE") {
+                                       editor.dom.remove(last);
+                               }
+                       });
+               }
+
+               // this nasty hack is here to work around some WebKit selection bugs.
+               function fixTableCellSelection() {
+                       function tableCellSelected(ed, rng, n, currentCell) {
+                               // The decision of when a table cell is selected is somewhat involved.  The fact that this code is
+                               // required is actually a pointer to the root cause of this bug. A cell is selected when the start
+                               // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
+                               // or the parent of the table (in the case of the selection containing the last cell of a table).
+                               var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE');
+                               var tableParent, allOfCellSelected, tableCellSelection;
+
+                               if (table) {
+                                       tableParent = table.parentNode;
+                               }
+
+                               allOfCellSelected =rng.startContainer.nodeType == TEXT_NODE &&
+                                       rng.startOffset === 0 &&
+                                       rng.endOffset === 0 &&
+                                       currentCell &&
+                                       (n.nodeName == "TR" || n == tableParent);
+
+                               tableCellSelection = (n.nodeName == "TD" || n.nodeName == "TH") && !currentCell;
+
+                               return allOfCellSelected || tableCellSelection;
+                       }
+
+                       function fixSelection() {
+                               var rng = editor.selection.getRng();
+                               var n = editor.selection.getNode();
+                               var currentCell = editor.dom.getParent(rng.startContainer, 'TD,TH');
+
+                               if (!tableCellSelected(editor, rng, n, currentCell)) {
+                                       return;
+                               }
+
+                               if (!currentCell) {
+                                       currentCell=n;
+                               }
+
+                               // Get the very last node inside the table cell
+                               var end = currentCell.lastChild;
+                               while (end.lastChild) {
+                                       end = end.lastChild;
+                               }
+
+                               // Select the entire table cell. Nothing outside of the table cell should be selected.
+                               rng.setEnd(end, end.nodeValue.length);
+                               editor.selection.setRng(rng);
+                       }
+
+                       editor.on('KeyDown', function() {
+                               fixSelection();
+                       });
+
+                       editor.on('MouseDown', function(e) {
+                               if (e.button != 2) {
+                                       fixSelection();
+                               }
+                       });
+               }
+
+               /**
+                * Delete table if all cells are selected.
+                */
+               function deleteTable() {
+                       editor.on('keydown', function(e) {
+                               if ((e.keyCode == VK.DELETE || e.keyCode == VK.BACKSPACE) && !e.isDefaultPrevented()) {
+                                       var table = editor.dom.getParent(editor.selection.getStart(), 'table');
+
+                                       if (table) {
+                                               var cells = editor.dom.select('td,th', table), i = cells.length;
+                                               while (i--) {
+                                                       if (!editor.dom.hasClass(cells[i], 'mce-item-selected')) {
+                                                               return;
+                                                       }
+                                               }
+
+                                               e.preventDefault();
+                                               editor.execCommand('mceTableDelete');
+                                       }
+                               }
+                       });
+               }
+
+               deleteTable();
+
+               if (Env.webkit) {
+                       moveWebKitSelection();
+                       fixTableCellSelection();
+               }
+
+               if (Env.gecko) {
+                       fixBeforeTableCaretBug();
+                       fixTableCaretPos();
+               }
+
+               if (Env.ie > 10) {
+                       fixBeforeTableCaretBug();
+                       fixTableCaretPos();
+               }
+       };
+});
+
+// Included from: js/tinymce/plugins/table/classes/CellSelection.js
+
+/**
+ * CellSelection.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class handles table cell selection by faking it using a css class that gets applied
+ * to cells when dragging the mouse from one cell to another.
+ *
+ * @class tinymce.tableplugin.CellSelection
+ * @private
+ */
+define("tinymce/tableplugin/CellSelection", [
+       "tinymce/tableplugin/TableGrid",
+       "tinymce/dom/TreeWalker",
+       "tinymce/util/Tools"
+], function(TableGrid, TreeWalker, Tools) {
+       return function(editor) {
+               var dom = editor.dom, tableGrid, startCell, startTable, hasCellSelection = true;
+
+               function clear() {
+                       // Restore selection possibilities
+                       editor.getBody().style.webkitUserSelect = '';
+
+                       if (hasCellSelection) {
+                               editor.dom.removeClass(
+                                       editor.dom.select('td.mce-item-selected,th.mce-item-selected'),
+                                       'mce-item-selected'
+                               );
+
+                               hasCellSelection = false;
+                       }
+               }
+
+               function cellSelectionHandler(e) {
+                       var sel, table, target = e.target;
+
+                       if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
+                               table = dom.getParent(target, 'table');
+                               if (table == startTable) {
+                                       if (!tableGrid) {
+                                               tableGrid = new TableGrid(editor, table);
+                                               tableGrid.setStartCell(startCell);
+
+                                               editor.getBody().style.webkitUserSelect = 'none';
+                                       }
+
+                                       tableGrid.setEndCell(target);
+                                       hasCellSelection = true;
+                               }
+
+                               // Remove current selection
+                               sel = editor.selection.getSel();
+
+                               try {
+                                       if (sel.removeAllRanges) {
+                                               sel.removeAllRanges();
+                                       } else {
+                                               sel.empty();
+                                       }
+                               } catch (ex) {
+                                       // IE9 might throw errors here
+                               }
+
+                               e.preventDefault();
+                       }
+               }
+
+               // Add cell selection logic
+               editor.on('MouseDown', function(e) {
+                       if (e.button != 2) {
+                               clear();
+
+                               startCell = dom.getParent(e.target, 'td,th');
+                               startTable = dom.getParent(startCell, 'table');
+                       }
+               });
+
+               dom.bind(editor.getDoc(), 'mouseover', cellSelectionHandler);
+
+               editor.on('remove', function() {
+                       dom.unbind(editor.getDoc(), 'mouseover', cellSelectionHandler);
+               });
+
+               editor.on('MouseUp', function() {
+                       var rng, sel = editor.selection, selectedCells, walker, node, lastNode, endNode;
+
+                       function setPoint(node, start) {
+                               var walker = new TreeWalker(node, node);
+
+                               do {
+                                       // Text node
+                                       if (node.nodeType == 3 && Tools.trim(node.nodeValue).length !== 0) {
+                                               if (start) {
+                                                       rng.setStart(node, 0);
+                                               } else {
+                                                       rng.setEnd(node, node.nodeValue.length);
+                                               }
+
+                                               return;
+                                       }
+
+                                       // BR element
+                                       if (node.nodeName == 'BR') {
+                                               if (start) {
+                                                       rng.setStartBefore(node);
+                                               } else {
+                                                       rng.setEndBefore(node);
+                                               }
+
+                                               return;
+                                       }
+                               } while ((node = (start ? walker.next() : walker.prev())));
+                       }
+
+                       // Move selection to startCell
+                       if (startCell) {
+                               if (tableGrid) {
+                                       editor.getBody().style.webkitUserSelect = '';
+                               }
+
+                               // Try to expand text selection as much as we can only Gecko supports cell selection
+                               selectedCells = dom.select('td.mce-item-selected,th.mce-item-selected');
+                               if (selectedCells.length > 0) {
+                                       rng = dom.createRng();
+                                       node = selectedCells[0];
+                                       endNode = selectedCells[selectedCells.length - 1];
+                                       rng.setStartBefore(node);
+                                       rng.setEndAfter(node);
+
+                                       setPoint(node, 1);
+                                       walker = new TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
+
+                                       do {
+                                               if (node.nodeName == 'TD' || node.nodeName == 'TH') {
+                                                       if (!dom.hasClass(node, 'mce-item-selected')) {
+                                                               break;
+                                                       }
+
+                                                       lastNode = node;
+                                               }
+                                       } while ((node = walker.next()));
+
+                                       setPoint(lastNode);
+
+                                       sel.setRng(rng);
+                               }
+
+                               editor.nodeChanged();
+                               startCell = tableGrid = startTable = null;
+                       }
+               });
+
+               editor.on('KeyUp', function() {
+                       clear();
+               });
+
+               return {
+                       clear: clear
+               };
+       };
+});
+
+// Included from: js/tinymce/plugins/table/classes/Plugin.js
+
+/**
+ * Plugin.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * This class contains all core logic for the table plugin.
+ *
+ * @class tinymce.tableplugin.Plugin
+ * @private
+ */
+define("tinymce/tableplugin/Plugin", [
+       "tinymce/tableplugin/TableGrid",
+       "tinymce/tableplugin/Quirks",
+       "tinymce/tableplugin/CellSelection",
+       "tinymce/util/Tools",
+       "tinymce/dom/TreeWalker",
+       "tinymce/Env",
+       "tinymce/PluginManager"
+], function(TableGrid, Quirks, CellSelection, Tools, TreeWalker, Env, PluginManager) {
+       var each = Tools.each;
+
+       function Plugin(editor) {
+               var winMan, clipboardRows, self = this; // Might be selected cells on reload
+
+               function removePxSuffix(size) {
+                       return size ? size.replace(/px$/, '') : "";
+               }
+
+               function addSizeSuffix(size) {
+                       if (/^[0-9]+$/.test(size)) {
+                               size += "px";
+                       }
+
+                       return size;
+               }
+
+               function unApplyAlign(elm) {
+                       each('left center right'.split(' '), function(name) {
+                               editor.formatter.remove('align' + name, {}, elm);
+                       });
+               }
+
+               function tableDialog() {
+                       var dom = editor.dom, tableElm, data;
+
+                       tableElm = dom.getParent(editor.selection.getStart(), 'table');
+
+                       data = {
+                               width: removePxSuffix(dom.getStyle(tableElm, 'width') || dom.getAttrib(tableElm, 'width')),
+                               height: removePxSuffix(dom.getStyle(tableElm, 'height') || dom.getAttrib(tableElm, 'height')),
+                               cellspacing: dom.getAttrib(tableElm, 'cellspacing'),
+                               cellpadding: dom.getAttrib(tableElm, 'cellpadding'),
+                               border: dom.getAttrib(tableElm, 'border'),
+                               caption: !!dom.select('caption', tableElm)[0]
+                       };
+
+                       each('left center right'.split(' '), function(name) {
+                               if (editor.formatter.matchNode(tableElm, 'align' + name)) {
+                                       data.align = name;
+                               }
+                       });
+
+                       editor.windowManager.open({
+                               title: "Table properties",
+                               items: {
+                                       type: 'form',
+                                       layout: 'grid',
+                                       columns: 2,
+                                       data: data,
+                                       defaults: {
+                                               type: 'textbox',
+                                               maxWidth: 50
+                                       },
+                                       items: [
+                                               {label: 'Width', name: 'width'},
+                                               {label: 'Height', name: 'height'},
+                                               {label: 'Cell spacing', name: 'cellspacing'},
+                                               {label: 'Cell padding', name: 'cellpadding'},
+                                               {label: 'Border', name: 'border'},
+                                               {label: 'Caption', name: 'caption', type: 'checkbox'},
+                                               {
+                                                       label: 'Alignment',
+                                                       minWidth: 90,
+                                                       name: 'align',
+                                                       type: 'listbox',
+                                                       text: 'None',
+                                                       maxWidth: null,
+                                                       values: [
+                                                               {text: 'None', value: ''},
+                                                               {text: 'Left', value: 'left'},
+                                                               {text: 'Center', value: 'center'},
+                                                               {text: 'Right', value: 'right'}
+                                                       ]
+                                               }
+                                       ]
+                               },
+
+                               onsubmit: function() {
+                                       var data = this.toJSON(), captionElm;
+
+                                       editor.undoManager.transact(function() {
+                                               editor.dom.setAttribs(tableElm, {
+                                                       cellspacing: data.cellspacing,
+                                                       cellpadding: data.cellpadding,
+                                                       border: data.border
+                                               });
+
+                                               editor.dom.setStyles(tableElm, {
+                                                       width: addSizeSuffix(data.width),
+                                                       height: addSizeSuffix(data.height)
+                                               });
+
+                                               // Toggle caption on/off
+                                               captionElm = dom.select('caption', tableElm)[0];
+
+                                               if (captionElm && !data.caption) {
+                                                       dom.remove(captionElm);
+                                               }
+
+                                               if (!captionElm && data.caption) {
+                                                       captionElm = dom.create('caption');
+                                                       captionElm.innerHTML = !Env.ie ? '<br data-mce-bogus="1"/>' : '\u00a0';
+                                                       tableElm.insertBefore(captionElm, tableElm.firstChild);
+                                               }
+
+                                               unApplyAlign(tableElm);
+                                               if (data.align) {
+                                                       editor.formatter.apply('align' + data.align, {}, tableElm);
+                                               }
+
+                                               editor.focus();
+                                               editor.addVisual();
+                                       });
+                               }
+                       });
+               }
+
+               function mergeDialog(grid, cell) {
+                       editor.windowManager.open({
+                               title: "Merge cells",
+                               body: [
+                                       {label: 'Cols', name: 'cols', type: 'textbox', size: 10},
+                                       {label: 'Rows', name: 'rows', type: 'textbox', size: 10}
+                               ],
+                               onsubmit: function() {
+                                       var data = this.toJSON();
+
+                                       editor.undoManager.transact(function() {
+                                               grid.merge(cell, data.cols, data.rows);
+                                       });
+                               }
+                       });
+               }
+
+               function cellDialog() {
+                       var dom = editor.dom, cellElm, data, cells = [];
+
+                       // Get selected cells or the current cell
+                       cells = editor.dom.select('td.mce-item-selected,th.mce-item-selected');
+                       cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
+                       if (!cells.length && cellElm) {
+                               cells.push(cellElm);
+                       }
+
+                       cellElm = cellElm || cells[0];
+
+                       data = {
+                               width: removePxSuffix(dom.getStyle(cellElm, 'width') || dom.getAttrib(cellElm, 'width')),
+                               height: removePxSuffix(dom.getStyle(cellElm, 'height') || dom.getAttrib(cellElm, 'height')),
+                               scope: dom.getAttrib(cellElm, 'scope')
+                       };
+
+                       data.type = cellElm.nodeName.toLowerCase();
+
+                       each('left center right'.split(' '), function(name) {
+                               if (editor.formatter.matchNode(cellElm, 'align' + name)) {
+                                       data.align = name;
+                               }
+                       });
+
+                       editor.windowManager.open({
+                               title: "Cell properties",
+                               items: {
+                                       type: 'form',
+                                       data: data,
+                                       layout: 'grid',
+                                       columns: 2,
+                                       defaults: {
+                                               type: 'textbox',
+                                               maxWidth: 50
+                                       },
+                                       items: [
+                                               {label: 'Width', name: 'width'},
+                                               {label: 'Height', name: 'height'},
+                                               {
+                                                       label: 'Cell type',
+                                                       name: 'type',
+                                                       type: 'listbox',
+                                                       text: 'None',
+                                                       minWidth: 90,
+                                                       maxWidth: null,
+                                                       menu: [
+                                                               {text: 'Cell', value: 'td'},
+                                                               {text: 'Header cell', value: 'th'}
+                                                       ]
+                                               },
+                                               {
+                                                       label: 'Scope',
+                                                       name: 'scope',
+                                                       type: 'listbox',
+                                                       text: 'None',
+                                                       minWidth: 90,
+                                                       maxWidth: null,
+                                                       menu: [
+                                                               {text: 'None', value: ''},
+                                                               {text: 'Row', value: 'row'},
+                                                               {text: 'Column', value: 'col'},
+                                                               {text: 'Row group', value: 'rowgroup'},
+                                                               {text: 'Column group', value: 'colgroup'}
+                                                       ]
+                                               },
+                                               {
+                                                       label: 'Alignment',
+                                                       name: 'align',
+                                                       type: 'listbox',
+                                                       text: 'None',
+                                                       minWidth: 90,
+                                                       maxWidth: null,
+                                                       values: [
+                                                               {text: 'None', value: ''},
+                                                               {text: 'Left', value: 'left'},
+                                                               {text: 'Center', value: 'center'},
+                                                               {text: 'Right', value: 'right'}
+                                                       ]
+                                               }
+                                       ]
+                               },
+
+                               onsubmit: function() {
+                                       var data = this.toJSON();
+
+                                       editor.undoManager.transact(function() {
+                                               each(cells, function(cellElm) {
+                                                       editor.dom.setAttrib(cellElm, 'scope', data.scope);
+
+                                                       editor.dom.setStyles(cellElm, {
+                                                               width: addSizeSuffix(data.width),
+                                                               height: addSizeSuffix(data.height)
+                                                       });
+
+                                                       // Switch cell type
+                                                       if (data.type && cellElm.nodeName.toLowerCase() != data.type) {
+                                                               cellElm = dom.rename(cellElm, data.type);
+                                                       }
+
+                                                       // Apply/remove alignment
+                                                       unApplyAlign(cellElm);
+                                                       if (data.align) {
+                                                               editor.formatter.apply('align' + data.align, {}, cellElm);
+                                                       }
+                                               });
+
+                                               editor.focus();
+                                       });
+                               }
+                       });
+               }
+
+               function rowDialog() {
+                       var dom = editor.dom, tableElm, cellElm, rowElm, data, rows = [];
+
+                       tableElm = editor.dom.getParent(editor.selection.getStart(), 'table');
+                       cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
+
+                       each(tableElm.rows, function(row) {
+                               each(row.cells, function(cell) {
+                                       if (dom.hasClass(cell, 'mce-item-selected') || cell == cellElm) {
+                                               rows.push(row);
+                                               return false;
+                                       }
+                               });
+                       });
+
+                       rowElm = rows[0];
+
+                       data = {
+                               height: removePxSuffix(dom.getStyle(rowElm, 'height') || dom.getAttrib(rowElm, 'height')),
+                               scope: dom.getAttrib(rowElm, 'scope')
+                       };
+
+                       data.type = rowElm.parentNode.nodeName.toLowerCase();
+
+                       each('left center right'.split(' '), function(name) {
+                               if (editor.formatter.matchNode(rowElm, 'align' + name)) {
+                                       data.align = name;
+                               }
+                       });
+
+                       editor.windowManager.open({
+                               title: "Row properties",
+                               items: {
+                                       type: 'form',
+                                       data: data,
+                                       columns: 2,
+                                       defaults: {
+                                               type: 'textbox'
+                                       },
+                                       items: [
+                                               {
+                                                       type: 'listbox',
+                                                       name: 'type',
+                                                       label: 'Row type',
+                                                       text: 'None',
+                                                       maxWidth: null,
+                                                       menu: [
+                                                               {text: 'Header', value: 'thead'},
+                                                               {text: 'Body', value: 'tbody'},
+                                                               {text: 'Footer', value: 'tfoot'}
+                                                       ]
+                                               },
+                                               {
+                                                       type: 'listbox',
+                                                       name: 'align',
+                                                       label: 'Alignment',
+                                                       text: 'None',
+                                                       maxWidth: null,
+                                                       menu: [
+                                                               {text: 'None', value: ''},
+                                                               {text: 'Left', value: 'left'},
+                                                               {text: 'Center', value: 'center'},
+                                                               {text: 'Right', value: 'right'}
+                                                       ]
+                                               },
+                                               {label: 'Height', name: 'height'}
+                                       ]
+                               },
+
+                               onsubmit: function() {
+                                       var data = this.toJSON(), tableElm, oldParentElm, parentElm;
+
+                                       editor.undoManager.transact(function() {
+                                               var toType = data.type;
+
+                                               each(rows, function(rowElm) {
+                                                       editor.dom.setAttrib(rowElm, 'scope', data.scope);
+
+                                                       editor.dom.setStyles(rowElm, {
+                                                               height: addSizeSuffix(data.height)
+                                                       });
+
+                                                       if (toType != rowElm.parentNode.nodeName.toLowerCase()) {
+                                                               tableElm = dom.getParent(rowElm, 'table');
+
+                                                               oldParentElm = rowElm.parentNode;
+                                                               parentElm = dom.select(toType, tableElm)[0];
+                                                               if (!parentElm) {
+                                                                       parentElm = dom.create(toType);
+                                                                       if (tableElm.firstChild) {
+                                                                               tableElm.insertBefore(parentElm, tableElm.firstChild);
+                                                                       } else {
+                                                                               tableElm.appendChild(parentElm);
+                                                                       }
+                                                               }
+
+                                                               parentElm.appendChild(rowElm);
+
+                                                               if (!oldParentElm.hasChildNodes()) {
+                                                                       dom.remove(oldParentElm);
+                                                               }
+                                                       }
+
+                                                       // Apply/remove alignment
+                                                       unApplyAlign(rowElm);
+                                                       if (data.align) {
+                                                               editor.formatter.apply('align' + data.align, {}, rowElm);
+                                                       }
+                                               });
+
+                                               editor.focus();
+                                       });
+                               }
+                       });
+               }
+
+               function cmd(command) {
+                       return function() {
+                               editor.execCommand(command);
+                       };
+               }
+
+               function insertTable(cols, rows) {
+                       var y, x, html;
+
+                       html = '<table><tbody>';
+
+                       for (y = 0; y < rows; y++) {
+                               html += '<tr>';
+
+                               for (x = 0; x < cols; x++) {
+                                       html += '<td>' + (Env.ie ? " " : '<br>') + '</td>';
+                               }
+
+                               html += '</tr>';
+                       }
+
+                       html += '</tbody></table>';
+
+                       editor.insertContent(html);
+               }
+
+               function handleDisabledState(ctrl, selector) {
+                       function bindStateListener() {
+                               ctrl.disabled(!editor.dom.getParent(editor.selection.getStart(), selector));
+
+                               editor.selection.selectorChanged(selector, function(state) {
+                                       ctrl.disabled(!state);
+                               });
+                       }
+
+                       if (editor.initialized) {
+                               bindStateListener();
+                       } else {
+                               editor.on('init', bindStateListener);
+                       }
+               }
+
+               function postRender() {
+                       /*jshint validthis:true*/
+                       handleDisabledState(this, 'table');
+               }
+
+               function postRenderCell() {
+                       /*jshint validthis:true*/
+                       handleDisabledState(this, 'td,th');
+               }
+
+               function generateTableGrid() {
+                       var html = '';
+
+                       html = '<table role="presentation" class="mce-grid mce-grid-border">';
+
+                       for (var y = 0; y < 10; y++) {
+                               html += '<tr>';
+
+                               for (var x = 0; x < 10; x++) {
+                                       html += '<td><a href="#" data-mce-index="' + x + ',' + y + '"></a></td>';
+                               }
+
+                               html += '</tr>';
+                       }
+
+                       html += '</table>';
+
+                       html += '<div class="mce-text-center">0 x 0</div>';
+
+                       return html;
+               }
+
+               editor.addMenuItem('inserttable', {
+                       text: 'Insert table',
+                       icon: 'table',
+                       context: 'table',
+                       onhide: function() {
+                               editor.dom.removeClass(this.menu.items()[0].getEl().getElementsByTagName('a'), 'mce-active');
+                       },
+                       menu: [
+                               {
+                                       type: 'container',
+                                       html: generateTableGrid(),
+
+                                       onmousemove: function(e) {
+                                               var x, y, target = e.target;
+
+                                               if (target.nodeName == 'A') {
+                                                       var table = editor.dom.getParent(target, 'table');
+                                                       var pos = target.getAttribute('data-mce-index');
+                                                       var rel = e.control.parent().rel;
+
+                                                       if (pos != this.lastPos) {
+                                                               pos = pos.split(',');
+
+                                                               pos[0] = parseInt(pos[0], 10);
+                                                               pos[1] = parseInt(pos[1], 10);
+
+                                                               if (e.control.isRtl() || rel == 'tl-tr') {
+                                                                       for (y = 9; y >= 0; y--) {
+                                                                               for (x = 0; x < 10; x++) {
+                                                                                       editor.dom.toggleClass(
+                                                                                               table.rows[y].childNodes[x].firstChild,
+                                                                                               'mce-active',
+                                                                                               x >= pos[0] && y <= pos[1]
+                                                                                       );
+                                                                               }
+                                                                       }
+
+                                                                       pos[0] = 9 - pos[0];
+                                                                       table.nextSibling.innerHTML = pos[0] + ' x '+ (pos[1] + 1);
+                                                               } else {
+                                                                       for (y = 0; y < 10; y++) {
+                                                                               for (x = 0; x < 10; x++) {
+                                                                                       editor.dom.toggleClass(
+                                                                                               table.rows[y].childNodes[x].firstChild,
+                                                                                               'mce-active',
+                                                                                               x <= pos[0] && y <= pos[1]
+                                                                                       );
+                                                                               }
+                                                                       }
+
+                                                                       table.nextSibling.innerHTML = (pos[0] + 1) + ' x '+ (pos[1] + 1);
+                                                               }
+
+                                                               this.lastPos = pos;
+                                                       }
+                                               }
+                                       },
+
+                                       onclick: function(e) {
+                                               if (e.target.nodeName == 'A' && this.lastPos) {
+                                                       e.preventDefault();
+
+                                                       insertTable(this.lastPos[0] + 1, this.lastPos[1] + 1);
+
+                                                       // TODO: Maybe rework this?
+                                                       this.parent().cancel(); // Close parent menu as if it was a click
+                                               }
+                                       }
+                               }
+                       ]
+               });
+
+               editor.addMenuItem('tableprops', {
+                       text: 'Table properties',
+                       context: 'table',
+                       onPostRender: postRender,
+                       onclick: tableDialog
+               });
+
+               editor.addMenuItem('deletetable', {
+                       text: 'Delete table',
+                       context: 'table',
+                       onPostRender: postRender,
+                       cmd: 'mceTableDelete'
+               });
+
+               editor.addMenuItem('cell', {
+                       separator: 'before',
+                       text: 'Cell',
+                       context: 'table',
+                       menu: [
+                               {text: 'Cell properties', onclick: cmd('mceTableCellProps'), onPostRender: postRenderCell},
+                               {text: 'Merge cells', onclick: cmd('mceTableMergeCells'), onPostRender: postRenderCell},
+                               {text: 'Split cell', onclick: cmd('mceTableSplitCells'), onPostRender: postRenderCell}
+                       ]
+               });
+
+               editor.addMenuItem('row', {
+                       text: 'Row',
+                       context: 'table',
+                       menu: [
+                               {text: 'Insert row before', onclick: cmd('mceTableInsertRowBefore'), onPostRender: postRenderCell},
+                               {text: 'Insert row after', onclick: cmd('mceTableInsertRowAfter'), onPostRender: postRenderCell},
+                               {text: 'Delete row', onclick: cmd('mceTableDeleteRow'), onPostRender: postRenderCell},
+                               {text: 'Row properties', onclick: cmd('mceTableRowProps'), onPostRender: postRenderCell},
+                               {text: '-'},
+                               {text: 'Cut row', onclick: cmd('mceTableCutRow'), onPostRender: postRenderCell},
+                               {text: 'Copy row', onclick: cmd('mceTableCopyRow'), onPostRender: postRenderCell},
+                               {text: 'Paste row before', onclick: cmd('mceTablePasteRowBefore'), onPostRender: postRenderCell},
+                               {text: 'Paste row after', onclick: cmd('mceTablePasteRowAfter'), onPostRender: postRenderCell}
+                       ]
+               });
+
+               editor.addMenuItem('column', {
+                       text: 'Column',
+                       context: 'table',
+                       menu: [
+                               {text: 'Insert column before', onclick: cmd('mceTableInsertColBefore'), onPostRender: postRenderCell},
+                               {text: 'Insert column after', onclick: cmd('mceTableInsertColAfter'), onPostRender: postRenderCell},
+                               {text: 'Delete column', onclick: cmd('mceTableDeleteCol'), onPostRender: postRenderCell}
+                       ]
+               });
+
+               var menuItems = [];
+               each("inserttable tableprops deletetable | cell row column".split(' '), function(name) {
+                       if (name == '|') {
+                               menuItems.push({text: '-'});
+                       } else {
+                               menuItems.push(editor.menuItems[name]);
+                       }
+               });
+
+               editor.addButton("table", {
+                       type: "menubutton",
+                       title: "Table",
+                       menu: menuItems
+               });
+
+               // Select whole table is a table border is clicked
+               if (!Env.isIE) {
+                       editor.on('click', function(e) {
+                               e = e.target;
+
+                               if (e.nodeName === 'TABLE') {
+                                       editor.selection.select(e);
+                                       editor.nodeChanged();
+                               }
+                       });
+               }
+
+               self.quirks = new Quirks(editor);
+
+               editor.on('Init', function() {
+                       winMan = editor.windowManager;
+                       self.cellSelection = new CellSelection(editor);
+               });
+
+               // Register action commands
+               each({
+                       mceTableSplitCells: function(grid) {
+                               grid.split();
+                       },
+
+                       mceTableMergeCells: function(grid) {
+                               var rowSpan, colSpan, cell;
+
+                               cell = editor.dom.getParent(editor.selection.getStart(), 'th,td');
+                               if (cell) {
+                                       rowSpan = cell.rowSpan;
+                                       colSpan = cell.colSpan;
+                               }
+
+                               if (!editor.dom.select('td.mce-item-selected,th.mce-item-selected').length) {
+                                       mergeDialog(grid, cell);
+                               } else {
+                                       grid.merge();
+                               }
+                       },
+
+                       mceTableInsertRowBefore: function(grid) {
+                               grid.insertRow(true);
+                       },
+
+                       mceTableInsertRowAfter: function(grid) {
+                               grid.insertRow();
+                       },
+
+                       mceTableInsertColBefore: function(grid) {
+                               grid.insertCol(true);
+                       },
+
+                       mceTableInsertColAfter: function(grid) {
+                               grid.insertCol();
+                       },
+
+                       mceTableDeleteCol: function(grid) {
+                               grid.deleteCols();
+                       },
+
+                       mceTableDeleteRow: function(grid) {
+                               grid.deleteRows();
+                       },
+
+                       mceTableCutRow: function(grid) {
+                               clipboardRows = grid.cutRows();
+                       },
+
+                       mceTableCopyRow: function(grid) {
+                               clipboardRows = grid.copyRows();
+                       },
+
+                       mceTablePasteRowBefore: function(grid) {
+                               grid.pasteRows(clipboardRows, true);
+                       },
+
+                       mceTablePasteRowAfter: function(grid) {
+                               grid.pasteRows(clipboardRows);
+                       },
+
+                       mceTableDelete: function(grid) {
+                               grid.deleteTable();
+                       }
+               }, function(func, name) {
+                       editor.addCommand(name, function() {
+                               var grid = new TableGrid(editor);
+
+                               if (grid) {
+                                       func(grid);
+                                       editor.execCommand('mceRepaint');
+                                       self.cellSelection.clear();
+                               }
+                       });
+               });
+
+               // Register dialog commands
+               each({
+                       mceInsertTable: function() {
+                               tableDialog();
+                       },
+
+                       mceTableRowProps: rowDialog,
+                       mceTableCellProps: cellDialog
+               }, function(func, name) {
+                       editor.addCommand(name, function(ui, val) {
+                               func(val);
+                       });
+               });
+       }
+
+       PluginManager.add('table', Plugin);
+});
+
+expose(["tinymce/tableplugin/TableGrid","tinymce/tableplugin/Quirks","tinymce/tableplugin/CellSelection","tinymce/tableplugin/Plugin"]);
+})(this);
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/external-plugins/table/plugin.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorexternalpluginstablepluginminjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/external-plugins/table/plugin.min.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/external-plugins/table/plugin.min.js                            (rev 0)
+++ trunk/tests/qunit/editor/external-plugins/table/plugin.min.js       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;i<e.length;++i){if(n=s[e[i]]||o(e[i]),!n)throw"module definition dependecy not found: "+e[i];r.push(n)}t.apply(null,r)}function r(e,r,i){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(r===t)throw"invalid module definition, dependencies must be specified";if(i===t)throw"invalid module definition, definition function must be specified";n(r,function(){s[e]=i.apply(null,arguments)})}function i(e){return!!s[e]}function o(t){for(var n=e,r=t.split(/[.\/]/),i=0;i<r.length;++i){if(!n[r[i]])return;n=n[r[i]]}return n}function a(n){for(var r=0;r<n.length;r++){for(var i=e,o=n[r],a=o.split(/[.\/]/),l=0;l<a.length-1;++l)i[a[l]]===t&&(i[a[l]]={}),i=i[a[l]];i[a[a.length-1]]=s[o]}}var s={},l="tinymce/tableplugin/TableGrid",c="tinymce/util/Tools",d="tinymce/Env",u=&q
 uot;tinymce/tableplugin/Quirks",f="tinymce/util/VK",p="tinymce/tableplugin/CellSelection",m="tinymce/dom/TreeWalker",h="tinymce/tableplugin/Plugin",g="tinymce/PluginManager";r(l,[c,d],function(e,t){function n(e,t){return parseInt(e.getAttribute(t)||1,10)}var r=e.each;return function(i,o){function a(){var e=0;R=[],r(["thead","tbody","tfoot"],function(t){var i=H.select("> "+t+" tr",o);r(i,function(i,o){o+=e,r(H.select("> td, > th",i),function(e,r){var i,a,s,l;if(R[o])for(;R[o][r];)r++;for(s=n(e,"rowspan"),l=n(e,"colspan"),a=o;o+s>a;a++)for(R[a]||(R[a]=[]),i=r;r+l>i;i++)R[a][i]={part:t,real:a==o&&i==r,elm:e,rowspan:s,colspan:l}})}),e+=i.length})}function s(e,t){return e=e.cloneNode(t),e.removeAttribute("id"),e}function l(e,t){var n;return n=R[t],n?n[e]:void 0}function c(e,t,n){e&&(n=parseInt(n,10),1===n?e.removeA
 ttribute(t,1):e.setAttribute(t,n,1))}function d(e){return e&&(H.hasClass(e.elm,"mce-item-selected")||e==L)}function u(){var e=[];return r(o.rows,function(t){r(t.cells,function(n){return H.hasClass(n,"mce-item-selected")||n==L.elm?(e.push(t),!1):void 0})}),e}function f(){var e=H.createRng();e.setStartAfter(o),e.setEndAfter(o),D.setRng(e),H.remove(o)}function p(n){var o,a={};return i.settings.table_clone_elements!==!1&&(a=e.makeMap((i.settings.table_clone_elements||"strong em b i span font h1 h2 h3 h4 h5 h6 p div").toUpperCase(),/[ ,]/)),e.walk(n,function(e){var i;return 3==e.nodeType?(r(H.getParents(e.parentNode,null,n).reverse(),function(e){a[e.nodeName]&&(e=s(e,!1),o?i&&i.appendChild(e):o=i=e,i=e)}),i&&(i.innerHTML=t.ie?"&nbsp;":'<br data-mce-bogus="1" />'),!1):void 0},"childNodes"),n=s(n,!1),c(n,"rowSpan",1),c(n,"colSpan",1),o?n.appendChild(o):t.ie||(n.
 innerHTML='<br data-mce-bogus="1" />'),n}function m(){var e=H.createRng(),t;return r(H.select("tr",o),function(e){0===e.cells.length&&H.remove(e)}),0===H.select("tr",o).length?(e.setStartBefore(o),e.setEndBefore(o),D.setRng(e),H.remove(o),void 0):(r(H.select("thead,tbody,tfoot",o),function(e){0===e.rows.length&&H.remove(e)}),a(),t=R[Math.min(R.length-1,A.y)],t&&(D.select(t[Math.min(t.length-1,A.x)].elm,!0),D.collapse(!0)),void 0)}function h(e,t,n,r){var i,o,a,s,l;for(i=R[t][e].elm.parentNode,a=1;n>=a;a++)if(i=H.getNext(i,"tr")){for(o=e;o>=0;o--)if(l=R[t+a][o].elm,l.parentNode==i){for(s=1;r>=s;s++)H.insertAfter(p(l),l);break}if(-1==o)for(s=1;r>=s;s++)i.insertBefore(p(i.cells[0]),i.cells[0])}}function g(){r(R,function(e,t){r(e,function(e,r){var i,o,a;if(d(e)&&(e=e.elm,i=n(e,"colspan"),o=n(e,"rowspan"),i>1||o>1)){for(c(e,"rowSpan",1),c(e,"colSpan&
 quot;,1),a=0;i-1>a;a++)H.insertAfter(p(e),e);h(r,t,o-1,i)}})})}function v(t,n,i){var o,s,u,f,p,h,v,y,b,C,x;if(t?(o=E(t),s=o.x,u=o.y,f=s+(n-1),p=u+(i-1)):(A=B=null,r(R,function(e,t){r(e,function(e,n){d(e)&&(A||(A={x:n,y:t}),B={x:n,y:t})})}),s=A.x,u=A.y,f=B.x,p=B.y),y=l(s,u),b=l(f,p),y&&b&&y.part==b.part){for(g(),a(),y=l(s,u).elm,c(y,"colSpan",f-s+1),c(y,"rowSpan",p-u+1),v=u;p>=v;v++)for(h=s;f>=h;h++)R[v]&&R[v][h]&&(t=R[v][h].elm,t!=y&&(C=e.grep(t.childNodes),r(C,function(e){y.appendChild(e)}),C.length&&(C=e.grep(y.childNodes),x=0,r(C,function(e){"BR"==e.nodeName&&H.getAttrib(e,"data-mce-bogus")&&x++<C.length-1&&y.removeChild(e)})),H.remove(t)));m()}}function y(e){var t,i,o,a,l,u,f,m,h;for(r(R,function(n,i){return r(n,function(n){return d(n)&&(n=n.elm,l=n.parentNode,u=s(l,!1),t=i,e)?!1:void 0}),e?!t:void 0}),a=0;a<R[0].length;a++)if(R[t][a]&amp
 ;&(i=R[t][a].elm,i!=o)){if(e){if(t>0&&R[t-1][a]&&(m=R[t-1][a].elm,h=n(m,"rowSpan"),h>1)){c(m,"rowSpan",h+1);continue}}else if(h=n(i,"rowspan"),h>1){c(i,"rowSpan",h+1);continue}f=p(i),c(f,"colSpan",i.colSpan),u.appendChild(f),o=i}u.hasChildNodes()&&(e?l.parentNode.insertBefore(u,l):H.insertAfter(u,l))}function b(e){var t,i;r(R,function(n){return r(n,function(n,r){return d(n)&&(t=r,e)?!1:void 0}),e?!t:void 0}),r(R,function(r,o){var a,s,l;r[t]&&(a=r[t].elm,a!=i&&(l=n(a,"colspan"),s=n(a,"rowspan"),1==l?e?(a.parentNode.insertBefore(p(a),a),h(t,o,s-1,l)):(H.insertAfter(p(a),a),h(t,o,s-1,l)):c(a,"colSpan",a.colSpan+1),i=a))})}function C(){var t=[];r(R,function(i){r(i,function(i,o){d(i)&&-1===e.inArray(t,o)&&(r(R,function(e){var t=e[o].elm,r;r=n(t,"colSpan"),r>1?c(t,"colSpan",r-1):H.remove(t)}),t.push(o))})}),m()}
 function x(){function e(e){var t,i,o;t=H.getNext(e,"tr"),r(e.cells,function(e){var t=n(e,"rowSpan");t>1&&(c(e,"rowSpan",t-1),i=E(e),h(i.x,i.y,1,1))}),i=E(e.cells[0]),r(R[i.y],function(e){var t;e=e.elm,e!=o&&(t=n(e,"rowSpan"),1>=t?H.remove(e):c(e,"rowSpan",t-1),o=e)})}var t;t=u(),r(t.reverse(),function(t){e(t)}),m()}function w(){var e=u();return H.remove(e),m(),e}function _(){var e=u();return r(e,function(t,n){e[n]=s(t,!0)}),e}function N(e,t){var n=u(),i=n[t?0:n.length-1],o=i.cells.length;e&&(r(R,function(e){var t;return o=0,r(e,function(e){e.real&&(o+=e.colspan),e.elm.parentNode==i&&(t=1)}),t?!1:void 0}),t||e.reverse(),r(e,function(e){var n,r=e.cells.length,a;for(n=0;r>n;n++)a=e.cells[n],c(a,"colSpan",1),c(a,"rowSpan",1);for(n=r;o>n;n++)e.appendChild(p(e.cells[r-1]));for(n=o;r>n;n++)H.remove(e.cells[n]);t?i.parentNode.insertBefore(e,i):H.insertAfter(e,i)}),H.r
 emoveClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"))}function E(e){var t;return r(R,function(n,i){return r(n,function(n,r){return n.elm==e?(t={x:r,y:i},!1):void 0}),!t}),t}function k(e){A=E(e)}function S(){var e,t;return e=t=0,r(R,function(n,i){r(n,function(n,r){var o,a;d(n)&&(n=R[i][r],r>e&&(e=r),i>t&&(t=i),n.real&&(o=n.colspan-1,a=n.rowspan-1,o&&r+o>e&&(e=r+o),a&&i+a>t&&(t=i+a)))})}),{x:e,y:t}}function T(e){var t,n,r,i,o,a,s,l,c,d;if(B=E(e),A&&B){for(t=Math.min(A.x,B.x),n=Math.min(A.y,B.y),r=Math.max(A.x,B.x),i=Math.max(A.y,B.y),o=r,a=i,d=n;a>=d;d++)e=R[d][t],e.real||t-(e.colspan-1)<t&&(t-=e.colspan-1);for(c=t;o>=c;c++)e=R[n][c],e.real||n-(e.rowspan-1)<n&&(n-=e.rowspan-1);for(d=n;i>=d;d++)for(c=t;r>=c;c++)e=R[d][c],e.real&&(s=e.colspan-1,l=e.rowspan-1,s&&c+s>o&&(o=c+s),l&&d+l&g
 t;a&&(a=d+l));for(H.removeClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),d=n;a>=d;d++)for(c=t;o>=c;c++)R[d][c]&&H.addClass(R[d][c].elm,"mce-item-selected")}}var R,A,B,L,D=i.selection,H=D.dom;o=o||H.getParent(D.getStart(),"table"),a(),L=H.getParent(D.getStart(),"th,td"),L&&(A=E(L),B=S(),L=l(A.x,A.y)),e.extend(this,{deleteTable:f,split:g,merge:v,insertRow:y,insertCol:b,deleteCols:C,deleteRows:x,cutRows:w,copyRows:_,pasteRows:N,getPos:E,setStartCell:k,setEndCell:T})}}),r(u,[f,d,c],function(e,t,n){function r(e,t){return parseInt(e.getAttribute(t)||1,10)}var i=n.each;return function(n){function o(){function t(t){function o(e,r){var i=e?"previousSibling":"nextSibling",o=n.dom.getParent(r,"tr"),s=o[i];if(s)return g(n,r,s,e),t.preventDefault(),!0;var d=n.dom.getParent(o,"table"),u=o.parentNode,f=u.nodeName.toLowerCase();if("tbody&quot
 ;===f||f===(e?"tfoot":"thead")){var p=a(e,d,u,"tbody");if(null!==p)return l(e,p,r)}return c(e,o,i,d)}function a(e,t,r,i){var o=n.dom.select(">"+i,t),a=o.indexOf(r);if(e&&0===a||!e&&a===o.length-1)return s(e,t);if(-1===a){var l="thead"===r.tagName.toLowerCase()?0:o.length-1;return o[l]}return o[a+(e?-1:1)]}function s(e,t){var r=e?"thead":"tfoot",i=n.dom.select(">"+r,t);return 0!==i.length?i[0]:null}function l(e,r,i){var o=d(r,e);return o&&g(n,i,o,e),t.preventDefault(),!0}function c(e,r,i,a){var s=a[i];if(s)return u(s),!0;var l=n.dom.getParent(a,"td,th");if(l)return o(e,l,t);var c=d(r,!e);return u(c),t.preventDefault(),!1}function d(e,t){var r=e&&e[t?"lastChild":"firstChild"];return r&&"BR"===r.nodeName?n.dom.getParent(r,"td,th"):r}function u(e){n.selection.setCursorLocation(e,0)}function f(){return b==e.UP||b==
 e.DOWN}function p(e){var t=e.selection.getNode(),n=e.dom.getParent(t,"tr");return null!==n}function m(e){for(var t=0,n=e;n.previousSibling;)n=n.previousSibling,t+=r(n,"colspan");return t}function h(e,t){var n=0,o=0;return i(e.children,function(e,i){return n+=r(e,"colspan"),o=i,n>t?!1:void 0}),o}function g(e,t,r,i){var o=m(n.dom.getParent(t,"td,th")),a=h(r,o),s=r.childNodes[a],l=d(s,i);u(l||s)}function v(e){var t=n.selection.getNode(),r=n.dom.getParent(t,"td,th"),i=n.dom.getParent(e,"td,th");return r&&r!==i&&y(r,i)}function y(e,t){return n.dom.getParent(e,"TABLE")===n.dom.getParent(t,"TABLE")}var b=t.keyCode;if(f()&&p(n)){var C=n.selection.getNode();setTimeout(function(){v(C)&&o(!t.shiftKey&&b===e.UP,C,t)},0)}}n.on("KeyDown",function(e){t(e)})}function a(){function e(e,t){var n=t.ownerDocument,r=n.createRange(),i;return r.setStartBefore(t),r.setEnd(e.en
 dContainer,e.endOffset),i=n.createElement("body"),i.appendChild(r.cloneContents()),0===i.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length}n.on("KeyDown",function(t){var r,i,o=n.dom;(37==t.keyCode||38==t.keyCode)&&(r=n.selection.getRng(),i=o.getParent(r.startContainer,"table"),i&&n.getBody().firstChild==i&&e(r,i)&&(r=o.createRng(),r.setStartBefore(i),r.setEndBefore(i),n.selection.setRng(r),t.preventDefault()))})}function s(){n.on("KeyDown SetContent VisualAid",function(){var e;for(e=n.getBody().lastChild;e;e=e.previousSibling)if(3==e.nodeType){if(e.nodeValue.length>0)break}else if(1==e.nodeType&&!e.getAttribute("data-mce-bogus"))break;e&&"TABLE"==e.nodeName&&(n.settings.forced_root_block?n.dom.add(n.getBody(),n.settings.forced_root_block,n.settings.forced_root_block_attrs,t.ie&a
 mp;&t.ie<11?"&nbsp;":'<br data-mce-bogus="1" />'):n.dom.add(n.getBody(),"br",{"data-mce-bogus":"1"}))}),n.on("PreProcess",function(e){var t=e.node.lastChild;t&&("BR"==t.nodeName||1==t.childNodes.length&&("BR"==t.firstChild.nodeName||"\xa0"==t.firstChild.nodeValue))&&t.previousSibling&&"TABLE"==t.previousSibling.nodeName&&n.dom.remove(t)})}function l(){function e(e,t,n,r){var i=3,o=e.dom.getParent(t.startContainer,"TABLE"),a,s,l;return o&&(a=o.parentNode),s=t.startContainer.nodeType==i&&0===t.startOffset&&0===t.endOffset&&r&&("TR"==n.nodeName||n==a),l=("TD"==n.nodeName||"TH"==n.nodeName)&&!r,s||l}function t(){var t=n.selection.getRng(),r=n.selection.getNode(),i=n.dom.getParent(t.startContainer,"TD,TH");if(e(n,t,r,i)){i||(i=r);for(var
  o=i.lastChild;o.lastChild;)o=o.lastChild;t.setEnd(o,o.nodeValue.length),n.selection.setRng(t)}}n.on("KeyDown",function(){t()}),n.on("MouseDown",function(e){2!=e.button&&t()})}function c(){n.on("keydown",function(t){if((t.keyCode==e.DELETE||t.keyCode==e.BACKSPACE)&&!t.isDefaultPrevented()){var r=n.dom.getParent(n.selection.getStart(),"table");if(r){for(var i=n.dom.select("td,th",r),o=i.length;o--;)if(!n.dom.hasClass(i[o],"mce-item-selected"))return;t.preventDefault(),n.execCommand("mceTableDelete")}}})}c(),t.webkit&&(o(),l()),t.gecko&&(a(),s()),t.ie>10&&(a(),s())}}),r(p,[l,m,c],function(e,t,n){return function(r){function i(){r.getBody().style.webkitUserSelect="",d&&(r.dom.removeClass(r.dom.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),d=!1)}function o(t){var n,i,o=t.target;if(l&&(s||o!=l)&&(&
 quot;TD"==o.nodeName||"TH"==o.nodeName)){i=a.getParent(o,"table"),i==c&&(s||(s=new e(r,i),s.setStartCell(l),r.getBody().style.webkitUserSelect="none"),s.setEndCell(o),d=!0),n=r.selection.getSel();try{n.removeAllRanges?n.removeAllRanges():n.empty()}catch(u){}t.preventDefault()}}var a=r.dom,s,l,c,d=!0;return r.on("MouseDown",function(e){2!=e.button&&(i(),l=a.getParent(e.target,"td,th"),c=a.getParent(l,"table"))}),a.bind(r.getDoc(),"mouseover",o),r.on("remove",function(){a.unbind(r.getDoc(),"mouseover",o)}),r.on("MouseUp",function(){function e(e,r){var o=new t(e,e);do{if(3==e.nodeType&&0!==n.trim(e.nodeValue).length)return r?i.setStart(e,0):i.setEnd(e,e.nodeValue.length),void 0;if("BR"==e.nodeName)return r?i.setStartBefore(e):i.setEndBefore(e),void 0}while(e=r?o.next():o.prev())}var i,o=r.selection,d,u,f,p,m;if(l){if(s&&(r.getBody().style.we
 bkitUserSelect=""),d=a.select("td.mce-item-selected,th.mce-item-selected"),d.length>0){i=a.createRng(),f=d[0],m=d[d.length-1],i.setStartBefore(f),i.setEndAfter(f),e(f,1),u=new t(f,a.getParent(d[0],"table"));do if("TD"==f.nodeName||"TH"==f.nodeName){if(!a.hasClass(f,"mce-item-selected"))break;p=f}while(f=u.next());e(p),o.setRng(i)}r.nodeChanged(),l=s=c=null}}),r.on("KeyUp",function(){i()}),{clear:i}}}),r(h,[l,u,p,c,m,d,g],function(e,t,n,r,i,o,a){function s(r){function i(e){return e?e.replace(/px$/,""):""}function a(e){return/^[0-9]+$/.test(e)&&(e+="px"),e}function s(e){l("left center right".split(" "),function(t){r.formatter.remove("align"+t,{},e)})}function c(){var e=r.dom,t,n;t=e.getParent(r.selection.getStart(),"table"),n={width:i(e.getStyle(t,"width")||e.getAttrib(t,"width")),height:i(e.getStyle(t,"height&q
 uot;)||e.getAttrib(t,"height")),cellspacing:e.getAttrib(t,"cellspacing"),cellpadding:e.getAttrib(t,"cellpadding"),border:e.getAttrib(t,"border"),caption:!!e.select("caption",t)[0]},l("left center right".split(" "),function(e){r.formatter.matchNode(t,"align"+e)&&(n.align=e)}),r.windowManager.open({title:"Table properties",items:{type:"form",layout:"grid",columns:2,data:n,defaults:{type:"textbox",maxWidth:50},items:[{label:"Width",name:"width"},{label:"Height",name:"height"},{label:"Cell spacing",name:"cellspacing"},{label:"Cell padding",name:"cellpadding"},{label:"Border",name:"border"},{label:"Caption",name:"caption",type:"checkbox"},{label:"Alignment",minWidth:90,name:"align",type:"listbox",text:&qu
 ot;None",maxWidth:null,values:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]},onsubmit:function(){var n=this.toJSON(),i;r.undoManager.transact(function(){r.dom.setAttribs(t,{cellspacing:n.cellspacing,cellpadding:n.cellpadding,border:n.border}),r.dom.setStyles(t,{width:a(n.width),height:a(n.height)}),i=e.select("caption",t)[0],i&&!n.caption&&e.remove(i),!i&&n.caption&&(i=e.create("caption"),i.innerHTML=o.ie?"\xa0":'<br data-mce-bogus="1"/>',t.insertBefore(i,t.firstChild)),s(t),n.align&&r.formatter.apply("align"+n.align,{},t),r.focus(),r.addVisual()})}})}function d(e,t){r.windowManager.open({title:"Merge cells",body:[{label:"Cols",name:"cols",type:"textbox",size:10},{label:"Rows",name:"r
 ows",type:"textbox",size:10}],onsubmit:function(){var n=this.toJSON();r.undoManager.transact(function(){e.merge(t,n.cols,n.rows)})}})}function u(){var e=r.dom,t,n,o=[];o=r.dom.select("td.mce-item-selected,th.mce-item-selected"),t=r.dom.getParent(r.selection.getStart(),"td,th"),!o.length&&t&&o.push(t),t=t||o[0],n={width:i(e.getStyle(t,"width")||e.getAttrib(t,"width")),height:i(e.getStyle(t,"height")||e.getAttrib(t,"height")),scope:e.getAttrib(t,"scope")},n.type=t.nodeName.toLowerCase(),l("left center right".split(" "),function(e){r.formatter.matchNode(t,"align"+e)&&(n.align=e)}),r.windowManager.open({title:"Cell properties",items:{type:"form",data:n,layout:"grid",columns:2,defaults:{type:"textbox",maxWidth:50},items:[{label:"Width",name:"width"},{label:"Height",name:"height
 "},{label:"Cell type",name:"type",type:"listbox",text:"None",minWidth:90,maxWidth:null,menu:[{text:"Cell",value:"td"},{text:"Header cell",value:"th"}]},{label:"Scope",name:"scope",type:"listbox",text:"None",minWidth:90,maxWidth:null,menu:[{text:"None",value:""},{text:"Row",value:"row"},{text:"Column",value:"col"},{text:"Row group",value:"rowgroup"},{text:"Column group",value:"colgroup"}]},{label:"Alignment",name:"align",type:"listbox",text:"None",minWidth:90,maxWidth:null,values:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]},onsubmit:function(){var t=this.toJSON();r.undoManager
 .transact(function(){l(o,function(n){r.dom.setAttrib(n,"scope",t.scope),r.dom.setStyles(n,{width:a(t.width),height:a(t.height)}),t.type&&n.nodeName.toLowerCase()!=t.type&&(n=e.rename(n,t.type)),s(n),t.align&&r.formatter.apply("align"+t.align,{},n)}),r.focus()})}})}function f(){var e=r.dom,t,n,o,c,d=[];t=r.dom.getParent(r.selection.getStart(),"table"),n=r.dom.getParent(r.selection.getStart(),"td,th"),l(t.rows,function(t){l(t.cells,function(r){return e.hasClass(r,"mce-item-selected")||r==n?(d.push(t),!1):void 0})}),o=d[0],c={height:i(e.getStyle(o,"height")||e.getAttrib(o,"height")),scope:e.getAttrib(o,"scope")},c.type=o.parentNode.nodeName.toLowerCase(),l("left center right".split(" "),function(e){r.formatter.matchNode(o,"align"+e)&&(c.align=e)}),r.windowManager.open({title:"Row properties",items:{type:"form",data:c,columns:2
 ,defaults:{type:"textbox"},items:[{type:"listbox",name:"type",label:"Row type",text:"None",maxWidth:null,menu:[{text:"Header",value:"thead"},{text:"Body",value:"tbody"},{text:"Footer",value:"tfoot"}]},{type:"listbox",name:"align",label:"Alignment",text:"None",maxWidth:null,menu:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]},{label:"Height",name:"height"}]},onsubmit:function(){var t=this.toJSON(),n,i,o;r.undoManager.transact(function(){var c=t.type;l(d,function(l){r.dom.setAttrib(l,"scope",t.scope),r.dom.setStyles(l,{height:a(t.height)}),c!=l.parentNode.nodeName.toLowerCase()&&(n=e.getParent(l,"table"),i=l.parentNode,o=e.select(c,n)[0],o||(o=e.cr
 eate(c),n.firstChild?n.insertBefore(o,n.firstChild):n.appendChild(o)),o.appendChild(l),i.hasChildNodes()||e.remove(i)),s(l),t.align&&r.formatter.apply("align"+t.align,{},l)}),r.focus()})}})}function p(e){return function(){r.execCommand(e)}}function m(e,t){var n,i,a;for(a="<table><tbody>",n=0;t>n;n++){for(a+="<tr>",i=0;e>i;i++)a+="<td>"+(o.ie?" ":"<br>")+"</td>";a+="</tr>"}a+="</tbody></table>",r.insertContent(a)}function h(e,t){function n(){e.disabled(!r.dom.getParent(r.selection.getStart(),t)),r.selection.selectorChanged(t,function(t){e.disabled(!t)})}r.initialized?n():r.on("init",n)}function g(){h(this,"table")}function v(){h(this,"td,th")}function y(){var e="";e='<table role="presentation" class="mce-grid mce-grid-border">';for(var t=0;10>t;t++){e+="&l
 t;tr>";for(var n=0;10>n;n++)e+='<td><a href="#" data-mce-index="'+n+","+t+'"></a></td>';e+="</tr>"}return e+="</table>",e+='<div class="mce-text-center">0 x 0</div>'}var b,C,x=this;r.addMenuItem("inserttable",{text:"Insert table",icon:"table",context:"table",onhide:function(){r.dom.removeClass(this.menu.items()[0].getEl().getElementsByTagName("a"),"mce-active")},menu:[{type:"container",html:y(),onmousemove:function(e){var t,n,i=e.target;if("A"==i.nodeName){var o=r.dom.getParent(i,"table"),a=i.getAttribute("data-mce-index"),s=e.control.parent().rel;if(a!=this.lastPos){if(a=a.split(","),a[0]=parseInt(a[0],10),a[1]=parseInt(a[1],10),e.control.isRtl()||"tl-tr"==s){for(n=9;n>=0;n--)for(t=0;10>t;t++)r.dom.toggleClass(o.rows[n].childNodes[t].firstCh
 ild,"mce-active",t>=a[0]&&n<=a[1]);a[0]=9-a[0],o.nextSibling.innerHTML=a[0]+" x "+(a[1]+1)}else{for(n=0;10>n;n++)for(t=0;10>t;t++)r.dom.toggleClass(o.rows[n].childNodes[t].firstChild,"mce-active",t<=a[0]&&n<=a[1]);o.nextSibling.innerHTML=a[0]+1+" x "+(a[1]+1)}this.lastPos=a}}},onclick:function(e){"A"==e.target.nodeName&&this.lastPos&&(e.preventDefault(),m(this.lastPos[0]+1,this.lastPos[1]+1),this.parent().cancel())}}]}),r.addMenuItem("tableprops",{text:"Table properties",context:"table",onPostRender:g,onclick:c}),r.addMenuItem("deletetable",{text:"Delete table",context:"table",onPostRender:g,cmd:"mceTableDelete"}),r.addMenuItem("cell",{separator:"before",text:"Cell",context:"table",menu:[{text:"Cell properties",onclick:p("mceTableCellProps"),onPostRender:v}
 ,{text:"Merge cells",onclick:p("mceTableMergeCells"),onPostRender:v},{text:"Split cell",onclick:p("mceTableSplitCells"),onPostRender:v}]}),r.addMenuItem("row",{text:"Row",context:"table",menu:[{text:"Insert row before",onclick:p("mceTableInsertRowBefore"),onPostRender:v},{text:"Insert row after",onclick:p("mceTableInsertRowAfter"),onPostRender:v},{text:"Delete row",onclick:p("mceTableDeleteRow"),onPostRender:v},{text:"Row properties",onclick:p("mceTableRowProps"),onPostRender:v},{text:"-"},{text:"Cut row",onclick:p("mceTableCutRow"),onPostRender:v},{text:"Copy row",onclick:p("mceTableCopyRow"),onPostRender:v},{text:"Paste row before",onclick:p("mceTablePasteRowBefore"),onPostRender:v},{text:"Paste row after",onclick:p("mceTablePasteRowAfter"),onPo
 stRender:v}]}),r.addMenuItem("column",{text:"Column",context:"table",menu:[{text:"Insert column before",onclick:p("mceTableInsertColBefore"),onPostRender:v},{text:"Insert column after",onclick:p("mceTableInsertColAfter"),onPostRender:v},{text:"Delete column",onclick:p("mceTableDeleteCol"),onPostRender:v}]});var w=[];l("inserttable tableprops deletetable | cell row column".split(" "),function(e){"|"==e?w.push({text:"-"}):w.push(r.menuItems[e])}),r.addButton("table",{type:"menubutton",title:"Table",menu:w}),o.isIE||r.on("click",function(e){e=e.target,"TABLE"===e.nodeName&&(r.selection.select(e),r.nodeChanged())}),x.quirks=new t(r),r.on("Init",function(){b=r.windowManager,x.cellSelection=new n(r)}),l({mceTableSplitCells:function(e){e.split()},mceTableMergeCells:function(e){var t,n,i;i=r.dom.
 getParent(r.selection.getStart(),"th,td"),i&&(t=i.rowSpan,n=i.colSpan),r.dom.select("td.mce-item-selected,th.mce-item-selected").length?e.merge():d(e,i)},mceTableInsertRowBefore:function(e){e.insertRow(!0)},mceTableInsertRowAfter:function(e){e.insertRow()},mceTableInsertColBefore:function(e){e.insertCol(!0)},mceTableInsertColAfter:function(e){e.insertCol()},mceTableDeleteCol:function(e){e.deleteCols()},mceTableDeleteRow:function(e){e.deleteRows()},mceTableCutRow:function(e){C=e.cutRows()},mceTableCopyRow:function(e){C=e.copyRows()},mceTablePasteRowBefore:function(e){e.pasteRows(C,!0)},mceTablePasteRowAfter:function(e){e.pasteRows(C)},mceTableDelete:function(e){e.deleteTable()}},function(t,n){r.addCommand(n,function(){var n=new e(r);n&&(t(n),r.execCommand("mceRepaint"),x.cellSelection.clear())})}),l({mceInsertTable:function(){c()},mceTableRowProps:f,mceTableCellProps:u},function(e,t){r.addCommand(t,function(t,n){e(n)})})}var l=r.each;a.ad
 d("table",s)}),a([l,u,p,h])}(this);
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/external-plugins/table/plugin.min.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorindexhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/index.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/index.html                              (rev 0)
+++ trunk/tests/qunit/editor/index.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8" />
+<title>Test Runner</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="js/qunit/testrunner.css" type="text/css" />
+<script src="js/qunit/testrunner.js"></script>
+<script>
+TestRunner.addSuites([
+       "tinymce/tests.js",
+       "tinymce/dom/tests.js",
+       "tinymce/html/tests.js",
+       "tinymce/ui/tests.js",
+       "tinymce/util/tests.js",
+       "plugins/tests.js"
+]);
+</script>
+</head>
+<body>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/index.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorjsqunitQUnitLICENSE"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/qunit/QUnit.LICENSE (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/qunit/QUnit.LICENSE                          (rev 0)
+++ trunk/tests/qunit/editor/js/qunit/QUnit.LICENSE     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+Copyright (c) 2010 John Resig, http://jquery.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunktestsquniteditorjsqunitqunitcss"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/qunit/qunit.css (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/qunit/qunit.css                              (rev 0)
+++ trunk/tests/qunit/editor/js/qunit/qunit.css 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,119 @@
</span><ins>+
+ol#qunit-tests {
+       font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+       margin:0;
+       padding:0;
+       list-style-position:inside;
+
+       font-size: smaller;
+}
+ol#qunit-tests li{
+       padding:0.4em 0.5em 0.4em 2.5em;
+       border-bottom:1px solid #fff;
+       font-size:small;
+       list-style-position:inside;
+}
+ol#qunit-tests li ol{
+       box-shadow: inset 0px 2px 13px #999;
+       -moz-box-shadow: inset 0px 2px 13px #999;
+       -webkit-box-shadow: inset 0px 2px 13px #999;
+       margin-top:0.5em;
+       margin-left:0;
+       padding:0.5em;
+       background-color:#fff;
+       border-radius:15px;
+       -moz-border-radius: 15px;
+       -webkit-border-radius: 15px;
+}
+ol#qunit-tests li li{
+       border-bottom:none;
+       margin:0.5em;
+       background-color:#fff;
+       list-style-position: inside;
+       padding:0.4em 0.5em 0.4em 0.5em;
+}
+
+ol#qunit-tests li li.pass{
+       border-left:26px solid #C6E746;
+       background-color:#fff;
+       color:#5E740B;
+       }
+ol#qunit-tests li li.fail{
+       border-left:26px solid #EE5757;
+       background-color:#fff;
+       color:#710909;
+}
+ol#qunit-tests li.pass{
+       background-color:#D2E0E6;
+       color:#528CE0;
+}
+ol#qunit-tests li.fail{
+       background-color:#EE5757;
+       color:#000;
+}
+ol#qunit-tests li strong {
+       cursor:pointer;
+}
+h1#qunit-header{
+       background-color:#0d3349;
+       margin:0;
+       padding:0.5em 0 0.5em 1em;
+       color:#fff;
+       font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+       border-top-right-radius:15px;
+       border-top-left-radius:15px;
+       -moz-border-radius-topright:15px;
+       -moz-border-radius-topleft:15px;
+       -webkit-border-top-right-radius:15px;
+       -webkit-border-top-left-radius:15px;
+       text-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px;
+}
+h2#qunit-banner{
+       font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+       height:5px;
+       margin:0;
+       padding:0;
+}
+h2#qunit-banner.qunit-pass{
+       background-color:#C6E746;
+}
+h2#qunit-banner.qunit-fail, #qunit-testrunner-toolbar {
+       background-color:#EE5757;
+}
+#qunit-testrunner-toolbar {
+       font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+       padding:0;
+       /*width:80%;*/
+       padding:0em 0 0.5em 2em;
+       font-size: small;
+}
+h2#qunit-userAgent {
+       font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+       background-color:#2b81af;
+       margin:0;
+       padding:0;
+       color:#fff;
+       font-size: small;
+       padding:0.5em 0 0.5em 2.5em;
+       text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+p#qunit-testresult{
+       font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+       margin:0;
+       font-size: small;
+       color:#2b81af;
+       border-bottom-right-radius:15px;
+       border-bottom-left-radius:15px;
+       -moz-border-radius-bottomright:15px;
+       -moz-border-radius-bottomleft:15px;
+       -webkit-border-bottom-right-radius:15px;
+       -webkit-border-bottom-left-radius:15px;
+       background-color:#D2E0E6;
+       padding:0.5em 0.5em 0.5em 2.5em;
+}
+strong b.fail{
+       color:#710909;
+       }
+strong b.pass{
+       color:#5E740B;
+       }
</ins></span></pre></div>
<a id="trunktestsquniteditorjsqunitqunitjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/qunit/qunit.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/qunit/qunit.js                               (rev 0)
+++ trunk/tests/qunit/editor/js/qunit/qunit.js  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,1265 @@
</span><ins>+/*
+ * QUnit - A JavaScript Unit Testing Framework
+ * 
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2009 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ */
+
+(function(window) {
+
+var QUnit = {
+
+       // call on start of module test to prepend name to all tests
+       module: function(name, testEnvironment) {
+               config.currentModule = name;
+
+               synchronize(function() {
+                       if ( config.currentModule ) {
+                               QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
+                       }
+
+                       config.currentModule = name;
+                       config.moduleTestEnvironment = testEnvironment;
+                       config.moduleStats = { all: 0, bad: 0 };
+
+                       QUnit.moduleStart( name, testEnvironment );
+               });
+       },
+
+       asyncTest: function(testName, expected, callback) {
+               if ( arguments.length === 2 ) {
+                       callback = expected;
+                       expected = 0;
+               }
+
+               QUnit.test(testName, expected, callback, true);
+       },
+       
+       test: function(testName, expected, callback, async) {
+               var name = '<span class="test-name">' + testName + '</span>', testEnvironment, testEnvironmentArg;
+
+               if ( arguments.length === 2 ) {
+                       callback = expected;
+                       expected = null;
+               }
+               // is 2nd argument a testEnvironment?
+               if ( expected && typeof expected === 'object') {
+                       testEnvironmentArg =  expected;
+                       expected = null;
+               }
+
+               if ( config.currentModule ) {
+                       name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
+               }
+
+               if ( !validTest(config.currentModule + ": " + testName) ) {
+                       return;
+               }
+
+               synchronize(function() {
+
+                       testEnvironment = extend({
+                               setup: function() {},
+                               teardown: function() {}
+                       }, config.moduleTestEnvironment);
+                       if (testEnvironmentArg) {
+                               extend(testEnvironment,testEnvironmentArg);
+                       }
+
+                       QUnit.testStart( testName, testEnvironment );
+
+                       // allow utility functions to access the current test environment
+                       QUnit.current_testEnvironment = testEnvironment;
+                       
+                       config.assertions = [];
+                       config.expected = expected;
+                       
+                       var tests = id("qunit-tests");
+                       if (tests) {
+                               var b = document.createElement("strong");
+                                       b.innerHTML = "Running " + name;
+                               var li = document.createElement("li");
+                                       li.appendChild( b );
+                                       li.id = "current-test-output";
+                               tests.appendChild( li )
+                       }
+
+                       try {
+                               if ( !config.pollution ) {
+                                       saveGlobal();
+                               }
+
+                               testEnvironment.setup.call(testEnvironment);
+                       } catch(e) {
+                               QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
+                       }
+           });
+       
+           synchronize(function() {
+                       if ( async ) {
+                               QUnit.stop();
+                       }
+
+                       try {
+                               callback.call(testEnvironment);
+                       } catch(e) {
+                               fail("Test " + name + " died, exception and test follows", e, callback);
+                               QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
+                               // else next test will carry the responsibility
+                               saveGlobal();
+
+                               // Restart the tests if they're blocking
+                               if ( config.blocking ) {
+                                       start();
+                               }
+                       }
+               });
+
+               synchronize(function() {
+                       try {
+                               checkPollution();
+                               testEnvironment.teardown.call(testEnvironment);
+                       } catch(e) {
+                               QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
+                       }
+           });
+       
+           synchronize(function() {
+                       try {
+                               QUnit.reset();
+                       } catch(e) {
+                               fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
+                       }
+
+                       if ( config.expected && config.expected != config.assertions.length ) {
+                               QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
+                       }
+
+                       var good = 0, bad = 0,
+                               tests = id("qunit-tests");
+
+                       config.stats.all += config.assertions.length;
+                       config.moduleStats.all += config.assertions.length;
+
+                       if ( tests ) {
+                               var ol  = document.createElement("ol");
+
+                               for ( var i = 0; i < config.assertions.length; i++ ) {
+                                       var assertion = config.assertions[i];
+
+                                       var li = document.createElement("li");
+                                       li.className = assertion.result ? "pass" : "fail";
+                                       li.innerHTML = assertion.message || "(no message)";
+                                       ol.appendChild( li );
+
+                                       if ( assertion.result ) {
+                                               good++;
+                                       } else {
+                                               bad++;
+                                               config.stats.bad++;
+                                               config.moduleStats.bad++;
+                                       }
+                               }
+                               if (bad == 0) {
+                                       ol.style.display = "none";
+                               }
+
+                               var b = document.createElement("strong");
+                               b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
+                               
+                               addEvent(b, "click", function() {
+                                       var next = b.nextSibling, display = next.style.display;
+                                       next.style.display = display === "none" ? "block" : "none";
+                               });
+                               
+                               addEvent(b, "dblclick", function(e) {
+                                       var target = e && e.target ? e.target : window.event.srcElement;
+                                       if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
+                                               target = target.parentNode;
+                                       }
+                                       if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
+                                               window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, ""));
+                                       }
+                               });
+
+                               var li = id("current-test-output");
+                               li.id = "";
+                               li.className = bad ? "fail" : "pass";
+                               li.removeChild( li.firstChild );
+                               li.appendChild( b );
+                               li.appendChild( ol );
+
+                               if ( bad ) {
+                                       var toolbar = id("qunit-testrunner-toolbar");
+                                       if ( toolbar ) {
+                                               toolbar.style.display = "block";
+                                               id("qunit-filter-pass").disabled = null;
+                                               id("qunit-filter-missing").disabled = null;
+                                       }
+                               }
+
+                       } else {
+                               for ( var i = 0; i < config.assertions.length; i++ ) {
+                                       if ( !config.assertions[i].result ) {
+                                               bad++;
+                                               config.stats.bad++;
+                                               config.moduleStats.bad++;
+                                       }
+                               }
+                       }
+
+                       QUnit.testDone( testName, bad, config.assertions.length );
+
+                       if ( !window.setTimeout && !config.queue.length ) {
+                               done();
+                       }
+               });
+
+               if ( window.setTimeout && !config.doneTimer ) {
+                       config.doneTimer = window.setTimeout(function(){
+                               if ( !config.queue.length ) {
+                                       done();
+                               } else {
+                                       synchronize( done );
+                               }
+                       }, 13);
+               }
+       },
+       
+       /**
+        * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
+        */
+       expect: function(asserts) {
+               config.expected = asserts;
+       },
+
+       /**
+        * Asserts true.
+        * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
+        */
+       ok: function(a, msg) {
+               msg = escapeHtml(msg);
+               QUnit.log(a, msg);
+
+               config.assertions.push({
+                       result: !!a,
+                       message: msg
+               });
+       },
+
+       /**
+        * Checks that the first two arguments are equal, with an optional message.
+        * Prints out both actual and expected values.
+        *
+        * Prefered to ok( actual == expected, message )
+        *
+        * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
+        *
+        * @param Object actual
+        * @param Object expected
+        * @param String message (optional)
+        */
+       equal: function(actual, expected, message) {
+               push(expected == actual, actual, expected, message);
+       },
+
+       notEqual: function(actual, expected, message) {
+               push(expected != actual, actual, expected, message);
+       },
+       
+       deepEqual: function(actual, expected, message) {
+               push(QUnit.equiv(actual, expected), actual, expected, message);
+       },
+
+       notDeepEqual: function(actual, expected, message) {
+               push(!QUnit.equiv(actual, expected), actual, expected, message);
+       },
+
+       strictEqual: function(actual, expected, message) {
+               push(expected === actual, actual, expected, message);
+       },
+
+       notStrictEqual: function(actual, expected, message) {
+               push(expected !== actual, actual, expected, message);
+       },
+
+       raises: function(fn,  message) {
+               try {
+                       fn();
+                       ok( false, message );
+               }
+               catch (e) {
+                       ok( true, message );
+               }
+       },
+
+       start: function() {
+               // A slight delay, to avoid any current callbacks
+               if ( window.setTimeout ) {
+                       window.setTimeout(function() {
+                               if ( config.timeout ) {
+                                       clearTimeout(config.timeout);
+                               }
+
+                               config.blocking = false;
+                               process();
+                       }, 13);
+               } else {
+                       config.blocking = false;
+                       process();
+               }
+       },
+       
+       stop: function(timeout) {
+               config.blocking = true;
+
+               if ( timeout && window.setTimeout ) {
+                       config.timeout = window.setTimeout(function() {
+                               QUnit.ok( false, "Test timed out" );
+                               QUnit.start();
+                       }, timeout);
+               }
+       }
+
+};
+
+// Backwards compatibility, deprecated
+QUnit.equals = QUnit.equal;
+QUnit.same = QUnit.deepEqual;
+
+// Maintain internal state
+var config = {
+       // The queue of tests to run
+       queue: [],
+
+       // block until document ready
+       blocking: true
+};
+
+// Load parameters
+(function() {
+       var location = window.location || { search: "", protocol: "file:" },
+               GETParams = location.search.slice(1).split('&');
+
+       for ( var i = 0; i < GETParams.length; i++ ) {
+               GETParams[i] = decodeURIComponent( GETParams[i] );
+               if ( GETParams[i] === "noglobals" ) {
+                       GETParams.splice( i, 1 );
+                       i--;
+                       config.noglobals = true;
+               } else if ( GETParams[i].search('=') > -1 ) {
+                       GETParams.splice( i, 1 );
+                       i--;
+               }
+       }
+       
+       // restrict modules/tests by get parameters
+       config.filters = GETParams;
+       
+       // Figure out if we're running the tests from a server or not
+       QUnit.isLocal = !!(location.protocol === 'file:');
+})();
+
+// Expose the API as global variables, unless an 'exports'
+// object exists, in that case we assume we're in CommonJS
+if ( typeof exports === "undefined" || typeof require === "undefined" ) {
+       extend(window, QUnit);
+       window.QUnit = QUnit;
+} else {
+       extend(exports, QUnit);
+       exports.QUnit = QUnit;
+}
+
+// define these after exposing globals to keep them in these QUnit namespace only
+extend(QUnit, {
+       config: config,
+
+       // Initialize the configuration options
+       init: function() {
+               extend(config, {
+                       stats: { all: 0, bad: 0 },
+                       moduleStats: { all: 0, bad: 0 },
+                       started: +new Date,
+                       updateRate: 1000,
+                       blocking: false,
+                       autostart: true,
+                       autorun: false,
+                       assertions: [],
+                       filters: [],
+                       queue: []
+               });
+
+               var tests = id("qunit-tests"),
+                       banner = id("qunit-banner"),
+                       result = id("qunit-testresult");
+
+               if ( tests ) {
+                       tests.innerHTML = "";
+               }
+
+               if ( banner ) {
+                       banner.className = "";
+               }
+
+               if ( result ) {
+                       result.parentNode.removeChild( result );
+               }
+       },
+       
+       /**
+        * Resets the test setup. Useful for tests that modify the DOM.
+        */
+       reset: function() {
+               if ( window.jQuery ) {
+                       jQuery("#main, #qunit-fixture").html( config.fixture );
+               }
+       },
+       
+       /**
+        * Trigger an event on an element.
+        *
+        * @example triggerEvent( document.body, "click" );
+        *
+        * @param DOMElement elem
+        * @param String type
+        */
+       triggerEvent: function( elem, type, event ) {
+               if ( document.createEvent ) {
+                       event = document.createEvent("MouseEvents");
+                       event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
+                               0, 0, 0, 0, 0, false, false, false, false, 0, null);
+                       elem.dispatchEvent( event );
+
+               } else if ( elem.fireEvent ) {
+                       elem.fireEvent("on"+type);
+               }
+       },
+       
+       // Safe object type checking
+       is: function( type, obj ) {
+               return QUnit.objectType( obj ) == type;
+       },
+       
+       objectType: function( obj ) {
+               if (typeof obj === "undefined") {
+                               return "undefined";
+
+               // consider: typeof null === object
+               }
+               if (obj === null) {
+                               return "null";
+               }
+
+               var type = Object.prototype.toString.call( obj )
+                       .match(/^\[object\s(.*)\]$/)[1] || '';
+
+               switch (type) {
+                               case 'Number':
+                                               if (isNaN(obj)) {
+                                                               return "nan";
+                                               } else {
+                                                               return "number";
+                                               }
+                               case 'String':
+                               case 'Boolean':
+                               case 'Array':
+                               case 'Date':
+                               case 'RegExp':
+                               case 'Function':
+                                               return type.toLowerCase();
+               }
+               if (typeof obj === "object") {
+                               return "object";
+               }
+               return undefined;
+       },
+       
+       // Logging callbacks
+       begin: function() {},
+       done: function(failures, total) {},
+       log: function(result, message) {},
+       testStart: function(name, testEnvironment) {},
+       testDone: function(name, failures, total) {},
+       moduleStart: function(name, testEnvironment) {},
+       moduleDone: function(name, failures, total) {}
+});
+
+if ( typeof document === "undefined" || document.readyState === "complete" ) {
+       config.autorun = true;
+}
+
+addEvent(window, "load", function() {
+       QUnit.begin();
+       
+       // Initialize the config, saving the execution queue
+       var oldconfig = extend({}, config);
+       QUnit.init();
+       extend(config, oldconfig);
+
+       config.blocking = false;
+
+       var userAgent = id("qunit-userAgent");
+       if ( userAgent ) {
+               userAgent.innerHTML = navigator.userAgent;
+       }
+       
+       var toolbar = id("qunit-testrunner-toolbar");
+       if ( toolbar ) {
+               toolbar.style.display = "none";
+               
+               var filter = document.createElement("input");
+               filter.type = "checkbox";
+               filter.id = "qunit-filter-pass";
+               filter.disabled = true;
+               addEvent( filter, "click", function() {
+                       var li = document.getElementsByTagName("li");
+                       for ( var i = 0; i < li.length; i++ ) {
+                               if ( li[i].className.indexOf("pass") > -1 ) {
+                                       li[i].style.display = filter.checked ? "none" : "";
+                               }
+                       }
+               });
+               toolbar.appendChild( filter );
+
+               var label = document.createElement("label");
+               label.setAttribute("for", "qunit-filter-pass");
+               label.innerHTML = "Hide passed tests";
+               toolbar.appendChild( label );
+
+               var missing = document.createElement("input");
+               missing.type = "checkbox";
+               missing.id = "qunit-filter-missing";
+               missing.disabled = true;
+               addEvent( missing, "click", function() {
+                       var li = document.getElementsByTagName("li");
+                       for ( var i = 0; i < li.length; i++ ) {
+                               if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
+                                       li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
+                               }
+                       }
+               });
+               toolbar.appendChild( missing );
+
+               label = document.createElement("label");
+               label.setAttribute("for", "qunit-filter-missing");
+               label.innerHTML = "Hide missing tests (untested code is broken code)";
+               toolbar.appendChild( label );
+       }
+
+       var main = id('main') || id('qunit-fixture');
+       if ( main ) {
+               config.fixture = main.innerHTML;
+       }
+
+       if (config.autostart) {
+               QUnit.start();
+       }
+});
+
+function done() {
+       if ( config.doneTimer && window.clearTimeout ) {
+               window.clearTimeout( config.doneTimer );
+               config.doneTimer = null;
+       }
+
+       if ( config.queue.length ) {
+               config.doneTimer = window.setTimeout(function(){
+                       if ( !config.queue.length ) {
+                               done();
+                       } else {
+                               synchronize( done );
+                       }
+               }, 13);
+
+               return;
+       }
+
+       config.autorun = true;
+
+       // Log the last module results
+       if ( config.currentModule ) {
+               QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
+       }
+
+       var banner = id("qunit-banner"),
+               tests = id("qunit-tests"),
+               html = ['Tests completed in ',
+               +new Date - config.started, ' milliseconds.<br/>',
+               '<span class="passed">', config.stats.all - config.stats.bad, '</span> tests of <span class="total">', config.stats.all, '</span> passed, <span class="failed">', config.stats.bad,'</span> failed.'].join('');
+
+       if ( banner ) {
+               banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
+       }
+
+       if ( tests ) {  
+               var result = id("qunit-testresult");
+
+               if ( !result ) {
+                       result = document.createElement("p");
+                       result.id = "qunit-testresult";
+                       result.className = "result";
+                       tests.parentNode.insertBefore( result, tests.nextSibling );
+               }
+
+               result.innerHTML = html;
+       }
+
+       QUnit.done( config.stats.bad, config.stats.all );
+}
+
+function validTest( name ) {
+       var i = config.filters.length,
+               run = false;
+
+       if ( !i ) {
+               return true;
+       }
+       
+       while ( i-- ) {
+               var filter = config.filters[i],
+                       not = filter.charAt(0) == '!';
+
+               if ( not ) {
+                       filter = filter.slice(1);
+               }
+
+               if ( name.indexOf(filter) !== -1 ) {
+                       return !not;
+               }
+
+               if ( not ) {
+                       run = true;
+               }
+       }
+
+       return run;
+}
+
+function escapeHtml(s) {
+       s = s === null ? "" : s + "";
+       return s.replace(/[\&"<>\\]/g, function(s) {
+               switch(s) {
+                       case "&": return "&amp;";
+                       case "\\": return "\\\\";
+                       case '"': return '\"';
+                       case "<": return "&lt;";
+                       case ">": return "&gt;";
+                       default: return s;
+               }
+       });
+}
+
+function push(result, actual, expected, message) {
+       message = escapeHtml(message) || (result ? "okay" : "failed");
+       message = '<span class="test-message">' + message + "</span>";
+       expected = escapeHtml(QUnit.jsDump.parse(expected));
+       actual = escapeHtml(QUnit.jsDump.parse(actual));
+       var output = message + ', expected: <span class="test-expected">' + expected + '</span>';
+       if (actual != expected) {
+               output += ' result: <span class="test-actual">' + actual + '</span>, diff: ' + QUnit.diff(expected, actual);
+       }
+       
+       // can't use ok, as that would double-escape messages
+       QUnit.log(result, output);
+       config.assertions.push({
+               result: !!result,
+               message: output
+       });
+}
+
+function synchronize( callback ) {
+       config.queue.push( callback );
+
+       if ( config.autorun && !config.blocking ) {
+               process();
+       }
+}
+
+function process() {
+       var start = (new Date()).getTime();
+
+       while ( config.queue.length && !config.blocking ) {
+               if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
+                       config.queue.shift()();
+
+               } else {
+                       setTimeout( process, 13 );
+                       break;
+               }
+       }
+}
+
+function saveGlobal() {
+       config.pollution = [];
+       
+       if ( config.noglobals ) {
+               for ( var key in window ) {
+                       config.pollution.push( key );
+               }
+       }
+}
+
+function checkPollution( name ) {
+       var old = config.pollution;
+       saveGlobal();
+       
+       var newGlobals = diff( old, config.pollution );
+       if ( newGlobals.length > 0 ) {
+               ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
+               config.expected++;
+       }
+
+       var deletedGlobals = diff( config.pollution, old );
+       if ( deletedGlobals.length > 0 ) {
+               ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
+               config.expected++;
+       }
+}
+
+// returns a new Array with the elements that are in a but not in b
+function diff( a, b ) {
+       var result = a.slice();
+       for ( var i = 0; i < result.length; i++ ) {
+               for ( var j = 0; j < b.length; j++ ) {
+                       if ( result[i] === b[j] ) {
+                               result.splice(i, 1);
+                               i--;
+                               break;
+                       }
+               }
+       }
+       return result;
+}
+
+function fail(message, exception, callback) {
+       if ( typeof console !== "undefined" && console.error && console.warn ) {
+               console.error(message);
+               console.error(exception);
+               console.warn(callback.toString());
+
+       } else if ( window.opera && opera.postError ) {
+               opera.postError(message, exception, callback.toString);
+       }
+}
+
+function extend(a, b) {
+       for ( var prop in b ) {
+               a[prop] = b[prop];
+       }
+
+       return a;
+}
+
+function addEvent(elem, type, fn) {
+       if ( elem.addEventListener ) {
+               elem.addEventListener( type, fn, false );
+       } else if ( elem.attachEvent ) {
+               elem.attachEvent( "on" + type, fn );
+       } else {
+               fn();
+       }
+}
+
+function id(name) {
+       return !!(typeof document !== "undefined" && document && document.getElementById) &&
+               document.getElementById( name );
+}
+
+// Test for equality any JavaScript type.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+QUnit.equiv = function () {
+
+    var innerEquiv; // the real equiv function
+    var callers = []; // stack to decide between skip/abort functions
+    var parents = []; // stack to avoiding loops from circular referencing
+
+    // Call the o related callback with the given arguments.
+    function bindCallbacks(o, callbacks, args) {
+        var prop = QUnit.objectType(o);
+        if (prop) {
+            if (QUnit.objectType(callbacks[prop]) === "function") {
+                return callbacks[prop].apply(callbacks, args);
+            } else {
+                return callbacks[prop]; // or undefined
+            }
+        }
+    }
+    
+    var callbacks = function () {
+
+        // for string, boolean, number and null
+        function useStrictEquality(b, a) {
+            if (b instanceof a.constructor || a instanceof b.constructor) {
+                // to catch short annotaion VS 'new' annotation of a declaration
+                // e.g. var i = 1;
+                //      var j = new Number(1);
+                return a == b;
+            } else {
+                return a === b;
+            }
+        }
+
+        return {
+            "string": useStrictEquality,
+            "boolean": useStrictEquality,
+            "number": useStrictEquality,
+            "null": useStrictEquality,
+            "undefined": useStrictEquality,
+
+            "nan": function (b) {
+                return isNaN(b);
+            },
+
+            "date": function (b, a) {
+                return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
+            },
+
+            "regexp": function (b, a) {
+                return QUnit.objectType(b) === "regexp" &&
+                    a.source === b.source && // the regex itself
+                    a.global === b.global && // and its modifers (gmi) ...
+                    a.ignoreCase === b.ignoreCase &&
+                    a.multiline === b.multiline;
+            },
+
+            // - skip when the property is a method of an instance (OOP)
+            // - abort otherwise,
+            //   initial === would have catch identical references anyway
+            "function": function () {
+                var caller = callers[callers.length - 1];
+                return caller !== Object &&
+                        typeof caller !== "undefined";
+            },
+
+            "array": function (b, a) {
+                var i, j, loop;
+                var len;
+
+                // b could be an object literal here
+                if ( ! (QUnit.objectType(b) === "array")) {
+                    return false;
+                }   
+                
+                len = a.length;
+                if (len !== b.length) { // safe and faster
+                    return false;
+                }
+                
+                //track reference to avoid circular references
+                parents.push(a);
+                for (i = 0; i < len; i++) {
+                    loop = false;
+                    for(j=0;j<parents.length;j++){
+                        if(parents[j] === a[i]){
+                            loop = true;//dont rewalk array
+                        }
+                    }
+                    if (!loop && ! innerEquiv(a[i], b[i])) {
+                        parents.pop();
+                        return false;
+                    }
+                }
+                parents.pop();
+                return true;
+            },
+
+            "object": function (b, a) {
+                var i, j, loop;
+                var eq = true; // unless we can proove it
+                var aProperties = [], bProperties = []; // collection of strings
+
+                // comparing constructors is more strict than using instanceof
+                if ( a.constructor !== b.constructor) {
+                    return false;
+                }
+
+                // stack constructor before traversing properties
+                callers.push(a.constructor);
+                //track reference to avoid circular references
+                parents.push(a);
+                
+                for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
+                    loop = false;
+                    for(j=0;j<parents.length;j++){
+                        if(parents[j] === a[i])
+                            loop = true; //don't go down the same path twice
+                    }
+                    aProperties.push(i); // collect a's properties
+
+                    if (!loop && ! innerEquiv(a[i], b[i])) {
+                        eq = false;
+                        break;
+                    }
+                }
+
+                callers.pop(); // unstack, we are done
+                parents.pop();
+
+                for (i in b) {
+                    bProperties.push(i); // collect b's properties
+                }
+
+                // Ensures identical properties name
+                return eq && innerEquiv(aProperties.sort(), bProperties.sort());
+            }
+        };
+    }();
+
+    innerEquiv = function () { // can take multiple arguments
+        var args = Array.prototype.slice.apply(arguments);
+        if (args.length < 2) {
+            return true; // end transition
+        }
+
+        return (function (a, b) {
+            if (a === b) {
+                return true; // catch the most you can
+            } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
+                return false; // don't lose time with error prone cases
+            } else {
+                return bindCallbacks(a, callbacks, [b, a]);
+            }
+
+        // apply transition with (1..n) arguments
+        })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
+    };
+
+    return innerEquiv;
+
+}();
+
+/**
+ * jsDump
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
+ * Date: 5/15/2008
+ * @projectDescription Advanced and extensible data dumping for Javascript.
+ * @version 1.0.0
+ * @author Ariel Flesler
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
+ */
+QUnit.jsDump = (function() {
+       function quote( str ) {
+               return '"' + str.toString().replace(/"/g, '\\"') + '"';
+       };
+       function literal( o ) {
+               return o + '';  
+       };
+       function join( pre, arr, post ) {
+               var s = jsDump.separator(),
+                       base = jsDump.indent(),
+                       inner = jsDump.indent(1);
+               if ( arr.join )
+                       arr = arr.join( ',' + s + inner );
+               if ( !arr )
+                       return pre + post;
+               return [ pre, inner + arr, base + post ].join(s);
+       };
+       function array( arr ) {
+               var i = arr.length,     ret = Array(i);                                 
+               this.up();
+               while ( i-- )
+                       ret[i] = this.parse( arr[i] );                          
+               this.down();
+               return join( '[', ret, ']' );
+       };
+       
+       var reName = /^function (\w+)/;
+       
+       var jsDump = {
+               parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
+                       var     parser = this.parsers[ type || this.typeOf(obj) ];
+                       type = typeof parser;                   
+                       
+                       return type == 'function' ? parser.call( this, obj ) :
+                                  type == 'string' ? parser :
+                                  this.parsers.error;
+               },
+               typeOf:function( obj ) {
+                       var type;
+                       if ( obj === null ) {
+                               type = "null";
+                       } else if (typeof obj === "undefined") {
+                               type = "undefined";
+                       } else if (QUnit.is("RegExp", obj)) {
+                               type = "regexp";
+                       } else if (QUnit.is("Date", obj)) {
+                               type = "date";
+                       } else if (QUnit.is("Function", obj)) {
+                               type = "function";
+                       } else if (obj.setInterval && obj.document && !obj.nodeType) {
+                               type = "window";
+                       } else if (obj.nodeType === 9) {
+                               type = "document";
+                       } else if (obj.nodeType) {
+                               type = "node";
+                       } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
+                               type = "array";
+                       } else {
+                               type = typeof obj;
+                       }
+                       return type;
+               },
+               separator:function() {
+                       return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
+               },
+               indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
+                       if ( !this.multiline )
+                               return '';
+                       var chr = this.indentChar;
+                       if ( this.HTML )
+                               chr = chr.replace(/\t/g,'   ').replace(/ /g,'&nbsp;');
+                       return Array( this._depth_ + (extra||0) ).join(chr);
+               },
+               up:function( a ) {
+                       this._depth_ += a || 1;
+               },
+               down:function( a ) {
+                       this._depth_ -= a || 1;
+               },
+               setParser:function( name, parser ) {
+                       this.parsers[name] = parser;
+               },
+               // The next 3 are exposed so you can use them
+               quote:quote, 
+               literal:literal,
+               join:join,
+               //
+               _depth_: 1,
+               // This is the list of parsers, to modify them, use jsDump.setParser
+               parsers:{
+                       window: '[Window]',
+                       document: '[Document]',
+                       error:'[ERROR]', //when no parser is found, shouldn't happen
+                       unknown: '[Unknown]',
+                       'null':'null',
+                       undefined:'undefined',
+                       'function':function( fn ) {
+                               var ret = 'function',
+                                       name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
+                               if ( name )
+                                       ret += ' ' + name;
+                               ret += '(';
+                               
+                               ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
+                               return join( ret, this.parse(fn,'functionCode'), '}' );
+                       },
+                       array: array,
+                       nodelist: array,
+                       arguments: array,
+                       object:function( map ) {
+                               var ret = [ ];
+                               this.up();
+                               for ( var key in map )
+                                       ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
+                               this.down();
+                               return join( '{', ret, '}' );
+                       },
+                       node:function( node ) {
+                               var open = this.HTML ? '&lt;' : '<',
+                                       close = this.HTML ? '&gt;' : '>';
+                                       
+                               var tag = node.nodeName.toLowerCase(),
+                                       ret = open + tag;
+                                       
+                               for ( var a in this.DOMAttrs ) {
+                                       var val = node[this.DOMAttrs[a]];
+                                       if ( val )
+                                               ret += ' ' + a + '=' + this.parse( val, 'attribute' );
+                               }
+                               return ret + close + open + '/' + tag + close;
+                       },
+                       functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
+                               var l = fn.length;
+                               if ( !l ) return '';                            
+                               
+                               var args = Array(l);
+                               while ( l-- )
+                                       args[l] = String.fromCharCode(97+l);//97 is 'a'
+                               return ' ' + args.join(', ') + ' ';
+                       },
+                       key:quote, //object calls it internally, the key part of an item in a map
+                       functionCode:'[code]', //function calls it internally, it's the content of the function
+                       attribute:quote, //node calls it internally, it's an html attribute value
+                       string:quote,
+                       date:quote,
+                       regexp:literal, //regex
+                       number:literal,
+                       'boolean':literal
+               },
+               DOMAttrs:{//attributes to dump from nodes, name=>realName
+                       id:'id',
+                       name:'name',
+                       'class':'className'
+               },
+               HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
+               indentChar:'   ',//indentation unit
+               multiline:false //if true, items in a collection, are separated by a \n, else just a space.
+       };
+
+       return jsDump;
+})();
+
+// from Sizzle.js
+function getText( elems ) {
+       var ret = "", elem;
+
+       for ( var i = 0; elems[i]; i++ ) {
+               elem = elems[i];
+
+               // Get the text from text nodes and CDATA nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+                       ret += elem.nodeValue;
+
+               // Traverse everything else, except comment nodes
+               } else if ( elem.nodeType !== 8 ) {
+                       ret += getText( elem.childNodes );
+               }
+       }
+
+       return ret;
+};
+
+/*
+ * Javascript Diff Algorithm
+ *  By John Resig (http://ejohn.org/)
+ *  Modified by Chu Alan "sprite"
+ *
+ * Released under the MIT license.
+ *
+ * More Info:
+ *  http://ejohn.org/projects/javascript-diff-algorithm/
+ *  
+ * Usage: QUnit.diff(expected, actual)
+ * 
+ * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the  quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
+ */
+QUnit.diff = (function() {
+       function diff(o, n){
+               var ns = new Object();
+               var os = new Object();
+               
+               for (var i = 0; i < n.length; i++) {
+                       if (ns[n[i]] == null) 
+                               ns[n[i]] = {
+                                       rows: new Array(),
+                                       o: null
+                               };
+                       ns[n[i]].rows.push(i);
+               }
+               
+               for (var i = 0; i < o.length; i++) {
+                       if (os[o[i]] == null) 
+                               os[o[i]] = {
+                                       rows: new Array(),
+                                       n: null
+                               };
+                       os[o[i]].rows.push(i);
+               }
+               
+               for (var i in ns) {
+                       if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
+                               n[ns[i].rows[0]] = {
+                                       text: n[ns[i].rows[0]],
+                                       row: os[i].rows[0]
+                               };
+                               o[os[i].rows[0]] = {
+                                       text: o[os[i].rows[0]],
+                                       row: ns[i].rows[0]
+                               };
+                       }
+               }
+               
+               for (var i = 0; i < n.length - 1; i++) {
+                       if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
+                       n[i + 1] == o[n[i].row + 1]) {
+                               n[i + 1] = {
+                                       text: n[i + 1],
+                                       row: n[i].row + 1
+                               };
+                               o[n[i].row + 1] = {
+                                       text: o[n[i].row + 1],
+                                       row: i + 1
+                               };
+                       }
+               }
+               
+               for (var i = n.length - 1; i > 0; i--) {
+                       if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
+                       n[i - 1] == o[n[i].row - 1]) {
+                               n[i - 1] = {
+                                       text: n[i - 1],
+                                       row: n[i].row - 1
+                               };
+                               o[n[i].row - 1] = {
+                                       text: o[n[i].row - 1],
+                                       row: i - 1
+                               };
+                       }
+               }
+               
+               return {
+                       o: o,
+                       n: n
+               };
+       }
+       
+       return function(o, n){
+               o = o.replace(/\s+$/, '');
+               n = n.replace(/\s+$/, '');
+               var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
+
+               var str = "";
+               
+               var oSpace = o.match(/\s+/g);
+               if (oSpace == null) {
+                       oSpace = [" "];
+               }
+               else {
+                       oSpace.push(" ");
+               }
+               var nSpace = n.match(/\s+/g);
+               if (nSpace == null) {
+                       nSpace = [" "];
+               }
+               else {
+                       nSpace.push(" ");
+               }
+               
+               if (out.n.length == 0) {
+                       for (var i = 0; i < out.o.length; i++) {
+                               str += '<del>' + out.o[i] + oSpace[i] + "</del>";
+                       }
+               }
+               else {
+                       if (out.n[0].text == null) {
+                               for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
+                                       str += '<del>' + out.o[n] + oSpace[n] + "</del>";
+                               }
+                       }
+                       
+                       for (var i = 0; i < out.n.length; i++) {
+                               if (out.n[i].text == null) {
+                                       str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
+                               }
+                               else {
+                                       var pre = "";
+                                       
+                                       for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
+                                               pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
+                                       }
+                                       str += " " + out.n[i].text + nSpace[i] + pre;
+                               }
+                       }
+               }
+               
+               return str;
+       }
+})();
+
+})(this);
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/js/qunit/qunit.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorjsqunitreporterjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/qunit/reporter.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/qunit/reporter.js                            (rev 0)
+++ trunk/tests/qunit/editor/js/qunit/reporter.js       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+(function() {
+       if (parent != window && window.QUnit) {
+               QUnit.done = function(data) {
+                       if (window.__$coverObject) {
+                               parent.TestRunner.addCoverObject(window.__$coverObject);
+                       }
+
+                       if (parent.TestRunner) {
+                               parent.TestRunner.done(data.failed, data.total, document.title);
+                       }
+               };
+       }
+})();
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/js/qunit/reporter.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorjsqunittestrunnercss"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/qunit/testrunner.css (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/qunit/testrunner.css                         (rev 0)
+++ trunk/tests/qunit/editor/js/qunit/testrunner.css    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,151 @@
</span><ins>+body, html {
+       margin: 0; padding: 0;
+       overflow: hidden;
+       width: 100%; height: 100%;
+       position: absolute;
+       top: 0; left: 0;
+       font-size: 12px;
+       font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+       color: #111;
+       background: #EEE;
+}
+
+a {
+       color: #111;
+}
+
+.runner, .sidebar, .controls, .tests {
+       position: absolute;
+       top: 0; left: 0;
+}
+
+.sidebar {
+       background: #DDD;
+}
+
+.controls {
+       background: #BBB;
+}
+
+.controls div {
+       padding: 2px;
+}
+
+.tests {
+       overflow: auto;
+}
+
+.suite {
+       padding: 10px;
+}
+
+.suite .selection {
+       float: right;
+       font-weight: normal;
+}
+
+.stats {
+       display: none;
+       float: right;
+       margin-right: 3px;
+       font-size: 10px;
+       line-height: 16px;
+}
+
+.test {
+       margin: 5px;
+       background: #EEE;
+       line-height: 16px;
+}
+
+.passed a {
+       color: #888;
+}
+
+span.passed {
+       color: green;
+}
+
+div.failed {
+       background: #EE5757;
+}
+
+span.failed {
+       color: red;
+}
+
+.failed span.failed {
+       color: black;
+}
+
+.running .stats, .failed .stats, .passed .stats, .skipped .stats {
+       display: inline;
+       font-weight: bold;
+}
+
+.suite-title {
+       font-weight: bold;
+}
+
+.gstatus {
+       float: right;
+}
+
+iframe {
+       position: absolute;
+       top: 0; left: 0;
+       border: 0;
+       padding: 0;
+}
+
+*[unselectable] {
+       -moz-user-select: none;
+       -webkit-user-select: none;
+       -o-user-select: none;
+       user-select: none;
+}
+
+button#coverage {
+       float: right;
+}
+
+#coverview {
+       display: none;
+       position: fixed;
+       background: #fff;
+       z-index: 9;
+       box-shadow: 0 0 10px rgba(0,0,0,0.5);
+}
+
+#coverview iframe {
+       position: absolute;
+       top: 0;
+       left: 0;
+       width: 100%;
+       height: 100%;
+}
+
+#coverview .close {
+       position: absolute;
+       right: -14px;
+       top: -18px;
+       color: #000;
+       font-size: 14px;
+       display: block;
+       z-index: 11;
+       text-decoration: none;
+       font-family: Verdana;
+       font-weight: bold;
+       text-shadow: 0 0 2px #fff;
+}
+
+#overlay {
+       display: none;
+       position: fixed;
+       top: 0;
+       left: 0;
+       width: 100%;
+       height: 100%;
+       background: #ccc;
+       background: rgba(0,0,0,0.3);
+}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunktestsquniteditorjsqunittestrunnerjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/qunit/testrunner.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/qunit/testrunner.js                          (rev 0)
+++ trunk/tests/qunit/editor/js/qunit/testrunner.js     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,540 @@
</span><ins>+// Quick and dirty testrunner hack, it's ugly but it works
+(function() {
+       function TestRunner() {
+               var suites = [], suiteUrls = [], actions = {};
+               var started, currentTest, testUrls = [], globalStats = {};
+               var coverObjects = [];
+
+               function get(id) {
+                       return document.getElementById(id);
+               }
+
+               function addClass(elm, cls) {
+                       if (cls && !hasClass(elm, cls)) {
+                               elm.className += elm.className ? ' ' + cls : cls;
+                       }
+               }
+
+               function removeClass(elm, cls) {
+                       if (hasClass(elm, cls)) {
+                               elm.className = elm.className.replace(new RegExp("(^|\\s+)" + cls + "(\\s+|$)", "g"), ' ');
+                       }
+               }
+
+               function hasClass(elm, cls) {
+                       return elm && cls && (' ' + elm.className + ' ').indexOf(' ' + cls + ' ') !== -1;
+               }
+
+               function init() {
+                       function loadNext() {
+                               var url = suiteUrls.shift();
+
+                               if (url) {
+                                       loadSuite(url, function(json, url) {
+                                               json.baseURL = url.substring(0, url.lastIndexOf('/'));
+                                               if (json.baseURL) {
+                                                       json.baseURL += '/';
+                                               }
+
+                                               suites.push(json);
+                                               loadNext();
+                                       });
+                               } else {
+                                       render();
+                                       reflow();
+                                       hashToStates();
+                                       // WP
+                                       wpTests();
+                               }
+                       }
+
+                       loadNext();
+               }
+
+               function getHashData() {
+                       var pos, hash = location.hash, items, item, data = {}, i;
+
+                       pos = hash.indexOf('!');
+                       if (pos > 0) {
+                               items = hash.substring(pos + 1).split('&');
+                               for (i = 0; i < items.length; i++) {
+                                       item = items[i].split('=');
+                                       data[item[0]] = item[1];
+                               }
+                       }
+
+                       return data;
+               }
+
+               function setHashData(data) {
+                       var name, hashItems = [];
+
+                       for (name in data) {
+                               if (data[name] !== null) {
+                                       hashItems.push(name + '=' + data[name]);
+                               }
+                       }
+
+                       location.hash = '!' + hashItems.join('&');
+               }
+
+               function statesToHash() {
+                       var i, checkboxes, states = [], hasDisabled;
+
+                       checkboxes = get('tests').getElementsByTagName("input");
+                       for (i = 0; i < checkboxes.length; i++) {
+                               states[i] = checkboxes[i].checked ? '1' : '0';
+                               hasDisabled = hasDisabled || states[i] === '0';
+                       }
+
+                       setHashData({
+                               min: get('min').checked,
+                               jsrobot: get('jsrobot').checked,
+                               tests: hasDisabled ? states.join('') : null
+                       });
+               }
+
+               function hashToStates() {
+                       var i, data = getHashData(location.hash), checkboxes;
+
+                       if (typeof(data.min) != "undefined") {
+                               get('min').checked = data.min === "true";
+                       }
+
+                       if (typeof(data.jsrobot) != "undefined") {
+                               get('jsrobot').checked = data.jsrobot === "true";
+                       }
+
+                       if (typeof(data.tests) != "undefined") {
+                               checkboxes = get('tests').getElementsByTagName("input");
+                               for (i = 0; i < checkboxes.length; i++) {
+                                       checkboxes[i].checked = data.tests.substr(i, 1) === '1';
+                               }
+                       }
+               }
+
+               function addAction(name, action) {
+                       actions[name] = action;
+               }
+
+               function toggleCheckboxes(elm, state) {
+                       var checkboxes = (elm || get('tests')).getElementsByTagName("input"), i;
+
+                       for (i = 0; i < checkboxes.length; i++) {
+                               checkboxes[i].checked = state;
+                       }
+               }
+
+               function start() {
+                       var si, ti, tests;
+
+                       testUrls = [];
+                       for (si = 0; si < suites.length; si++) {
+                               tests = suites[si].tests;
+                               for (ti = 0; ti < tests.length; ti++) {
+                                       if (get('c' + si + '-' + ti).checked) {
+                                               testUrls.push(tests[ti]);
+                                       }
+
+                                       removeClass(get('t' + si + '-' + ti), "passed");
+                                       removeClass(get('t' + si + '-' + ti), "failed");
+                               }
+                       }
+
+                       globalStats = {
+                               total: 0,
+                               failed: 0
+                       };
+
+                       // Start first test
+                       currentTest = testUrls.shift();
+                       if (currentTest) {
+                               get('testview').src = currentTest.url + "?min=" + get('min').checked;
+                       }
+
+                       get('coverage').disabled = true;
+               }
+
+               function stop() {
+                       started = false;
+                       get('testview').src = 'javascript:""';
+                       get('start').innerHTML = 'start';
+
+                       if (coverObjects.length) {
+                               get('coverage').disabled = false;
+                       }
+               }
+
+               addAction("start", function(elm) {
+                       started = !started;
+
+                       if (started) {
+                               start();
+                       } else {
+                               stop();
+                               reset();
+                       }
+
+                       elm.innerHTML = started ? 'stop' : 'start';
+               });
+
+               addAction("select-none", function(elm) {
+                       toggleCheckboxes(get('s' + elm.getAttribute("data-suite")), false);
+                       reset();
+               });
+
+               addAction("select-all", function(elm) {
+                       toggleCheckboxes(get('s' + elm.getAttribute("data-suite")), true);
+                       reset();
+               });
+
+               addAction("select-failed", function(elm) {
+                       toggleCheckboxes(get('s' + elm.getAttribute("data-suite")), false);
+                       reset();
+
+                       var targetIndex = elm.getAttribute("data-suite");
+
+                       for (si = 0; si < suites.length; si++) {
+                               if (targetIndex !== null && targetIndex != si) {
+                                       continue;
+                               }
+
+                               tests = suites[si].tests;
+                               for (ti = 0; ti < tests.length; ti++) {
+                                       if (tests[ti].failed) {
+                                               get('c' + si + '-' + ti).checked = true;
+                                       }
+                               }
+                       }
+               });
+
+               // WP
+               function wpTests( element ) {
+                       var si, ti, tests, targetIndex = null;
+
+                       if ( element ) {
+                               targetIndex = element.getAttribute("data-suite");
+                       }
+
+                       toggleCheckboxes( get( 's' + targetIndex ), false );
+                       reset();
+
+                       for ( si = 0; si < suites.length; si++ ) {
+                               if ( targetIndex !== null && targetIndex != si ) {
+                                       continue;
+                               }
+
+                               tests = suites[si].tests;
+                               
+                               if ( si === 0 || si === 2 || si === 3 || si === 4 ) {
+                                       for ( ti in tests ) {
+                                               get( 'c' + si + '-' + ti ).checked = true;
+                                       }
+                               } else if ( si === 1 ) {
+                                       for ( ti in tests ) {
+                                               if ( ti !== '1' ) {
+                                                       // No jQuery integration
+                                                       get( 'c' + si + '-' + ti ).checked = true;
+                                               }
+                                       }
+                               } else if ( si === 5 ) {
+                                       for ( ti in tests ) {
+                                               // Only the media and paste plugins
+                                               if ( ti === '0' || ti === '2' ) {
+                                                       get( 'c' + si + '-' + ti ).checked = true;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               // WP
+               addAction("select-wordpress", wpTests );
+
+               addAction("coverage", function(elm) {
+                       if (elm.disabled) {
+                               return;
+                       }
+                       showCoverage();
+               });
+
+               function render() {
+                       var si, ti, tests, html = '';
+
+                       var div = document.createElement('div');
+                       addClass(div, "runner");
+
+                       html += '<div id="sidebar" class="sidebar" unselectable="true">';
+                       html += '<div id="controls" class="controls">';
+                       html += '<div>';
+                       html += '<button id="start" data-action="start">Start</button>';
+                       html += '<label><input id="min" type="checkbox" checked>Minified</label>';
+                       html += '<label style="display:none"><input id="jsrobot" type="checkbox">JSRobot</label>';
+                       html += '<button id="coverage" data-action="coverage" disabled>Coverage</button>';
+                       html += '</div>';
+                       html += '<div>';
+                       html += '<span id="gstatus" class="gstatus"></span>';
+                       html += 'Select: ';
+                       html += '<a data-action="select-wordpress" href="javascript:;">WP</a> ';
+                       html += '<a data-action="select-all" href="javascript:;">[All]</a> ';
+                       html += '<a data-action="select-none" href="javascript:;">[None]</a> ';
+                       html += '<a data-action="select-failed" href="javascript:;">[Failed]</a>';
+                       html += '</div>';
+                       html += '</div>';
+                       html += '<div id="tests" class="tests">';
+
+                       for (si = 0; si < suites.length; si++) {
+                               tests = suites[si].tests;
+                               html += '<div id="s' + si + '" class="suite"><div class="suite-title">';
+                               html += '<div class="selection">';
+                               html += '<a data-action="select-wordpress" data-suite="' + si + '" href="javascript:;">WP</a> ';
+                               html += '<a data-action="select-all" data-suite="' + si + '" href="javascript:;">[All]</a> ';
+                               html += '<a data-action="select-none" data-suite="' + si + '" href="javascript:;">[None]</a> ';
+                               html += '<a data-action="select-failed" data-suite="' + si + '" href="javascript:;">[Failed]</a>';
+                               html += '</div>' + suites[si].title;
+                               html += '</div>';
+                               for (ti = 0; ti < tests.length; ti++) {
+                                       tests[ti].suiteIndex = si;
+                                       tests[ti].testIndex = ti;
+                                       tests[ti].url = suites[si].baseURL + tests[ti].url;
+
+                                       html += (
+                                               '<div id="t' + si + '-' + ti + '" class="test">' +
+                                                       '<span id="s' + si + '-' + ti + '" class="stats">Running</span>' +
+                                                       '<input id="c' + si + '-' + ti + '" type="checkbox" checked />' +
+                                                       '<a href="' + tests[ti].url + '" target="testview">' + tests[ti].title + '</a>' +
+                                               '</div>'
+                                       );
+                               }
+                               html += '</div>';
+                       }
+
+                       html += '</div>';
+                       html += '</div>';
+
+                       html += '<iframe id="testview" name="testview" src="javascript:\'\'"></iframe>';
+
+                       // coverage
+                       html += '<div id="overlay"></div>'; 
+                       html += '<div id="coverview">';
+                       html += '<a class="close" href="javascript:TestRunner.hideCoverage();" title="Close">x</a>';
+                       html += '<iframe frameborder="0" src="javascript:\'\'"></iframe>';
+                       html += '</div>';
+
+                       div.innerHTML = html;
+                       document.body.appendChild(div);
+
+                       get('sidebar').onclick = function(e) {
+                               var target;
+
+                               e = e || event;
+                               target = e.target || e.srcElement;
+
+                               if ((action = actions[target.getAttribute("data-action")])) {
+                                       action(target);
+                               }
+
+                               statesToHash();
+                       };
+               }
+
+               function addSuites(urls) {
+                       suiteUrls.push.apply(suiteUrls, urls);
+               }
+
+               function loadSuite(url, callback) {
+                       var xhr;
+
+                       function ready() {
+                               if (xhr.readyState == 4) {
+                                       callback(eval("(" + xhr.responseText + ")"), url);
+                                       xhr = null;
+                               } else {
+                                       setTimeout(ready, 10);
+                               }
+                       }
+
+                       xhr = new XMLHttpRequest();
+
+                       if (xhr) {
+                               xhr.open('GET', url, true);
+                               xhr.send();
+                               setTimeout(ready, 10);
+                       }
+               }
+
+               function reflow() {
+                       var viewPortW, viewPortH, sideBarWidth, controlsHeight;
+
+                       function rect(id, x, y, w, h) {
+                               var style, elm;
+
+                               if ((elm = get(id))) {
+                                       style = elm.style;
+                                       style.left = x + "px";
+                                       style.top = y + "px";
+                                       style.width = w + "px";
+                                       style.height = h + "px";
+                               }
+                       }
+
+                       viewPortW = window.innerWidth || document.documentElement.clientWidth;
+                       viewPortH = window.innerHeight || document.documentElement.clientHeight;
+
+                       sideBarWidth = 300;
+                       controlsHeight = 60;
+
+                       rect('testview', sideBarWidth, 0, viewPortW - sideBarWidth, viewPortH);
+                       rect('sidebar', 0, 0, sideBarWidth, viewPortH);
+                       rect('controls', 0, 0, sideBarWidth, controlsHeight);
+                       rect('tests', 0, controlsHeight, sideBarWidth, viewPortH - controlsHeight);
+               }
+
+               function reset() {
+                       var si, tests, ti;
+
+                       stop();
+                       get('gstatus').innerHTML = '';
+                       removeClass(get("controls"), "failed");
+
+                       for (si = 0; si < suites.length; si++) {
+                               tests = suites[si].tests;
+                               for (ti = 0; ti < tests.length; ti++) {
+                                       removeClass(get('t' + si + '-' + ti), "passed");
+                                       removeClass(get('t' + si + '-' + ti), "failed");
+                                       removeClass(get('t' + si + '-' + ti), "running");
+                               }
+                       }
+               }
+
+               function updateGlobalStatus() {
+                       get('gstatus').innerHTML = 'Total: ' + globalStats.total + ", Failed: " + globalStats.failed;
+                       addClass(get("controls"), globalStats.failed > 0 ? "failed" : "");
+               }
+
+               function done(failed, total) {
+                       var nextTest, currentTestElm;
+
+                       function runNextTest() {
+                               if ((nextTest = testUrls.shift())) {
+                                       currentTest = nextTest;
+                                       currentTestElm = get('t' + currentTest.suiteIndex + '-' + currentTest.testIndex);
+                                       currentTestElm.scrollIntoView(false);
+
+                                       if (nextTest.jsrobot === true && !get('jsrobot').checked) {
+                                               get('s' + currentTest.suiteIndex + '-' + currentTest.testIndex).innerHTML = 'Skipped';
+                                               addClass(currentTestElm, "skipped");
+                                               runNextTest();
+                                       } else {
+                                               addClass(currentTestElm, "running");
+                                               get('testview').src = nextTest.url + "?min=" + get('min').checked;
+                                       }
+                               } else {
+                                       stop();
+                               }
+                       }
+
+                       if (started) {
+                               currentTest.failed = failed;
+                               currentTest.total = total;
+
+                               globalStats.total += total;
+                               globalStats.failed += failed;
+                               updateGlobalStatus();
+
+                               get('s' + currentTest.suiteIndex + '-' + currentTest.testIndex).innerHTML = (
+                                       '(<span class="failed">' + failed + '</span>, ' +
+                                       '<span class="passed">' + (total - failed) + '</span>, ' +
+                                       '<span class="total">' + total + '</span>)'
+                               );
+
+                               addClass(get('t' + currentTest.suiteIndex + '-' + currentTest.testIndex), failed > 0 ? 'failed' : 'passed');
+                               removeClass(currentTestElm, "running");
+
+                               runNextTest();
+                       }
+               }
+
+
+               function addCoverObject(coverObject) {
+                       coverObjects.push(coverObject);
+               }
+
+
+               // this is going to be called from the coverage iframe
+               function getCoverObject() {
+                       var coverObject = {}, fileName, gaps, gap, count;
+
+                       for (var i = 0, length = coverObjects.length; i < length; i++) {
+                               for (fileName in coverObjects[i]) {
+                                       gaps = coverObjects[i][fileName];
+
+                                       if (!coverObject.hasOwnProperty(fileName))      {
+                                               coverObject[fileName] = gaps;
+                                       } else {
+                                               for (gap in gaps) {
+                                                       if (gap === '__code') {
+                                                               continue;
+                                                       }
+                                                       count = gaps[gap];
+                                                       if (!coverObject[fileName].hasOwnProperty(gap)) {
+                                                               coverObject[fileName][gap] = count;
+                                                       } else {
+                                                               coverObject[fileName][gap] += count;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       return coverObject;
+               }
+
+               function showCoverage() {
+                       var overlay, coverView, viewPortW, viewPortH;
+
+                       viewPortW = window.innerWidth || document.documentElement.clientWidth;
+                       viewPortH = window.innerHeight || document.documentElement.clientHeight;
+
+                       overlay = get('overlay');
+                       overlay.style.display = 'block';
+
+                       coverView = get('coverview');
+                       coverView.style.left = '30px';
+                       coverView.style.top = '30px';
+                       coverView.style.width = (viewPortW - 60) + 'px';
+                       coverView.style.height = (viewPortH - 60) + 'px';
+                       coverView.style.display = 'block';
+
+                       coverView.getElementsByTagName('iframe')[0].src = 'coverage/index.html';
+               }
+
+               function hideCoverage() {
+                       get('overlay').style.display = 'none';
+                       get('coverview').style.display = 'none';
+               }
+
+               return {
+                       init: init,
+                       addSuites: addSuites,
+                       reflow: reflow,
+                       done: done,
+                       addCoverObject: addCoverObject,
+                       getCoverObject: getCoverObject,
+                       showCoverage: showCoverage,
+                       hideCoverage: hideCoverage
+               };
+       }
+
+       var testRunner = new TestRunner();
+
+       self.onload = function() {
+               testRunner.init();
+       };
+
+       self.onresize = function() {
+               testRunner.reflow();
+       };
+
+       self.TestRunner = testRunner;
+})();
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/js/qunit/testrunner.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorjstinymce_loaderjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/tinymce_loader.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/tinymce_loader.js                            (rev 0)
+++ trunk/tests/qunit/editor/js/tinymce_loader.js       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+// Edited for WordPress
+(function() {
+       var baseURL;
+
+       // Get base where the tinymce script is located
+       var scripts = document.getElementsByTagName('script');
+       for ( var i = 0; i < scripts.length; i++ ) {
+               var src = scripts[i].src;
+
+               if ( /tinymce_loader\.js/.test( src ) ) {
+                       baseURL = src.substring( 0, src.indexOf('/tests/qunit/') );
+                       break;
+               }
+       }
+
+       document.write('<script src="' + baseURL + '/src/wp-includes/js/tinymce/tinymce.min.js"></script>');
+})();
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/js/tinymce_loader.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorjsutilsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/js/utils.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/js/utils.js                             (rev 0)
+++ trunk/tests/qunit/editor/js/utils.js        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,299 @@
</span><ins>+function fontFace(face) {
+       if (tinymce.isOpera) {
+               return "'" + face + "'";
+       } else {
+               return face;
+       }
+}
+
+function findContainer(selector) {
+       var container;
+       if (tinymce.is(selector, 'string')) {
+               container = editor.dom.select(selector)[0];
+       } else {
+               container = selector;
+       }
+       if (container.firstChild) {
+               container = container.firstChild;
+       }
+       return container;
+}
+
+function setSelection(startSelector, startOffset, endSelector, endOffset) {
+       if (!endSelector) {
+               endSelector = startSelector;
+               endOffset = startOffset;
+       }
+       var startContainer = findContainer(startSelector);
+       var endContainer = findContainer(endSelector);
+       var rng = editor.dom.createRng();
+
+       function setRange(container, offset, start) {
+               offset = offset || 0;
+
+               if (offset === 'after') {
+                       if (start) {
+                               rng.setStartAfter(container);
+                       } else {
+                               rng.setEndAfter(container);
+                       }
+                       return;
+               } else if (offset === 'afterNextCharacter') {
+                       container = container.nextSibling;
+                       offset = 1;
+               }
+               if (start) {
+                       rng.setStart(container, offset);
+               } else {
+                       rng.setEnd(container, offset);
+               }
+       }
+
+       setRange(startContainer, startOffset, true);
+       setRange(endContainer, endOffset, false);
+       editor.selection.setRng(rng);
+}
+
+function initWhenTinyAndRobotAreReady(initTinyFunction) {
+       function loaded() {
+               QUnit.start();
+       }
+
+       tinymce.on('AddEditor', function(e) {
+               e.editor.on('Init', function() {
+                       loaded();
+               });
+       });
+
+       window.robot.onload(initTinyFunction);
+}
+
+function trimContent(content) {
+       return content.replace(/^<p>&nbsp;<\/p>\n?/, '').replace(/\n?<p>&nbsp;<\/p>$/, '');
+}
+
+/**
+ * Fakes a key event.
+ *
+ * @param {Element/String} e DOM element object or element id to send fake event to.
+ * @param {String} na Event name to fake like "keydown".
+ * @param {Object} o Optional object with data to send with the event like keyCode and charCode.
+ */
+function fakeKeyEvent(e, na, o) {
+       var ev;
+
+       o = tinymce.extend({
+               keyCode : 13,
+               charCode : 0
+       }, o);
+
+       e = tinymce.DOM.get(e);
+
+       if (e.fireEvent) {
+               ev = document.createEventObject();
+               tinymce.extend(ev, o);
+               e.fireEvent('on' + na, ev);
+               return;
+       }
+
+       if (document.createEvent) {
+               try {
+                       // Fails in Safari
+                       ev = document.createEvent('KeyEvents');
+                       ev.initKeyEvent(na, true, true, window, false, false, false, false, o.keyCode, o.charCode);
+               } catch (ex) {
+                       ev = document.createEvent('Events');
+                       ev.initEvent(na, true, true);
+
+                       ev.keyCode = o.keyCode;
+                       ev.charCode = o.charCode;
+               }
+       } else {
+               ev = document.createEvent('UIEvents');
+
+               if (ev.initUIEvent)
+                       ev.initUIEvent(na, true, true, window, 1);
+
+               ev.keyCode = o.keyCode;
+               ev.charCode = o.charCode;
+       }
+
+       e.dispatchEvent(ev);
+}
+
+function normalizeRng(rng) {
+       if (rng.startContainer.nodeType == 3) {
+               if (rng.startOffset == 0)
+                       rng.setStartBefore(rng.startContainer);
+               else if (rng.startOffset >= rng.startContainer.nodeValue.length - 1)
+                       rng.setStartAfter(rng.startContainer);
+       }
+
+       if (rng.endContainer.nodeType == 3) {
+               if (rng.endOffset == 0)
+                       rng.setEndBefore(rng.endContainer);
+               else if (rng.endOffset >= rng.endContainer.nodeValue.length - 1)
+                       rng.setEndAfter(rng.endContainer);
+       }
+
+       return rng;
+}
+
+// TODO: Replace this with the new event logic in 3.5
+function type(chr) {
+       var editor = tinymce.activeEditor, keyCode, charCode, event = tinymce.dom.Event, evt, startElm, rng;
+
+       function fakeEvent(target, type, evt) {
+               editor.dom.fire(target, type, evt);
+       }
+
+       // Numeric keyCode
+       if (typeof(chr) == "number") {
+               charCode = keyCode = chr;
+       } else if (typeof(chr) == "string") {
+               // String value
+               if (chr == '\b') {
+                       keyCode = 8;
+                       charCode = chr.charCodeAt(0);
+               } else if (chr == '\n') {
+                       keyCode = 13;
+                       charCode = chr.charCodeAt(0);
+               } else {
+                       charCode = chr.charCodeAt(0);
+                       keyCode = charCode;
+               }
+       } else {
+               evt = chr;
+       }
+
+       evt = evt || {keyCode: keyCode, charCode: charCode};
+
+       startElm = editor.selection.getStart();
+       fakeEvent(startElm, 'keydown', evt);
+       fakeEvent(startElm, 'keypress', evt);
+
+       if (!evt.isDefaultPrevented()) {
+               if (keyCode == 8) {
+                       if (editor.getDoc().selection) {
+                               rng = editor.getDoc().selection.createRange();
+
+                               if (rng.text.length === 0) {
+                                       rng.moveStart('character', -1);
+                                       rng.select();
+                               }
+
+                               rng.execCommand('Delete', false, null);
+                       } else {
+                               rng = editor.selection.getRng();
+
+                               if (rng.startContainer.nodeType == 1 && rng.collapsed) {
+                                       var nodes = rng.startContainer.childNodes, lastNode = nodes[nodes.length - 1];
+
+                                       // If caret is at <p>abc|</p> and after the abc text node then move it to the end of the text node
+                                       // Expand the range to include the last char <p>ab[c]</p> since IE 11 doesn't delete otherwise
+                                       if (rng.startOffset >= nodes.length - 1 && lastNode && lastNode.nodeType == 3 && lastNode.data.length > 0) {
+                                               rng.setStart(lastNode, lastNode.data.length - 1);
+                                               rng.setEnd(lastNode, lastNode.data.length);
+                                               editor.selection.setRng(rng);
+                                       }
+                               }
+
+                               editor.getDoc().execCommand('Delete', false, null);
+                       }
+               } else if (typeof(chr) == 'string') {
+                       rng = editor.selection.getRng(true);
+
+                       if (rng.startContainer.nodeType == 3 && rng.collapsed) {
+                               rng.startContainer.insertData(rng.startOffset, chr);
+                               rng.setStart(rng.startContainer, rng.startOffset + 1);
+                               rng.collapse(true);
+                               editor.selection.setRng(rng);
+                       } else {
+                               rng.insertNode(editor.getDoc().createTextNode(chr));
+                       }
+               }
+       }
+
+       fakeEvent(startElm, 'keyup', evt);
+}
+
+function cleanHtml(html) {
+       html = html.toLowerCase().replace(/[\r\n]+/gi, '');
+       html = html.replace(/ (sizcache[0-9]+|sizcache|nodeindex|sizset[0-9]+|sizset|data\-mce\-expando|data\-mce\-selected)="[^"]*"/gi, '');
+       html = html.replace(/<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>|<div[^>]+data-mce-bogus[^>]+><\/div>/gi, '');
+
+       return html;
+}
+
+function normalizeHtml(html) {
+       var writer = new tinymce.html.Writer();
+
+       new tinymce.html.SaxParser({
+               validate: false,
+               comment: writer.comment,
+               cdata: writer.cdata,
+               text: writer.text,
+               end: writer.end,
+               pi: writer.pi,
+               doctype: writer.doctype,
+
+               start: function(name, attrs, empty) {
+                       attrs.sort(function(a, b) {
+                               if (a.name === b.name) {
+                                       return 0;
+                               }
+
+                               return a.name > b.name ? 1 : -1;
+                       });
+
+                       writer.start(name, attrs, empty);
+               }
+       }).parse(html);
+
+       return writer.getContent();
+}
+
+/**
+ * Measures the x, y, w, h of the specified element/control relative to the view element.
+ */
+function rect(ctrl) {
+       var outerRect, innerRect;
+
+       if (ctrl.nodeType) {
+               innerRect = ctrl.getBoundingClientRect();
+       } else {
+               innerRect = ctrl.getEl().getBoundingClientRect();
+       }
+
+       outerRect = document.getElementById('view').getBoundingClientRect();
+
+       return [
+               Math.round(innerRect.left - outerRect.left),
+               Math.round(innerRect.top - outerRect.top),
+               Math.round(innerRect.right - innerRect.left),
+               Math.round(innerRect.bottom - innerRect.top)
+       ];
+}
+
+function size(ctrl) {
+       return rect(ctrl).slice(2);
+}
+
+function resetScroll(elm) {
+       elm.scrollTop = 0;
+       elm.scrollLeft = 0;
+}
+
+// Needed since fonts render differently on different platforms
+function nearlyEqualRects(rect1, rect2, diff) {
+       diff = diff || 1;
+
+       for (var i = 0; i < 4; i++) {
+               if (Math.abs(rect1[i] - rect2[i]) > diff) {
+                       deepEqual(rect1, rect2);
+                       return;
+               }
+       }
+
+       ok(true);
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/js/utils.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsautolinkhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/autolink.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/autolink.html                           (rev 0)
+++ trunk/tests/qunit/editor/plugins/autolink.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,170 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Automatic link tests</title>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script src="js/dsl.js"></script>
+<script src="js/autolink.actions.js"></script>
+<script src="js/states.js"></script>
+<script><!--
+window.robotUsesSymbols = true;
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Automatic Links", {
+    autostart: false,
+    setup: function() {
+        window.queue = new dsl.Queue();
+    }
+});
+
+if (!tinymce.isIE) {
+       asyncTest('Typing a HTTP URL', function() {
+               TypingHTTPURL.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPURL.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPURL.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPURL.inA(ParagraphWithMarginAndPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px; margin-left: 60px;"><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test</h1>$'));
+               TypingHTTPURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test</td><td>&nbsp;</td></tr></tbody></table>$'));
+               TypingHTTPURL.inA(TableCellWithBrsFirstLine2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s|&nbsp;)Test<br />Line 2</td><td>&nbsp;</td></tr></tbody></table>$'));
+
+               TypingEclipsedHTTPURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="http://www.ephox.com">http://www.ephox.com</a>\\)(\\s|&nbsp;)Test</p>$'));
+
+               TypingHTTPURLAndNewline.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="http://www.ephox.com">http://www.ephox.com</a></p><p>(Test|<a href=\"http://www.ephox.com\"></a>Test)</p>$'));
+
+               queue.done();
+       });
+
+       asyncTest('Typing a HTTPS URL', function() {
+               TypingHTTPSURL.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPSURL.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPSURL.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPSURL.inA(ParagraphWithMarginAndPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px; margin-left: 60px;"><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingHTTPSURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test</h1>$'));
+               TypingHTTPSURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test</td><td>&nbsp;</td></tr></tbody></table>$'));
+               TypingHTTPSURL.inA(TableCellWithBrsFirstLine2).gives(new RegExp('^<table><tbody><tr><td><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s|&nbsp;)Test<br />Line 2</td><td>&nbsp;</td></tr></tbody></table>$'));
+
+               TypingEclipsedHTTPSURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="https://www.ephox.com">https://www.ephox.com</a>\\)(\\s|&nbsp;)Test</p>$'));
+
+               TypingHTTPSURLAndNewline.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="https://www.ephox.com">https://www.ephox.com</a></p><p>(Test|<a href=\"https://www.ephox.com\"></a>Test)</p>$'));
+
+               queue.done();
+       });
+
+       asyncTest('Typing a SSH URL', function() {
+               TypingSSHURL.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingSSHURL.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingSSHURL.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingSSHURL.inA(ParagraphWithMarginAndPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px; margin-left: 60px;"><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingSSHURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test</h1>$'));
+               TypingSSHURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test</td><td>&nbsp;</td></tr></tbody></table>$'));
+               TypingSSHURL.inA(TableCellWithBrsFirstLine2).gives(new RegExp('^<table><tbody><tr><td><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s|&nbsp;)Test<br />Line 2</td><td>&nbsp;</td></tr></tbody></table>$'));
+
+               TypingEclipsedSSHURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="ssh://www.ephox.com">ssh://www.ephox.com</a>\\)(\\s|&nbsp;)Test</p>$'));
+
+               TypingSSHURLAndNewline.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="ssh://www.ephox.com">ssh://www.ephox.com</a></p><p>(Test|<a href=\"ssh://www.ephox.com\"></a>Test)</p>$'));
+
+               queue.done();
+       });
+
+       asyncTest('Typing a FTP URL', function() {
+               TypingFTPURL.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingFTPURL.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingFTPURL.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingFTPURL.inA(ParagraphWithMarginAndPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px; margin-left: 60px;"><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingFTPURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test</h1>$'));
+               TypingFTPURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test</td><td>&nbsp;</td></tr></tbody></table>$'));
+               TypingFTPURL.inA(TableCellWithBrsFirstLine2).gives(new RegExp('^<table><tbody><tr><td><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s|&nbsp;)Test<br />Line 2</td><td>&nbsp;</td></tr></tbody></table>$'));
+
+               TypingEclipsedFTPURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="ftp://www.ephox.com">ftp://www.ephox.com</a>\\)(\\s|&nbsp;)Test</p>$'));
+
+               TypingFTPURLAndNewline.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="ftp://www.ephox.com">ftp://www.ephox.com</a></p><p>(Test|<a href=\"ftp://www.ephox.com\"></a>Test)</p>$'));
+
+               queue.done();
+       });
+
+       asyncTest('Typing a WWW URL', function() {
+               TypingWWWURL.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURL.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURL.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURL.inA(ParagraphWithMarginAndPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px; margin-left: 60px;"><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test</h1>$'));
+               TypingWWWURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test</td><td>&nbsp;</td></tr></tbody></table>$'));
+               TypingWWWURL.inA(TableCellWithBrsFirstLine2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.ephox.com">www.ephox.com</a>(\\s|&nbsp;)Test<br />Line 2</td><td>&nbsp;</td></tr></tbody></table>$'));
+
+               TypingEclipsedWWWURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="http://www.ephox.com">www.ephox.com</a>\\)(\\s|&nbsp;)Test</p>$'));
+
+               TypingWWWURLAndNewline.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="http://www.ephox.com">www.ephox.com</a></p><p>(Test|<a href=\"http://www.ephox.com\"></a>Test)</p>$'));
+
+               queue.done();
+       });
+
+       asyncTest('Typing a WWW URL with end dot', function() {
+               TypingWWWURLWithEndDot.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURLWithEndDot.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURLWithEndDot.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURLWithEndDot.inA(ParagraphWithMarginAndPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px; margin-left: 60px;"><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test</p>$'));
+               TypingWWWURLWithEndDot.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test</h1>$'));
+               TypingWWWURLWithEndDot.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test</td><td>&nbsp;</td></tr></tbody></table>$'));
+               TypingWWWURLWithEndDot.inA(TableCellWithBrsFirstLine2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.site.com">www.site.com</a>.(\\s|&nbsp;)Test<br />Line 2</td><td>&nbsp;</td></tr></tbody></table>$'));
+               queue.done();
+       });
+
+       asyncTest('Typing a mail address', function() {
+               TypingMailAddr.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="mailto:user@domain.com">user@domain.com</a>(\\s|&nbsp;)Test</p>$'));
+               TypingDashedMailAddr.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="mailto:first-last@domain.com">first-last@domain.com</a>(\\s|&nbsp;)Test</p>$'));
+
+               queue.done();
+       });
+
+       asyncTest('Typing a mail address with protocol', function() {
+               TypingMailAddrWithProtocol.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="mailto:user@domain.com">mailto:user@domain.com</a>(\\s|&nbsp;)Test</p>$'));
+
+               queue.done();
+       });
+} else {
+       test("IE has built in support", function() {
+               ok(true, "Skipped");
+       });
+}
+
+var initTinyFunction = function(){
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               plugins : "autolink",
+               add_unload_trigger : false,
+               webkit_fake_resize: false,
+               theme_advanced_styles : 'test1=test1;test2=test2',
+               valid_styles : {
+                       '*' : 'text-align,padding-left,color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+               },
+               indent : 0,
+               init_instance_callback : function(ed) {
+                       editor = ed;
+               }
+       });
+}
+--></script>
+</head>
+<body>
+       <h1 id="qunit-header">Automatic link tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+       </div>
+       <script src="../js/jsrobot/robot.js"></script>
+       <script>
+               initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/autolink.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsautosavehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/autosave.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/autosave.html                           (rev 0)
+++ trunk/tests/qunit/editor/plugins/autosave.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,104 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for the Autosave plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Autosave plugin", {
+       autostart: false
+});
+
+test("isEmpty true", function() {
+       ok(editor.plugins.autosave.isEmpty(''));
+       ok(editor.plugins.autosave.isEmpty('   '));
+       ok(editor.plugins.autosave.isEmpty('\t\t\t'));
+
+       ok(editor.plugins.autosave.isEmpty('<p id="x"></p>'));
+       ok(editor.plugins.autosave.isEmpty('<p></p>'));
+       ok(editor.plugins.autosave.isEmpty('<p> </p>'));
+       ok(editor.plugins.autosave.isEmpty('<p>\t</p>'));
+
+       ok(editor.plugins.autosave.isEmpty('<p><br></p>'));
+       ok(editor.plugins.autosave.isEmpty('<p><br /></p>'));
+       ok(editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" /></p>'));
+
+       ok(editor.plugins.autosave.isEmpty('<p><br><br></p>'));
+       ok(editor.plugins.autosave.isEmpty('<p><br /><br /></p>'));
+       ok(editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" /><br data-mce-bogus="true" /></p>'));
+});
+
+test("isEmpty false", function() {
+       ok(!editor.plugins.autosave.isEmpty('X'));
+       ok(!editor.plugins.autosave.isEmpty('   X'));
+       ok(!editor.plugins.autosave.isEmpty('\t\t\tX'));
+
+       ok(!editor.plugins.autosave.isEmpty('<p>X</p>'));
+       ok(!editor.plugins.autosave.isEmpty('<p> X</p>'));
+       ok(!editor.plugins.autosave.isEmpty('<p>\tX</p>'));
+
+       ok(!editor.plugins.autosave.isEmpty('<p><br>X</p>'));
+       ok(!editor.plugins.autosave.isEmpty('<p><br />X</p>'));
+       ok(!editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" />X</p>'));
+
+       ok(!editor.plugins.autosave.isEmpty('<p><br><br>X</p>'));
+       ok(!editor.plugins.autosave.isEmpty('<p><br /><br />X</p>'));
+       ok(!editor.plugins.autosave.isEmpty('<p><br data-mce-bogus="true" /><br data-mce-bogus="true" />X</p>'));
+
+       ok(!editor.plugins.autosave.isEmpty('<h1></h1>'));
+       ok(!editor.plugins.autosave.isEmpty('<img src="x" />'));
+});
+
+test("hasDraft/storeDraft/restoreDraft", function() {
+       ok(!editor.plugins.autosave.hasDraft());
+
+       editor.setContent('X');
+       editor.undoManager.add();
+       editor.plugins.autosave.storeDraft();
+
+       ok(editor.plugins.autosave.hasDraft());
+
+       editor.setContent('Y');
+       editor.undoManager.add();
+
+       editor.plugins.autosave.restoreDraft();
+       equal(editor.getContent(), '<p>X</p>');
+});
+
+tinymce.init({
+       selector: "textarea",
+       add_unload_trigger: false,
+       plugins: 'autosave',
+       autosave_ask_before_unload: false,
+       init_instance_callback: function(ed) {
+               editor = ed;
+               editor.plugins.autosave.removeDraft();
+               QUnit.start();
+       }
+});
+</script>
+
+       <h1 id="qunit-header">Unit tests for the Table plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/autosave.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsfullpagehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/fullpage.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/fullpage.html                           (rev 0)
+++ trunk/tests/qunit/editor/plugins/fullpage.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,154 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Fullpage plugin tests</title>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Fullpage plugin", {
+       autostart: false,
+       teardown: function() {
+               editor.getBody().dir = 'ltr';
+       }
+});
+
+function normalizeHTML(html) {
+       return html.replace(/\s/g, '');
+}
+
+function hasLink(href) {
+       var links = editor.getDoc().getElementsByTagName('link');
+
+       for (var i = 0; i < links.length; i++) {
+               if (links[i].href.indexOf('/' + href) != -1) {
+                       return true;
+               }
+       }
+}
+
+test('Keep header/footer intact', function() {
+       expect(2);
+
+       editor.setContent('<html><body><p>Test</p>');
+       equal(normalizeHTML(editor.getContent()), '<html><body><p>Test</p>', 'Invalid HTML content is still editable.');
+
+       editor.setContent('<html><body><p>Test</p></body></html>');
+       equal(normalizeHTML(editor.getContent()), '<html><body><p>Test</p></body></html>', 'Header/footer is intact.');
+});
+
+test('Default header/footer', function() {
+       expect(1);
+
+       editor.setContent('<p>Test</p>');
+       equal(editor.getContent(), '<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body>\n<p>Test</p>\n</body>\n</html>', 'Invalid HTML content is still editable.');
+});
+
+test('Parse body attributes', function() {
+       expect(9);
+
+       editor.setContent('<html><body><p>Test</p></body></html>');
+       equal(editor.getBody().style.color, '', 'No color on body.');
+       equal(editor.getBody().dir, '', 'No dir on body.');
+       equal(editor.dom.getStyle(editor.getBody().firstChild, 'display', true), 'block', 'No styles added to iframe document');
+
+       editor.setContent('<html><body style="color:#FF0000"><p>Test</p></body></html>');
+       ok(editor.getBody().style.color.length > 0, 'Color added to body');
+
+       editor.setContent('<html><body dir="rtl"><p>Test</p></body></html>');
+       equal(editor.getBody().dir, 'rtl', 'Dir added to body');
+
+       editor.setContent('<html><head><style>p {text-align:right}</style></head><body dir="rtl"><p>Test</p></body></html>');
+       equal(editor.dom.getStyle(editor.getBody().firstChild, 'text-align', true), 'right', 'Styles added to iframe document');
+
+       editor.setContent('<html><body><p>Test</p></body></html>');
+       equal(editor.getBody().style.color, '', 'No color on body.');
+       equal(editor.getBody().dir, '', 'No dir on body.');
+       equal(editor.dom.getStyle(editor.getBody().firstChild, 'display', true), 'block', 'No styles added to iframe document');
+});
+
+test('fullpage_hide_in_source_view: false', function() {
+       editor.settings.fullpage_hide_in_source_view = false;
+       editor.setContent('<html><body><p>1</p></body></html>');
+       equal(editor.getContent({source_view: true}), '<html><body>\n<p>1</p>\n</body></html>');
+});
+
+test('fullpage_hide_in_source_view: false', function() {
+       editor.settings.fullpage_hide_in_source_view = true;
+       editor.setContent('<html><body><p>1</p></body></html>');
+       equal(editor.getContent({source_view: true}), '<p>1</p>');
+});
+
+test('fullpage link elements', function() {
+       editor.setContent('<html><head><link rel="stylesheet" href="a.css"><link rel="something"></head><body><p>c</p></body></html>');
+       equal(editor.getContent(), '<html><head><link rel="stylesheet" href="a.css"><link rel="something"></head><body>\n<p>c</p>\n</body></html>');
+});
+
+test('fullpage add/remove stylesheets', function() {
+       editor.setContent('<html><head><link rel="stylesheet" href="a.css"></head><body><p>c</p></body></html>');
+       ok(hasLink("a.css"));
+       ok(!hasLink("b.css"));
+       ok(!hasLink("c.css"));
+
+       editor.setContent('<html><head><link rel="stylesheet" href="a.css"><link rel="stylesheet" href="b.css"></head><body><p>c</p></body></html>');
+       ok(hasLink("a.css"));
+       ok(hasLink("b.css"));
+       ok(!hasLink("c.css"));
+
+       editor.setContent('<html><head><link rel="stylesheet" href="a.css"><link rel="stylesheet" href="b.css"><link rel="stylesheet" href="c.css"></head><body><p>c</p></body></html>');
+       ok(hasLink("a.css"));
+       ok(hasLink("b.css"));
+       ok(hasLink("c.css"));
+
+       editor.setContent('<html><head><link rel="stylesheet" href="a.css"></head><body><p>c</p></body></html>');
+       ok(hasLink("a.css"));
+       ok(!hasLink("b.css"));
+       ok(!hasLink("c.css"));
+
+       editor.setContent('<html><head></head><body><p>c</p></body></html>');
+       ok(!hasLink("a.css"));
+       ok(!hasLink("b.css"));
+       ok(!hasLink("c.css"));
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       plugins : "fullpage",
+       add_unload_trigger : false,
+       valid_styles : {
+               '*' : 'text-align,padding-left,color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+       },
+       indent : 0,
+       setup: function(ed) {
+               ed.on('NodeChange', false);
+       },
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Fullpage plugin tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/fullpage.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsjquery_pluginhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/jquery_plugin.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/jquery_plugin.html                              (rev 0)
+++ trunk/tests/qunit/editor/plugins/jquery_plugin.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,126 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>jQuery Plugin tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="http://www.google.com/jsapi"></script>
+<script>
+       google.load("jquery", "1");
+</script>
+<script src="../../js/tinymce/classes/jquery.tinymce.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("jQuery plugin", {
+       autostart: false
+});
+
+test("Get contents using jQuery", function() {
+       expect(4);
+
+       tinymce.get('elm1').setContent('<p>Editor 1</p>');
+
+       equal($('#elm1').html(), '<p>Editor 1</p>');
+       equal($('#elm1').val(), '<p>Editor 1</p>');
+       equal($('#elm1').attr('value'), '<p>Editor 1</p>');
+       equal($('#elm1').text(), 'Editor 1');
+});
+
+test("Set contents using jQuery", function() {
+       expect(4);
+
+       $('#elm1').html('Test 1');
+       equal($('#elm1').html(), '<p>Test 1</p>');
+
+       $('#elm1').val('Test 2');
+       equal($('#elm1').html(), '<p>Test 2</p>');
+
+       $('#elm1').text('Test 3');
+       equal($('#elm1').html(), '<p>Test 3</p>');
+
+       $('#elm1').attr('value', 'Test 4');
+       equal($('#elm1').html(), '<p>Test 4</p>');
+});
+
+test("append/prepend contents using jQuery", function() {
+       expect(2);
+
+       tinymce.get('elm1').setContent('<p>Editor 1</p>');
+
+       $('#elm1').append('<p>Test 1</p>');
+       equal($('#elm1').html(), '<p>Editor 1</p>\n<p>Test 1</p>');
+
+       $('#elm1').prepend('<p>Test 2</p>');
+       equal($('#elm1').html(), '<p>Test 2</p>\n<p>Editor 1</p>\n<p>Test 1</p>');
+});
+
+test("Find using :tinymce selector", function() {
+       expect(1);
+
+       equal($('textarea:tinymce').length, 2);
+});
+
+test("Set contents using :tinymce selector", function() {
+       expect(3);
+
+       $('textarea:tinymce').val('Test 1');
+       equal($('#elm1').val(), '<p>Test 1</p>');
+       equal($('#elm2').val(), '<p>Test 1</p>');
+       equal($('#elm3').val(), 'Textarea');
+});
+
+test("Get contents using :tinymce selector", function() {
+       expect(1);
+
+       $('textarea:tinymce').val('Test get');
+       equal($('textarea:tinymce').val(), '<p>Test get</p>');
+});
+
+QUnit.stop();
+
+$(function() {
+       $('textarea.tinymce').tinymce({
+               // Location of TinyMCE script
+               script_url : location.search.indexOf('min=true') > 0 ? '../../js/tinymce/tinymce.min.js' : '../../js/tinymce/tinymce.js',
+
+               // General options
+               plugins : "pagebreak,layer,table,save,emoticons,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,template",
+
+               // Theme options
+               theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect",
+               theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
+               theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emoticons,media,advhr,|,print,|,ltr,rtl,|,fullscreen",
+               theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak",
+               theme_advanced_toolbar_location : "top",
+               theme_advanced_toolbar_align : "left",
+               theme_advanced_statusbar_location : "bottom",
+               theme_advanced_resizing : true,
+
+               init_instance_callback : function(ed) {
+                       var ed1 = tinymce.get('elm1'), ed2 = tinymce.get('elm2');
+
+                       // When both editors are initialized
+                       if (ed1 && ed1.initialized && ed2 && ed2.initialized)
+                               QUnit.start();
+               }
+       });
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">TinyMCE jQuery plugin tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1" class="tinymce">Editor 1</textarea>
+               <textarea id="elm2" name="elm2" class="tinymce">Editor 2</textarea>
+               <textarea id="elm3" name="elm3">Textarea</textarea>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/jquery_plugin.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsjsautolinkactionsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/js/autolink.actions.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/js/autolink.actions.js                          (rev 0)
+++ trunk/tests/qunit/editor/plugins/js/autolink.actions.js     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+function fakeTypeAURL(url) {
+       return function(callback) {
+        // type the URL and then press the space bar
+        tinymce.execCommand('mceInsertContent', false, url);
+        window.robot.type(32, false, callback, editor.selection.getNode());
+    };
+}
+
+function fakeTypeAnEclipsedURL(url) {
+       return function(callback) {
+        // type the URL and then type ')'
+        tinymce.execCommand('mceInsertContent', false, '(' + url);
+               window.robot.typeSymbol(")", function() {
+            window.robot.type(32, false, callback, editor.selection.getNode());
+        }, editor.selection.getNode());
+    };
+}
+
+function fakeTypeANewlineURL(url) {
+       return function(callback) {
+        // type the URL and then press the enter key
+        tinymce.execCommand('mceInsertContent', false, url);
+        window.robot.type('\n', false, callback, editor.selection.getNode());
+    };
+}
+
+createAction('Typing HTTP URL', fakeTypeAURL('http://www.ephox.com'));
+createAction('Typing HTTPS URL', fakeTypeAURL('https://www.ephox.com'));
+createAction('Typing SSH URL', fakeTypeAURL('ssh://www.ephox.com'));
+createAction('Typing FTP URL', fakeTypeAURL('ftp://www.ephox.com'));
+createAction('Typing WWW URL', fakeTypeAURL('www.ephox.com'));
+createAction('Typing WWW URL With End Dot', fakeTypeAURL('www.site.com.'));
+createAction('Typing Mail Addr', fakeTypeAURL('user@domain.com'));
+createAction('Typing Mail Addr With Protocol', fakeTypeAURL('mailto:user@domain.com'));
+createAction('Typing Dashed Mail Addr', fakeTypeAURL('first-last@domain.com'));
+createAction('Typing Eclipsed HTTP URL', fakeTypeAnEclipsedURL('http://www.ephox.com'));
+createAction('Typing Eclipsed HTTPS URL', fakeTypeAnEclipsedURL('https://www.ephox.com'));
+createAction('Typing Eclipsed SSH URL', fakeTypeAnEclipsedURL('ssh://www.ephox.com'));
+createAction('Typing Eclipsed FTP URL', fakeTypeAnEclipsedURL('ftp://www.ephox.com'));
+createAction('Typing Eclipsed WWW URL', fakeTypeAnEclipsedURL('www.ephox.com'));
+createAction('Typing HTTP URL And Newline', fakeTypeANewlineURL('http://www.ephox.com'));
+createAction('Typing HTTPS URL And Newline', fakeTypeANewlineURL('https://www.ephox.com'));
+createAction('Typing SSH URL And Newline', fakeTypeANewlineURL('ssh://www.ephox.com'));
+createAction('Typing FTP URL And Newline', fakeTypeANewlineURL('ftp://www.ephox.com'));
+createAction('Typing WWW URL And Newline', fakeTypeANewlineURL('www.ephox.com'));
+createAction('Applying OL', 'InsertOrderedList');
+createAction('Applying UL', 'InsertUnorderedList');
+createAction('Indenting', 'Indent');
+createAction('Outdenting', 'Outdent');
+createAction('Typing Enter', fakeKeyPressAction('\n'));
+createAction('Typing Tab', fakeKeyPressAction('\t'));
+createAction('Typing Shift Tab', fakeKeyPressAction('\t', true));
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/js/autolink.actions.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsjsdsljs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/js/dsl.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/js/dsl.js                               (rev 0)
+++ trunk/tests/qunit/editor/plugins/js/dsl.js  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+var editor;
+
+function getFunctionName(func) {
+       if (func.name && func.name != "") {
+               return func.name;
+       } else if (typeof func == "function" || typeof func == "object") {
+               var fName = ("" + func).match(/function\s*([\w\$]+)\s*\(/);
+               if (fName !== null && fName != "") {
+                       return fName[1];
+               } else {
+                       for (var v in window) {
+                               if (window[v] === func) {
+                                       func.name = v;
+                                       return v;
+                               }
+                       }
+               }
+       }
+}
+
+function assertState(expected, message) {
+       var content = editor.getContent().replace(/[\n\r]/g, '');
+       if (expected && expected.replace) expected = expected.replace(/[\n\r]/g, '');
+    // Safari reports "function", while Firefox and IE report "object"
+    if (typeof expected == "function" || typeof expected == "object") {
+        if (expected.test(content))
+            equal(content, content, message);
+        else 
+            equal(content, expected.toString(), message);
+    } else {
+        equal(content, expected, message);
+    }
+}
+
+tinymce.create('dsl.Queue', {
+       Queue: function() {
+               this.queue = [];
+       },
+       
+       add: function(task) {
+               this.queue.push(task);
+       },
+       
+       next: function() {
+               if (this.queue.length > 0) {
+                       var task = this.queue.shift();
+                       task();
+                       return true;
+               } else {
+                       QUnit.start();
+                       return false;
+               }
+       },
+       
+       done: function() {
+               expect(this.queue.length);
+               this.next();
+       }
+});
+
+tinymce.create('dsl.Action', {
+       Action: function(name, action) {
+               this.name = name;
+               this.a = this.curryPreposition('a');
+               this.inA = this.curryPreposition('in a');
+               this.to = this.curryPreposition('to');
+               if (tinymce.is(action, 'string')) {
+                       this.action = function(callback) {
+                               editor.execCommand(action);
+                               callback();
+                       };
+               } else {
+                       this.action = action;
+               }
+       },
+       
+       curryPreposition: function(preposition) {
+               return function(state) {
+                       return this.go(state, preposition);
+               };
+       },
+       
+       go: function(state, preposition) {
+               var message = this.name + " " + preposition + " " + getFunctionName(state);
+               var action = this.action;
+               var actionPerformed = false;
+               function defer(callback) {
+                       return function() {
+                               var args = arguments;
+                               queue.add(function() {
+                                       if (actionPerformed) {
+                                               callback.apply(undefined, args);
+                                               queue.next();
+                                               return;
+                                       }
+                                       editor.focus();
+                                       state();
+                                       action(function() {
+                                               actionPerformed = true;
+                                               callback.apply(undefined, args);
+                                               queue.next();
+                                       });
+                               });
+                               return this;
+                       };
+               }
+               
+               var dslState = {
+                       gives: defer(function(expected) {
+                               assertState(expected, message);
+                       }),
+
+                       enablesState: defer(function(state) {
+                               ok(editor.queryCommandState(state), message + " enables " + state + " command");
+                       }),
+                       
+                       disablesState: defer(function(state) {
+                               ok(!editor.queryCommandState(state), message + " disables " + state + " command");
+                       })
+               };
+               dslState.andGives = dslState.gives;
+               return dslState;
+       }
+});
+
+
+// Action Utilities
+function fakeKeyPressAction(keyCode, shiftKey) {
+       return function(callback) {
+               setTimeout(function() {
+                       window.robot.type(keyCode, shiftKey, callback, editor.selection.getNode());
+               }, 1);
+       };
+}
+
+function createAction(name, action) {
+       window[name.replace(/\s+/g, '')] = new dsl.Action(name, action);
+}
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/js/dsl.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsjsstatesjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/js/states.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/js/states.js                            (rev 0)
+++ trunk/tests/qunit/editor/plugins/js/states.js       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,176 @@
</span><ins>+function createState(content, startSelector, startOffset, endSelector, endOffset) {
+       return function() {
+               editor.setContent(content);
+               setSelection(startSelector, startOffset, endSelector, endOffset);
+       };
+}
+
+/** Collapsed Selection States **/
+function EmptyParagraph() {
+       var body = editor.getBody();
+       while (body.firstChild) {
+               editor.dom.remove(body.firstChild);
+       }
+       var p = body.ownerDocument.createElement('p');
+       p.appendChild(body.ownerDocument.createTextNode(''));
+       body.appendChild(p, body);
+       setSelection(p.firstChild, 0);
+}
+
+function EmptyHeading() {
+       EmptyParagraph();
+       editor.dom.rename(editor.getBody().firstChild, 'h1');
+       setSelection(editor.getBody().firstChild.firstChild, 0);
+}
+
+function TextAfterUL() {
+       editor.setContent('<ul><li>Item</li></ul>Test');
+       setSelection(editor.dom.getRoot().lastChild, 2);
+}
+
+function TextAfterOL() {
+       editor.setContent('<ol><li>Item</li></ol>Test');
+       setSelection(editor.dom.getRoot().lastChild, 2);
+}
+
+EmptyContent = createState('', 'body', 0);
+PlainText = createState('Test', 'body', 0);
+NonEmptyParagraph = createState('<p>Test</p>', 'p', 0);
+ParagraphWithMarginLeft = createState('<p style="margin-left: 60px;">Test</p>', 'p', 0);
+ParagraphWithPaddingLeft = createState('<p style="padding-left: 60px;">Test</p>', 'p', 0);
+ParagraphWithMarginAndPaddingLeft = createState('<p style="margin-left: 60px; padding-left: 60px;">Test</p>', 'p', 0);
+
+CenteredListItem = createState('<ul><li style="text-align: center;">Item1</li><li>Item2</li></ul>', 'li:nth-child(1)', 2);
+ItemInCenteredList = createState('<ul style="text-align: center;"><li>Item1</li><li>Item2</li></ul>', 'li:nth-child(1)', 2);
+RightAlignedListItem = createState('<ul><li style="text-align: right;">Item1</li><li>Item2</li></ul>', 'li:nth-child(1)', 2);
+ItemInRightAlignedList = createState('<ul style="text-align: right;"><li>Item1</li><li>Item2</li></ul>', 'li:nth-child(1)', 2);
+
+ParagraphBetweenOrderedLists = createState('<ol><li>Item1</li></ol><p>Test</p><ol><li>Item2</li></ol>', 'p', 2);
+ParagraphBetweenUnorderedLists = createState('<ul><li>Item1</li></ul><p>Test</p><ul><li>Item2</li></ul>', 'p', 2);
+ParagraphBetweenMixedLists = createState('<ol><li>Item1</li></ol><p>Test</p><ul><li>Item2</li></ul>', 'p', 2);
+
+NonEmptyHeading = createState('<h1>Test</h1>', 'h1', 0);
+TableCellWithoutBrs = createState('<table><tbody><tr><td>Test</td><td>&nbsp;</td></tr></tbody></table>', 'td', 4);
+TableCellWithoutBrs2 = createState('<table><tbody><tr><td>Test</td><td>&nbsp;</td></tr></tbody></table>', 'td', 0);
+TableCellWithBrsFirstLine = createState('<table><tbody><tr><td>Test<br>Line 2</td><td>&nbsp;</td></tr></tbody></table>', 'td', 1);
+TableCellWithBrsFirstLine2 = createState('<table><tbody><tr><td>Test<br>Line 2</td><td>&nbsp;</td></tr></tbody></table>', 'td', 0);
+TableCellWithBrsMiddleLine = createState('<table><tbody><tr><td>Test<br/>Line 2<br/>Line 3</td><td>&nbsp;</td></tr></tbody></table>', 'td br:nth-child(1)', 'afterNextCharacter');
+TableCellWithBrsLastLine = createState('<table><tbody><tr><td>Test<br>Line 2</td><td>&nbsp;</td></tr></tbody></table>', 'td br:nth-child(1)', 'afterNextCharacter');
+TableCellWithAdjacentBrsFirstLine = createState('<table><tbody><tr><td>Test<br><br>Line 2</td><td>&nbsp;</td></tr></tbody></table>', 'td', 1);
+
+HeadingInOrderedList = createState('<ol><li><h2>Test</h2></li></ol>', 'h2', '2');
+HeadingInUnorderedList = createState('<ul><li><h2>Test</h2></li></ul>', 'h2', '2');
+HeadingInOrderedListBeforeParagraph = createState('<ol><li><h2>Test</h2></li></ol><p>Content<br />After</p>', 'h2', '2');
+
+DefinitionListDescription = createState('<dl><dt>Term</dt><dd>Description</dd></dl>', 'dd', 2);
+DefinitionListTerm = createState('<dl><dt>Term</dt><dd>Description</dd></dl>', 'dt', 2);
+EndOfParagraphBeforeOL = createState('<p>Test</p><ol><li>Item</li></ol>', 'p', 4);
+EndOfParagraphBeforeOLWithListType = createState('<p>Test</p><ol style="list-style-type: lower-alpha;"><li>Item</li></ol>', 'p', 4);
+EndOfParagraphBeforeUL = createState('<p>Test</p><ul><li>Item</li></ul>', 'p', 4);
+StartOfParagraphAfterOL = createState('<ol><li>Item</li></ol><p>Test</p>', 'p', 1);
+StartOfParagraphAfterUL = createState('<ul><li>Item</li></ul><p>Test</p>', 'p', 1);
+StartOfParagraphAfterOLWithListType = createState('<ol style="list-style-type: lower-alpha;"><li>Item</li></ol><p>Test</p>', 'p', 1);
+EmptyOrderedListItem = createState('<ol><li>Before</li><li>&nbsp;</li><li>After</li></ol>', 'li:nth-child(2)', 0);
+EmptyUnorderedListItem = createState('<ul><li>Before</li><li>&nbsp;</li><li>After</li></ul>', 'li:nth-child(2)', 0);
+NonEmptyOrderedListItem = createState('<ol><li>Before</li><li>Test</li><li>After</li></ol>', 'li:nth-child(2)', 0);
+NonEmptyUnorderedListItem = createState('<ul><li>Before</li><li>Test</li><li>After</li></ul>', 'li:nth-child(2)', 0);
+NestedEmptyOrderedListItem = createState('<ol><li>Before<ol><li>&nbsp;</li></ol></li><li>After</li></ol>', 'li ol li', 0);
+NestedEmptyUnorderedListItem = createState('<ul><li>Before<ul><li>&nbsp;</li></ul></li><li>After</li></ul>', 'li ul li', 0);
+NestedNonEmptyOrderedListItem = createState('<ol><li>Before<ol><li>Test</li></ol></li><li>After</li></ol>', 'li ol li', 0);
+NestedNonEmptyUnorderedListItem = createState('<ul><li>Before<ul><li>Test</li></ul></li><li>After</li></ul>', 'li ul li', 0);
+NestedOrderedListWithMultipleItems = createState('<ol><li>Before<ol><li>Item1</li><li>Item2</li></ol></li></ol>', 'li ol li', 0);
+NestedUnorderedListWithMultipleItems = createState('<ul><li>Before<ul><li>Item1</li><li>Item2</li></ul></li></ul>', 'li ul li', 0);
+OrderedLowerAlphaListItem = createState('<ol style="list-style-type: lower-alpha;"><li>Item 1</li><li>Item 2</li></ol>', 'li:nth-child(2)', 0);
+UnorderedSquareListItem = createState('<ul style="list-style-type: square;"><li>Item 1</li><li>Item 2</li></ul>', 'li:nth-child(2)', 0);
+
+OrderedListItemWithNestedChild = createState('<ol><li>Item1<ol><li>Nested</li></ol></li></ol>', 'li:nth-child(1)', 2);
+UnorderedListItemWithNestedChild = createState('<ul><li>Item1<ul><li>Nested</li></ul></li></ul>', 'li:nth-child(1)', 2);
+
+OrderedListWithAdjacentNestedLists = createState('<ol><li style="list-style-type: none;"><ol><li>Item 1</li></ol></li><li>Item 2</li><li style="list-style-type: none;"><ol><li>Item 3</li></ol></li></ol>', 'li:nth-child(2)', 4);
+UnorderedListWithAdjacentNestedLists = createState('<ul><li style="list-style-type: none;"><ul><li>Item 1</li></ul></li><li>Item 2</li><li style="list-style-type: none;"><ul><li>Item 3</li></ul></li></ul>', 'li:nth-child(2)', 4);
+
+OrderedListItemWithMargin = createState('<ol><li style="margin-left: 60px;">Test</li></ol>', 'li', 0);
+UnorderedListItemWithMargin = createState('<ul><li style="margin-left: 60px;">Test</li></ul>', 'li', 0);
+
+OrderedListItemWithNestedAlphaList = createState('<ol><li>Item<ol style="list-style-type: lower-alpha;"><li>Nested</li></ol></li></ol>', 'li', 2);
+
+/** Collapsed DIV Tests **/
+OrderedListItemInsideDiv = createState('<div id="div"><ol>\n<li>Item1</li><li>Item2</li></ol></div>', 'li:nth-child(1)', 2);
+UnorderedListItemInsideDiv = createState('<div id="div"><ul>\n<li>Item1</li><li>Item2</li></ul></div>', 'li:nth-child(1)', 2);
+
+ParagraphInDiv = createState('<div><p>Item</p></div>', 'p', 2);
+TextInDiv = createState('<div>Item</div>', 'div', 2);
+TextWithBrsInDivFirstLine = createState('<div>Item1<br />Item2</div>', 'div', 2);
+TextWithBrsInDivMiddleLine = createState('<div>Item1<br />Item2<br />Item3</div>', 'br:nth-child(1)', 'afterNextCharacter');
+TextWithBrsInDivLastLine = createState('<div>Item1<br />Item2</div>', 'br:nth-child(1)', 'afterNextCharacter');
+TextWithBrsInFormattingInDiv = function() {
+       var rng;
+       editor.setContent('<div><strong>Before<br /></strong>Item1<br />Item2<br />Item3</div>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('div')[0].childNodes[1], 0);
+       rng.setEnd(editor.dom.select('div')[0], 6);
+       editor.selection.setRng(rng);
+};
+TextWithBrInsideFormatting = function() {
+       var rng;
+       editor.setContent('<div><em><strong>Before<br /><span class="foo">Item1</span></strong></em>Item2<br />Item3</div>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].childNodes[0], 2);
+       rng.setEnd(editor.dom.select('div')[0], 4);
+       editor.selection.setRng(rng);
+};
+
+/** Expanded Selection States **/
+SingleParagraphSelection = createState('<p>This is a test</p>', 'p', 5, 'p', 7);
+MultipleParagraphSelection = createState('<p>This is a test</p><p>Second paragraph</p>', 'p:nth-child(1)', 5, 'p:nth-child(2)', 6);
+SingleHeadingSelection = createState('<h1>This is a test</h1>', 'h1', 5, 'h1', 7);
+MultipleHeadingSelection = createState('<h1>This is a test</h1><h1>Second paragraph</h1>', 'h1:nth-child(1)', 5, 'h1:nth-child(2)', 6);
+SingleBlockSelection = createState('<div>This is a test</div>', 'div', 5, 'div', 7);
+MultipleBlockSelection = createState('<div>This is a test</div><div>Second paragraph</div>', 'div:nth-child(1)', 5, 'div:nth-child(2)', 6);
+
+SingleBlockWithBrSelection = createState('<div>Item1<br />Item2</div>', 'div', 3, 'br', 'afterNextCharacter');
+MultipleBlockWithBrSelection = createState('<div>Item1<br />Item2</div><div>Item3</div>', 'div:nth-child(1)', 2, 'div:nth-child(2)', 3);
+MultipleBlockWithBrPartialSelection = createState('<div>Item1<br />Item2</div><div>Item3<br />Item4</div>', 'div:nth-child(1)', 2, 'div:nth-child(2)', 3);
+MultipleBlockWithBrPartialSelectionAtEnd = createState('<div>Item1<br />Item2</div><div>Item3<br />Item4</div>', 'div:nth-child(1) br', 'afterNextCharacter', 'div:nth-child(2) br', 'afterNextCharacter');
+MultipleBlockWithEmptyDivsAllSelected = createState('<div id="start">&nbsp;</div><div>a</div><div></div><div>b</div><div></div><div id="end">&nbsp;</div>', '#start', 0, '#end', 0);
+
+CellWithoutBrSelection = createState('<table><tbody><tr><td>Cell 1</td></tr></tbody></table>', 'td', 1, 'td', 1); //selection is a single point so it will avoid table selection bugs in ie9.
+CellWithBrSingleLineSelection = createState('<table><tbody><tr><td>Cell 1<br>Line 2</td></tr></tbody></table>', 'td', 1, 'td', 4);
+CellWithBrMultipleLineSelection = createState('<table><tbody><tr><td>Cell 1<br>Line 2</td></tr></tbody></table>', 'td', 1, 'td', 4);
+
+TableCellWithTextAfterUL = createState('<table><tbody><tr><td><ul><li>Existing</li></ul><span id="start">Line1</span><br />Line2<br id="end" />Line3<br />Line4</td></tr></tbody></table>', '#start', 1, '#end', 'afterNextCharacter');
+
+ParagraphToHeadingSelection = createState('<p>This is a test</p><h1>Second paragraph</h1>', 'p', 5, 'h1', 6);
+ParagraphToBlockSelection = createState('<p>This is a test</p><div>Second paragraph</div>', 'p', 5, 'div', 6);
+HeadingToParagraphSelection = createState('<h1>This is a test</h1><p>Second paragraph</p>', 'h1', 5, 'p', 6);
+BlockToParagraphSelection = createState('<div>This is a test</div><p>Second paragraph</p>', 'div', 5, 'p', 6);
+MultipleParagraphAndHeadingSelection = createState('<p>This is a test</p><h1>Second paragraph</h1><div>Third paragraph</div>', 'p', 5, 'div', 5);
+ThreeBoldDivsWithBrSelection = createState('<div><strong>One</strong></div><div><strong>Two</strong></div><div><strong>Three<br></strong></div>', 'div:nth-child(1) strong', 2, 'div:nth-child(3) strong', 2);
+
+SingleLiOlSelection = createState('<ol><li>Item 1</li></ol>', 'li', 1, 'li', 4);
+MultiLiOlSelection = createState('<ol><li>Item 1</li><li>Item 2</li></ol>', 'li:nth-child(1)', 1, 'li:nth-child(2)', 4);
+SingleLiUlSelection = createState('<ul><li>Item 1</li></ul>', 'li', 1, 'li', 4);
+MultiLiUlSelection = createState('<ul><li>Item 1</li><li>Item 2</li></ul>', 'li:nth-child(1)', 1, 'li:nth-child(2)', 4);
+MultiNestedLiUlSelection = createState('<ul><li style="list-style-type: none;"><ul><li>Item 1</li><li>Item 2</li></ul></li></ul>', 'li li:nth-child(1)', 1, 'li li:nth-child(2)', 4);
+MultiNestedLiOlSelection = createState('<ol><li style="list-style-type: none;"><ol><li>Item 1</li><li>Item 2</li></ol></li></ol>', 'li li:nth-child(1)', 1, 'li li:nth-child(2)', 4);
+
+IndentedOlInOlCorrectSelection = createState('<ol><li>Item 1<ol><li>Indented</li></ol></li></ol>', 'li', 1, 'li li', 4);
+IndentedUlInUlCorrectSelection = createState('<ul><li>Item 1<ul><li>Indented</li></ul></li></ul>', 'li', 1, 'li li', 4);
+IndentedOlInOlIncorrectSelection = createState('<ol><li>Item 1</li><ol><li>Indented</li></ol></ol>', 'li', 1, 'ol ol li', 4);
+IndentedUlInUlIncorrectSelection = createState('<ul><li>Item 1</li><ul><li>Indented</li></ul></ul>', 'li', 1, 'ul ul li', 4);
+
+IndentedOlInUlCorrectSelection = createState('<ul><li>Item 1<ol><li>Indented</li></ol></li></ul>', 'li', 1, 'li li', 4);
+IndentedUlInOlCorrectSelection = createState('<ol><li>Item 1<ul><li>Indented</li></ul></li></ol>', 'li', 1, 'li li', 4);
+IndentedOlInUlIncorrectSelection = createState('<ul><li>Item 1</li><ol><li>Indented</li></ol></ul>', 'li', 1, 'ul ol li', 4);
+IndentedUlInOlIncorrectSelection = createState('<ol><li>Item 1</li><ul><li>Indented</li></ul></ol>', 'li', 1, 'ol ul li', 4);
+
+// TODO: Paragraph/heading to list combinations.
+ParagraphBeforeOlSelection = createState('<p>Before</p><ol><li>Item 1</li></ol>', 'p', 3, 'li', 4);
+ParagraphBeforeUlSelection = createState('<p>Before</p><ul><li>Item 1</li></ul>', 'p', 3, 'li', 4);
+ParagraphAfterOlSelection = createState('<ol><li>Item 1</li></ol><p>After</p>', 'li', 4, 'p', 3);
+ParagraphAfterUlSelection = createState('<ul><li>Item 1</li></ul><p>After</p>', 'li', 4, 'p', 3);
+ParagraphBeforeAndAfterOlSelection = createState('<p>Before</p><ol><li>Item 1</li></ol><p id="after">After</p>', 'p', 4, '#after', 3);
+ParagraphBeforeAndAfterUlSelection = createState('<p>Before</p><ul><li>Item 1</li></ul><p id="after">After</p>', 'p', 4, '#after', 3);
+
+SelectionEndingAtBr = createState('<p>Item<br>After</p>', 'p', 2, 'br', 'after');
+SelectionStartingAtBr = createState('<p>Before<br>Item</p>', 'p', 'after', 'br', 'afterNextCharacter');
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/js/states.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginslegacyoutputhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/legacyoutput.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/legacyoutput.html                               (rev 0)
+++ trunk/tests/qunit/editor/plugins/legacyoutput.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,130 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for Media Plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script src="../js/utils.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Legacyoutput plugin", {
+       autostart: false
+});
+
+test("Font color", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('forecolor', false, '#FF0000');
+       equal(editor.getContent().toLowerCase(), '<p><font color="#ff0000">text</font></p>');
+});
+
+test("Font size", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('fontsize', false, 7);
+       equal(editor.getContent(), '<p><font size="7">text</font></p>');
+});
+
+test("Font face", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('fontname', false, "times");
+       equal(editor.getContent(), '<p><font face="times">text</font></p>');
+});
+
+test("Bold", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('bold');
+       equal(editor.getContent(), '<p><b>text</b></p>');
+});
+
+test("Italic", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('italic');
+       equal(editor.getContent(), '<p><i>text</i></p>');
+});
+
+test("Underline", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('underline');
+       equal(editor.getContent(), '<p><u>text</u></p>');
+});
+
+test("Strikethrough", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('strikethrough');
+       equal(editor.getContent(), '<p><strike>text</strike></p>');
+});
+
+test("Justifyleft", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('justifyleft');
+       equal(editor.getContent(), '<p align="left">text</p>');
+});
+
+test("Justifycenter", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('justifycenter');
+       equal(editor.getContent(), '<p align="center">text</p>');
+});
+
+test("Justifyright", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('justifyright');
+       equal(editor.getContent(), '<p align="right">text</p>');
+});
+
+test("Justifyfull", function() {
+       editor.setContent('<p>text</p>');
+       setSelection('p', 0, 'p', 4);
+       editor.execCommand('justifyfull');
+       equal(editor.getContent(), '<p align="justify">text</p>');
+});
+
+function initTiny(settings, load) {
+       var default_settings = {
+               mode : "exact",
+               elements : "elm1",
+               add_unload_trigger : false,
+               document_base_url : '/tinymce/tinymce/trunk/tests/',
+               plugins : 'legacyoutput',
+               init_instance_callback : function(ed) {
+                       editor = ed;
+                       load();
+               }
+       };
+       var settings = tinymce.extend(default_settings, settings);
+       tinymce.init(settings);
+}
+
+initTiny({}, QUnit.start);
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for Legacyoutput Plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/legacyoutput.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginslistshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/lists.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/lists.html                              (rev 0)
+++ trunk/tests/qunit/editor/plugins/lists.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,1770 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for lists plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor, inlineEditor, rng;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.Lists", {
+       autostart: false,
+       setup: function() {
+               editor.settings.forced_root_block = 'p';
+       }
+});
+
+function trimBrs(html) {
+       return html.toLowerCase().replace(/<br[^>]*>|[\r\n]+/gi, '');
+}
+
+function execCommand(cmd) {
+       // Make sure we execute custom execCommands not browser commands
+       var cmdItem = editor.execCommands[cmd];
+       return cmdItem.func.call(cmdItem.scope, false, null);
+}
+
+test('Apply UL list to single P', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<p>a</p>'
+       );
+
+       editor.focus();
+       setSelection('p', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), '<ul><li>a</li></ul>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Apply UL list to single empty P', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<p><br></p>'
+       );
+
+       editor.focus();
+       setSelection('p', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(trimBrs(editor.getContent({format: 'raw'})), '<ul><li></li></ul>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Apply UL list to multiple Ps', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<p>a</p>' +
+               '<p>b</p>' +
+               '<p>c</p>'
+       );
+
+       editor.focus();
+       setSelection('p', 0, 'p:last', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply OL list to single P', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<p>a</p>'
+       );
+
+       editor.focus();
+       setSelection('p', 0);
+       execCommand('InsertOrderedList');
+
+       equal(editor.getContent(), '<ol><li>a</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Apply OL list to single empty P', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<p><br></p>'
+       );
+
+       editor.focus();
+       setSelection('p', 0);
+       execCommand('InsertOrderedList');
+
+       equal(trimBrs(editor.getContent({format: 'raw'})), '<ol><li></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Apply OL list to multiple Ps', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<p>a</p>' +
+               '<p>b</p>' +
+               '<p>c</p>'
+       );
+
+       editor.focus();
+       setSelection('p', 0, 'p:last', 0);
+       execCommand('InsertOrderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply OL to UL list', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 0, 'li:last', 0);
+       execCommand('InsertOrderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply OL to UL list with collapsed selection', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)');
+       execCommand('InsertOrderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL to OL list', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li', 0, 'li:last', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL to OL list collapsed selection', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL to P and merge with adjacent lists', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>' +
+               '<p>b</p>' +
+               '<ul>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('p', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL to OL and merge with adjacent lists', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>' +
+               '<ol><li>b</li></ol>' +
+               '<ul>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('ol li', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply OL to P and merge with adjacent lists', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+               '</ol>' +
+               '<p>b</p>' +
+               '<ol>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('p', 1);
+       execCommand('InsertOrderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply OL to UL and merge with adjacent lists', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+               '</ol>' +
+               '<ul><li>b</li></ul>' +
+               '<ol>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ul li', 1);
+       execCommand('InsertOrderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL list to single text line', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               'a'
+       );
+
+       editor.focus();
+       setSelection('body', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), '<ul><li>a</li></ul>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Apply UL list to single text line with BR', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               'a<br>'
+       );
+
+       editor.focus();
+       setSelection('body', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), '<ul><li>a</li></ul>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Apply UL list to multiple lines separated by BR', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               'a<br>' +
+               'b<br>' +
+               'c'
+       );
+
+       editor.focus();
+       editor.execCommand('SelectAll');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL list to multiple lines separated by BR and with trailing BR', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               'a<br>' +
+               'b<br>' +
+               'c<br>'
+       );
+
+       editor.focus();
+       editor.execCommand('SelectAll');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'LI');
+});
+
+test('Apply UL list to multiple formatted lines separated by BR', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               '<strong>a</strong><br>' +
+               '<span>b</span><br>' +
+               '<em>c</em>'
+       );
+
+       editor.focus();
+       setSelection('strong', 0, 'em', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li><strong>a</strong></li>' +
+                       '<li><span>b</span></li>' +
+                       '<li><em>c</em></li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getStart().nodeName, 'STRONG');
+       equal(editor.selection.getEnd().nodeName, tinymce.Env.ie && tinymce.Env.ie < 9 ? 'LI' : 'EM'); // Old IE will return the end LI not a big deal
+});
+
+test('Apply UL list to br line and text block line', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.setContent(
+               'a' +
+               '<p>b</p>'
+       );
+
+       var rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 1);
+       editor.selection.setRng(rng);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getStart().nodeName, 'LI');
+       equal(editor.selection.getEnd().nodeName, 'LI');
+});
+
+test('Apply UL list to text block line and br line', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               '<p>a</p>' +
+               'b'
+       );
+
+       editor.focus();
+       var rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().lastChild, 1);
+       editor.selection.setRng(rng);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getStart().nodeName, 'LI');
+       equal(editor.selection.getEnd().nodeName, 'LI');
+});
+
+test('Apply UL list to all BR lines (SelectAll)', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = (
+               'a<br>' +
+               'b<br>' +
+               'c<br>'
+       );
+
+       editor.focus();
+       editor.execCommand('SelectAll');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+});
+
+test('Apply UL list to all P lines (SelectAll)', function() {
+       editor.getBody().innerHTML = (
+               '<p>a</p>' +
+               '<p>b</p>' +
+               '<p>c</p>'
+       );
+
+       editor.focus();
+       editor.execCommand('SelectAll');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+});
+
+// Remove
+
+test('Remove UL at single LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<p>a</p>'
+       );
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove UL at start LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<p>a</p>' +
+               '<ul>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove UL at start empty LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li><br></li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li');
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<p>\u00a0</p>' +
+               '<ul>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Remove UL at middle LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>' +
+               '<p>b</p>' +
+               '<ul>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove UL at middle empty LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li><br></li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>' +
+               '<p>\u00a0</p>' +
+               '<ul>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Remove UL at end LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:last', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>' +
+               '<p>c</p>'
+       );
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove UL at end empty LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li><br></li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:last', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>' +
+               '<p>\u00a0</p>'
+       );
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Remove UL at middle LI inside parent OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ul>' +
+                               '<li>b</li>' +
+                               '<li>c</li>' +
+                               '<li>d</li>' +
+                       '</ul>' +
+                       '<li>e</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ul li:nth-child(2)', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ul>' +
+                               '<li>b</li>' +
+                       '</ul>' +
+               '</ol>' +
+               '<p>c</p>' +
+               '<ol>' +
+                       '<ul>' +
+                               '<li>d</li>' +
+                       '</ul>' +
+                       '<li>e</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove UL at middle LI inside parent OL (html5)', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+                       '<li>e</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ul li:nth-child(2)', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ol>' +
+               '<p>c</p>' +
+               '<ol>' +
+                       '<li>' +
+                               '<ul>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+                       '<li>e</li>' +
+               '</ol>'
+       );
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove UL with single LI in BR mode', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               'a'
+       );
+       equal(editor.selection.getStart().nodeName, 'BODY');
+});
+
+test('Remove UL with multiple LI in BR mode', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:first', 1, 'li:last', 1);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               'a<br />' +
+               'b'
+       );
+       equal(editor.selection.getStart().nodeName, 'BODY');
+});
+
+test('Remove empty UL between two textblocks', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<div>a</div>' +
+               '<ul>' +
+                       '<li></li>' +
+               '</ul>' +
+               '<div>b</div>'
+       );
+
+       editor.focus();
+       setSelection('li:first', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<div>a</div>' +
+               '<p>\u00a0</p>' +
+               '<div>b</div>'
+       );
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Remove empty UL between two textblocks in BR mode', function() {
+       editor.settings.forced_root_block = false;
+
+       editor.getBody().innerHTML = trimBrs(
+               '<div>a</div>' +
+               '<ul>' +
+                       '<li></li>' +
+               '</ul>' +
+               '<div>b</div>'
+       );
+
+       editor.focus();
+       setSelection('li:first', 0);
+       execCommand('InsertUnorderedList');
+
+       equal(editor.getContent(), 
+               '<div>a</div>' +
+               '<br />' +
+               '<div>b</div>'
+       );
+       equal(editor.selection.getStart().nodeName, 'BR');
+});
+
+// Outdent
+
+test('Outdent inside LI in beginning of OL in LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li li', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b' +
+                               '<ol>' +
+                                       '<li>c</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent inside LI in middle of OL in LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                                       '<li>d</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li li:nth-child(2)', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+                       '<li>c' +
+                               '<ol>' +
+                                       '<li>d</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent inside LI in end of OL in LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li li:last', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+// Nested lists in OL elements
+
+test('Outdent inside LI in beginning of OL in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>b</li>' +
+                               '<li>c</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ol ol li', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<ol>' +
+                               '<li>c</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent inside LI in middle of OL in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>b</li>' +
+                               '<li>c</li>' +
+                               '<li>d</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ol ol li:nth-child(2)', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>b</li>' +
+                       '</ol>' +
+                       '<li>c</li>' +
+                       '<ol>' +
+                               '<li>d</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent inside first/last LI in inner OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>1' +
+                       '<ol>' +
+                               '<li>2</li>' +
+                               '<li>3</li>' +
+                       '</ol>' +
+                       '</li>' +
+                       '<li>4</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ol ol li:nth-child(1)', 0, 'ol ol li:nth-child(2)', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>1</li>' +
+                       '<li>2</li>' +
+                       '<li>3</li>' +
+                       '<li>4</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getRng(true).startContainer.nodeValue, '2');
+       equal(editor.selection.getRng(true).endContainer.nodeValue, '3');
+});
+
+test('Outdent inside first LI in inner OL where OL is single child of parent LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ol ol li:first', 0);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b' +
+                               '<ol>' +
+                                       '<li>c</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent inside LI in end of OL in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>b</li>' +
+                               '<li>c</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ol ol li:last', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>b</li>' +
+                       '</ol>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent inside only child LI in OL in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('ol ol li', 0);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Outdent multiple LI in OL and nested OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li', 0, 'li li', 1);
+       execCommand('Outdent');
+
+       equal(editor.getContent(), 
+               '<p>a</p>' +
+               '<ol>' +
+                       '<li>b</li>' +
+               '</ol>'
+       );
+});
+
+// Indent
+
+test('Indent single LI in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li', 0);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Indent middle LI in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 0);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Indent last LI in OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li:last', 0);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Indent last LI to same level as middle LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+                       '<li>c</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li:last', 1);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Indent first LI and nested LI OL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       editor.focus();
+       setSelection('li', 0, 'li li', 0);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Indent second LI to same level as nested LI', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b' +
+                               '<ul>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 0);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Indent second LI to same level as nested LI 2', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                               '</ul>' +
+                       '</li>' +
+                       '<li>cd' +
+                               '<ul>' +
+                                       '<li>e</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 1);
+       execCommand('Indent');
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>cd</li>' +
+                                       '<li>e</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+// Backspace
+
+test('Backspace at beginning of single LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<p>a</p>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Backspace at beginning of first LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(),
+               '<p>a</p>' +
+               '<ul>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Backspace at beginning of middle LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>ab</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Backspace at beginning of start LI in UL inside UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li li', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>ab' +
+                               '<ul>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Backspace at beginning of middle LI in UL inside UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li li:nth-child(2)', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>bc</li>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Backspace at beginning of single LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<p>a</p>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Backspace at beginning of first LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(),
+               '<p>a</p>' +
+               '<ul>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Backspace at beginning of middle LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>ab</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Backspace at beginning of start LI in UL inside UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li li', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>ab' +
+                               '<ul>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Backspace at beginning of middle LI in UL inside UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li li:nth-child(2)', 0);
+       editor.plugins.lists.backspaceDelete();
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>bc</li>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+// Delete
+
+test('Delete at end of single LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 1);
+       editor.plugins.lists.backspaceDelete(true);
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Delete at end of first LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li', 1);
+       editor.plugins.lists.backspaceDelete(true);
+
+       equal(editor.getContent(),
+               '<ul>' +
+                       '<li>ab</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Delete at end of middle LI in UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>b</li>' +
+                       '<li>c</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li:nth-child(2)', 1);
+       editor.plugins.lists.backspaceDelete(true);
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a</li>' +
+                       '<li>bc</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Delete at end of start LI in UL inside UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li li', 1);
+       editor.plugins.lists.backspaceDelete(true);
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>bc</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Delete at end of middle LI in UL inside UL', function() {
+       editor.getBody().innerHTML = trimBrs(
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                                       '<li>d</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       editor.focus();
+       setSelection('li li:nth-child(2)', 1);
+       editor.plugins.lists.backspaceDelete(true);
+
+       equal(editor.getContent(), 
+               '<ul>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>cd</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ul>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Remove UL in inline body element contained in LI', function() {
+       inlineEditor.setContent('<ul><li>a</li></ul>');
+       inlineEditor.focus();
+       inlineEditor.execCommand('InsertUnorderedList');
+       equal(inlineEditor.getContent(), '<p>a</p>');
+});
+
+test('Backspace in LI in UL in inline body element contained within LI', function() {
+       inlineEditor.setContent('<ul><li>a</li></ul>');
+       inlineEditor.focus();
+       inlineEditor.selection.select(inlineEditor.getBody(), true);
+       inlineEditor.selection.collapse(true);
+       inlineEditor.plugins.lists.backspaceDelete();
+       equal(inlineEditor.getContent(), '<p>a</p>');
+});
+
+function wait() {
+       if (editor && inlineEditor) {
+               if (!QUnit.started) {
+                       QUnit.start();
+                       QUnit.started = true;
+               }
+       } else {
+               setTimeout(wait, 0);
+       }
+}
+
+tinymce.init({
+       mode: "exact",
+       plugins: "lists",
+       elements: "elm1",
+       add_unload_trigger: false,
+       indent: false,
+       schema: 'html5',
+       entities: 'raw',
+       valid_elements: 'li,ol,ul,em,strong,span,#p,div,br',
+       valid_styles: {
+               '*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left'
+       },
+       disable_nodechange: true,
+       init_instance_callback: function(ed) {
+               editor = ed;
+               wait();
+       }
+});
+
+tinymce.init({
+       selector: '#elm2',
+       inline: true,
+       add_unload_trigger: false,
+       plugins: "lists",
+       init_instance_callback: function(ed) {
+               inlineEditor = ed;
+               wait();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for lists plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <a href="javascript:;" onclick="alert(tinymce.get('elm1').getContent({format: 'raw'}));return false;">[Get raw]</a>
+
+       <ul><li><div id="elm2"></div></li></ul>
+       <a href="javascript:;" onclick="alert(tinymce.get('elm2').getContent({format: 'raw'}));return false;">[Get raw]</a>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/lists.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsmediahtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/media.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/media.html                              (rev 0)
+++ trunk/tests/qunit/editor/plugins/media.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,180 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for Media Plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Media plugin", {
+       autostart: false
+});
+
+test("Object retain as is", function() {
+       editor.setContent(
+               '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="355">' +
+                       '<param name="movie" value="someurl">' +
+                       '<param name="wmode" value="transparent">' +
+                       '<embed src="someurl" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355" />' +
+               '</object>'
+       );
+
+       equal(editor.getContent(),
+               '<p><object width="425" height="355" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">' +
+                       '<param name="movie" value="someurl">' +
+                       '<param name="wmode" value="transparent">' +
+                       '<embed src="someurl" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355" />' +
+               '</object></p>'
+       );
+});
+
+test("Embed retain as is", function() {
+       editor.setContent(
+               '<video src="320x240.ogg" autoplay loop controls>text<a href="#">link</a></video>'
+       );
+
+       equal(editor.getContent(),
+               // IE produces a different attribute order for some odd reason, I love IE
+               tinymce.isIE ? 
+                       '<p><video width="300" height="150" controls="controls" loop="loop" autoplay="autoplay" src="320x240.ogg">text<a href="#">link</a></video></p>' :
+                       '<p><video width="300" height="150" src="320x240.ogg" autoplay="autoplay" loop="loop" controls="controls">text<a href="#">link</a></video></p>'
+       );
+});
+
+test("Video retain as is", function() {
+       editor.setContent(
+               '<video src="320x240.ogg" autoplay loop controls>text<a href="#">link</a></video>'
+       );
+
+       equal(editor.getContent(),
+               // IE produces a different attribute order for some odd reason, I love IE
+               tinymce.isIE ? 
+                       '<p><video width="300" height="150" controls="controls" loop="loop" autoplay="autoplay" src="320x240.ogg">text<a href="#">link</a></video></p>' :
+                       '<p><video width="300" height="150" src="320x240.ogg" autoplay="autoplay" loop="loop" controls="controls">text<a href="#">link</a></video></p>'
+       );
+});
+
+test("Iframe retain as is", function() {
+       editor.setContent(
+               '<iframe src="320x240.ogg" allowfullscreen>text<a href="#">link</a></iframe>'
+       );
+
+       equal(editor.getContent(),
+               '<p><iframe src="320x240.ogg" width="300" height="150" allowfullscreen="allowfullscreen">text<a href="#">link</a></iframe></p>'
+       );
+});
+
+test("Audio retain as is", function() {
+       editor.setContent(
+               '<audio src="sound.mp3">' +
+                       '<track kind="captions" src="foo.en.vtt" srclang="en" label="English">' +
+                       '<track kind="captions" src="foo.sv.vtt" srclang="sv" label="Svenska">' +
+                       'text<a href="#">link</a>' +
+               '</audio>'
+       );
+
+       equal(editor.getContent(),
+               '<p>' +
+                       '<audio src="sound.mp3">' +
+                               '<track kind="captions" src="foo.en.vtt" srclang="en" label="English">' +
+                               '<track kind="captions" src="foo.sv.vtt" srclang="sv" label="Svenska">' +
+                               'text<a href="#">link</a>' +
+                       '</audio>' +
+               '</p>'
+       );
+});
+
+test("Resize complex object", function() {
+       editor.setContent(
+               '<video width="300" height="150" controls="controls">' +
+                       '<source src="s" />' +
+                       '<object type="application/x-shockwave-flash" data="../../js/tinymce/plugins/media/moxieplayer.swf" width="300" height="150">' +
+                               '<param name="allowfullscreen" value="true" />' +
+                               '<param name="allowscriptaccess" value="always" />' +
+                               '<param name="flashvars" value="video_src=s" />' +
+                               '<!--[if IE]><param name="movie" value="../../js/tinymce/plugins/media/moxieplayer.swf" /><![endif]-->' +
+                       '</object>' +
+               '</video>'
+       );
+
+       var placeholderElm = editor.getBody().firstChild.firstChild;
+       placeholderElm.width = 100;
+       placeholderElm.height = 200;
+       editor.fire('objectResized', {target: placeholderElm, width: placeholderElm.width, height: placeholderElm.height});
+
+       equal(editor.getContent(),
+               '<p>' +
+                       '<video width="100" height="200" controls="controls">' +
+                               '<source src="s" />' +
+                               '<object type="application/x-shockwave-flash" data="../../js/tinymce/plugins/media/moxieplayer.swf" width="100" height="200">' +
+                                       '<param name="allowfullscreen" value="true" />' +
+                                       '<param name="allowscriptaccess" value="always" />' +
+                                       '<param name="flashvars" value="video_src=s" />' +
+                                       '<!--[if IE]>' +
+                                               '<param name="movie" value="../../js/tinymce/plugins/media/moxieplayer.swf" />' +
+                                       '<![endif]-->' +
+                               '</object>' +
+                       '</video>' +
+               '</p>'
+       );
+});
+
+test("Media script elements", function() {
+       editor.setContent(
+               '<script src="http://media1.tinymce.com/123456"></sc'+'ript>' +
+               '<script src="http://media2.tinymce.com/123456"></sc'+'ript>'
+       );
+
+       equal(editor.getBody().getElementsByTagName('img')[0].className, 'mce-object mce-object-script');
+       equal(editor.getBody().getElementsByTagName('img')[0].width, 300);
+       equal(editor.getBody().getElementsByTagName('img')[0].height, 150);
+       equal(editor.getBody().getElementsByTagName('img')[1].className, 'mce-object mce-object-script');
+       equal(editor.getBody().getElementsByTagName('img')[1].width, 100);
+       equal(editor.getBody().getElementsByTagName('img')[1].height, 200);
+
+       equal(editor.getContent(),
+               '<p>\n' +
+                       '<script src="http://media1.tinymce.com/123456" type="text/javascript"></sc'+'ript>\n' +
+                       '<script src="http://media2.tinymce.com/123456" type="text/javascript"></sc'+'ript>\n' +
+               '</p>'
+       );
+});
+
+tinymce.init({
+       mode: "exact",
+       elements: "elm1",
+       add_unload_trigger: false,
+       document_base_url: '/tinymce/tinymce/trunk/tests/',
+       plugins: 'media',
+       media_scripts: [
+               {filter: 'http://media1.tinymce.com'},
+               {filter: 'http://media2.tinymce.com', width: 100, height: 200}
+       ],
+       init_instance_callback: function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for Media Plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/media.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsnoneditablehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/noneditable.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/noneditable.html                                (rev 0)
+++ trunk/tests/qunit/editor/plugins/noneditable.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,237 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for noneditable</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor, rng;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("Noneditable plugin", {
+       autostart: false
+});
+
+test('expand to noneditable (start)', function() {
+       editor.setContent('<p><span class="mceNonEditable">no</span>yes</p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild.lastChild, 1);
+       editor.selection.setRng(rng);
+
+       editor.dom.fire(editor.getBody(), 'mouseup');
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 0);
+       equal(rng.endContainer.nodeName, '#text');
+       equal(rng.endOffset, 1);
+});
+
+test('expand to noneditable (end)', function() {
+       editor.setContent('<p>yes<span class="mceNonEditable">no</span></p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild.lastChild.firstChild, 1);
+       editor.selection.setRng(rng);
+
+       editor.dom.fire(editor.getBody(), 'mouseup');
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, '#text');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 2);
+});
+
+test('expand to noneditable (start/end)', function() {
+       editor.setContent('<p>yes<span class="mceNonEditable">noedit</span>yes</p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+
+       editor.dom.fire(editor.getBody(), 'mouseup');
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 2);
+});
+
+test('type after non editable', function() {
+       editor.setContent('<p><span class="mceNonEditable">no</span>yes</p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 2);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+
+       editor.dom.fire(editor.getBody(), 'mouseup');
+       type('X');
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.getAttribute('data-mce-bogus'), 'true');
+       equal(rng.startContainer.nodeName, 'SPAN');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'SPAN');
+       equal(rng.endOffset, 1);
+       equal(editor.getContent(), '<p><span class="mceNonEditable">no</span>Xyes</p>');
+});
+
+test('type between non editable', function() {
+       editor.setContent('<p><span class="mceNonEditable">no</span><span class="mceNonEditable">no</span></p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 2);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+
+       editor.dom.fire(editor.getBody(), 'mouseup');
+       type('X');
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.getAttribute('data-mce-bogus'), 'true');
+       equal(rng.startContainer.nodeName, 'SPAN');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'SPAN');
+       equal(rng.endOffset, 1);
+       equal(editor.getContent(), '<p><span class="mceNonEditable">no</span>X<span class="mceNonEditable">no</span></p>');
+});
+
+test('type after last non editable', function() {
+       editor.setContent('<p><span class="mceNonEditable">no</span></p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 2);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+
+       editor.dom.fire(editor.getBody(), 'mouseup');
+       type('X');
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.getAttribute('data-mce-bogus'), 'true');
+       equal(rng.startContainer.nodeName, 'SPAN');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'SPAN');
+       equal(rng.endOffset, 1);
+       equal(editor.getContent(), '<p><span class="mceNonEditable">no</span>X</p>');
+});
+
+test('escape noneditable inline element (left)', function() {
+       editor.setContent('<p>no <span class="mceNonEditable">yes</span> no</p><p class="mceNonEditable">no</p>');
+       var container = editor.dom.select('p')[0];
+       rng = editor.dom.createRng();
+       rng.selectNode(editor.dom.select('span')[0]);
+       editor.selection.setRng(rng);
+
+       type({keyCode: 37});
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, 'SPAN');
+       equal(rng.startContainer.parentNode.nodeName, 'P');
+       equal(editor.dom.nodeIndex(rng.startContainer), 1);
+       equal(rng.collapsed, true);
+});
+
+test('escape noneditable inline element (right)', function() {
+       editor.setContent('<p>no <span class="mceNonEditable">yes</span> no</p><p class="mceNonEditable">no</p>');
+       var container = editor.dom.select('p')[0];
+       rng = editor.dom.createRng();
+       rng.selectNode(editor.dom.select('span')[0]);
+       editor.selection.setRng(rng);
+
+       type({keyCode: 39});
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, 'SPAN');
+       equal(rng.startContainer.parentNode.nodeName, 'P');
+       equal(editor.dom.nodeIndex(rng.startContainer), 2);
+       equal(rng.collapsed, true);
+});
+
+test('escape noneditable block element (left)', function(){
+       editor.setContent('<p>yes</p><p class="mceNonEditable">no</p><p>yes</p>');
+       rng = editor.dom.createRng();
+       rng.selectNode(editor.dom.select('p')[1]);
+       editor.selection.setRng(rng);
+
+       type({keyCode: 37});
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, "P");
+       equal(editor.dom.nodeIndex(rng.startContainer), 0);
+       equal(rng.startOffset, 1);
+       equal(rng.collapsed, true);
+
+});
+
+test('escape noneditable block element (right)', function(){
+       editor.setContent('<p>yes</p><p class="mceNonEditable">no</p><p>yes</p>');
+       rng = editor.dom.createRng();
+       rng.selectNode(editor.dom.select('p')[1]);
+       editor.selection.setRng(rng);
+
+       type({keyCode: 39});
+       rng = normalizeRng(editor.selection.getRng(true));
+
+       equal(rng.startContainer.nodeName, "P");
+       equal(editor.dom.nodeIndex(rng.startContainer), 2);
+       equal(rng.startOffset, 0);
+       equal(rng.collapsed, true);
+
+});
+
+test('noneditable regexp', function() {
+       editor.setContent('<p>{test1}{test2}</p>');
+
+       equal(editor.dom.select('span').length, 2);
+       equal(editor.getContent(), '<p>{test1}{test2}</p>');
+});
+
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       indent : false,
+       theme_advanced_styles : 'test1=test1;test2=test2',
+       noneditable_regexp : [/\{[^\}]+\}/g],
+       valid_elements : '@[contenteditable|id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong,b,em,i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codeb
 ase|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big',
+       plugins: 'noneditable',
+       forced_root_block : '',
+       convert_fonts_to_spans : false,
+       entities : 'raw',
+       valid_styles : {
+               '*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+       },
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests noneditable plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/noneditable.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginspastehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/paste.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/paste.html                              (rev 0)
+++ trunk/tests/qunit/editor/plugins/paste.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,440 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for the Paste plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Paste plugin", {
+       autostart: false
+});
+
+test("Paste simple text content", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('<p>1234</p>');
+       editor.focus();
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: 'TEST'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>1TEST4</p>');
+});
+
+test("Paste styled text content", function() {
+       var rng = editor.dom.createRng();
+
+       editor.settings.paste_remove_styles_if_webkit = false;
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<strong><em><span style="color: red;">TEST</span></em></strong>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>1<strong><em><span style="color: red;">TEST</span></em></strong>4</p>');
+});
+
+test("Paste paragraph in paragraph", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p>TEST</p>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>1</p><p>TEST</p><p>4</p>');
+});
+
+test("Paste paragraphs in complex paragraph", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('<p><strong><em>1234</em></strong></p>');
+       rng.setStart(editor.dom.select('em,i')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('em,i')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p>TEST 1</p><p>TEST 2</p>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p><strong><em>1</em></strong></p><p>TEST 1</p><p>TEST 2</p><p><strong><em>4</em></strong></p>');
+});
+
+test("Paste Word fake list", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 4);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="ProgId" content="Word.Document"><meta name="Generator" content="Microsoft Word 12"><meta name="Originator" content="Microsoft Word 12"><link rel="File-List" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml"><link rel="themeData" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx"><link rel="colorSchemeMapping" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml"><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/&gt
 ; <w:TrackFormatting/> <w:HyphenationZone>21</w:HyphenationZone> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>SV</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:DontVertAlignCellWithSp/> <w:DontBreakConstrainedForcedTables/> <w:DontVertAlignInTxbx/> <w:Word11KerningPairs/> <w:CachedColBalance/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:
 BrowserLevel> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/&gt
 ; <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9&quot
 ; QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Pr
 iority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/>  <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Nam
 e="Emphasis"/>  <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>  <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/>  <
 w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"
 />  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading A
 ccent 1"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision&
 quot;/>  <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>  <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/>  <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>  <w:LsdException Locked="false" Priority="68&qu
 ot; SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>  <w:
 LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false
 " Name="Medium List 1 Accent 2"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/>  <w:LsdException Locked="false" Priority="71" 
 SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/>  <w:LsdExc
 eption Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false
 " Name="Medium Grid 2 Accent 3"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>  <w:LsdException Locked="false" Priority="60&quo
 t; SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>  <w:
 LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false&quo
 t; Name="Colorful Shading Accent 4"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/>  <w:LsdException Locked="false" Priority="63" Sem
 iHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>  <w:
 LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false&
 quot; Name="Light Shading Accent 6"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>  <w:LsdException Locked="false" Priority="66&quo
 t; SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>  <w:L
 sdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>  <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>  <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>  <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>  <w:LsdException Locked="false" Priority="32" 
 SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>  <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>  <w:LsdException Locked="false" Priority="37" Name="Bibliography"/>  <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>  </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:0 268435456 0 0 -2147483648 0;} @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature
 :0 268435456 0 0 -2147483648 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:
 yes; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:36.0pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; margin-left:36.0pt; margin-bottom:.0001pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-th
 eme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; margin-left:36.0pt; margin-bottom:.0001pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-
 US;} p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:36.0pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-fam
 ily:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} .MsoPapDefault {mso-style-type:export-only; margin-bottom:10.0pt; line-height:115%;} @page Section1 {size:595.3pt 841.9pt; margin:70.85pt 70.85pt 70.85pt 70.85pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:1742563504; mso-list-type:hybrid; mso-list-template-ids:-524928352 69009409 69009411 69009413 69009409 69009411 69009413 69009409 69009411 69009413;} @list l0:level1 {mso-level-number-format:bullet; mso-level-text:?; mso-level-tab-stop:none; mso-level-number-position:left; text-indent:-18.0pt; font-family:Symbol;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso
 -style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style> <![endif]--> <p class="MsoListParagraphCxSpFirst" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"&gt
 ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 1</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 2</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;
 <span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 3</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--
 [endif]-->Item 4</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 5</p> <p class="MsoListParagraphCxSpLast" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: norm
 al; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 6</p>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li><li>Item 4</li><li>Item 5</li><li>Item 6</li></ul>');
+
+       editor.settings.paste_retain_style_properties = 'border';
+       
+       rng = editor.dom.createRng();
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p class="ListStyle" style="margin-top:0cm;margin-right:0cm;margin-bottom:3.0pt;margin-left:18.0pt;mso-add-space:auto;text-align:justify;text-indent:-18.0pt;mso-list:l0 level1 lfo1;tab-stops:list 18.0pt"><span lang="DE" style="font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana;color:black"><span style="mso-list:Ignore">\u25CF<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span lang="DE" style="font-family:Arial;mso-fareast-font-family:Arial;mso-bidi-font-family:Arial;color:black">Item&nbsp; Spaces.<o:p></o:p></span></p>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<ul><li>Item&nbsp; Spaces.</li></ul>');
+
+       rng = editor.dom.createRng();
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p class="ListStyle" style="margin-left:36.0pt;mso-add-space:auto;text-indent:-18.0pt;mso-list:l0 level1 lfo1;tab-stops:list 36.0pt"><span lang="EN-US" style="color:black;mso-ansi-language:EN-US"><span style="mso-list:Ignore">1.<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang="EN-US" style="font-family:Arial;mso-fareast-font-family:Arial;mso-bidi-font-family:Arial;color:black;mso-ansi-language:EN-US">Version 7.0</span><span lang="EN-US" style="font-family:Arial;mso-fareast-font-family:Arial;mso-bidi-font-family:Arial;color:black;mso-ansi-language:EN-US">:<o:p></o:p></span></p>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<ol><li>Version 7.0:</li></ol>');
+       editor.settings.paste_retain_style_properties = '';
+});
+
+test("Paste Word fake list before BR", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 4);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertContent', false, '<br>a');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild, 0);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="ProgId" content="Word.Document"><meta name="Generator" content="Microsoft Word 12"><meta name="Originator" content="Microsoft Word 12"><link rel="File-List" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml"><link rel="themeData" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx"><link rel="colorSchemeMapping" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml"><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/&gt
 ; <w:TrackFormatting/> <w:HyphenationZone>21</w:HyphenationZone> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>SV</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:DontVertAlignCellWithSp/> <w:DontBreakConstrainedForcedTables/> <w:DontVertAlignInTxbx/> <w:Word11KerningPairs/> <w:CachedColBalance/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:
 BrowserLevel> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/&gt
 ; <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9&quot
 ; QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Pr
 iority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/>  <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Nam
 e="Emphasis"/>  <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>  <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/>  <
 w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"
 />  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading A
 ccent 1"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision&
 quot;/>  <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>  <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/>  <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>  <w:LsdException Locked="false" Priority="68&qu
 ot; SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>  <w:
 LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false
 " Name="Medium List 1 Accent 2"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/>  <w:LsdException Locked="false" Priority="71" 
 SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/>  <w:LsdExc
 eption Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false
 " Name="Medium Grid 2 Accent 3"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>  <w:LsdException Locked="false" Priority="60&quo
 t; SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>  <w:
 LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false&quo
 t; Name="Colorful Shading Accent 4"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/>  <w:LsdException Locked="false" Priority="63" Sem
 iHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>  <w:
 LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false&
 quot; Name="Light Shading Accent 6"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>  <w:LsdException Locked="false" Priority="66&quo
 t; SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>  <w:L
 sdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>  <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>  <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>  <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>  <w:LsdException Locked="false" Priority="32" 
 SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>  <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>  <w:LsdException Locked="false" Priority="37" Name="Bibliography"/>  <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>  </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:0 268435456 0 0 -2147483648 0;} @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature
 :0 268435456 0 0 -2147483648 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:
 yes; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:36.0pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; margin-left:36.0pt; margin-bottom:.0001pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-th
 eme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; margin-left:36.0pt; margin-bottom:.0001pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-
 US;} p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:36.0pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-fam
 ily:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} .MsoPapDefault {mso-style-type:export-only; margin-bottom:10.0pt; line-height:115%;} @page Section1 {size:595.3pt 841.9pt; margin:70.85pt 70.85pt 70.85pt 70.85pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:1742563504; mso-list-type:hybrid; mso-list-template-ids:-524928352 69009409 69009411 69009413 69009409 69009411 69009413 69009409 69009411 69009413;} @list l0:level1 {mso-level-number-format:bullet; mso-level-text:?; mso-level-tab-stop:none; mso-level-number-position:left; text-indent:-18.0pt; font-family:Symbol;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso
 -style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style> <![endif]--> <p class="MsoListParagraphCxSpFirst" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"&gt
 ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 1</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 2</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;
 <span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 3</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--
 [endif]-->Item 4</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 5</p> <p class="MsoListParagraphCxSpLast" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">&middot;<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: norm
 al; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><!--[endif]-->Item 6</p>'});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li><li>Item 4</li><li>Item 5</li><li>Item 6</li></ul><p><br />a</p>');
+});
+
+test("Paste list like paragraph and list", function() {
+       editor.setContent('');
+
+       editor.execCommand('mceInsertClipboardContent', false, {
+               content: '<p class=MsoNormal><span style=\'font-size:10.0pt;line-height:115%;font-family:"Trebuchet MS","sans-serif";color:#666666\'>A. X<o:p></o:p></span></p><p class=MsoListParagraph style=\'text-indent:-.25in;mso-list:l0 level1 lfo1\'><![if !supportLists]><span style=\'mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;mso-bidi-font-family:Calibri;mso-bidi-theme-font:minor-latin\'><span style=\'mso-list:Ignore\'>1.<span style=\'font:7.0pt "Times New Roman"\'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><![endif]>Y</p>'
+       });
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>A. X</p><ol><li>Y</li></ol>');
+});
+
+test("Paste Word table", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('<p>1234</p>');
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 4);
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="ProgId" content="Word.Document"><meta name="Generator" content="Microsoft Word 12"><meta name="Originator" content="Microsoft Word 12"><link rel="File-List" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml"><link rel="themeData" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx"><link rel="colorSchemeMapping" href="file:///C:%5CUsers%5Cspocke%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml"><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/&gt
 ; <w:TrackFormatting/> <w:HyphenationZone>21</w:HyphenationZone> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>SV</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:DontVertAlignCellWithSp/> <w:DontBreakConstrainedForcedTables/> <w:DontVertAlignInTxbx/> <w:Word11KerningPairs/> <w:CachedColBalance/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:
 BrowserLevel> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/&gt
 ; <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9&quot
 ; QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Pr
 iority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/>  <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Nam
 e="Emphasis"/>  <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>  <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/>  <
 w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"
 />  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading A
 ccent 1"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision&
 quot;/>  <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>  <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/>  <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>  <w:LsdException Locked="false" Priority="68&qu
 ot; SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>  <w:
 LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false
 " Name="Medium List 1 Accent 2"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/>  <w:LsdException Locked="false" Priority="71" 
 SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/>  <w:LsdExc
 eption Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false
 " Name="Medium Grid 2 Accent 3"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>  <w:LsdException Locked="false" Priority="60&quo
 t; SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>  <w:
 LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false&quo
 t; Name="Colorful Shading Accent 4"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/>  <w:LsdException Locked="false" Priority="63" Sem
 iHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>  <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>  <w:
 LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>  <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>  <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false&
 quot; Name="Light Shading Accent 6"/>  <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/>  <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/>  <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>  <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>  <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>  <w:LsdException Locked="false" Priority="66&quo
 t; SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>  <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>  <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>  <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>  <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/>  <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>  <w:L
 sdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/>  <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>  <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>  <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>  <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>  <w:LsdException Locked="false" Priority="32" 
 SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>  <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>  <w:LsdException Locked="false" Priority="37" Name="Bibliography"/>  <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>  </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin-top:0cm
 ; margin-right:0cm; margin-bottom:10.0pt; margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:36.0pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Cali
 bri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; margin-left:36.0pt; margin-bottom:.0001pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle {mso-style-priority:34;
  mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:0cm; margin-left:36.0pt; margin-bottom:.0001pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; mso-style-type:export-only; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:36.0pt; mso-add-space:auto; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri",&q
 uot;sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-fareast-language:EN-US;} .MsoPapDefault {mso-style-type:export-only; margin-bottom:10.0pt; line-height:115%;} @page Section1 {size:595.3pt 841.9pt; margin:70.85pt 70.85pt 70.85pt 70.85pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} --> </style>&
 lt;!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} table.MsoTableGrid {mso-style-name:"Table Grid"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-priority:59; mso-style-unhide:no; border:solid black 1.0pt; mso-border-themecolor:text1; mso-border-alt:solid black .5pt; mso-border-themecolor:text1; mso-padding-alt:0
 cm 5.4pt 0cm 5.4pt; mso-border-insideh:.5pt solid black; mso-border-insideh-themecolor:text1; mso-border-insidev:.5pt solid black; mso-border-insidev-themecolor:text1; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style> <![endif]--> <table class="MsoTableGrid" style="border: medium none ; margin-left: 36pt; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"> <tbody><tr style=""> <td style="border: 1pt solid black; padding: 0cm 5.4pt; width: 230.3pt;" valign="top" width="307"> <p class="MsoListParagraphCxSpFirst" style="margin: 0cm 0cm 0.0001pt; line-heigh
 t: normal;">Cell 1</p> </td> <td style="border-style: solid solid solid none; border-color: black black black -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 230.3pt;" valign="top" width="307"> <p class="MsoListParagraphCxSpLast" style="margin: 0cm 0cm 0.0001pt; line-height: normal;">Cell 2</p> </td> </tr> <tr style=""> <td style="border-style: none solid solid; border-color: -moz-use-text-color black black; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 230.3pt;" valign="top" width="307"> <p class="MsoListParagraphCxSpFirst" style="margin: 0cm 0cm 0.0001pt; line-height: normal;">Cell 3</p> </td> <td style="border-style: none solid solid none; border-color: -moz-use-text-color black black -moz-use-text-color; border-width: medium 1pt 1pt medium;
  padding: 0cm 5.4pt; width: 230.3pt;" valign="top" width="307"> <p class="MsoListParagraphCxSpLast" style="margin: 0cm 0cm 0.0001pt; line-height: normal;">Cell 4</p> </td> </tr> </tbody></table> <p class="MsoListParagraph"><o:p>&nbsp;</o:p></p>'});
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<table><tbody><tr><td><p>Cell 1</p></td><td><p>Cell 2</p></td></tr><tr><td><p>Cell 3</p></td><td><p>Cell 4</p></td></tr></tbody></table><p>&nbsp;</p>');
+});
+
+test("Paste Word without mso markings", function() {
+       editor.setContent('');
+       editor.execCommand('mceInsertClipboardContent', false, {
+               content: (
+                       '<font face="Times New Roman" size="3"></font>' +
+                       '<p style="margin: 0in 0in 10pt;">' +
+                       '<span style=\'line-height: 115%; font-family: "Comic Sans MS"; font-size: 22pt;\'>Comic Sans MS</span>' +
+                       '</p>' +
+                       '<font face="Times New Roman" size="3"></font>'
+               )
+       });
+
+       equal(trimContent(editor.getContent()), (
+               '<p>Comic Sans MS</p>'
+       ));
+});
+
+test("Paste Word links", function() {
+       editor.setContent('');
+       editor.execCommand('mceInsertClipboardContent', false, {
+               content: (
+                       '<p class="MsoNormal">' +
+                               '<a href="file:///C:/somelocation/filename.doc#_Toc238571849">1</a>' +
+                               '<a href="#_Toc238571849">2</a>' +
+                               '<a name="Toc238571849">3</a>' +
+                               '<a href="http://www.tinymce.com/someurl">4</a>' +
+                               '<a>5</a>' +
+                       '</p>'
+               )
+       });
+
+       equal(trimContent(editor.getContent()), (
+               '<p>' +
+                       '<a href="#_Toc238571849">1</a>' +
+                       '<a href="#_Toc238571849">2</a>' +
+                       '<a name="Toc238571849"></a>3' +
+                       '<a href="http://www.tinymce.com/someurl">4</a>' +
+                       '5' +
+               '</p>'
+       ));
+});
+
+test("Paste Word retain styles", function() {
+       var rng = editor.dom.createRng();
+
+       editor.settings.paste_retain_style_properties = 'color,background-color,font-family';
+
+       // Test color
+       editor.setContent('');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p class="MsoNormal" style="color: #ff0000">Test</p>'});
+       equal(trimContent(editor.getContent().replace(/[\r\n]+/g, '')), '<p style=\"color: #ff0000;\">Test</p>');
+
+       // Test background-color
+       editor.setContent('');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p class="MsoNormal" style="background-color: #ff0000">Test</p>'});
+       equal(trimContent(editor.getContent().replace(/[\r\n]+/g, '')), '<p style=\"background-color: #ff0000;\">Test</p>');
+
+       editor.settings.paste_retain_style_properties = '';
+});
+
+test("Paste part of list from IE", function() {
+       var rng = editor.dom.createRng();
+
+       editor.setContent('');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<li>item2</li><li>item3</li>'});
+       equal(trimContent(editor.getContent().replace(/[\r\n]+/g, '')), '<ul><li>item2</li><li>item3</li></ul>', 'List tags are inferred when pasting LI');
+});
+
+test("Disable default filters", function() {
+       var rng = editor.dom.createRng();
+
+       editor.settings.paste_enable_default_filters = false;
+
+       // Test color
+       editor.setContent('');
+       editor.execCommand('SelectAll');
+       
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<p class="MsoNormal" style="color: #ff0000;">Test</p>'});
+       equal(trimContent(editor.getContent().replace(/[\r\n]+/g, '')), '<p class="MsoNormal" style="color: #ff0000;">Test</p>');
+
+       editor.settings.paste_enable_default_filters = true;
+});
+
+test('paste invalid content with spans on page', function() {
+       var startingContent = '<p>123 testing <span id="x">span later in document</span></p>',
+               insertedContent = '<ul><li>u</li><li>l</li></ul>';
+       editor.setContent(startingContent);
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 0);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {content: insertedContent});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), insertedContent + startingContent);
+});
+
+test('paste plain text with space', function() {
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {text: ' a '});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>t a xt</p>');
+});
+
+test('paste plain text with linefeeds', function() {
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {text: 'a\nb\n\c\n'});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>ta<br />b<br />c<br />xt</p>');
+});
+
+test('paste plain text with double linefeeds', function() {
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {text: 'a\n\nb\n\nc'});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>t</p><p>a</p><p>b</p><p>c</p><p>xt</p>');
+});
+
+test('paste plain text with entities', function() {
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {text: '< & >'});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>t&lt; &amp; &gt;xt</p>');
+});
+
+test('paste plain text with paragraphs', function() {
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertClipboardContent', false, {text: 'a\n<b>b</b>\n\nc'});
+
+       equal(editor.getContent().replace(/[\r\n]+/g, ''), '<p>t</p><p>a<br />&lt;b&gt;b&lt;/b&gt;</p><p>c</p><p>xt</p>');
+});
+
+test('paste data image with paste_data_images: false', function() {
+       editor.setContent('');
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<img src="data:image/png;base64,...">'});
+       equal(editor.getContent(), '');
+
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<img alt="alt" src="data:image/png;base64,...">'});
+       equal(editor.getContent(), '');
+});
+
+test('paste data image with paste_data_images: true', function() {
+       editor.settings.paste_data_images = true;
+
+       editor.setContent('');
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<img src="data:image/png;base64,...">'});
+
+       equal(editor.getContent(), '<p><img src="data:image/png;base64,..." alt="" /></p>');
+});
+
+test('paste pre process text (event)', function() {
+       function callback(e) {
+               e.content = 'PRE:' + e.content;
+       }
+
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.on('PastePreProcess', callback);
+       editor.execCommand('mceInsertClipboardContent', false, {text: 'b\n2'});
+       equal(editor.getContent(), '<p>PRE:b<br />2</p>');
+
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.off('PastePreProcess', callback);
+       editor.execCommand('mceInsertClipboardContent', false, {text: 'c'});
+       equal(editor.getContent(), '<p>c</p>');
+});
+
+test('paste pre process html (event)', function() {
+       function callback(e) {
+               e.content = 'PRE:' + e.content;
+       }
+
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.on('PastePreProcess', callback);
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<em>b</em>'});
+       equal(editor.getContent(), '<p>PRE:<em>b</em></p>');
+
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.off('PastePreProcess', callback);
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<em>c</em>'});
+       equal(editor.getContent(), '<p><em>c</em></p>');
+});
+
+test('paste post process (event)', function() {
+       function callback(e) {
+               e.node.innerHTML += ':POST';
+       }
+
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.on('PastePostProcess', callback);
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<em>b</em>'});
+       equal(editor.getContent(), '<p><em>b</em>:POST</p>');
+
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.off('PastePostProcess', callback);
+       editor.execCommand('mceInsertClipboardContent', false, {content: '<em>c</em>'});
+       equal(editor.getContent(), '<p><em>c</em></p>');
+});
+
+test('paste innerText of single P', function() {
+       editor.setContent('<p>a</p>');
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML), 'a');
+});
+
+test('paste innerText of single P with whitespace wrapped content', function() {
+       editor.setContent('<p>   a   </p>');
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML), 'a');
+});
+
+test('paste innerText of two P', function() {
+       editor.setContent('<p>a</p><p>b</p>');
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML), 'a\n\nb');
+});
+
+test('paste innerText of H1 and P', function() {
+       editor.setContent('<h1>a</h1><p>b</p>');
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML), 'a\nb');
+});
+
+test('paste innerText of P with BR', function() {
+       editor.setContent('<p>a<br>b</p>');
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML), 'a\nb');
+});
+
+test('paste innerText of P with VIDEO', function() {
+       editor.setContent('<p>a<video>b<br>c</video>d</p>');
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML), 'a d');
+});
+
+test('paste innerText of PRE', function() {
+       editor.getBody().innerHTML = '<pre>a\nb\n</pre>';
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().innerHTML).replace(/\r\n/g, '\n'), 'a\nb\n');
+});
+
+test('paste innerText of textnode with whitespace', function() {
+       editor.getBody().innerHTML = '<pre> a </pre>';
+       equal(tinymce.pasteplugin.Utils.innerText(editor.getBody().firstChild.innerHTML), ' a ');
+});
+
+tinymce.init({
+       mode: "exact",
+       elements: "elm1",
+       add_unload_trigger: false,
+       plugins: 'paste',
+       setup: function(ed) {
+               ed.on('NodeChange', false);
+       },
+       init_instance_callback: function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+
+       <h1 id="qunit-header">Unit tests for the Paste plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format: 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/paste.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsplugin_dependency_chainhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/plugin_dependency_chain.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/plugin_dependency_chain.html                            (rev 0)
+++ trunk/tests/qunit/editor/plugins/plugin_dependency_chain.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Basic editor functionality tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+function check_plugin_loaded(name){
+       var pluginManager = tinymce.PluginManager;
+       var depPlugin = pluginManager.get(name);
+       ok(depPlugin, name + " plugin should have loaded");
+       
+}
+test('Dependency Chain Legacy style test', function() {
+       expect(3);
+       check_plugin_loaded("example");
+       check_plugin_loaded("example_dependency");
+       check_plugin_loaded("depend_chain");
+});
+
+tinymce.create('tinymce.plugins.DependencyChain', {});
+
+// Register plugin
+       tinymce.PluginManager.add('depend_chain', tinymce.plugins.DependencyChain, ["example_dependency"]);
+
+       tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       plugins: "depend_chain",
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Plugin Dependency Functional tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/plugin_dependency_chain.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsplugin_dependency_chain_legacyhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html                             (rev 0)
+++ trunk/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Plugin Dependency Functional tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+function check_plugin_loaded(name){
+       var pluginManager = tinymce.PluginManager;
+       var depPlugin = pluginManager.get(name);
+       ok(depPlugin, name + " plugin should have loaded");
+       
+}
+test('Dependency Chain Legacy style test', function() {
+       expect(3);
+       check_plugin_loaded("example");
+       check_plugin_loaded("example_dependency");
+       check_plugin_loaded("depend_chain");
+});
+
+tinymce.create('tinymce.plugins.DependencyChain', {});
+
+// Register plugin
+       tinymce.PluginManager.add('depend_chain', tinymce.plugins.DependencyChain, ["example_dependency"]);
+
+       tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       plugins: "-depend_chain",
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Plugin Dependency Functional tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsplugin_dependency_init_call_orderhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html                          (rev 0)
+++ trunk/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Basic editor functionality tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+function check_plugin_order(order){
+       deepEqual(plugin_load_order, order, "Load order for plugins");
+}
+test('PluginDependencyIsLoaded', function() {
+       expect(1);
+       check_plugin_order(["one", "two", "three", "four"]);
+});
+var plugin_load_order =[];
+tinymce.create('tinymce.plugins.One', {
+       init: function(ed, url) {plugin_load_order.push("one");}
+});
+
+tinymce.create('tinymce.plugins.Two', {
+       init: function(ed, url) {plugin_load_order.push("two");}
+});
+tinymce.create('tinymce.plugins.Three', {
+       init: function(ed, url) {plugin_load_order.push("three");}
+});
+tinymce.create('tinymce.plugins.Four', {
+       init: function(ed, url) {plugin_load_order.push("four");}
+});
+
+// Register plugin
+       tinymce.PluginManager.add('two', tinymce.plugins.Two, ["one"]);
+       tinymce.PluginManager.add('three', tinymce.plugins.Three, ["two"]);
+       tinymce.PluginManager.add('one', tinymce.plugins.One);
+       tinymce.PluginManager.add('four', tinymce.plugins.Four, ["one", "two"]);
+
+       tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       plugins: "-three,-four",
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Plugin Dependency Functional tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsplugin_dependency_simplehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/plugin_dependency_simple.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/plugin_dependency_simple.html                           (rev 0)
+++ trunk/tests/qunit/editor/plugins/plugin_dependency_simple.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Basic editor functionality tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+test('PluginDependencyIsLoaded', function() {
+       expect(2);
+       var pluginManager = tinymce.PluginManager;
+       var depPlugin = pluginManager.get("example_dependency");
+       ok(depPlugin, "Example Dependent plugin should have loaded");
+       var examplePlugin = pluginManager.get("example");
+       ok(examplePlugin, "Example plugin should have loaded via dependencies");
+});
+
+       tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       plugins: "example_dependency",
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Plugin Dependency Functional tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/plugin_dependency_simple.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsplugin_dependency_specific_locationhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/plugin_dependency_specific_location.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/plugin_dependency_specific_location.html                                (rev 0)
+++ trunk/tests/qunit/editor/plugins/plugin_dependency_specific_location.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Basic editor functionality tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+function check_plugin_loaded(name){
+       var pluginManager = tinymce.PluginManager;
+       var depPlugin = pluginManager.get(name);
+       ok(depPlugin, name + " plugin should have loaded");
+       
+}
+test('Plugin Dependency Loaded from a Specific location', function() {
+       expect(2);
+       check_plugin_loaded("specific_location");
+       check_plugin_loaded("autolink");
+});
+
+tinymce.create('tinymce.plugins.SpecificLocation', {});
+
+// Register plugin
+       tinymce.PluginManager.add('specific_location', tinymce.plugins.SpecificLocation, [{prefix: "plugins/", resource:"autolink",  suffix:'/plugin' + tinymce.suffix + '.js'}]);
+
+       tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       plugins: "-specific_location",
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Plugin Dependency Functional tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/plugin_dependency_specific_location.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginssearchreplacehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/searchreplace.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/searchreplace.html                              (rev 0)
+++ trunk/tests/qunit/editor/plugins/searchreplace.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for searchreplace plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor, rng;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.SearchReplace", {
+       autostart: false
+});
+
+test('Find no match', function() {
+       editor.getBody().innerHTML = 'a';
+       equal(0, editor.plugins.searchreplace.find('x'));
+});
+
+test('Find single match', function() {
+       editor.getBody().innerHTML = 'a';
+       equal(1, editor.plugins.searchreplace.find('a'));
+});
+
+test('Find single match in multiple elements', function() {
+       editor.getBody().innerHTML = 't<b>e</b><em>xt</em>';
+       equal(1, editor.plugins.searchreplace.find('text'));
+});
+
+test('Find single match, match case: true', function() {
+       editor.getBody().innerHTML = 'a A';
+       equal(1, editor.plugins.searchreplace.find('A', true));
+});
+
+test('Find single match, whole words: true', function() {
+       editor.getBody().innerHTML = 'a Ax';
+       equal(1, editor.plugins.searchreplace.find('a', false, true));
+});
+
+test('Find multiple matches', function() {
+       editor.getBody().innerHTML = 'a b A';
+       equal(2, editor.plugins.searchreplace.find('a'));
+});
+
+test('Find and replace single match', function() {
+       editor.getBody().innerHTML = 'a';
+       editor.plugins.searchreplace.find('a');
+       ok(!editor.plugins.searchreplace.replace('x'));
+       equal("<p>x</p>", editor.getContent());
+});
+
+test('Find and replace first in multiple matches', function() {
+       editor.getBody().innerHTML = 'a b a';
+       editor.plugins.searchreplace.find('a');
+       ok(editor.plugins.searchreplace.replace('x'));
+       equal("<p>x b a</p>", editor.getContent());
+});
+
+test('Find and replace all in multiple matches', function() {
+       editor.getBody().innerHTML = 'a b a';
+       editor.plugins.searchreplace.find('a');
+       ok(!editor.plugins.searchreplace.replace('x', true, true));
+       equal("<p>x b x</p>", editor.getContent());
+});
+
+test('Find multiple matches, move to next and replace', function() {
+       editor.getBody().innerHTML = 'a a';
+       equal(2, editor.plugins.searchreplace.find('a'));
+       editor.plugins.searchreplace.next();
+       ok(!editor.plugins.searchreplace.replace('x'));
+       equal("<p>a x</p>", editor.getContent());
+});
+
+test('Find multiple matches, move to next and replace backwards', function() {
+       editor.getBody().innerHTML = 'a a';
+       equal(2, editor.plugins.searchreplace.find('a'));
+       editor.plugins.searchreplace.next();
+       ok(editor.plugins.searchreplace.replace('x', false));
+       ok(!editor.plugins.searchreplace.replace('y', false));
+       equal("<p>y x</p>", editor.getContent());
+});
+
+test('Find multiple matches and unmark them', function() {
+       editor.getBody().innerHTML = 'a b a';
+       equal(2, editor.plugins.searchreplace.find('a'));
+       editor.plugins.searchreplace.done();
+       equal('a', editor.selection.getContent());
+       equal(0, editor.getBody().getElementsByTagName('span').length);
+});
+
+test('Find multiple matches with pre blocks', function() {
+       editor.getBody().innerHTML = 'abc<pre>  abc  </pre>abc';
+       equal(3, editor.plugins.searchreplace.find('b'));
+       equal(normalizeHtml(editor.getBody().innerHTML), (
+               'a<span class="mce-match-marker mce-match-marker-selected" data-mce-bogus="1" data-mce-index="0">b</span>c' +
+               '<pre>  a<span class="mce-match-marker" data-mce-bogus="1" data-mce-index="1">b</span>c  </pre>' +
+               'a<span class="mce-match-marker" data-mce-bogus="1" data-mce-index="2">b</span>c'
+       ));
+});
+
+tinymce.init({
+       mode: "exact",
+       plugins: "searchreplace",
+       elements: "elm1",
+       add_unload_trigger: false,
+       indent: false,
+       disable_nodechange: true,
+       init_instance_callback : function(ed) {
+               editor = ed;
+               window.setTimeout(function() {
+                       QUnit.start();
+               }, 0);
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for lists plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <a href="javascript:;" onclick="alert(tinymce.get('elm1').getContent({format: 'raw'}));return false;">[Get raw]</a>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/searchreplace.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginsspellcheckerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/spellchecker.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/spellchecker.html                               (rev 0)
+++ trunk/tests/qunit/editor/plugins/spellchecker.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,108 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for spellchecker plugin</title>
+<meta http-eqiv="X-UA-Compatible" content="IE-edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editors = {}, awaitingInit=2;
+
+initTinyMCE({
+       instance_name: 'no_lang'
+});
+
+initTinyMCE({
+       instance_name: 'one_lang',
+       spellchecker_languages: 'English=en'
+});
+
+initTinyMCE({
+       instance_name: 'many_lang',
+       spellchecker_languages: 'English=en,French=fr,German=de'
+});
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.Spellchecker", {
+       autostart: false
+});
+
+// Default spellchecker language should match editor language
+test('Check default language', function() {
+       var mainLanguage = editors.no_lang.settings.language || 'en';
+       equal(editors.no_lang.settings.spellchecker_language, mainLanguage);
+});
+
+// Spellchecker button may include a language menu
+
+// When no languages are specified, the default list of languages should be
+// used, matching the list in the old TinyMCE 3 spellchecker plugin.
+test('Check spellcheck button is a splitbutton (no languages)', function() {
+       var spellcheckButton = editors.no_lang.buttons.spellchecker;
+       equal(spellcheckButton.type, 'splitbutton');
+});
+
+// When exactly one spellchecker language is specified, there's no need to
+// display a selection menu.
+test('Check spellcheck button is a normal button (one language)', function() {
+       var spellcheckButton = editors.one_lang.buttons.spellchecker;
+       equal(spellcheckButton.type, 'button');
+});
+
+// When more than one spellchecker language is specified, a selection menu
+// should be provided to choose between them.
+test('Check spellcheck button is a splitbutton (many languages)', function() {
+       var spellcheckButton = editors.many_lang.buttons.spellchecker;
+       equal(spellcheckButton.type, 'splitbutton');
+});
+
+function initTinyMCE(args) {
+       var instance_name = args.instance_name;
+       var init_args = {
+               mode: "exact",
+               plugins: "spellchecker",
+               selector: '#' + instance_name,
+               add_unload_trigger: false,
+               disable_nodechange: true,
+               toolbar1: "spellchecker",
+               init_instance_callback: function(ed) {
+                       editors[instance_name] = ed;
+                       checkEditorsReady();
+               }
+       };
+       if (args.spellchecker_languages) {
+               init_args.spellchecker_languages = args.spellchecker_languages;
+       }
+       tinymce.init(init_args);
+}
+
+function checkEditorsReady() {
+       awaitingInit--;
+       if (awaitingInit == 0) {
+               window.setTimeout(function() {
+                       QUnit.start();
+               }, 0);
+       }
+}
+
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for spellchecker plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="no_lang"></textarea>
+       <a href="javascript:;" onclick="alert(tinymce.get('no_lang').getContent({format: 'raw'}));return false;">[Get raw]</a>
+       <textarea id="one_lang"></textarea>
+       <a href="javascript:;" onclick="alert(tinymce.get('one_lang').getContent({format: 'raw'}));return false;">[Get raw]</a>
+       <textarea id="many_lang"></textarea>
+       <a href="javascript:;" onclick="alert(tinymce.get('many_lang').getContent({format: 'raw'}));return false;">[Get raw]</a>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/spellchecker.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginstablehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/table.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/table.html                              (rev 0)
+++ trunk/tests/qunit/editor/plugins/table.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,348 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for the Table plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Table plugin", {
+       autostart: false
+});
+
+function getFontmostWindow() {
+       return editor.windowManager.windows[editor.windowManager.windows.length - 1];
+}
+
+function fillAndSubmitWindowForm(data) {
+       var win = getFontmostWindow();
+
+       win.fromJSON(data);
+       win.find('form')[0].submit();
+       win.close();
+}
+
+function cleanTableHtml(html) {
+       return cleanHtml(html).replace(/<p>(&nbsp;|<br[^>]+>)<\/p>$/, '');
+}
+
+test("Table properties dialog (get data from plain table)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+
+       deepEqual(getFontmostWindow().toJSON(), {
+               "align": false,
+               "border": "",
+               "caption": false,
+               "cellpadding": "",
+               "cellspacing": "",
+               "height": "",
+               "width": ""
+       });
+
+       getFontmostWindow().close();
+});
+
+test("Table properties dialog (get data from full table)", function() {
+       editor.setContent(
+               '<table style="width: 100px; height: 101px;" border="4" cellspacing="2" cellpadding="3">' +
+               '<caption>&nbsp;</caption>' +
+               '<tbody>' +
+               '<tr>' +
+               '<td>&nbsp;</td>' +
+               '</tr>' +
+               '</tbody>' +
+               '</table>'
+       );
+
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+
+       deepEqual(getFontmostWindow().toJSON(), {
+               "align": false,
+               "border": "4",
+               "caption": true,
+               "cellpadding": "3",
+               "cellspacing": "2",
+               "height": "101",
+               "width": "100"
+       });
+
+       getFontmostWindow().close();
+});
+
+test("Table properties dialog (add caption)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+       fillAndSubmitWindowForm({
+               caption: true
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table><caption>&nbsp;</caption><tbody><tr><td>x</td></tr></tbody></table>'
+       );
+});
+
+test("Table properties dialog (remove caption)", function() {
+       editor.setContent('<table><caption>&nbsp;</caption><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+       fillAndSubmitWindowForm({
+               caption: false
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table><tbody><tr><td>x</td></tr></tbody></table>'
+       );
+});
+
+test("Table properties dialog (change size in pixels)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+       fillAndSubmitWindowForm({
+               width: 100,
+               height: 101
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table style="width: 100px; height: 101px;"><tbody><tr><td>x</td></tr></tbody></table>'
+       );
+});
+
+test("Table properties dialog (change size in %)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+       fillAndSubmitWindowForm({
+               width: "100%",
+               height: "101%"
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table style="width: 100%; height: 101%;"><tbody><tr><td>x</td></tr></tbody></table>'
+       );
+});
+
+test("Table properties dialog (change: border,cellpadding,cellspacing,align)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceInsertTable');
+       fillAndSubmitWindowForm({
+               border: "1",
+               cellpadding: "2",
+               cellspacing: "3",
+               align: "right"
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table style="float: right;" border="1" cellspacing="3" cellpadding="2"><tbody><tr><td>x</td></tr></tbody></table>'
+       );
+});
+
+test("Table cell properties dialog (get data from plain cell)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableCellProps');
+
+       deepEqual(getFontmostWindow().toJSON(), {
+               "align": false,
+               "height": "",
+               "scope": "",
+               "type": "td",
+               "width": ""
+       });
+
+       getFontmostWindow().close();
+});
+
+test("Table cell properties dialog (get data from complex cell)", function() {
+       editor.setContent('<table><tr><th style="text-align: right; width: 10px; height: 11px" scope="row">X</th></tr></table>');
+       setSelection('th', 0);
+       editor.execCommand('mceTableCellProps');
+
+       deepEqual(getFontmostWindow().toJSON(), {
+               "align": "right",
+               "height": "11",
+               "scope": "row",
+               "type": "th",
+               "width": "10"
+       });
+
+       getFontmostWindow().close();
+});
+
+test("Table cell properties dialog (update all)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableCellProps');
+
+       fillAndSubmitWindowForm({
+               "align": "right",
+               "height": "11",
+               "scope": "row",
+               "type": "th",
+               "width": "10"
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table><tbody><tr><th style="width: 10px; height: 11px; text-align: right;" scope="row">x</th></tr></tbody></table>'
+       );
+});
+
+test("Table row properties dialog (get data from plain cell)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableRowProps');
+
+       deepEqual(getFontmostWindow().toJSON(), {
+               "align": false,
+               "height": "",
+               "type": "tbody"
+       });
+
+       getFontmostWindow().close();
+});
+
+test("Table row properties dialog (get data from complex cell)", function() {
+       editor.setContent('<table><thead><tr style="height: 10px; text-align: right"><td>X</td></tr></thead></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableRowProps');
+
+       deepEqual(getFontmostWindow().toJSON(), {
+               "align": "right",
+               "height": "10",
+               "type": "thead"
+       });
+
+       getFontmostWindow().close();
+});
+
+test("Table row properties dialog (update all)", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableRowProps');
+
+       fillAndSubmitWindowForm({
+               "align": "right",
+               "height": "10",
+               "type": "thead"
+       });
+
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table><thead><tr style="height: 10px; text-align: right;"><td>x</td></tr></thead></table>'
+       );
+});
+
+test("mceTableDelete command", function() {
+       editor.setContent('<table><tr><td>X</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableDelete');
+       equal(cleanTableHtml(editor.getContent()), '');
+});
+
+test("mceTableDeleteCol command", function() {
+       editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableDeleteCol');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>2</td></tr></tbody></table>');
+});
+
+test("mceTableDeleteRow command", function() {
+       editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableDeleteRow');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>2</td></tr></tbody></table>');
+});
+
+test("mceTableInsertColAfter command", function() {
+       editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableInsertColAfter');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td>&nbsp;</td></tr><tr><td>2</td><td>&nbsp;</td></tr></tbody></table>');
+});
+
+test("mceTableInsertColBefore command", function() {
+       editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableInsertColBefore');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>&nbsp;</td><td>1</td></tr><tr><td>&nbsp;</td><td>2</td></tr></tbody></table>');
+});
+
+test("mceTableInsertRowAfter command", function() {
+       editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableInsertRowAfter');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td>2</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr></tbody></table>');
+});
+
+test("mceTableInsertRowBefore command", function() {
+       editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableInsertRowBefore');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>&nbsp;</td><td>&nbsp;</td></tr><tr><td>1</td><td>2</td></tr></tbody></table>');
+});
+
+test("mceTableMergeCells command with cell selection", function() {
+       editor.setContent('<table><tr><td class="mce-item-selected">1</td><td class="mce-item-selected">2</td></tr></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableMergeCells');
+       equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
+});
+
+test("mceTableSplitCells command", function() {
+       editor.setContent('<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
+       setSelection('td', 0);
+       editor.execCommand('mceTableSplitCells');
+       equal(
+               cleanTableHtml(editor.getContent()),
+               '<table><tbody><tr><td>12</td><td>&nbsp;</td></tr></tbody></table>'
+       );
+});
+
+tinymce.init({
+       selector: "textarea",
+       add_unload_trigger: false,
+       plugins: 'table',
+       valid_styles: {
+               '*' : 'width,height,text-align,float'
+       },
+       init_instance_callback: function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+
+       <h1 id="qunit-header">Unit tests for the Table plugin</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/table.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginstable_robothtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/table_robot.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/table_robot.html                                (rev 0)
+++ trunk/tests/qunit/editor/plugins/table_robot.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,189 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Table plugin tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script src="../js/jsrobot/robot.js"></script>
+<script>
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module('Table plugin', {
+       autostart: false
+});
+
+var VK;
+var UP_ARROW = 0x26;
+var DOWN_ARROW = 0x28;
+var ENTER = 0xA;
+
+if (tinymce.isWebKit) {
+       asyncTest('Selecting Cell and typing should update cell correctly in WebKit', function() {
+               editor.setContent('<table><tr><td><p>first cell</p></td><td><p>second cell</p></td></tr></table>');
+               // in order for the robot to work well, we need to focus the editor before performing selection on it.
+               editor.focus();
+               // in order to simulate the section on tables as per the plugin we do a select then call out to the fix table selection
+               // (which is called by selection events).
+               editor.selection.select(editor.dom.select('td')[0]);
+               editor.fire('keydown');
+               robot.type('g',false, function(){
+                       var expected = '<table><tbody><tr><td><p>g</p></td><td><p>second cell</p></td></tr></tbody></table>';
+                       var actual = editor.getContent();
+                       equal(actual, expected);
+                       start();
+               }, editor.getBody());
+       });
+} else {
+       asyncTest('Empty stub', function() {
+               start();
+               ok(true, "Dummy");
+       });
+}
+
+function testCursorKey(html, nodeToSelect, keyCode, expected) {
+       editor.setContent(html);
+       editor.focus();
+       setSelection(nodeToSelect, 0);
+       editor.focus();
+       robot.type(keyCode, false, function() {
+               var node = editor.selection.getNode();
+               var actual = node.firstChild.nodeValue;
+               equal(actual, expected);
+               start();
+       }, editor.getBody());
+}
+
+asyncTest('space key does not nuke content in th cells', 1, function() {
+    editor.setContent('<table><tbody><tr><th id="a">abcdef</th></tr></tbody></table>');
+    editor.focus();
+    setSelection('#a', 3);
+    editor.focus();
+    robot.type(VK.SPACEBAR, false, function() {
+        var actual = editor.dom.get('a').innerHTML;
+        var expected = 'abc def';
+        equal(actual, expected);
+        start()
+    }, editor.getBody());
+});
+
+asyncTest('arrow up key moves to row above', function() {
+       var html = '<table><tr><td>0</td><td>1</td></tr><tr><td>0</td><td id="b">2</td></tr></table>';
+       testCursorKey(html, '#b', UP_ARROW, '1');
+});
+
+asyncTest('arrow up key moves to row above for heading cells', function() {
+       var html = '<table><tr><td>0</td><td>1</td></tr><tr><td>0</td><th id="b">2</th></tr></table>';
+       testCursorKey(html, '#b', UP_ARROW, '1');
+});
+
+
+asyncTest('arrow down key moves to row below', function() {
+       var html = '<table><tr><td id="a"></td></tr><tr><td>2</td></tr></table>';
+       testCursorKey(html, '#a', DOWN_ARROW, '2');
+});
+
+asyncTest('arrow up key in cell with colspan moves to row above', function() {
+       var html = '<table><tr><td>1</td><td></td></tr><tr><td id="b" colspan="2"></td></tr></table>';
+       testCursorKey(html, '#b', UP_ARROW, '1');
+});
+
+asyncTest('arrow down key in cell with colspan moves to row below', function() {
+       var html = '<table><tr><td id="a" colspan="2"></td></tr><tr><td>2</td><td></td></tr></table>';
+       testCursorKey(html, '#a', DOWN_ARROW, '2');
+});
+
+asyncTest('arrow key up in top row escapes table', function() {
+       var html = '<p>outside</p><table><tr><td id="a"></td></tr><tr><td></td></tr></table>';
+       testCursorKey(html, '#a', UP_ARROW, 'outside');
+});
+
+asyncTest('arrow key down in bottom row escapes table', function() {
+       var html = '<table><tr><td></td></tr><tr><td id="b"></td></tr></table><p>outside</p>';
+       testCursorKey(html, '#b', DOWN_ARROW, 'outside');
+});
+
+asyncTest('arrow key up in bottom row to last p in above tr', 1, function() {
+       var html = "<table><tr><td><p id='a'>a</p><p id='b'>b</p></td></tr><tr><td><p id='c'>c</p><p>d</p></td></tr></table>";
+       testCursorKey(html, '#c', UP_ARROW, 'b');
+});
+
+asyncTest('arrow key down in top row to first p in below tr', 1, function() {
+       var html = "<table><tr><td><p id='a'>a</p><p id='b'>b</p></td></tr><tr><td><p id='c'>c</p><p>d</p></td></tr></table>";
+       testCursorKey(html, '#b', DOWN_ARROW, 'c');
+});
+
+asyncTest('arrow key down into table cell with br', 1, function() {
+       var html = "<table><tr><td id='a'></td></tr><tr><td>something<br></td></tr></table>";
+       testCursorKey(html, '#a', DOWN_ARROW, 'something');
+});
+
+asyncTest('shift-enter in table cell ending with BR places caret on new line', function() {
+               editor.setContent('<table><tr><td>d <strong>e</strong><br></td></tr></table>');
+               setSelection('strong', 1);
+               robot.type(ENTER, true, function(){
+                       var expected = '<table><tbody><tr><td>d <strong>e<br /></strong></td></tr></tbody></table>';
+                       var actual = editor.getContent();
+                       var range = editor.selection.getRng(true);
+                       equal(cleanHtml(actual), expected);
+                       equal(range.startContainer.nodeName, 'STRONG');
+                       equal(range.startOffset, 2);
+                       equal(range.collapsed, true);
+                       start();
+               }, editor.getBody());
+});
+
+// Only run on Gecko since WebKit and IE can place a caret after a table
+if (tinymce.Env.gecko) {
+       test("Insert table and remove caret placeholder", function() {
+               editor.setContent('<table><tbody><tr><td>x</td></tr></tbody></table>');
+               equal(editor.getBody().firstChild.nodeName, "TABLE");
+               equal(editor.getBody().lastChild.nodeName, "P");
+               equal(editor.getContent(), '<table><tbody><tr><td>x</td></tr></tbody></table>');
+       });
+} else {
+       test("Skipped since it works in this browser", function() {
+               ok(true, "Dummy assert");
+       });
+}
+
+var initTinyFunction = function(){
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               cleanup: true,
+               indent: false,
+               add_unload_trigger : false,
+               webkit_fake_resize: false,
+               plugins: "table",
+               init_instance_callback : function(ed) {
+                       editor = ed;
+                       VK = tinymce.util.VK;
+               }
+       });
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Table plugin tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div> 
+       <script>
+       initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/table_robot.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginstestsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/tests.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/tests.js                                (rev 0)
+++ trunk/tests/qunit/editor/plugins/tests.js   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+{
+       "title": "Plugins tests",
+       "tests": [
+               {"title": "Media", "url": "media.html"},
+               {"title": "Noneditable", "url": "noneditable.html"},
+               {"title": "Paste", "url": "paste.html"},
+               {"title": "Table", "url": "table.html"},
+               {"title": "Table (robot)", "url": "table_robot.html", "jsrobot": true},
+               {"title": "jQuery", "url": "jquery_plugin.html"},
+               {"title": "Autolink (robot)", "url": "autolink.html", "jsrobot": true},
+               {"title": "Autosave", "url": "autosave.html"},
+               {"title": "Wordcount", "url": "wordcount.html"},
+               {"title": "Fullpage", "url": "fullpage.html"},
+               {"title": "Legacyoutput", "url": "legacyoutput.html"},
+               {"title": "Plugin Dependencies", "url": "plugin_dependency_simple.html"},
+               {"title": "Plugin Dependency Chain", "url": "plugin_dependency_chain.html"},
+               {"title": "Plugin Dependency Chain Legacy", "url": "plugin_dependency_chain_legacy.html"},
+               {"title": "Dependency Chain Init Call Order", "url": "plugin_dependency_init_call_order.html"},
+               {"title": "Dependency With Specific Location", "url": "plugin_dependency_specific_location.html"},
+               {"title": "Lists", "url": "lists.html"},
+               {"title": "Searchreplace", "url": "searchreplace.html"},
+               {"title": "Spellchecker", "url": "spellchecker.html"}
+       ]
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/tests.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditorpluginswordcounthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/plugins/wordcount.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/plugins/wordcount.html                          (rev 0)
+++ trunk/tests/qunit/editor/plugins/wordcount.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,122 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for the Wordcount plugin</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.plugins.Wordcount", { 
+       autostart: false
+});
+
+test("Blank document has 0 words", function() {
+       expect(1);
+
+       editor.setContent('');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 0);
+});
+
+test("Simple word count", function() {
+       expect(1);
+
+       editor.setContent('<p>My sentence is this.</p>');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 4);
+});
+
+test("Does not count dashes", function() {
+       expect(1);
+
+       editor.setContent('<p>Something -- ok</p>');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 2);
+});
+
+test("Does not count asterisks, non-word characters", function() {
+       expect(1);
+
+       editor.setContent('<p>* something\n· something else</p>');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 3);
+});
+
+test("Does not count htmlentities", function() {
+       expect(1);
+
+       editor.setContent('<p>It&rsquo;s my life &ndash; don\'t you forget.</p>');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 6);
+});
+
+test("Counts hyphenated words as one word", function() {
+       expect(1);
+
+       editor.setContent('<p>Hello some-word here.</p>');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 3);
+});
+
+test("Counts words between blocks as two words", function() {
+       expect(1);
+
+       editor.setContent('<p>Hello</p><p>world</p>');
+       var result = editor.plugins.wordcount.getCount();
+       equal(result, 2);
+});
+
+/*
+The blocking functionality in the wordcount plugin prevents this code from
+being tested correctly.
+
+I'm of the opinion that the blocking code isn't really doing 
+anything crucial, and should be ripped out, so this module can be tested.
+---------
+test("should set the word count in the target html element", function() {
+       expect(1);
+       editor.setContent('<p>Hey, it\'s me!</p>');
+       equal(parseInt(document.getElementById('elm1-word-count').innerHTML), 3);
+});
+*/
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       wordcount_target_id: 'current-count',
+       plugins : 'wordcount',
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+
+<h1 id="qunit-header">Unit tests for the Wordcount plugin</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+
+<div id="word-count">
+       Current Count: <span id="current-count"></span>
+</div>
+
+<textarea id="elm1" name="elm1"></textarea>
+<div>
+       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+</div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/plugins/wordcount.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortestgif"></a>
<div class="binary"><h4>Added: trunk/tests/qunit/editor/test.gif</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Index: trunk/tests/qunit/editor/test.gif
</span><span class="cx">===================================================================
</span><del>--- trunk/tests/qunit/editor/test.gif   2014-02-09 22:33:56 UTC (rev 27154)
</del><ins>+++ trunk/tests/qunit/editor/test.gif    2014-02-10 01:11:25 UTC (rev 27155)
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/test.gif
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<ins>+image/gif
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceEditorhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/Editor.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/Editor.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/Editor.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,221 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.Editor</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("tinymce.Editor", {
+       autostart: false
+});
+
+test('Event: change', function() {
+       var level, lastLevel;
+
+       editor.on('change', function(e) {
+               level = e.level;
+               lastLevel = e.lastLevel;
+       });
+
+       editor.setContent('');
+       editor.insertContent('a');
+       equal(level.content.toLowerCase(), '<p>a</p>');
+       equal(lastLevel.content, editor.undoManager.data[0].content);
+
+       editor.off('change');
+});
+
+test('Event: beforeExecCommand', function() {
+       var level, lastLevel, cmd, ui, value;
+
+       editor.on('BeforeExecCommand', function(e) {
+               cmd = e.command;
+               ui = e.ui;
+               value = e.value;
+
+               e.preventDefault();
+       });
+
+       editor.setContent('');
+       editor.insertContent('a');
+       equal(editor.getContent(), '');
+       equal(cmd, 'mceInsertContent');
+       equal(ui, false);
+       equal(value, 'a');
+
+       editor.off('BeforeExecCommand');
+       editor.setContent('');
+       editor.insertContent('a');
+       equal(editor.getContent(), '<p>a</p>');
+});
+
+test('urls - relativeURLs', function() {
+       editor.settings.relative_urls = true;
+       editor.documentBaseURI = new tinymce.util.URI('http://www.site.com/dirA/dirB/dirC/');
+
+       editor.setContent('<a href="test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="test.html">test</a></p>');
+
+       editor.setContent('<a href="../test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="../test.html">test</a></p>');
+
+       editor.setContent('<a href="test/test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="test/test.html">test</a></p>');
+
+       editor.setContent('<a href="/test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="../../../test.html">test</a></p>');
+
+       editor.setContent('<a href="http://www.somesite.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="http://www.somesite.com/test/file.htm">test</a></p>');
+
+       editor.setContent('<a href="//www.site.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="../../../test/file.htm">test</a></p>');
+
+       editor.setContent('<a href="//www.somesite.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="//www.somesite.com/test/file.htm">test</a></p>');
+});
+
+test('urls - absoluteURLs', function() {
+       editor.settings.relative_urls = false;
+       editor.settings.remove_script_host = true;
+       editor.documentBaseURI = new tinymce.util.URI('http://www.site.com/dirA/dirB/dirC/');
+
+       editor.setContent('<a href="test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="/dirA/dirB/dirC/test.html">test</a></p>');
+
+       editor.setContent('<a href="../test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="/dirA/dirB/test.html">test</a></p>');
+
+       editor.setContent('<a href="test/test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="/dirA/dirB/dirC/test/test.html">test</a></p>');
+
+       editor.setContent('<a href="http://www.somesite.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="http://www.somesite.com/test/file.htm">test</a></p>');
+
+       editor.settings.relative_urls = false;
+       editor.settings.remove_script_host = false;
+
+       editor.setContent('<a href="test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="http://www.site.com/dirA/dirB/dirC/test.html">test</a></p>');
+
+       editor.setContent('<a href="../test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="http://www.site.com/dirA/dirB/test.html">test</a></p>');
+
+       editor.setContent('<a href="test/test.html">test</a>');
+       equal(editor.getContent(), '<p><a href="http://www.site.com/dirA/dirB/dirC/test/test.html">test</a></p>');
+
+       editor.setContent('<a href="http://www.somesite.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="http://www.somesite.com/test/file.htm">test</a></p>');
+
+       editor.setContent('<a href="//www.site.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="//www.site.com/test/file.htm">test</a></p>');
+
+       editor.setContent('<a href="//www.somesite.com/test/file.htm">test</a>');
+       equal(editor.getContent(), '<p><a href="//www.somesite.com/test/file.htm">test</a></p>');
+});
+
+test('WebKit Serialization range bug', function() {
+       expect(1);
+
+       if (tinymce.isIE) {
+               ok(true, "Skip IE");
+       } else {
+               // Note that if we create the P with this invalid content directly, Chrome cleans it up differently to other browsers so we don't
+               // wind up testing the serialization functionality we were aiming for and the test fails.
+               var p = editor.dom.create('p', {}, '123<table><tbody><tr><td>X</td></tr></tbody></table>456');
+               editor.dom.replace(p, editor.getBody().firstChild);
+
+               equal(editor.getContent(), '<p>123</p>\n<table>\n<tbody>\n<tr>\n<td>X</td>\n</tr>\n</tbody>\n</table>\n<p>456</p>');
+       }
+});
+
+
+test('editor_methods - getParam', function() {
+       expect(5);
+
+       editor.settings.test = 'a,b,c';
+       equal(editor.getParam('test', '', 'hash')['c'], 'c');
+
+       editor.settings.test = 'a';
+       equal(editor.getParam('test', '', 'hash')['a'], 'a');
+
+       editor.settings.test = 'a=b';
+       equal(editor.getParam('test', '', 'hash')['a'], 'b');
+
+       editor.settings.test = 'a=b;c=d,e';
+       equal(editor.getParam('test', '', 'hash')['c'], 'd,e');
+
+       editor.settings.test = 'a=b,c=d';
+       equal(editor.getParam('test', '', 'hash')['c'], 'd');
+});
+
+test('setContent', function() {
+       var count;
+
+       expect(4);
+
+       function callback(e) {
+               e.content = e.content.replace(/test/, 'X');
+               count++;
+       };
+
+       editor.on('SetContent', callback);
+       editor.on('BeforeSetContent', callback);
+       count = 0;
+       editor.setContent('<p>test</p>');
+       equal(editor.getContent(), "<p>X</p>");
+       equal(count, 2);
+       editor.off('SetContent', callback);
+       editor.off('BeforeSetContent', callback);
+
+       count = 0;
+       editor.setContent('<p>test</p>');
+       equal(editor.getContent(), "<p>test</p>");
+       equal(count, 0);
+});
+
+test('custom elements', function() {
+       expect(1);
+
+       editor.setContent('<custom1>c1</custom1><custom2>c1</custom2>');
+       equal(editor.getContent().replace(/[\r\n]/g, ''), '<custom1>c1</custom1><p><custom2>c1</custom2></p>');
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       entities : 'raw',
+       valid_styles : {
+               '*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+       },
+       custom_elements: 'custom1,~custom2',
+       extended_valid_elements: 'custom1,custom2',
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for tinymce.Editor</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/Editor.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceEditorCommandshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/EditorCommands.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/EditorCommands.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/EditorCommands.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,765 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.EditorCommands</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("tinymce.EditorCommands", {
+       autostart: false
+});
+
+function getContent() {
+       return editor.getContent({format:'raw'}).toLowerCase().replace(/[\r\n]+/g, '');
+};
+
+test('mceInsertContent - p inside text of p', function() {
+       var rng;
+       
+       expect(7);
+
+       editor.setContent('<p>1234</p>');
+       editor.focus();
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<p>abc</p>');
+       equal(getContent(), '<p>1</p><p>abc</p><p>4</p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - p inside whole p', function() {
+       var rng;
+
+       expect(7);
+
+       editor.setContent('<p>1234</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<p>abc</p>');
+       equal(getContent(), '<p>abc</p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - pre in text of pre', function() {
+       var rng;
+       
+       expect(7);
+
+       editor.setContent('<pre>1234</pre>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('pre')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('pre')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<pre>abc</pre>');
+       equal(getContent(), '<pre>1</pre><pre>abc</pre><pre>4</pre>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'PRE');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'PRE');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - h1 in text of h1', function() {
+       var rng;
+       
+       expect(7);
+
+       editor.setContent('<h1>1234</h1>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('h1')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('h1')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<h1>abc</h1>');
+       equal(getContent(), '<h1>1</h1><h1>abc</h1><h1>4</h1>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'H1');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'H1');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - li inside li', function() {
+       var rng;
+       
+       expect(7);
+
+       editor.setContent('<ul><li>1234</li></ul>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('li')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('li')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<li>abc</li>');
+       equal(getContent(), '<ul><li>1</li><li>abc</li><li>4</li></ul>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'LI');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'LI');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - p inside empty editor', function() {
+       var rng;
+
+       expect(7);
+
+       editor.setContent('');
+       editor.execCommand('mceInsertContent', false, '<p>abc</p>');
+       equal(getContent(), '<p>abc</p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - text inside empty p', function() {
+       var rng;
+
+       expect(7);
+
+       editor.getBody().innerHTML = '<p></p>';
+       setSelection('p', 0);
+       editor.execCommand('mceInsertContent', false, 'abc');
+       equal(editor.getBody().innerHTML.toLowerCase().replace(/^<br>/, ''), '<p>abc</p>'); // Opera inserts a BR at the beginning of contents if the P is empty
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - text inside empty p with br caret node', function() {
+       var rng;
+
+       expect(7);
+
+       editor.getBody().innerHTML = '<p><br></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild, 0);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, 'abc');
+       equal(editor.getBody().innerHTML.toLowerCase(), '<p>abc</p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 1);
+       equal(rng.startContainer.innerHTML, 'abc');
+});
+
+test('mceInsertContent - image inside p', function() {
+       var rng;
+       
+       expect(6);
+
+       editor.setContent('<p>1</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 1);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<img src="about:blank" />');
+       equal(editor.getContent(), '<p><img src="about:blank" alt="" /></p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 1);
+});
+
+test('mceInsertContent - legacy content', function() {
+       var rng;
+       
+       expect(1);
+
+       // Convert legacy content
+       editor.setContent('<p>1</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 1);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<u>u</u><strike>strike</strike><font size="7">font</font>');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;">u</span><span style="text-decoration: line-through;">strike</span><span style="font-size: 300%;">font</span></p>');
+});
+
+test('mceInsertContent - hr', function() {
+       var rng;
+       
+       expect(7);
+
+       editor.setContent('<p>123</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, '<hr />');
+       equal(editor.getContent(), '<p>1</p><hr /><p>3</p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer, editor.getBody().lastChild);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 0);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 0);
+});
+
+test('mceInsertContent - forced root block', function() {
+       var rng;
+       
+       expect(1);
+
+       // Forced root block
+       editor.getBody().innerHTML = '';
+       editor.execCommand('mceInsertContent', false, 'test<b>123</b><!-- a -->');
+       // Opera adds an extra paragraph since it adds a BR at the end of the contents pass though this for now since it's an minority browser
+       equal(editor.getContent().replace(/<p>\u00a0<\/p>/g, ''), '<p>test<strong>123</strong></p><!-- a -->');
+});
+
+test('mceInsertContent - mixed inline content inside td', function() {
+       var rng;
+       
+       expect(1);
+
+       // Forced root block
+       editor.getBody().innerHTML = '<table><tr><td>X</td></tr></table>';
+       setSelection('td', 0, 'td', 0);
+       editor.execCommand('mceInsertContent', false, 'test<b>123</b><!-- a -->');
+       equal(editor.getContent(), '<table><tbody><tr><td>test<strong>123</strong><!-- a -->X</td></tr></tbody></table>');
+});
+
+test('mceInsertContent - invalid insertion with spans on page', function(){
+       var startingContent = '<p>123 testing <em>span later in document</em></p>',
+               insertedContent = '<ul><li>u</li><li>l</li></ul>';
+       editor.setContent(startingContent);
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 0);
+       editor.selection.setRng(rng);
+       editor.execCommand('mceInsertContent', false, insertedContent);
+
+       equal(editor.getContent(), insertedContent + startingContent);
+});
+
+test('mceInsertContent - text with space before at start of block', function() {
+       editor.getBody().innerHTML = '<p>a</p>';
+       setSelection('p', 0);
+       editor.execCommand('mceInsertContent', false, ' b');
+       equal(editor.getContent(), '<p>\u00a0ba</p>');
+});
+
+test('mceInsertContent - text with space after at end of block', function() {
+       editor.getBody().innerHTML = '<p>a</p>';
+       setSelection('p', 1);
+       editor.execCommand('mceInsertContent', false, 'b ');
+       equal(editor.getContent(), '<p>ab\u00a0</p>');
+});
+
+test('mceInsertContent - text with space before/after at middle of block', function() {
+       editor.getBody().innerHTML = '<p>ac</p>';
+       setSelection('p', 1);
+       editor.execCommand('mceInsertContent', false, ' b ');
+       equal(editor.getContent(), '<p>a b c</p>');
+});
+
+test('mceInsertContent - inline element with space before/after at middle of block', function() {
+       editor.getBody().innerHTML = '<p>ac</p>';
+       setSelection('p', 1);
+       editor.execCommand('mceInsertContent', false, ' <em>b</em> ');
+       equal(editor.getContent(), '<p>a <em>b</em> c</p>');
+});
+
+test('mceInsertContent - block element with space before/after at middle of block', function() {
+       editor.getBody().innerHTML = '<p>ac</p>';
+       setSelection('p', 1);
+       editor.execCommand('mceInsertContent', false, ' <p>b</p> ');
+       equal(editor.getContent(), '<p>a</p><p>b</p><p>c</p>');
+});
+
+test('InsertHorizontalRule', function() {
+       var rng;
+       
+       expect(7);
+
+       editor.setContent('<p>123</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.execCommand('InsertHorizontalRule');
+       equal(editor.getContent(), '<p>1</p><hr /><p>3</p>');
+       rng = normalizeRng(editor.selection.getRng(true));
+       ok(rng.collapsed);
+       equal(rng.startContainer, editor.getBody().lastChild);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startOffset, 0);
+       equal(rng.endContainer.nodeName, 'P');
+       equal(rng.endOffset, 0);
+});
+
+test('Justify - multiple block elements selected - queryCommandState', function() {
+       editor.setContent('<div style="text-align: left;"><div id="a" style="text-align: right;">one</div><div id="b" style="text-align: right;">two</div></div>');
+       setSelection('#a', 0, '#b', 3);
+       equal(editor.queryCommandState('JustifyLeft'), false);
+       ok(editor.queryCommandState('JustifyRight'));
+});
+
+test('Formatting commands (xhtmlTextStyles)', function() {
+       var c;
+
+       expect(19);
+       editor.focus();
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+       equal(editor.getContent(), "<p><strong>test 123</strong></p>");
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Italic');
+       equal(editor.getContent(), "<p><em>test 123</em></p>");
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Underline');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;">test 123</span></p>');
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Strikethrough');
+       equal(editor.getContent(), '<p><span style="text-decoration: line-through;">test 123</span></p>');
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('FontName',false,'Arial');
+       equal(editor.getContent(), '<p><span style="font-family: ' + fontFace('Arial') + ';">test 123</span></p>');
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('FontSize',false,'7');
+       equal(editor.getContent(), '<p><span style="font-size: xx-large;">test 123</span></p>');
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('ForeColor', false, '#FF0000');
+       equal(editor.getContent(), '<p><span style="color: #ff0000;">test 123</span></p>');
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('HiliteColor', false, '#FF0000');
+       equal(editor.getContent(), '<p><span style="background-color: #ff0000;">test 123</span></p>');
+
+       editor.setContent('<p><span style="text-decoration: underline;">test 123</span></p>');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;">test 123</span></p>');
+
+       editor.setContent('<p><span style="text-decoration: line-through;">test 123</span></p>');
+       equal(editor.getContent(), '<p><span style="text-decoration: line-through;">test 123</span></p>');
+
+       editor.setContent('<p><span style="font-family: Arial;">test 123</span></p>');
+       equal(editor.getContent(), '<p><span style="font-family: Arial;">test 123</span></p>');
+
+       editor.setContent('<p><span style="font-size: xx-large;">test 123</span></p>');
+       equal(editor.getContent(), '<p><span style="font-size: xx-large;">test 123</span></p>');
+
+       editor.setContent('<p><u>test 123</u></p>');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;">test 123</span></p>');
+
+       editor.setContent('<p><strike>test 123</strike></p>');
+       equal(editor.getContent(), '<p><span style="text-decoration: line-through;">test 123</span></p>');
+
+       editor.setContent('<p><font face="Arial">test 123</font></p>');
+       equal(editor.getContent(), '<p><span style="font-family: ' + fontFace('Arial') + ';">test 123</span></p>');
+
+       editor.setContent('<p><font size="7">test 123</font></p>');
+       equal(editor.getContent(), '<p><span style="font-size: 300%;">test 123</span></p>');
+
+       editor.setContent('<p><font face="Arial" size="7">test 123</font></p>');
+       equal(editor.getContent(), '<p><span style="font-size: 300%; font-family: ' + fontFace('Arial') + ';">test 123</span></p>');
+
+       editor.setContent('<font style="background-color: #ff0000" color="#ff0000">test</font><font face="Arial">test</font>');
+       equal(editor.getContent(), '<p><span style="color: #ff0000; background-color: #ff0000;">test</span><span style="font-family: ' + fontFace('Arial') + ';">test</span></p>');
+
+       editor.setContent('<p><font face="Arial" style="color: #ff0000">test 123</font></p>');
+       equal(editor.getContent(), '<p><span style="color: #ff0000; font-family: ' + fontFace('Arial') + ';">test 123</span></p>');
+});
+
+test('Formatting commands (alignInline)', function() {
+       expect(7);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('JustifyLeft');
+       equal(editor.getContent(), '<p style="text-align: left;">test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('JustifyCenter');
+       equal(editor.getContent(), '<p style="text-align: center;">test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('JustifyRight');
+       equal(editor.getContent(), '<p style="text-align: right;">test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('JustifyFull');
+       equal(editor.getContent(), '<p style="text-align: justify;">test 123</p>');
+
+       editor.setContent('<img src="../media/logo.jpg" />');
+       editor.selection.select(editor.dom.select('img')[0]);
+       editor.execCommand('JustifyLeft');
+       equal(editor.getContent(), '<p><img style="float: left;" src="../media/logo.jpg" alt="" /></p>');
+
+       editor.setContent('<img src="../media/logo.jpg" />');
+       editor.selection.select(editor.dom.select('img')[0]);
+       editor.execCommand('JustifyCenter');
+       equal(editor.getContent(), '<p><img style="margin-right: auto; margin-left: auto; display: block;" src="../media/logo.jpg" alt="" /></p>');
+
+       editor.setContent('<img src="../media/logo.jpg" />');
+       editor.selection.select(editor.dom.select('img')[0]);
+       editor.execCommand('JustifyRight');
+       equal(editor.getContent(), '<p><img style="float: right;" src="../media/logo.jpg" alt="" /></p>');
+});
+
+test('mceBlockQuote', function() {
+       expect(2);
+
+       editor.focus();
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceBlockQuote');
+       equal(editor.getContent().replace(/\s+/g, ''), '<blockquote><p>test123</p></blockquote>');
+
+       editor.setContent('<p>test 123</p><p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceBlockQuote');
+       equal(editor.getContent().replace(/\s+/g, ''), '<blockquote><p>test123</p><p>test123</p></blockquote>');
+});
+
+test('FormatBlock', function() {
+       expect(9);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'h1');
+       equal(editor.getContent(), '<h1>test 123</h1>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'h2');
+       equal(editor.getContent(), '<h2>test 123</h2>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'h3');
+       equal(editor.getContent(), '<h3>test 123</h3>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'h4');
+       equal(editor.getContent(), '<h4>test 123</h4>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'h5');
+       equal(editor.getContent(), '<h5>test 123</h5>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'h6');
+       equal(editor.getContent(), '<h6>test 123</h6>');
+
+       editor.execCommand('SelectAll');
+
+       try {
+               editor.execCommand('FormatBlock', false, 'div');
+       } catch (ex) {
+               //t.log('Failed: ' + ex.message);
+       }
+
+       equal(editor.getContent(), '<div>test 123</div>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'address');
+       equal(editor.getContent(), '<address>test 123</address>');
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('FormatBlock', false, 'pre');
+       equal(editor.getContent(), '<pre>test 123</pre>');
+});
+
+test('mceInsertLink (relative)', function() {
+       expect(1);
+
+       editor.setContent('test 123');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertLink', false, 'test');
+       equal(editor.getContent(), '<p><a href="test">test 123</a></p>');
+});
+
+test('mceInsertLink (link absolute)', function() {
+       expect(1);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertLink', false, 'http://www.site.com');
+       equal(editor.getContent(), '<p><a href="http://www.site.com">test 123</a></p>');
+});
+
+test('mceInsertLink (link encoded)', function() {
+       expect(1);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertLink', false, '"&<>');
+       equal(editor.getContent(), '<p><a href="&quot;&amp;&lt;&gt;">test 123</a></p>');
+});
+
+test('mceInsertLink (link encoded and with class)', function() {
+       expect(1);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertLink', false, {href : '"&<>', 'class' : 'test'});
+       equal(editor.getContent(), '<p><a class="test" href="&quot;&amp;&lt;&gt;">test 123</a></p>');
+});
+
+test('mceInsertLink (link with space)', function() {
+       expect(1);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertLink', false, {href : 'foo bar'});
+       equal(editor.getContent(), '<p><a href="foo%20bar">test 123</a></p>');
+});
+
+test('mceInsertLink (link floated img)', function() {
+       expect(1);
+
+       editor.setContent('<p><img style="float: right;" src="about:blank" /></p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="link"><img style="float: right;" src="about:blank" alt="" /></a></p>');
+});
+
+test('mceInsertLink (link adjacent text)', function() {
+       var rng;
+
+       expect(1);
+
+       editor.setContent('<p><a href="#">a</a>b</p>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.lastChild, 0);
+       rng.setEnd(editor.getBody().firstChild.lastChild, 1);   
+       editor.selection.setRng(rng);
+
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="#">a</a><a href="link">b</a></p>');
+});
+
+test('mceInsertLink (link text inside text)', function() {
+       var rng;
+
+       expect(1);
+
+       editor.setContent('<p><a href="#"><em>abc</em></a></p>');
+       setSelection('em', 1, 'em', 2);
+
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="link"><em>abc</em></a></p>');
+});
+
+test('mceInsertLink (link around existing links)', function() {
+       var rng;
+
+       expect(1);
+
+       editor.setContent('<p><a href="#1">1</a><a href="#2">2</a></p>');
+       editor.execCommand('SelectAll');
+
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="link">12</a></p>');
+});
+
+test('mceInsertLink (link around existing links with different attrs)', function() {
+       var rng;
+
+       expect(1);
+
+       editor.setContent('<p><a id="a" href="#1">1</a><a id="b" href="#2">2</a></p>');
+       editor.execCommand('SelectAll');
+
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="link">12</a></p>');
+});
+
+test('mceInsertLink (link around existing complex contents with links)', function() {
+       var rng;
+
+       expect(1);
+
+       editor.setContent('<p><span id="s1"><strong><a id="a" href="#1"><em>1</em></a></strong></span><span id="s2"><em><a id="b" href="#2"><strong>2</strong></a></em></span></p>');
+       editor.execCommand('SelectAll');
+
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="link"><span id="s1"><strong><em>1</em></strong></span><span id="s2"><em><strong>2</strong></em></span></a></p>');
+});
+
+test('mceInsertLink (link text inside link)', function() {
+       var rng;
+
+       expect(1);
+
+       editor.setContent('<p><a href="#">test</a></p>');
+       setSelection('p', 0, 'p', 1);
+       editor.execCommand('SelectAll');
+
+       editor.execCommand('mceInsertLink', false, 'link');
+       equal(editor.getContent(), '<p><a href="link">test</a></p>');
+});
+
+test('unlink', function() {
+       expect(1);
+
+       editor.setContent('<p><a href="test">test</a> <a href="test">123</a></p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('unlink');
+       equal(editor.getContent(), '<p>test 123</p>');
+});
+
+test('subscript/superscript', function() {
+       expect(4);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('subscript');
+       equal(editor.getContent(), '<p><sub>test 123</sub></p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('superscript');
+       equal(editor.getContent(), '<p><sup>test 123</sup></p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('subscript');
+       editor.execCommand('subscript');
+       equal(editor.getContent(), '<p>test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('superscript');
+       editor.execCommand('superscript');
+       equal(editor.getContent(), '<p>test 123</p>');
+});
+
+test('indent/outdent', function() {
+       expect(4);
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Indent');
+       equal(editor.getContent(), '<p style="padding-left: 30px;">test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Indent');
+       editor.execCommand('Indent');
+       equal(editor.getContent(), '<p style="padding-left: 60px;">test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Indent');
+       editor.execCommand('Indent');
+       editor.execCommand('Outdent');
+       equal(editor.getContent(), '<p style="padding-left: 30px;">test 123</p>');
+
+       editor.setContent('<p>test 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Outdent');
+       equal(editor.getContent(), '<p>test 123</p>');
+});
+
+test('RemoveFormat', function() {
+       var t = this;
+
+       expect(3);
+
+       editor.setContent('<p><em>test</em> <strong>123</strong> <a href="123">123</a> 123</p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('RemoveFormat');
+       equal(editor.getContent(), '<p>test 123 <a href="123">123</a> 123</p>');
+
+       editor.setContent('<p><em><em>test</em> <strong>123</strong> <a href="123">123</a> 123</em></p>');
+       editor.execCommand('SelectAll');
+       editor.execCommand('RemoveFormat');
+       equal(editor.getContent(), '<p>test 123 <a href="123">123</a> 123</p>');
+
+       editor.setContent('<p><em>test<span id="x">test <strong>123</strong></span><a href="123">123</a> 123</em></p>');
+       editor.selection.select(editor.dom.get('x'));
+       editor.execCommand('RemoveFormat');
+       equal(editor.getContent(), '<p><em>test</em><span id="x">test 123</span><em><a href="123">123</a> 123</em></p>');
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       indent : false,
+       entities : 'raw',
+       convert_urls : false,
+       valid_styles : {
+               '*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,padding-left,text-align,display'
+       },
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for tinymce.EditorCommands</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/EditorCommands.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceEnterKeyhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/EnterKey.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/EnterKey.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/EnterKey.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,1018 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for EnterKey</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor, rng;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.EnterKey", {
+       autostart: false,
+       setup: function() {
+               editor.settings.forced_root_block = 'p';
+               editor.settings.forced_root_block_attrs = null;
+               editor.settings.end_container_on_empty_block = false;
+               editor.settings.br_in_pre = true;
+               editor.settings.keep_styles = true;
+               delete editor.settings.force_p_newlines;
+       }
+});
+
+function pressEnter(evt) {
+       var dom = editor.dom, target = editor.selection.getNode();
+
+       evt = tinymce.extend({keyCode: 13}, evt);
+
+       dom.fire(target, 'keydown', evt);
+       dom.fire(target, 'keypress', evt);
+       dom.fire(target, 'keyup', evt);
+}
+
+function trimBrsOnIE(html) {
+       return html.replace(/<br[^>]*>/gi, '');
+}
+
+test('Enter at end of H1', function() {
+       editor.setContent('<h1>abc</h1>');
+       setSelection('h1', 3);
+       pressEnter();
+       equal(editor.getContent(), '<h1>abc</h1><p>\u00a0</p>');
+       equal(editor.selection.getRng(true).startContainer.nodeName, 'P');
+});
+
+test('Enter in midde of H1', function() {
+       editor.setContent('<h1>abcd</h1>');
+       setSelection('h1', 2);
+       pressEnter();
+       equal(editor.getContent(), '<h1>ab</h1><h1>cd</h1>');
+       equal(editor.selection.getRng(true).startContainer.parentNode.nodeName, 'H1');
+});
+
+test('Enter before text after EM', function() {
+       editor.setContent('<p><em>a</em>b</p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 1);
+       pressEnter();
+       equal(editor.getContent(), '<p><em>a</em></p><p>b</p>');
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeValue, 'b');
+});
+
+test('Enter before first IMG in P', function() {
+       editor.setContent('<p><img alt="" src="about:blank" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><p><img src="about:blank" alt="" /></p>');
+});
+
+test('Enter before last IMG in P with text', function() {
+       editor.setContent('<p>abc<img alt="" src="about:blank" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 1);
+       pressEnter();
+       equal(editor.getContent(), '<p>abc</p><p><img src="about:blank" alt="" /></p>');
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startContainer.childNodes[rng.startOffset].nodeName, 'IMG');  
+});
+
+test('Enter before last IMG in P with IMG sibling', function() {
+       editor.setContent('<p><img src="about:blank" alt="" /><img src="about:blank" alt="" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 1);
+       pressEnter();
+       equal(editor.getContent(), '<p><img src="about:blank" alt="" /></p><p><img src="about:blank" alt="" /></p>');
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startContainer.childNodes[rng.startOffset].nodeName, 'IMG');  
+});
+
+test('Enter after last IMG in P', function() {
+       editor.setContent('<p>abc<img alt="" src="about:blank" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 2);
+       pressEnter();
+       equal(editor.getContent(), '<p>abc<img src="about:blank" alt="" /></p><p>\u00a0</p>');
+});
+
+test('Enter before last INPUT in P with text', function() {
+       editor.setContent('<p>abc<input type="text" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 1);
+       pressEnter();
+       equal(editor.getContent(), '<p>abc</p><p><input type="text" /></p>');
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startContainer.childNodes[rng.startOffset].nodeName, 'INPUT');        
+});
+
+test('Enter before last INPUT in P with IMG sibling', function() {
+       editor.setContent('<p><input type="text" /><input type="text" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 1);
+       pressEnter();
+       equal(editor.getContent(), '<p><input type="text" /></p><p><input type="text" /></p>');
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeName, 'P');
+       equal(rng.startContainer.childNodes[rng.startOffset].nodeName, 'INPUT');        
+});
+
+test('Enter after last INPUT in P', function() {
+       editor.setContent('<p>abc<input type="text" /></p>');
+       editor.selection.setCursorLocation(editor.getBody().firstChild, 2);
+       pressEnter();
+       equal(editor.getContent(), '<p>abc<input type="text" /></p><p>\u00a0</p>');
+});
+
+test('Enter at end of P', function() {
+       editor.setContent('<p>abc</p>');
+       setSelection('p', 3);
+       pressEnter();
+       equal(editor.getContent(), '<p>abc</p><p>\u00a0</p>');
+       equal(editor.selection.getRng(true).startContainer.nodeName, 'P');
+});
+
+test('Enter at end of EM inside P', function() {
+       editor.setContent('<p><em>abc</em></p>');
+       setSelection('em', 3);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML).replace(/<br([^>]+|)>|&nbsp;/g, ''), '<p><em>abc</em></p><p><em></em></p>');
+       equal(editor.selection.getRng(true).startContainer.nodeName, 'EM');
+});
+
+test('Enter at middle of EM inside P', function() {
+       editor.setContent('<p><em>abcd</em></p>');
+       setSelection('em', 2);
+       pressEnter();
+       equal(editor.getContent(), '<p><em>ab</em></p><p><em>cd</em></p>');
+       equal(editor.selection.getRng(true).startContainer.parentNode.nodeName, 'EM');
+});
+
+test('Enter at beginning EM inside P', function() {
+       editor.setContent('<p><em>abc</em></p>');
+       setSelection('em', 0);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML).replace(/<br([^>]+|)>|&nbsp;/g, ''), '<p><em></em></p><p><em>abc</em></p>');
+       equal(editor.selection.getRng(true).startContainer.nodeValue, 'abc');
+});
+
+test('Enter at end of STRONG in EM inside P', function() {
+       editor.setContent('<p><em><strong>abc</strong></em></p>');
+       setSelection('strong', 3);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML).replace(/<br([^>]+|)>|&nbsp;/g, ''), '<p><em><strong>abc</strong></em></p><p><em><strong></strong></em></p>');
+       equal(editor.selection.getRng(true).startContainer.nodeName, 'STRONG');
+});
+
+test('Enter at middle of STRONG in EM inside P', function() {
+       editor.setContent('<p><em><strong>abcd</strong></em></p>');
+       setSelection('strong', 2);
+       pressEnter();
+       equal(editor.getContent(), '<p><em><strong>ab</strong></em></p><p><em><strong>cd</strong></em></p>');
+       equal(editor.selection.getRng(true).startContainer.parentNode.nodeName, 'STRONG');
+});
+
+test('Enter at beginning STRONG in EM inside P', function() {
+       editor.setContent('<p><em><strong>abc</strong></em></p>');
+       setSelection('strong', 0);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML).replace(/<br([^>]+|)>|&nbsp;/g, ''), '<p><em><strong></strong></em></p><p><em><strong>abc</strong></em></p>');
+       equal(editor.selection.getRng(true).startContainer.nodeValue, 'abc');
+});
+
+test('Enter at beginning of P', function() {
+       editor.setContent('<p>abc</p>');
+       setSelection('p', 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><p>abc</p>');
+       equal(editor.selection.getRng(true).startContainer.nodeValue, 'abc');
+});
+
+test('Enter at middle of P with style, id and class attributes', function() {
+       editor.setContent('<p id="a" class="b" style="color:#000">abcd</p>');
+       setSelection('p', 2);
+       pressEnter();
+       equal(editor.getContent(), '<p id="a" class="b" style="color: #000;">ab</p><p class="b" style="color: #000;">cd</p>');
+       equal(editor.selection.getRng(true).startContainer.parentNode.nodeName, 'P');
+});
+
+test('Enter at a range between H1 and P', function() {
+       editor.setContent('<h1>abcd</h1><p>efgh</p>');
+       setSelection('h1', 2, 'p', 2);
+       pressEnter();
+       equal(editor.getContent(), '<h1>abgh</h1>');
+       equal(editor.selection.getNode().nodeName, 'H1');
+});
+
+test('Enter at end of H1 in HGROUP', function() {
+       editor.setContent('<hgroup><h1>abc</h1></hgroup>');
+       setSelection('h1', 3);
+       pressEnter();
+       equal(editor.getContent(), '<hgroup><h1>abc</h1><h1>\u00a0</h1></hgroup>');
+       equal(editor.selection.getRng(true).startContainer.nodeName, 'H1');
+});
+
+test('Enter inside empty TD', function() {
+       editor.getBody().innerHTML = '<table><tr><td></td></tr></table>';
+       setSelection('td', 0);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML).replace(/<br([^>]+|)>|&nbsp;/g, ''), '<table><tbody><tr><td><p></p><p></p></td></tr></tbody></table>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Shift+Enter inside STRONG inside TD with BR', function() {
+       editor.getBody().innerHTML = '<table><tr><td>d <strong>e</strong><br></td></tr></table>';
+       setSelection('strong', 1);
+       pressEnter({shiftKey: true});
+       equal(cleanHtml(editor.getBody().innerHTML), '<table><tbody><tr><td>d <strong>e<br></strong><br></td></tr></tbody></table>');
+       equal(editor.selection.getNode().nodeName, 'STRONG');
+});
+
+test('Enter inside middle of text node in body', function() {
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 2);
+       pressEnter();
+       equal(editor.getContent(), '<p>ab</p><p>cd</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside at beginning of text node in body', function() {
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><p>abcd</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside at end of text node in body', function() {
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 4);
+       pressEnter();
+       equal(editor.getContent(), '<p>abcd</p><p>\u00a0</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside empty body', function() {
+       editor.getBody().innerHTML = '';
+       setSelection('body', 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><p>\u00a0</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside empty li in beginning of ol', function() {
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li></li><li>a</li></ol>' : '<ol><li><br></li><li>a</li></ol>';
+       setSelection('li', 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><ol><li>a</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside empty li at the end of ol', function() {
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li>a</li><li></li></ol>' : '<ol><li>a</li><li><br></li></ol>';
+       setSelection('li:last', 0);
+       pressEnter();
+       equal(editor.getContent(), '<ol><li>a</li></ol><p>\u00a0</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Shift+Enter inside empty li in the middle of ol', function() {
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li>a</li><li></li><li>b</li></ol>' :  '<ol><li>a</li><li><br></li><li>b</li></ol>';
+       setSelection('li:nth-child(2)', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<ol><li>a</li></ol><p>\u00a0</p><ol><li>b</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Shift+Enter inside empty li in beginning of ol', function() {
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li></li><li>a</li></ol>' : '<ol><li><br></li><li>a</li></ol>';
+       setSelection('li', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p>\u00a0</p><ol><li>a</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Shift+Enter inside empty li at the end of ol', function() {
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li>a</li><li></li></ol>' : '<ol><li>a</li><li><br></li></ol>';
+       setSelection('li:last', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<ol><li>a</li></ol><p>\u00a0</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside empty li in the middle of ol with forced_root_block: false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li>a</li><li></li><li>b</li></ol>' :  '<ol><li>a</li><li><br></li><li>b</li></ol>';
+       setSelection('li:nth-child(2)', 0);
+       pressEnter();
+       equal(editor.getContent(), '<ol><li>a</li></ol><br /><ol><li>b</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'BODY');
+});
+
+test('Enter inside empty li in beginning of ol with forced_root_block: false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li></li><li>a</li></ol>' : '<ol><li><br></li><li>a</li></ol>';
+       setSelection('li', 0);
+       pressEnter();
+       equal(editor.getContent(), '<br /><ol><li>a</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'BODY');
+});
+
+test('Enter inside empty li at the end of ol with forced_root_block: false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li>a</li><li></li></ol>' : '<ol><li>a</li><li><br></li></ol>';
+       setSelection('li:last', 0);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<ol><li>a</li></ol><br>');
+       equal(editor.selection.getNode().nodeName, 'BODY');
+});
+
+test('Enter inside empty li in the middle of ol', function() {
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li>a</li><li></li><li>b</li></ol>' :  '<ol><li>a</li><li><br></li><li>b</li></ol>';
+       setSelection('li:nth-child(2)', 0);
+       pressEnter();
+       equal(editor.getContent(), '<ol><li>a</li></ol><p>\u00a0</p><ol><li>b</li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+// Nested lists in LI elements
+
+test('Enter inside empty LI in beginning of OL in LI', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li><br></li>' +
+                                       '<li>a</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       setSelection('li li', 0);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>' +
+                               '<ol>' +
+                                       '<li>a</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Enter inside empty LI in middle of OL in LI', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>a</li>' +
+                                       '<li><br></li>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       setSelection('li li:nth-child(2)', 0);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>a</li>' +
+                               '</ol>' +
+                       '</li>' +
+                       '<li>\u00a0' +
+                               '<ol>' +
+                                       '<li>b</li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Enter inside empty LI in end of OL in LI', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>a</li>' +
+                                       '<li><br></li>' +
+                               '</ol>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       setSelection('li li:last', 0);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a' +
+                               '<ol>' +
+                                       '<li>a</li>' +
+                               '</ol>' +
+                       '</li>' +
+                       '<li></li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+// Nested lists in OL elements
+
+test('Enter before nested list', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       setSelection('ol > li', 1);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li>\u00a0' +
+                               '<ul>' +
+                                       '<li>b</li>' +
+                                       '<li>c</li>' +
+                               '</ul>' +
+                       '</li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Enter inside empty LI in beginning of OL in OL', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li><br></li>' +
+                               '<li>a</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       setSelection('ol ol li', 0);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<li></li>' +
+                       '<ol>' +
+                               '<li>a</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Enter inside empty LI in middle of OL in OL', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>a</li>' +
+                               '<li><br></li>' +
+                               '<li>b</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       setSelection('ol ol li:nth-child(2)', 0);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>a</li>' +
+                       '</ol>' +
+                       '<li></li>' +
+                       '<ol>' +
+                               '<li>b</li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+test('Enter inside empty LI in end of OL in OL', function() {
+       editor.getBody().innerHTML = trimBrsOnIE(
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>a</li>' +
+                               '<li><br></li>' +
+                       '</ol>' +
+               '</ol>'
+       );
+
+       setSelection('ol ol li:last', 0);
+       editor.focus();
+       pressEnter();
+
+       equal(editor.getContent(), 
+               '<ol>' +
+                       '<li>a</li>' +
+                       '<ol>' +
+                               '<li>a</li>' +
+                       '</ol>' +
+                       '<li></li>' +
+               '</ol>'
+       );
+
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+
+
+test('Enter at beginning of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 0);
+       pressEnter();
+       equal(editor.getContent(), '<ol><li></li><li><p>abcd</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter inside middle of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 2);
+       pressEnter();
+       equal(editor.getContent(), '<ol><li><p>ab</p></li><li><p>cd</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Enter at end of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 4);
+       pressEnter();
+       equal(editor.getContent(), '<ol><li><p>abcd</p></li><li></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'LI');
+});
+
+
+test('Shift+Enter at beginning of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<ol><li><p><br />abcd</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Shift+Enter inside middle of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 2);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<ol><li><p>ab<br />cd</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Shift+Enter at end of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 4);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), (tinymce.isIE && tinymce.Env.ie < 11) ? '<ol><li><p>abcd</p></li></ol>' : '<ol><li><p>abcd<br /><br /></p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+
+test('Ctrl+Enter at beginning of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 0);
+       pressEnter({ctrlKey: true});
+       equal(editor.getContent(), '<ol><li><p>\u00a0</p><p>abcd</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Ctrl+Enter inside middle of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 2);
+       pressEnter({ctrlKey: true});
+       equal(editor.getContent(), '<ol><li><p>ab</p><p>cd</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Ctrl+Enter at end of P inside LI', function() {
+       editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
+       setSelection('p', 4);
+       pressEnter({ctrlKey: true});
+       equal(editor.getContent(), '<ol><li><p>abcd</p><p>\u00a0</p></li></ol>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+
+test('Enter in the middle of text in P with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<p>abc</p>';
+       setSelection('p', 2);
+       pressEnter();
+       equal(editor.getContent(), '<p>ab<br />c</p>');
+});
+
+test('Enter at the end of text in P with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<p>abc</p>';
+       setSelection('p', 3);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), (tinymce.isIE && tinymce.Env.ie < 11) ? '<p>abc<br></p>' : '<p>abc<br><br></p>');
+});
+
+test('Enter at the middle of text in BODY with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 2);
+       editor.focus();
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), 'ab<br>cd');
+});
+
+test('Enter at the beginning of text in BODY with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 0);
+       editor.focus();
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<br>abcd');
+});
+
+test('Enter at the end of text in BODY with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 4);
+       editor.focus();
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), (tinymce.isIE && tinymce.Env.ie < 11) ? 'abcd<br>' : 'abcd<br><br>');
+});
+
+test('Enter in empty P at the end of a blockquote and end_container_on_empty_block: true', function() {
+       editor.settings.end_container_on_empty_block = true;
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<blockquote><p>abc</p><p></p></blockquote>' : '<blockquote><p>abc</p><p><br></p></blockquote>';
+       setSelection('p:last', 0);
+       pressEnter();
+       equal(editor.getContent(), '<blockquote><p>abc</p></blockquote><p>\u00a0</p>');
+});
+
+test('Enter in empty P at the beginning of a blockquote and end_container_on_empty_block: true', function() {
+       editor.settings.end_container_on_empty_block = true;
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<blockquote><p></p><p>abc</p></blockquote>' : '<blockquote><p><br></p><p>abc</p></blockquote>';
+       setSelection('p', 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><blockquote><p>abc</p></blockquote>');
+});
+
+test('Enter in empty P at in the middle of a blockquote and end_container_on_empty_block: true', function() {
+       editor.settings.end_container_on_empty_block = true;
+       editor.getBody().innerHTML = (tinymce.isIE && tinymce.Env.ie < 11) ? '<blockquote><p>abc</p><p></p><p>123</p></blockquote>' : '<blockquote><p>abc</p><p><br></p><p>123</p></blockquote>';
+       setSelection('p:nth-child(2)', 0);
+       pressEnter();
+       equal(editor.getContent(), '<blockquote><p>abc</p></blockquote><p>\u00a0</p><blockquote><p>123</p></blockquote>');
+});
+
+test('Enter inside empty P with empty P siblings', function() {
+       // Tests that a workaround for an IE bug is working correctly
+       editor.getBody().innerHTML = '<p></p><p></p><p>X</p>';
+       setSelection('p', 0);
+       pressEnter();
+       equal(editor.getContent(), '<p>\u00a0</p><p>\u00a0</p><p>\u00a0</p><p>X</p>');
+});
+
+test('Enter at end of H1 with forced_root_block_attrs', function() {
+       editor.settings.forced_root_block_attrs = {"class": "class1"};
+       editor.getBody().innerHTML = '<h1>a</h1>';
+       setSelection('h1', 1);
+       pressEnter();
+       equal(editor.getContent(), '<h1>a</h1><p class="class1">\u00a0</p>');
+});
+
+test('Shift+Enter at beginning of P', function() {
+       editor.getBody().innerHTML = '<p>abc</p>';
+       setSelection('p', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p><br />abc</p>');
+});
+
+test('Shift+Enter in the middle of P', function() {
+       editor.getBody().innerHTML = '<p>abcd</p>';
+       setSelection('p', 2);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p>ab<br />cd</p>');
+});
+
+test('Shift+Enter at the end of P', function() {
+       editor.getBody().innerHTML = '<p>abcd</p>';
+       setSelection('p', 4);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), (tinymce.isIE && tinymce.Env.ie < 11) ? '<p>abcd</p>' : '<p>abcd<br /><br /></p>');
+});
+
+test('Shift+Enter in the middle of B with a BR after it', function() {
+       editor.getBody().innerHTML = '<p><b>abcd</b><br></p>';
+       setSelection('b', 2);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p><b>ab<br />cd</b></p>');
+});
+
+test('Shift+Enter at the end of B with a BR after it', function() {
+       editor.getBody().innerHTML = '<p><b>abcd</b><br></p>';
+       setSelection('b', 4);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p><b>abcd<br /></b></p>');
+});
+
+test('Enter in beginning of PRE', function() {
+       editor.getBody().innerHTML = '<pre>abc</pre>';
+       setSelection('pre', 0);
+       pressEnter();
+       equal(editor.getContent(), '<pre><br />abc</pre>');
+});
+
+test('Enter in the middle of PRE', function() {
+       editor.getBody().innerHTML = '<pre>abcd</pre>';
+       setSelection('pre', 2);
+       pressEnter();
+       equal(editor.getContent(), '<pre>ab<br />cd</pre>');
+});
+
+test('Enter at the end of PRE', function() {
+       editor.getBody().innerHTML = '<pre>abcd</pre>';
+       setSelection('pre', 4);
+       pressEnter();
+       equal(editor.getContent(), (tinymce.isIE && tinymce.Env.ie < 11) ? '<pre>abcd</pre>' : '<pre>abcd<br /><br /></pre>');
+});
+
+test('Enter in beginning of PRE and br_in_pre: false', function() {
+       editor.settings.br_in_pre = false;
+       editor.getBody().innerHTML = '<pre>abc</pre>';
+       setSelection('pre', 0);
+       pressEnter();
+       equal(editor.getContent(), '<pre>\u00a0</pre><pre>abc</pre>');
+});
+
+test('Enter in the middle of PRE and br_in_pre: false', function() {
+       editor.settings.br_in_pre = false;
+       editor.getBody().innerHTML = '<pre>abcd</pre>';
+       setSelection('pre', 2);
+       pressEnter();
+       equal(editor.getContent(), '<pre>ab</pre><pre>cd</pre>');
+});
+
+test('Enter at the end of PRE and br_in_pre: false', function() {
+       editor.settings.br_in_pre = false;
+       editor.getBody().innerHTML = '<pre>abcd</pre>';
+       setSelection('pre', 4);
+       pressEnter();
+       equal(editor.getContent(), '<pre>abcd</pre><p>\u00a0</p>');
+});
+
+test('Shift+Enter in beginning of PRE', function() {
+       editor.getBody().innerHTML = '<pre>abc</pre>';
+       setSelection('pre', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<pre>\u00a0</pre><pre>abc</pre>');
+});
+
+test('Shift+Enter in the middle of PRE', function() {
+       editor.getBody().innerHTML = '<pre>abcd</pre>';
+       setSelection('pre', 2);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<pre>ab</pre><pre>cd</pre>');
+});
+
+test('Shift+Enter at the end of PRE', function() {
+       editor.getBody().innerHTML = '<pre>abcd</pre>';
+       setSelection('pre', 4);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<pre>abcd</pre><p>\u00a0</p>');
+});
+
+test('Shift+Enter in beginning of P with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<p>abc</p>';
+       setSelection('p', 0);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p>\u00a0</p><p>abc</p>');
+});
+
+test('Shift+Enter in middle of P with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<p>abcd</p>';
+       setSelection('p', 2);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p>ab</p><p>cd</p>');
+});
+
+test('Shift+Enter at the end of P with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<p>abc</p>';
+       setSelection('p', 3);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p>abc</p><p>\u00a0</p>');
+});
+
+test('Shift+Enter in body with forced_root_block set to false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = 'abcd';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 2);
+       rng.setEnd(editor.getBody().firstChild, 2);
+       editor.selection.setRng(rng);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<p>ab</p><p>cd</p>');
+});
+
+test('Enter at the end of DIV layer', function() {
+       editor.settings.br_in_pre = false;
+       editor.setContent('<div style="position: absolute; top: 1px; left: 2px;">abcd</div>');
+       setSelection('div', 4);
+       pressEnter();
+       equal(editor.getContent(), '<div style="position: absolute; top: 1px; left: 2px;"><p>abcd</p><p>\u00a0</p></div>');
+});
+
+test('Enter in div inside contentEditable:false div', function() {
+       editor.getBody().innerHTML = '<div data-mce-contenteditable="false"><div>abcd</div></div>';
+       setSelection('div div', 2);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<div data-mce-contenteditable="false"><div>abcd</div></div>');
+});
+
+test('Enter in div with contentEditable:true inside contentEditable:false div', function() {
+       editor.getBody().innerHTML = '<div data-mce-contenteditable="false"><div data-mce-contenteditable="true">abcd</div></div>';
+       setSelection('div div', 2);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<div data-mce-contenteditable="false"><div data-mce-contenteditable="true"><p>ab</p><p>cd</p></div></div>');
+});
+
+test('Enter in span with contentEditable:true inside contentEditable:false div', function() {
+       editor.getBody().innerHTML = '<div data-mce-contenteditable="false"><span data-mce-contenteditable="true">abcd</span></div>';
+       setSelection('span', 2);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<div data-mce-contenteditable="false"><span data-mce-contenteditable="true">abcd</span></div>');
+});
+
+test('Shift+Enter in span with contentEditable:true inside contentEditable:false div', function() {
+       editor.getBody().innerHTML = '<div data-mce-contenteditable="false"><span data-mce-contenteditable="true">abcd</span></div>';
+       setSelection('span', 2);
+       pressEnter({shiftKey: true});
+       equal(cleanHtml(editor.getBody().innerHTML), '<div data-mce-contenteditable="false"><span data-mce-contenteditable="true">ab<br>cd</span></div>');
+});
+
+test('Enter in span with contentEditable:true inside contentEditable:false div and forced_root_block: false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<div data-mce-contenteditable="false"><span data-mce-contenteditable="true">abcd</span></div>';
+       setSelection('span', 2);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<div data-mce-contenteditable="false"><span data-mce-contenteditable="true">ab<br>cd</span></div>');
+});
+
+test('Enter in em within contentEditable:true div inside contentEditable:false div', function() {
+       editor.getBody().innerHTML = '<div data-mce-contenteditable="false"><div data-mce-contenteditable="true"><em>abcd</em></div></div>';
+       setSelection('em', 2);
+       pressEnter();
+       equal(cleanHtml(editor.getBody().innerHTML), '<div data-mce-contenteditable="false"><div data-mce-contenteditable="true"><p><em>ab</em></p><p><em>cd</em></p></div></div>');
+});
+
+test('Enter at end of text in a span inside a P and keep_styles: false', function() {
+       editor.settings.keep_styles = false;
+       editor.getBody().innerHTML = '<p><em><span style="font-size: 13px;">X</span></em></p>';
+       setSelection('span', 1);
+       pressEnter();
+       equal(editor.getContent(), '<p><em><span style="font-size: 13px;">X</span></em></p><p>\u00a0</p>');
+});
+
+test('Shift+enter in LI when forced_root_block: false', function() {
+       editor.settings.forced_root_block = false;
+       editor.getBody().innerHTML = '<ul><li>text</li></ul>';
+       setSelection('li', 2);
+       pressEnter({shiftKey: true});
+       equal(editor.getContent(), '<ul><li>te<br />xt</li></ul>');
+});
+
+test('Enter when forced_root_block: false and force_p_newlines : true', function() {
+       editor.settings.forced_root_block = false;
+       editor.settings.force_p_newlines = true;
+       editor.getBody().innerHTML = 'text';
+       setSelection('body', 2);
+       pressEnter();
+       equal(editor.getContent(), '<p>te</p><p>xt</p>');
+});
+
+test('Enter before BR between DIVs', function() {
+       editor.getBody().innerHTML = '<div>a<span>b</span>c</div><br /><div>d</div>';
+       var rng = editor.dom.createRng();
+       rng.setStartBefore(editor.dom.select('br')[0]);
+       rng.setEndBefore(editor.dom.select('br')[0]);
+       editor.selection.setRng(rng);
+       pressEnter();
+       equal(editor.getContent(), '<div>a<span>b</span>c</div><p>\u00a0</p><p>\u00a0</p><div>d</div>');
+});
+
+// Only test these on modern browsers
+if (window.getSelection) {
+       test('Enter behind table element', function() {
+               var rng = editor.dom.createRng();
+
+               editor.getBody().innerHTML = '<table><tbody><td>x</td></tbody></table>';
+               rng.setStartAfter(editor.getBody().lastChild);
+               rng.setEndAfter(editor.getBody().lastChild);
+               editor.selection.setRng(rng);
+
+               pressEnter();
+               equal(editor.getContent(), '<table><tbody><tr><td>x</td></tr></tbody></table><p>\u00a0</p>');
+       });
+
+       test('Enter before table element', function() {
+               var rng = editor.dom.createRng();
+
+               editor.getBody().innerHTML = '<table><tbody><td>x</td></tbody></table>';
+               rng.setStartBefore(editor.getBody().lastChild);
+               rng.setEndBefore(editor.getBody().lastChild);
+               editor.selection.setRng(rng);
+
+               pressEnter();
+               equal(editor.getContent(), '<p>\u00a0</p><table><tbody><tr><td>x</td></tr></tbody></table>');
+       });
+
+       test('Enter behind table followed by a p', function() {
+               var rng = editor.dom.createRng();
+
+               editor.getBody().innerHTML = '<table><tbody><td>x</td></tbody></table><p>x</p>';
+               rng.setStartAfter(editor.getBody().firstChild);
+               rng.setEndAfter(editor.getBody().firstChild);
+               editor.selection.setRng(rng);
+
+               pressEnter();
+               equal(editor.getContent(), '<table><tbody><tr><td>x</td></tr></tbody></table><p>\u00a0</p><p>x</p>');
+       });
+
+       test('Enter before table element preceded by a p', function() {
+               var rng = editor.dom.createRng();
+
+               editor.getBody().innerHTML = '<p>x</p><table><tbody><td>x</td></tbody></table>';
+               rng.setStartBefore(editor.getBody().lastChild);
+               rng.setStartBefore(editor.getBody().lastChild);
+               editor.selection.setRng(rng);
+
+               pressEnter();
+               equal(editor.getContent(), '<p>x</p><p>\u00a0</p><table><tbody><tr><td>x</td></tr></tbody></table>');
+       });
+}
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       indent : false,
+       schema: 'html5',
+       entities : 'raw',
+       extended_valid_elements: 'div[id|style|contenteditable],span[id|style|contenteditable]',
+       valid_styles : {
+               '*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left'
+       },
+       disable_nodechange: true,
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for tinymce.EnterKey</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/EnterKey.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceForceBlockshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ForceBlocks.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ForceBlocks.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ForceBlocks.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,116 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.ForceBlocks</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.ForceBlocks", {
+       autostart: false,
+       setup: function() {
+               editor.settings.forced_root_block = 'p';
+               editor.settings.forced_root_block_attrs = null;
+       }
+});
+
+function pressArrowKey(evt) {
+       var dom = editor.dom, target = editor.selection.getNode();
+
+       evt = tinymce.extend({keyCode: 37}, evt);
+
+       dom.fire(target, 'keydown', evt);
+       dom.fire(target, 'keypress', evt);
+       dom.fire(target, 'keyup', evt);
+}
+
+test('Wrap single root text node in P', function() {
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 2);
+       pressArrowKey();
+       equal(cleanHtml(editor.getBody().innerHTML), '<p>abcd</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Wrap single root text node in P with attrs', function() {
+       editor.settings.forced_root_block_attrs = {"class": "class1"};
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 2);
+       pressArrowKey();
+       equal(editor.getContent(), '<p class="class1">abcd</p>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Wrap single root text node in P but not table sibling', function() {
+       editor.getBody().innerHTML = 'abcd<table><tr><td>x</td></tr></table>';
+       setSelection('body', 2);
+       pressArrowKey();
+       equal(cleanHtml(editor.getBody().innerHTML), '<p>abcd</p><table><tbody><tr><td>x</td></tr></tbody></table>');
+       equal(editor.selection.getNode().nodeName, 'P');
+});
+
+test('Wrap root em in P but not table sibling', function() {
+       editor.getBody().innerHTML = '<em>abcd</em><table><tr><td>x</td></tr></table>';
+       setSelection('em', 2);
+       pressArrowKey();
+       equal(cleanHtml(editor.getBody().innerHTML), '<p><em>abcd</em></p><table><tbody><tr><td>x</td></tr></tbody></table>');
+       equal(editor.selection.getNode().nodeName, 'EM');
+});
+
+test('Wrap single root text node in DIV', function() {
+       editor.settings.forced_root_block = 'div';
+       editor.getBody().innerHTML = 'abcd';
+       setSelection('body', 2);
+       pressArrowKey();
+       equal(cleanHtml(editor.getBody().innerHTML), '<div>abcd</div>');
+       equal(editor.selection.getNode().nodeName, 'DIV');
+});
+
+test('Remove empty root text nodes', function() {
+       var body = editor.getBody();
+
+       editor.settings.forced_root_block = 'div';
+       editor.getBody().innerHTML = 'abcd<div>abcd</div>';
+       setSelection('body', 2);
+       body.insertBefore(editor.getDoc().createTextNode(''), body.firstChild);
+       body.appendChild(editor.getDoc().createTextNode(''));
+       pressArrowKey();
+       equal(cleanHtml(body.innerHTML), '<div>abcd</div><div>abcd</div>');
+       equal(editor.selection.getNode().nodeName, 'DIV');
+       equal(body.childNodes.length, 2);
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       indent : false,
+       schema: 'html5',
+       entities : 'raw',
+       valid_styles : {
+               '*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+       },
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for tinymce.ForceBlocks</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ForceBlocks.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceFormatter_applyhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/Formatter_apply.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/Formatter_apply.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/Formatter_apply.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,1228 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for apply formatting</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor, inlineEditor, rng, format;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("Apply formatting", {
+       autostart: false
+});
+
+function getContent() {
+       return editor.getContent().toLowerCase().replace(/[\r]+/g, '');
+};
+
+test('apply inline to a list', function(){
+       editor.formatter.register('format', {inline : 'b', toggle: false});
+       editor.getBody().innerHTML = '<p>1234</p><ul><li>first element</li><li>second element</li></ul><p>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[1].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p><ul><li><b>first element</b></li><li><b>second element</b></li></ul><p><b>5678</b></p>', 'selection of a list');
+});
+
+test('Toggle OFF - Inline element on selected text', function() {
+       // Toggle OFF - Inline element on selected text
+       editor.formatter.register('format', {inline : 'b', toggle: false});
+       editor.getBody().innerHTML = '<p><b>1234</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.toggle('format');
+       equal(getContent(), '<p><b>1234</b></p>');
+});
+
+test('Toggle OFF - Inline element on partially selected text', function() {
+       // Toggle OFF - Inline element on partially selected text
+       editor.formatter.register('format', {inline : 'b', toggle: 0});
+       editor.getBody().innerHTML = '<p>1<b>23</b>4</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 2);
+       editor.selection.setRng(rng);
+       editor.formatter.toggle('format');
+       equal(getContent(), '<p>1<b>23</b>4</p>');
+});
+
+test('Toggle OFF - Inline element on partially selected text in start/end elements', function() {
+       // Toggle OFF - Inline element on partially selected text in start/end elements
+       editor.formatter.register('format', {inline : 'b', toggle: false});
+       editor.getBody().innerHTML = '<p>1<b>234</b></p><p><b>123</b>4</p>';//'<p>1234</p><p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[1].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.toggle('format');
+       equal(getContent(), '<p>1<b>234</b></p><p><b>123</b>4</p>');
+});
+
+test('Toggle ON - NO inline element on selected text', function() {
+       // Inline element on selected text
+       editor.formatter.register('format', {inline : 'b', toggle: true});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p>', 'Inline element on selected text');
+       editor.formatter.toggle('format');
+       equal(getContent(), '<p>1234</p>', 'Toggle ON - NO inline element on selected text');
+});
+
+test('Selection spanning from within format to outside format with toggle off', function() {
+       editor.formatter.register('format', {inline : 'b', toggle: false});
+       editor.getBody().innerHTML = '<p><b>12</b>34</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].lastChild, 2);
+       editor.selection.setRng(rng);
+       editor.formatter.toggle('format');
+       equal(getContent(), '<p><b>1234</b></p>', 'Extend formating if start of selection is already formatted');
+});
+
+test('Inline element on partially selected text', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p>1<b>23</b>4</p>', 'Inline element on partially selected text');
+       editor.formatter.toggle('format');
+       equal(getContent(), '<p>1234</p>', 'Toggle ON - NO inline element on partially selected text');
+});
+
+test('Inline element on partially selected text in start/end elements', function() {
+       // Inline element on partially selected text in start/end elements
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234</p><p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[1].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p>1<b>234</b></p><p><b>123</b>4</p>');
+});
+
+test('Inline element on selected element', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p>', 'Inline element on selected element');
+});
+
+test('Inline element on multiple selected elements', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234</p><p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p><p><b>1234</b></p>', 'Inline element on multiple selected elements');
+});
+
+test('Inline element on multiple selected elements with various childnodes', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><em>1234</em>5678<span>9</span></p><p><em>1234</em>5678<span>9</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b><em>1234</em>5678<span>9</span></b></p><p><b><em>1234</em>5678<span>9</span></b></p>', 'Inline element on multiple selected elements with various childnodes');
+});
+
+test('Inline element with attributes', function() {
+       editor.formatter.register('format', {inline : 'b', attributes : {title : 'value1', id : 'value2'}});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b id="value2" title="value1">1234</b></p>', 'Inline element with attributes');
+});
+
+test('Inline element with styles', function() {
+       editor.formatter.register('format', {inline : 'b', styles : {color : '#ff0000', fontSize : '10px'}});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b style=\"color: #ff0000; font-size: 10px;\">1234</b></p>', 'Inline element with styles');
+});
+
+test('Inline element with attributes and styles', function() {
+       editor.formatter.register('format', {inline : 'b', attributes : {title : 'value1', id : 'value2'}, styles : {color : '#ff0000', fontSize : '10px'}});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b id="value2" style="color: #ff0000; font-size: 10px;" title="value1">1234</b></p>', 'Inline element with attributes and styles');
+});
+
+test('Inline element with wrapable parents', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>x<em><span>1234</span></em>y</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p>x<b><em><span>1234</span></em></b>y</p>', 'Inline element with wrapable parents');
+});
+
+test('Inline element with redundant child', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p>', 'Inline element with redundant child');
+});
+
+test('Inline element with redundant parent', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>a<em>1234</em>b</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('em')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>a<em>1234</em>b</b></p>', 'Inline element with redundant parent');
+});
+
+test('Inline element with redundant child of similar type 1', function() {
+       editor.formatter.register('format', [
+               {inline : 'b'},
+               {inline : 'strong'}
+       ]);
+       editor.getBody().innerHTML = '<p>a<strong>1234</strong>b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 3);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>a1234b</b></p>', 'Inline element with redundant child of similar type 1');
+});
+
+test('Inline element with redundant child of similar type 2', function() {
+       editor.formatter.register('format', [
+               {inline : 'b'},
+               {inline : 'span', styles : {fontWeight : 'bold'}}
+       ]);
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p>', 'Inline element with redundant child of similar type 2');
+});
+
+test('Inline element with redundant children of similar types', function() {
+       editor.formatter.register('format', [
+               {inline : 'b'},
+               {inline : 'strong'},
+               {inline : 'span', styles : {fontWeight : 'bold'}}
+       ]);
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold">a<strong>1234</strong><b>5678</b>b</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>a12345678b</b></p>', 'Inline element with redundant children of similar types');
+});
+
+test('Inline element with redundant parent 1', function() {
+       editor.formatter.register('format', [
+               {inline : 'b'},
+               {inline : 'strong'}
+       ]);
+       editor.getBody().innerHTML = '<p><strong>a<em>1234</em>b</strong></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('em')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><strong>a<em>1234</em>b</strong></p>', 'Inline element with redundant parent 1');
+});
+
+test('Inline element with redundant parent 2', function() {
+       editor.formatter.register('format', [
+               {inline : 'b'},
+               {inline : 'span', styles : {fontWeight : 'bold'}}
+       ]);
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold">a<em>1234</em>b</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('em')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="font-weight: bold;">a<em>1234</em>b</span></p>', 'Inline element with redundant parent 2');
+});
+
+test('Inline element with redundant parents of similar types', function() {
+       editor.formatter.register('format', [
+               {inline : 'b'},
+               {inline : 'strong'},
+               {inline : 'span', styles : {fontWeight : 'bold'}}
+       ]);
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold"><strong><b>a<em>1234</em>b</b></strong></span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('em')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="font-weight: bold;"><strong><b>a<em>1234</em>b</b></strong></span></p>', 'Inline element with redundant parents of similar types');
+});
+
+test('Inline element merged with parent and child', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>a<b>12<b>34</b>56</b>b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('b')[0].lastChild, 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p>a<b>123456</b>b</p>', 'Inline element merged with parent and child');
+});
+
+test('Inline element merged with child 1', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontWeight : 'bold'}});
+       editor.getBody().innerHTML = '<p>a<span style="font-weight:bold">1234</span>b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="font-weight: bold;">a1234b</span></p>', 'Inline element merged with child 1');
+});
+
+test('Inline element merged with child 2', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontWeight : 'bold'}});
+       editor.getBody().innerHTML = '<p>a<span style="font-weight:bold; color:#ff0000">1234</span>b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style=\"font-weight: bold;\">a<span style=\"color: #ff0000;\">1234</span>b</span></p>', 'Inline element merged with child 2');
+});
+
+test('Inline element merged with child 3', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontWeight : 'bold'}});
+       editor.getBody().innerHTML = '<p>a<span id="id" style="font-weight:bold">1234</span>b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style=\"font-weight: bold;\">a<span id=\"id\">1234</span>b</span></p>', 'Inline element merged with child 3');
+});
+
+test('Inline element merged with child 3', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontWeight : 'bold'}, merge : true});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="color: #ff0000; font-weight: bold;">1234</span></p>', 'Inline element merged with child 3');
+});
+
+test('Inline element merged with child 4', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {color : '#00ff00'}});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="color: #00ff00;">1234</span></p>', 'Inline element merged with child 4');
+});
+
+test('Inline element with attributes merged with child 1', function() {
+       editor.formatter.register('format', {inline : 'font', attributes : {face : 'arial'}, merge : true});
+       editor.getBody().innerHTML = '<p><font size="7">1234</font></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><font face="arial" size="7">1234</font></p>', 'Inline element with attributes merged with child 1');
+});
+
+test('Inline element with attributes merged with child 2', function() {
+       editor.formatter.register('format', {inline : 'font', attributes : {size : '7'}});
+       editor.getBody().innerHTML = '<p>a<font size="7">1234</font>b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><font size="7">a1234b</font></p>', 'Inline element with attributes merged with child 2');
+});
+
+test('Inline element merged with left sibling', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234</b>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].lastChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].lastChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>12345678</b></p>', 'Inline element merged with left sibling');
+});
+
+test('Inline element merged with right sibling', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234<b>5678</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>12345678</b></p>', 'Inline element merged with right sibling');
+});
+
+test('Inline element merged with left and right siblings', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>12</b>34<b>56</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].childNodes[1], 0);
+       rng.setEnd(editor.dom.select('p')[0].childNodes[1], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>123456</b></p>', 'Inline element merged with left and right siblings');
+});
+
+test('Don\'t merge siblings with whitespace between 1', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>a</b> b</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].lastChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].lastChild, 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>a</b> <b>b</b></p>', 'Don\'t merge siblings with whitespace between 1');
+});
+
+test('Don\'t merge siblings with whitespace between 1', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>a <b>b</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>a</b> <b>b</b></p>', 'Don\'t merge siblings with whitespace between 2');
+});
+
+test('Inline element not merged in exact mode', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {color : '#00ff00'}, exact : true});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="color: #00ff00;"><span style="color: #ff0000;">1234</span></span></p>', 'Inline element not merged in exact mode');
+});
+
+test('Inline element merged in exact mode', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {color : '#ff0000'}, exact : true});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style="color: #ff0000;">1234</span></p>', 'Inline element merged in exact mode');
+});
+
+test('Deep left branch', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><em><i><ins>1234</ins></i></em><em>text1</em><em>text2</em></p><p><em>5678</em></p><p>9012</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('ins')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[2].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><em><i><ins>1<b>234</b></ins></i></em><b><em>text1</em><em>text2</em></b></p><p><b><em>5678</em></b></p><p><b>9012</b></p>', 'Deep left branch');
+});
+
+test('Deep right branch', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>9012</p><p><em>5678</em></p><p><em><i><ins>1234</ins></i></em><em>text1</em><em>text2</em></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('em')[3].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>9012</b></p><p><b><em>5678</em></b></p><p><b><em><i><ins>1234</ins></i></em><em>text1</em></b><em><b>text</b>2</em></p>', 'Deep right branch');
+});
+
+test('Full element text selection on two elements with a table in the middle', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234</p><table><tbody><tr><td>123</td></tr></tbody></table><p>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[1].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><b>1234</b></p><table><tbody><tr><td><b>123</b></td></tr></tbody></table><p><b>5678</b></p>', 'Full element text selection on two elements with a table in the middle');
+});
+
+test('Inline element on selected text with variables', function() {
+       editor.formatter.register('format', {inline : 'b', styles : {color : '%color'}, attributes : {title : '%title'}}, {color : '#ff0000', title : 'title'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format', {color : '#ff0000', title : 'title'});
+       equal(getContent(), '<p><b style="color: #ff0000;" title="title">1234</b></p>', 'Inline element on selected text');
+});
+
+test('Remove redundant children', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontFamily : 'arial'}});
+       editor.getBody().innerHTML = '<p><span style="font-family: sans-serif;"><span style="font-family: palatino;">1</span>2<span style="font-family: verdana;">3</span>4</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><span style=\"font-family: ' + fontFace('arial') + ';\">1234</span></p>', 'Remove redundant children');
+});
+
+test('Inline element on selected text with function values', function() {
+       editor.formatter.register('format', {
+               inline : 'b',
+               styles : {
+                       color : function(vars) {
+                               return vars.color + '00ff';
+                       }
+               },
+               attributes : {
+                       title : function(vars) {
+                               return vars.title + '2';
+                       }
+               }
+       });
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format', {
+               color : '#ff',
+               title : 'title'
+       });
+       equal(getContent(), '<p><b style="color: #ff00ff;" title="title2">1234</b></p>', 'Inline element on selected text with function values');
+});
+
+test('Block element on selected text', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div>', 'Block element on selected text');
+});
+
+test('Block element on partially selected text', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div>', 'Block element on partially selected text');
+});
+
+test('Block element on selected element', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div>', 'Block element on selected element');
+});
+
+test('Block element on selected elements', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '<p>1234</p><p>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div><div>5678</div>', 'Block element on selected elements');
+});
+
+test('Block element on selected elements with attributes', function() {
+       editor.formatter.register('format', {block : 'div', attributes : {'title' : 'test'}});
+       editor.getBody().innerHTML = '<p>1234</p><p>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div title="test">1234</div><div title="test">5678</div>', 'Block element on selected elements with attributes');
+});
+
+test('Block element on nested element', function() {
+       editor.formatter.register('format', {block : 'p'});
+       editor.getBody().innerHTML = '<div><h1>1234</h1></div>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('h1')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('h1')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div><p>1234</p></div>', 'Block element on nested element');
+});
+
+test('Block element on selected non wrapped text 1', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '1234';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div>', 'Block element on selected non wrapped text 1');
+});
+
+test('Block element on selected non wrapped text 2', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '1234<br />4567<br />8910';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().lastChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div><div>4567</div><div>8910</div>', 'Block element on selected non wrapped text 2');
+});
+
+test('Block element on selected non wrapped text 3', function() {
+       editor.formatter.register('format', {block : 'div'});
+       editor.getBody().innerHTML = '<br />1234<br /><br />4567<br />8910<br />';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 7);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div>1234</div><div>4567</div><div>8910</div>', 'Block element on selected non wrapped text 3');
+});
+
+test('Block element wrapper 1', function() {
+       editor.formatter.register('format', {block : 'blockquote', wrapper : 1});
+       editor.getBody().innerHTML = '<h1>1234</h1><p>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('h1')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<blockquote><h1>1234</h1><p>5678</p></blockquote>', 'Block element wrapper 1');
+});
+
+test('Block element wrapper 2', function() {
+       editor.formatter.register('format', {block : 'blockquote', wrapper : 1});
+       editor.getBody().innerHTML = '<h1>1234</h1>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('h1')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('h1')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<blockquote><h1>1234</h1></blockquote>', 'Block element wrapper 2');
+});
+
+test('Block element wrapper 3', function() {
+       editor.formatter.register('format', {block : 'blockquote', wrapper : 1});
+       editor.getBody().innerHTML = '<br /><h1>1234</h1><br />';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 3);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<blockquote><h1>1234</h1></blockquote>', 'Block element wrapper 3');
+});
+
+test('Apply format on single element that matches a selector 1', function() {
+       editor.formatter.register('format', {selector : 'p', attributes : {title : 'test'}, styles : {'color' : '#ff0000'}, classes : 'a b c'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p class="a b c" style="color: #ff0000;" title="test">1234</p>', 'Apply format on single element that matches a selector');
+});
+
+test('Apply format on single element parent that matches a selector 2', function() {
+       editor.formatter.register('format', {selector : 'div', attributes : {title : 'test'}, styles : {'color' : '#ff0000'}, classes : 'a b c'});
+       editor.getBody().innerHTML = '<div><p>1234</p><p>test</p><p>1234</p></div>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('div')[0], 1);
+       rng.setEnd(editor.dom.select('div')[0], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div class="a b c" style="color: #ff0000;" title="test"><p>1234</p><p>test</p><p>1234</p></div>', 'Apply format on single element parent that matches a selector');
+});
+
+test('Apply format on multiple elements that matches a selector 2', function() {
+       editor.formatter.register('format', {selector : 'p', attributes : {title : 'test'}, styles : {'color' : '#ff0000'}, classes : 'a b c'});
+       editor.getBody().innerHTML = '<p>1234</p><div>test</div><p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[1].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p class="a b c" style="color: #ff0000;" title="test">1234</p><div>test</div><p class="a b c" style="color: #ff0000;" title="test">1234</p>', 'Apply format on multiple elements that matches a selector');
+});
+
+test('Apply format on top of existing selector element', function() {
+       editor.formatter.register('format', {selector : 'p', attributes : {title : 'test2'}, styles : {'color' : '#00ff00'}, classes : 'a b c'});
+       editor.getBody().innerHTML = '<p class=\"c d\" title=\"test\">1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p class="c d a b" style="color: #00ff00;" title="test2">1234</p>', 'Apply format on top of existing selector element');
+});
+
+test('Format on single li that matches a selector', function() {
+       editor.formatter.register('format', {inline : 'span', selector : 'li', attributes : {title : 'test'}, styles : {'color' : '#ff0000'}, classes : 'a b c'});
+       editor.getBody().innerHTML = '<div>text</div>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('div')[0], 0);
+       rng.setEnd(editor.dom.select('div')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div><span class="a b c" style="color: #ff0000;" title="test">text</span></div>', 'Apply format on single element that matches a selector');
+});
+
+test('Format on single div that matches a selector', function() {
+       editor.formatter.register('format', {inline : 'span', selector : 'div', attributes : {title : 'test'}, styles : {'color' : '#ff0000'}, classes : 'a b c'});
+       editor.getBody().innerHTML = '<div>text</div>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('div')[0], 0);
+       rng.setEnd(editor.dom.select('div')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<div class="a b c" style="color: #ff0000;" title="test">text</div>', 'Apply format on single element that matches a selector');
+});
+
+test('Bold and italics is applied to text that is not highlighted', function() {
+       rng = editor.dom.createRng();
+       editor.setContent('<p><span style="font-family: Arial;"><strong>test1 test2</strong> test3 test4 test5 test6</span></p>');
+       rng.setStart(editor.dom.select('strong')[0].firstChild, 6);
+       rng.setEnd(editor.dom.select('strong')[0].firstChild, 11);
+       editor.focus();
+       editor.selection.setRng(rng);
+       editor.execCommand('Italic');
+       equal(editor.getContent(), '<p><span style="font-family: Arial;"><strong>test1 <em>test2</em></strong> test3 test4 test5 test6</span></p>', 'Selected text should be bold.');
+});
+
+test('No wrapping of links', function() {
+       editor.setContent('<p>123<a href="#">abc</a>456</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].lastChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.formatter.register('format', {inline : 'span', styles : {color : '#FF0000'}, wrap_links : false});
+       editor.formatter.apply('format');
+
+       equal(editor.getContent(), '<p><span style="color: #ff0000;">123<a href="#"><span style="color: #ff0000;">abc</span></a>456</span></p>', 'Link should have it\'s own span.');
+});
+
+test('Color on link element', function() {
+       editor.setContent('<p><span style="font-size: 10px;">123<a href="#">abc</a>456</span></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].lastChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.formatter.register('format', {inline : 'span', styles : {color : '#FF0000'}, wrap_links : false});
+       editor.formatter.apply('format');
+
+       equal(editor.getContent(), '<p><span style="color: #ff0000; font-size: 10px;">123<a href="#"><span style="color: #ff0000;">abc</span></a>456</span></p>', 'Link should have it\'s own span.');
+});
+
+test("Applying formats in lists", function(){
+       editor.setContent('<ul><li>text<ul><li>nested</li></ul></li></ul>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('li')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('li')[0].firstChild, 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply("h1");
+       equal(editor.getContent(), '<ul><li><h1>text</h1><ul><li>nested</li></ul></li></ul>', "heading should not automatically apply to sublists");
+});
+
+test('Block format on li element', function() {
+       editor.setContent('<ul><li>text<ul><li>nested</li></ul></li></ul>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('li')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('li')[1].firstChild, 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply("h1");
+       equal(editor.getContent(), '<ul><li><h1>text</h1><ul><li><h1>nested</h1></li></ul></li></ul>', "heading should automatically apply to sublists, when selection spans the sublist");
+});
+
+test('Block on li element 2', function() {
+       editor.setContent('<ul><li>before<ul><li>nested</li></ul>after</li></ul>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('li')[0].lastChild, 1);
+       rng.setEnd(editor.dom.select('li')[0].lastChild, 2);
+       editor.selection.setRng(rng);
+       editor.formatter.apply("h1");
+       equal(editor.getContent(), '<ul><li>before<ul><li>nested</li></ul><h1>after</h1></li></ul>', "heading should automatically apply to sublists, when selection spans the sublist");
+});
+
+test('Block on li element 3', function() {
+       editor.setContent('<ul><li>before<ul><li>nested</li></ul>after</li></ul>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('li')[1].firstChild, 0);
+       rng.setEnd(editor.dom.select('li')[0].lastChild, 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply("h1");
+       equal(editor.getContent(), '<ul><li>before<ul><li><h1>nested</h1></li></ul><h1>after</h1></li></ul>', "heading should automatically apply to sublists, when selection spans the sublist");
+});
+
+test('Block on li element 4', function() {
+       editor.setContent('<ul><li>before<ul><li>nested</li></ul>after</li></ul>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('li')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('li')[0].lastChild, 1);
+       editor.selection.setRng(rng);
+       editor.formatter.apply("h1");
+       equal(editor.getContent(), '<ul><li><h1>before</h1><ul><li><h1>nested</h1></li></ul><h1>after</h1></li></ul>', "heading should apply correctly when selection is after a sublist");
+});
+
+test('Underline colors 1', function() {
+       editor.formatter.register('format', {inline: 'span', styles : {'color' : '#ff0000'}});
+       editor.setContent('<p><span style="font-family: \'arial black\'; text-decoration: underline;">test</span></p>');
+       editor.execCommand('SelectAll');
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><span style="color: #ff0000; font-family: \'arial black\'; text-decoration: underline;">test</span></p>', 'Coloring an underlined text should result in a colored underline');
+});
+
+test('Underline colors 2', function() {
+       editor.formatter.register('format', {inline: "span", exact: true, styles: {'textDecoration' : 'underline'}});
+       editor.setContent('<p><span style="font-family: \'arial black\'; color: rgb(255, 0, 0);">test</span></p>');
+       editor.execCommand('SelectAll');
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;"><span style="color: #ff0000; font-family: \'arial black\'; text-decoration: underline;">test</span></span></p>', 'Underlining colored text should result in a colored underline');
+});
+
+test('Underline colors 3', function() {
+       editor.formatter.register('format', {inline: "span", exact: true, styles: {'textDecoration' : 'underline'}});
+       editor.setContent('<p><span style="font-family: \'arial black\'; text-decoration: underline;"><em><strong>This is some <span style="color: rgb(255, 0, 0);">example</span></strong></em> text</span></p>');
+       editor.execCommand('SelectAll');
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;"><span style="font-family: \'arial black\';"><em><strong>This is some <span style="color: #ff0000; text-decoration: underline;">example</span></strong></em> text</span></span></p>', 'Underlining colored and underlined text should result in a colored underline');
+});
+
+test('Underline colors 4', function() {
+       editor.formatter.register('format', {inline: 'span', styles : {'color' : '#ff0000'}});
+       editor.setContent('<p style="font-size: 22pt;"><span style=\"text-decoration: underline;\"><span style=\"color: yellow; text-decoration: underline;\">yellowredyellow</span></span></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[1].firstChild, 6);
+       rng.setEnd(editor.dom.select('span')[1].firstChild, 9);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(getContent(), '<p style="font-size: 22pt;"><span style="text-decoration: underline;"><span style="color: yellow; text-decoration: underline;">yellow<span style="color: #ff0000; text-decoration: underline;">red</span>yellow</span></span></p>', 'Coloring an colored underdlined text should result in newly colored underline');
+});
+
+test('Underline colors 5', function() {
+       editor.formatter.register('format', {inline: "span", exact: true, styles: {'textDecoration' : 'underline'}});
+       editor.setContent('<p><span style="font-family: \'arial black\',\'avant garde\';"><em><strong>This is some <span style="color: rgb(255, 0, 0);">example</span></strong></em> text</span></p><p><span style="font-family: \'arial black\',\'avant garde\';"><em><strong>This is some <span style="color: rgb(255, 0, 0);">example</span></strong></em> text</span></p><p><span style="font-family: \'arial black\', \'avant garde\';"><em><strong>This is some <span style="color: rgb(255, 0, 0);">example</span></strong></em> text</span></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('strong')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[4].lastChild, 5);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;"><span style="font-family: \'arial black\',\'avant garde\';"><em><strong>This is some <span style="color: #ff0000; text-decoration: underline;">example</span></strong></em> text</span></span></p><p><span style="text-decoration: underline;"><span style="font-family: \'arial black\',\'avant garde\';"><em><strong>This is some <span style="color: #ff0000; text-decoration: underline;">example</span></strong></em> text</span></span></p><p><span style="text-decoration: underline;"><span style="font-family: \'arial black\', \'avant garde\';"><em><strong>This is some <span style="color: #ff0000; text-decoration: underline;">example</span></strong
 ></em> text</span></span></p>', 'Colored elements should be underlined when selection is across multiple paragraphs');
+});
+
+test('Underline colors 6', function() {
+       editor.formatter.register('format', {inline: 'span', exact: true, styles : {'color' : '#ff0000'}});
+       editor.setContent('<p><span style="text-decoration: underline;">This is some text.</span></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 8);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 12);
+       editor.selection.setRng(rng);
+       editor.formatter.apply('format');
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p><span style="text-decoration: underline;">This is some text.</span></p>', 'Children nodes that are underlined should be removed if their parent nodes are underlined');
+});
+
+test('Underline colors 7', function() {
+       editor.formatter.register('format', {inline: 'span', exact: true, styles : {'color' : '#ff0000'}});
+       editor.setContent('<p><span style="text-decoration: underline;">This is <span style="color: #ff0000; text-decoration: underline; background-color: #ff0000">some</span> text.</span></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[1].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[1].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p><span style=\"text-decoration: underline;\">This is <span style=\"background-color: #ff0000;\">some</span> text.</span></p>', 'Children nodes that are underlined should be removed if their parent nodes are underlined');
+});
+
+test('Caret format inside single block word', function() {
+       editor.setContent('<p>abc</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 2, 'p', 2);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><b>abc</b></p>');
+});
+
+test('Caret format inside first block word', function() {
+       editor.setContent('<p>abc 123</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 2, 'p', 2);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><b>abc</b> 123</p>');
+});
+
+test('Caret format inside last block word', function() {
+       editor.setContent('<p>abc 123</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 5, 'p', 5);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc <b>123</b></p>');
+});
+
+test('Caret format inside middle block word', function() {
+       editor.setContent('<p>abc 123 456</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 5, 'p', 5);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc <b>123</b> 456</p>');
+});
+
+test('Caret format on word separated by non breaking space', function() {
+       editor.setContent('<p>one&nbsp;two</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 1, 'p', 1);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><b>one</b>\u00a0two</p>');
+});
+
+test('Caret format inside single inline wrapped word', function() {
+       editor.setContent('<p>abc <em>123</em> 456</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('em', 1, 'em', 1);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc <b><em>123</em></b> 456</p>');
+});
+
+test('Caret format inside last inline wrapped word', function() {
+       editor.setContent('<p>abc <em>abc 123</em> 456</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('em', 5, 'em', 5);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc <em>abc <b>123</b></em> 456</p>');
+});
+
+test('Caret format before text', function() {
+       editor.setContent('<p>a</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 0, 'p', 0);
+       editor.formatter.apply('format');
+       type('b');
+       equal(editor.getContent(), '<p><b>b</b>a</p>');
+});
+
+test('Caret format after text', function() {
+       editor.setContent('<p>a</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 1, 'p', 1);
+       editor.formatter.apply('format');
+       type('b');
+       equal(editor.getContent(), '<p>a<b>b</b></p>');
+});
+
+test('Caret format and no key press', function() {
+       editor.setContent('<p>a</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 0, 'p', 0);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>a</p>');
+});
+
+test('Caret format and arrow left', function() {
+       editor.setContent('<p>a</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 0, 'p', 0);
+       editor.formatter.apply('format');
+       type({keyCode: 37});
+       equal(editor.getContent(), '<p>a</p>');
+});
+
+test('Caret format and arrow right', function() {
+       editor.setContent('<p>a</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('p', 0, 'p', 0);
+       editor.formatter.apply('format');
+       type({keyCode: 39});
+       equal(editor.getContent(), '<p>a</p>');
+});
+
+test('Caret format and backspace', function() {
+       var rng;
+
+       if (tinymce.isOpera) {
+               ok(true, "Skip Opera since faking backspace doesn't work.");
+               return;
+       }
+
+       editor.formatter.register('format', {inline: 'b'});
+
+       editor.setContent('<p>abc</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 3);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+
+       editor.formatter.apply('format');
+       type('\b');
+       equal(editor.getContent(), '<p>ab</p>');
+});
+
+test('Caret format on word in li with word in parent li before it', function() {
+       editor.setContent('<ul><li>one<ul><li>two</li></ul></li></ul>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('ul li li', 1, 'ul li li', 1);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<ul><li>one<ul><li><b>two</b></li></ul></li></ul>');
+});
+
+test('Selector format on whole contents', function() {
+       editor.setContent('<p>a</p>');
+       editor.formatter.register('format', {inline: 'span', selector: '*', classes: 'test'});
+       setSelection('p', 0, 'p', 1);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p class="test">a</p>');
+});
+
+test('format inline on contentEditable: false block', function() {
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p contenteditable="false">def</p>');
+       setSelection('p:nth-child(2)', 0, 'p:nth-child(2)', 3);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc</p><p>def</p>', 'Text is not bold');
+});
+
+test('format block on contentEditable: false block', function() {
+       editor.formatter.register('format', {block: 'h1'});
+       editor.setContent('<p>abc</p><p contenteditable="false">def</p>');
+       setSelection('p:nth-child(2)', 0, 'p:nth-child(2)', 3);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc</p><p>def</p>', 'P is not h1');
+});
+
+test('contentEditable: false on start and contentEditable: true on end', function() {
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p contenteditable="false">def</p><p>ghi</p>');
+       setSelection('p:nth-child(2)', 0, 'p:nth-child(3)', 3);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc</p><p>def</p><p><b>ghi</b></p>', 'Text in last paragraph is bold');
+});
+
+test('contentEditable: true on start and contentEditable: false on end', function() {
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p contenteditable="false">def</p>');
+       setSelection('p:nth-child(1)', 0, 'p:nth-child(2)', 3);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><b>abc</b></p><p>def</p>', 'Text in first paragraph is bold');
+});
+
+test('contentEditable: true inside contentEditable: false', function() {
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p contenteditable="false"><span contenteditable="true">def</span></p>');
+       setSelection('span', 0, 'span', 3);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p>abc</p><p><span><b>def</b></span></p>', 'Text is bold');
+});
+
+test('Del element wrapping blocks', function() {
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.formatter.register('format', {block : 'del', wrapper: true});
+       editor.formatter.apply('format');
+       equal(getContent(), '<del><p>a</p></del>');
+});
+
+test('Del element replacing block', function() {
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.formatter.register('format', {block : 'del'});
+       editor.formatter.apply('format');
+       equal(getContent(), '<del>a</del>');
+});
+
+test('Del element as inline', function() {
+       editor.setContent('<p>a</p>');
+       setSelection('p', 0, 'p', 1);
+       editor.formatter.register('format', {inline : 'del'});
+       editor.formatter.apply('format');
+       equal(getContent(), '<p><del>a</del></p>');
+});
+
+test('Align specified table element with collapsed: false and selection collapsed', function() {
+       editor.setContent('<table><tr><td>a</td></tr></table>');
+       setSelection('td', 0, 'td', 0);
+       editor.formatter.register('format', {selector: 'table', collapsed: false, styles: {'float': 'right'}});
+       editor.formatter.apply('format', {}, editor.getBody().firstChild);
+       equal(getContent(), '<table style="float: right;"><tbody><tr><td>a</td></tr></tbody></table>');
+});
+
+test('Bug #5134 - TinyMCE removes formatting tags in the getContent', function() {
+       editor.setContent('');
+       editor.formatter.register('format', {inline : 'strong', toggle: false});
+       editor.formatter.apply('format');
+       equal(getContent(), '', 'empty TinyMCE');
+       editor.selection.setContent('a');
+       equal(getContent(), '<strong>a</strong>', 'bold text inside TinyMCE');
+});
+
+test('Bug #5134 - TinyMCE removes formatting tags in the getContent - typing', function() {
+       editor.setContent('');
+       editor.formatter.register('format', {inline : 'strong', toggle: false});
+       editor.formatter.apply('format');
+       equal(getContent(), '', 'empty TinyMCE');
+       type('a');
+       equal(getContent(), '<strong>a</strong>', 'bold text inside TinyMCE');
+});
+
+test('Bug #5453 - TD contents with BR gets wrapped in block format', function() {
+       editor.setContent('<table><tr><td>abc<br />123</td></tr></table>');
+       setSelection('td', 1, 'td', 1);
+       editor.formatter.register('format', {block : 'h1'});
+       editor.formatter.apply('format');
+       equal(getContent(), '<table><tbody><tr><td><h1>abc</h1>123</td></tr></tbody></table>');
+});
+
+test('Bug #6471 - Merge left/right style properties', function() {
+       editor.formatter.register('format', {inline: 'span', styles: {fontWeight: 'bold'}});
+       editor.setContent('<p>abc</p>');
+       setSelection('p', 2, 'p', 3);
+       editor.formatter.apply('format');
+       setSelection('p', 1, 'p', 2);
+       editor.formatter.apply('format');
+       setSelection('p', 0, 'p', 1);
+       editor.formatter.apply('format');
+       equal(editor.getContent(), '<p><span style="font-weight: bold;">abc</span></p>');
+});
+
+test('Bug #6518 - Apply div blocks to inline editor paragraph', function() {
+       inlineEditor.setContent('<p>a</p><p>b</p>');
+       inlineEditor.selection.select(inlineEditor.getBody().firstChild, true);
+       inlineEditor.selection.collapse(true);
+       inlineEditor.formatter.register('format', {block: 'div'});
+       inlineEditor.formatter.apply('format');
+       equal(inlineEditor.getContent(), '<div>a</div><p>b</p>');
+});
+
+var url = document.location.href.substring( 0, document.location.href.lastIndexOf('tinymce/') );
+
+tinymce.init({
+       selector: "#elm1",
+       external_plugins: {
+               noneditable: url + 'external-plugins/noneditable/plugin.js'
+       },
+       add_unload_trigger: false,
+       indent: false,
+       theme_advanced_styles: 'test1=test1;test2=test2',
+       valid_elements: '@[contenteditable|id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong,b,em,i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codeba
 se|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big',
+       forced_root_block: '',
+       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'
+       },
+       init_instance_callback: function(ed) {
+               editor = ed;
+
+               if (inlineEditor) {
+                       QUnit.start();
+               }
+       }
+});
+
+tinymce.init({
+       selector: "#elm2",
+       inline: true,
+       external_plugins: {
+               noneditable: url + 'external-plugins/noneditable/plugin.js'
+       },
+       add_unload_trigger: false,
+       indent: false,
+       theme_advanced_styles: 'test1=test1;test2=test2',
+       forced_root_block: '',
+       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'
+       },
+       init_instance_callback: function(ed) {
+               inlineEditor = ed;
+
+               if (editor) {
+                       QUnit.start();
+               }
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for text formatting</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+       <div id="elm2"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/Formatter_apply.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceFormatter_checkhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/Formatter_check.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/Formatter_check.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/Formatter_check.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,271 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for check formatting</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script src="../js/utils.js"></script>
+<script>
+var editor, inlineEditor, rng, format;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("Check formatting", {
+       autostart: false
+});
+
+function getContent() {
+       return editor.getContent().toLowerCase().replace(/[\r\n]+/g, '');
+};
+
+test('Selected style element text', function() {
+       editor.formatter.register('bold', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('bold'), 'Selected style element text');
+});
+
+test('Selected style element with css styles', function() {
+       editor.formatter.register('color', {inline : 'span', styles : {color : '#ff0000'}});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('color'), 'Selected style element with css styles');
+});
+
+test('Selected style element with attributes', function() {
+       editor.formatter.register('fontsize', {inline : 'font', attributes : {size : '7'}});
+       editor.getBody().innerHTML = '<p><font size="7">1234</font></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('font')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('font')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('fontsize'), 'Selected style element with attributes');
+});
+
+test('Selected style element text multiple formats', function() {
+       editor.formatter.register('multiple', [
+               {inline : 'b'},
+               {inline : 'strong'}
+       ]);
+       editor.getBody().innerHTML = '<p><strong>1234</strong></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('strong')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('strong')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('multiple'), 'Selected style element text multiple formats');
+});
+
+test('Selected complex style element', function() {
+       editor.formatter.register('complex', {inline : 'span', styles : {fontWeight : 'bold'}});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000; font-weight:bold">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('complex'), 'Selected complex style element');
+});
+
+test('Selected non style element text', function() {
+       editor.formatter.register('bold', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(!editor.formatter.match('bold'), 'Selected non style element text');
+});
+
+test('Selected partial style element (start)', function() {
+       editor.formatter.register('bold', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234</b>5678</p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].lastChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('bold'), 'Selected partial style element (start)');
+});
+
+test('Selected partial style element (end)', function() {
+       editor.formatter.register('bold', {inline : 'b'});
+       editor.getBody().innerHTML = '<p>1234<b>5678</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[0].lastChild, 4);
+       editor.selection.setRng(rng);
+       ok(!editor.formatter.match('bold'), 'Selected partial style element (end)');
+});
+
+test('Selected element text with parent inline element', function() {
+       editor.formatter.register('bold', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b><em><span>1234</span></em></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('bold'), 'Selected element text with parent inline element');
+});
+
+test('Selected element match with variable', function() {
+       editor.formatter.register('complex', {inline : 'span', styles : {color : '%color'}});
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('complex', {color : '#ff0000'}), 'Selected element match with variable');
+});
+
+test('Selected element match with variable and function', function() {
+       editor.formatter.register('complex', {
+               inline : 'span',
+               styles : {
+                       color : function(vars) {
+                               return vars.color + '00';
+                       }
+               }
+       });
+
+       editor.getBody().innerHTML = '<p><span style="color:#ff0000">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       ok(editor.formatter.match('complex', {color : '#ff00'}), 'Selected element match with variable and function');
+});
+
+test('formatChanged simple format', function() {
+       var newState, newArgs;
+
+       editor.formatter.formatChanged('bold', function(state, args) {
+               newState = state;
+               newArgs = args;
+       });
+
+       editor.getBody().innerHTML = '<p>text</p>';
+       setSelection('p', 0, 'p', 4);
+
+       // Check apply
+       editor.formatter.apply('bold');
+       editor.nodeChanged();
+       ok(newState);
+       equal(newArgs.format, 'bold');
+       equal(newArgs.node, editor.getBody().firstChild.firstChild);
+       equal(newArgs.parents.length, 2);
+
+       // Check remove
+       editor.formatter.remove('bold');
+       editor.nodeChanged();
+       ok(!newState);
+       equal(newArgs.format, 'bold');
+       equal(newArgs.node, editor.getBody().firstChild);
+       equal(newArgs.parents.length, 1);
+});
+
+test('formatChanged complex format', function() {
+       var newState, newArgs;
+
+       editor.formatter.register('complex', {inline : 'span', styles : {color : '%color'}});
+
+       editor.formatter.formatChanged('complex', function(state, args) {
+               newState = state;
+               newArgs = args;
+       }, true);
+
+       editor.getBody().innerHTML = '<p>text</p>';
+       setSelection('p', 0, 'p', 4);
+
+       // Check apply
+       editor.formatter.apply('complex', {color: '#FF0000'});
+       editor.nodeChanged();
+       ok(newState);
+       equal(newArgs.format, 'complex');
+       equal(newArgs.node, editor.getBody().firstChild.firstChild);
+       equal(newArgs.parents.length, 2);
+
+       // Check remove
+       editor.formatter.remove('complex', {color: '#FF0000'});
+       editor.nodeChanged();
+       ok(!newState);
+       equal(newArgs.format, 'complex');
+       equal(newArgs.node, editor.getBody().firstChild);
+       equal(newArgs.parents.length, 1);
+});
+
+test('Match format on div block in inline mode', function() {
+       inlineEditor.setContent('<p>a</p><p>b</p>');
+       inlineEditor.execCommand('SelectAll');
+       ok(!inlineEditor.formatter.match('div'), 'Formatter.match on div says true');
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       theme_advanced_styles : 'test1=test1;test2=test2',
+       valid_elements : '@[id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong,b,em,i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codebase|*],param[nam
 e|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big',
+       fix_list_elements : 0,
+       fix_table_elements : 0,
+       entities : 'raw',
+       valid_styles : {
+               '*' : 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+       },
+       init_instance_callback : function(ed) {
+               editor = ed;
+
+               if (inlineEditor) {
+                       QUnit.start();
+               }
+       }
+});
+
+var url = document.location.href.substring( 0, document.location.href.lastIndexOf('tinymce/') );
+
+tinymce.init({
+       selector: "#elm2",
+       inline: true,
+       external_plugins: {
+               noneditable: url + 'external-plugins/noneditable/plugin.js'
+       },
+       add_unload_trigger: false,
+       indent: false,
+       theme_advanced_styles: 'test1=test1;test2=test2',
+       forced_root_block: '',
+       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'
+       },
+       init_instance_callback: function(ed) {
+               inlineEditor = ed;
+
+               if (editor) {
+                       QUnit.start();
+               }
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for text formatting</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+       <div id="elm2"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/Formatter_check.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceFormatter_removehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/Formatter_remove.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/Formatter_remove.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/Formatter_remove.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,401 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for remove formatting</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor, rng, format;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("Remove formatting", {
+       autostart: false
+});
+
+function getContent() {
+       return editor.getContent().toLowerCase().replace(/[\r]+/g, '');
+};
+
+test('Inline element on selected text', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p>1234</p>', 'Inline element on selected text');
+});
+
+test('Inline element on selected text with remove=all', function() {
+       editor.formatter.register('format', {selector : 'b', remove : 'all'});
+       editor.getBody().innerHTML = '<p><b title="text">1234</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p>1234</p>', 'Inline element on selected text with remove=all');
+});
+
+test('Inline element on selected text with remove=none', function() {
+       editor.formatter.register('format', {selector : 'span', styles : {fontWeight : 'bold'}, remove : 'none'});
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><span>1234</span></p>', 'Inline element on selected text with remove=none');
+});
+
+test('Inline element style where element is format root', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontWeight : 'bold'}});
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold; color:#FF0000"><em>1234</em></span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('em')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(),
+               '<p><span style="color: #ff0000; font-weight: bold;">' +
+               '<em>1</em></span><span style="color: #ff0000;"><em>23</em></span>' +
+               '<span style=\"color: #ff0000; font-weight: bold;\"><em>4' +
+               '</em></span></p>',
+       'Inline element style where element is format root');
+});
+
+test('Partially selected inline element text', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234</b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 2);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><b>12</b>34</p>', 'Partially selected inline element text');
+});
+
+test('Partially selected inline element text with children', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b><em><span>1234</span></em></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[0].firstChild, 2);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><b><em><span>12</span></em></b><em><span>34</span></em></p>', 'Partially selected inline element text with children');
+});
+
+test('Partially selected inline element text with complex children', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {fontWeight : 'bold'}});
+       editor.getBody().innerHTML = '<p><span style="font-weight:bold"><em><span style="color:#ff0000;font-weight:bold">1234</span></em></span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('span')[1].firstChild, 2);
+       rng.setEnd(editor.dom.select('span')[1].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><span style="font-weight: bold;"><em><span style="color: #ff0000; font-weight: bold;">12</span></em></span><em><span style="color: #ff0000;">34</span></em></p>', 'Partially selected inline element text with complex children');
+});
+
+test('Inline elements with exact flag', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {color : '#ff0000'}, exact : true});
+       editor.getBody().innerHTML = '<p><span style="font-size:10px;color:#ff0000">1234</span><span style="font-size:10px;color:#00ff00">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><span style="font-size: 10px;">1234</span><span style="color: #00ff00; font-size: 10px;">1234</span></p>', 'Inline elements with exact flag');
+});
+
+test('Inline elements with variables', function() {
+       editor.formatter.register('format', {inline : 'span', styles : {color : '%color'}, exact : true});
+       editor.getBody().innerHTML = '<p><span style="font-size:10px;color:#ff0000">1234</span><span style="font-size:10px;color:#00ff00">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format', {color : '#ff0000'});
+       equal(getContent(), '<p><span style="font-size: 10px;">1234</span><span style="color: #00ff00; font-size: 10px;">1234</span></p>', 'Inline elements on selected text with variables');
+});
+
+test('Inline elements with functions and variables', function() {
+       editor.formatter.register('format', {
+               inline : 'span',
+               styles : {
+                       color : function(vars) {
+                               return vars.color + "00";
+                       }
+               },
+               exact : true
+       });
+
+       editor.getBody().innerHTML = '<p><span style="font-size:10px;color:#ff0000">1234</span><span style="font-size:10px;color:#00ff00">1234</span></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('p')[0], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format', {
+               color : '#ff00'
+       });
+       equal(getContent(), '<p><span style="font-size: 10px;">1234</span><span style="color: #00ff00; font-size: 10px;">1234</span></p>', 'Inline elements with functions and variables');
+});
+
+test('End within start element', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b>1234<b>5678</b></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('b')[0], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p>12345678</p>', 'End within start element');
+});
+
+test('Start and end within similar format 1', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b><em><b>1234<b>5678</b></b></em></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0], 0);
+       rng.setEnd(editor.dom.select('b')[1], 2);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><em>12345678</em></p>', 'Start and end within similar format 1');
+});
+
+test('Start and end within similar format 2', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b><em><b>1234</b><b>5678</b></em></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0], 0);
+       rng.setEnd(editor.dom.select('em')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><em>1234</em><b><em><b>5678</b></em></b></p>', 'Start and end within similar format 2');
+});
+
+test('Start and end within similar format 3', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b><em><b>1234</b></em></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0], 0);
+       rng.setEnd(editor.dom.select('em')[0], 1);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><em>1234</em></p>', 'Start and end within similar format 3');
+});
+
+test('End within start', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       editor.getBody().innerHTML = '<p><b><em>x<b>abc</b>y</em></b></p>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0], 0);
+       rng.setEnd(editor.dom.select('b')[1].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><em>x</em><em>abc</em><b><em>y</em></b></p>', 'End within start');
+});
+
+test('Remove block format', function() {
+       editor.formatter.register('format', {block : 'h1'});
+       editor.getBody().innerHTML = '<h1>text</h1>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('h1')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('h1')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p>text</p>', 'Remove block format');
+});
+
+test('Remove wrapper block format', function() {
+       editor.formatter.register('format', {block : 'blockquote', wrapper : true});
+       editor.getBody().innerHTML = '<blockquote><p>text</p></blockquote>';
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p>text</p>', 'Remove wrapper block format');
+});
+
+test('Remove span format within block with style', function() {
+       editor.formatter.register('format', {selector : 'span', attributes : ['style', 'class'], remove : 'empty', split : true, expand : false, deep : true});
+       rng = editor.dom.createRng();
+       editor.getBody().innerHTML = '<p style="color:#ff0000"><span style="color:#00ff00">text</span></p>';
+       rng.setStart(editor.dom.select('span')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('span')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p style="color: #ff0000;"><span style="color: #00ff00;">t</span>ex<span style="color: #00ff00;">t</span></p>', 'Remove span format within block with style');
+});
+
+test('Remove and verify start element', function() {
+       editor.formatter.register('format', {inline : 'b'});
+       rng = editor.dom.createRng();
+       editor.getBody().innerHTML = '<p><b>text</b></p>';
+       rng.setStart(editor.dom.select('b')[0].firstChild, 1);
+       rng.setEnd(editor.dom.select('b')[0].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), '<p><b>t</b>ex<b>t</b></p>');
+       equal(editor.selection.getStart().nodeName, 'P');
+});
+
+test('Remove with selection collapsed ensure correct caret position', function() {
+       var content = '<p>test</p><p>testing</p>';
+
+       editor.formatter.register('format', {block : 'p'});
+       rng = editor.dom.createRng();
+       editor.getBody().innerHTML = content;
+       rng.setStart(editor.dom.select('p')[0].firstChild, 4);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 4);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(getContent(), content);
+       equal(editor.selection.getStart(), editor.dom.select('p')[0]);
+});
+
+test('Caret format at middle of text', function() {
+       editor.setContent('<p><b>abc</b></p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('b', 1, 'b', 1);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p>abc</p>');
+});
+
+test('Caret format at end of text', function() {
+       editor.setContent('<p><b>abc</b></p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('b', 3, 'b', 3);
+       editor.formatter.remove('format');
+       type('d');
+       equal(editor.getContent(), '<p><b>abc</b>d</p>');
+});
+
+test('Caret format at end of text inside other format', function() {
+       editor.setContent('<p><em><b>abc</b></em></p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('b', 3, 'b', 3);
+       editor.formatter.remove('format');
+       type('d');
+       equal(editor.getContent(), '<p><em><b>abc</b>d</em></p>');
+});
+
+test('Caret format at end of text inside other format with text after 1', function() {
+       editor.setContent('<p><em><b>abc</b></em>e</p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('b', 3, 'b', 3);
+       editor.formatter.remove('format');
+       type('d');
+       equal(editor.getContent(), '<p><em><b>abc</b>d</em>e</p>');
+});
+
+test('Caret format at end of text inside other format with text after 2', function() {
+       editor.setContent('<p><em><b>abc</b></em>e</p>');
+       editor.formatter.register('format', {inline: 'em'});
+       setSelection('b', 3, 'b', 3);
+       editor.formatter.remove('format');
+       type('d');
+       equal(editor.getContent(), '<p><em><b>abc</b></em><b>d</b>e</p>');
+});
+
+test('Caret format on second word in table cell', function() {
+       editor.setContent('<table><tbody><tr><td>one <b>two</b></td></tr></tbody></table>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('b', 2, 'b', 2);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<table><tbody><tr><td>one two</td></tr></tbody></table>');
+});
+
+test('contentEditable: false on start and contentEditable: true on end', function() {
+       var rng;
+
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p contenteditable="false"><b>def</b></p><p><b>ghj</b></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('b')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('b')[1].firstChild, 3);
+       editor.selection.setRng(rng);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p>abc</p><p><b>def</b></p><p>ghj</p>', 'Text in last paragraph is not bold');
+});
+
+test('contentEditable: true on start and contentEditable: false on end', function() {
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p><b>def</b></p><p contenteditable="false"><b>ghj</b></p>');
+       setSelection('p:nth-child(2) b', 0, 'p:last b', 3);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p>abc</p><p>def</p><p><b>ghj</b></p>', 'Text in first paragraph is not bold');
+});
+
+test('contentEditable: true inside contentEditable: false', function() {
+       editor.formatter.register('format', {inline: 'b'});
+       editor.setContent('<p>abc</p><p contenteditable="false"><span contenteditable="true"><b>def</b></span></p>');
+       setSelection('b', 0, 'b', 3);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p>abc</p><p><span>def</span></p>', 'Text is not bold');
+});
+
+test('remove format block on contentEditable: false block', function() {
+       editor.formatter.register('format', {block: 'h1'});
+       editor.setContent('<p>abc</p><h1 contenteditable="false">def</h1>');
+       setSelection('h1:nth-child(2)', 0, 'h1:nth-child(2)', 3);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p>abc</p><h1>def</h1>', 'H1 is still not h1');
+});
+
+/*
+test('Remove format bug 1', function() {
+       editor.setContent('<p><b>ab<em>cde</em>fgh</b></p>');
+       editor.formatter.register('format', {inline: 'b'});
+       setSelection('em', 0, 'em', 2);
+       editor.formatter.remove('format');
+       equal(editor.getContent(), '<p><b>ab</b><em>cd</em><b><em>e</em>fgh</b></p>');
+});
+*/
+
+var url = document.location.href.substring( 0, document.location.href.lastIndexOf('tinymce/') );
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       external_plugins: {
+               noneditable: url + 'external-plugins/noneditable/plugin.js'
+       },
+       indent : false,
+       add_unload_trigger : false,
+       theme_advanced_styles : 'test1=test1;test2=test2',
+       valid_elements : '@[contenteditable|id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong,b,em,i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codeb
 ase|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big',
+       fix_list_elements : 0,
+       fix_table_elements : 0,
+       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'
+       },
+       disable_nodechange: true,
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for text formatting</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/Formatter_remove.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceFormatter_robothtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/Formatter_robot.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/Formatter_robot.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/Formatter_robot.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Basic editor functionality tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script src="../js/jsrobot/robot.js"></script>
+<script>
+       QUnit.config.reorder = false;
+       QUnit.config.autostart = false;
+
+       module('Formatting - Robot Tests', {
+               autostart: false
+       });
+       function checkExpectedAfterNewParagraph(expected) {
+               robot.type('\n', false, function() {
+                       robot.type('g', false, function() {
+                               var actual = editor.getContent();
+                               var cleaned = actual.replace("<br />","");
+                               equal(cleaned, expected);
+                               start();
+                       }, editor.getBody())
+               }, editor.getBody());
+       }
+       asyncTest('Should not be bold after turning off bold and going to a new paragraph', function() {
+               editor.setContent('<p><strong>text</strong></p>');
+               // in order for the robot to work well, we need to focus the editor before performing selection on it.
+               editor.focus();
+               setSelection("strong",4);
+               editor.execCommand("Bold");
+               var expected = '<p><strong>text</strong></p>\n<p>g</p>';
+               checkExpectedAfterNewParagraph(expected);
+       });
+       
+       asyncTest('Format with nested formatting turned off handled correctly', function(){
+               editor.setContent('<p><strong>bold<em>italic<span style="text-decoration: underline;">under</span></em></strong></p>');
+               editor.focus();
+               setSelection("span",5);
+               editor.execCommand("Italic");
+               var expected ='<p><strong>bold<em>italic<span style="text-decoration: underline;">under</span></em></strong></p>\n<p><strong><span style="text-decoration: underline;">g</span></strong></p>';
+               checkExpectedAfterNewParagraph(expected);
+       });
+
+       asyncTest('Format selection over two lines', function(){
+               editor.setContent("<div id='a'>one</div><div id='b'>two</div>");
+               editor.focus();
+               setSelection('#a', 0, '#b', 0);
+               editor.execCommand('formatBlock', false, 'h1');
+               equal(editor.dom.select('#a')[0].tagName, 'H1');
+               equal(editor.dom.select('#b')[0].tagName, 'DIV');
+               start();
+       });
+
+       var initTinyFunction = function(){
+               tinymce.init({
+                       mode : "exact",
+                       elements : "elm1",
+                       cleanup: true,
+
+                       add_unload_trigger : false,
+                       plugins: "table",
+                       init_instance_callback : function(ed) {
+                               editor = ed;
+
+                       }
+               });
+       };
+</script>
+</head>
+<body>
+<h1 id="qunit-header">Plugin Dependency Functional tests</h1>
+
+<h2 id="qunit-banner"></h2>
+
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="content">
+       <textarea id="elm1" name="elm1"></textarea>
+
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</div>
+<script>
+       initWhenTinyAndRobotAreReady(initTinyFunction);
+</script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/Formatter_robot.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceUndoManagerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/UndoManager.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/UndoManager.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/UndoManager.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,189 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.UndoManager tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("tinymce.UndoManager", {
+       autostart: false
+});
+
+test('Initial states', function() {
+       expect(3);
+
+       ok(!editor.undoManager.hasUndo());
+       ok(!editor.undoManager.hasRedo());
+       ok(!editor.undoManager.typing)
+});
+
+test('One undo level', function() {
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(3);
+
+       editor.focus();
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+
+       ok(editor.undoManager.hasUndo());
+       ok(!editor.undoManager.hasRedo());
+       ok(!editor.undoManager.typing)
+});
+
+test('Two undo levels', function() {
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(3);
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Italic');
+
+       ok(editor.undoManager.hasUndo());
+       ok(!editor.undoManager.hasRedo());
+       ok(!editor.undoManager.typing)
+});
+
+test('No undo levels and one redo', function() {
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(3);
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+       editor.undoManager.undo();
+
+       ok(!editor.undoManager.hasUndo());
+       ok(editor.undoManager.hasRedo());
+       ok(!editor.undoManager.typing)
+});
+
+test('One undo levels and one redo', function() {
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(3);
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+       editor.execCommand('SelectAll');
+       editor.execCommand('Italic');
+       editor.undoManager.undo();
+
+       ok(editor.undoManager.hasUndo());
+       ok(editor.undoManager.hasRedo());
+       ok(!editor.undoManager.typing)
+});
+
+test('Typing state', function() {
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(2);
+
+       editor.dom.fire(editor.getBody(), 'keydown', {keyCode : 65});
+       ok(editor.undoManager.typing)
+
+       editor.dom.fire(editor.getBody(), 'keyup', {keyCode : 13});
+       ok(!editor.undoManager.typing)
+});
+
+test('Undo and add new level', function() {
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(3);
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+       editor.undoManager.undo();
+       editor.execCommand('SelectAll');
+       editor.execCommand('Italic');
+
+       ok(editor.undoManager.hasUndo());
+       ok(!editor.undoManager.hasRedo());
+       ok(!editor.undoManager.typing)
+});
+
+test('Events', function() {
+       var add, undo, redo;
+
+       editor.undoManager.clear();
+       editor.setContent('test');
+
+       expect(6);
+
+       editor.on('AddUndo', function(e) {
+               add = e.level;
+       });
+
+       editor.on('Undo', function(e) {
+               undo = e.level;
+       });
+
+       editor.on('Redo', function(e) {
+               redo = e.level;
+       });
+
+       editor.execCommand('SelectAll');
+       editor.execCommand('Bold');
+       ok(add.content);
+       ok(add.bookmark);
+
+       editor.undoManager.undo();
+       ok(undo.content);
+       ok(undo.bookmark);
+
+       editor.undoManager.redo();
+       ok(redo.content);
+       ok(redo.bookmark);
+});
+
+test('Undo added when typing and losing focus', function() {
+       editor.focus();
+       editor.undoManager.clear();
+       editor.setContent("<p>some text</p>");
+       setSelection('p', 4, 'p', 9);
+       type('\b');
+       window.focus();
+       editor.dom.fire(editor.getBody(), 'focusout');
+       editor.execCommand('FormatBlock', false, 'h1');
+       editor.undoManager.undo();
+       equal(editor.getContent(), "<p>some</p>");
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       theme_advanced_styles : 'test1=test1;test2=test2',
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.UndoManager tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"><textarea id="elm1" name="elm1"></textarea></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/UndoManager.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceUndoManager_robothtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/UndoManager_robot.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/UndoManager_robot.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/UndoManager_robot.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,115 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Undo Tests</title>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../js/qunit/reporter.js"></script>
+<script src="../js/utils.js"></script>
+<script src="../js/tinymce_loader.js"></script>
+<script src="../js/jsrobot/robot.js"></script>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+var BACKSPACE = 0x8;
+
+module('Undo', {
+       autostart: false
+});
+
+function isUndoEnabled() {
+       return editor.undoManager.hasUndo();
+}
+
+// The following code never made it into the main codebase -- but it might be useful one day.  
+// If you're seeing this in August 2011 or later, please delete.                       
+                       // in webkit the iframe window needs to be given focus before selection
+                       // will behave correctly.  This code assigns focus to the tinymce window, giving it back to the
+                       // main window if it started with it.
+//                     if (tinymce.isWebKit) {
+//                             var hadFocus = document.hasFocus();
+//                             t.getWin().focus();
+//                             if (hadFocus) {
+//                                     window.focus();
+//                             }
+//                     }
+
+
+function assertUndoEnabledWhenTyping(c, expectedContent) {
+       editor.setContent('<p>Content</p>');
+
+       editor.undoManager.clear();
+       editor.undoManager.add();
+       editor.execCommand('mceRepaint');
+       // Need to focus the editor before setting selection in order to get the editor typing working correctly.
+       // All evidence points to the normal APIs not needing an editor.focus() call
+       editor.focus();
+       setSelection('p', 4);
+       ok(!isUndoEnabled(), 'Undo starts disabled.');
+       robot.type(c, false, function() {
+               equal(editor.getContent(), expectedContent);
+               ok(isUndoEnabled(), 'Undo is enabled.');
+               QUnit.start();
+       }, editor.selection.getNode());
+}
+
+asyncTest('Undo added when typing character', function() {
+       assertUndoEnabledWhenTyping('b', '<p>Contbent</p>');
+});
+
+asyncTest('Undo added when typing enter', function() {
+       assertUndoEnabledWhenTyping('\n', '<p>Cont</p><p>ent</p>');
+});
+
+asyncTest('Forward delete triggers undo in IE', function() {
+       editor.setContent('<p>Test1 Test2</p>');
+       editor.undoManager.clear();
+       editor.execCommand('mceRepaint');
+       ok(!isUndoEnabled(), 'Undo is disabled.');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('p')[0].firstChild, 0);
+       rng.setEnd(editor.dom.select('p')[0].firstChild, 6);
+       editor.selection.setRng(rng);
+
+       robot.forwardDelete(function() {
+               equal(editor.getContent(), '<p>Test2</p>', 'First word has been deleted');
+               ok(isUndoEnabled(), 'Undo is enabled.');
+
+               editor.undoManager.undo();
+               equal(editor.getContent(), '<p>Test1 Test2</p>', 'First word has been restored');
+
+               QUnit.start();
+       }, editor.selection.getNode());
+});
+
+var initTinyFunction = function(){
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               cleanup: true,
+               add_unload_trigger : false,
+               indent : 0,
+               init_instance_callback : function(ed) {
+                       editor = ed;
+               }
+       });
+}
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Undo Tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1">Content
+               </textarea>
+       </div>
+       <script>
+       initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/UndoManager_robot.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomDOMUtilshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/DOMUtils.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/DOMUtils.html                               (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/DOMUtils.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.dom.DOMUtils</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+QUnit.config.reorder = false;
+
+module("tinymce.dom.DOMUtils", {
+});
+</script>
+<script src="DOMUtils.js"></script>
+<h1 id="qunit-header">Unit tests for tinymce.dom.DOMUtils</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/DOMUtils.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomDOMUtilsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,680 @@
</span><ins>+(function() {
+       var DOM = new tinymce.dom.DOMUtils(document, {keep_values : true, schema : new tinymce.html.Schema()});
+
+       test('parseStyle', 11, function() {
+               var dom;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               dom = new tinymce.dom.DOMUtils(document, {hex_colors : true, keep_values : true, url_converter : function(u, n, e) {
+                       return 'X' + u + 'Y';
+               }});
+
+               equal(
+                       dom.serializeStyle(dom.parseStyle('border: 1px solid red; color: green')),
+                       'border: 1px solid red; color: green;'
+               );
+
+               equal(
+                       dom.serializeStyle(dom.parseStyle('border: 1px solid rgb(0, 255, 255); color: green')),
+                       'border: 1px solid #00ffff; color: green;'
+               );
+
+               equal(
+                       dom.serializeStyle(dom.parseStyle('border-top: 1px solid red; border-left: 1px solid red; border-bottom: 1px solid red; border-right: 1px solid red;')),
+                       'border: 1px solid red;'
+               );
+
+               equal(
+                       dom.serializeStyle(dom.parseStyle('border-width: 1pt 1pt 1pt 1pt; border-style: none none none none; border-color: black black black black;')),
+                       'border: 1pt none black;'
+               );
+               
+               equal(
+                       dom.serializeStyle(dom.parseStyle('border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;')),
+                       'border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;'
+               );
+
+               equal(
+                       dom.serializeStyle(dom.parseStyle('background: transparent url(test.gif);')),
+                       'background: transparent url(\'Xtest.gifY\');'
+               );
+
+               equal(
+                       dom.serializeStyle(dom.parseStyle('background: transparent url(http://www.site.com/test.gif?a=1&b=2);')),
+                       'background: transparent url(\'Xhttp://www.site.com/test.gif?a=1&b=2Y\');'
+               );
+
+               dom.setHTML('test', '<span id="test2" style="   margin-left: 1px;    margin-top: 1px;   margin-right: 1px;   margin-bottom: 1px   "></span>');
+               equal(dom.getAttrib('test2', 'style'), 'margin: 1px;');
+
+               dom.setHTML('test', '<span id="test2" style="background-image: url(test.gif);"></span>');
+               equal(dom.getAttrib('test2', 'style'), 'background-image: url(\'Xtest.gifY\');');
+
+               dom.get('test').innerHTML = '<span id="test2" style="border: 1px solid #00ff00"></span>';
+               equal(dom.getAttrib('test2', 'style'), tinymce.isIE && !window.getSelection ? 'border: #00ff00 1px solid;' : 'border: 1px solid #00ff00;'); // IE has a separate output
+
+               dom.get('test').innerHTML = '<span id="test2" style="background-image: url(http://www.site.com/test.gif);"></span>';
+               equal(dom.getAttrib('test2', 'style'), 'background-image: url(\'Xhttp://www.site.com/test.gifY\');');
+
+               DOM.remove('test');
+       });
+
+       test('addClass', 10, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').className = '';
+               DOM.addClass('test', 'abc');
+               equal(DOM.get('test').className, 'abc');
+
+               DOM.get('test').className = '';
+               equal(DOM.addClass('test', 'abc'), 'abc');
+               equal(DOM.addClass(null, 'abc'), false);
+
+               DOM.addClass('test', '123');
+               equal(DOM.get('test').className, 'abc 123');
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.addClass(DOM.select('span', 'test'), 'abc');
+               equal(DOM.get('test2').className, 'abc');
+               equal(DOM.get('test3').className, 'abc');
+               equal(DOM.get('test4').className, 'abc');
+               DOM.get('test').innerHTML = '';
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.addClass(['test2', 'test3', 'test4'], 'abc');
+               equal(DOM.get('test2').className, 'abc');
+               equal(DOM.get('test3').className, 'abc');
+               equal(DOM.get('test4').className, 'abc');
+               DOM.get('test').innerHTML = '';
+
+               DOM.remove('test');
+       });
+
+       test('removeClass', 4, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').className = 'abc 123 xyz';
+               DOM.removeClass('test', '123');
+               equal(DOM.get('test').className, 'abc xyz');
+
+               DOM.get('test').innerHTML = '<span id="test2" class="test1"></span><span id="test3" class="test test1 test"></span><span id="test4" class="test1 test"></span>';
+               DOM.removeClass(DOM.select('span', 'test'), 'test1');
+               equal(DOM.get('test2').className, '');
+               equal(DOM.get('test3').className, 'test test');
+               equal(DOM.get('test4').className, 'test');
+               DOM.get('test').innerHTML = '';
+
+               DOM.remove('test');
+       });
+
+       test('hasClass', 7, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').className = 'abc 123 xyz';
+               ok(DOM.hasClass('test', 'abc'));
+               ok(DOM.hasClass('test', '123'));
+               ok(DOM.hasClass('test', 'xyz'));
+               ok(!DOM.hasClass('test', 'aaa'));
+
+               DOM.get('test').className = 'abc';
+               ok(DOM.hasClass('test', 'abc'));
+
+               DOM.get('test').className = 'aaa abc';
+               ok(DOM.hasClass('test', 'abc'));
+
+               DOM.get('test').className = 'abc aaa';
+               ok(DOM.hasClass('test', 'abc'));
+
+               DOM.remove('test');
+       });
+
+       test('add', 5, function() {
+               var e;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.add('test', 'span', {'class' : 'abc 123'}, 'content <b>abc</b>');
+               e = DOM.get('test').getElementsByTagName('span')[0];
+               equal(e.className, 'abc 123');
+               equal(e.innerHTML.toLowerCase(), 'content <b>abc</b>');
+               DOM.remove(e);
+
+               DOM.add('test', 'span', {'class' : 'abc 123'});
+               e = DOM.get('test').getElementsByTagName('span')[0];
+               equal(e.className, 'abc 123');
+               DOM.remove(e);
+
+               DOM.add('test', 'span');
+               e = DOM.get('test').getElementsByTagName('span')[0];
+               equal(e.nodeName, 'SPAN');
+               DOM.remove(e);
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.add(['test2', 'test3', 'test4'], 'span', {'class' : 'abc 123'});
+               equal(DOM.select('span', 'test').length, 6);
+
+               DOM.remove('test');
+       });
+
+       test('create', 3, function() {
+               var e;
+
+               e = DOM.create('span', {'class' : 'abc 123'}, 'content <b>abc</b>');
+
+               equal(e.nodeName, 'SPAN');
+               equal(e.className, 'abc 123');
+               equal(e.innerHTML.toLowerCase(), 'content <b>abc</b>');
+       });
+
+       test('createHTML', 4, function() {
+               equal(DOM.createHTML('span', {'id' : 'id1', 'class' : 'abc 123'}, 'content <b>abc</b>'), '<span id="id1" class="abc 123">content <b>abc</b></span>');
+               equal(DOM.createHTML('span', {'id' : 'id1', 'class' : 'abc 123'}), '<span id="id1" class="abc 123" />');
+               equal(DOM.createHTML('span'), '<span />');
+               equal(DOM.createHTML('span', null, 'content <b>abc</b>'), '<span>content <b>abc</b></span>');
+       });
+
+       test('uniqueId', 3, function() {
+               DOM.counter = 0;
+
+               equal(DOM.uniqueId(), 'mce_0');
+               equal(DOM.uniqueId(), 'mce_1');
+               equal(DOM.uniqueId(), 'mce_2');
+       });
+
+       test('showHide', 10, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.show('test');
+               equal(DOM.get('test').style.display, 'block');
+               ok(!DOM.isHidden('test'));
+
+               DOM.hide('test');
+               equal(DOM.get('test').style.display, 'none');
+               ok(DOM.isHidden('test'));
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.hide(['test2', 'test3', 'test4'], 'test');
+               equal(DOM.get('test2').style.display, 'none');
+               equal(DOM.get('test3').style.display, 'none');
+               equal(DOM.get('test4').style.display, 'none');
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.show(['test2', 'test3', 'test4'], 'test');
+               equal(DOM.get('test2').style.display, 'block');
+               equal(DOM.get('test3').style.display, 'block');
+               equal(DOM.get('test4').style.display, 'block');
+
+               // Cleanup
+               DOM.setAttrib('test', 'style', '');
+
+               DOM.remove('test');
+       });
+
+       test('select', 4, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setHTML('test', '<div>test 1</div><div>test 2 <div>test 3</div></div><div>test 4</div>');
+               equal(DOM.select('div', 'test').length, 4);
+               ok(DOM.select('div', 'test').reverse);
+
+               DOM.setHTML('test', '<div class="test1 test2 test3">test 1</div><div class="test2">test 2 <div>test 3</div></div><div>test 4</div>')
+               equal(DOM.select('div.test2', 'test').length, 2);
+
+               DOM.setHTML('test', '<div class="test1 test2 test3">test 1</div><div class="test2">test 2 <div>test 3</div></div><div>test 4</div>')
+               equal(DOM.select('div div', 'test').length, 1, null, tinymce.isWebKit); // Issue: http://bugs.webkit.org/show_bug.cgi?id=17461
+               //alert(DOM.select('div div', 'test').length +","+DOM.get('test').querySelectorAll('div div').length);
+
+               DOM.remove('test');
+       });
+
+       test('is', 3, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+               DOM.setHTML('test', '<div id="textX" class="test">test 1</div>');
+
+               ok(DOM.is(DOM.get('textX'), 'div'));
+               ok(DOM.is(DOM.get('textX'), 'div#textX.test'));
+               ok(!DOM.is(DOM.get('textX'), 'div#textX2'));
+
+               DOM.remove('test');
+       });
+
+       test('encode', 1, function() {
+               equal(DOM.encode('abc<>"&\'\u00e5\u00e4\u00f6'), 'abc&lt;&gt;&quot;&amp;&#39;\u00e5\u00e4\u00f6');
+       });
+
+       test('setGetAttrib', 16, function() {
+               var dom;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setAttrib('test', 'class', 'test 123');
+               equal(DOM.getAttrib('test', 'class'), 'test 123');
+
+               DOM.setAttrib('test', 'src', 'url');
+               equal(DOM.getAttrib('test', 'src'), 'url');
+               equal(DOM.getAttrib('test', 'data-mce-src'), 'url');
+               equal(DOM.getAttrib('test', 'abc'), '');
+
+               DOM.setAttribs('test', {'class' : '123', title : 'abc'});
+               equal(DOM.getAttrib('test', 'class'), '123');
+               equal(DOM.getAttrib('test', 'title'), 'abc');
+
+               DOM.setAttribs('test');
+               equal(DOM.getAttrib('test', 'class'), '123');
+               equal(DOM.getAttrib('test', 'title'), 'abc');
+
+               dom = new tinymce.dom.DOMUtils(document, {keep_values : true, url_converter : function(u, n, e) {
+                       return '&<>"' + u + '&<>"' + n;
+               }});
+
+               dom.setAttribs('test', {src : '123', href : 'abc'});
+               equal(DOM.getAttrib('test', 'src'), '&<>"123&<>"src');
+               equal(DOM.getAttrib('test', 'href'), '&<>"abc&<>"href');
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.setAttribs(['test2', 'test3', 'test4'], {test1 : "1", test2 : "2"});
+               equal(DOM.getAttrib('test2', 'test1'), '1');
+               equal(DOM.getAttrib('test3', 'test2'), '2');
+               equal(DOM.getAttrib('test4', 'test1'), '1');
+
+               equal(DOM.getAttrib(document, 'test'), false);
+               equal(DOM.getAttrib(document, 'test', ''), '');
+               equal(DOM.getAttrib(document, 'test', 'x'), 'x');
+
+               DOM.remove('test');
+       });
+
+       test('getAttribs', 2, function() {
+               var dom;
+
+               function check(obj, val) {
+                       var count = 0;
+
+                       val = val.split(',');
+
+                       tinymce.each(obj, function(o) {
+                               if (tinymce.inArray(val, o.nodeName.toLowerCase()) != -1 && o.specified)
+                                       count++;
+                       });
+
+                       return count == obj.length;
+               };
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').innerHTML = '<span id="test2" class="test"></span>';
+               ok(check(DOM.getAttribs('test2'), 'id,class'));
+
+               DOM.get('test').innerHTML = '<input id="test2" type="checkbox" name="test" value="1" disabled readonly checked></span>';
+               ok(check(DOM.getAttribs('test2'), 'id,type,name,value,disabled,readonly,checked'), 'Expected attributed: type,name,disabled,readonly,checked');
+
+               DOM.remove('test');
+       });
+
+       test('setGetStyles', 7, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setStyle('test', 'font-size', '20px');
+               equal(DOM.getStyle('test', 'font-size'), '20px', null, tinymce.isWebKit);
+
+               DOM.setStyle('test', 'fontSize', '21px');
+               equal(DOM.getStyle('test', 'fontSize'), '21px', null, tinymce.isWebKit);
+
+               DOM.setStyles('test', {fontSize : '22px', display : 'inline'});
+               equal(DOM.getStyle('test', 'fontSize'), '22px', null, tinymce.isWebKit);
+               equal(DOM.getStyle('test', 'display'), 'inline', null, tinymce.isWebKit);
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.setStyles(['test2', 'test3', 'test4'], {fontSize : "22px"});
+               equal(DOM.getStyle('test2', 'fontSize'), '22px');
+               equal(DOM.getStyle('test3', 'fontSize'), '22px');
+               equal(DOM.getStyle('test4', 'fontSize'), '22px');
+
+               DOM.setAttrib('test', 'style', '');
+
+               DOM.remove('test');
+       });
+
+       test('getPos', 2, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setStyles('test', {position : 'absolute', left : 100, top : 110});
+               equal(DOM.getPos('test').x, 100);
+               equal(DOM.getPos('test').y, 110);
+
+               DOM.setAttrib('test', 'style', '');
+
+               DOM.remove('test');
+       });
+
+       test('getParent', 6, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').innerHTML = '<div><span>ab<a id="test2" href="">abc</a>c</span></div>';
+
+               equal(DOM.getParent('test2', function(n) {return n.nodeName == 'SPAN';}).nodeName, 'SPAN');
+               equal(DOM.getParent('test2', function(n) {return n.nodeName == 'BODY';}).nodeName, 'BODY');
+               equal(DOM.getParent('test2', function(n) {return n.nodeName == 'BODY';}, document.body), null);
+               equal(DOM.getParent('test2', function(n) {return false;}), null);
+               equal(DOM.getParent('test2', 'SPAN').nodeName, 'SPAN');
+               equal(DOM.getParent('test2', 'body', DOM.get('test')), null);
+
+               DOM.get('test').innerHTML = '';
+
+               DOM.remove('test');
+       });
+
+       test('getParents', 4, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+               DOM.get('test').innerHTML = '<div><span class="test">ab<span><a id="test2" href="">abc</a>c</span></span></div>';
+
+               equal(DOM.getParents('test2', function(n) {return n.nodeName == 'SPAN';}).length, 2);
+               equal(DOM.getParents('test2', 'span').length, 2);
+               equal(DOM.getParents('test2', 'span.test').length, 1);
+               equal(DOM.getParents('test2', 'body', DOM.get('test')).length, 0);
+
+               DOM.remove('test');
+       });
+
+       test('is', 2, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+               DOM.get('test').innerHTML = '<div><span class="test">ab<span><a id="test2" href="">abc</a>c</span></span></div>';
+
+               ok(DOM.is(DOM.select('span', 'test'), 'span'));
+               ok(DOM.is(DOM.select('#test2', 'test'), '#test2'));
+
+               DOM.remove('test');
+       });
+
+       test('getViewPort', 4, function() {
+               var wp;
+
+               wp = DOM.getViewPort();
+               equal(wp.x, 0);
+               equal(wp.y, 0);
+               ok(wp.w > 0);
+               ok(wp.h > 0);
+       });
+
+       test('getRect', 5, function() {
+               var r;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setStyles('test', {position : 'absolute', left : 100, top : 110, width : 320, height : 240});
+               r = DOM.getRect('test');
+               equal(r.x, 100);
+               equal(r.y, 110);
+               equal(r.w, 320);
+               equal(r.h, 240);
+
+               DOM.setAttrib('test', 'style', '');
+
+               DOM.get('test').innerHTML = '<div style="width:320px;height:240px"><div id="test2" style="width:50%;height:240px"></div></div>';
+               r = DOM.getRect('test2');
+               equal(r.w, 160);
+
+               DOM.remove('test');
+       });
+
+       test('getSize', 2, function() {
+               var r;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').innerHTML = '<div style="width:320px;height:240px"><div id="test2" style="width:50%;height:240px"></div></div>';
+               r = DOM.getSize('test2');
+               equal(r.w, 160);
+
+               DOM.get('test').innerHTML = '<div style="width:320px;height:240px"><div id="test2" style="width:100px;height:240px"></div></div>';
+               r = DOM.getSize('test2');
+               equal(r.w, 100);
+
+               DOM.remove('test');
+       });
+
+       test('getNext', 5, function() {
+               var r;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').innerHTML = '<strong>A</strong><span>B</span><em>C</em>';
+               equal(DOM.getNext(DOM.get('test').firstChild, '*').nodeName, 'SPAN');
+               equal(DOM.getNext(DOM.get('test').firstChild, 'em').nodeName, 'EM');
+               equal(DOM.getNext(DOM.get('test').firstChild, 'div'), null);
+               equal(DOM.getNext(null, 'div'), null);
+               equal(DOM.getNext(DOM.get('test').firstChild, function(n) {return n.nodeName == 'EM'}).nodeName, 'EM');
+
+               DOM.remove('test');
+       });
+
+       test('getPrev', 5, function() {
+               var r;
+
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.get('test').innerHTML = '<strong>A</strong><span>B</span><em>C</em>';
+               equal(DOM.getPrev(DOM.get('test').lastChild, '*').nodeName, 'SPAN');
+               equal(DOM.getPrev(DOM.get('test').lastChild, 'strong').nodeName, 'STRONG');
+               equal(DOM.getPrev(DOM.get('test').lastChild, 'div'), null);
+               equal(DOM.getPrev(null, 'div'), null);
+               equal(DOM.getPrev(DOM.get('test').lastChild, function(n) {return n.nodeName == 'STRONG'}).nodeName, 'STRONG');
+
+               DOM.remove('test');
+       });
+
+       test('loadCSS', 1, function() {
+               var c = 0;
+
+               DOM.loadCSS('css/test.css?a=1,css/test.css?a=2,css/test.css?a=3');
+
+               tinymce.each(document.getElementsByTagName('link'), function(n) {
+                       if (n.href.indexOf('test.css?a=') != -1)
+                               c++;
+               });
+
+               equal(c, 3, null, tinymce.isOpera);
+       });
+
+       test('insertAfter', 2, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setHTML('test', '<span id="test2"></span>');
+               DOM.insertAfter(DOM.create('br'), 'test2');
+               equal(DOM.get('test2').nextSibling.nodeName, 'BR');
+
+               DOM.setHTML('test', '<span>test</span><span id="test2"></span><span>test</span>');
+               DOM.insertAfter(DOM.create('br'), 'test2');
+               equal(DOM.get('test2').nextSibling.nodeName, 'BR');
+
+               DOM.remove('test');
+       });
+
+       test('isBlock', 4, function() {
+               ok(DOM.isBlock(DOM.create('div')));
+               ok(DOM.isBlock('DIV'));
+               ok(!DOM.isBlock('SPAN'));
+               ok(DOM.isBlock('div'));
+       });
+
+       test('remove', 3, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               DOM.remove('test2', 1);
+               equal(DOM.get('test').innerHTML.toLowerCase(), '<span>test</span><span>test2</span>');
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               equal(DOM.remove('test2').nodeName, 'SPAN');
+
+               DOM.get('test').innerHTML = '<span id="test2"></span><span id="test3"></span><span id="test4"></span>';
+               DOM.remove(['test2', 'test4']);
+               equal(DOM.select('span', 'test').length, 1);
+
+               DOM.remove('test');
+       });
+
+       test('replace', 2, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               DOM.replace(DOM.create('div', {id : 'test2'}), 'test2', 1);
+               equal(DOM.get('test2').innerHTML.toLowerCase(), '<span>test</span><span>test2</span>');
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               DOM.replace(DOM.create('div', {id : 'test2'}), 'test2');
+               equal(DOM.get('test2').innerHTML, '');
+
+               DOM.remove('test');
+       });
+
+       test('toHex', 5, function() {
+               equal(DOM.toHex('rgb(0, 255, 255)'), '#00ffff');
+               equal(DOM.toHex('rgb(255, 0, 0)'), '#ff0000');
+               equal(DOM.toHex('rgb(0, 0, 255)'), '#0000ff');
+               equal(DOM.toHex('rgb  (  0  , 0  , 255  )  '), '#0000ff');
+               equal(DOM.toHex('   RGB  (  0  , 0  , 255  )  '), '#0000ff');
+       });
+
+       test('getOuterHTML', 4, function() {
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               equal(DOM.getOuterHTML('test2').toLowerCase().replace(/\"/g, ''), '<span id=test2><span>test</span><span>test2</span></span>');
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               DOM.setOuterHTML('test2', '<div id="test2">123</div>');
+               equal(tinymce.trim(DOM.getOuterHTML('test2') || '').toLowerCase().replace(/\"/g, ''), '<div id=test2>123</div>');
+
+               DOM.setHTML('test', '<span id="test2"><span>test</span><span>test2</span></span>');
+               DOM.setOuterHTML('test2', '<div id="test2">123</div><div id="test3">abc</div>');
+               equal(tinymce.trim(DOM.get('test').innerHTML).toLowerCase().replace(/>\s+</g, '><').replace(/\"/g, ''), '<div id=test2>123</div><div id=test3>abc</div>');
+
+               DOM.setHTML('test', 'test');
+               equal(tinymce.trim(DOM.getOuterHTML(DOM.get('test').firstChild)), 'test');
+
+               DOM.remove('test');
+       });
+
+       test('encodeDecode', 2, function() {
+               equal(DOM.encode('\u00e5\u00e4\u00f6&<>"'), '\u00e5\u00e4\u00f6&amp;&lt;&gt;&quot;');
+               equal(DOM.decode('&aring;&auml;&ouml;&amp;&lt;&gt;&quot;'), '\u00e5\u00e4\u00f6&<>"');
+       });
+
+       test('split', 2, function() {
+               var point, parent;
+               DOM.add(document.body, 'div', {id : 'test'});
+
+               DOM.setHTML('test', '<p><b>text1<span>inner</span>text2</b></p>');
+               parent = DOM.select('p', DOM.get('test'))[0];
+               point = DOM.select('span', DOM.get('test'))[0];
+               DOM.split(parent, point);
+               equal(DOM.get('test').innerHTML.toLowerCase().replace(/\s+/g, ''), '<p><b>text1</b></p><span>inner</span><p><b>text2</b></p>');
+
+               DOM.setHTML('test', '<ul><li>first line<br><ul><li><span>second</span> <span>line</span></li><li>third line<br></li></ul></li></ul>');
+               parent = DOM.select('li:nth-child(1)', DOM.get('test'))[0];
+               point = DOM.select('ul li:nth-child(2)', DOM.get('test'))[0];
+               DOM.split(parent, point);
+               equal(cleanHtml(DOM.get('test').innerHTML), '<ul><li>first line<br><ul><li><span>second</span> <span>line</span></li></ul></li><li>third line<br></li></ul>');
+
+               DOM.remove('test');
+       });
+
+       test('nodeIndex', 5, function() {
+               DOM.add(document.body, 'div', {id : 'test'}, 'abc<b>abc</b>abc');
+
+               equal(DOM.nodeIndex(DOM.get('test').childNodes[0]), 0, 'Index of first child.');
+               equal(DOM.nodeIndex(DOM.get('test').childNodes[1]), 1, 'Index of second child.');
+               equal(DOM.nodeIndex(DOM.get('test').childNodes[2]), 2, 'Index of third child.');
+
+               DOM.get('test').insertBefore(DOM.doc.createTextNode('a'), DOM.get('test').firstChild);
+               DOM.get('test').insertBefore(DOM.doc.createTextNode('b'), DOM.get('test').firstChild);
+
+               equal(DOM.nodeIndex(DOM.get('test').lastChild), 4, 'Index of last child with fragmented DOM.');
+               equal(DOM.nodeIndex(DOM.get('test').lastChild, true), 2, 'Normalized index of last child with fragmented DOM.');
+
+               DOM.remove('test');
+       });
+
+       test('isEmpty', 14, function() {
+               DOM.schema = new tinymce.html.Schema(); // A schema will be added when used within a editor instance
+               DOM.add(document.body, 'div', {id : 'test'}, '');
+
+               ok(DOM.isEmpty(DOM.get('test')), 'No children');
+
+               DOM.setHTML('test', '<br />');
+               ok(DOM.isEmpty(DOM.get('test')), 'Br child');
+
+               DOM.setHTML('test', '<br /><br />');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Br children');
+
+               DOM.setHTML('test', 'text');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Text child');
+
+               DOM.setHTML('test', '<span>text</span>');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Text child in span');
+
+               DOM.setHTML('test', '<span></span>');
+               ok(DOM.isEmpty(DOM.get('test')), 'Empty span child');
+
+               DOM.setHTML('test', '<div><span><b></b></span><b></b><em></em></div>');
+               ok(DOM.isEmpty(DOM.get('test')), 'Empty complex HTML');
+
+               DOM.setHTML('test', '<div><span><b></b></span><b></b><em>X</em></div>');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Non empty complex HTML');
+
+               DOM.setHTML('test', '<div><span><b></b></span><b></b><em> </em></div>');
+               ok(DOM.isEmpty(DOM.get('test')), 'Non empty complex HTML with space');
+
+               DOM.setHTML('test', '<div><span><b></b></span><b></b><em><a name="x"></a></em></div>');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Non empty complex HTML with achor name');
+
+               DOM.setHTML('test', '<img src="x">');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Non empty html with img element');
+
+               DOM.setHTML('test', '<span data-mce-bookmark="1"></span>');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Span with bookmark attribute.');
+
+               DOM.setHTML('test', '<span data-mce-style="color:Red"></span>');
+               ok(DOM.isEmpty(DOM.get('test')), 'Span with data-mce attribute.');
+
+               DOM.setHTML('test', '<div><!-- comment --></div>');
+               ok(!DOM.isEmpty(DOM.get('test')), 'Element with comment.');
+
+               DOM.remove('test');
+       });
+
+       test('isEmpty on P with BR in EM', function() {
+               var elm = DOM.create('p', null, '<em><br></em>');
+               ok(DOM.isEmpty(elm, 'No children'));
+       });
+       
+       test('isEmpty on P with two BR in EM', function() {
+               var elm = DOM.create('p', null, '<em><br><br></em>');
+               equal(false, DOM.isEmpty(elm));
+       });
+
+       test('bind/unbind/fire', function() {
+               var count = 0;
+
+               DOM.bind(document, 'click', function() {count++;});
+               DOM.fire(document, 'click');
+               DOM.unbind(document, 'click');
+               equal(count, 1);
+
+               count = 0;
+               DOM.bind([document, window], 'click', function(e) {e.stopPropagation(); count++;});
+               DOM.fire(document, 'click');
+               DOM.fire(window, 'click');
+               DOM.unbind([document, window], 'click');
+               equal(count, 2);
+
+               count = 0;
+               DOM.fire(document, 'click');
+               DOM.fire(window, 'click');
+               equal(count, 0);
+       });
+
+       DOM.remove('test');
+})();
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/DOMUtils.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomDOMUtils_jqueryhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.dom.DOMUtils</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../../js/tinymce/tinymce.jquery.min.js"></script>
+</head>
+<body>
+<script>
+QUnit.config.reorder = false;
+
+module("tinymce.dom.DOMUtils (jQuery)", {
+});
+</script>
+<script src="DOMUtils.js"></script>
+
+<h1 id="qunit-header">Unit tests for tinymce.dom.DOMUtils</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomEventUtilshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/EventUtils.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/EventUtils.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/EventUtils.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,459 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for the EventUtils class</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var eventUtils = tinymce.dom.Event;
+
+QUnit.config.reorder = false;
+
+module("tinymce.dom.Event", {
+       teardown: function() {
+               eventUtils.clean(window);
+       }
+});
+
+// Bind dummy ready so it gets the domLoaded ready state
+eventUtils.bind(window, "ready", function() {});
+
+test("unbind all", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click = true;
+       });
+
+       eventUtils.bind(window, 'keydown', function(e) {
+               result.keydown1 = true;
+       });
+
+       eventUtils.bind(window, 'keydown', function(e) {
+               result.keydown2 = true;
+       });
+
+       result = {};
+       eventUtils.fire(window, 'click');
+       eventUtils.fire(window, 'keydown');
+       deepEqual(result, {click: true, keydown1: true, keydown2: true});
+
+       eventUtils.unbind(window);
+       result = {};
+       eventUtils.fire(window, 'click');
+       eventUtils.fire(window, 'keydown');
+       deepEqual(result, {});
+});
+
+test("unbind event", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click = true;
+       });
+
+       eventUtils.bind(window, 'keydown', function(e) {
+               result.keydown1 = true;
+       });
+
+       eventUtils.bind(window, 'keydown', function(e) {
+               result.keydown2 = true;
+       });
+
+       result = {};
+       eventUtils.fire(window, 'click');
+       eventUtils.fire(window, 'keydown');
+       deepEqual(result, {click: true, keydown1: true, keydown2: true});
+
+       eventUtils.unbind(window, 'click');
+       result = {};
+       eventUtils.fire(window, 'click');
+       eventUtils.fire(window, 'keydown');
+       deepEqual(result, {keydown1: true, keydown2: true});
+});
+
+test("unbind event non existing", function() {
+       eventUtils.unbind(window, 'noevent');
+       ok(true, "No exception");
+});
+
+test("unbind callback", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click = true;
+       });
+
+       eventUtils.bind(window, 'keydown', function(e) {
+               result.keydown1 = true;
+       });
+
+       function callback2(e) {
+               result.keydown2 = true;
+       };
+
+       eventUtils.bind(window, 'keydown', callback2);
+
+       result = {};
+       eventUtils.fire(window, 'click');
+       eventUtils.fire(window, 'keydown');
+       deepEqual(result, {click: true, keydown1: true, keydown2: true});
+
+       eventUtils.unbind(window, 'keydown', callback2);
+       result = {};
+       eventUtils.fire(window, 'click');
+       eventUtils.fire(window, 'keydown');
+       deepEqual(result, {click: true, keydown1: true});
+});
+
+test("unbind multiple", function() {
+       var result;
+
+       eventUtils.bind(window, 'mouseup mousedown click', function(e) {
+               result[e.type] = true;
+       });
+
+       eventUtils.unbind(window, 'mouseup mousedown');
+
+       result = {};
+       eventUtils.fire(window, 'mouseup');
+       eventUtils.fire(window, 'mousedown');
+       eventUtils.fire(window, 'click');
+       deepEqual(result, {click: true});
+});
+
+test("bind multiple", function() {
+       var result;
+
+       eventUtils.bind(window, 'mouseup mousedown', function(e) {
+               result[e.type] = true;
+       });
+
+       result = {};
+       eventUtils.fire(window, 'mouseup');
+       eventUtils.fire(window, 'mousedown');
+       eventUtils.fire(window, 'click');
+       deepEqual(result, {mouseup: true, mousedown: true});
+});
+
+test("bind/fire bubbling", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.window = true;
+       });
+
+       eventUtils.bind(document, 'click', function() {
+               result.document = true;
+       });
+
+       eventUtils.bind(document.body, 'click', function() {
+               result.body = true;
+       });
+
+       eventUtils.bind(document.getElementById('content'), 'click', function() {
+               result.content = true;
+       });
+
+       eventUtils.bind(document.getElementById('inner'), 'click', function() {
+               result.inner = true;
+       });
+
+       result = {};
+       eventUtils.fire(window, 'click');
+       deepEqual(result, {window: true});
+
+       result = {};
+       eventUtils.fire(document, 'click');
+       deepEqual(result, {document: true, window: true});
+
+       result = {};
+       eventUtils.fire(document.body, 'click');
+       deepEqual(result, {body: true, document: true, window: true});
+
+       result = {};
+       eventUtils.fire(document.getElementById('content'), 'click');
+       deepEqual(result, {content: true, body: true, document: true, window: true});
+
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {inner: true, content: true, body: true, document: true, window: true});
+});
+
+test("bind/fire stopImmediatePropagation", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click1 = true;
+       });
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click2 = true;
+               e.stopImmediatePropagation();
+       });
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click3 = true;
+       });
+
+       result = {};
+       eventUtils.fire(window, 'click');
+       deepEqual(result, {click1: true, click2: true});
+});
+
+test("bind/fire stopPropagation", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click1 = true;
+       });
+
+       eventUtils.bind(document.body, 'click', function(e) {
+               result.click2 = true;
+       });
+
+       eventUtils.bind(document.getElementById('inner'), 'click', function(e) {
+               result.click3 = true;
+               e.stopPropagation();
+       });
+
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {click3: true});
+});
+
+test("clean window", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click1 = true;
+       });
+
+       eventUtils.bind(document.body, 'click', function(e) {
+               result.click2 = true;
+       });
+
+       eventUtils.bind(document.getElementById('content'), 'click', function(e) {
+               result.click3 = true;
+       });
+
+       eventUtils.bind(document.getElementById('inner'), 'click', function(e) {
+               result.click4 = true;
+       });
+
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {click1: true, click2: true, click3: true, click4: true});
+
+       eventUtils.clean(window);
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {});
+});
+
+test("clean document", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click1 = true;
+       });
+
+       eventUtils.bind(document, 'click', function(e) {
+               result.click2 = true;
+       });
+
+       eventUtils.bind(document.body, 'click', function(e) {
+               result.click3 = true;
+       });
+
+       eventUtils.bind(document.getElementById('content'), 'click', function(e) {
+               result.click4 = true;
+       });
+
+       eventUtils.bind(document.getElementById('inner'), 'click', function(e) {
+               result.click5 = true;
+       });
+
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {click1: true, click2: true, click3: true, click4: true, click5: true});
+
+       eventUtils.clean(document);
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {click1: true});
+});
+
+test("clean element", function() {
+       var result;
+
+       eventUtils.bind(window, 'click', function(e) {
+               result.click1 = true;
+       });
+
+       eventUtils.bind(document.body, 'click', function(e) {
+               result.click2 = true;
+       });
+
+       eventUtils.bind(document.getElementById('content'), 'click', function(e) {
+               result.click3 = true;
+       });
+
+       eventUtils.bind(document.getElementById('inner'), 'click', function(e) {
+               result.click4 = true;
+       });
+
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {click1: true, click2: true, click3: true, click4: true});
+
+       eventUtils.clean(document.getElementById('content'));
+       result = {};
+       eventUtils.fire(document.getElementById('inner'), 'click');
+       deepEqual(result, {click1: true, click2: true});
+});
+
+test("mouseenter/mouseleave bind/unbind", function() {
+       var result = {};
+
+       eventUtils.bind(document.body, 'mouseenter mouseleave', function(e) {
+               result[e.type] = true;
+       });
+
+       eventUtils.fire(document.body, 'mouseenter');
+       eventUtils.fire(document.body, 'mouseleave');
+
+       deepEqual(result, {mouseenter: true, mouseleave: true});
+
+       result = {};
+       eventUtils.clean(document.body);
+       eventUtils.fire(document.body, 'mouseenter');
+       eventUtils.fire(document.body, 'mouseleave');
+       deepEqual(result, {});
+});
+
+test("focusin/focusout bind/unbind", function() {
+       var result = {};
+
+       eventUtils.bind(document.body, 'focusin focusout', function(e) {
+               // IE will fire a focusout on the parent element if you focus an element within not a big deal so lets detect it in the test
+               if (e.type == "focusout" && e.target.contains(document.activeElement)) {
+                       return;
+               }
+
+               result[e.type] = result[e.type] ? ++result[e.type] : 1;
+       });
+
+       document.getElementById('inner').focus();
+       document.getElementById('content').focus();
+
+       deepEqual(result, {focusin: 2, focusout: 1});
+});
+
+test("bind unbind fire clean on null", function() {
+       eventUtils.bind(null, 'click', function() {});
+       eventUtils.unbind(null, 'click', function() {});
+       eventUtils.fire(null, {});
+       eventUtils.clean(null);
+       ok(true, "No exception");
+});
+
+test("bind ready when page is loaded", function() {
+       var ready;
+
+       eventUtils.bind(window, 'ready', function() {
+               ready = true;
+       });
+
+       ok(eventUtils.domLoaded, "DomLoaded state true");
+       ok(ready, "Window is ready.");
+});
+
+test("event states when event object is fired twice", function() {
+       var result = {};
+
+       eventUtils.bind(window, 'keydown', function(e) {result[e.type] = true;e.preventDefault();e.stopPropagation();});
+       eventUtils.bind(window, 'keyup', function(e) {result[e.type] = true;e.stopImmediatePropagation();});
+
+       var event = {};
+       eventUtils.fire(window, 'keydown', event);
+       eventUtils.fire(window, 'keyup', event);
+
+       ok(event.isDefaultPrevented(), "Default is prevented.");
+       ok(event.isPropagationStopped(), "Propagation is stopped.");
+       ok(event.isImmediatePropagationStopped(), "Immediate propagation is stopped.");
+
+       deepEqual(result, {keydown: true, keyup: true});
+});
+
+test("unbind inside callback", function() {
+       var data;
+
+       function append(value) {
+               return function() {
+                       data += value;
+               };
+       }
+
+       function callback() {
+               eventUtils.unbind(window, 'click', callback);
+               data += 'b';
+       }
+
+       data = '';
+       eventUtils.bind(window, 'click', append("a"));
+       eventUtils.bind(window, 'click', callback);
+       eventUtils.bind(window, 'click', append("c"));
+
+       eventUtils.fire(window, 'click', {});
+       equal(data, 'abc');
+
+       data = '';
+       eventUtils.fire(window, 'click', {});
+       equal(data, 'ac');
+});
+
+test("ready/DOMContentLoaded (domLoaded = true)", function() {
+       var evt;
+
+       eventUtils.bind(window, "ready", function(e) {evt = e});
+       equal(evt.type, "ready");
+});
+
+test("ready/DOMContentLoaded (document.readyState check)", function() {
+       var evt;
+
+       try {
+               document.readyState = "loading";
+       } catch (e) {
+               ok(true, "IE doesn't allow us to set document.readyState");
+               return;
+       }
+
+       eventUtils.domLoaded = false;
+       document.readyState = "loading";
+       eventUtils.bind(window, "ready", function(e) {evt = e});
+       ok(typeof(evt) !== "undefined");
+
+       eventUtils.domLoaded = false;
+       document.readyState = "complete";
+       eventUtils.bind(window, "ready", function(e) {evt = e});
+       equal(evt.type, "ready");
+});
+</script>
+
+       <h1 id="qunit-header">Unit tests for DOM Selection IE implementation</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content" tabindex="0">
+               <div id="inner" tabindex="0"></div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/EventUtils.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomRangehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/Range.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/Range.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/Range.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,606 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for DOM Range IE implementation</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("Range", {
+       autostart: false
+});
+
+function createRng() {
+       return document.createRange ? document.createRange() : new tinymce.dom.Range(tinymce.DOM);
+};
+
+function getHTML(co) {
+       var div = document.createElement('div'), h;
+
+       if (!co)
+               return 'null';
+
+       div.appendChild(co.cloneNode(true));
+       h = div.innerHTML.toLowerCase();
+
+       h = h.replace(/[\r\n\t]/g, ''); // Remove line feeds and tabs
+       h = h.replace(/ (\w+)=([^\"][^\s>]*)/gi, ' $1="$2"'); // Restore attribs on IE
+
+       return h;
+};
+
+function setup() {
+       if (this.orgHTML)
+               document.getElementById('sample').innerHTML = this.orgHTML;
+
+       // Remove whitespace nodes to normalize IE and other browsers
+       function clean(n) {
+               var i;
+
+               if (n.nodeType == 3 && /^[\s]+$/.test(n.nodeValue))
+                       return n.parentNode.removeChild(n);
+
+               for (i = n.childNodes.length - 1; i >= 0; i--)
+                       clean(n.childNodes[i]);
+       };
+
+       clean(document.getElementById('sample'));
+
+       this.orgHTML = document.getElementById('sample').innerHTML;
+};
+
+test("Initial state", function() {
+       var r = createRng();
+
+       setup();
+       expect(5);
+
+       equal(r.startContainer, document)
+       equal(r.startOffset, 0)
+       equal(r.endContainer, document)
+       equal(r.endOffset, 0)
+       equal(r.commonAncestorContainer, document)
+});
+
+test("setStartSetEnd", function() {
+       var r = createRng();
+
+       setup();
+       expect(12);
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('strong').firstChild, 3);
+
+       equal(r.startContainer.nodeValue, 'first')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeValue, 'strong')
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 3)
+       equal(r.commonAncestorContainer.nodeName, 'P')
+
+       r.setStart(document.getElementById('first'), 0);
+       r.setEnd(document.getElementById('strong'), 0);
+
+       equal(r.startContainer.nodeName, 'P')
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeName, 'STRONG')
+       equal(r.endOffset, 0)
+       equal(r.commonAncestorContainer.nodeName, 'P')
+});
+
+test("setStartBeforeSetEndAfter", function() {
+       var r = createRng();
+
+       setup();
+       expect(5);
+
+       r.setStartBefore(document.getElementById('first'));
+       r.setEndAfter(document.getElementById('strong'));
+
+       equal(r.startContainer.nodeName, 'DIV')
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeName, 'P')
+       equal(r.endOffset, 5)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+});
+
+test("test_setStartAfterSetEndBefore", function() {
+       var r = createRng();
+
+       setup();
+       expect(5);
+
+       r.setStartAfter(document.getElementById('strong'));
+       r.setEndBefore(document.getElementById('em1'));
+
+       equal(r.startContainer.nodeName, 'P')
+       equal(r.startOffset, 5)
+       equal(r.endContainer.nodeName, 'P')
+       equal(r.endOffset, 6)
+       equal(r.commonAncestorContainer.nodeName, 'P')
+});
+
+test("test_collapse", function() {
+       var r = createRng();
+
+       setup();
+       expect(10);
+
+       r.setStart(document.getElementById('strong').firstChild, 0);
+       r.setEnd(document.getElementById('strong').firstChild, 6);
+
+       r.collapse(true);
+
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 0)
+       equal(r.commonAncestorContainer.nodeType, 3)
+
+       r.setStart(document.getElementById('strong').firstChild, 0);
+       r.setEnd(document.getElementById('strong').firstChild, 6);
+
+       r.collapse(false);
+
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 6)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 6)
+       equal(r.commonAncestorContainer.nodeType, 3)
+});
+
+test("test_selectNode", function() {
+       var r = createRng();
+
+       setup();
+       expect(4);
+
+       r.selectNode(document.getElementById('strong').firstChild);
+
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 1)
+});
+
+test("test_selectNodeContents", function() {
+       var r = createRng();
+
+       setup();
+       expect(8);
+
+       r.selectNodeContents(document.getElementById('strong').firstChild);
+
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 6)
+
+       r.selectNodeContents(document.getElementById('first'));
+
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 8)
+});
+
+test("test_insertNode", function() {
+       var r = createRng();
+
+       setup();
+       expect(4);
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('first').firstChild, 2);
+       r.insertNode(document.createTextNode('ABC'));
+
+       equal(document.getElementById('first').childNodes[0].nodeValue, 'f')
+       equal(document.getElementById('first').childNodes[1].nodeValue, 'ABC')
+       equal(document.getElementById('first').childNodes[2].nodeValue, 'irst')
+
+       r.selectNode(document.getElementById('strong'));
+       r.insertNode(document.createElement('span'));
+
+       equal(document.getElementById('strong').previousSibling.nodeName, 'SPAN')
+});
+
+test("test_cloneRange", function() {
+       var r = createRng();
+
+       setup();
+       expect(6);
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('strong').firstChild, 2);
+
+       var r2 = r.cloneRange();
+
+       equal(r2.startContainer.nodeType, 3)
+       equal(r2.startOffset, 1)
+       equal(r2.endContainer.nodeType, 3)
+       equal(r2.endOffset, 2)
+       equal(r2.collapsed, false)
+       equal(r2.commonAncestorContainer.nodeName, 'P')
+});
+
+if (tinymce.isGecko) {
+       test('test_cloneContents (SKIPPED)', function() {
+               ok(true, 'Before Firefox 3.6 this test fails because of a corner case bug but since the point is to test the IE Range implementation we skip it.');
+       });
+} else {
+test("test_cloneContents", function() {
+       var r = createRng();
+
+       setup();
+       expect(77);
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('two').firstChild, 2);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">irst<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">ab</td></tr></tbody></table>')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 2)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+
+       r.setStart(document.getElementById('two').firstChild, 1);
+       r.setEnd(document.getElementById('last').firstChild, 2);
+
+       equal(getHTML(r.cloneContents()), '<table id="table"><tbody><tr><td id="two">bc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">te</p>')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 2)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('first').lastChild, 4);
+
+       equal(getHTML(r.cloneContents()), 'irst<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> str')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 4)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeName, 'P')
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('first').firstChild, 4);
+
+       equal(getHTML(r.cloneContents()), 'irs')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 4)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 3)
+
+       r.setStart(document.getElementById('first'), 0);
+       r.setEnd(document.getElementById('last'), 0);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id=\"last\"></p>')
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 0)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+
+       r.setStart(document.getElementById('first'), 1);
+       r.setEnd(document.getElementById('last'), 1);
+
+       equal(getHTML(r.cloneContents()), '<p id="first"><!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc</p>')
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 1)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+
+       r.setStart(document.getElementById('sample'), 0);
+       r.setEnd(document.getElementById('sample'), document.getElementById('sample').childNodes.length - 1);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table>')
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, document.getElementById('sample').childNodes.length - 1)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+
+       r.setStart(document.getElementById('first'), 0);
+       r.setEnd(document.getElementById('last').firstChild, 1);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">t</p>')
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 1)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('last'), 0);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">irst<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id=\"last\"></p>')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 0)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+
+       r.setStart(document.getElementById('sample'), 0);
+       r.setEnd(document.getElementById('traverse'), 2);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em></p>')
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 2)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+
+       r.setStart(document.getElementById('sample'), 0);
+       r.setEnd(document.getElementById('traverse'), 1);
+
+       equal(getHTML(r.cloneContents()), '<p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b></p>')
+       equal(r.startContainer.nodeType, 1)
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 1)
+       equal(r.collapsed, false)
+       equal(r.commonAncestorContainer.nodeType, 1)
+});
+}
+
+test("test_extractContents1", function() {
+       var r = createRng();
+
+       setup();
+       expect(10);
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('first').firstChild, 4);
+
+       equal(getHTML(r.extractContents()), 'irs')
+       equal(r.startContainer.nodeType, 3)
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 3)
+       equal(r.endOffset, 1)
+       equal(r.collapsed, true)
+       equal(r.startContainer == r.endContainer, true)
+       equal(r.startOffset == r.endOffset, true)
+       equal(r.commonAncestorContainer.nodeType, 3)
+       equal(getHTML(document.getElementById('first')), '<p id="first">ft<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p>')
+});
+
+test("test_extractContents2", function() {
+       var r = createRng();
+
+       setup();
+       expect(9);
+
+       r.setStart(document.getElementById('two').firstChild, 1);
+       r.setEnd(document.getElementById('last').firstChild, 2);
+
+       equal(getHTML(r.extractContents()), '<table id="table"><tbody><tr><td id="two">bc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">te</p>')
+       equal(r.startContainer.nodeType, 1)
+       equal(getHTML(r.startContainer), '<div id="sample"><p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">a</td></tr></tbody></table><p id="last">xtabc<span>span</span></p></div>')
+       equal(r.startOffset, 4)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 4)
+       equal(getHTML(r.endContainer), '<div id="sample"><p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">a</td></tr></tbody></table><p id="last">xtabc<span>span</span></p></div>')
+       equal(r.collapsed, true)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+});
+
+test("test_extractContents3", function() {
+       var r = createRng();
+
+       setup();
+       expect(9);
+
+       r.setStart(document.getElementById('sample'), 0);
+       r.setEnd(document.getElementById('traverse'), 2);
+
+       equal(getHTML(r.extractContents()), '<p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em></p>')
+       equal(getHTML(r.startContainer), '<div id="sample"><p id="traverse">more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 0)
+       equal(getHTML(r.endContainer), '<div id="sample"><p id="traverse">more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(getHTML(document.getElementById('sample')), '<div id="sample"><p id="traverse">more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.collapsed, true)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+});
+
+test("test_deleteContents1", function() {
+       var r = createRng();
+
+       setup();
+       expect(8);
+
+       r.setStart(document.getElementById('two').firstChild, 1);
+       r.setEnd(document.getElementById('last').firstChild, 2);
+       r.deleteContents();
+
+       equal(getHTML(r.startContainer), '<div id="sample"><p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">a</td></tr></tbody></table><p id="last">xtabc<span>span</span></p></div>')
+       equal(r.startOffset, 4)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 4)
+       equal(getHTML(r.endContainer), '<div id="sample"><p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">a</td></tr></tbody></table><p id="last">xtabc<span>span</span></p></div>')
+       equal(getHTML(document.getElementById('sample')), '<div id="sample"><p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">a</td></tr></tbody></table><p id="last">xtabc<span>span</span></p></div>')
+       equal(r.collapsed, true)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+});
+
+test("test_deleteContents2", function() {
+       var r = createRng();
+
+       setup();
+       expect(8);
+
+       r.setStart(document.getElementById('first').firstChild, 1);
+       r.setEnd(document.getElementById('first').lastChild, 4);
+       r.deleteContents();
+
+       equal(getHTML(r.startContainer), '<p id="first">fong.</p>')
+       equal(r.startOffset, 1)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 1)
+       equal(getHTML(r.endContainer), '<p id="first">fong.</p>')
+       equal(getHTML(document.getElementById('sample')), '<div id="sample"><p id="first">fong.</p><p id="second">bar</p><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.collapsed, true)
+       equal(r.commonAncestorContainer.nodeName, 'P')
+});
+
+test("test_deleteContents3", function() {
+       var r = createRng();
+
+       setup();
+       expect(8);
+
+       r.setStart(document.getElementById('sample'), 0);
+       r.setEnd(document.getElementById('sample'), 2);
+       r.deleteContents();
+
+       equal(getHTML(r.startContainer), '<div id="sample"><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 0)
+       equal(getHTML(r.endContainer), '<div id="sample"><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(getHTML(document.getElementById('sample')), '<div id="sample"><p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.collapsed, true)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+});
+
+test("test_deleteContents4", function() {
+       var r = createRng();
+
+       setup();
+       expect(8);
+
+       r.setStart(document.getElementById('sample'), 0);
+       r.setEnd(document.getElementById('traverse'), 2);
+       r.deleteContents();
+
+       equal(getHTML(r.startContainer), '<div id="sample"><p id="traverse">more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.startOffset, 0)
+       equal(r.endContainer.nodeType, 1)
+       equal(r.endOffset, 0)
+       equal(getHTML(r.endContainer), '<div id="sample"><p id="traverse">more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(getHTML(document.getElementById('sample')), '<div id="sample"><p id="traverse">more text</p><table id="table"><tbody><tr><td>1</td><td id="two">abc</td></tr><tr><td>3</td><td>4</td></tr></tbody></table><p id="last">textabc<span>span</span></p></div>')
+       equal(r.collapsed, true)
+       equal(r.commonAncestorContainer.nodeName, 'DIV')
+});
+
+test("test_compareBoundaryPoints", function() {
+       var r1 = createRng(), r2 = createRng(), START_TO_START = 0, START_TO_END = 1, END_TO_END = 2, END_TO_START = 3;
+       setup();
+        
+       r1.setStartBefore(document.getElementById('strong'));
+       r1.setEndAfter(document.getElementById('strong'));
+       r2.setStartBefore(document.getElementById('strong'));
+       r2.setEndAfter(document.getElementById('strong'));
+       equal(r1.compareBoundaryPoints(START_TO_START, r2), 0, 'Start to start for same ranges');
+       equal(r1.compareBoundaryPoints(END_TO_END, r2), 0, 'End to end for same ranges');
+       equal(r1.compareBoundaryPoints(START_TO_END, r1), 1, 'Start to end for same ranges');
+       equal(r1.compareBoundaryPoints(END_TO_START, r2), -1, 'End to start for same ranges');
+
+       r1.setStartBefore(document.getElementById('strong'));
+       r1.setEndAfter(document.getElementById('strong'));
+       r2.setStartBefore(document.getElementById('em1'));
+       r2.setEndAfter(document.getElementById('em1'));
+       equal(r1.compareBoundaryPoints(START_TO_START, r2), -1, 'Start to start for range before');
+       equal(r1.compareBoundaryPoints(END_TO_END, r2), -1, 'End to end for range before');
+       equal(r1.compareBoundaryPoints(START_TO_END, r2), -1, 'Start to end for range before');
+       equal(r1.compareBoundaryPoints(END_TO_START, r2), -1, 'End to start for range before');
+
+       equal(r2.compareBoundaryPoints(START_TO_START, r1), 1, 'Start to start for range after');
+       equal(r2.compareBoundaryPoints(END_TO_END, r1), 1, 'End to end for range after');
+       equal(r2.compareBoundaryPoints(START_TO_END, r1), 1, 'Start to end for range after');
+       equal(r2.compareBoundaryPoints(END_TO_START, r1), 1, 'End to start for range after');
+
+       r1.setStartBefore(document.getElementById('strong'));
+       r1.setEndAfter(document.getElementById('strong'));
+       r2.setStart(document.getElementById('strong').firstChild, 2);
+       r2.setEnd(document.getElementById('strong').firstChild, 3);
+       equal(r1.compareBoundaryPoints(START_TO_START, r2), -1, 'Start to start for range inside');
+       equal(r1.compareBoundaryPoints(END_TO_END, r2), 1, 'End to end for range inside');
+       equal(r1.compareBoundaryPoints(START_TO_END, r2), 1, 'Start to end for range inside');
+       equal(r1.compareBoundaryPoints(END_TO_START, r2), -1, 'End to start for range inside');
+});
+
+test("toString in part of same text node", function() {
+       var rng = createRng();
+
+       rng.setStart(document.getElementById('strong').firstChild, 1);
+       rng.setEnd(document.getElementById('strong').firstChild, 3);
+       equal(rng.toString(), "tr");
+});
+
+test("toString in start/end of same text node", function() {
+       var rng = createRng();
+
+       rng.setStart(document.getElementById('strong').firstChild, 0);
+       rng.setEnd(document.getElementById('strong').firstChild, 6);
+       equal(rng.toString(), "strong");
+});
+
+test("toString in start in one text node end in another", function() {
+       var rng = createRng();
+
+       rng.setStart(document.getElementById('strong').firstChild, 1);
+       rng.setEnd(document.getElementById('em1').firstChild, 1);
+       equal(rng.toString(), "trong second e");
+});
+
+// Run on IE only
+if (tinymce.isIE) {
+       test("toString in start in one text node end in another", function() {
+               var rng = createRng();
+
+               rng.setStartBefore(document.getElementById('strong'));
+               rng.setEndAfter(document.getElementById('em2'));
+               equal(rng.toString().replace(/\r\n/g, ''), "strong second em strong.barsome text");
+       });
+}
+
+tinymce.DOM.bind(window, 'load', function() {
+       QUnit.start();
+});
+</script>
+       <h1 id="qunit-header">Unit tests for DOM Range IE implementation</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="sample">
+               <p id="first">first<!--not--> strong <!-- --><strong id="strong">strong</strong> second <em id="em1">em</em> strong.</p>
+               <p id="second">bar</p>
+               <p id="traverse"><b><em id="em2">some text</em></b><em>em text</em>more text</p>
+               <table id="table">
+                       <tr>
+                               <td>1</td>
+                               <td id="two">abc</td>
+                       </tr>
+                       <tr>
+                               <td>3</td>
+                               <td>4</td>
+                       </tr>
+               </table>
+               <p id="last">textabc<span>span</span></p>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/Range.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomSelectionhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/Selection.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/Selection.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/Selection.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,878 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.dom.Selection</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("Selection", {
+       autostart: false
+});
+
+test('getContent', function() {
+       var rng, eventObj;
+
+       // Get selected contents
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       equal(editor.selection.getContent(), '<p>text</p>', 'Get selected contents');
+
+       // Get selected contents (collapsed)
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 0);
+       editor.selection.setRng(rng);
+       equal(editor.selection.getContent(), '', 'Get selected contents (collapsed)');
+
+       // Get selected contents, onGetContent event
+       eventObj = {};
+
+       function handler(event) {
+               eventObj = event;
+       };
+
+       editor.on('GetContent', handler);
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.selection.getContent();
+       equal(eventObj.content, '<p>text</p>', 'Get selected contents, onGetContent event');
+       editor.off('GetContent', handler);
+});
+
+test('setContent', function() {
+       var rng, eventObj;
+
+       // Set contents at selection
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.selection.setContent('<div>test</div>');
+       equal(editor.getContent(), '<div>test</div>', 'Set contents at selection');
+
+       // Set contents at selection (collapsed)
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 0);
+       editor.selection.setRng(rng);
+       editor.selection.setContent('<div>test</div>');
+       equal(editor.getContent(), '<div>test</div>\n<p>text</p>', 'Set contents at selection (collapsed)');
+
+       // Insert in middle of paragraph
+       editor.setContent('<p>beforeafter</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 'before'.length);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 'before'.length);
+       editor.selection.setRng(rng);
+       editor.selection.setContent('<br />');
+       equal(editor.getContent(), '<p>before<br />after</p>', 'Set contents at selection (inside paragraph)');
+
+       // Check the caret is left in the correct position.
+       rng = editor.selection.getRng(true);
+       if (document.createRange) {
+               equal(rng.startContainer, editor.getBody().firstChild, 'Selection start container');
+               equal(rng.startOffset, 2, 'Selection start offset');
+               equal(rng.endContainer, editor.getBody().firstChild, 'Selection end container');
+               equal(rng.endOffset, 2, 'Selection end offset');
+       } else {
+               // TridentSelection resolves indexed text nodes
+               equal(rng.startContainer, editor.getBody().firstChild.lastChild, 'Selection start container');
+               equal(rng.startOffset, 0, 'Selection start offset');
+               equal(rng.endContainer, editor.getBody().firstChild.lastChild, 'Selection end container');
+               equal(rng.endOffset, 0, 'Selection end offset');
+       }
+
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 0);
+       editor.selection.setRng(rng);
+       editor.selection.setContent('');
+       equal(editor.getContent(), '<p>text</p>', 'Set contents to empty at selection (collapsed)');
+       rng = editor.selection.getRng(true);
+       if (!document.createRange) {
+               // The old IE selection can only be positioned in text nodes
+               equal(rng.startContainer, editor.getBody().firstChild.firstChild, 'Selection start container');
+               equal(rng.startOffset, 0, 'Selection start offset');
+               equal(rng.endContainer, editor.getBody().firstChild.firstChild, 'Selection end container');
+               equal(rng.endOffset, 0, 'Selection end offset');
+       } else {
+               equal(rng.startContainer, editor.getBody(), 'Selection start container');
+               equal(rng.startOffset, 0, 'Selection start offset');
+               equal(rng.endContainer, editor.getBody(), 'Selection end container');
+               equal(rng.endOffset, 0, 'Selection end offset');
+       }
+       
+       // Set selected contents, onSetContent event
+       eventObj = {};
+
+       function handler(event) {
+               eventObj = event;
+       };
+
+       editor.on('SetContent', handler);
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 1);
+       editor.selection.setRng(rng);
+       editor.selection.setContent('<div>text</div>');
+       equal(eventObj.content, '<div>text</div>', 'Set selected contents, onSetContent event');
+       editor.off('SetContent', handler);
+});
+
+test('getStart/getEnd', function() {
+       var rng;
+
+       // Selected contents
+       editor.setContent('<p id="a">text</p><p id="b">text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 0);
+       editor.selection.setRng(rng);
+       equal(editor.selection.getStart().id, 'a', 'Selected contents (getStart)');
+       equal(editor.selection.getEnd().id, 'b', 'Selected contents (getEnd)');
+
+       // Selected contents (collapsed)
+       editor.setContent('<p id="a">text</p>\n<p id="b">text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild.firstChild, 0);
+       editor.selection.setRng(rng);
+       equal(editor.selection.getStart().id, 'a', 'Selected contents (getStart, collapsed)');
+       equal(editor.selection.getEnd().id, 'a', 'Selected contents (getEnd, collapsed)');
+});
+
+test('getBookmark/setBookmark (persistent)', function() {
+       var rng, bookmark;
+
+       // Get persistent bookmark simple text selection
+       editor.setContent('text');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark();
+       equal(editor.getContent(), 'text', 'Editor contents (text)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), 'ex', 'Selected contents (text)');
+
+       // Get persistent bookmark multiple elements text selection
+       editor.setContent('<p>text</p>\n<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark();
+       equal(editor.getContent(), '<p>text</p>\n<p>text</p>', 'Editor contents (elements)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), '<p>ext</p>\n<p>tex</p>', 'Selected contents (elements)');
+});
+
+test('getBookmark/setBookmark (simple)', function() {
+       var rng, bookmark;
+
+       // Get persistent bookmark simple text selection
+       editor.setContent('text');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(1);
+       equal(editor.getContent(), 'text', 'Editor contents (text)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), 'ex', 'Selected contents (text)');
+
+       // Get persistent bookmark multiple elements text selection
+       editor.setContent('<p>text</p>\n<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(1);
+       equal(editor.getContent(), '<p>text</p>\n<p>text</p>', 'Editor contents (elements)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), '<p>ext</p>\n<p>tex</p>', 'Selected contents (elements)');
+});
+
+test('getBookmark/setBookmark (nonintrusive) - simple text selection', function() {
+       var rng, bookmark;
+
+       expect(2);
+
+       editor.setContent('text');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2);
+       equal(editor.getContent(), 'text', 'Editor contents (text)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), 'ex', 'Selected contents (text)');
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get non intrusive bookmark simple element selection', function() {
+       var rng, bookmark;
+
+       expect(1);
+
+       // Get non intrusive bookmark simple element selection
+       editor.setContent('<p>text<em>a<strong>b</strong>c</em></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.select('em')[0], 1);
+       rng.setEnd(editor.dom.select('em')[0], 2);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2);
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), '<strong>b</strong>', 'Selected contents (element)');
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get non intrusive bookmark multiple elements text selection', function() {
+       var rng, bookmark;
+
+       expect(2);
+
+       // Get non intrusive bookmark multiple elements text selection
+       editor.setContent('<p>text</p>\n<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.firstChild, 1);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2);
+       equal(editor.getContent(), '<p>text</p>\n<p>text</p>', 'Editor contents (elements)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), '<p>ext</p>\n<p>tex</p>', 'Selected contents (elements)');
+});
+
+test('getBookmark/setBookmark (nonintrusive)', function() {
+       var rng, bookmark;
+
+       expect(2);
+
+       // Get non intrusive bookmark multiple elements text selection fragmented
+       editor.setContent('<p>text</p><p>text</p>');
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('a'));
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('a'));
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('a'));
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('text'));
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.lastChild, 1);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2);
+       equal(editor.getContent(), '<p>textaaatext</p>\n<p>text</p>', 'Editor contents (fragmented, elements)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), '<p>ext</p>\n<p>tex</p>', 'Selected contents (fragmented, elements)');
+});
+
+test('getBookmark/setBookmark (nonintrusive) - fragmentext text (normalized)', function() {
+       var rng, bookmark;
+
+       expect(2);
+
+       // Get non intrusive bookmark multiple elements text selection fragmented
+       editor.setContent('<p>text</p><p>text</p>');
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('a'));
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('a'));
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('a'));
+       editor.dom.select('p')[0].appendChild(editor.dom.doc.createTextNode('text'));
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild.lastChild, 1);
+       rng.setEnd(editor.getBody().lastChild.firstChild, 3);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.setContent(editor.getContent());
+       equal(editor.getContent(), '<p>textaaatext</p>\n<p>text</p>', 'Editor contents (fragmented, elements)');
+       editor.selection.moveToBookmark(bookmark);
+       equal(editor.selection.getContent(), '<p>ext</p>\n<p>tex</p>', 'Selected contents (fragmented, elements)');
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark before image', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('<p><img src="about:blank" /></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild, 0);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().firstChild);
+       equal(rng.startOffset, 0);
+       equal(rng.endContainer, editor.getBody().firstChild);
+       equal(rng.endOffset, 0);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark before/after image', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('<p><img src="about:blank" /></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild, 1);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().firstChild);
+       equal(rng.startOffset, 0);
+       equal(rng.endContainer, editor.getBody().firstChild);
+       equal(rng.endOffset, 1);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark after image', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('<p><img src="about:blank" /></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild, 1);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().firstChild);
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer, editor.getBody().firstChild);
+       equal(rng.endOffset, 1);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark before element', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('abc<b>123</b>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 0);
+       rng.setEnd(editor.getBody().firstChild, 2);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().firstChild);
+       equal(rng.startOffset, 0);
+       equal(rng.endContainer, editor.getBody().firstChild);
+       equal(rng.endOffset, 2);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark after element', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       // Get bookmark after element
+       editor.setContent('<b>123</b>abc');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().lastChild, 1);
+       rng.setEnd(editor.getBody().lastChild, 2);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().lastChild);
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer, editor.getBody().lastChild);
+       equal(rng.endOffset, 2);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark inside element', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('abc<b>123</b>abc');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().childNodes[1].firstChild, 1);
+       rng.setEnd(editor.getBody().childNodes[1].firstChild, 2);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().childNodes[1].firstChild);
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer, editor.getBody().childNodes[1].firstChild);
+       equal(rng.endOffset, 2);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark inside root text', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('abc');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody().firstChild, 1);
+       rng.setEnd(editor.getBody().firstChild, 2);
+       editor.selection.setRng(rng);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.getBody().firstChild);
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer, editor.getBody().firstChild);
+       equal(rng.endOffset, 2);
+});
+
+test('getBookmark/setBookmark (nonintrusive) - Get bookmark inside complex html', function() {
+       var rng, bookmark;
+
+       expect(4);
+
+       editor.setContent('<p>abc</p>123<p>123</p><p>123<b>123</b><table><tr><td>abc</td></tr></table></p>');
+       editor.execCommand('SelectAll');
+       setSelection('td', 1, 'td', 2);
+       bookmark = editor.selection.getBookmark(2, true);
+       editor.getBody().innerHTML = editor.getBody().innerHTML;
+       editor.selection.moveToBookmark(bookmark);
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer, editor.dom.select('td')[0].firstChild);
+       equal(rng.startOffset, 1);
+       equal(rng.endContainer, editor.dom.select('td')[0].firstChild);
+       equal(rng.endOffset, 2);
+});
+
+test('select first p', 2, function() {
+       editor.setContent('<p>text1</p><p>text2</p>');
+       editor.selection.select(editor.dom.select('p')[0]);
+       equal(editor.selection.getContent(), '<p>text1</p>', 'Select simple element, content');
+       equal(editor.selection.getStart().nodeName, 'P', 'Select simple element, nodeName');
+});
+
+test('select table', 2, function() {
+       editor.setContent('<table><tbody><tr><td>text1</td></tr></tbody></table>');
+       editor.selection.select(editor.dom.select('table')[0]);
+       equal(editor.selection.getContent(), '<table>\n<tbody>\n<tr>\n<td>text1</td>\n</tr>\n</tbody>\n</table>', 'Select complex element, content');
+       equal(editor.selection.getNode().nodeName, 'TABLE', 'Select complex element, nodeName');
+});
+
+test('select table text 1', 2, function() {
+       editor.setContent('<table><tbody><tr><td id="a">text1</td><td id="b">text2</td></tr></tbody></table>');
+       editor.selection.select(editor.dom.select('table')[0], true);
+       equal(editor.selection.getStart().id, 'a', 'Expand to text content 1 (start)');
+       equal(editor.selection.getEnd().id, 'b', 'Expand to text content 1 (end)');
+});
+
+test('select table text 2', 2, function() {
+       editor.setContent('<table><tbody><tr><td id="a"><br /></td><td id="b"><br /></td></tr></tbody></table>');
+       editor.selection.select(editor.dom.select('table')[0], true);
+       equal(editor.dom.getParent(editor.selection.getStart(), 'td').id, 'a', 'Expand to text content 2 (start)');
+       equal(editor.dom.getParent(editor.selection.getEnd(), 'td').id, 'b', 'Expand to text content 2 (end)');
+});
+
+test('getNode', function() {
+       var rng;
+
+       editor.setContent('<p id="p1"><span id="s1">span1</span> word <span id="s2">span2</span> word <span id="s3">span3</span></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.get('s1').firstChild, 0);
+       rng.setEnd(editor.dom.get('s1').nextSibling, 0);
+       editor.selection.setRng(rng);
+       deepEqual(editor.selection.getNode(), editor.dom.get('s1'), 'Detect selection ends immediately after node at start of paragraph.');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.get('s2').previousSibling, editor.dom.get('s2').previousSibling.length);
+       rng.setEnd(editor.dom.get('s2').nextSibling, 0);
+       editor.selection.setRng(rng);
+       deepEqual(editor.selection.getNode(), editor.dom.get('s2'), 'Detect selection immediately surrounds node in middle of paragraph.');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.get('s3').previousSibling, editor.dom.get('s3').previousSibling.length);
+       rng.setEnd(editor.dom.get('s3').lastChild, editor.dom.get('s3').lastChild.length);
+       editor.selection.setRng(rng);
+       deepEqual(editor.selection.getNode(), editor.dom.get('s3'), 'Detect selection starts immediately before node at end of paragraph.');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.dom.get('s2').previousSibling, editor.dom.get('s2').previousSibling.length);
+       rng.setEnd(editor.dom.get('s3').lastChild, editor.dom.get('s3').lastChild.length);
+       editor.selection.setRng(rng);
+       deepEqual(editor.selection.getNode(), editor.dom.get('p1'), 'Detect selection wrapping multiple nodes does not collapse.');
+});
+
+test('normalize to text node from document', function() {
+       var rng;
+
+       if (tinymce.isOpera || tinymce.isIE) {
+               ok(true, "Skipped on Opera/IE since Opera doesn't let you to set the range to document and IE will steal focus.");
+               return;
+       }
+
+       editor.setContent('<p>text</p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getDoc(), 0);
+       rng.setEnd(editor.getDoc(), 0);
+       editor.selection.setRng(rng);
+       editor.selection.normalize();
+
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeType, 3, 'startContainer node type');
+       equal(rng.startOffset, 0, 'startContainer offset');
+       equal(rng.endContainer.nodeType, 3, 'endContainer node type');
+       equal(rng.endOffset, 0, 'endOffset offset');
+});
+
+test('normalize to br from document', function() {
+       var rng;
+
+       if (tinymce.isOpera || tinymce.isIE) {
+               ok(true, "Skipped on Opera/IE since Opera doesn't let you to set the range to document and IE will steal focus.");
+               return;
+       }
+
+       editor.setContent('<p><br /></p>');
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getDoc(), 0);
+       rng.setEnd(editor.getDoc(), 0);
+       editor.selection.setRng(rng);
+       editor.selection.normalize();
+
+       rng = editor.selection.getRng(true);
+       equal(rng.startContainer.nodeName, 'P', 'startContainer node name');
+       equal(rng.startContainer.nodeType, 1, 'startContainer node type');
+       equal(rng.startOffset, 0, 'startContainer offset');
+       equal(rng.endContainer.nodeType, 1, 'endContainer node type');
+       equal(rng.endOffset, 0, 'endOffset offset');
+});
+
+// Only run on non IE browsers since it's not an issue on IE
+if (!tinymce.isIE) {
+       test('normalize to text node from body', function() {
+               var rng;
+
+               editor.setContent('<p>text</p>');
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 0);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeType, 3, 'startContainer node type');
+               equal(rng.startOffset, 0, 'startContainer offset');
+               equal(rng.endContainer.nodeType, 3, 'endContainer node type');
+               equal(rng.endOffset, 0, 'endOffset offset');
+       });
+
+       test('normalize to br from body', function() {
+               var rng;
+
+               editor.setContent('<p><br /></p>');
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 0);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, 'P', 'startContainer node name');
+               equal(rng.startContainer.nodeType, 1, 'startContainer node type');
+               equal(rng.startOffset, 0, 'startContainer offset');
+               equal(rng.endContainer.nodeType, 1, 'endContainer node type');
+               equal(rng.endOffset, 0, 'endOffset offset');
+       });
+
+       test('normalize ignore img', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<img src="about:blank " />';
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, 'BODY', 'startContainer node name');
+               equal(rng.startContainer.nodeType, 1, 'startContainer node type');
+               equal(rng.startOffset, 0, 'startContainer offset');
+               equal(rng.endContainer.nodeName, 'BODY', 'endContainer node name');
+               equal(rng.endContainer.nodeType, 1, 'endContainer node type');
+               equal(rng.endOffset, 1, 'endOffset offset');
+       });
+
+       test('normalize to before/after img', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p><img src="about:blank " /></p>';
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, 'P', 'startContainer node name');
+               equal(rng.startContainer.nodeType, 1, 'startContainer node type');
+               equal(rng.startOffset, 0, 'startContainer offset');
+               equal(rng.endContainer.nodeName, 'P', 'endContainer node name');
+               equal(rng.endContainer.nodeType, 1, 'endContainer node type');
+               equal(rng.endOffset, 1, 'endOffset offset');
+       });
+
+       test('normalize to text node inside P', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p>abc</p>';
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, '#text', 'startContainer node name');
+               equal(rng.startOffset, 0, 'startContainer offset');
+               equal(rng.endContainer.nodeName, '#text', 'endContainer node name');
+               equal(rng.endOffset, 3, 'endOffset offset');
+       });
+
+       test('normalize lean left if at the start of text node', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p><b>a</b><i>b</i></p>';
+               setSelection('i', 0);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, '#text', 'startContainer node name');
+               equal(rng.startContainer.parentNode.nodeName, 'B');
+               equal(rng.startOffset, 1, 'startContainer offset');
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.endContainer.parentNode.nodeName, 'B');
+               equal(rng.endOffset, 1, 'endOffset offset');
+       });
+
+       test('normalize lean start to the right if at end of text node', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p><b>a</b><i>b</i></p>';
+               setSelection('b', 1, 'i', 1);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, '#text', 'startContainer node name');
+               equal(rng.startContainer.parentNode.nodeName, 'I');
+               equal(rng.startOffset, 0, 'startContainer offset');
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.endContainer.parentNode.nodeName, 'I');
+               equal(rng.endOffset, 1, 'endOffset offset');
+       });
+
+       test('normalize lean left but break before br', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p>a<br><b>b</b></p>';
+               setSelection('b', 0);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeValue, 'b');
+               equal(rng.startOffset, 0);
+       });
+
+       test('normalize lean left but break before img', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p>a<img><b>b</b></p>';
+               setSelection('b', 0);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeValue, 'b');
+               equal(rng.startOffset, 0);
+       });
+
+       test('normalize lean left but don\'t walk out the parent block', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p>a</p><p><b>b</b></p>';
+               setSelection('b', 0);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeValue, 'b');
+               equal(rng.startOffset, 0);
+       });
+
+       test('normalize lean left into empty inline elements when caret is before br', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p><i><b></b></i><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.nodeName, 'B');
+               equal(rng.startOffset, 0);
+       });
+
+       test('normalize don\'t lean left into empty inline elements if there is a br element after caret', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p><i><b></b></i><br /><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.nodeName, 'P');
+               equal(rng.startOffset, 2);
+       });
+
+       test('normalize don\'t lean left into empty inline elements if there is a br element before caret', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p><i><b><br /></b></i><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.nodeName, 'P');
+               equal(rng.startOffset, 1);
+       });
+
+       test('normalize don\'t move start/end if it\'s before/after table', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<table><tr><td>X</td></tr></table>';
+               rng = editor.dom.createRng();
+               rng.setStartBefore(editor.getBody().firstChild);
+               rng.setEndAfter(editor.getBody().lastChild);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, 'BODY');
+               equal(rng.startOffset, 0);
+               equal(rng.endContainer.nodeName, 'BODY');
+               equal(rng.endOffset, 1);
+       });
+
+       test('normalize after paragraph', function() {
+               var rng;
+
+               editor.getBody().innerHTML = '<p>a</p>';
+               rng = editor.dom.createRng();
+               rng.setStartAfter(editor.getBody().firstChild);
+               rng.setEndAfter(editor.getBody().lastChild);
+               editor.selection.setRng(rng);
+               editor.selection.normalize();
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, '#text');
+               equal(rng.startOffset, 1);
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.endOffset, 1);
+       });
+}
+
+test('custom elements', function() {
+       var rng;
+
+       editor.setContent('<custom1>test</custom1><custom2>test</custom2>');
+
+       rng = editor.dom.createRng();
+       rng.setStart(editor.getBody(), 0);
+       rng.setEnd(editor.getBody(), 2);
+       editor.selection.setRng(rng);
+
+       equal(editor.selection.getContent(), '<custom1>test</custom1><custom2>test</custom2>');
+});
+
+test('selectorChanged', function() {
+       var newState, newArgs;
+
+       editor.selection.selectorChanged('a[href]', function(state, args) {
+               newState = state;
+               newArgs = args;
+       });
+
+       editor.getBody().innerHTML = '<p><a href="#">text</a></p>';
+       setSelection('a', 0, 'a', 4);
+       editor.nodeChanged();
+
+       ok(newState);
+       equal(newArgs.selector, 'a[href]');
+       equal(newArgs.node, editor.getBody().firstChild.firstChild);
+       equal(newArgs.parents.length, 2);
+
+       editor.getBody().innerHTML = '<p>text</p>';
+       setSelection('p', 0, 'p', 4);
+       editor.nodeChanged();
+       equal(newArgs.selector, 'a[href]');
+       equal(newArgs.node, editor.getBody().firstChild);
+       equal(newArgs.parents.length, 1);
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       fix_list_elements : 0,
+       fix_table_elements : 0,
+       forced_root_block : '',
+       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'
+       },
+       custom_elements : 'custom1,~custom2',
+       extended_valid_elements : 'custom1,custom2',
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Unit tests for tinymce.dom.Selection</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/Selection.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomSerializerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/Serializer.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/Serializer.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/Serializer.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,515 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for tinymce.dom.Serializer</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var DOM = tinymce.DOM;
+
+QUnit.config.reorder = false;
+
+module("tinymce.dom.Serializer", {
+});
+
+test('Schema rules', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(8);
+
+       ser.setRules('@[id|title|class|style],div,img[src|alt|-style|border],span,hr');
+       DOM.setHTML('test', '<img title="test" src="file.gif" data-mce-src="file.gif" alt="test" border="0" style="border: 1px solid red" class="test" /><span id="test2">test</span><hr />');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><img title="test" class="test" src="file.gif" alt="test" border="0" /><span id="test2">test</span><hr /></div>', 'Global rule');
+
+       ser.setRules('*a[*],em/i[*],strong/b[*i*]');
+       DOM.setHTML('test', '<a href="test" data-mce-href="test">test</a><strong title="test" class="test">test2</strong><em title="test">test3</em>');
+       equal(ser.serialize(DOM.get('test')), '<a href="test">test</a><strong title="test">test2</strong><em title="test">test3</em>', 'Wildcard rules');
+
+       ser.setRules('br,hr,input[type|name|value],div[id],span[id],strong/b,a,em/i,a[!href|!name],img[src|border=0|title={$uid}]');
+       DOM.setHTML('test', '<br /><hr /><input type="text" name="test" value="val" class="no" /><span id="test2" class="no"><b class="no">abc</b><em class="no">123</em></span>123<a href="file.html"  data-mce-href="file.html">link</a><a name="anchor"></a><a>no</a><img src="file.gif" data-mce-src="file.gif" />');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><br /><hr /><input type="text" name="test" value="val" /><span id="test2"><strong>abc</strong><em>123</em></span>123<a href="file.html">link</a><a name="anchor"></a>no<img src="file.gif" border="0" title="mce_0" /></div>', 'Output name and attribute rules');
+
+       ser.setRules('a[href|target<_blank?_top|title:forced value]');
+       DOM.setHTML('test', '<a href="file.htm" data-mce-href="file.htm" target="_blank" title="title">link</a><a href="#" data-mce-href="#" target="test">test2</a>');
+       equal(ser.serialize(DOM.get('test')), '<a href="file.htm" target="_blank" title="forced value">link</a><a href="#" title="forced value">test2</a>');
+
+       ser.setRules('img[src|border=0|alt=]');
+       DOM.setHTML('test', '<img src="file.gif" data-mce-src="file.gif" border="0" alt="" />');
+       equal(ser.serialize(DOM.get('test')), '<img src="file.gif" border="0" alt="" />', 'Default attribute with empty value');
+
+       ser.setRules('img[src|border=0|alt=],*[*]');
+       DOM.setHTML('test', '<img src="file.gif" data-mce-src="file.gif" /><hr />');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><img src="file.gif" border="0" alt="" /><hr /></div>');
+
+       ser = new tinymce.dom.Serializer({
+               valid_elements : 'img[src|border=0|alt=]',
+               extended_valid_elements : 'div[id],img[src|alt=]'
+       });
+       DOM.setHTML('test', '<img src="file.gif" data-mce-src="file.gif" alt="" />');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><img src="file.gif" alt="" /></div>');
+
+       ser = new tinymce.dom.Serializer({invalid_elements : 'hr,br'});
+       DOM.setHTML('test', '<img src="file.gif" data-mce-src="file.gif" /><hr /><br />');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><img src="file.gif" alt="" /></div>');
+});
+
+test('Entity encoding', function() {
+       var ser;
+
+       expect(4);
+
+       ser = new tinymce.dom.Serializer({entity_encoding : 'numeric'});
+       DOM.setHTML('test', '&lt;&gt;&amp;&quot;&nbsp;&aring;&auml;&ouml;');
+       equal(ser.serialize(DOM.get('test')), '<div id="test">&lt;&gt;&amp;"&#160;&#229;&#228;&#246;</div>');
+
+       ser = new tinymce.dom.Serializer({entity_encoding : 'named'});
+       DOM.setHTML('test', '&lt;&gt;&amp;&quot;&nbsp;&aring;&auml;&ouml;');
+       equal(ser.serialize(DOM.get('test')), '<div id="test">&lt;&gt;&amp;"&nbsp;&aring;&auml;&ouml;</div>');
+
+       ser = new tinymce.dom.Serializer({entity_encoding : 'named+numeric', entities : '160,nbsp,34,quot,38,amp,60,lt,62,gt'});
+       DOM.setHTML('test', '&lt;&gt;&amp;&quot;&nbsp;&aring;&auml;&ouml;');
+       equal(ser.serialize(DOM.get('test')), '<div id="test">&lt;&gt;&amp;"&nbsp;&#229;&#228;&#246;</div>');
+
+       ser = new tinymce.dom.Serializer({entity_encoding : 'raw'});
+       DOM.setHTML('test', '&lt;&gt;&amp;&quot;&nbsp;&aring;&auml;&ouml;');
+       equal(ser.serialize(DOM.get('test')), '<div id="test">&lt;&gt;&amp;"\u00a0\u00e5\u00e4\u00f6</div>');
+});
+
+test('Form elements (general)', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(5);
+
+       ser.setRules('form[method],label[for],input[type|name|value|checked|disabled|readonly|length|maxlength],select[multiple],option[value|selected],textarea[name|disabled|readonly]');
+
+       DOM.setHTML('test', '<input type="text" />');
+       equal(ser.serialize(DOM.get('test')), '<input type="text" />');
+
+       DOM.setHTML('test', '<input type="text" value="text" length="128" maxlength="129" />');
+       equal(ser.serialize(DOM.get('test')), '<input type="text" value="text" length="128" maxlength="129" />');
+
+       DOM.setHTML('test', '<form method="post"><input type="hidden" name="method" value="get" /></form>');
+       equal(ser.serialize(DOM.get('test')), '<form method="post"><input type="hidden" name="method" value="get" /></form>');
+
+       DOM.setHTML('test', '<label for="test">label</label>');
+       equal(ser.serialize(DOM.get('test')), '<label for="test">label</label>');
+
+       DOM.setHTML('test', '<input type="checkbox" value="test" /><input type="button" /><textarea></textarea>');
+       equal(ser.serialize(DOM.get('test')), '<input type="checkbox" value="test" /><input type="button" /><textarea></textarea>');
+});
+
+test('Form elements (checkbox)', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(4);
+
+       ser.setRules('form[method],label[for],input[type|name|value|checked|disabled|readonly|length|maxlength],select[multiple],option[value|selected]');
+
+       DOM.setHTML('test', '<input type="checkbox" value="1">');
+       equal(ser.serialize(DOM.get('test')), '<input type="checkbox" value="1" />');
+
+       DOM.setHTML('test', '<input type="checkbox" value="1" checked disabled readonly>');
+       equal(ser.serialize(DOM.get('test')), '<input type="checkbox" value="1" checked="checked" disabled="disabled" readonly="readonly" />');
+
+       DOM.setHTML('test', '<input type="checkbox" value="1" checked="1" disabled="1" readonly="1">');
+       equal(ser.serialize(DOM.get('test')), '<input type="checkbox" value="1" checked="checked" disabled="disabled" readonly="readonly" />');
+
+       DOM.setHTML('test', '<input type="checkbox" value="1" checked="true" disabled="true" readonly="true">');
+       equal(ser.serialize(DOM.get('test')), '<input type="checkbox" value="1" checked="checked" disabled="disabled" readonly="readonly" />');
+});
+
+test('Form elements (select)', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(7);
+
+       ser.setRules('form[method],label[for],input[type|name|value|checked|disabled|readonly|length|maxlength],select[multiple],option[value|selected]');
+
+       DOM.setHTML('test', '<select><option value="1">test1</option><option value="2" selected>test2</option></select>');
+       equal(ser.serialize(DOM.get('test')), '<select><option value="1">test1</option><option value="2" selected="selected">test2</option></select>');
+
+       DOM.setHTML('test', '<select><option value="1">test1</option><option selected="1" value="2">test2</option></select>');
+       equal(ser.serialize(DOM.get('test')), '<select><option value="1">test1</option><option value="2" selected="selected">test2</option></select>');
+
+       DOM.setHTML('test', '<select><option value="1">test1</option><option value="2" selected="true">test2</option></select>');
+       equal(ser.serialize(DOM.get('test')), '<select><option value="1">test1</option><option value="2" selected="selected">test2</option></select>');
+
+       DOM.setHTML('test', '<select multiple></select>');
+       equal(ser.serialize(DOM.get('test')), '<select multiple="multiple"></select>');
+
+       DOM.setHTML('test', '<select multiple="multiple"></select>');
+       equal(ser.serialize(DOM.get('test')), '<select multiple="multiple"></select>');
+
+       DOM.setHTML('test', '<select multiple="1"></select>');
+       equal(ser.serialize(DOM.get('test')), '<select multiple="multiple"></select>');
+
+       DOM.setHTML('test', '<select></select>');
+       equal(ser.serialize(DOM.get('test')), '<select></select>');
+});
+
+test('List elements', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(5);
+
+       ser.setRules('ul[compact],ol,li');
+
+       DOM.setHTML('test', '<ul compact></ul>');
+       equal(ser.serialize(DOM.get('test')), '<ul compact="compact"></ul>');
+
+       DOM.setHTML('test', '<ul compact="compact"></ul>');
+       equal(ser.serialize(DOM.get('test')), '<ul compact="compact"></ul>');
+
+       DOM.setHTML('test', '<ul compact="1"></ul>');
+       equal(ser.serialize(DOM.get('test')), '<ul compact="compact"></ul>');
+
+       DOM.setHTML('test', '<ul></ul>');
+       equal(ser.serialize(DOM.get('test')), '<ul></ul>');
+
+       DOM.setHTML('test', '<ol><li>a</li><ol><li>b</li><li>c</li></ol><li>e</li></ol>');
+       equal(ser.serialize(DOM.get('test')), '<ol><li>a<ol><li>b</li><li>c</li></ol></li><li>e</li></ol>');
+});
+
+test('Tables', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(4);
+
+       ser.setRules('table,tr,td[nowrap]');
+
+       DOM.setHTML('test', '<table><tr><td></td></tr></table>');
+       equal(ser.serialize(DOM.get('test')), '<table><tr><td></td></tr></table>');
+
+       DOM.setHTML('test', '<table><tr><td nowrap></td></tr></table>');
+       equal(ser.serialize(DOM.get('test')), '<table><tr><td nowrap="nowrap"></td></tr></table>');
+
+       DOM.setHTML('test', '<table><tr><td nowrap="nowrap"></td></tr></table>');
+       equal(ser.serialize(DOM.get('test')), '<table><tr><td nowrap="nowrap"></td></tr></table>');
+
+       DOM.setHTML('test', '<table><tr><td nowrap="1"></td></tr></table>');
+       equal(ser.serialize(DOM.get('test')), '<table><tr><td nowrap="nowrap"></td></tr></table>');
+});
+
+test('Styles', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(1);
+
+       ser.setRules('*[*]');
+
+       DOM.setHTML('test', '<span style="border: 1px solid red" data-mce-style="border: 1px solid red;">test</span>');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><span style="border: 1px solid red;">test</span></div>');
+});
+
+test('Comments', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(1);
+
+       ser.setRules('*[*]');
+
+       DOM.setHTML('test', '<!-- abc -->');
+       equal(ser.serialize(DOM.get('test')), '<div id="test"><!-- abc --></div>');
+});
+
+test('Non HTML elements and attributes', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(2);
+
+       ser.setRules('*[*]');
+       ser.schema.addValidChildren('+div[prefix:test]');
+
+       DOM.setHTML('test', '<div test:attr="test">test</div>');
+       equal(ser.serialize(DOM.get('test'), {getInner : 1}), '<div test:attr="test">test</div>');
+
+       DOM.setHTML('test', 'test1<prefix:test>Test</prefix:test>test2');
+       equal(ser.serialize(DOM.get('test')), '<div id="test">test1<prefix:test>Test</prefix:test>test2</div>');
+});
+
+test('Padd empty elements', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(1);
+
+       ser.setRules('#p');
+
+       DOM.setHTML('test', '<p>test</p><p></p>');
+       equal(ser.serialize(DOM.get('test')), '<p>test</p><p>&nbsp;</p>');
+});
+
+test('Remove empty elements', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(1);
+
+       ser.setRules('-p');
+
+       DOM.setHTML('test', '<p>test</p><p></p>');
+       equal(ser.serialize(DOM.get('test')), '<p>test</p>');
+});
+
+test('Pre/post process events', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(3);
+
+       ser.setRules('div[id],span[id|class],a[href],b[class]');
+
+       ser.onPreProcess = function(o) {
+               equal(o.test, 'abc');
+               DOM.setAttrib(o.node.getElementsByTagName('span')[0], 'class', 'abc');
+       };
+
+       ser.onPostProcess = function(o) {
+               equal(o.test, 'abc');
+               o.content = o.content.replace(/<b>/g, '<b class="123">');
+       };
+
+       DOM.setHTML('test', '<span id="test2"><b>abc</b></span>123<a href="file.html" data-mce-href="file.html">link</a>');
+       equal(ser.serialize(DOM.get('test'), {test : 'abc'}), '<div id="test"><span id="test2" class="abc"><b class="123">abc</b></span>123<a href="file.html">link</a></div>');
+});
+
+test('Script with non JS type attribute', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<s'+'cript type="mylanguage"></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript type="mylanguage"></s'+'cript>');
+});
+
+test('Script with tags inside a comment', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<s'+'cript>// <img src="test"><a href="#"></a></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n// <img src="test"><a href="#"></a>\n// ]]></s'+'cript>');
+});
+
+test('Script with less than', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<s'+'cript>1 < 2;</s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script with type attrib and less than', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<s'+'cript type="text/javascript">1 < 2;</s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<script>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script with whitespace in beginning/end', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>\n\t1 < 2;\n\t if (2 < 1)\n\t\talert(1);\n</s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n\t1 < 2;\n\t if (2 < 1)\n\t\talert(1);\n// ]]></s'+'cript>');
+});
+
+test('Script with a HTML comment and less than', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script><!-- 1 < 2; // --></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script with white space in beginning, comment and less than', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>\n\n<!-- 1 < 2;\n\n--></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script with comments and cdata', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>// <![CDATA[1 < 2; // ]]></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script with cdata', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script><![CDATA[1 < 2; ]]></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script whitespace in beginning/end and cdata', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>\n\n<![CDATA[\n\n1 < 2;\n\n]]>\n\n</s'+'cript>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<s'+'cript>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
+});
+
+test('Script with src attr', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script src="test.js" data-mce-src="test.js"></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')), '<s'+'cript src="test.js"></s'+'cript>');
+});
+
+test('Script with HTML comment, comment and CDATA', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script><!--// <![CDATA[var hi = "hello";// ]]>--></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')), '<script>// <![CDATA[\nvar hi = \"hello\";\n// ]]></s'+'cript>');
+});
+
+test('Script with block comment around cdata', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>/* <![CDATA[ */\nvar hi = "hello";\n/* ]]> */</s'+'cript>');
+       equal(ser.serialize(DOM.get('test')), '<script>// <![CDATA[\nvar hi = \"hello\";\n// ]]></s'+'cript>');
+});
+
+test('Script with html comment and block comment around cdata', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script><!-- /* <![CDATA[ */\nvar hi = "hello";\n/* ]]>*/--></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')), '<script>// <![CDATA[\nvar hi = \"hello\";\n// ]]></s'+'cript>');
+});
+
+test('Script with line comment and html comment', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>// <!--\nvar hi = "hello";\n// --></s'+'cript>');
+       equal(ser.serialize(DOM.get('test')), '<script>// <![CDATA[\nvar hi = \"hello\";\n// ]]></s'+'cript>');
+});
+
+test('Script with block comment around html comment', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+       ser.setRules('script[type|language|src]');
+
+       DOM.setHTML('test', '<script>/* <!-- */\nvar hi = "hello";\n/*-->*/</s'+'cript>');
+       equal(ser.serialize(DOM.get('test')), '<script>// <![CDATA[\nvar hi = \"hello\";\n// ]]></s'+'cript>');
+});
+
+test('Protected blocks', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(3);
+
+       ser.setRules('noscript[test]');
+
+       DOM.setHTML('test', '<!--mce:protected ' + escape('<noscript test="test"><br></noscript>') + '-->');
+       equal(ser.serialize(DOM.get('test')), '<noscript test="test"><br></noscript>');
+
+       DOM.setHTML('test', '<!--mce:protected ' + escape('<noscript><br></noscript>') + '-->');
+       equal(ser.serialize(DOM.get('test')), '<noscript><br></noscript>');
+
+       DOM.setHTML('test', '<!--mce:protected ' + escape('<noscript><!-- text --><br></noscript>') + '-->');
+       equal(ser.serialize(DOM.get('test')), '<noscript><!-- text --><br></noscript>');
+});
+
+test('Style with whitespace at beginning', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true, valid_children: '+body[style]'});
+       ser.setRules('style');
+
+       DOM.setHTML('test', '<style> body { background:#fff }</style>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<style><!--\n body { background:#fff }\n--></style>');
+});
+
+test('Style with cdata', 1, function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true, valid_children: '+body[style]'});
+       ser.setRules('style');
+
+       DOM.setHTML('test', '<style>\r\n<![CDATA[\r\n   body { background:#fff }]]></style>');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<style><!--\nbody { background:#fff }\n--></style>');
+});
+
+test('CDATA', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       expect(2);
+
+       ser.setRules('span');
+
+       DOM.setHTML('test', '123<!--[CDATA[<test>]]-->abc');
+       equal(ser.serialize(DOM.get('test')), '123<![CDATA[<test>]]>abc');
+
+       DOM.setHTML('test', '123<!--[CDATA[<te\n\nst>]]-->abc');
+       equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '123<![CDATA[<te\n\nst>]]>abc');
+});
+
+test('BR at end of blocks', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       ser.setRules('ul,li,br');
+
+       DOM.setHTML('test', '<ul><li>test<br /></li><li>test<br /></li><li>test<br /></li></ul>');
+       equal(ser.serialize(DOM.get('test')), '<ul><li>test</li><li>test</li><li>test</li></ul>');
+});
+
+test('Map elements', function() {
+       var ser = new tinymce.dom.Serializer({fix_list_elements : true});
+
+       ser.setRules('map[id|name],area[shape|coords|href|target|alt]');
+
+       DOM.setHTML('test', '<map id="planetmap" name="planetmap"><area shape="rect" coords="0,0,82,126" href="sun.htm" data-mce-href="sun.htm" target="_blank" alt="sun" /></map>');
+       equal(ser.serialize(DOM.get('test')).toLowerCase(), '<map id="planetmap" name="planetmap"><area shape="rect" coords="0,0,82,126" href="sun.htm" target="_blank" alt="sun" /></map>');
+});
+
+test('Custom elements', function() {
+       var ser = new tinymce.dom.Serializer({
+               custom_elements: 'custom1,~custom2',
+               valid_elements: 'custom1,custom2'
+       });
+
+       document.createElement('custom1');
+       document.createElement('custom2');
+
+       DOM.setHTML('test', '<p><custom1>c1</custom1><custom2>c2</custom2></p>');
+       equal(ser.serialize(DOM.get('test')), '<custom1>c1</custom1><custom2>c2</custom2>');
+});
+
+test('Remove internal classes', function() {
+       var ser = new tinymce.dom.Serializer({
+               valid_elements: 'span[class]'
+       });
+
+       DOM.setHTML('test', '<span class="a mce-item-X mce-item-selected b"></span>');
+       equal(ser.serialize(DOM.get('test')), '<span class="a b"></span>');
+
+       DOM.setHTML('test', '<span class="a mce-item-X"></span>');
+       equal(ser.serialize(DOM.get('test')), '<span class="a"></span>');
+
+       DOM.setHTML('test', '<span class="mce-item-X"></span>');
+       equal(ser.serialize(DOM.get('test')), '<span></span>');
+
+       DOM.setHTML('test', '<span class="mce-item-X b"></span>');
+       equal(ser.serialize(DOM.get('test')), '<span class=" b"></span>');
+
+       DOM.setHTML('test', '<span class="b mce-item-X"></span>');
+       equal(ser.serialize(DOM.get('test')), '<span class="b"></span>');
+});
+</script>
+
+       <h1 id="qunit-header">Unit tests for tinymce.dom.Serializer</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <div id="test"></div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/Serializer.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomTridentSelectionhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/TridentSelection.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/TridentSelection.html                               (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/TridentSelection.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,586 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Unit tests for DOM Selection IE implementation</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+</head>
+<body>
+<script>
+var editor, rng;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("IE Selection", {
+       autostart: false
+});
+
+if (tinymce.isIE && !window.getSelection) {
+       test("Selection of element containing text", function(){
+               expect(5);
+               
+               editor.setContent('<p>123</p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, '#text', 'Start container is text node');
+               equal(rng.endContainer.nodeName, '#text', 'End container is text node');
+               equal(rng.startOffset, 0, 'Start of text node');
+               equal(rng.endOffset, 3, 'End of text node');
+               equal(editor.dom.getOuterHTML(rng.cloneContents()), '123', 'Contents matches');
+       });
+       
+       test("Single image selection", function(){
+               expect(6);
+               
+               editor.setContent('<p><img src="about:blank" /></p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStartBefore(editor.dom.select('img')[0]);
+               rng.setEndAfter(editor.dom.select('img')[0]);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'P', 'Check startContainer');
+               equal(rng.endContainer.nodeName, 'P', 'Check endContainer');
+               equal(rng.startOffset, 0, 'Check startOffset');
+               equal(rng.endOffset, 1, 'Check endOffset');
+               equal(cleanHtml(editor.dom.getOuterHTML(rng.cloneContents()).toLowerCase()), '<img src="about:blank">', 'Check contents');
+               ok(editor.selection.getRng().item, 'Check if it\'s a control selection');
+       });
+       
+       test("Multiple image selection", function(){
+               expect(6);
+               
+               editor.setContent('<p><img src="about:blank" /><img src="about:blank" /></p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStartBefore(editor.dom.select('img')[0]);
+               rng.setEndAfter(editor.dom.select('img')[1]);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'P');
+               equal(rng.endContainer.nodeName, 'P');
+               equal(rng.startOffset, 0);
+               equal(rng.endOffset, 2);
+               equal(editor.dom.getOuterHTML(rng.cloneContents()).toLowerCase(), '<img src="about:blank"><img src="about:blank">');
+               ok(editor.selection.getRng().parentElement, 'Is text selection');
+       });
+       
+       test("Text node selection", function(){
+               expect(5);
+               
+               editor.setContent('<p>1234</p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody().firstChild.firstChild, 1);
+               rng.setEnd(editor.getBody().firstChild.firstChild, 3);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, '#text');
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.startOffset, 1);
+               equal(rng.endOffset, 3);
+               equal(editor.dom.getOuterHTML(rng.cloneContents()), '23');
+       });
+       
+       test("Text node selection between two elements", function(){
+               expect(5);
+               
+               editor.setContent('<p>1234</p><p>abcd</p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody().firstChild.firstChild, 1);
+               rng.setEnd(editor.getBody().childNodes[1].firstChild, 3);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, '#text');
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.startOffset, 1);
+               equal(rng.endOffset, 3);
+               equal(editor.dom.getOuterHTML(rng.cloneContents()).replace(/[\r\n]/g, '').toLowerCase(), '<p>234</p><p>abc</p>');
+               
+               editor.setContent('<p>1</p><p>1234</p><p>abcd</p><p>2</p>', {
+                       format: 'raw'
+               });
+               /*
+                rng = editor.dom.createRng();
+                rng.setStartBefore(editor.dom.select('p')[1]);
+                rng.setEndAfter(editor.dom.select('p')[2]);
+                editor.selection.setRng(rng);
+                rng = editor.selection.getRng(1);
+                equal(rng.startContainer.nodeName, 'BODY', "startContainer type check");
+                equal(rng.startOffset, 1, "startOffset doesn't match");
+                equal(rng.endContainer.nodeName, 'BODY', "endContainer type check");
+                equal(rng.endOffset, 3, "endOffset doesn't match");
+                equal(editor.dom.getOuterHTML(rng.cloneContents()).replace(/[\r\n]/g, '').toLowerCase(), '<p>1234</p><p>abcd</p>');*/
+       });
+       
+       test("Mixed selection start at element end at text", function(){
+               expect(5);
+               
+               editor.setContent('<p><img src="about:blank" />text</p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStartBefore(editor.dom.select('img')[0]);
+               rng.setEnd(editor.getBody().firstChild.lastChild, 3);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'P');
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.startOffset, 0);
+               equal(rng.endOffset, 3);
+               equal(editor.dom.getOuterHTML(rng.cloneContents()).toLowerCase(), '<img src="about:blank">tex');
+       });
+       
+       test("Mixed selection start at text end at element", function(){
+               expect(5);
+               
+               editor.setContent('<p>text<img src="about:blank" /></p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody().firstChild.firstChild, 1);
+               rng.setEndAfter(editor.getBody().firstChild.lastChild);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               
+               equal(rng.startContainer.nodeName, '#text');
+               equal(rng.startOffset, 1);
+               
+               equal(rng.endContainer.nodeName, 'P');
+               equal(rng.endOffset, 2);
+               
+               equal(editor.dom.getOuterHTML(rng.cloneContents()).toLowerCase(), 'ext<img src="about:blank">');
+       });
+       
+       test("Caret position before image", function(){
+               expect(4);
+               
+               editor.setContent('<p><img src="about:blank" /><img src="about:blank" /></p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStartBefore(editor.dom.select('img')[0]);
+               rng.setEndBefore(editor.dom.select('img')[0]);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'P');
+               equal(rng.endContainer.nodeName, 'P');
+               equal(rng.startOffset, 0);
+               equal(rng.endOffset, 0);
+       });
+       
+       test("Caret position between images", function(){
+               expect(4);
+               
+               editor.setContent('<p><img src="about:blank" /><img src="about:blank" /></p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStartAfter(editor.dom.select('img')[0]);
+               rng.setEndAfter(editor.dom.select('img')[0]);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'P');
+               equal(rng.endContainer.nodeName, 'P');
+               equal(rng.startOffset, 1);
+               equal(rng.endOffset, 1);
+       });
+       
+       test("Caret position after image", function(){
+               expect(4);
+               
+               editor.setContent('<p><img src="about:blank" /><img src="about:blank" /></p>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStartAfter(editor.dom.select('img')[1]);
+               rng.setEndAfter(editor.dom.select('img')[1]);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'P');
+               equal(rng.endContainer.nodeName, 'P');
+               equal(rng.startOffset, 2);
+               equal(rng.endOffset, 2);
+       });
+       
+       test("Selection of empty text element", function(){
+               expect(6);
+               
+               editor.setContent('<div></div>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody(), 0);
+               rng.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, 'BODY');
+               equal(rng.endContainer.nodeName, 'BODY');
+               equal(rng.startOffset, 0);
+               equal(rng.endOffset, 1);
+               equal(rng.startContainer.childNodes[0].innerHTML, '');
+               equal(editor.dom.getOuterHTML(rng.cloneContents()).toLowerCase(), '<div></div>');
+       });
+
+       test("Selection of empty text element with caret inside", function(){
+               expect(6);
+               
+               editor.setContent('<div></div>', {
+                       format: 'raw'
+               });
+               
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody().firstChild, 0);
+               rng.setEnd(editor.getBody().firstChild, 0);
+               editor.selection.setRng(rng);
+               
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, 'DIV');
+               equal(rng.endContainer.nodeName, 'DIV');
+               equal(rng.startOffset, 0);
+               equal(rng.endOffset, 0);
+               equal(rng.startContainer.innerHTML, '');
+               equal(editor.dom.getOuterHTML(rng.cloneContents()).toLowerCase(), '');
+       });
+
+       /*test("Caret position before table", function() {
+               var table, rng;
+
+               editor.focus();
+               editor.setContent('<p>Before</p><table id="table" border="1"><tr><td>Cell 1</td><td>Cell 2</td></tr><tr><td>Cell 3</td><td>Cell 4</td></tr></table><p>After</p>');
+
+               table = editor.dom.get('table');
+               rng = editor.selection.getRng();
+               rng.moveToElementText(table);
+               rng.move('character', -1);
+               rng.select();
+
+               rng = editor.selection.getRng(1);
+               equal(rng.startContainer.nodeName, 'BODY');
+               equal(rng.startOffset, 1);
+               equal(rng.endContainer.nodeName, 'BODY');
+               equal(rng.endOffset, 1);
+       });*/
+
+       test("Selection end within empty element", function() {
+               var rng;
+
+               editor.focus();
+               editor.getBody().innerHTML = '<p>123</p><p></p>';
+
+               rng = editor.execCommand('SelectAll');
+
+               rng = editor.selection.getRng(true);
+               equal(rng.startContainer.nodeName, '#text');
+               equal(rng.startOffset, 0);
+               equal(rng.endContainer.nodeName, 'BODY');
+               equal(rng.endOffset, 2);
+       });
+
+       test("Selection after paragraph", function() {
+               var rng;
+
+               editor.focus();
+               editor.getBody().innerHTML = '<p>123</p><p>abcd</p>';
+
+               rng = editor.dom.createRng();
+               rng.setStart(editor.getBody().firstChild, 1);
+               rng.setEnd(editor.getBody().firstChild, 1);
+               editor.selection.setRng(rng);
+
+               rng = editor.selection.getRng(true);
+               ok(rng.startContainer == rng.endContainer);
+               equal(rng.startContainer.nodeName, '#text');
+               equal(rng.startOffset, 3);
+               equal(rng.endContainer.nodeName, '#text');
+               equal(rng.endOffset, 3);
+       });
+
+       test("Selection of text outside of a block element", function() {
+               var r;
+               
+               editor.settings.forced_root_block = '';
+               editor.focus();
+               editor.getBody().innerHTML = '<ul><li>Item</li></ul>Text';
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().lastChild, 2);
+               r.setEnd(editor.getBody().lastChild, 2);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().lastChild, "Start container is text node.");
+               equal(r.endContainer, editor.getBody().lastChild, "End container is text node.");
+               equal(r.startOffset, 2);
+               equal(r.endOffset, 2);
+
+               equal(editor.selection.getStart(), editor.getBody(), "Selection start is body.");
+               deepEqual(editor.selection.getSelectedBlocks(), [], "No blocks selected.");
+       });
+
+       test("Resizable element text selection", function() {
+               var r;
+
+               editor.getBody().innerHTML = '<div style="width: 100px; height:100px;"><table><tr><td>.</td></tr></table>abc</div>';
+               editor.focus();
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().firstChild.lastChild, 1);
+               r.setEnd(editor.getBody().firstChild.lastChild, 2);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().firstChild.lastChild, "Start container is text node.");
+               equal(r.endContainer, editor.getBody().firstChild.lastChild, "End container is text node.");
+               equal(r.startOffset, 1);
+               equal(r.endOffset, 2);
+       });
+
+       test("Resizable element before table selection", function() {
+               var r;
+
+               editor.getBody().innerHTML = '<div style="width: 100px; height:100px;"><table><tr><td>.</td></tr></table></div>';
+               editor.focus();
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().firstChild, 0);
+               r.setEnd(editor.getBody().firstChild, 0);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().firstChild, "Start container is div node.");
+               equal(r.endContainer, editor.getBody().firstChild, "End container is div node.");
+               equal(r.startOffset, 0);
+               equal(r.endOffset, 0);
+       });
+
+       test("Fragmented text nodes after element", function() {
+               var r;
+
+               editor.getBody().innerHTML = '<b>x</b>';
+               editor.getBody().appendChild(editor.getDoc().createTextNode('1'));
+               editor.getBody().appendChild(editor.getDoc().createTextNode('23'));
+               editor.getBody().appendChild(editor.getDoc().createTextNode('456'));
+               editor.getBody().appendChild(editor.getDoc().createTextNode('7890'));
+               editor.focus();
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().lastChild, 1);
+               r.setEnd(editor.getBody().lastChild, 1);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().lastChild, "Start container is last text node.");
+               equal(r.endContainer, editor.getBody().lastChild, "End container is last text node.");
+               equal(r.startOffset, 1);
+               equal(r.endOffset, 1);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().childNodes[2], 2);
+               r.setEnd(editor.getBody().childNodes[2], 2);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().childNodes[2], "Start container is second text node.");
+               equal(r.endContainer, editor.getBody().childNodes[2], "End container is second text node.");
+               equal(r.startOffset, 2);
+               equal(r.endOffset, 2);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().childNodes[3], 0);
+               r.setEnd(editor.getBody().childNodes[3], 1);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().childNodes[2], "Start container is second text node (lean left).");
+               equal(r.endContainer, editor.getBody().childNodes[3], "End container is third text node.");
+               equal(r.startOffset, 2);
+               equal(r.endOffset, 1);
+       });
+
+       test("Fragmented text nodes before element", function() {
+               var r;
+
+               editor.getBody().innerHTML = '';
+               editor.getBody().appendChild(editor.getDoc().createTextNode('1'));
+               editor.getBody().appendChild(editor.getDoc().createTextNode('23'));
+               editor.getBody().appendChild(editor.getDoc().createTextNode('456'));
+               editor.getBody().appendChild(editor.getDoc().createTextNode('7890'));
+               editor.getBody().appendChild(editor.dom.create('b', null, 'x'));
+               editor.focus();
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().childNodes[3], 1);
+               r.setEnd(editor.getBody().childNodes[3], 1);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().childNodes[3], "Start container is last text node.");
+               equal(r.endContainer, editor.getBody().childNodes[3], "End container is last text node.");
+               equal(r.startContainer.nodeValue, '7890');
+               equal(r.startOffset, 1);
+               equal(r.endOffset, 1);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().childNodes[1], 2);
+               r.setEnd(editor.getBody().childNodes[1], 2);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().childNodes[2], "Start container is second text node. (lean right)");
+               equal(r.endContainer, editor.getBody().childNodes[2], "End container is second text node.");
+               equal(r.startContainer.nodeValue, '456');
+               equal(r.startOffset, 0);
+               equal(r.endOffset, 0);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody().childNodes[1], 0);
+               r.setEnd(editor.getBody().childNodes[1], 1);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody().childNodes[1], "Start container is second text node.");
+               equal(r.endContainer, editor.getBody().childNodes[1], "End container is third text node.");
+               equal(r.startContainer.nodeValue, '23');
+               equal(r.endContainer.nodeValue, '23');
+               equal(r.startOffset, 0);
+               equal(r.endOffset, 1);
+       });
+
+       test("Non contentEditable elements", function() {
+               var r;
+
+               editor.getBody().innerHTML = '<span contentEditable="false">a</span><span contentEditable="false">a</span><span contentEditable="false">a</span>';
+               editor.focus();
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody(), 0);
+               r.setEnd(editor.getBody(), 0);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody(), "Start container is before first nonEditable.");
+               equal(r.endContainer, editor.getBody(), "End container is before  first nonEditable.");
+               equal(r.startOffset, 0);
+               equal(r.endOffset, 0);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody(), 0);
+               r.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody(), "Start container before first nonEditable.");
+               equal(r.endContainer, editor.getBody(), "End container is after first nonEditable.");
+               equal(r.startOffset, 0);
+               equal(r.endOffset, 1);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody(), 0);
+               r.setEnd(editor.getBody(), 2);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody(), "Start container before first nonEditable.");
+               equal(r.endContainer, editor.getBody(), "End container is after second nonEditable.");
+               equal(r.startOffset, 0);
+               equal(r.endOffset, 2);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody(), 1);
+               r.setEnd(editor.getBody(), 1);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody(), "Start container is before second nonEditable.");
+               equal(r.endContainer, editor.getBody(), "End container is div before second nonEditable.");
+               equal(r.startOffset, 1);
+               equal(r.endOffset, 1);
+
+               r = editor.dom.createRng();
+               r.setStart(editor.getBody(), 2);
+               r.setEnd(editor.getBody(), 2);
+               editor.selection.setRng(r);
+
+               r = editor.selection.getRng(true);
+               equal(r.startContainer, editor.getBody(), "Start container is after last nonEditable.");
+               equal(r.endContainer, editor.getBody(), "End container is after last nonEditable.");
+               equal(r.startOffset, 2);
+               equal(r.endOffset, 2);
+       });
+} else {
+       test("Skipped ie_selection tests as not running in IE.", function() {
+               ok(true, "Dummy assert");
+       });
+}
+
+function getCaretInfo() {
+       editor.focus();
+       var rng = editor.selection.getRng(1);
+       alert(rng.startContainer + " - " + rng.startOffset);
+       alert(rng.endContainer + " - " + rng.endOffset);
+       editor.focus();
+}
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+
+       <h1 id="qunit-header">Unit tests for DOM Selection IE implementation</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+       <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+                       <a href="javascript:getCaretInfo();">[getCaretInfo]</a>
+               </div>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/TridentSelection.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcedomtestcss"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/test.css (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/test.css                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/test.css       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,120 @@
</span><ins>+body, div, h1 { font-family: 'trebuchet ms', verdana, arial; margin: 0; padding: 0 }
+body {font-size: 10pt; }
+h1 { padding: 15px; font-size: large; background-color: #06b; color: white; }
+h1 a { color: white; }
+h2 { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal }
+
+.pass { color: green; } 
+.fail { color: red; } 
+p.result { margin-left: 1em; }
+
+#banner { height: 2em; border-bottom: 1px solid white; }
+h2.pass { background-color: green; }
+h2.fail { background-color: red; }
+
+div.testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; }
+
+ol#tests > li > strong { cursor:pointer; }
+
+div#fx-tests h4 {
+       background: red;
+}
+
+div#fx-tests h4.pass {
+       background: green;
+}
+
+div#fx-tests div.box {
+       background: red url(data/cow.jpg) no-repeat;
+       overflow: hidden;
+       border: 2px solid #000;
+}
+
+div#fx-tests div.overflow {
+       overflow: visible;
+}
+
+div.inline {
+       display: inline;
+}
+
+div.autoheight {
+       height: auto;
+}
+
+div.autowidth {
+       width: auto;
+}
+
+div.autoopacity {
+       opacity: auto;
+}
+
+div.largewidth {
+       width: 100px;
+}
+
+div.largeheight {
+       height: 100px;
+}
+
+div.largeopacity {
+       filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100);
+}
+
+div.medwidth {
+       width: 50px;
+}
+
+div.medheight {
+       height: 50px;
+}
+
+div.medopacity {
+       opacity: 0.5;
+       filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50);
+}
+
+div.nowidth {
+       width: 0px;
+}
+
+div.noheight {
+       height: 0px;
+}
+
+div.noopacity {
+       opacity: 0;
+       filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
+}
+
+div.hidden {
+       display: none;
+}
+
+div#fx-tests div.widewidth {
+       background-repeat: repeat-x;
+}
+
+div#fx-tests div.wideheight {
+       background-repeat: repeat-y;
+}
+
+div#fx-tests div.widewidth.wideheight {
+       background-repeat: repeat;
+}
+
+div#fx-tests div.noback {
+       background-image: none;
+}
+
+div.chain, div.chain div { width: 100px; height: 20px; position: relative; float: left; }
+div.chain div { position: absolute; top: 0px; left: 0px; }
+
+div.chain.test { background: red; }
+div.chain.test div { background: green; }
+
+div.chain.out { background: green; }
+div.chain.out div { background: red; display: none; }
+
+div#show-tests * { display: none; }
</ins></span></pre></div>
<a id="trunktestsquniteditortinymcedomtestsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/dom/tests.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/dom/tests.js                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/dom/tests.js       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+{
+       "title": "tinymce.dom",
+       "tests": [
+               {"title": "DOMUtils", "url": "DOMUtils.html"},
+               {"title": "DOMUtils (jQuery)", "url": "DOMUtils_jquery.html"},
+               {"title": "EventUtils", "url": "EventUtils.html"},
+               {"title": "Range (IE/Native)", "url": "Range.html"},
+               {"title": "Selection", "url": "Selection.html"},
+               {"title": "Serializer", "url": "Serializer.html"},
+               {"title": "TridentSelection (IE)", "url": "TridentSelection.html"}
+       ]
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/dom/tests.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlDomParserhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/DomParser.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/DomParser.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/DomParser.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,506 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.DomParser tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.DomParser");
+
+QUnit.config.reorder = false;
+
+var schema = new tinymce.html.Schema({valid_elements: '*[class|title]'});
+var serializer = new tinymce.html.Serializer({}, schema);
+var parser, root;
+
+function countNodes(node, counter) {
+       var sibling;
+
+       if (!counter)
+               counter = {};
+
+       if (node.name in counter) {
+               counter[node.name]++;
+       } else
+               counter[node.name] = 1;
+
+       for (sibling = node.firstChild; sibling; sibling = sibling.next) {
+               countNodes(sibling, counter);
+       }
+
+       return counter;
+}
+
+schema.addValidChildren('+body[style]');
+
+test('Parse element', function() {
+       var parser, root;
+
+       expect(7);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<B title="title" class="class">test</B>');
+       equal(serializer.serialize(root), '<b class="class" title="title">test</b>', 'Inline element');
+       equal(root.firstChild.type, 1, 'Element type');
+       equal(root.firstChild.name, 'b', 'Element name');
+       deepEqual(root.firstChild.attributes, [{name: 'title', value: 'title'}, {name: 'class', value: 'class'}], 'Element attributes');
+       deepEqual(countNodes(root), {body:1, b:1, '#text':1}, 'Element attributes (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <SCRIPT>  \t\r\n   a < b > \t\r\n   </S' + 'CRIPT>   \t\r\n  ');
+       equal(serializer.serialize(root), '<script>  \t\r\n   a < b > \t\r\n   </s' + 'cript>', 'Retain code inside SCRIPT');
+       deepEqual(countNodes(root), {body:1, script:1, '#text':1}, 'Retain code inside SCRIPT (count)');
+});
+
+test('Whitespace', function() {
+       expect(12);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <B>  \t\r\n   test  \t\r\n   </B>   \t\r\n  ');
+       equal(serializer.serialize(root), ' <b> test </b> ', 'Redundant whitespace (inline element)');
+       deepEqual(countNodes(root), {body:1, b:1, '#text':3}, 'Redundant whitespace (inline element) (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <P>  \t\r\n   test  \t\r\n   </P>   \t\r\n  ');
+       equal(serializer.serialize(root), '<p>test</p>', 'Redundant whitespace (block element)');
+       deepEqual(countNodes(root), {body:1, p:1, '#text':1}, 'Redundant whitespace (block element) (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <SCRIPT>  \t\r\n   test  \t\r\n   </S' + 'CRIPT>   \t\r\n  ');
+       equal(serializer.serialize(root), '<script>  \t\r\n   test  \t\r\n   </s' + 'cript>', 'Whitespace around and inside SCRIPT');
+       deepEqual(countNodes(root), {body:1, script:1, '#text':1}, 'Whitespace around and inside SCRIPT (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <STYLE>  \t\r\n   test  \t\r\n   </STYLE>   \t\r\n  ');
+       equal(serializer.serialize(root), '<style>  \t\r\n   test  \t\r\n   </style>', 'Whitespace around and inside STYLE');
+       deepEqual(countNodes(root), {body:1, style:1, '#text':1}, 'Whitespace around and inside STYLE (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<ul>\n<li>Item 1\n<ul>\n<li>\n \t Indented \t \n</li>\n</ul>\n</li>\n</ul>\n');
+       equal(serializer.serialize(root), '<ul><li>Item 1<ul><li>Indented</li></ul></li></ul>', 'Whitespace around and inside blocks (ul/li)');
+       deepEqual(countNodes(root), {body:1, li:2, ul:2, '#text':2}, 'Whitespace around and inside blocks (ul/li) (count)');
+
+       parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({invalid_elements : 'hr,br'}));
+       root = parser.parse('\n<hr />\n<br />\n<div>\n<hr />\n<br />\n<img src="file.gif" data-mce-src="file.gif" />\n<hr />\n<br />\n</div>\n<hr />\n<br />\n');
+       equal(serializer.serialize(root), '<div><img src="file.gif" data-mce-src="file.gif" alt="" /></div>', 'Whitespace where SaxParser will produce multiple whitespace nodes');
+       deepEqual(countNodes(root), {body:1, div:1, img:1}, 'Whitespace where SaxParser will produce multiple whitespace nodes (count)');
+});
+
+test('Whitespace before/after invalid element with text in block', function() {
+       parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({invalid_elements : 'em'}));
+       root = parser.parse('<p>a <em>b</em> c</p>');
+       equal(serializer.serialize(root), '<p>a b c</p>');
+});
+
+test('Whitespace before/after invalid element whitespace element in block', function() {
+       parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({invalid_elements : 'span'}));
+       root = parser.parse('<p> <span></span> </p>');
+       equal(serializer.serialize(root), '<p>\u00a0</p>');
+});
+
+test('Whitespace preserved in PRE', function() {
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <PRE>  \t\r\n   test  \t\r\n   </PRE>   \t\r\n  ');
+       equal(serializer.serialize(root), '<pre>  \t\r\n   test  \t\r\n   </pre>', 'Whitespace around and inside PRE');
+       deepEqual(countNodes(root), {body:1, pre:1, '#text':1}, 'Whitespace around and inside PRE (count)');
+});
+
+test('Whitespace preserved in SPAN inside PRE', function() {
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('  \t\r\n  <PRE>  \t\r\n  <span>    test    </span> \t\r\n   </PRE>   \t\r\n  ');
+       equal(serializer.serialize(root), '<pre>  \t\r\n  <span>    test    </span> \t\r\n   </pre>', 'Whitespace around and inside PRE');
+       deepEqual(countNodes(root), {body:1, pre:1, span:1, '#text':3}, 'Whitespace around and inside PRE (count)');
+});
+
+test('Parse invalid contents', function() {
+       var parser, root;
+
+       expect(20);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a"><p class="b">123</p></p>');
+       equal(serializer.serialize(root), '<p class="b">123</p>', 'P in P, no nodes before/after');
+       deepEqual(countNodes(root), {body:1, p:1, '#text':1}, 'P in P, no nodes before/after (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a">a<p class="b">b</p><p class="c">c</p>d</p>');
+       equal(serializer.serialize(root), '<p class="a">a</p><p class="b">b</p><p class="c">c</p><p class="a">d</p>', 'Two P in P, no nodes before/after');
+       deepEqual(countNodes(root), {body: 1, p:4, '#text': 4}, 'Two P in P, no nodes before/after (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a">abc<p class="b">def</p></p>');
+       equal(serializer.serialize(root), '<p class="a">abc</p><p class="b">def</p>', 'P in P with nodes before');
+       deepEqual(countNodes(root), {body: 1, p:2, '#text': 2}, 'P in P with nodes before (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a"><p class="b">abc</p>def</p>');
+       equal(serializer.serialize(root), '<p class="b">abc</p><p class="a">def</p>', 'P in P with nodes after');
+       deepEqual(countNodes(root), {body: 1, p:2, '#text': 2}, 'P in P with nodes after (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a"><p class="b">abc</p><br></p>');
+       equal(serializer.serialize(root), '<p class="b">abc</p>', 'P in P with BR after');
+       deepEqual(countNodes(root), {body: 1, p:1, '#text': 1}, 'P in P with BR after (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a">a<strong>b<span>c<em>d<p class="b">e</p>f</em>g</span>h</strong>i</p>');
+       equal(serializer.serialize(root), '<p class="a">a<strong>b<span>c<em>d</em></span></strong></p><p class="b">e</p><p class="a"><strong><span><em>f</em>g</span>h</strong>i</p>', 'P in P wrapped in inline elements');
+       deepEqual(countNodes(root), {"body":1, "p":3, "#text":9, "strong":2, "span":2, "em": 2}, 'P in P wrapped in inline elements (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p class="a">a<p class="b">b<p class="c">c</p>d</p>e</p>');
+       equal(serializer.serialize(root), '<p class="a">a</p><p class="b">b</p><p class="c">c</p><p class="b">d</p><p class="a">e</p>', 'P in P in P with text before/after');
+       deepEqual(countNodes(root), {body: 1, p:5, '#text': 5}, 'P in P in P with text before/after (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p>a<ul><li>b</li><li>c</li></ul>d</p>');
+       equal(serializer.serialize(root), '<p>a</p><ul><li>b</li><li>c</li></ul><p>d</p>', 'UL inside P');
+       deepEqual(countNodes(root), {body: 1, p:2, ul:1, li:2, '#text': 4}, 'UL inside P (count)');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<table><tr><td><tr>a</tr></td></tr></table>');
+       equal(serializer.serialize(root), '<table><tr><td>a</td></tr></table>', 'TR inside TD');
+       deepEqual(countNodes(root), {body: 1, table:1, tr:1, td:1, '#text': 1}, 'TR inside TD (count)');
+
+       parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({valid_elements: 'p,section,div'}));
+       root = parser.parse('<div><section><p>a</p></section></div>');
+       equal(serializer.serialize(root), '<div><section><p>a</p></section></div>', 'P inside SECTION');
+       deepEqual(countNodes(root), {"body":1, "div":1, "section":1, "p":1, "#text":1}, 'P inside SECTION (count)');
+});
+
+test('addNodeFilter', function() {
+       var parser, result;
+
+       expect(7);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       parser.addNodeFilter('#comment', function(nodes, name, args) {
+               result = {nodes : nodes, name : name, args : args};
+       });
+       parser.parse('text<!--text1-->text<!--text2-->');
+
+       deepEqual(result.args, {}, 'Parser args');
+       equal(result.name, '#comment', 'Parser filter result name');
+       equal(result.nodes.length, 2, 'Parser filter result node');
+       equal(result.nodes[0].name, '#comment', 'Parser filter result node(0) name');
+       equal(result.nodes[0].value, 'text1', 'Parser filter result node(0) value');
+       equal(result.nodes[1].name, '#comment', 'Parser filter result node(1) name');
+       equal(result.nodes[1].value, 'text2', 'Parser filter result node(1) value');
+});
+
+test('addNodeFilter multiple names', function() {
+       var parser, results = {};
+
+       expect(14);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       parser.addNodeFilter('#comment,#text', function(nodes, name, args) {
+               results[name] = {nodes : nodes, name : name, args : args};
+       });
+       parser.parse('text1<!--text1-->text2<!--text2-->');
+
+       deepEqual(results['#comment'].args, {}, 'Parser args');
+       equal(results['#comment'].name, '#comment', 'Parser filter result name');
+       equal(results['#comment'].nodes.length, 2, 'Parser filter result node');
+       equal(results['#comment'].nodes[0].name, '#comment', 'Parser filter result node(0) name');
+       equal(results['#comment'].nodes[0].value, 'text1', 'Parser filter result node(0) value');
+       equal(results['#comment'].nodes[1].name, '#comment', 'Parser filter result node(1) name');
+       equal(results['#comment'].nodes[1].value, 'text2', 'Parser filter result node(1) value');
+       deepEqual(results['#text'].args, {}, 'Parser args');
+       equal(results['#text'].name, '#text', 'Parser filter result name');
+       equal(results['#text'].nodes.length, 2, 'Parser filter result node');
+       equal(results['#text'].nodes[0].name, '#text', 'Parser filter result node(0) name');
+       equal(results['#text'].nodes[0].value, 'text1', 'Parser filter result node(0) value');
+       equal(results['#text'].nodes[1].name, '#text', 'Parser filter result node(1) name');
+       equal(results['#text'].nodes[1].value, 'text2', 'Parser filter result node(1) value');
+});
+
+test('addNodeFilter with parser args', function() {
+       var parser, result;
+
+       expect(1);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       parser.addNodeFilter('#comment', function(nodes, name, args) {
+               result = {nodes : nodes, name : name, args : args};
+       });
+       parser.parse('text<!--text1-->text<!--text2-->', {value: 1});
+
+       deepEqual(result.args, {value: 1}, 'Parser args');
+});
+
+test('addAttributeFilter', function() {
+       var parser, result;
+
+       expect(7);
+
+       parser = new tinymce.html.DomParser({});
+       parser.addAttributeFilter('src', function(nodes, name, args) {
+               result = {nodes : nodes, name : name, args : args};
+       });
+       parser.parse('<b>a<img src="1.gif" />b<img src="1.gif" />c</b>');
+
+       deepEqual(result.args, {}, 'Parser args');
+       equal(result.name, 'src', 'Parser filter result name');
+       equal(result.nodes.length, 2, 'Parser filter result node');
+       equal(result.nodes[0].name, 'img', 'Parser filter result node(0) name');
+       equal(result.nodes[0].attr('src'), '1.gif', 'Parser filter result node(0) attr');
+       equal(result.nodes[1].name, 'img', 'Parser filter result node(1) name');
+       equal(result.nodes[1].attr('src'), '1.gif', 'Parser filter result node(1) attr');
+});
+
+test('addAttributeFilter multiple', function() {
+       var parser, results = {};
+
+       expect(14);
+
+       parser = new tinymce.html.DomParser({});
+       parser.addAttributeFilter('src,href', function(nodes, name, args) {
+               results[name] = {nodes : nodes, name : name, args : args};
+       });
+       parser.parse('<b><a href="1.gif">a</a><img src="1.gif" />b<img src="1.gif" /><a href="2.gif">c</a></b>');
+
+       deepEqual(results['src'].args, {}, 'Parser args');
+       equal(results['src'].name, 'src', 'Parser filter result name');
+       equal(results['src'].nodes.length, 2, 'Parser filter result node');
+       equal(results['src'].nodes[0].name, 'img', 'Parser filter result node(0) name');
+       equal(results['src'].nodes[0].attr('src'), '1.gif', 'Parser filter result node(0) attr');
+       equal(results['src'].nodes[1].name, 'img', 'Parser filter result node(1) name');
+       equal(results['src'].nodes[1].attr('src'), '1.gif', 'Parser filter result node(1) attr');
+       deepEqual(results['href'].args, {}, 'Parser args');
+       equal(results['href'].name, 'href', 'Parser filter result name');
+       equal(results['href'].nodes.length, 2, 'Parser filter result node');
+       equal(results['href'].nodes[0].name, 'a', 'Parser filter result node(0) name');
+       equal(results['href'].nodes[0].attr('href'), '1.gif', 'Parser filter result node(0) attr');
+       equal(results['href'].nodes[1].name, 'a', 'Parser filter result node(1) name');
+       equal(results['href'].nodes[1].attr('href'), '2.gif', 'Parser filter result node(1) attr');
+});
+
+test('Fix orphan LI elements', function() {
+       var parser, result;
+
+       expect(3);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<ul><li>a</li></ul><li>b</li>');
+       equal(serializer.serialize(root), '<ul><li>a</li><li>b</li></ul>', 'LI moved to previous sibling UL');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<li>a</li><ul><li>b</li></ul>');
+       equal(serializer.serialize(root), '<ul><li>a</li><li>b</li></ul>', 'LI moved to next sibling UL');
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<li>a</li>');
+       equal(serializer.serialize(root), '<ul><li>a</li></ul>', 'LI wrapped in new UL');
+});
+
+test('Remove empty elements', function() {
+       var parser, result, schema = new tinymce.html.Schema({valid_elements: 'span,-a,img'});
+
+       expect(3);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<span></span><a href="#"></a>');
+       equal(serializer.serialize(root), '<span></span>', 'Remove empty a element');
+
+/*     parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<span></span><a href="#"><!-'+'- x -'+'-></a>');
+       equal(serializer.serialize(root), '<span></span>', 'Remove empty a element containing comment');*/
+
+       parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({valid_elements: 'span,a[name],img'}));
+       root = parser.parse('<span></span><a name="anchor"></a>');
+       equal(serializer.serialize(root), '<span></span><a name="anchor"></a>', 'Leave a with name attribute');
+       
+       parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({valid_elements: 'span,a[href],img[src]'}));
+       root = parser.parse('<span></span><a href="#"><img src="about:blank" /></a>');
+       equal(serializer.serialize(root), '<span></span><a href="#"><img src="about:blank" /></a>', 'Leave elements with img in it');
+});
+
+test('Self closing list elements', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       expect(1);
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<ul><li>1<li><b>2</b><li><em><b>3</b></em></ul>');
+       equal(serializer.serialize(root), '<ul><li>1</li><li><strong>2</strong></li><li><em><strong>3</strong></em></li></ul>', 'Split out LI elements in LI elements.');
+});
+
+test('Remove redundant br elements', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       expect(1);
+
+       parser = new tinymce.html.DomParser({remove_trailing_brs : true}, schema);
+       root = parser.parse(
+               '<p>a<br></p>' +
+               '<p>a<br>b<br></p>' +
+               '<p>a<br><br></p><p>a<br><span data-mce-type="bookmark"></span><br></p>' +
+               '<p>a<span data-mce-type="bookmark"></span><br></p>'
+       );
+       equal(serializer.serialize(root), '<p>a</p><p>a<br />b</p><p>a<br /><br /></p><p>a<br /><br /></p><p>a</p>', 'Remove traling br elements.');
+});
+
+test('Replace br with nbsp when wrapped in two inline elements and one block', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({remove_trailing_brs : true}, schema);
+       root = parser.parse('<p><strong><em><br /></em></strong></p>');
+       equal(serializer.serialize(root), '<p><strong><em>\u00a0</em></strong></p>');
+});
+
+test('Replace br with nbsp when wrapped in an inline element and placed in the root', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({remove_trailing_brs : true}, schema);
+       root = parser.parse('<strong><br /></strong>');
+       equal(serializer.serialize(root), '<strong>\u00a0</strong>');
+});
+
+test('Don\'t replace br inside root element when there is multiple brs', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({remove_trailing_brs : true}, schema);
+       root = parser.parse('<strong><br /><br /></strong>');
+       equal(serializer.serialize(root), '<strong><br /><br /></strong>');
+});
+
+test('Don\'t replace br inside root element when there is siblings', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({remove_trailing_brs : true}, schema);
+       root = parser.parse('<strong><br /></strong><em>x</em>');
+       equal(serializer.serialize(root), '<strong><br /></strong><em>x</em>');
+});
+
+test('Remove br in invalid parent bug', function() {
+       var parser, root, schema = new tinymce.html.Schema({valid_elements: 'br'});
+
+       expect(1);
+
+       parser = new tinymce.html.DomParser({remove_trailing_brs : true}, schema);
+       root = parser.parse('<br>');
+       equal(serializer.serialize(root), '', 'Remove traling br elements.');
+});
+
+test('Forced root blocks', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       expect(1);
+
+       parser = new tinymce.html.DomParser({forced_root_block : 'p'}, schema);
+       root = parser.parse(
+               '<!-- a -->' +
+               'b' +
+               '<b>c</b>' +
+               '<p>d</p>' +
+               '<p>e</p>' +
+               'f' +
+               '<b>g</b>' +
+               'h'
+       );
+       equal(serializer.serialize(root), '<!-- a --><p>b<strong>c</strong></p><p>d</p><p>e</p><p>f<strong>g</strong>h</p>', 'Mixed text nodes, inline elements and blocks.');
+});
+
+test('Forced root blocks attrs', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       expect(1);
+
+       parser = new tinymce.html.DomParser({forced_root_block: 'p', forced_root_block_attrs: {"class": "class1"}}, schema);
+       root = parser.parse(
+               '<!-- a -->' +
+               'b' +
+               '<b>c</b>' +
+               '<p>d</p>' +
+               '<p>e</p>' +
+               'f' +
+               '<b>g</b>' +
+               'h'
+       );
+       equal(serializer.serialize(root), '<!-- a -->' +
+               '<p class="class1">b<strong>c</strong></p>' +
+               '<p>d</p>' +
+               '<p>e</p>' +
+               '<p class="class1">f<strong>g</strong>h</p>',
+       'Mixed text nodes, inline elements and blocks.');
+});
+
+test('Parse contents with html4 anchors and allow_html_in_named_anchor: false', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({allow_html_in_named_anchor : false}, schema);
+       root = parser.parse('<a name="x">a</a><a href="x">x</a>');
+       equal(serializer.serialize(root), '<a name="x"></a>a<a href="x">x</a>');
+});
+
+test('Parse contents with html5 anchors and allow_html_in_named_anchor: false', function() {
+       var parser, root, schema = new tinymce.html.Schema({schema: "html5"});
+
+       parser = new tinymce.html.DomParser({allow_html_in_named_anchor : false}, schema);
+       root = parser.parse('<a id="x">a</a><a href="x">x</a>');
+       equal(serializer.serialize(root), '<a id="x"></a>a<a href="x">x</a>');
+});
+
+test('Parse contents with html4 anchors and allow_html_in_named_anchor: true', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({allow_html_in_named_anchor : true}, schema);
+       root = parser.parse('<a name="x">a</a><a href="x">x</a>');
+       equal(serializer.serialize(root), '<a name="x">a</a><a href="x">x</a>');
+});
+
+test('Parse contents with html5 anchors and allow_html_in_named_anchor: true', function() {
+       var parser, root, schema = new tinymce.html.Schema({schema: "html5"});
+
+       parser = new tinymce.html.DomParser({allow_html_in_named_anchor : true}, schema);
+       root = parser.parse('<a id="x">a</a><a href="x">x</a>');
+       equal(serializer.serialize(root), '<a id="x">a</a><a href="x">x</a>');
+});
+
+test('Parse contents with html5 self closing datalist options', function() {
+       var parser, root, schema = new tinymce.html.Schema({schema: "html5"});
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<datalist><option label="a1" value="b1"><option label="a2" value="b2"><option label="a3" value="b3"></datalist>');
+       equal(serializer.serialize(root), '<datalist><option label="a1" value="b1"></option><option label="a2" value="b2"></option><option label="a3" value="b3"></option></datalist>');
+});
+
+test('Parse inline contents before block bug #5424', function() {
+       var parser, root, schema = new tinymce.html.Schema({schema: "html5"});
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<b>1</b> 2<p>3</p>');
+       equal(serializer.serialize(root), '<b>1</b> 2<p>3</p>');
+});
+
+test('Invalid text blocks within a li', function() {
+       var parser, root, schema = new tinymce.html.Schema({schema: "html5", valid_children: '-li[p]'});
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<ul><li>1<p>2</p></li><li>a<p>b</p><p>c</p></li></ul>');
+       equal(serializer.serialize(root), '<ul><li>12</li><li>ab</li><li>c</li></ul>');
+});
+
+test('Invalid inline element with space before', function() {
+       var parser, root, schema = new tinymce.html.Schema();
+
+       parser = new tinymce.html.DomParser({}, schema);
+       root = parser.parse('<p><span>1</span> <strong>2</strong></p>');
+       equal(serializer.serialize(root), '<p>1 <strong>2</strong></p>');
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.DomParser tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/DomParser.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlEntitieshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/Entities.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/Entities.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/Entities.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,98 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.Entities tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.Entities");
+
+QUnit.config.reorder = false;
+
+test('encodeRaw', function() {
+       expect(2);
+
+       equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;\u00e5\u00e4\u00f6', 'Raw encoding text');
+       equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;\u00e5\u00e4\u00f6', 'Raw encoding attribute');
+});
+
+test('encodeAllRaw', function() {
+       expect(1);
+
+       equal(tinymce.html.Entities.encodeAllRaw('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;&quot;&#39;&amp;\u00e5\u00e4\u00f6', 'Raw encoding all');
+});
+
+test('encodeNumeric', function() {
+       expect(2);
+
+       equal(tinymce.html.Entities.encodeNumeric('<>"\'&\u00e5\u00e4\u00f6\u03b8\u2170\ufa11'), '&lt;&gt;"\'&amp;&#229;&#228;&#246;&#952;&#8560;&#64017;', 'Numeric encoding text');
+       equal(tinymce.html.Entities.encodeNumeric('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;&#229;&#228;&#246;', 'Numeric encoding attribute');
+});
+
+test('encodeNamed', function() {
+       expect(4);
+
+       equal(tinymce.html.Entities.encodeNamed('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;&aring;&auml;&ouml;', 'Named encoding text');
+       equal(tinymce.html.Entities.encodeNamed('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;&aring;&auml;&ouml;', 'Named encoding attribute');
+       equal(tinymce.html.Entities.encodeNamed('<>"\'\u00e5\u00e4\u00f6', false, {'\u00e5' : '&aring;'}), '&lt;&gt;"\'&aring;\u00e4\u00f6', 'Named encoding text');
+       equal(tinymce.html.Entities.encodeNamed('<>"\'\u00e5\u00e4\u00f6', true, {'\u00e5' : '&aring;'}), '&lt;&gt;&quot;\'&aring;\u00e4\u00f6', 'Named encoding attribute');
+});
+
+test('getEncodeFunc', function() {
+       var encodeFunc;
+
+       expect(10);
+
+       encodeFunc = tinymce.html.Entities.getEncodeFunc('raw');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;\u00e5\u00e4\u00f6', 'Raw encoding text');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;\u00e5\u00e4\u00f6', 'Raw encoding attribute');
+
+       encodeFunc = tinymce.html.Entities.getEncodeFunc('named');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;&aring;&auml;&ouml;', 'Named encoding text');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;&aring;&auml;&ouml;', 'Named encoding attribute');
+
+       encodeFunc = tinymce.html.Entities.getEncodeFunc('numeric');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;&#229;&#228;&#246;', 'Named encoding text');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;&#229;&#228;&#246;', 'Named encoding attribute');
+
+       encodeFunc = tinymce.html.Entities.getEncodeFunc('named+numeric', '229,aring');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;&aring;&#228;&#246;', 'Named+numeric encoding text');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;&aring;&#228;&#246;', 'Named+numeric encoding attribute');
+
+       encodeFunc = tinymce.html.Entities.getEncodeFunc('named,numeric', '229,aring');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '&lt;&gt;"\'&amp;&aring;&#228;&#246;', 'Named+numeric encoding text');
+       equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '&lt;&gt;&quot;\'&amp;&aring;&#228;&#246;', 'Named+numeric encoding attribute');
+});
+
+test('decode', function() {
+       expect(3);
+
+       equal(tinymce.html.Entities.decode('&lt;&gt;&quot;&#39;&amp;&aring;&auml;&ouml;&unknown;&#039;&#x27;'), '<>"\'&\u00e5\u00e4\u00f6&unknown;\'\'', 'Decode text with various entities');
+
+       equal(tinymce.html.Entities.encodeNumeric(tinymce.html.Entities.decode(
+               '&#130;&#131;&#132;&#133;&#134;&#135;&#136;&#137;&#138;' +
+               '&#139;&#140;&#141;&#142;&#143;&#144;&#145;&#146;&#147;&#148;&#149;&#150;&#151;&#152;' +
+               '&#153;&#154;&#155;&#156;&#157;&#158;&#159;')
+       ), '&#8218;&#402;&#8222;&#8230;&#8224;&#8225;&#710;&#8240;&#352;&#8249;&#338;&#141;&#381;' +
+               '&#143;&#144;&#8216;&#8217;&#8220;&#8221;&#8226;&#8211;&#8212;&#732;&#8482;&#353;' +
+               '&#8250;&#339;&#157;&#382;&#376;',
+       'Entity decode ascii');
+
+       equal(tinymce.html.Entities.encodeNumeric(tinymce.html.Entities.decode('&#194564;')), '&#194564;', "High byte non western character.");
+});
+
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Entities tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/Entities.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlNodehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/Node.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/Node.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/Node.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,466 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.Node tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.Node");
+
+QUnit.config.reorder = false;
+
+test('construction', function() {
+       var node;
+
+       expect(15);
+
+       node = new tinymce.html.Node('#text', 3);
+       equal(node.name, '#text');
+       equal(node.type, 3);
+
+       node = new tinymce.html.Node('#comment', 8);
+       equal(node.name, '#comment');
+       equal(node.type, 8);
+
+       node = new tinymce.html.Node('b', 1);
+       equal(node.name, 'b');
+       equal(node.type, 1);
+       deepEqual(node.attributes, []);
+
+       node = new tinymce.html.Node('#pi', 7);
+       equal(node.name, '#pi');
+       equal(node.type, 7);
+
+       node = new tinymce.html.Node('#doctype', 10);
+       equal(node.name, '#doctype');
+       equal(node.type, 10);
+
+       node = new tinymce.html.Node('#cdata', 4);
+       equal(node.name, '#cdata');
+       equal(node.type, 4);
+
+       node = new tinymce.html.Node('#frag', 11);
+       equal(node.name, '#frag');
+       equal(node.type, 11);
+});
+
+test('append inside empty node', function() {
+       var root, node, node2;
+
+       expect(10);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node = root.append(new tinymce.html.Node('b', 1));
+       ok(root.firstChild.parent === root);
+       equal(root.firstChild.next, undefined);
+       equal(root.firstChild.prev, undefined);
+       equal(root.firstChild.firstChild, undefined);
+       equal(root.firstChild.lastChild, undefined);
+       ok(node.parent === root);
+       equal(node.next, undefined);
+       equal(node.prev, undefined);
+       equal(node.firstChild, undefined);
+       equal(node.lastChild, undefined);
+});
+
+test('append node after node', function() {
+       var root, node, node2;
+
+       expect(17);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node2 = root.append(new tinymce.html.Node('a', 1));
+       node = root.append(new tinymce.html.Node('b', 1));
+       ok(root.firstChild.parent === root, 'root.firstChild.parent === root');
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node, 'root.firstChild');
+       ok(root.firstChild.next === node, 'root.firstChild.next');
+       equal(root.firstChild.prev, undefined, 'root.firstChild.prev');
+       equal(root.firstChild.firstChild, undefined, 'root.firstChild.firstChild');
+       equal(root.firstChild.lastChild, undefined, 'root.firstChild.lastChild');
+       ok(node2.parent === root, 'node2.parent === root');
+       ok(node2.next === node, 'node2.next');
+       equal(node2.prev, undefined, 'node2.prev');
+       equal(node2.firstChild, undefined, 'node2.firstChild');
+       equal(node2.lastChild, undefined, 'node2.lastChild');
+       ok(node.parent === root, 'node.parent === root');
+       equal(node.next, undefined, 'node.next');
+       ok(node.prev === node2, 'node.prev');
+       equal(node.firstChild, undefined, 'node.firstChild');
+       equal(node.lastChild, undefined, 'node.lastChild');
+});
+
+test('append existing node before other existing node', function() {
+       var root, node, node2;
+
+       expect(8);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node = root.append(new tinymce.html.Node('a', 1));
+       node2 = root.append(new tinymce.html.Node('b', 1));
+       root.append(node);
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node, 'root.lastChild');
+       equal(node.next, undefined, 'node.next');
+       ok(node.prev === node2, 'node.prev');
+       ok(node.parent === root, 'node.parent');
+       ok(node2.parent === root, 'node2.parent');
+       equal(node2.prev, undefined, 'node2.prev');
+       ok(node2.next === node, 'node2.next');
+});
+
+test('remove unattached node', function() {
+       expect(1);
+
+       ok(!new tinymce.html.Node('#text', 3).remove().parent);
+});
+
+test('remove single child', function() {
+       var root, node, node2, node3;
+
+       expect(6);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node = root.append(new tinymce.html.Node('p', 1));
+       node = root.firstChild.remove();
+       equal(root.firstChild, undefined);
+       equal(root.lastChild, undefined);
+       equal(node.parent, undefined);
+       equal(node.next, undefined);
+       equal(node.prev, undefined);
+       equal(node.name, 'p');
+});
+
+test('remove middle node', function() {
+       var root, node, node2, node3;
+
+       expect(9);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node = root.append(new tinymce.html.Node('a', 1));
+       node2 = root.append(new tinymce.html.Node('b', 1));
+       node3 = root.append(new tinymce.html.Node('c', 1));
+       node2.remove();
+       equal(node2.parent, undefined);
+       equal(node2.next, undefined);
+       equal(node2.prev, undefined);
+       ok(root.firstChild === node, 'root.firstChild');
+       ok(root.lastChild === node3, 'root.lastChild');
+       ok(node.next === node3, 'node.next');
+       equal(node.prev, undefined, 'node.prev');
+       ok(node3.prev, node, 'node3.prev');
+       equal(node3.next, undefined, 'node3.next');
+});
+
+test('insert after last', function() {
+       var fragment, root, node, node2;
+
+       expect(5);
+
+       fragment = new tinymce.html.Node('#frag', 11);
+       root = fragment.append(new tinymce.html.Node('body', 1));
+       node = root.append(new tinymce.html.Node('a', 1));
+       node2 = root.insert(new tinymce.html.Node('x', 1), node);
+       ok(root.firstChild === node, 'root.firstChild');
+       ok(root.lastChild === node2, 'root.lastChild');
+       ok(node.next === node2, 'node.next');
+       ok(node2.prev === node, 'node2.prev');
+       ok(node2.parent === root, 'node3.next');
+});
+
+test('insert before first', function() {
+       var fragment, root, node, node2;
+
+       expect(8);
+
+       fragment = new tinymce.html.Node('#frag', 11);
+       root = fragment.append(new tinymce.html.Node('body', 1));
+       node = root.append(new tinymce.html.Node('a', 1));
+       node2 = root.insert(new tinymce.html.Node('x', 1), node, true);
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node, 'root.lastChild');
+       ok(node2.parent === root, 'node2.lastChild');
+       ok(node2.next === node, 'node2.next');
+       ok(node2.prev === undefined, 'node2.prev');
+       ok(node.parent === root, 'node.lastChild');
+       ok(node.next === undefined, 'node.next');
+       ok(node.prev === node2, 'node.prev');
+});
+
+test('insert before second', function() {
+       var fragment, root, node, node2;
+
+       expect(5);
+
+       fragment = new tinymce.html.Node('#frag', 11);
+       root = fragment.append(new tinymce.html.Node('body', 1));
+       node = root.append(new tinymce.html.Node('a', 1));
+       node2 = root.append(new tinymce.html.Node('b', 1));
+       node3 = root.insert(new tinymce.html.Node('x', 1), node2, true);
+       ok(root.firstChild === node, 'root.firstChild');
+       ok(root.lastChild === node2, 'root.lastChild');
+       ok(node3.parent === root, 'node3.parent');
+       ok(node3.next === node2, 'node3.next');
+       ok(node3.prev === node, 'node3.prev');
+});
+
+test('insert after and between two nodes', function() {
+       var root, node, node2, node3;
+
+       expect(7);
+
+       fragment = new tinymce.html.Node('#frag', 11);
+       root = fragment.append(new tinymce.html.Node('body', 1));
+       node = root.append(new tinymce.html.Node('a', 1));
+       node2 = root.append(new tinymce.html.Node('b', 1));
+       node3 = root.insert(new tinymce.html.Node('x', 1), node);
+       ok(root.firstChild === node, 'root.firstChild');
+       ok(root.lastChild === node2, 'root.lastChild');
+       ok(node.next === node3, 'node.next');
+       ok(node2.prev === node3, 'node2.prev');
+       ok(node3.parent === root, 'node3.next');
+       ok(node3.next === node2, 'node3.next');
+       ok(node3.prev === node, 'node3.prev');
+});
+
+test('replace single child', function() {
+       var root, node1, node2;
+
+       expect(5);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node2 = root.append(new tinymce.html.Node('em', 1));
+       node1.replace(node2);
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node2, 'root.lastChild');
+       ok(node2.parent === root, 'node2.parent');
+       ok(!node2.next, 'node2.next');
+       ok(!node2.prev, 'node2.prev');
+});
+
+test('replace first child', function() {
+       var root, node1, node2, node3;
+
+       expect(5);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node2 = root.append(new tinymce.html.Node('em', 1));
+       node3 = root.append(new tinymce.html.Node('b', 1));
+       node1.replace(node2);
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node3, 'root.lastChild');
+       ok(node2.parent === root, 'node2.parent');
+       ok(node2.next === node3, 'node2.next');
+       ok(!node2.prev, 'node2.prev');
+});
+
+test('replace last child', function() {
+       var root, node1, node2, node3;
+
+       expect(5);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node3 = root.append(new tinymce.html.Node('b', 1));
+       node2 = root.append(new tinymce.html.Node('em', 1));
+       node3.replace(node2);
+       ok(root.firstChild === node1, 'root.firstChild');
+       ok(root.lastChild === node2, 'root.lastChild');
+       ok(node2.parent === root, 'node2.parent');
+       ok(!node2.next, 'node2.next');
+       ok(node2.prev === node1, 'node2.prev');
+});
+
+test('replace middle child', function() {
+       var root, node1, node2, node3, node4;
+
+       expect(5);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node2 = root.append(new tinymce.html.Node('b', 1));
+       node3 = root.append(new tinymce.html.Node('b', 1));
+       node4 = root.append(new tinymce.html.Node('em', 1));
+       node2.replace(node4);
+       ok(root.firstChild === node1, 'root.firstChild');
+       ok(root.lastChild === node3, 'root.lastChild');
+       ok(node4.parent === root, 'node4.parent');
+       ok(node4.next === node3, 'node4.next');
+       ok(node4.prev === node1, 'node4.prev');
+});
+
+test('attr', 22, function() {
+       var node;
+
+       node = new tinymce.html.Node('b', 1);
+       deepEqual(node.attributes, []);
+       node.attr('attr1', 'value1');
+       equal(node.attr('attr1'), 'value1');
+       equal(node.attr('attr2'), undefined);
+       deepEqual(node.attributes, [{name: 'attr1', value: 'value1'}]);
+       deepEqual(node.attributes.map, {'attr1': 'value1'});
+
+       node = new tinymce.html.Node('b', 1);
+       deepEqual(node.attributes, []);
+       node.attr('attr1', 'value1');
+       node.attr('attr1', 'valueX');
+       equal(node.attr('attr1'), 'valueX');
+       deepEqual(node.attributes, [{name: 'attr1', value: 'valueX'}]);
+       deepEqual(node.attributes.map, {'attr1': 'valueX'});
+
+       node = new tinymce.html.Node('b', 1);
+       deepEqual(node.attributes, []);
+       node.attr('attr1', 'value1');
+       node.attr('attr2', 'value2');
+       equal(node.attr('attr1'), 'value1');
+       equal(node.attr('attr2'), 'value2');
+       deepEqual(node.attributes, [{name: 'attr1', value: 'value1'}, {name: 'attr2', value: 'value2'}]);
+       deepEqual(node.attributes.map, {'attr1': 'value1', 'attr2': 'value2'});
+
+       node = new tinymce.html.Node('b', 1);
+       deepEqual(node.attributes, []);
+       node.attr('attr1', 'value1');
+       node.attr('attr1', null);
+       equal(node.attr('attr1'), undefined);
+       deepEqual(node.attributes, []);
+       deepEqual(node.attributes.map, {});
+
+       node = new tinymce.html.Node('b', 1);
+       node.attr({a:'1', b:'2'});
+       deepEqual(node.attributes, [{name: 'a', value: '1'}, {name: 'b', value: '2'}]);
+       deepEqual(node.attributes.map, {a:'1', b:'2'});
+
+       node = new tinymce.html.Node('b', 1);
+       node.attr(null);
+       deepEqual(node.attributes, []);
+       deepEqual(node.attributes.map, {});
+});
+
+test('clone', function() {
+       var root, node, clone;
+
+       expect(16);
+
+       node = new tinymce.html.Node('#text', 3);
+       node.value = 'value';
+       clone = node.clone();
+       equal(clone.name, '#text');
+       equal(clone.type, 3);
+       equal(clone.value, 'value');
+       equal(clone.parent, undefined);
+       equal(clone.next, undefined);
+       equal(clone.prev, undefined);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node = new tinymce.html.Node('#text', 3);
+       node.value = 'value';
+       root.append(node);
+       equal(clone.name, '#text');
+       equal(clone.type, 3);
+       equal(clone.value, 'value');
+       equal(clone.parent, undefined);
+       equal(clone.next, undefined);
+       equal(clone.prev, undefined);
+
+       node = new tinymce.html.Node('b', 1);
+       node.attr('id', 'id');
+       node.attr('class', 'class');
+       node.attr('title', 'title');
+       clone = node.clone();
+       equal(clone.name, 'b');
+       equal(clone.type, 1);
+       deepEqual(clone.attributes, [{name: 'class', value: 'class'}, {name: 'title', value: 'title'}]);
+       deepEqual(clone.attributes.map, {'class': 'class', 'title': 'title'});
+});
+
+test('unwrap', function() {
+       var root, node1, node2, node3;
+
+       expect(7);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node2 = node1.append(new tinymce.html.Node('em', 1));
+       node1.unwrap();
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node2, 'root.lastChild');
+       ok(node2.parent === root, 'node2.parent');
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node2 = node1.append(new tinymce.html.Node('em', 1));
+       node3 = node1.append(new tinymce.html.Node('span', 1));
+       node1.unwrap();
+       ok(root.firstChild === node2, 'root.firstChild');
+       ok(root.lastChild === node3, 'root.lastChild');
+       ok(node2.parent === root, 'node2.parent');
+       ok(node3.parent === root, 'node3.parent');
+});
+
+test('empty', function() {
+       var root, node1, node2;
+
+       expect(4);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('b', 1));
+       node2 = node1.append(new tinymce.html.Node('em', 1));
+       node1.empty();
+       ok(root.firstChild === node1, 'root.firstChild');
+       ok(root.lastChild === node1, 'root.firstChild');
+       ok(!node1.firstChild, 'node1.firstChild');
+       ok(!node1.lastChild, 'node1.firstChild');
+});
+
+test('isEmpty', function() {
+       var root, node1, node2;
+
+       expect(9);
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('p', 1));
+       node2 = node1.append(new tinymce.html.Node('b', 1));
+       ok(root.isEmpty({img: 1}), 'Is empty 1');
+       ok(node1.isEmpty({img: 1}), 'Is empty 2');
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('p', 1));
+       node2 = node1.append(new tinymce.html.Node('img', 1));
+       ok(!root.isEmpty({img: 1}), 'Is not empty 1');
+       ok(!node1.isEmpty({img: 1}), 'Is not empty 2');
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('p', 1));
+       node2 = node1.append(new tinymce.html.Node('#text', 3));
+       node2.value = 'X';
+       ok(!root.isEmpty({img: 1}), 'Is not empty 3');
+       ok(!node1.isEmpty({img: 1}), 'Is not empty 4');
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('p', 1));
+       node2 = node1.append(new tinymce.html.Node('#text', 3));
+       node2.value = '';
+       ok(root.isEmpty({img: 1}), 'Is empty 4');
+       ok(node1.isEmpty({img: 1}), 'Is empty 5');
+
+       root = new tinymce.html.Node('#frag', 11);
+       node1 = root.append(new tinymce.html.Node('a', 1)).attr('name', 'x');
+       ok(!root.isEmpty({img: 1}), 'Contains anchor with name attribute.');
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Node tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/Node.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlSaxParserhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/SaxParser.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/SaxParser.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/SaxParser.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,616 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.SaxParser tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.SaxParser");
+
+QUnit.config.reorder = false;
+
+var writer = new tinymce.html.Writer(), schema = new tinymce.html.Schema();
+
+function createCounter(writer) {
+       var counts = {};
+
+       return {
+               counts : counts,
+
+               comment: function(text) {
+                       if ("comment" in counts)
+                               counts.comment++;
+                       else
+                               counts.comment = 1;
+
+                       writer.comment(text);
+               },
+
+               cdata: function(text) {
+                       if ("cdata" in counts)
+                               counts.cdata++;
+                       else
+                               counts.cdata = 1;
+
+                       writer.cdata(text);
+               },
+
+               text: function(text, raw) {
+                       if ("text" in counts)
+                               counts.text++;
+                       else
+                               counts.text = 1;
+
+                       writer.text(text, raw);
+               },
+
+               start: function(name, attrs, empty) {
+                       if ("start" in counts)
+                               counts.start++;
+                       else
+                               counts.start = 1;
+
+                       writer.start(name, attrs, empty);
+               },
+
+               end: function(name) {
+                       if ("end" in counts)
+                               counts.end++;
+                       else
+                               counts.end = 1;
+
+                       writer.end(name);
+               },
+
+               pi: function(name, text) {
+                       if ("pi" in counts)
+                               counts.pi++;
+                       else
+                               counts.pi = 1;
+
+                       writer.pi(name, text);
+               },
+
+               doctype: function(text) {
+                       if ("doctype:" in counts)
+                               counts.doctype++;
+                       else
+                               counts.doctype = 1;
+
+                       writer.doctype(text);
+               }
+       };
+}
+
+test('Parse elements', function() {
+       expect(46);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span id=id1 title="title value" class=\'class1 class2\' data-value="value1" MYATTR="val1" myns:myattr="val2" disabled empty=""></span>');
+       equal(writer.getContent(), '<span id="id1" title="title value" class="class1 class2" data-value="value1" myattr="val1" myns:myattr="val2" disabled="disabled" empty=""></span>', 'Parse attribute formats.');
+       deepEqual(counter.counts, {start:1, end:1}, 'Parse attribute formats counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<b href=\'"&amp;<>\'></b>');
+       equal(writer.getContent(), '<b href="&quot;&amp;&lt;&gt;"></b>', 'Parse attributes with <> in them.');
+       deepEqual(counter.counts, {start:1, end:1}, 'Parse attributes with <> in them (count).');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span title=" "class=" "></span>');
+       equal(writer.getContent(), '<span title=" " class=" "></span>', 'Parse compressed attributes.');
+       deepEqual(counter.counts, {start:1, end:1}, 'Parse compressed attributes (count).');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span title></span>');
+       equal(writer.getContent(), '<span title=""></span>', 'Single empty attribute.');
+       deepEqual(counter.counts, {start:1, end:1}, 'Single empty attributes (count).');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span class="class" title></span>');
+       equal(writer.getContent(), '<span class="class" title=""></span>', 'Empty attribute at end.');
+       deepEqual(counter.counts, {start:1, end:1}, 'Empty attribute at end (count).');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span title class="class"></span>');
+       equal(writer.getContent(), '<span title="" class="class"></span>', 'Empty attribute at start.');
+       deepEqual(counter.counts, {start:1, end:1}, 'Empty attribute at start (count).');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<img src="test">');
+       equal(writer.getContent(), '<img src="test" />', 'Parse empty element.');
+       deepEqual(counter.counts, {start:1}, 'Parse empty element counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<img\nsrc="test"\ntitle="row1\nrow2">');
+       equal(writer.getContent(), '<img src="test" title="row1\nrow2" />', 'Parse attributes with linebreak.');
+       deepEqual(counter.counts, {start: 1}, 'Parse attributes with linebreak counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<img     \t  \t   src="test"     \t  \t   title="\t    row1\t     row2">');
+       equal(writer.getContent(), '<img src="test" title="\t    row1\t     row2" />', 'Parse attributes with whitespace.');
+       deepEqual(counter.counts, {start: 1}, 'Parse attributes with whitespace counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<myns:mytag>text</myns:mytag>');
+       equal(writer.getContent(), '<myns:mytag>text</myns:mytag>', 'Parse element with namespace.');
+       deepEqual(counter.counts, {start:1, text:1, end: 1}, 'Parse element with namespace counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<myns-mytag>text</myns-mytag>');
+       equal(writer.getContent(), '<myns-mytag>text</myns-mytag>', 'Parse element with dash name.');
+       deepEqual(counter.counts, {start:1, text:1, end:1}, 'Parse element with dash name counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<p>text2<b>text3</p>text4</b>text5');
+       equal(writer.getContent(), 'text1<p>text2<b>text3</b></p>text4text5', 'Parse tag soup 1.');
+       deepEqual(counter.counts, {text:5, start: 2, end: 2}, 'Parse tag soup 1 counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<P>text2<B>text3</p>text4</b>text5');
+       equal(writer.getContent(), 'text1<p>text2<b>text3</b></p>text4text5', 'Parse tag soup 2.');
+       deepEqual(counter.counts, {text: 5, start: 2, end: 2}, 'Parse tag soup 2 counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<P>text2<B>tex<t3</p>te>xt4</b>text5');
+       equal(writer.getContent(), 'text1<p>text2<b>tex&lt;t3</b></p>te&gt;xt4text5', 'Parse tag soup 3.');
+       deepEqual(counter.counts, {text: 5, start: 2, end: 2}, 'Parse tag soup 3 counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<p>text2<b>text3');
+       equal(writer.getContent(), 'text1<p>text2<b>text3</b></p>', 'Parse tag soup 4.');
+       deepEqual(counter.counts, {text: 3, start: 2, end: 2}, 'Parse tag soup 4 counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<script>text2');
+       equal(writer.getContent(), 'text1<script>text2</s' + 'cript>', 'Parse tag soup 5.');
+       deepEqual(counter.counts, {text: 2, start: 1, end: 1}, 'Parse tag soup 5 counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<style>text2');
+       equal(writer.getContent(), 'text1<style>text2</st' + 'yle>', 'Parse tag soup 6.');
+       deepEqual(counter.counts, {text: 2, start: 1, end: 1}, 'Parse tag soup 6 counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<span title="<test" data-test="test>"></span>');
+       equal(writer.getContent(), 'text1<span title="&lt;test" data-test="test&gt;"></span>', 'Parse element with </> in attributes.');
+       deepEqual(counter.counts, {text: 1, start: 1, end: 1}, 'Parse element with </> in attributes counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse("text\n<SC"+"RIPT type=mce-text/javascript>// <![CDATA[\nalert('HELLO WORLD!');\n// ]]></SC"+"RIPT>");
+       equal(writer.getContent(), "text\n<sc"+"ript type=\"mce-text/javascript\">// <![CDATA[\nalert('HELLO WORLD!');\n// ]]></sc"+"ript>", 'Parse cdata script.');
+       deepEqual(counter.counts, {text: 2, start: 1, end: 1}, 'Parse cdata script counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<noscript>te<br>xt2</noscript>text3');
+       equal(writer.getContent(), 'text1<noscript>te<br>xt2</noscript>text3', 'Parse noscript elements.');
+       deepEqual(counter.counts, {text: 3, start: 1, end: 1}, 'Parse noscript elements counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<p>a</p><p /><p>b</p>');
+       equal(writer.getContent(), '<p>a</p><p></p><p>b</p>', 'Parse invalid closed element.');
+       deepEqual(counter.counts, {text: 2, start: 3, end: 3}, 'Parse invalid closed element counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<br><br /><br/>');
+       equal(writer.getContent(), '<br /><br /><br />', 'Parse short ended elements.');
+       deepEqual(counter.counts, {start: 3}, 'Parse short ended elements counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<p ></p>');
+       equal(writer.getContent(), '<p></p>', 'Parse start elements with whitespace only attribs part.');
+       deepEqual(counter.counts, {start: 1, end: 1}, 'Parse start elements with whitespace only attribs part (counts).');
+});
+
+test('Parse style elements', function() {
+       expect(8);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<em><style>// <b>tag</b></st' + 'yle>text2</em>');
+       equal(writer.getContent(), 'text1<em><style>// <b>tag</b></st' + 'yle>text2</em>', 'Parse style element.');
+       deepEqual(counter.counts, {start: 2, end: 2, text: 3}, 'Parse style element counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<em><style id="id">// <b>tag</b></st' + 'yle>text2</em>');
+       equal(writer.getContent(), 'text1<em><style id="id">// <b>tag</b></st' + 'yle>text2</em>', 'Parse style element with attributes.');
+       deepEqual(counter.counts, {text:3, start:2, end:2}, 'Parse style element with attributes counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<em><style></st' + 'yle>text2</span>');
+       equal(writer.getContent(), 'text1<em><style></st' + 'yle>text2</em>', 'Parse empty style element.');
+       deepEqual(counter.counts, {text:2, start:2, end:2}, 'Parse empty style element counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(tinymce.extend({validate : true}, counter), new tinymce.html.Schema({invalid_elements: 'style'}));
+       writer.reset();
+       parser.parse('text1<em><style>text2</st' + 'yle>text3</em>');
+       equal(writer.getContent(), 'text1<em>text3</em>', 'Parse invalid style element.');
+       deepEqual(counter.counts, {text:2, start:1, end:1}, 'Parse invalid style element (count).');
+});
+
+test('Parse script elements', function() {
+       expect(8);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<em><script>// <b>tag</b></s' + 'cript>text2</em>');
+       equal(writer.getContent(), 'text1<em><script>// <b>tag</b></s' + 'cript>text2</em>', 'Parse script element.');
+       deepEqual(counter.counts, {start:2, end:2, text:3}, 'Parse script element counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<em><script id="id">// <b>tag</b></s' + 'cript>text2</em>');
+       equal(writer.getContent(), 'text1<em><script id="id">// <b>tag</b></s' + 'cript>text2</em>', 'Parse script element with attributes.');
+       deepEqual(counter.counts, {start:2, end:2, text:3}, 'Parse script element with attributes counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<em><script></s' + 'cript>text2</em>');
+       equal(writer.getContent(), 'text1<em><script></s' + 'cript>text2</em>', 'Parse empty script element.');
+       deepEqual(counter.counts, {text: 2, start:2, end: 2}, 'Parse empty script element counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(tinymce.extend({validate : true}, counter), new tinymce.html.Schema({invalid_elements: 'script'}));
+       writer.reset();
+       parser.parse('text1<em><s' + 'cript>text2</s' + 'cript>text3</em>');
+       equal(writer.getContent(), 'text1<em>text3</em>', 'Parse invalid script element.');
+       deepEqual(counter.counts, {text:2, start:1, end:1}, 'Parse invalid script element (count).');
+});
+
+test('Parse text', function() {
+       expect(10);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('');
+       equal(writer.getContent(), '', 'Parse empty.');
+       deepEqual(counter.counts, {}, 'Parse empty counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text');
+       equal(writer.getContent(), 'text', 'Parse single text node.');
+       deepEqual(counter.counts, {text: 1}, 'Parse single text node counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<b>text</b>');
+       equal(writer.getContent(), '<b>text</b>', 'Parse wrapped text.');
+       deepEqual(counter.counts, {start:1, text:1, end:1}, 'Parse wrapped text counts');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('text1<b>text2</b>');
+       equal(writer.getContent(), 'text1<b>text2</b>', 'Parse text at start.');
+       deepEqual(counter.counts, {start:1, text:2, end:1}, 'Parse text at start counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<b>text1</b>text2');
+       equal(writer.getContent(), '<b>text1</b>text2', 'Parse text at end.');
+       deepEqual(counter.counts, {start:1, end:1, text:2}, 'Parse text at end counts.');
+});
+
+test('Parsing comments', function() {
+       expect(8);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<!-- comment value -->');
+       equal(writer.getContent(), '<!-- comment value -->', 'Parse comment with value.');
+       deepEqual(counter.counts, {comment:1}, 'Parse comment with value count.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<!---->');
+       equal(writer.getContent(), '', 'Parse comment without value.');
+       deepEqual(counter.counts, {}, 'Parse comment without value count.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<!--<b></b>-->');
+       equal(writer.getContent(), '<!--<b></b>-->', 'Parse comment with tag inside.');
+       deepEqual(counter.counts, {comment:1}, 'Parse comment with tag inside counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<b>a<!-- value -->b</b>');
+       equal(writer.getContent(), '<b>a<!-- value -->b</b>', 'Parse comment with tags around it.');
+       deepEqual(counter.counts, {comment:1, text:2, start:1, end:1}, 'Parse comment with tags around it counts.');
+});
+
+test('Parsing cdata', function() {
+       expect(8);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<![CDATA[test text]]>');
+       equal(writer.getContent(), '<![CDATA[test text]]>', 'Parse cdata with value.');
+       deepEqual(counter.counts, {cdata:1}, 'Parse cdata with value counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<![CDATA[]]>');
+       equal(writer.getContent(), '', 'Parse cdata without value.');
+       deepEqual(counter.counts, {}, 'Parse cdata without value counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<![CDATA[<b>a</b>]]>');
+       equal(writer.getContent(), '<![CDATA[<b>a</b>]]>', 'Parse cdata with tag inside.');
+       deepEqual(counter.counts, {cdata:1}, 'Parse cdata with tag inside counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<b>a<![CDATA[value]]>b</b>');
+       equal(writer.getContent(), '<b>a<![CDATA[value]]>b</b>', 'Parse cdata with tags around it.');
+       deepEqual(counter.counts, {cdata:1, start:1, end:1, text:2}, 'Parse cdata with tags around it counts.');
+});
+
+test('Parse PI', function() {
+       expect(6);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<?xml version="1.0" encoding="UTF-8" ?>text1');
+       equal(writer.getContent(), '<?xml version="1.0" encoding="UTF-8" ?>text1', 'Parse PI with attributes.');
+       deepEqual(counter.counts, {pi:1, text:1}, 'Parse PI with attributes counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<?xml?>text1');
+       equal(writer.getContent(), '<?xml?>text1', 'Parse PI with no data.');
+       deepEqual(counter.counts, {pi:1, text:1}, 'Parse PI with data counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<?xml somevalue/>text1');
+       equal(writer.getContent(), '<?xml somevalue?>text1', 'Parse PI with IE style ending.');
+       deepEqual(counter.counts, {pi:1, text:1}, 'Parse PI with IE style ending counts.');
+});
+
+test('Parse doctype', function() {
+       expect(4);
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">text1');
+       equal(writer.getContent(), '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">text1', 'Parse DOCTYPE.');
+       deepEqual(counter.counts, {doctype:1, text:1}, 'Parse HTML5 DOCTYPE counts.');
+
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<!DOCTYPE html>text1');
+       equal(writer.getContent(), '<!DOCTYPE html>text1', 'Parse HTML5 DOCTYPE.');
+       deepEqual(counter.counts, {doctype:1, text:1}, 'Parse HTML5 DOCTYPE counts.');
+});
+
+test('Parse (validate)', function() {
+       expect(2);
+
+       var counter = createCounter(writer);
+       counter.validate = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<invalid1>123<invalid2 />456<span title="title" invalid3="value">789</span>012</invalid1>');
+       equal(writer.getContent(), '123456<span title="title">789</span>012', 'Parse invalid elements and attributes.');
+       deepEqual(counter.counts, {start:1, end:1, text:4}, 'Parse invalid elements and attributes counts.');
+});
+
+test('Self closing', function() {
+       expect(1);
+
+       var counter = createCounter(writer);
+       counter.validate = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<ul><li>1<li><b>2</b><li><em><b>3</b></em></ul>');
+       equal(writer.getContent(), '<ul><li>1</li><li><b>2</b></li><li><em><b>3</b></em></li></ul>', 'Parse list with self closing items.');
+});
+
+test('Preserve internal elements', function() {
+       expect(2);
+
+       var schema = new tinymce.html.Schema({valid_elements : 'b'});
+       var counter = createCounter(writer);
+       counter.validate = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span id="id"><b>text</b></span><span id="id" data-mce-type="something"></span>');
+       equal(writer.getContent(), '<b>text</b><span id="id" data-mce-type="something"></span>', 'Preserve internal span element without any span schema rule.');
+
+       var schema = new tinymce.html.Schema({valid_elements : 'b,span[class]'});
+       var counter = createCounter(writer);
+       counter.validate = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span id="id" class="class"><b>text</b></span><span id="id" data-mce-type="something"></span>');
+       equal(writer.getContent(), '<span class="class"><b>text</b></span><span id="id" data-mce-type="something"></span>', 'Preserve internal span element with a span schema rule.');
+});
+
+test('Remove internal elements', function() {
+       expect(2);
+
+       var schema = new tinymce.html.Schema({valid_elements : 'b'});
+       var counter = createCounter(writer);
+       counter.validate = true;
+       counter.remove_internals = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span id="id"><b>text</b></span><span id="id" data-mce-type="something"></span>');
+       equal(writer.getContent(), '<b>text</b>', 'Remove internal span element without any span schema rule.');
+
+       var schema = new tinymce.html.Schema({valid_elements : 'b,span[class]'});
+       var counter = createCounter(writer);
+       counter.validate = true;
+       counter.remove_internals = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<span id="id" class="class"><b>text</b></span><span id="id" data-mce-type="something"></span>');
+       equal(writer.getContent(), '<span class="class"><b>text</b></span>', 'Remove internal span element with a span schema rule.');
+
+       // Reset
+       counter.remove_internals = false;
+});
+
+test('Parse attr with backslash #5436', function() {
+       var counter = createCounter(writer);
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<a title="\\" href="h">x</a>');
+       equal(writer.getContent(), '<a title="\\" href="h">x</a>');
+});
+
+test('Parse no attributes span before strong', function() {
+       var counter = createCounter(writer);
+       counter.validate = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse('<p><span>A</span> <strong>B</strong></p>');
+       equal(writer.getContent(), '<p>A <strong>B</strong></p>');
+});
+
+test('Conditional comments (allowed)', function() {
+       var counter = createCounter(writer);
+       counter.validate = false;
+       counter.allow_conditional_comments = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+
+       writer.reset();
+       parser.parse('<!--[if gte IE 4]>alert(1)<![endif]-->');
+       equal(writer.getContent(), '<!--[if gte IE 4]>alert(1)<![endif]-->');
+});
+
+test('Conditional comments (denied)', function() {
+       var counter = createCounter(writer);
+       counter.validate = false;
+       counter.allow_conditional_comments = false;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+
+       writer.reset();
+       parser.parse('<!--[if gte IE 4]>alert(1)<![endif]-->');
+       equal(writer.getContent(), '<!-- [if gte IE 4]>alert(1)<![endif]-->');
+
+       writer.reset();
+       parser.parse('<!--[if !IE]>alert(1)<![endif]-->');
+       equal(writer.getContent(), '<!-- [if !IE]>alert(1)<![endif]-->');
+});
+
+test('Parse script urls (allowed)', function() {
+       var counter = createCounter(writer);
+       counter.validate = false;
+       counter.allow_script_urls = true;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+       writer.reset();
+       parser.parse(
+               '<a href="javascript:alert(1)">1</a>' +
+               '<a href=" 2 ">2</a>'
+       );
+       equal(writer.getContent(), '<a href="javascript:alert(1)">1</a><a href=" 2 ">2</a>');
+});
+
+test('Parse script urls (denied)', function() {
+       var counter = createCounter(writer);
+       counter.validate = false;
+       var parser = new tinymce.html.SaxParser(counter, schema);
+
+       writer.reset();
+       parser.parse(
+               '<a href="jAvaScript:alert(1)">1</a>' +
+               '<a href="vbscript:alert(2)">2</a>' +
+               '<a href="java\u0000script:alert(3)">3</a>' +
+               '<a href="\njavascript:alert(4)">4</a>' +
+               '<a href="java\nscript:alert(5)">5</a>' +
+               '<a href="java\tscript:alert(6)">6</a>' +
+               '<a href="%6aavascript:alert(7)">7</a>' +
+               '<a href="%E3%82%AA%E3%83%BC%E3%83">Invalid url</a>'
+       );
+       equal(writer.getContent(), '<a>1</a><a>2</a><a>3</a><a>4</a><a>5</a><a>6</a><a>7</a><a href="%E3%82%AA%E3%83%BC%E3%83">Invalid url</a>');
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.SaxParser tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/SaxParser.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlSchemahtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/Schema.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/Schema.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/Schema.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,374 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.Schema tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.Schema");
+
+QUnit.config.reorder = false;
+
+test('Valid elements global rule', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: '@[id|style],img[src|-style]'});
+       deepEqual(schema.getElementRule('img'), {"attributes": {"id": {}, "src": {}}, "attributesOrder": ["id", "src"]});
+});
+
+test('Whildcard element rule', function() {
+       expect(17);
+
+       var schema = new tinymce.html.Schema({valid_elements: '*[id|class]'});
+       deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'b*[id|class]'});
+       deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
+       deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('body').attributesOrder, ["id", "class"]);
+       equal(schema.getElementRule('img'), undefined);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'b?[id|class]'});
+       deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
+       deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('bx').attributesOrder, ["id", "class"]);
+       equal(schema.getElementRule('body'), undefined);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'b+[id|class]'});
+       deepEqual(schema.getElementRule('body').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('body').attributesOrder, ["id", "class"]);
+       deepEqual(schema.getElementRule('bx').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('bx').attributesOrder, ["id", "class"]);
+       equal(schema.getElementRule('b'), undefined);
+});
+
+test('Whildcard attribute rule', function() {
+       expect(13);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'b[id|class|*]'});
+       deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
+       ok(schema.getElementRule('b').attributePatterns[0].pattern.test('x'));
+
+       var schema = new tinymce.html.Schema({valid_elements: 'b[id|class|x?]'});
+       deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
+       ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xy'));
+       ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('xba'));
+       ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('a'));
+
+       var schema = new tinymce.html.Schema({valid_elements: 'b[id|class|x+]'});
+       deepEqual(schema.getElementRule('b').attributes, {"id": {}, "class": {} });
+       deepEqual(schema.getElementRule('b').attributesOrder, ["id", "class"]);
+       ok(!schema.getElementRule('b').attributePatterns[0].pattern.test('x'));
+       ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xb'));
+       ok(schema.getElementRule('b').attributePatterns[0].pattern.test('xba'));
+});
+
+test('Valid attributes and attribute order', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'div,a[href|title],b[title]'});
+       deepEqual(schema.getElementRule('div'), {"attributes": {}, "attributesOrder": []});
+       deepEqual(schema.getElementRule('a'), {"attributes": {"href": {}, "title": {}}, "attributesOrder": ["href", "title"]});
+       deepEqual(schema.getElementRule('b'), {"attributes": {"title": {}}, "attributesOrder": ["title"]});
+});
+
+test('Required any attributes', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'a![id|style|href]'});
+       deepEqual(schema.getElementRule('a'), {"attributes": {"href": {}, "id": {}, "style": {}}, "attributesOrder": ["id", "style", "href"], "removeEmptyAttrs": true});
+});
+
+test('Required attributes', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'a[!href|!name]'});
+       deepEqual(schema.getElementRule('a'), {"attributes": {"href": {"required": true}, "name": {"required": true}}, "attributesOrder": ["href", "name"], "attributesRequired": ["href", "name"]});
+});
+
+test('Default attribute values', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'img[border=0]'});
+       deepEqual(schema.getElementRule('img'), {"attributes": {"border": {"defaultValue": "0"}}, "attributesOrder": ["border"], "attributesDefault": [{"name": "border", "value": "0"}]});
+});
+
+test('Forced attribute values', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'img[border:0]'});
+       deepEqual(schema.getElementRule('img'), {"attributes": {"border": {"forcedValue": "0"}}, "attributesOrder": ["border"], "attributesForced": [{"name": "border", "value": "0"}]});
+});
+
+test('Required attribute values', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: 'span[dir<ltr?rtl]'});
+       deepEqual(schema.getElementRule('span'), {"attributes": {"dir": {"validValues": {"rtl": {}, "ltr": {}}}}, "attributesOrder": ["dir"]});
+});
+
+test('Remove empty elements', function() {
+       expect(2);
+
+       var schema = new tinymce.html.Schema({valid_elements: '-span'});
+       deepEqual(schema.getElementRule('span'), {"attributes": {}, "attributesOrder": [], "removeEmpty": true});
+
+       var schema = new tinymce.html.Schema({valid_elements: '#span'});
+       deepEqual(schema.getElementRule('span'), {"attributes": {}, "attributesOrder": [], "paddEmpty": true});
+});
+
+test('addValidElements', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema({valid_elements: '@[id|style],img[src|-style]'});
+       schema.addValidElements('b[class]');
+       deepEqual(schema.getElementRule('b'), {"attributes": {"id": {}, "style": {}, "class": {}}, "attributesOrder": ["id", "style", "class"]});
+});
+
+test('setValidElements', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({valid_elements: '@[id|style],img[src|-style]'});
+       schema.setValidElements('b[class]');
+       equal(schema.getElementRule('img'), undefined);
+       deepEqual(schema.getElementRule('b'), {"attributes": {"class": {}}, "attributesOrder": ["class"]});
+
+       var schema = new tinymce.html.Schema({valid_elements: 'img[src]'});
+       schema.setValidElements('@[id|style],img[src]');
+       deepEqual(schema.getElementRule('img'), {"attributes": {"id": {}, "style": {}, "src": {}}, "attributesOrder": ["id", "style", "src"]});
+});
+
+test('getBoolAttrs', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema();
+       deepEqual(schema.getBoolAttrs(), {
+               "CONTROLS": {}, "LOOP": {}, "AUTOPLAY": {}, "SELECTED": {}, "READONLY": {}, "NOWRAP": {},
+               "NOSHADE": {}, "NORESIZE": {}, "NOHREF": {}, "MULTIPLE": {}, "ISMAP": {}, "DISABLED": {}, "DEFER": {},
+               "DECLARE": {}, "COMPACT": {}, "CHECKED": {},
+               "controls": {}, "loop": {}, "autoplay": {}, "selected": {}, "readonly": {}, "nowrap": {},
+               "noshade": {}, "noresize": {}, "nohref": {}, "multiple": {}, "ismap": {}, "disabled": {}, "defer": {},
+               "declare": {}, "compact": {}, "checked": {}
+       });
+});
+
+test('getBlockElements', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema();
+       deepEqual(schema.getBlockElements(), {
+               ASIDE: {}, HGROUP: {}, SECTION: {}, ARTICLE: {}, FOOTER: {}, HEADER: {}, SAMP: {},
+               ISINDEX: {}, MENU: {}, NOSCRIPT: {}, FIELDSET: {}, DIR: {}, DD: {}, DT: {},
+               DL: {}, CENTER: {}, BLOCKQUOTE: {}, CAPTION: {}, UL: {}, OL: {}, LI: {},
+               TD: {}, TR: {}, TH: {}, TFOOT: {}, THEAD: {}, TBODY: {}, TABLE: {}, FORM: {},
+               PRE: {}, ADDRESS: {}, DIV: {}, P: {}, HR: {}, H6: {}, H5: {}, H4: {}, H3: {},
+               H2: {}, H1: {}, NAV: {}, FIGURE: {}, DATALIST: {}, OPTGROUP: {}, OPTION: {}, SELECT: {},
+               aside: {}, hgroup: {}, section: {}, article: {}, footer: {}, header: {}, samp: {},
+               isindex: {}, menu: {}, noscript: {}, fieldset: {}, dir: {}, dd: {}, dt: {}, dl: {}, center: {},
+               blockquote: {}, caption: {}, ul: {}, ol: {}, li: {}, td: {}, tr: {}, th: {}, tfoot: {}, thead: {},
+               tbody: {}, table: {}, form: {}, pre: {}, address: {}, div: {}, p: {}, hr: {}, h6: {},
+               h5: {}, h4: {}, h3: {}, h2: {}, h1: {}, nav: {}, figure: {}, datalist: {}, optgroup: {},
+               option: {}, select: {}
+       });
+});
+
+test('getShortEndedElements', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema();
+       deepEqual(schema.getShortEndedElements(), {
+               "EMBED": {}, "PARAM": {}, "META": {}, "LINK": {}, "ISINDEX": {},
+               "INPUT": {}, "IMG": {}, "HR": {}, "FRAME": {}, "COL": {}, "BR": {},
+               "BASEFONT": {}, "BASE": {}, "AREA": {}, "SOURCE" : {}, "WBR" : {}, "TRACK" : {},
+               "embed": {}, "param": {}, "meta": {}, "link": {}, "isindex": {},
+               "input": {}, "img": {}, "hr": {}, "frame": {}, "col": {}, "br": {},
+               "basefont": {}, "base": {}, "area": {}, "source" : {}, "wbr" : {}, "track" : {}
+       });
+});
+
+test('getNonEmptyElements', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema();
+       deepEqual(schema.getNonEmptyElements(), {
+               "EMBED": {}, "PARAM": {}, "META": {}, "LINK": {}, "ISINDEX": {},
+               "INPUT": {}, "IMG": {}, "HR": {}, "FRAME": {}, "COL": {}, "BR": {},
+               "BASEFONT": {}, "BASE": {}, "AREA": {}, "SOURCE" : {},
+               "TD": {}, "TH": {}, "IFRAME": {}, "VIDEO": {}, "AUDIO": {}, "OBJECT": {}, "WBR": {}, "TRACK" : {}, "SCRIPT" : {},
+               "embed": {}, "param": {}, "meta": {}, "link": {}, "isindex": {},
+               "input": {}, "img": {}, "hr": {}, "frame": {}, "col": {}, "br": {},
+               "basefont": {}, "base": {}, "area": {}, "source" : {},
+               "td": {}, "th": {}, "iframe": {}, "video": {}, "audio": {}, "object": {}, "wbr" : {}, "track" : {},  "script" : {},
+       });
+});
+
+test('getWhiteSpaceElements', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema();
+       deepEqual(schema.getWhiteSpaceElements(), {
+               "IFRAME": {}, "NOSCRIPT": {}, "OBJECT": {}, "PRE": {},
+               "SCRIPT": {}, "STYLE": {}, "TEXTAREA": {}, "VIDEO": {}, "AUDIO": {},
+               "iframe": {}, "noscript": {}, "object": {}, "pre": {},
+               "script": {}, "style": {}, "textarea": {}, "video": {}, "audio": {}
+       });
+});
+
+test('getTextBlockElements', function() {
+       expect(1);
+
+       var schema = new tinymce.html.Schema();
+       deepEqual(schema.getTextBlockElements(), {
+               "ADDRESS": {}, "ARTICLE": {}, "ASIDE": {}, "BLOCKQUOTE": {}, "CENTER": {}, "DIR": {}, "DIV": {}, "FIELDSET": {}, "FIGURE": {}, "FOOTER": {}, "FORM": {},
+               "H1": {}, "H2": {}, "H3": {}, "H4": {}, "H5": {}, "H6": {}, "HEADER": {}, "HGROUP": {}, "NAV": {}, "P": {}, "PRE": {}, "SECTION": {},
+               "address": {}, "article": {}, "aside": {}, "blockquote": {}, "center": {}, "dir": {}, "div": {}, "fieldset": {}, "figure": {}, "footer": {}, "form": {},
+               "h1": {}, "h2": {}, "h3": {}, "h4": {}, "h5": {}, "h6": {}, "header": {}, "hgroup": {}, "nav": {}, "p": {}, "pre": {}, "section": {}
+       });
+});
+
+test('isValidChild', function() {
+       expect(4);
+
+       var schema = new tinymce.html.Schema();
+       ok(schema.isValidChild('body', 'p'));
+       ok(schema.isValidChild('p', 'img'));
+       ok(!schema.isValidChild('body', 'body'));
+       ok(!schema.isValidChild('p', 'body'));
+});
+
+test('getElementRule', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema();
+       ok(schema.getElementRule('b'));
+       ok(!schema.getElementRule('bx'));
+       ok(!schema.getElementRule(null));
+});
+
+test('addCustomElements', function() {
+       expect(5);
+
+       var schema = new tinymce.html.Schema({valid_elements:'inline,block'});
+       schema.addCustomElements('~inline,block');
+       ok(schema.getElementRule('inline'));
+       ok(schema.getElementRule('block'));
+       ok(schema.isValidChild('body', 'block'));
+       ok(schema.isValidChild('block', 'inline'));
+       ok(schema.isValidChild('p', 'inline'));
+});
+
+test('addValidChildren', function() {
+       expect(7);
+
+       var schema = new tinymce.html.Schema();
+       ok(schema.isValidChild('body', 'p'));
+       ok(!schema.isValidChild('body', 'body'));
+       ok(!schema.isValidChild('body', 'html'));
+       schema.addValidChildren('+body[body|html]');
+       ok(schema.isValidChild('body', 'body'));
+       ok(schema.isValidChild('body', 'html'));
+
+       var schema = new tinymce.html.Schema();
+       ok(schema.isValidChild('body', 'p'));
+       schema.addValidChildren('-body[p]');
+       ok(!schema.isValidChild('body', 'p'));
+});
+
+test('addCustomElements/getCustomElements', function() {
+       expect(4);
+
+       var schema = new tinymce.html.Schema();
+       schema.addCustomElements('~inline,block');
+       ok(schema.getBlockElements()['block']);
+       ok(!schema.getBlockElements()['inline']);
+       ok(schema.getCustomElements()['inline']);
+       ok(schema.getCustomElements()['block']);
+});
+
+test('whitespaceElements', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({whitespace_elements : 'pre,p'});
+       ok(schema.getWhiteSpaceElements()['pre']);
+       ok(!schema.getWhiteSpaceElements()['span']);
+
+       var schema = new tinymce.html.Schema({whitespace_elements : 'code'});
+       ok(schema.getWhiteSpaceElements()['code']);
+});
+
+test('selfClosingElements', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({self_closing_elements : 'pre,p'});
+       ok(schema.getSelfClosingElements()['pre']);
+       ok(schema.getSelfClosingElements()['p']);
+       ok(!schema.getSelfClosingElements()['li']);
+});
+
+test('shortEndedElements', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({short_ended_elements : 'pre,p'});
+       ok(schema.getShortEndedElements()['pre']);
+       ok(schema.getShortEndedElements()['p']);
+       ok(!schema.getShortEndedElements()['img']);
+});
+
+test('booleanAttributes', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({boolean_attributes : 'href,alt'});
+       ok(schema.getBoolAttrs()['href']);
+       ok(schema.getBoolAttrs()['alt']);
+       ok(!schema.getBoolAttrs()['checked']);
+});
+
+test('nonEmptyElements', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({non_empty_elements : 'pre,p'});
+       ok(schema.getNonEmptyElements()['pre']);
+       ok(schema.getNonEmptyElements()['p']);
+       ok(!schema.getNonEmptyElements()['img']);
+});
+
+test('blockElements', function() {
+       expect(3);
+
+       var schema = new tinymce.html.Schema({block_elements : 'pre,p'});
+       ok(schema.getBlockElements()['pre']);
+       ok(schema.getBlockElements()['p']);
+       ok(!schema.getBlockElements()['h1']);
+});
+
+test('isValid', function() {
+       var schema = new tinymce.html.Schema({valid_elements : 'a[href],i[*]'});
+
+       ok(schema.isValid('a'));
+       ok(schema.isValid('a', 'href'));
+       ok(!schema.isValid('b'));
+       ok(!schema.isValid('b', 'href'));
+       ok(!schema.isValid('a', 'id'));
+       ok(schema.isValid('i'));
+       ok(schema.isValid('i', 'id'));
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Schema tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/Schema.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlSerializerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/Serializer.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/Serializer.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/Serializer.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.Serializer tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.Serializer");
+
+QUnit.config.reorder = false;
+
+test('Basic serialization', function() {
+       var serializer = new tinymce.html.Serializer();
+
+       expect(6);
+
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('text<text&')), 'text&lt;text&amp;');
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('<B>text</B><IMG src="1.gif">')), '<strong>text</strong><img src="1.gif" alt="" />');
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('<!-- comment -->')), '<!-- comment -->');
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('<![CDATA[cdata]]>')), '<![CDATA[cdata]]>');
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('<?xml attr="value" ?>')), '<?xml attr="value" ?>');
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('<!DOCTYPE html>')), '<!DOCTYPE html>');
+});
+
+test('Sorting of attributes', function() {
+       var serializer = new tinymce.html.Serializer();
+
+       expect(1);
+
+       equal(serializer.serialize(new tinymce.html.DomParser().parse('<b class="class" id="id">x</b>')), '<strong id="id" class="class">x</strong>');
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Serializer tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/Serializer.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlStyleshtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/Styles.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/Styles.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/Styles.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,176 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.Styles tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.Styles");
+
+QUnit.config.reorder = false;
+
+test('Basic parsing/serializing', function() {
+       var styles = new tinymce.html.Styles();
+
+       expect(11);
+
+       equal(styles.serialize(styles.parse('FONT-SIZE:10px')), "font-size: 10px;");
+       equal(styles.serialize(styles.parse('FONT-SIZE:10px;COLOR:red')), "font-size: 10px; color: red;");
+       equal(styles.serialize(styles.parse('   FONT-SIZE  :  10px  ;   COLOR  :  red   ')), "font-size: 10px; color: red;");
+       equal(styles.serialize(styles.parse('key:"value"')), "key: 'value';");
+       equal(styles.serialize(styles.parse('key:"value1" \'value2\'')), "key: 'value1' 'value2';");
+       equal(styles.serialize(styles.parse('key:"val\\"ue1" \'val\\\'ue2\'')), "key: 'val\"ue1' 'val\\'ue2';");
+       equal(styles.serialize(styles.parse('width:100%')), 'width: 100%;');
+       equal(styles.serialize(styles.parse('value:_; value2:"_"')), 'value: _; value2: \'_\';');
+       equal(styles.serialize(styles.parse('value: "&amp;"')), "value: '&amp;';");
+       equal(styles.serialize(styles.parse('value: "&"')), "value: '&';");
+       equal(styles.serialize(styles.parse('value: ')), "");
+});
+
+test('Colors force hex and lowercase', function() {
+       var styles = new tinymce.html.Styles();
+
+       expect(6);
+
+       equal(styles.serialize(styles.parse('color: rgb(1,2,3)')), "color: #010203;");
+       equal(styles.serialize(styles.parse('color: RGB(1,2,3)')), "color: #010203;");
+       equal(styles.serialize(styles.parse('color: #FF0000')), "color: #ff0000;");
+       equal(styles.serialize(styles.parse('  color:   RGB  (  1  ,  2  ,  3  )  ')), "color: #010203;");
+       equal(styles.serialize(styles.parse('   FONT-SIZE  :  10px  ;   COLOR  :  RGB  (  1  ,  2  ,  3  )   ')), "font-size: 10px; color: #010203;");
+       equal(styles.serialize(styles.parse('   FONT-SIZE  :  10px  ;   COLOR  :  RED   ')), "font-size: 10px; color: red;");
+});
+
+test('Urls convert urls and force format', function() {
+       var styles = new tinymce.html.Styles({url_converter : function(url) {
+               return '|' + url + '|';
+       }});
+
+       expect(9);
+
+       equal(styles.serialize(styles.parse('background: url(a)')), "background: url('|a|');");
+       equal(styles.serialize(styles.parse('background: url("a")')), "background: url('|a|');");
+       equal(styles.serialize(styles.parse("background: url('a')")), "background: url('|a|');");
+       equal(styles.serialize(styles.parse('background: url(   a   )')), "background: url('|a|');");
+       equal(styles.serialize(styles.parse('background: url(   "a"   )')), "background: url('|a|');");
+       equal(styles.serialize(styles.parse("background: url(    'a'    )")), "background: url('|a|');");
+       equal(styles.serialize(styles.parse('background1: url(a); background2: url("a"); background3: url(\'a\')')), "background1: url('|a|'); background2: url('|a|'); background3: url('|a|');");
+       equal(styles.serialize(styles.parse("background: url('http://www.site.com/a?a=b&c=d')")), "background: url('|http://www.site.com/a?a=b&c=d|');");
+       equal(styles.serialize(styles.parse("background: url('http://www.site.com/a_190x144.jpg');")), "background: url('|http://www.site.com/a_190x144.jpg|');");
+});
+
+test('Compress styles', function() {
+       var styles = new tinymce.html.Styles();
+
+       equal(
+               styles.serialize(styles.parse('border-top: 1px solid red; border-left: 1px solid red; border-bottom: 1px solid red; border-right: 1px solid red;')),
+               'border: 1px solid red;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('border-width: 1pt 1pt 1pt 1pt; border-style: none none none none; border-color: black black black black;')),
+               'border: 1pt none black;'
+       );
+       
+       equal(
+               styles.serialize(styles.parse('border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;')),
+               'border-width: 1pt 4pt 2pt 3pt; border-style: solid dashed dotted none; border-color: black red green blue;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('border-top: 1px solid red; border-left: 1px solid red; border-right: 1px solid red; border-bottom: 1px solid red')),
+               'border: 1px solid red;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('border-top: 1px solid red; border-right: 2px solid red; border-bottom: 3px solid red; border-left: 4px solid red')),
+               'border-top: 1px solid red; border-right: 2px solid red; border-bottom: 3px solid red; border-left: 4px solid red;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('padding-top: 1px; padding-right: 2px; padding-bottom: 3px; padding-left: 4px')),
+               'padding: 1px 2px 3px 4px;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('margin-top: 1px; margin-right: 2px; margin-bottom: 3px; margin-left: 4px')),
+               'margin: 1px 2px 3px 4px;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('margin-top: 1px; margin-right: 1px; margin-bottom: 1px; margin-left: 2px')),
+               'margin: 1px 1px 1px 2px;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('margin-top: 2px; margin-right: 1px; margin-bottom: 1px; margin-left: 1px')),
+               'margin: 2px 1px 1px 1px;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('border-top-color: red; border-right-color: green; border-bottom-color: blue; border-left-color: yellow')),
+               'border-color: red green blue yellow;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('border-width: 1px; border-style: solid; border-color: red')),
+               'border: 1px solid red;'
+       );
+
+       equal(
+               styles.serialize(styles.parse('border-width: 1px; border-color: red')),
+               'border-width: 1px; border-color: red;'
+       );
+});
+
+test('Font weight', function() {
+       var styles = new tinymce.html.Styles();
+
+       expect(1);
+
+       equal(styles.serialize(styles.parse('font-weight: 700')), "font-weight: bold;");
+});
+
+test('Valid styles', function() {
+       var styles = new tinymce.html.Styles({}, new tinymce.html.Schema({valid_styles : {'*' : 'color,font-size', 'a' : 'margin-left'}}));
+
+       expect(2);
+
+       equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px; invalid: 1;'), 'b'), "color: #ff0000; font-size: 10px;");
+       equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px; invalid: 2;'), 'a'), "color: #ff0000; font-size: 10px; margin-left: 10px;");
+});
+
+test('Script urls denied', function() {
+       var styles = new tinymce.html.Styles();
+
+       equal(styles.serialize(styles.parse('behavior:url(test.htc)')), "");
+       equal(styles.serialize(styles.parse('color:expression(alert(1))')), "");
+       equal(styles.serialize(styles.parse('color:  expression  (  alert(1))')), "");
+       equal(styles.serialize(styles.parse('background:url(jAvaScript:alert(1)')), "");
+       equal(styles.serialize(styles.parse('background:url(javascript:alert(1)')), "");
+       equal(styles.serialize(styles.parse('background:url(vbscript:alert(1)')), "");
+       equal(styles.serialize(styles.parse('background:url(j\navas\u0000cr\tipt:alert(1)')), "");
+});
+
+test('Script urls allowed', function() {
+       var styles = new tinymce.html.Styles({allow_script_urls: true});
+
+       equal(styles.serialize(styles.parse('behavior:url(test.htc)')), "behavior: url('test.htc');");
+       equal(styles.serialize(styles.parse('color:expression(alert(1))')), "color: expression(alert(1));");
+       equal(styles.serialize(styles.parse('background:url(javascript:alert(1)')), "background: url('javascript:alert(1');");
+       equal(styles.serialize(styles.parse('background:url(vbscript:alert(1)')), "background: url('vbscript:alert(1');");
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Styles tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/Styles.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlWriterhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/Writer.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/Writer.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/Writer.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,174 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.html.Writer tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.html.Writer");
+
+QUnit.config.reorder = false;
+
+test('Comment', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer();
+       writer.comment('text');
+       equal(writer.getContent(), '<!--text-->');
+
+       var writer = new tinymce.html.Writer();
+       writer.comment('');
+       equal(writer.getContent(), '<!---->');
+});
+
+test('CDATA', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer();
+       writer.cdata('text');
+       equal(writer.getContent(), '<![CDATA[text]]>');
+
+       var writer = new tinymce.html.Writer();
+       writer.cdata('');
+       equal(writer.getContent(), '<![CDATA[]]>');
+});
+
+test('PI', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer();
+       writer.pi('xml', 'someval');
+       equal(writer.getContent(), '<?xml someval?>');
+
+       var writer = new tinymce.html.Writer();
+       writer.pi('xml');
+       equal(writer.getContent(), '<?xml?>');
+});
+
+test('Doctype', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer();
+       writer.doctype(' text');
+       equal(writer.getContent(), '<!DOCTYPE text>');
+
+       var writer = new tinymce.html.Writer();
+       writer.doctype('');
+       equal(writer.getContent(), '<!DOCTYPE>');
+});
+
+test('Text', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer();
+       writer.text('te<xt');
+       equal(writer.getContent(), 'te&lt;xt');
+
+       var writer = new tinymce.html.Writer();
+       writer.text('');
+       equal(writer.getContent(), '');
+});
+
+test('Text raw', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer();
+       writer.text('te<xt', true);
+       equal(writer.getContent(), 'te<xt');
+
+       var writer = new tinymce.html.Writer();
+       writer.text('', true);
+       equal(writer.getContent(), '');
+});
+
+test('Start', function() {
+       expect(5);
+
+       var writer = new tinymce.html.Writer();
+       writer.start('b');
+       equal(writer.getContent(), '<b>');
+
+       var writer = new tinymce.html.Writer();
+       writer.start('b', [{name: 'attr1', value: 'value1'}, {name: 'attr2', value: 'value2'}]);
+       equal(writer.getContent(), '<b attr1="value1" attr2="value2">');
+
+       var writer = new tinymce.html.Writer();
+       writer.start('b', [{name: 'attr1', value: 'val<"ue1'}]);
+       equal(writer.getContent(), '<b attr1="val&lt;&quot;ue1">');
+
+       var writer = new tinymce.html.Writer();
+       writer.start('img', [{name: 'attr1', value: 'value1'}, {name: 'attr2', value: 'value2'}], true);
+       equal(writer.getContent(), '<img attr1="value1" attr2="value2" />');
+
+       var writer = new tinymce.html.Writer();
+       writer.start('br', null, true);
+       equal(writer.getContent(), '<br />');
+});
+
+test('End', function() {
+       expect(1);
+
+       var writer = new tinymce.html.Writer();
+       writer.end('b');
+       equal(writer.getContent(), '</b>');
+});
+
+test('Indentation', function() {
+       expect(2);
+
+       var writer = new tinymce.html.Writer({indent: true, indent_before: 'p', indent_after:'p'});
+       writer.start('p');
+       writer.start('span');
+       writer.text('a');
+       writer.end('span');
+       writer.end('p');
+       writer.start('p');
+       writer.text('a');
+       writer.end('p');
+       equal(writer.getContent(), '<p><span>a</span></p>\n<p>a</p>');
+
+       var writer = new tinymce.html.Writer({indent: true, indent_before: 'p', indent_after:'p'});
+       writer.start('p');
+       writer.text('a');
+       writer.end('p');
+       equal(writer.getContent(), '<p>a</p>');
+});
+
+test('Entities', function() {
+       expect(3);
+
+       var writer = new tinymce.html.Writer();
+       writer.start('p', [{name: "title", value: '<>"\'&\u00e5\u00e4\u00f6'}]);
+       writer.text('<>"\'&\u00e5\u00e4\u00f6');
+       writer.end('p');
+       equal(writer.getContent(), '<p title="&lt;&gt;&quot;\'&amp;\u00e5\u00e4\u00f6">&lt;&gt;"\'&amp;\u00e5\u00e4\u00f6</p>');
+
+       var writer = new tinymce.html.Writer({entity_encoding: 'numeric'});
+       writer.start('p', [{name: "title", value: '<>"\'&\u00e5\u00e4\u00f6'}]);
+       writer.text('<>"\'&\u00e5\u00e4\u00f6');
+       writer.end('p');
+       equal(writer.getContent(), '<p title="&lt;&gt;&quot;\'&amp;&#229;&#228;&#246;">&lt;&gt;"\'&amp;&#229;&#228;&#246;</p>');
+
+       var writer = new tinymce.html.Writer({entity_encoding: 'named'});
+       writer.start('p', [{name: "title", value: '<>"\'&\u00e5\u00e4\u00f6'}]);
+       writer.text('<>"\'&\u00e5\u00e4\u00f6');
+       writer.end('p');
+       equal(writer.getContent(), '<p title="&lt;&gt;&quot;\'&amp;&aring;&auml;&ouml;">&lt;&gt;"\'&amp;&aring;&auml;&ouml;</p>');
+});
+
+
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Writer tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/Writer.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmlobsoletehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/obsolete.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/obsolete.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/obsolete.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,294 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Support for obsolete tags and attributes in the default HTML 5.0 schema</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+module("tinymce.html.Schema", {
+       autostart: false
+});
+
+function getContent() {
+       return editor.getContent().replace(/[\r\n]+/g, '');
+};
+
+/**
+ * Test whether attribute exists in a HTML string
+ *
+ * @param html The HTML string
+ * @param attr string|object When string, test for the first instance of attr.
+ *                     When object, break up the HTML string into individual tags and test for attr in the specified tag.
+ *                     Format: { tagName: 'attr1 attr2', ... }
+ * @return bool
+ */
+function hasAttr( html, attr ) {
+       var tagName, tags, tag, array, regex, i;
+
+       if ( typeof attr === 'string' ) {
+               return new RegExp( ' \\b' + attr + '\\b' ).test( html );
+       }
+
+       for ( tagName in attr ) {
+               if ( tags = html.match( new RegExp( '<' + tagName + ' [^>]+>', 'g' ) ) ) {
+                       for ( tag in tags ) {
+                               array = attr[tagName].split(' ');
+
+                               for ( i in array ) {
+                                       regex = new RegExp( '\\b' + array[i] + '\\b' );
+
+                                       if ( regex.test( tags[tag] ) ) {
+                                               attr[tagName] = attr[tagName].replace( regex, '' );
+                                       }
+                               }
+                       }
+
+                       if ( attr[tagName].replace( / +/g, '' ).length ) {
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+// Ref: http://www.w3.org/TR/html5/obsolete.html, http://developers.whatwg.org/obsolete.html
+
+test('HTML elements non-conforming to HTML 5.0', function() {
+       var testString;
+
+       /*
+       Not supported, deprecated in HTML 4.0 or earlier, and/or proprietary:
+               applet
+               bgsound
+               dir
+               frame
+               frameset
+               noframes
+               isindex
+               listing
+               nextid
+               noembed
+               plaintext
+               rb
+               xmp
+               basefont
+               blink
+               marquee
+               multicol
+               nobr
+               spacer
+
+       The rest are still supported in TinyMCE but "...must not be used by authors".
+       */
+
+       expect(6);
+
+       text = 'acronym';
+       testString = '<p><acronym title="www">WWW</acronym></p>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'strike, converted to span';
+       editor.setContent( '<strike>test</strike>' );
+       equal( getContent(), '<p><span style="text-decoration: line-through;">test</span></p>', text );
+
+       text = 'big';
+       testString = '<p><big>test</big></p>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'center';
+       testString = '<center>test</center>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'font, converted to span';
+       editor.setContent( '<p><font size="4">test</font></p>' );
+       equal( getContent(), '<p><span style="font-size: large;">test</span></p>', text );
+
+       text = 'tt';
+       testString = '<p><tt>test</tt></p>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+});
+
+test('Obsolete (but still conforming) HTML attributes', function() {
+       var testString;
+
+       expect(3);
+
+       text = 'border on <img>';
+       testString = '<p><img src="../../test.gif" alt="" border="5" /></p>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'Old style anchors';
+       testString = '<p><a name="test"></a></p>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'maxlength, size on input type="number"';
+       testString = '<p><input maxlength="5" size="10" type="number" value="" /></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { input: 'maxlength size' } ), text );
+});
+
+test('Obsolete attributes in HTML 5.0', function() {
+       var testString, text;
+
+       expect(22);
+
+       text = 'charset, rev, shape, coords on <a> elements';
+       testString = '<p><a href="javascript;:" charset="en" rev="made" shape="rect" coords="5,5">test</a></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { a: 'charset rev shape coords' } ), text );
+
+       text = 'name, align, hspace, vspace on img elements';
+       testString = '<p><img src="../../test.gif" alt="" name="test" align="left" hspace="5" vspace="5" /></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { img: 'name align hspace vspace' } ), text );
+
+       text = 'name, align, hspace, vspace, on embed elements';
+       testString = '<p><embed width="100" height="100" src="test.swf" vspace="5" hspace="5" align="left" name="test"></embed></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { embed: 'name align hspace vspace' } ), text );
+
+       text = 'archive, classid, code, codebase, codetype, declare, standby on object elements';
+       testString = '<p><object width="100" height="100" classid="clsid" codebase="clsid" standby="standby" codetype="1" code="1" archive="1" declare="declare"></object></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { object: 'archive classid code codebase codetype declare standby' } ), text );
+
+       text = 'type, valuetype on param elements';
+       testString = '<p><object width="100" height="100"><param type="" valuetype="" /></object></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { param: 'type valuetype' } ), text );
+
+       text = 'align, bgcolor, border, cellpadding, cellspacing, frame, rules, summary, width on table elements';
+       testString = '<table border="1" summary="" width="100" frame="" rules="" cellspacing="5" cellpadding="5" align="left" bgcolor="blue"><tbody><tr><td>test</td></tr></tbody></table>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { table: 'align bgcolor border cellpadding cellspacing frame rules summary width' } ), text );
+
+       text = 'align, char, charoff, valign on tbody, thead, and tfoot elements';
+       testString = '<table><thead align="left" char="" charoff="" valign="top"></thead><tfoot align="left" char="" charoff="" valign="top"></tfoot><tbody align="left" char="" charoff="" valign="top"><tr><th>test</th><td>test</td></tr></tbody></table>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), {
+               thead: 'align char charoff valign',
+               tfoot: 'align char charoff valign',
+               tbody: 'align char charoff valign'
+       } ), text );
+
+       text = 'axis, align, bgcolor, char, charoff, height, nowrap, valign, width on td and th elements, scope on td elements';
+       testString = '<table><tbody><tr><th axis="" align="left" char="" charoff="" valign="top" nowrap="nowrap" bgcolor="blue" width="100" height="10">test</th><td axis="" align="left" char="" charoff="" valign="top" nowrap="nowrap" bgcolor="blue" width="100" height="10" scope="">test</td></tr></tbody></table>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), {
+               th: 'axis align bgcolor char charoff height nowrap valign width',
+               td: 'axis align bgcolor char charoff height nowrap valign width scope'
+       } ), text );
+
+       text = 'align, bgcolor, char, charoff, valign on tr elements';
+       testString = '<table><tbody><tr align="left" char="" charoff="" valign="top" bgcolor="blue"><td>test</td></tr></tbody></table>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { tr: 'align bgcolor char charoff valign' } ), text );
+
+       text = 'clear on br elements';
+       testString = '<p>test<br clear="all" />test</p>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'align on caption elements';
+       testString = '<table><caption align="left">test</caption><tbody><tr><td>test</td></tr></tbody></table>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'align, char, charoff, valign, width on col elements';
+       testString = '<table><colgroup><col width="100" align="left" char="a" charoff="1" valign="top" /><col /></colgroup><tbody><tr><td>test</td><td>test</td></tr></tbody></table>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { col: 'align char charoff valign width' } ), text );
+
+       text = 'align on div, h1—h6, input, legend, p elements';
+       testString = '<div align="left">1</div><h3 align="left">1</h3><p align="left">1</p><form><fieldset><legend align="left">test</legend><input type="text" align="left" /></fieldset></form>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'compact on dl elements';
+       testString = '<dl compact="compact"><dd>1</dd></dl>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'align, hspace, vspace on embed elements';
+       testString = '<p><embed width="100" height="100" vspace="5" hspace="5" align="left"></embed></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { embed: 'align hspace vspace' } ), text );
+
+       text = 'align, noshade, size, width on hr elements';
+       testString = '<hr align="left" noshade="noshade" size="1" width="100" />';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { hr: 'align noshade size width' } ), text );
+
+       text = 'align, frameborder, marginheight, marginwidth, scrolling on iframe elements';
+       testString = '<p><iframe width="100" height="100" frameborder="1" marginwidth="5" marginheight="5" scrolling="" align="left"></iframe></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { iframe: 'align frameborder marginheight marginwidth scrolling' } ), text );
+
+       text = 'type on li elements';
+       testString = '<ul><li type="disc">test</li></ul>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'align, border, hspace, vspace on object elements';
+       testString = '<p><object width="100" height="100" border="1" vspace="5" hspace="5" align="left"></object></p>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { object: 'align border hspace vspace' } ), text );
+
+       text = 'compact on ol elements';
+       testString = '<ol compact="compact"><li>test</li></ol>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+
+       text = 'compact, type on ul elements';
+       testString = '<ul type="disc" compact="compact"><li>test</li></ul>';
+       editor.setContent( testString );
+       ok( hasAttr( getContent(), { ul: 'compact type' } ), text );
+
+       text = 'width on pre elements';
+       testString = '<pre width="100">1</pre>';
+       editor.setContent( testString );
+       equal( getContent(), testString, text );
+});
+
+tinymce.init({
+       mode : "exact",
+       elements : "elm1",
+       add_unload_trigger : false,
+       indent : false,
+       entities : 'raw',
+       plugins: 'media',
+       convert_urls : false,
+       init_instance_callback : function(ed) {
+               editor = ed;
+               QUnit.start();
+       }
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Support for obsolete tags and attributes in the default HTML 5.0 schema</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <textarea id="elm1" name="elm1"></textarea>
+       <div>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+               <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+       </div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/obsolete.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcehtmltestsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/html/tests.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/html/tests.js                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/html/tests.js      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+{
+       "title": "tinymce.html",
+       "tests": [
+               {"title": "DomParser", "url": "DomParser.html"},
+               {"title": "Entities", "url": "Entities.html"},
+               {"title": "Node", "url": "Node.html"},
+               {"title": "SaxParser", "url": "SaxParser.html"},
+               {"title": "Schema", "url": "Schema.html"},
+               {"title": "Serializer", "url": "Serializer.html"},
+               {"title": "Styles", "url": "Styles.html"},
+               {"title": "Writer", "url": "Writer.html"},
+               {"title": "Obsolete tags and attributes", "url": "obsolete.html"}
+       ]
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/html/tests.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymcetestsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/tests.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/tests.js                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/tests.js   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+{
+       "title": "tinymce",
+       "tests": [
+               {"title": "Editor", "url": "Editor.html"},
+               {"title": "EditorCommands", "url": "EditorCommands.html"},
+               {"title": "EnterKey", "url": "EnterKey.html"},
+               {"title": "ForceBlocks", "url": "ForceBlocks.html"},
+               {"title": "Formatter (Apply)", "url": "Formatter_apply.html"},
+               {"title": "Formatter (Remove)", "url": "Formatter_remove.html"},
+               {"title": "Formatter (Check)", "url": "Formatter_check.html"},
+               {"title": "Formatter (jsrobot)", "url": "Formatter_robot.html", "jsrobot":true},
+               {"title": "UndoManager", "url": "UndoManager.html"},
+               {"title": "Undo", "url": "UndoManager_robot.html", "jsrobot": true}
+       ]
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/tests.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiAbsoluteLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.AbsoluteLayout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.AbsoluteLayout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createPanel(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'panel',
+               layout: 'absolute',
+               width: 200,
+               height: 200
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+}
+
+test("spacer x:10, y:20, minWidth: 100, minHeight: 100", function() {
+       panel = createPanel({
+               items: [
+                       {type: 'spacer', x: 10, y: 20, w: 100, h: 120, classes: 'red'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 200, 200]);
+       deepEqual(rect(panel.find('spacer')[0]), [10, 20, 100, 120]);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.AbsoluteLayout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiButtonhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Button.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Button.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Button.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,133 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Button Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Button", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createButton(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'button'
+       }, settings)).renderTo(document.getElementById('view'));
+}
+
+test("button text, size default", function() {
+       var button = createButton({text: 'X'});
+
+       nearlyEqualRects(rect(button), [0, 0, 34, 30], 4);
+});
+
+test("button text, size large", function() {
+       var button = createButton({text: 'X', size: 'large'});
+
+       nearlyEqualRects(rect(button), [0, 0, 41, 39], 4);
+});
+
+test("button text, size small", function() {
+       var button = createButton({text: 'X', size: 'small'});
+
+       nearlyEqualRects(rect(button), [0, 0, 19, 23], 4);
+});
+
+test("button text, width 100, height 100", function() {
+       var button = createButton({text: 'X', width: 100, height: 100});
+
+       deepEqual(rect(button), [0, 0, 100, 100]);
+       deepEqual(rect(button.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("button icon, size default", function() {
+       var button = createButton({icon: 'test'});
+
+       nearlyEqualRects(rect(button), [0, 0, 40, 30], 4);
+});
+
+test("button icon, size small", function() {
+       var button = createButton({icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(button), [0, 0, 28, 24], 4);
+});
+
+test("button icon, size large", function() {
+       var button = createButton({icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(button), [0, 0, 44, 40], 4);
+});
+
+test("button icon, width 100, height 100", function() {
+       var button = createButton({icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(button), [0, 0, 100, 100]);
+       deepEqual(rect(button.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("button text & icon, size default", function() {
+       var button = createButton({text: 'X', icon: 'test'});
+
+       nearlyEqualRects(rect(button), [0, 0, 52, 30], 4);
+});
+
+test("button text & icon, size large", function() {
+       var button = createButton({text: 'X', icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(button), [0, 0, 59, 40], 4);
+});
+
+test("button text & icon, size small", function() {
+       var button = createButton({text: 'X', icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(button), [0, 0, 38, 24], 4);
+});
+
+test("button text & icon, width 100, height 100", function() {
+       var button = createButton({text: 'X', icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(button), [0, 0, 100, 100]);
+       deepEqual(rect(button.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("button click event", function() {
+       var button, clicks = {};
+
+       button = createButton({text: 'X', onclick: function() {clicks.a = 'a';}});
+       button.on('click', function() {clicks.b = 'b';});
+       button.on('click', function() {clicks.c = 'c';});
+       button.fire('click');
+
+       deepEqual(clicks, {a: 'a', b: 'b', c: 'c'});
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Button Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Button.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiButtonGrouphtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/ButtonGroup.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/ButtonGroup.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/ButtonGroup.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.ButtonGroup Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.ButtonGroup", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.ButtonGroup Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/ButtonGroup.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiCheckboxhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Checkbox.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Checkbox.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Checkbox.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Checkbox Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Checkbox", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Checkbox Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Checkbox.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiCollectionhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Collection.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Collection.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Collection.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,273 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Collection Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+module("ui.Collection");
+
+window.onload = function() {
+       panel = tinymce.ui.Factory.create({
+               type: 'panel',
+               items: [
+                       {type: 'button', name: 'button1', text: 'button1', classes: 'class1', disabled: true},
+                       {type: 'button', name: 'button2', classes: 'class1 class2'},
+                       {type: 'button', name: 'button3', classes: 'class2 class1 class3'},
+
+                       {type: 'buttongroup', name: 'buttongroup1', items: [
+                               {type: 'button', name: 'button4'},
+                               {type: 'button', name: 'button5'},
+                               {type: 'button', name: 'button6'}
+                       ]},
+
+                       {type: 'buttongroup', name: 'buttongroup2', items: [
+                               {type: 'button', name: 'button7'},
+                               {type: 'button', name: 'button8'},
+                               {type: 'button', name: 'button9'}
+                       ]},
+
+                       {type: 'toolbar', name: 'toolbar1', items: [
+                               {type: 'buttongroup', name: 'buttongroup3', items: [
+                                       {type: 'button', name: 'button10', disabled: true},
+                                       {type: 'button', name: 'button11'},
+                                       {type: 'button', name: 'button12', classes: 'class4'}
+                               ]}
+                       ]}
+               ]
+       }).renderTo(document.getElementById('view'));
+
+       QUnit.start();
+};
+
+test("Constructor", function() {
+       equal(new tinymce.ui.Collection().length, 0);
+       equal(new tinymce.ui.Collection(panel.find('button').toArray()).length, 12);
+       equal(new tinymce.ui.Collection(panel.find('button')).length, 12);
+       equal(new tinymce.ui.Collection(panel.find('button:first')[0]).length, 1);
+       equal(new tinymce.ui.Collection(panel.find('button:first')[0])[0].type, 'button');
+});
+
+test("add", function() {
+       var collection = new tinymce.ui.Collection([panel, panel]);
+
+       equal(collection.add(panel).length, 3);
+       equal(collection.add([panel, panel]).length, 5);
+});
+
+test("set", function() {
+       var collection = new tinymce.ui.Collection([panel, panel]);
+
+       equal(collection.set(panel).length, 1);
+       equal(collection.set([panel, panel]).length, 2);
+});
+
+test("filter", function() {
+       equal(panel.find('button').filter('*:first').length, 4);
+       equal(panel.find('button').filter('buttongroup button').length, 9);
+       equal(panel.find('button').filter('*').length, 12);
+       equal(panel.find('button').filter('nomatch').length, 0);
+       equal(panel.find('button').filter(function(ctrl) {return ctrl.settings.name == "button7";}).length, 1);
+});
+
+test("slice", function() {
+       equal(panel.find('button').slice(1).length, 11);
+       equal(panel.find('button').slice(1)[0].name(), 'button2');
+
+       equal(panel.find('button').slice(0, 1).length, 1);
+       equal(panel.find('button').slice(0, 1)[0].name(), 'button1');
+
+       equal(panel.find('button').slice(-1).length, 1);
+       equal(panel.find('button').slice(-1)[0].name(), 'button12');
+
+       equal(panel.find('button').slice(-2).length, 2);
+       equal(panel.find('button').slice(-2)[0].name(), 'button11');
+
+       equal(panel.find('button').slice(-2, -1).length, 1);
+       equal(panel.find('button').slice(-2, -1)[0].name(), 'button11');
+
+       equal(panel.find('button').slice(1000).length, 0);
+       equal(panel.find('button').slice(-1000).length, 12);
+});
+
+test("eq", function() {
+       equal(panel.find('button').eq(1).length, 1);
+       equal(panel.find('button').eq(1)[0].name(), 'button2');
+
+       equal(panel.find('button').eq(-2).length, 1);
+       equal(panel.find('button').eq(-2)[0].name(), 'button11');
+
+       equal(panel.find('button').eq(1000).length, 0);
+});
+
+test("each", function() {
+       var count;
+
+       count = 0;
+       panel.find('button').each(function() {
+               count++;
+       });
+
+       equal(count, 12);
+
+       count = 0;
+       panel.find('nomatch').each(function() {
+               count++;
+       });
+
+       equal(count, 0);
+
+       count = 0;
+       panel.find('button').each(function(item, index) {
+               count += index;
+       });
+
+       equal(count, 66);
+
+       count = 0;
+       panel.find('button').each(function(item, index) {
+               if (item.type == 'button')
+                       count++;
+       });
+
+       equal(count, 12);
+
+       count = 0;
+       panel.find('button').each(function(item, index) {
+               count++;
+
+               if (index == 3)
+                       return false;
+       });
+
+       equal(count, 4);
+});
+
+test("toArray", function() {
+       equal(panel.find('button').toArray().length, 12);
+       equal(panel.find('button').toArray().concat, Array.prototype.concat);   
+});
+
+test("fire/on/off", function() {
+       var value;
+
+       value = 0;
+       panel.find('button').off();
+       panel.find('button#button1,button#button2').on('test', function(args) {
+               value += args.value;
+       });
+       panel.find('button#button1').fire('test', {value: 42});
+       equal(value, 42);
+
+       value = 0;
+       panel.find('button').off();
+       panel.find('button#button1,button#button2').on('test', function(args) {
+               value += args.value;
+       });
+       panel.find('button').fire('test', {value: 42});
+       equal(value, 84);
+
+       value = 0;
+       panel.find('button').off();
+       panel.find('button#button1,button#button2').on('test', function(args) {
+               value += args.value;
+       });
+       panel.find('button#button1').off('test');
+       panel.find('button').fire('test', {value: 42});
+       equal(value, 42);
+
+       panel.find('button').off();
+
+       value = 0;
+       panel.find('button').fire('test', {value: 42});
+       equal(value, 0);
+});
+
+test("show/hide", function() {
+       panel.find('button#button1,button#button2').hide();
+       equal(panel.find('button:not(:visible)').length, 2);
+
+       panel.find('button#button1').show();
+       equal(panel.find('button:not(:visible)').length, 1);
+
+       panel.find('button#button2').show();
+});
+
+test("text", function() {
+       equal(panel.find('button#button1,button#button2').text(), 'button1');
+       equal(panel.find('button#button2').text('button2').text(), 'button2');
+
+       equal(panel.find('button#button2,button#button3').text('test').text(), 'test');
+       equal(panel.find('button#button3').text(), 'test');
+});
+
+test("disabled", function() {
+       ok(panel.find('button#button1').disabled());
+       ok(!panel.find('button#button2').disabled());
+       ok(panel.find('button#button2').disabled(true).disabled());
+
+       panel.find('button#button2').disabled(false);
+});
+
+test("visible", function() {
+       ok(panel.find('button#button2').visible());
+       ok(!panel.find('button#button2').visible(false).visible());
+
+       panel.find('button#button2').visible(true);
+});
+
+test("active", function() {
+       ok(!panel.find('button#button2').active());
+       ok(panel.find('button#button2').active(true).active());
+
+       panel.find('button#button2').active(false);
+});
+
+test("name", function() {
+       equal(panel.find('button#button1').name(), 'button1');
+       equal(panel.find('button#button2').name('buttonX').name(), 'buttonX');
+
+       panel.find('button#buttonX').name('button2');
+});
+
+test("addClass/removeClass/hasClass", function() {
+       panel.find('button#button1').addClass('test');
+       ok(panel.find('button#button1').hasClass('test'));
+       ok(!panel.find('button#button1').hasClass('nomatch'));
+       panel.find('button#button1').removeClass('test');
+       ok(!panel.find('button#button1').hasClass('test'));
+});
+
+test("prop", function() {
+       ok(panel.find('button#button1').prop('disabled'));
+       equal(panel.find('button#button1').prop('name'), 'button1');
+       equal(panel.find('button#button1').prop('name', 'buttonX').prop('name'), 'buttonX');
+       panel.find('button#buttonX').prop('name', 'button1');
+       equal(panel.find('button#button1').prop('missingProperty'), undefined);
+});
+
+test("exec", function() {
+       ok(!panel.find('button#button1').exec('disabled', false).disabled());
+       panel.find('button#button1').disabled(true);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Collection Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Collection.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiColorButtonhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/ColorButton.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/ColorButton.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/ColorButton.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Button Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.ColorButton", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createColorButton(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'colorbutton'
+       }, settings)).renderTo(document.getElementById('view'));
+}
+
+test("colorbutton text, size default", function() {
+       var colorButton = createColorButton({text: 'X'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 42, 30], 4);
+});
+
+test("colorbutton text, size large", function() {
+       var colorButton = createColorButton({text: 'X', size: 'large'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 49, 39], 4);
+});
+
+test("colorbutton text, size small", function() {
+       var colorButton = createColorButton({text: 'X', size: 'small'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 34, 23], 4);
+});
+
+test("colorbutton text, width 100, height 100", function() {
+       var colorButton = createColorButton({text: 'X', width: 100, height: 100});
+
+       deepEqual(rect(colorButton), [0, 0, 100, 100]);
+       deepEqual(rect(colorButton.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("colorbutton icon, size default", function() {
+       var colorButton = createColorButton({icon: 'test'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 50, 30], 4);
+});
+
+test("colorbutton icon, size small", function() {
+       var colorButton = createColorButton({icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 43, 24], 4);
+});
+
+test("colorbutton icon, size large", function() {
+       var colorButton = createColorButton({icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 54, 40], 4);
+});
+
+test("colorbutton icon, width 100, height 100", function() {
+       var colorButton = createColorButton({icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(colorButton), [0, 0, 100, 100]);
+       deepEqual(rect(colorButton.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("colorbutton text & icon, size default", function() {
+       var colorButton = createColorButton({text: 'X', icon: 'test'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 62, 30], 4);
+});
+
+test("colorbutton text & icon, size large", function() {
+       var colorButton = createColorButton({text: 'X', icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 69, 40], 4);
+});
+
+test("colorbutton text & icon, size small", function() {
+       var colorButton = createColorButton({text: 'X', icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(colorButton), [0, 0, 53, 24], 4);
+});
+
+test("colorbutton text & icon, width 100, height 100", function() {
+       var colorButton = createColorButton({text: 'X', icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(colorButton), [0, 0, 100, 100]);
+       deepEqual(rect(colorButton.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("colorbutton click event", function() {
+       var colorButton, clicks = {};
+
+       colorButton = createColorButton({text: 'X', onclick: function() {clicks.a = 'a';}});
+       colorButton.renderTo(document.getElementById('view'));
+       colorButton.fire('click', {target: colorButton.getEl()});
+
+       deepEqual(clicks, {a: 'a'});
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Button Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/ColorButton.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiComboBoxhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/ComboBox.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/ComboBox.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/ComboBox.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.ComboBox Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.TextBox", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+/*
+test("combobox text, size default", function() {
+       var combobox = new tinymce.ui.ComboBox({text: 'abc'}).renderTo(document.getElementById('view'));
+
+       deepEqual(rect(combobox), [0, 0, 40, 22]);
+});
+*/
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.ComboBox Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/ComboBox.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiContainerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Container.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Container.html                               (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Container.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Container Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Container", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Container Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Container.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiControlhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Control.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Control.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Control.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,229 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Control Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+module("ui.Control");
+
+test("Initial states", function() {
+       var ctrl;
+
+       ctrl = new tinymce.ui.Control({});
+
+       // Check inital states
+       equal(ctrl.disabled(), false);
+       equal(ctrl.active(), false);
+       equal(ctrl.visible(), true);
+       equal(ctrl.text(), "");
+       equal(ctrl.width(), 0);
+       equal(ctrl.height(), 0);
+       equal(ctrl.name(), "");
+       equal(ctrl.title(), "");
+       equal(ctrl.parent(), undefined);
+       deepEqual(ctrl.settings, {});
+});
+
+test("Settings", function() {
+       var ctrl = new tinymce.ui.Control({
+               disabled: true,
+               active: true,
+               visible: true,
+               text: 'Text',
+               title: 'Title',
+               width: 100,
+               height: 200,
+               name: 'Name'
+       });
+
+       // Check settings states
+       equal(ctrl.disabled(), true);
+       equal(ctrl.active(), true);
+       equal(ctrl.visible(), true);
+       equal(ctrl.text(), "Text");
+       equal(ctrl.width(), 100);
+       equal(ctrl.height(), 200);
+       equal(ctrl.name(), "Name");
+       equal(ctrl.title(), "Title");
+       equal(ctrl.parent(), undefined);
+       deepEqual(ctrl.settings, {
+               disabled: true,
+               active: true,
+               visible: true,
+               text: 'Text',
+               title: 'Title',
+               width: 100,
+               height: 200,
+               name: 'Name'
+       });
+});
+
+/*
+test("Properties", function() {
+       var ctrl, cont;
+
+       cont = new tinymce.ui.Container({});
+       ctrl = new tinymce.ui.Control({});
+
+       // Set all states
+       ctrl = ctrl.
+               disabled(true).
+               active(true).
+               visible(true).
+               text("Text").
+               title("Title").
+               width(100).
+               height(200).
+               name("Name").parent(cont);
+
+       // Check states
+       equal(ctrl.disabled(), true);
+       equal(ctrl.active(), true);
+       equal(ctrl.visible(), true);
+       equal(ctrl.text(), "Text");
+       equal(ctrl.width(), 100);
+       equal(ctrl.height(), 200);
+       equal(ctrl.name(), "Name");
+       equal(ctrl.title(), "Title");
+       equal(ctrl.parent(), cont);
+       deepEqual(ctrl.settings, {});
+});
+
+test("Chained methods", function() {
+       var ctrl = new tinymce.ui.Control({});
+
+       // Set all states
+       ctrl = ctrl.
+               refresh().
+               bind('click', function() {}).
+               unbind().
+               renderTo(document.getElementById('viewport')).
+               fire("nothing").
+               remove();
+
+       // Check so that the chain worked
+       ok(ctrl instanceof tinymce.ui.Control);
+});
+
+test("Events", function() {
+       var ctrl = new tinymce.ui.Control({
+               handlers: {
+                       handler1: function() {
+                               count++;
+                       }
+               }
+       }), count;
+
+       ctrl.bind('MyEvent', function(target, args) {
+               ok(target === ctrl);
+               ok(ctrl === this);
+               deepEqual(args, {myKey: 'myVal'});
+       });
+
+       ctrl.fire('MyEvent', {myKey: 'myVal'});
+
+       function countAndBreak(target, args) {
+               count++;
+               return false;
+       }
+
+       // Bind two events
+       ctrl.bind('MyEvent2', countAndBreak);
+       ctrl.bind('MyEvent2', countAndBreak);
+
+       // Check if only one of them was called
+       count = 0;
+       ctrl.fire('MyEvent2', {myKey: 'myVal'});
+       equal(count, 1);
+
+       // Fire unbound event
+       ctrl.fire('MyEvent3', {myKey: 'myVal'});
+
+       // Unbind all
+       ctrl.unbind();
+       count = 0;
+       ctrl.fire('MyEvent2', {myKey: 'myVal'});
+       equal(count, 0, 'Unbind all');
+
+       // Unbind by name
+       ctrl.bind('MyEvent1', countAndBreak);
+       ctrl.bind('MyEvent2', countAndBreak);
+       ctrl.unbind('MyEvent2');
+       count = 0;
+       ctrl.fire('MyEvent1', {myKey: 'myVal'});
+       ctrl.fire('MyEvent2', {myKey: 'myVal'});
+       equal(count, 1);
+
+       // Unbind by name callback
+       ctrl.bind('MyEvent1', countAndBreak);
+       ctrl.bind('MyEvent1', function() {count++;});
+       ctrl.unbind('MyEvent1', countAndBreak);
+       count = 0;
+       ctrl.fire('MyEvent1', {myKey: 'myVal'});
+       equal(count, 1);
+
+       // Bind by named handler
+       ctrl.unbind();
+       ctrl.bind('MyEvent', 'handler1');
+       count = 0;
+       ctrl.fire('MyEvent', {myKey: 'myVal'});
+       equal(count, 1);
+});
+
+test("hasClass,addClass,removeClass", function() {
+       var ctrl = new tinymce.ui.Control({classes: 'class1 class2 class3'});
+
+       equal(ctrl.classes(), 'class1 class2 class3');
+       ok(ctrl.hasClass('class1'));
+       ok(ctrl.hasClass('class2'));
+       ok(ctrl.hasClass('class3'));
+       ok(!ctrl.hasClass('class4'));
+
+       ctrl.addClass('class4');
+       equal(ctrl.classes(), 'class1 class2 class3 class4');
+       ok(ctrl.hasClass('class1'));
+       ok(ctrl.hasClass('class2'));
+       ok(ctrl.hasClass('class3'));
+       ok(ctrl.hasClass('class4'));
+
+       ctrl.removeClass('class4');
+       equal(ctrl.classes(), 'class1 class2 class3');
+       ok(ctrl.hasClass('class1'));
+       ok(ctrl.hasClass('class2'));
+       ok(ctrl.hasClass('class3'));
+       ok(!ctrl.hasClass('class4'));
+
+       ctrl.removeClass('class3').removeClass('class2');
+       equal(ctrl.classes(), 'class1');
+       ok(ctrl.hasClass('class1'));
+       ok(!ctrl.hasClass('class2'));
+       ok(!ctrl.hasClass('class3'));
+
+       ctrl.removeClass('class3').removeClass('class1');
+       equal(ctrl.classes(), '');
+       ok(!ctrl.hasClass('class1'));
+       ok(!ctrl.hasClass('class2'));
+       ok(!ctrl.hasClass('class3'));
+});
+*/
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Control Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Control.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiDragHelperhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/DragHelper.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/DragHelper.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/DragHelper.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.DragHelper Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.DragHelper", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.DragHelper Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/DragHelper.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiElementPathhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/ElementPath.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/ElementPath.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/ElementPath.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.ElementPath Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.ElementPath", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.ElementPath Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/ElementPath.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFactoryhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Factory.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Factory.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Factory.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Factory Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Factory", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Factory Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Factory.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFieldSethtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FieldSet.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FieldSet.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FieldSet.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FieldSet Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FieldSet", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FieldSet Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FieldSet.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFilePickerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FilePicker.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FilePicker.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FilePicker.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FilePicker Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FilePicker", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FilePicker Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FilePicker.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFitLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FitLayout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FitLayout.html                               (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FitLayout.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,87 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FitLayout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FitLayout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createFitPanel(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'panel',
+               layout: 'fit',
+               width: 200,
+               height: 200,
+               border: 1
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+}
+
+test("fit with spacer inside", function() {
+       panel = createFitPanel({
+               items: [
+                       {type: 'spacer', classes: 'red'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 200, 200]);
+       deepEqual(rect(panel.find('spacer')[0]), [1, 1, 198, 198]);
+});
+
+test("fit with padding and spacer inside", function() {
+       panel = createFitPanel({
+               padding: 3,
+               items: [
+                       {type: 'spacer', classes: 'red'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 200, 200]);
+       deepEqual(rect(panel.find('spacer')[0]), [4, 4, 192, 192]);
+});
+
+test("fit with panel inside", function() {
+       panel = createFitPanel({
+               items: [
+                       {type: 'panel', border: 1}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 200, 200]);
+       deepEqual(rect(panel.find('panel')[0]), [1, 1, 198, 198]);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FitLayout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FitLayout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFlexLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FlexLayout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FlexLayout.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FlexLayout.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,915 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FlexLayout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FlexLayout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function renderPanel(settings) {
+       var panel = tinymce.ui.Factory.create(tinymce.extend({
+               type: "panel",
+               layout: "flex",
+               width: 200, height: 200,
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'spacer', classes: 'green'},
+                       {type: 'spacer', classes: 'blue'}
+               ]
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+
+       resetScroll(panel.getEl('body'));
+
+       return panel;
+}
+
+test("pack: default, align: default, flex: default", function() {
+       panel = renderPanel({});
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 0, 20, 20]);
+});
+
+test("pack: default, align: default, flex: default, borders", function() {
+       panel = renderPanel({defaults: {border: 1}});
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 22, 22]);
+       deepEqual(rect(panel.find('spacer')[1]), [22, 0, 22, 22]);
+       deepEqual(rect(panel.find('spacer')[2]), [44, 0, 22, 22]);
+});
+
+test("pack: default, flex: 1", function() {
+       panel = renderPanel({
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [67, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [133, 0, 67, 20]);
+});
+
+test("pack: default, flex: 1, minWidth: various", function() {
+       panel = renderPanel({
+               defaults: {flex: 1},
+               items: [
+                       {type: 'spacer', minWidth: 25, classes: 'red'},
+                       {type: 'spacer', minWidth: 30, classes: 'green'},
+                       {type: 'spacer', minWidth: 35, classes: 'blue'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 62, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [62, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [128, 0, 72, 20]);
+});
+
+test("pack: start, flex: default", function() {
+       panel = renderPanel({
+               pack: "start"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 0, 20, 20]);
+});
+
+test("pack: start, flex: 1", function() {
+       panel = renderPanel({
+               pack: "start",
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [67, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [133, 0, 67, 20]);
+});
+
+test("pack: end, flex: default", function() {
+       panel = renderPanel({
+               pack: "end"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [140, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [160, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [180, 0, 20, 20]);
+});
+
+test("pack: end, flex: 1", function() {
+       panel = renderPanel({
+               pack: "end",
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [67, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [133, 0, 67, 20]);
+});
+
+test("pack: center, flex: default", function() {
+       panel = renderPanel({
+               pack: "center"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [70, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [90, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [110, 0, 20, 20]);
+});
+
+test("pack: center, flex: 1", function() {
+       panel = renderPanel({
+               pack: "center",
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [67, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [133, 0, 67, 20]);
+});
+
+test("pack: start, spacing: 3", function() {
+       panel = renderPanel({
+               layout: "flex",
+               pack: "start",
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [23, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [46, 0, 20, 20]);
+});
+
+test("pack: end, spacing: 3", function() {
+       panel = renderPanel({
+               pack: "end",
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [134, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [157, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [180, 0, 20, 20]);
+});
+
+test("pack: center, spacing: 3", function() {
+       panel = renderPanel({
+               pack: "center",
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [67, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [90, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [113, 0, 20, 20]);
+});
+
+test("pack: start, padding: 3", function() {
+       panel = renderPanel({
+               pack: "start",
+               padding: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [23, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [43, 3, 20, 20]);
+});
+
+test("pack: start, spacing: 3, padding: 3", function() {
+       panel = renderPanel({
+               pack: "start",
+               padding: 3,
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [26, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [49, 3, 20, 20]);
+});
+
+test("pack: start, align: start", function() {
+       panel = renderPanel({
+               pack: "start",
+               align: "start"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 0, 20, 20]);
+});
+
+test("pack start, align: center", function() {
+       panel = renderPanel({
+               pack: "start",
+               align: "center"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 90, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 90, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 90, 20, 20]);
+});
+
+test("pack: start, align: end", function() {
+       panel = renderPanel({
+               pack: "start",
+               align: "end"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 180, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 180, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 180, 20, 20]);
+});
+
+test("pack: start, align: stretch", function() {
+       panel = renderPanel({
+               pack: "start",
+               align: "stretch"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 200]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 0, 20, 200]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 0, 20, 200]);
+});
+
+test("pack: start, padding: 3, align: stretch", function() {
+       panel = renderPanel({
+               pack: "start",
+               align: "stretch",
+               padding: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 194]);
+       deepEqual(rect(panel.find('spacer')[1]), [23, 3, 20, 194]);
+       deepEqual(rect(panel.find('spacer')[2]), [43, 3, 20, 194]);
+});
+
+test("pack: start, flex: mixed values", function() {
+       panel = renderPanel({
+               pack: "start",
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 0.3},
+                       {type: 'spacer', classes: 'green', flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 0.5}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 43, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [43, 0, 98, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [141, 0, 59, 20]);
+});
+
+test("pack: justify", function() {
+       panel = renderPanel({
+               pack: "justify"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [90, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [180, 0, 20, 20]);
+});
+
+test("pack: justify, padding: 3", function() {
+       panel = renderPanel({
+               pack: "justify",
+               padding: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [90, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [177, 3, 20, 20]);
+});
+
+test("pack: justify, minWidth: mixed values, padding: 3", function() {
+       panel = renderPanel({
+               pack: "justify",
+               padding: 3,
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'spacer', classes: 'green', minWidth: 80},
+                       {type: 'spacer', classes: 'blue', minWidth: 50}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [45, 3,  80, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [147, 3, 50, 20]);
+});
+
+test("pack: start, flex: 1, maxWidth: 80 on second", function() {
+       panel = renderPanel({
+               pack: "start",
+               width: 400,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1},
+                       {type: 'spacer', classes: 'green', maxWidth: 80, flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 1}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 160, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [160, 0, 80, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [240, 0, 160, 20]);
+});
+
+test("pack: start, flex: 1, minWidth: 150 on second", function() {
+       panel = renderPanel({
+               pack: "start",
+               width: 400,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1},
+                       {type: 'spacer', classes: 'green', minWidth: 150, flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 1}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 90, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [90, 0, 220, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [310, 0, 90, 20]);
+});
+
+test("pack: start, flex: default, hide item and reflow", function() {
+       panel = renderPanel({
+               pack: "start",
+               autoResize: true,
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'spacer', classes: 'green'},
+                       {type: 'spacer', classes: 'blue'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [40, 0, 20, 20]);
+
+       deepEqual(rect(panel), [0, 0, 60, 20]);
+       panel.items().eq(0).hide();
+       panel.reflow();
+
+       deepEqual(rect(panel), [0, 0, 40, 20]);
+});
+
+test("pack: start, flex: 1, reflow after resize outer width", function() {
+       panel = renderPanel({
+               pack: "start",
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1},
+                       {type: 'spacer', classes: 'green', flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 1}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [67, 0, 67, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [133, 0, 67, 20]);
+
+       panel.layoutRect({w: 400, h: 400}).reflow();
+
+       deepEqual(rect(panel), [0, 0, 400, 400]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 133, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [133, 0, 133, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [267, 0, 133, 20]);
+});
+
+test("pack: start, maxWidth/maxHeight: 100, item minWidth/maxHeight: 200 (overflow W+H)", function() {
+       panel = renderPanel({
+               pack: "start",
+               autoResize: true,
+               autoScroll: true,
+               maxWidth: 100,
+               maxHeight: 100,
+               items: [
+                       {type: 'spacer', minWidth: 200, minHeight: 200, classes: 'red dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 200, 200]);
+       equal(panel.layoutRect().contentW, 200);
+       equal(panel.layoutRect().contentH, 200);
+});
+
+test("pack: start, direction: column, maxWidth/maxHeight: 100, padding: 20, spacing: 10, item minWidth/maxHeight: 200 (overflow W+H)", function() {
+       panel = renderPanel({
+               pack: "start",
+               direction: "column",
+               autoResize: true,
+               autoScroll: true,
+               maxWidth: 100,
+               maxHeight: 100,
+               padding: 20,
+               spacing: 10,
+               items: [
+                       {type: 'spacer', minWidth: 100, minHeight: 100, classes: 'red dotted'},
+                       {type: 'spacer', minWidth: 100, minHeight: 100, classes: 'green dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[0]), [20, 20, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 130, 100, 100]);
+       equal(panel.layoutRect().contentW, 20 + 100 + 20);
+       equal(panel.layoutRect().contentH, 20 + 100 + 10 + 100 + 20);
+});
+
+test("pack: start, maxWidth/maxHeight: 100, item minWidth/maxHeight: 200 (overflow W)", function() {
+       panel = renderPanel({
+               pack: "start",
+               autoResize: true,
+               autoScroll: true,
+               maxWidth: 100,
+               items: [
+                       {type: 'spacer', minWidth: 200, minHeight: 200, classes: 'red dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 200, 200]);
+       equal(panel.layoutRect().contentW, 200);
+       equal(panel.layoutRect().contentH, 200);
+});
+
+test("pack: start, maxWidth/maxHeight: 100, item minWidth/maxHeight: 200 (overflow H)", function() {
+       panel = renderPanel({
+               pack: "start",
+               autoResize: true,
+               autoScroll: true,
+               maxHeight: 100,
+               items: [
+                       {type: 'spacer', minWidth: 200, minHeight: 200, classes: 'red dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 200, 200]);
+       equal(panel.layoutRect().contentW, 200);
+       equal(panel.layoutRect().contentH, 200);
+});
+
+test("pack: start, minWidth: 200, item minWidth: 100 (underflow)", function() {
+       panel = renderPanel({
+               pack: "start",
+               autoResize: true,
+               minWidth: 200,
+               items: [
+                       {type: 'spacer', minWidth: 100, classes: 'red'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 200, 20]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 100, 20]);
+});
+
+test("pack: start, flex: 1, border: 1, reflow after resize inner width", function() {
+       panel = renderPanel({
+               pack: "start",
+               border: 1,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1}
+               ]
+       });
+
+       panel.layoutRect({innerW: 400, innerH: 400}).reflow();
+
+       deepEqual(rect(panel), [0, 0, 402, 402]);
+       deepEqual(rect(panel.find('spacer')[0]), [1, 1, 400, 20]);
+});
+
+test("row flexbox in row flexbox", function() {
+       panel = tinymce.ui.Factory.create({
+               type: 'panel',
+               layout: 'flex',
+               align: 'end',
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'panel', layout: 'flex', padding: 10, spacing: 10, items: [
+                               {type: 'spacer', classes: 'yellow'},
+                               {type: 'spacer', classes: 'magenta'}
+                       ]},
+                       {type: 'spacer', classes: 'green'}
+               ]
+       }).renderTo(document.getElementById('view')).reflow();
+
+       deepEqual(rect(panel), [0, 0, 110, 40]);
+       deepEqual(rect(panel.find("panel")[0]), [20, 0, 70, 40]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [30, 10, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [60, 10, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [90, 20, 20, 20]);
+});
+
+test("row flexbox in row flexbox hide inner item and reflow", function() {
+       panel = tinymce.ui.Factory.create({
+               type: 'panel',
+               layout: 'flex',
+               align: 'end',
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'panel', layout: 'flex', padding: 10, spacing: 10, items: [
+                               {type: 'spacer', classes: 'yellow'},
+                               {type: 'spacer', classes: 'magenta'}
+                       ]},
+                       {type: 'spacer', classes: 'green'}
+               ]
+       }).renderTo(document.getElementById('view')).reflow();
+
+       panel.find('spacer')[1].hide().parent().reflow();
+
+       deepEqual(rect(panel), [0, 0, 80, 40]);
+       deepEqual(rect(panel.find("panel")[0]), [20, 0, 40, 40]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [30, 10, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [60, 20, 20, 20]);
+});
+
+// Direction column tests
+
+function renderColumnPanel(settings) {
+       settings.direction = "column";
+       return renderPanel(settings);
+}
+
+test("direction: column, pack: default, align: default, flex: default", function() {
+       panel = renderColumnPanel({});
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 40, 20, 20]);
+});
+
+test("direction: column, pack: default, flex: 1", function() {
+       panel = renderColumnPanel({
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 67, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 133, 20, 67]);
+});
+
+test("direction: column, pack: default, flex: 1, minWidth: various", function() {
+       panel = renderColumnPanel({
+               defaults: {flex: 1},
+               items: [
+                       {type: 'spacer', minHeight: 25, classes: 'red'},
+                       {type: 'spacer', minHeight: 30, classes: 'green'},
+                       {type: 'spacer', minHeight: 35, classes: 'blue'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 62]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 62, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 128, 20, 72]);
+});
+
+test("direction: column, pack: start, flex: default", function() {
+       panel = renderColumnPanel({
+               pack: "start"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 40, 20, 20]);
+});
+
+test("direction: column, pack: start, flex: 1", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 67, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 133, 20, 67]);
+});
+
+test("direction: column, pack: end, flex: default", function() {
+       panel = renderColumnPanel({
+               pack: "end"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 140, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 160, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 180, 20, 20]);
+});
+
+test("direction: column, pack: end, flex: 1", function() {
+       panel = renderColumnPanel({
+               pack: "end",
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 67, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 133, 20, 67]);
+});
+
+test("direction: column, pack: center, flex: default", function() {
+       panel = renderColumnPanel({
+               pack: "center"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 70, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 90, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 110, 20, 20]);
+});
+
+test("direction: column, pack: center, flex: 1", function() {
+       panel = renderColumnPanel({
+               pack: "center",
+               defaults: {flex: 1}
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 67, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 133, 20, 67]);
+});
+
+test("direction: column, pack: start, spacing: 3", function() {
+       panel = renderColumnPanel({
+               layout: "flex",
+               pack: "start",
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 23, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 46, 20, 20]);
+});
+
+test("direction: column, pack: end, spacing: 3", function() {
+       panel = renderColumnPanel({
+               pack: "end",
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 134, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 157, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 180, 20, 20]);
+});
+
+test("direction: column, pack: center, spacing: 3", function() {
+       panel = renderColumnPanel({
+               pack: "center",
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 67, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 90, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 113, 20, 20]);
+});
+
+test("direction: column, pack: start, padding: 3", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               padding: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [3, 23, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 43, 20, 20]);
+});
+
+test("direction: column, pack: start, spacing: 3, padding: 3", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               padding: 3,
+               spacing: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [3, 26, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 49, 20, 20]);
+});
+
+test("direction: column, pack: start, align: start", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               align: "start"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 40, 20, 20]);
+});
+
+test("direction: column, pack start, align: center", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               align: "center"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [90, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [90, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [90, 40, 20, 20]);
+});
+
+test("direction: column, pack: start, align: end", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               align: "end"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [180, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [180, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [180, 40, 20, 20]);
+});
+
+test("direction: column, pack: start, align: stretch", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               align: "stretch"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 200, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 20, 200, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 40, 200, 20]);
+});
+
+test("direction: column, pack: start, padding: 3, align: stretch", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               align: "stretch",
+               padding: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 194, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [3, 23, 194, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 43, 194, 20]);
+});
+
+test("direction: column, pack: start, flex: mixed values", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 0.3},
+                       {type: 'spacer', classes: 'green', flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 0.5}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 43]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 43, 20, 98]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 141, 20, 59]);
+});
+
+test("direction: column, pack: justify", function() {
+       panel = renderColumnPanel({
+               pack: "justify"
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 90, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 180, 20, 20]);
+});
+
+test("direction: column, pack: justify, padding: 3", function() {
+       panel = renderColumnPanel({
+               pack: "justify",
+               padding: 3
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [3, 90, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 177, 20, 20]);
+});
+
+test("direction: column, pack: justify, minHeight: mixed values, padding: 3", function() {
+       panel = renderColumnPanel({
+               pack: "justify",
+               padding: 3,
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'spacer', classes: 'green', minHeight: 80},
+                       {type: 'spacer', classes: 'blue', minHeight: 50}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [3, 45, 20, 80]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 147, 20, 50]);
+});
+
+test("direction: column, pack: start, flex: 1, maxHeight: 80 on second", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               height: 400,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1},
+                       {type: 'spacer', classes: 'green', maxHeight: 80, flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 1}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 160]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 160, 20, 80]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 240, 20, 160]);
+});
+
+test("direction: column, pack: start, flex: 1, minHeight: 150 on second", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               height: 400,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1},
+                       {type: 'spacer', classes: 'green', minHeight: 150, flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 1}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 90]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 90, 20, 220]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 310, 20, 90]);
+});
+
+test("direction: column, pack: start, flex: 1, reflow after resize outer height", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1},
+                       {type: 'spacer', classes: 'green', flex: 1},
+                       {type: 'spacer', classes: 'blue', flex: 1}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 67, 20, 67]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 133, 20, 67]);
+
+       panel.layoutRect({w: 400, h: 400}).reflow();
+
+       deepEqual(rect(panel), [0, 0, 400, 400]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 133]);
+       deepEqual(rect(panel.find('spacer')[1]), [0, 133, 20, 133]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 267, 20, 133]);
+});
+
+test("direction: column, pack: start, flex: 1, border: 1, reflow after resize inner width", function() {
+       panel = renderColumnPanel({
+               pack: "start",
+               border: 1,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1}
+               ]
+       });
+
+       panel.layoutRect({innerW: 400, innerH: 400}).reflow();
+
+       deepEqual(rect(panel), [0, 0, 402, 402]);
+       deepEqual(rect(panel.find('spacer')[0]), [1, 1, 20, 400]);
+});
+
+test("direction: column, row flexbox in row flexbox and resize parent", function() {
+       panel = tinymce.ui.Factory.create({
+               type: 'panel',
+               layout: 'flex',
+               align: 'end',
+               items: [
+                       {type: 'spacer', classes: 'red'},
+                       {type: 'panel', layout: 'flex', padding: 10, spacing: 10, items: [
+                               {type: 'spacer', classes: 'yellow'},
+                               {type: 'spacer', classes: 'magenta'}
+                       ]},
+                       {type: 'spacer', classes: 'green'}
+               ]
+       }).renderTo(document.getElementById('view')).reflow();
+
+       deepEqual(rect(panel), [0, 0, 110, 40]);
+       deepEqual(rect(panel.find("panel")[0]), [20, 0, 70, 40]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 20, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [30, 10, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [60, 10, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [90, 20, 20, 20]);
+});
+
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FlexLayout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FlexLayout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFloatPanelhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FloatPanel.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FloatPanel.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FloatPanel.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FloatPanel Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FloatPanel", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FloatPanel Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FloatPanel.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFlowLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FlowLayout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FlowLayout.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FlowLayout.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FlowLayout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FlowLayout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FlowLayout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FlowLayout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFormhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Form.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Form.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Form.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Form Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Form", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Form Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Form.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiFormItemhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/FormItem.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/FormItem.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/FormItem.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.FormItem Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.FormItem", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.FormItem Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/FormItem.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiGridLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/GridLayout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/GridLayout.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/GridLayout.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,244 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.GridLayout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.GridLayout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function renderGridPanel(settings) {
+       var panel = tinymce.ui.Factory.create(tinymce.extend({
+               type: "panel",
+               layout: "grid",
+               defaults: {type: 'spacer'}
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+
+       resetScroll(panel.getEl('body'));
+
+       return panel;
+}
+
+test("automatic grid size 2x2", function() {
+       panel = renderGridPanel({
+               items: [
+                       {classes: 'red'}, {classes: 'green'},
+                       {classes: 'blue'}, {classes: 'cyan'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 40, 40]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [20, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 20,  20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [20, 20, 20, 20]);
+});
+
+/*
+test("fixed pixel size, automatic grid size 2x2", function() {
+       panel = renderGridPanel({
+               width: 100, height: 100,
+               align: "center",
+               items: [
+                       {classes: 'red'}, {classes: 'green'},
+                       {classes: 'blue'}, {classes: 'cyan'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 200, 200]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 17, 22]);
+       deepEqual(rect(panel.find('spacer')[1]), [17, 0, 17, 22]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 22, 16, 22]);
+       deepEqual(rect(panel.find('spacer')[3]), [17, 22, 17, 22]);
+});
+*/
+
+test("spacing: 3, automatic grid size 2x2", function() {
+       panel = renderGridPanel({
+               spacing: 3,
+               items: [
+                       {classes: 'red'}, {classes: 'green'},
+                       {classes: 'blue'}, {classes: 'cyan'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 43, 43]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [23, 0, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 23, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [23, 23, 20, 20]);
+});
+
+test("padding: 3, automatic grid size 2x2", function() {
+       panel = renderGridPanel({
+               padding: 3,
+               items: [
+                       {classes: 'red'}, {classes: 'green'},
+                       {classes: 'blue'}, {classes: 'cyan'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 46, 46]);
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [23, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 23, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [23, 23, 20, 20]);
+});
+
+test("spacing: 3, padding: 3, automatic grid size 2x2", function() {
+       panel = renderGridPanel({
+               padding: 3,
+               spacing: 3,
+               items: [
+                       {classes: 'red'}, {classes: 'green'},
+                       {classes: 'blue'}, {classes: 'cyan'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 49, 49]);
+       deepEqual(rect(panel.find('spacer')[0]), [3, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[1]), [26, 3, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[2]), [3, 26, 20, 20]);
+       deepEqual(rect(panel.find('spacer')[3]), [26, 26, 20, 20]);
+});
+
+test("inner elements 100x100 maxWidth/maxHeight: 118 (overflow W+H)", function() {
+       panel = renderGridPanel({
+               autoResize: true,
+               autoScroll: true,
+               maxWidth: 118,
+               maxHeight: 118,
+               defaults: {
+                       type: 'spacer',
+                       minWidth: 100,
+                       minHeight: 100
+               },
+               items: [
+                       {classes: 'red dotted'}, {classes: 'green dotted'},
+                       {classes: 'blue dotted'}, {classes: 'cyan dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 118, 118]);
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[1]), [100, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 100, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[3]), [100, 100, 100, 100]);
+       equal(panel.layoutRect().w, 118);
+       equal(panel.layoutRect().h, 118);
+       equal(panel.layoutRect().contentW, 200);
+       equal(panel.layoutRect().contentH, 200);
+});
+
+test("inner elements: 100x100, padding: 20, spacing: 10, maxWidth/maxHeight: 118 (overflow W+H)", function() {
+       panel = renderGridPanel({
+               autoResize: true,
+               autoScroll: true,
+               maxWidth: 118,
+               maxHeight: 118,
+               padding: 20,
+               spacing: 10,
+               defaults: {
+                       type: 'spacer',
+                       minWidth: 100,
+                       minHeight: 100
+               },
+               items: [
+                       {classes: 'red dotted'}, {classes: 'green dotted'},
+                       {classes: 'blue dotted'}, {classes: 'cyan dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel), [0, 0, 118, 118]);
+       deepEqual(rect(panel.find('spacer')[0]), [20, 20, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[1]), [130, 20, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[2]), [20, 130, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[3]), [130, 130, 100, 100]);
+       equal(panel.layoutRect().w, 118);
+       equal(panel.layoutRect().h, 118);
+       equal(panel.layoutRect().contentW, 20 + 200 + 10 + 20);
+       equal(panel.layoutRect().contentH, 20 + 200 + 10 + 20);
+});
+
+test("inner elements 100x100 maxWidth: 118 (overflow W)", function() {
+       panel = renderGridPanel({
+               autoResize: true,
+               autoScroll: true,
+               maxWidth: 100,
+               defaults: {
+                       type: 'spacer',
+                       minWidth: 100,
+                       minHeight: 100
+               },
+               items: [
+                       {classes: 'red dotted'}, {classes: 'green dotted'},
+                       {classes: 'blue dotted'}, {classes: 'cyan dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[1]), [100, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 100, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[3]), [100, 100, 100, 100]);
+       equal(panel.layoutRect().contentW, 200);
+       equal(panel.layoutRect().contentH, 200);
+});
+
+test("inner elements 100x100 maxHeight: 118 (overflow H)", function() {
+       panel = renderGridPanel({
+               autoResize: true,
+               autoScroll: true,
+               maxHeight: 100,
+               defaults: {
+                       type: 'spacer',
+                       minWidth: 100,
+                       minHeight: 100
+               },
+               items: [
+                       {classes: 'red dotted'}, {classes: 'green dotted'},
+                       {classes: 'blue dotted'}, {classes: 'cyan dotted'}
+               ]
+       });
+
+       deepEqual(rect(panel.find('spacer')[0]), [0, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[1]), [100, 0, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[2]), [0, 100, 100, 100]);
+       deepEqual(rect(panel.find('spacer')[3]), [100, 100, 100, 100]);
+       equal(panel.layoutRect().contentW, 200);
+       equal(panel.layoutRect().contentH, 200);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.GridLayout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/GridLayout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiIframehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Iframe.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Iframe.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Iframe.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Iframe Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Iframe", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Iframe Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Iframe.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiKeyboardNavigationhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.KeyboardNavigation Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.KeyboardNavigation", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.KeyboardNavigation Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiLabelhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Label.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Label.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Label.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Label Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Label", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Label Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Label.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Layout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Layout.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Layout.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Layout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Layout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Layout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Layout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiListBoxhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/ListBox.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/ListBox.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/ListBox.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.ListBox Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.ListBox", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.ListBox Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/ListBox.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiMenuhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Menu.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Menu.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Menu.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Menu Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Menu", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Menu Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Menu.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiMenuBarhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/MenuBar.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/MenuBar.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/MenuBar.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.MenuBar Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.MenuBar", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.MenuBar Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/MenuBar.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiMenuButtonhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/MenuButton.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/MenuButton.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/MenuButton.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,139 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.MenuButton Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.MenuButton", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createMenuButton(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'menubutton',
+               menu: [
+                       {text: '1'},
+                       {text: '2'},
+                       {text: '3'}
+               ]
+       }, settings)).renderTo(document.getElementById('view'));
+}
+
+test("menubutton text, size default", function() {
+       var menuButton = createMenuButton({text: 'X'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 46, 30], 4);
+});
+
+test("menubutton text, size large", function() {
+       var menuButton = createMenuButton({text: 'X', size: 'large'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 53, 39], 4);
+});
+
+test("menubutton text, size small", function() {
+       var menuButton = createMenuButton({text: 'X', size: 'small'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 30, 23], 4);
+});
+
+test("menubutton text, width 100, height 100", function() {
+       var menuButton = createMenuButton({text: 'X', width: 100, height: 100});
+
+       deepEqual(rect(menuButton), [0, 0, 100, 100]);
+       deepEqual(rect(menuButton.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("menubutton icon, size default", function() {
+       var menuButton = createMenuButton({icon: 'test'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 52, 30], 4);
+});
+
+test("menubutton icon, size small", function() {
+       var menuButton = createMenuButton({icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 39, 24], 4);
+});
+
+test("menubutton icon, size large", function() {
+       var menuButton = createMenuButton({icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 56, 40], 4);
+});
+
+test("menubutton icon, width 100, height 100", function() {
+       var menuButton = createMenuButton({icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(menuButton), [0, 0, 100, 100]);
+       deepEqual(rect(menuButton.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("menubutton text & icon, size default", function() {
+       var menuButton = createMenuButton({text: 'X', icon: 'test'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 64, 30], 4);
+});
+
+test("menubutton text & icon, size large", function() {
+       var menuButton = createMenuButton({text: 'X', icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 71, 40], 4);
+});
+
+test("menubutton text & icon, size small", function() {
+       var menuButton = createMenuButton({text: 'X', icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(menuButton), [0, 0, 49, 24], 4);
+});
+
+test("menubutton text & icon, width 100, height 100", function() {
+       var menuButton = createMenuButton({text: 'X', icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(menuButton), [0, 0, 100, 100]);
+       deepEqual(rect(menuButton.getEl().firstChild), [1, 1, 98, 98]);
+});
+
+test("menubutton click event", function() {
+       var menuButton, clicks = {};
+
+       menuButton = createMenuButton({text: 'X', onclick: function() {clicks.a = 'a';}});
+       menuButton.on('click', function() {clicks.b = 'b';});
+       menuButton;
+       menuButton.on('click', function() {clicks.c = 'c';});
+       menuButton.fire('click');
+
+       deepEqual(clicks, {a: 'a', b: 'b', c: 'c'});
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">MenuButton Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/MenuButton.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiMenuItemhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/MenuItem.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/MenuItem.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/MenuItem.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.MenuItem Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.MenuItem", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.MenuItem Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/MenuItem.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiMessageBoxhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/MessageBox.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/MessageBox.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/MessageBox.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.MessageBox Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.MessageBox", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.MessageBox Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/MessageBox.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiMovablehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Movable.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Movable.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Movable.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Movable Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Movable", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Movable Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Movable.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiPanelhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Panel.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Panel.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Panel.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Panel</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Panel", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createPanel(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'panel'
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+}
+
+test("panel width: 100, height: 100", function() {
+       panel = createPanel({
+               width: 100,
+               height: 100
+       });
+
+       nearlyEqualRects(rect(panel), [0, 0, 100, 100], 4);
+});
+
+test("panel border: 1, width: 100, height: 100", function() {
+       panel = createPanel({
+               width: 100,
+               height: 100,
+               border: 1
+       });
+
+       nearlyEqualRects(rect(panel), [0, 0, 100, 100], 4);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Panel Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Panel.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiPanelButtonhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/PanelButton.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/PanelButton.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/PanelButton.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.PanelButton Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.PanelButton", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.PanelButton Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/PanelButton.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiPathhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Path.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Path.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Path.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Path Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Path", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Path Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Path.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiRadiohtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Radio.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Radio.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Radio.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Radio Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Radio", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Radio Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Radio.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiResizablehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Resizable.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Resizable.html                               (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Resizable.html  2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Resizable Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Resizable", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Resizable Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Resizable.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiResizeHandlehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/ResizeHandle.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/ResizeHandle.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/ResizeHandle.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.ResizeHandle Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.ResizeHandle", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.ResizeHandle Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/ResizeHandle.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiScrollablehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Scrollable.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Scrollable.html                              (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Scrollable.html 2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Scrollable Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Scrollable", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Scrollable Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Scrollable.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiSelectorhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Selector.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Selector.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Selector.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,148 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Selector Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+module("ui.Selector");
+
+window.onload = function() {
+       panel = tinymce.ui.Factory.create({
+               type: 'panel',
+               items: [
+                       {type: 'button', name: 'button1', text: 'button1', classes: 'class1', disabled: true},
+                       {type: 'button', name: 'button2', classes: 'class1 class2'},
+                       {type: 'button', name: 'button3', classes: 'class2 class1 class3'},
+
+                       {type: 'buttongroup', name: 'buttongroup1', items: [
+                               {type: 'button', name: 'button4'},
+                               {type: 'button', name: 'button5'},
+                               {type: 'button', name: 'button6'}
+                       ]},
+
+                       {type: 'buttongroup', name: 'buttongroup2', items: [
+                               {type: 'button', name: 'button7'},
+                               {type: 'button', name: 'button8'},
+                               {type: 'button', name: 'button9'}
+                       ]},
+
+                       {type: 'toolbar', name: 'toolbar1', items: [
+                               {type: 'buttongroup', name: 'buttongroup3', items: [
+                                       {type: 'button', name: 'button10', disabled: true},
+                                       {type: 'button', name: 'button11'},
+                                       {type: 'button', name: 'button12', classes: 'class4'}
+                               ]}
+                       ]}
+               ]
+       }).renderTo(document.getElementById('view'));
+
+       QUnit.start();
+};
+
+test("Basic", function() {
+       var matches;
+
+       matches = panel.find('button');
+       equal(matches.length, 12);
+       equal(matches[0].type, 'button');
+
+       equal(panel.find('Button').length, 12);
+       equal(panel.find('buttongroup').length, 3);
+       equal(panel.find('buttongroup button').length, 9);
+       equal(panel.find('toolbar buttongroup button').length, 3);
+       equal(panel.find('button#button1').length, 1);
+       equal(panel.find('buttongroup#buttongroup1 button#button4').length, 1);
+       equal(panel.find('button,button,buttongroup button').length, 12, 'Check unique');
+});
+
+test("Classes", function() {
+       equal(panel.find('button.class1').length, 3);
+       equal(panel.find('button.class1.class2').length, 2);
+       equal(panel.find('button.class2.class1').length, 2);
+       equal(panel.find('button.classX').length, 0);
+       equal(panel.find('button.class1, button.class2').length, 3);
+});
+
+test("Psuedo:not", function() {
+       equal(panel.find('button:not(.class1)').length, 9);
+       equal(panel.find('button:not(buttongroup button)').length, 3);
+       equal(panel.find('button:not(toolbar button)').length, 9);
+       equal(panel.find('button:not(toolbar buttongroup button)').length, 9);
+       equal(panel.find('button:not(panel button)').length, 0);
+       equal(panel.find('button:not(.class1)').length, 9);
+       equal(panel.find('button:not(.class3, .class4)').length, 10);
+});
+
+test("Psuedo:odd/even/first/last", function() {
+       var matches;
+
+       matches = panel.find('button:first');
+
+       equal(matches.length, 4);
+       ok(matches[0].name() == 'button1');
+       ok(matches[3].name() == 'button10');
+
+       matches = panel.find('button:last');
+
+       equal(matches.length, 3);
+       ok(matches[0].name() == 'button6');
+       ok(matches[1].name() == 'button9');
+
+       matches = panel.find('button:odd');
+
+       equal(matches.length, 4);
+       ok(matches[0].name() == 'button2');
+       ok(matches[1].name() == 'button5');
+
+       matches = panel.find('button:even');
+
+       equal(matches.length, 8);
+       ok(matches[0].name() == 'button1');
+       ok(matches[1].name() == 'button3');
+});
+
+test("Psuedo:disabled", function() {
+       equal(panel.find('button:disabled').length, 2);
+});
+
+test("Attribute value", function() {
+       equal(panel.find('button[name]').length, 12);
+       equal(panel.find('button[name=button1]').length, 1);
+       equal(panel.find('button[name^=button1]').length, 4);
+       equal(panel.find('button[name$=1]').length, 2);
+       equal(panel.find('button[name*=utt]').length, 12);
+       equal(panel.find('button[name!=button1]').length, 11);
+});
+
+test("Direct descendant", function() {
+       equal(panel.find('> button').length, 3);
+       equal(panel.find('toolbar > buttongroup').length, 1);
+       equal(panel.find('toolbar > button').length, 0);
+});
+
+test("Parents", function() {
+       equal(panel.find("#button10")[0].parents("toolbar,buttongroup").length, 2);
+       equal(panel.find("#button10")[0].parents("panel").length, 1);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Selector Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Selector.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiSpacerhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Spacer.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Spacer.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Spacer.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Spacer Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Spacer", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Spacer Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Spacer.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiSplitButtonhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/SplitButton.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/SplitButton.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/SplitButton.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,131 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.SplitButton Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.SplitButton", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createSplitButton(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'splitbutton'
+       }, settings)).renderTo(document.getElementById('view'));
+}
+
+test("splitbutton text, size default", function() {
+       var splitButton = createSplitButton({text: 'X'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 42, 30], 4);
+});
+
+test("splitbutton text, size large", function() {
+       var splitButton = createSplitButton({text: 'X', size: 'large'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 49, 39], 4);
+});
+
+test("splitbutton text, size small", function() {
+       var splitButton = createSplitButton({text: 'X', size: 'small'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 36, 23], 4);
+});
+
+test("splitbutton text, width 100, height 100", function() {
+       var splitButton = createSplitButton({text: 'X', width: 100, height: 100});
+
+       deepEqual(rect(splitButton), [0, 0, 100, 100]);
+       deepEqual(rect(splitButton.getEl().firstChild), [1, 1, 82, 98]);
+});
+
+test("splitbutton icon, size default", function() {
+       var splitButton = createSplitButton({icon: 'test'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 50, 30], 4);
+});
+
+test("splitbutton icon, size small", function() {
+       var splitButton = createSplitButton({icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 45, 24], 4);
+});
+
+test("splitbutton icon, size large", function() {
+       var splitButton = createSplitButton({icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 54, 40], 4);
+});
+
+test("splitbutton icon, width 100, height 100", function() {
+       var splitButton = createSplitButton({icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(splitButton), [0, 0, 100, 100]);
+       deepEqual(rect(splitButton.getEl().firstChild), [1, 1, 82, 98]);
+});
+
+test("splitbutton text & icon, size default", function() {
+       var splitButton = createSplitButton({text: 'X', icon: 'test'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 62, 30], 4);
+});
+
+test("splitbutton text & icon, size large", function() {
+       var splitButton = createSplitButton({text: 'X', icon: 'test', size: 'large'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 69, 40], 4);
+});
+
+test("splitbutton text & icon, size small", function() {
+       var splitButton = createSplitButton({text: 'X', icon: 'test', size: 'small'});
+
+       nearlyEqualRects(rect(splitButton), [0, 0, 55, 24], 4);
+});
+
+test("splitbutton text & icon, width 100, height 100", function() {
+       var splitButton = createSplitButton({text: 'X', icon: 'test', width: 100, height: 100});
+
+       deepEqual(rect(splitButton), [0, 0, 100, 100]);
+       deepEqual(rect(splitButton.getEl().firstChild), [1, 1, 82, 98]);
+});
+
+test("splitbutton click event", function() {
+       var splitButton, clicks = {};
+
+       splitButton = createSplitButton({text: 'X', onclick: function() {clicks.a = 'a';}});
+       splitButton.fire('click', {target: splitButton.getEl().firstChild});
+
+       deepEqual(clicks, {a: 'a'});
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Button Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/SplitButton.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiStackLayouthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/StackLayout.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/StackLayout.html                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/StackLayout.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.StackLayout Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.StackLayout", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.StackLayout Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/StackLayout.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiTabPanelhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/TabPanel.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/TabPanel.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/TabPanel.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,164 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.TabPanel Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.TabPanel", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createTabPanel(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'tabpanel',
+               items: [
+                       {title: 'a', type: 'spacer', classes: 'red'},
+                       {title: 'b', type: 'spacer', classes: 'green'},
+                       {title: 'c', type: 'spacer', classes: 'blue'}
+               ]
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+}
+
+test("panel width: 100, height: 100", function() {
+       panel = createTabPanel({
+               width: 100,
+               height: 100,
+               layout: 'fit'
+       });
+
+       deepEqual(rect(panel), [0, 0, 100, 100]);
+       nearlyEqualRects(rect(panel.items()[0]), [0, 31, 100, 69], 4);
+});
+
+test("panel width: 100, height: 100, border: 1", function() {
+       panel = createTabPanel({
+               width: 100,
+               height: 100,
+               border: 1,
+               layout: 'fit'
+       });
+
+       deepEqual(rect(panel), [0, 0, 100, 100]);
+       nearlyEqualRects(rect(panel.items()[0]), [0, 31, 100, 69], 4);
+});
+
+test("panel width: 100, height: 100, activeTab: 1", function() {
+       panel = createTabPanel({
+               width: 100,
+               height: 100,
+               activeTab: 1,
+               layout: 'fit'
+       });
+
+       deepEqual(rect(panel), [0, 0, 100, 100]);
+       nearlyEqualRects(rect(panel.items()[1]), [0, 31, 100, 69], 4);
+});
+
+test("panel width: auto, height: auto, mixed sized widgets", function() {
+       panel = createTabPanel({
+               items: [
+                       {title: 'a', type: 'spacer', classes: 'red', style: 'width: 100px; height: 100px'},
+                       {title: 'b', type: 'spacer', classes: 'green', style: 'width: 70px; height: 70px'},
+                       {title: 'c', type: 'spacer', classes: 'blue', style: 'width: 120px; height: 120px'}
+               ]
+       });
+
+       nearlyEqualRects(rect(panel), [0, 0, 120, 151], 4);
+       nearlyEqualRects(rect(panel.items()[0]), [0, 31, 120, 120], 4);
+
+       panel.activateTab(1);
+       nearlyEqualRects(rect(panel.items()[1]), [0, 31, 120, 120], 4);
+
+       panel.activateTab(2);
+       nearlyEqualRects(rect(panel.items()[2]), [0, 31, 120, 120], 4);
+});
+
+test("panel width: auto, height: auto, mixed sized containers", function() {
+       panel = createTabPanel({
+               items: [
+                       {
+                               title: 'a',
+                               type: 'panel',
+                               layout: 'flex',
+                               align: 'stretch',
+                               items: {
+                                       type: 'spacer',
+                                       classes: 'red',
+                                       flex: 1,
+                                       minWidth: 100,
+                                       minHeight: 100
+                               }
+                       },
+
+                       {
+                               title: 'b',
+                               type: 'panel',
+                               layout: 'flex',
+                               align: 'stretch',
+                               items: {
+                                       type: 'spacer',
+                                       flex: 1,
+                                       classes: 'green',
+                                       minWidth: 70,
+                                       minHeight: 70
+                               }
+                       },
+
+                       {
+                               title: 'c',
+                               type: 'panel',
+                               layout: 'flex',
+                               align: 'stretch',
+                               items: {
+                                       type: 'spacer',
+                                       classes: 'blue',
+                                       flex: 1,
+                                       minWidth: 120,
+                                       minHeight: 120
+                               }
+                       }
+               ]
+       });
+
+       nearlyEqualRects(rect(panel), [0, 0, 120, 151], 4);
+       nearlyEqualRects(rect(panel.items()[0]), [0, 31, 120, 120], 4);
+
+       panel.activateTab(1);
+       nearlyEqualRects(rect(panel.items()[1]), [0, 31, 120, 120], 4);
+
+       panel.activateTab(2);
+       nearlyEqualRects(rect(panel.items()[2]), [0, 31, 120, 120], 4);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.TabPanel Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/TabPanel.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiTextBoxhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/TextBox.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/TextBox.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/TextBox.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.TextBox Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.TextBox", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createTextBox(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'textbox'
+       }, settings)).renderTo(document.getElementById('view'));
+}
+
+test("textbox text, size chars: 5", function() {
+       var textBox = createTextBox({text: 'X', size: 5});
+
+       nearlyEqualRects(size(textBox), [69, 30], 20);
+});
+
+test("textbox text, size 100x100", function() {
+       var textBox = createTextBox({text: 'X', width: 100, height: 100});
+
+       deepEqual(size(textBox), [100, 100]);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.TextBox Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/TextBox.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiThrobberhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Throbber.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Throbber.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Throbber.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Throbber Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Throbber", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Throbber Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Throbber.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiToolbarhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Toolbar.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Toolbar.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Toolbar.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Toolbar Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Toolbar", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Toolbar Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Toolbar.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiTooltiphtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Tooltip.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Tooltip.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Tooltip.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Tooltip Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Tooltip", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Tooltip Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Tooltip.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiWidgethtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Widget.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Widget.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Widget.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Widget Test Suite</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var panel;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Widget", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               //document.getElementById('view').innerHTML = '';
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Widget Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; right: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Widget.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuiWindowhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/Window.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/Window.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/Window.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,118 @@
</span><ins>+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>ui.Window</title>
+<link type="text/css" rel="stylesheet" href="../../../../../src/wp-includes/js/tinymce/skins/lightgray/skin.min.css" />
+<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+<link rel="stylesheet" href="css/ui-overrides.css" type="text/css" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script type="text/javascript">
+var win;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("ui.Window", {
+       setup: function() {
+               document.getElementById('view').innerHTML = '';
+       },
+
+       teardown: function() {
+               tinymce.DOM.remove(document.getElementById('mce-modal-block'));
+       }
+});
+
+window.onload = function() {
+       QUnit.start();
+};
+
+function createWindow(settings) {
+       return tinymce.ui.Factory.create(tinymce.extend({
+               type: 'window'
+       }, settings)).renderTo(document.getElementById('view')).reflow();
+}
+
+test("window x, y, w, h", function() {
+       win = createWindow({x: 100, y: 120, width: 200, height: 210});
+
+       deepEqual(size(win), [200, 210]);
+});
+
+test("no title, no buttonbar, autoResize", function() {
+       win = createWindow({
+               x: 100,
+               y: 120,
+               items: [
+                       {type: 'spacer', classes: 'red'}
+               ]
+       });
+
+       deepEqual(size(win), [22, 22]);
+       deepEqual(size(win.find("spacer")[0]), [20, 20]);
+});
+
+test("title, no buttonbar, autoResize, title is widest", function() {
+       win = createWindow({
+               x: 100,
+               y: 120,
+               title: "XXXXXXXXXXXXXXXXXXXXXX",
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1}
+               ]
+       });
+
+       nearlyEqualRects(size(win), [326, 61], 10);
+       nearlyEqualRects(size(win.find("spacer")[0]), [324, 20], 10);
+});
+
+test("buttonbar, autoResize, buttonbar is widest", function() {
+       win = createWindow({
+               x: 100,
+               y: 120,
+               items: [
+                       {type: 'spacer', classes: 'red', flex: 1}
+               ],
+               buttons: [
+                       {type: 'spacer', classes: 'green', minWidth: 400}
+               ]
+       });
+
+       deepEqual(size(win), [422, 63]);
+       deepEqual(size(win.find("spacer")[0]), [420, 20]);
+       deepEqual(size(win.statusbar.find("spacer")[0]), [400, 20]);
+});
+
+test("buttonbar, title, autoResize, content is widest", function() {
+       win = createWindow({
+               x: 100,
+               y: 120,
+               title: "X",
+               items: [
+                       {type: 'spacer', classes: 'red', minWidth: 400}
+               ],
+               buttons: [
+                       {type: 'spacer', classes: 'green'}
+               ]
+       });
+
+       deepEqual(size(win), [402, 102]);
+       deepEqual(size(win.getEl("head")), [400, 39]);
+       deepEqual(size(win.find("spacer")[0]), [400, 20]);
+       deepEqual(size(win.statusbar.find("spacer")[0]), [20, 20]);
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">ui.Window Test Suite</h1>
+       <h2 id="qunit-banner"></h2>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests">
+       </ol>
+       <div id="view" style="position: absolute; left: 0; top: 0"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/Window.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuicssuioverridescss"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/css/ui-overrides.css (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/css/ui-overrides.css                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/css/ui-overrides.css    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+/* Hardcodes sizes since fonts vary on platforms */
+
+.mce-spacer {
+       width: 20px;
+       height: 20px;
+       visibility: visible;
+       border: 0 solid black;
+}
+
+.mce-head .mce-title {
+       width: 100px;
+       height: 20px;
+       display: inline-block;
+}
+
+.mce-btn .mce-txt {
+       width: 20px;
+}
+
+/* Colors used for debugging */
+
+.mce-red {background-color: red;}
+.mce-green {background-color: green;}
+.mce-blue {background-color: blue;}
+.mce-yellow {background-color: yellow;}
+.mce-magenta {background-color: magenta;}
+.mce-cyan {background-color: cyan;}
+.mce-dotted {background-image: url(../img/raster.gif);}
+.mce-i-test {background: red;}

</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunktestsquniteditortinymceuiimgrastergif"></a>
<div class="binary"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/img/raster.gif</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Index: trunk/tests/qunit/editor/tinymce/ui/img/raster.gif
</span><span class="cx">===================================================================
</span><del>--- trunk/tests/qunit/editor/tinymce/ui/img/raster.gif  2014-02-09 22:33:56 UTC (rev 27154)
</del><ins>+++ trunk/tests/qunit/editor/tinymce/ui/img/raster.gif   2014-02-10 01:11:25 UTC (rev 27155)
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/img/raster.gif
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<ins>+image/gif
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceuitestsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/ui/tests.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/ui/tests.js                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/ui/tests.js        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+{
+       "title": "tinymce.ui",
+       "tests": [
+               {"title": "AbsoluteLayout", "url": "AbsoluteLayout.html"},
+               {"title": "Button", "url": "Button.html"},
+               {"title": "ButtonGroup", "url": "ButtonGroup.html"},
+               {"title": "Checkbox", "url": "Checkbox.html"},
+               {"title": "Collection", "url": "Collection.html"},
+               {"title": "ColorButton", "url": "ColorButton.html"},
+               {"title": "ComboBox", "url": "ComboBox.html"},
+               {"title": "Container", "url": "Container.html"},
+               {"title": "Control", "url": "Control.html"},
+               {"title": "DragHelper", "url": "DragHelper.html"},
+               {"title": "ElementPath", "url": "ElementPath.html"},
+               {"title": "Factory", "url": "Factory.html"},
+               {"title": "FieldSet", "url": "FieldSet.html"},
+               {"title": "FilePicker", "url": "FilePicker.html"},
+               {"title": "FitLayout", "url": "FitLayout.html"},
+               {"title": "FlexLayout", "url": "FlexLayout.html"},
+               {"title": "FloatPanel", "url": "FloatPanel.html"},
+               {"title": "FlowLayout", "url": "FlowLayout.html"},
+               {"title": "Form", "url": "Form.html"},
+               {"title": "FormItem", "url": "FormItem.html"},
+               {"title": "GridLayout", "url": "GridLayout.html"},
+               {"title": "Iframe", "url": "Iframe.html"},
+               {"title": "KeyboardNavigation", "url": "KeyboardNavigation.html"},
+               {"title": "Label", "url": "Label.html"},
+               {"title": "Layout", "url": "Layout.html"},
+               {"title": "ListBox", "url": "ListBox.html"},
+               {"title": "Menu", "url": "Menu.html"},
+               {"title": "MenuBar", "url": "MenuBar.html"},
+               {"title": "MenuButton", "url": "MenuButton.html"},
+               {"title": "MenuItem", "url": "MenuItem.html"},
+               {"title": "MessageBox", "url": "MessageBox.html"},
+               {"title": "Movable", "url": "Movable.html"},
+               {"title": "Panel", "url": "Panel.html"},
+               {"title": "PanelButton", "url": "PanelButton.html"},
+               {"title": "Path", "url": "Path.html"},
+               {"title": "Radio", "url": "Radio.html"},
+               {"title": "Resizable", "url": "Resizable.html"},
+               {"title": "ResizeHandle", "url": "ResizeHandle.html"},
+               {"title": "Scrollable", "url": "Scrollable.html"},
+               {"title": "Selector", "url": "Selector.html"},
+               {"title": "Spacer", "url": "Spacer.html"},
+               {"title": "SplitButton", "url": "SplitButton.html"},
+               {"title": "StackLayout", "url": "StackLayout.html"},
+               {"title": "TabPanel", "url": "TabPanel.html"},
+               {"title": "TextBox", "url": "TextBox.html"},
+               {"title": "Throbber", "url": "Throbber.html"},
+               {"title": "Toolbar", "url": "Toolbar.html"},
+               {"title": "Tooltip", "url": "Tooltip.html"},
+               {"title": "Widget", "url": "Widget.html"},
+               {"title": "Window", "url": "Window.html"}
+       ]
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/ui/tests.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilJSONhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/JSON.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/JSON.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/JSON.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,39 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.util.JSON tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.util.JSON");
+
+QUnit.config.reorder = false;
+
+(function() {
+       var JSON = tinymce.util.JSON;
+
+       test('serialize', 2, function() {
+               equal(JSON.serialize({arr1 : [1, 2, 3, [1, 2, 3]], bool1 : true, float1: 3.14, int1 : 123, null1 : null, obj1 : {key1 : "val1", key2 : "val2"}, str1 : '\"\'abc\u00C5123\\'}), '{"arr1":[1,2,3,[1,2,3]],"bool1":true,"float1":3.14,"int1":123,"null1":null,"obj1":{"key1":"val1","key2":"val2"},"str1":"\\"\'abc\\u00c5123\\\\"}');
+
+               equal(JSON.serialize({arr1 : [1, 2, 3, [1, 2, 3]], bool1 : true, float1: 3.14, int1 : 123, null1 : null, obj1 : {key1 : "val1", key2 : "val2"}, str1 : '\"\'abc\u00C5123'}, "'"), "{'arr1':[1,2,3,[1,2,3]],'bool1':true,'float1':3.14,'int1':123,'null1':null,'obj1':{'key1':'val1','key2':'val2'},'str1':'\\\"\\'abc\\u00c5123'}");
+       });
+
+       test('parse', 1, function() {
+               equal(JSON.parse('{"arr1":[1,2,3,[1,2,3]],"bool1":true,"float1":3.14,"int1":123,"null1":null,"obj1":{"key1":"val1","key2":"val2"},"str1":"abc\\u00c5123"}').str1, 'abc\u00c5123');
+       });
+})();
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.util.JSON tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/JSON.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilJSONRequesthtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/JSONRequest.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/JSONRequest.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/JSONRequest.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,77 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.util.JSONRequest tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.util.JSONRequest");
+
+QUnit.config.reorder = false;
+
+asyncTest("Successful request - send method", function() {
+       expect(1);
+
+       new tinymce.util.JSONRequest({}).send({
+               type : 'GET',
+               url : 'json_rpc_ok.js',
+               success: function(data) {
+                       equal(data, 'Hello JSON-RPC');
+                       start();
+               }
+       });
+});
+
+asyncTest("Successful request - sendRPC static method", function() {
+       expect(1);
+
+       tinymce.util.JSONRequest.sendRPC({
+               type : 'GET',
+               url : 'json_rpc_ok.js',
+               success: function(data) {
+                       equal(data, 'Hello JSON-RPC');
+                       start();
+               }
+       });
+});
+
+asyncTest("Error request - send method", function() {
+       expect(1);
+
+       new tinymce.util.JSONRequest({}).send({
+               type : 'GET',
+               url : 'json_rpc_error.js',
+               error: function(error) {
+                       equal(error.code, 42);
+                       start();
+               }
+       });
+});
+
+asyncTest("Error request - sendRPC static method", function() {
+       expect(1);
+
+       tinymce.util.JSONRequest.sendRPC({
+               type : 'GET',
+               url : 'json_rpc_error.js',
+               error: function(error) {
+                       equal(error.code, 42);
+                       start();
+               }
+       });
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.util.JSONRequest tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/JSONRequest.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilLocalStoragehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/LocalStorage.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/LocalStorage.html                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/LocalStorage.html     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,118 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.util.LocalStorage tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+var LocalStorage = tinymce.util.LocalStorage;
+
+module("tinymce.util.LocalStorage", {
+       setup: function() {
+               LocalStorage.clear();
+       },
+
+       teardown: function() {
+               LocalStorage.clear();
+       }
+});
+
+QUnit.config.reorder = false;
+
+test('setItem', function() {
+       LocalStorage.setItem("a", "1");
+       equal(LocalStorage.getItem("a"), "1");
+       LocalStorage.setItem("a", "2");
+       equal(LocalStorage.getItem("a"), "2");
+       LocalStorage.setItem("a", 3);
+       equal(LocalStorage.getItem("a"), "3");
+       LocalStorage.setItem("a", null);
+       equal(LocalStorage.getItem("a"), "null");
+       LocalStorage.setItem("a", undefined);
+       equal(LocalStorage.getItem("a"), "undefined");
+       LocalStorage.setItem("a", new Date(0));
+       equal(LocalStorage.getItem("a"), new Date(0).toString());
+});
+
+test('getItem', function() {
+       LocalStorage.setItem("a", "1");
+       equal(LocalStorage.getItem("a"), "1");
+       LocalStorage.setItem("a", "0");
+       equal(LocalStorage.getItem("a"), "0");
+       equal(LocalStorage.getItem("b"), null);
+});
+
+test('removeItem', function() {
+       LocalStorage.setItem("a", "1");
+       equal(LocalStorage.getItem("a"), "1");
+       LocalStorage.removeItem("a");
+       equal(LocalStorage.getItem("a"), null);
+});
+
+test('key', function() {
+       LocalStorage.setItem("a", "1");
+       equal(LocalStorage.key(0), "a");
+       equal(LocalStorage.length, 1);
+});
+
+test('length', function() {
+       equal(LocalStorage.length, 0);
+       LocalStorage.setItem("a", "1");
+       equal(LocalStorage.length, 1);
+});
+
+test('clear', function() {
+       equal(LocalStorage.length, 0);
+       LocalStorage.setItem("a", "1");
+       equal(LocalStorage.length, 1);
+});
+
+test('setItem key and value with commas', function() {
+       LocalStorage.setItem("a,1", "1,2");
+       LocalStorage.setItem("b,2", "2,3");
+       equal(LocalStorage.getItem("a,1"), "1,2");
+       equal(LocalStorage.getItem("b,2"), "2,3");
+});
+
+test('setItem with two large values', function() {
+       var data = "";
+
+       for (var i = 0; i < 1024; i++) {
+               data += 'x';
+       }
+
+       LocalStorage.clear();
+       LocalStorage.setItem("a", data + "1");
+       LocalStorage.setItem("b", data);
+       equal(LocalStorage.getItem("a").length, 1024 + 1);
+       equal(LocalStorage.getItem("b").length, 1024);
+});
+
+test('setItem with two large keys', function() {
+       var key = "";
+
+       for (var i = 0; i < 1024; i++) {
+               key += 'x';
+       }
+
+       LocalStorage.clear();
+       LocalStorage.setItem(key + "1", "a");
+       LocalStorage.setItem(key + "2", "b");
+       equal(LocalStorage.key(0), key + "1");
+       equal(LocalStorage.key(1), key + "2");
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.util.Cookie tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/LocalStorage.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilQuirks_allhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/Quirks_all.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/Quirks_all.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_all.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>All browser types Quirks</title>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script src="../../js/jsrobot/robot.js"></script>
+<script src="../../plugins/js/dsl.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+var BACKSPACE = 0x08;
+
+module("Quirks Tests", {
+       autostart: false
+});
+
+// IE does the right thing
+if (!tinymce.isIE) {
+       test('Backspace when whole body contents is selected', function() {
+               editor.getBody().innerHTML = '<p><b>1</b></p><p><b>2</b></p>';
+               setSelection('p:first b', 0, 'p:last b', 1);
+               editor.dom.fire(editor.getBody(), 'keydown', {keyCode: BACKSPACE});
+               equal(editor.getContent(), '<p>&nbsp;</p>');
+       });
+}
+
+asyncTest('Backspace into <table> should be disabled', 1, function() {
+       var testContent = '<table class="mceItemTable" border="1"><tbody><tr><th><p>Table heading</p></th></tr><tr><td><p>Table contents</p></td></tr></tbody></table><h2 id="a">Paragraph Heading</h2>';
+       editor.setContent(testContent);
+       var initialContent = editor.getContent();
+       setSelection('#a', 0);
+       editor.focus();
+       robot.type(BACKSPACE, false, function() {
+               var expected = initialContent;
+               var actual = editor.getContent();
+               equal(actual, expected);
+               start();
+       }, editor.getBody());
+});
+
+function initTinyFunction() {
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               init_instance_callback : function(ed) {
+                       editor = ed;
+               }
+       });
+}
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">All browser types Quirks</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+    <script>
+       initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/Quirks_all.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilQuirks_firefoxhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/Quirks_firefox.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/Quirks_firefox.html                                (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_firefox.html   2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Firefox Quirks</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script src="../../js/jsrobot/robot.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Quirks Tests", {
+       autostart: false
+});
+
+if (tinymce.isGecko) {
+       asyncTest('Remove hr between p with backspace', 1, function() {
+               setTimeout(function() {
+                       editor.setContent('<p>one</p><hr /><p id="a">two</p>');
+                       setSelection('#a', 0);
+                       editor.focus();
+                       robot.type(8, false, function() {
+                               var expected = '<p>one</p><p id="a">two</p>';
+                               var actual = editor.getContent({ format: 'raw' });
+                               equal(actual, expected);
+                               start();
+                       }, editor.getBody());
+               }, 100);
+       });
+
+       test('Add BR element at end of paragraphs with single link', function() {
+               editor.setContent('<p><b><a href="#">x</a></b></p>');
+               equal(editor.getBody().innerHTML, '<p><strong><a href="#" data-mce-href="#">x</a></strong><br data-mce-bogus="1"></p>');
+       });
+} else {
+       test('ignored', function() {
+               ok(true, "Tests ignored since the browser isn't Gecko.");
+       });
+}
+
+function initTinyFunction() {
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               init_instance_callback : function(ed) {
+                       editor = ed;
+               }
+       });
+}
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Firefox Quirks</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+    <script>
+       initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/Quirks_firefox.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilQuirks_ie8html"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/Quirks_ie8.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/Quirks_ie8.html                            (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_ie8.html       2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Internet Explorer 8 Quirks</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script src="../../js/jsrobot/robot.js"></script>
+<script>
+var editor;
+
+QUnit.config.reorder = false;
+QUnit.config.autostart = false;
+
+module("Quirks Tests", {
+       autostart: false
+});
+
+if (tinymce.isIE) {
+       asyncTest('Remove hr between p with backspace', 1, function() {
+               setTimeout(function() {
+                       editor.setContent('<p>one</p><hr /><p>two</p>');
+                       setSelection('p:last', 0);
+                       editor.focus();
+                       robot.type(8, false, function() {
+                               var expected = '<p>one</p><p>two</p>';
+                               var actual = cleanHtml(editor.getContent({ format: 'raw' }));
+                               equal(actual, expected);
+                               start();
+                       }, editor.getBody());
+               }, 100);
+       });
+
+       asyncTest('Heading text alignment', 1, function() {
+               editor.setContent('<h1 id="x" style="text-align: center;">x</h1>');
+               setSelection('#x', 1);
+               editor.focus();
+               robot.type(0xA, false, function() {
+                       var expected = '<h1 id="x" style="text-align: center;">x</h1>\n<p>&nbsp;</p>';
+                       var actual = editor.getContent();
+                       equal(actual, expected);
+                       start();
+               }, editor.getBody());
+       });
+} else {
+       test('ignored', function() {
+               ok(true, "Tests ignored since the browser isn't IE8.");
+       });
+}
+
+var initTinyFunction = function() {
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               init_instance_callback : function(ed) {
+                       editor = ed;
+               }
+       });
+}
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Internet Explorer 8 Quirks</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+               <div>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+                       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+               </div>
+       </div>
+    <script>
+       initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/Quirks_ie8.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilQuirks_removehtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/Quirks_remove.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/Quirks_remove.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_remove.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,270 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Removing content tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script src="../../js/jsrobot/robot.js"></script>
+<script>
+var editor;
+
+QUnit.config.autostart = false;
+QUnit.config.reorder = false;
+
+module("Remove Content", {
+       autostart: false
+});
+
+asyncTest('Backspace with indented text', function() {
+       var c, originalContent = '<p>Line1</p>\n<p style="margin-left: 30px;">Line2</p>';
+
+       expect(2);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('p:nth-child(1)', 4, 'p:nth-child(2)', 4);
+       robot.type('\b', false, function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), "<p>Line2</p>", 'Delete content');
+                       editor.execCommand('undo', false, null);
+                       equal(editor.getContent(), originalContent, 'Undo deletion');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+// oncut is not supported by FireFox 2.0 so this is impossible to fix there.
+if (!tinymce.isGecko || !/Firefox\/[12].[0-9]/.test(navigator.userAgent)) {
+       asyncTest('Cut with indented text', function() {
+               var c, originalContent = '<p>Line1</p>\n<p style="margin-left: 30px;">Line2</p>';
+       
+               expect(3);
+       
+               editor.setContent(originalContent);
+               editor.focus();
+               setSelection('p:nth-child(1)', 4, 'p:nth-child(2)', 4);
+               robot.cut(function() {
+                       // The fix for this bug happens in a timeout after cut so we need to make sure that happens first by adding an additional delay.
+                       setTimeout(function() {
+                               equal(editor.getContent(), "<p>Line2</p>", 'Cut text');
+                               editor.execCommand('undo', false, null);
+                               equal(editor.getContent(), originalContent, 'Undo cut');
+                               editor.execCommand('SelectAll');
+                               robot.paste(function() {
+                                       ok(/Line/.test(editor.getContent()), 'Content should have been on clipboard. Got: ' + editor.getContent());
+                                       QUnit.start();
+                               }, editor.selection.getNode());
+                       }, 100);
+               }, editor.selection.getNode());
+       });
+} else {
+       test('Skipped on FireFox 2.x: Cut with indented text', function() {});
+}
+
+asyncTest('Forward delete with indented text', function() {
+       var c, originalContent = '<p>Line1</p>\n<p style="margin-left: 30px;">Line2</p>';
+
+       expect(2);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('p:nth-child(1)', 4, 'p:nth-child(2)', 4);
+       robot.forwardDelete(function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), "<p>Line2</p>", 'Delete content');
+                       editor.execCommand('undo', false, null);
+                       equal(editor.getContent(), originalContent, 'Undo deletion');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Forward delete with first paragraph indented', function() {
+       var c, originalContent = '<p style="margin-left: 30px;">Line1</p>\n<p>Line2</p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('p:nth-child(1)', 4, 'p:nth-child(2)', 4);
+       robot.forwardDelete(function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<p style="margin-left: 30px;">Line2</p>', 'Delete content');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Backward delete from paragraph to heading', function () {
+       var c, originalContent = '<h1>Heading</h1><p>text</p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('p', 0);
+       robot.type('\b', false, function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<h1>Headingtext</h1>', 'Delete content');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Forward delete from heading to paragraph', function () {
+       var c, originalContent = '<h1>Heading</h1><p>text</p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('h1', 7);
+       robot.forwardDelete(function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<h1>Headingtext</h1>', 'Delete content');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Forward delete from heading to paragraph with span', function () {
+       var c, originalContent = '<h1>Heading</h1><p><span style="color: #ff0000;">text</span></p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('h1', 7);
+       robot.forwardDelete(function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<h1>Heading<span style="color: #ff0000;">text</span></h1>', 'Delete content');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Backward delete from paragraph with span to heading', function () {
+       var c, originalContent = '<h1>Heading</h1><p><span style="color: #ff0000;">text</span></p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       setSelection('p', 0);
+       robot.type('\b', false, function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<h1>Heading<span style="color: #ff0000;">text</span></h1>', 'Delete content');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Backward delete all contents', function () {
+       var c, originalContent = '<h1>Heading</h1><p><span style="color: #ff0000;">text</span></p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       editor.execCommand('SelectAll');
+       robot.type('\b', false, function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<p>&nbsp;</p>', 'Empty contents');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Forward delete all contents', function () {
+       var c, originalContent = '<h1>Heading</h1><p><span style="color: #ff0000;">text</span></p>';
+
+       expect(1);
+
+       editor.setContent(originalContent);
+       editor.focus();
+       editor.execCommand('SelectAll');
+       robot.forwardDelete(function() {
+               // The content is fixed up after a small timeout to let the browser default behaviour kick in.
+               // As such we need to defer our checks as well.
+               setTimeout(function() {
+                       equal(editor.getContent(), '<p>&nbsp;</p>', 'Empty contents');
+                       QUnit.start();
+               }, 100);
+       }, editor.selection.getNode());
+});
+
+asyncTest('Backward delete blockquote contents', function () {
+       expect(1);
+
+       editor.setContent('<blockquote><p>some text here</p></blockquote>');
+       var textNode = editor.dom.select('p')[0].firstChild;
+       setSelection(textNode, 0, textNode, 5);
+       editor.focus();
+       robot.type('\b', false, function() {
+               equal(cleanHtml(editor.getContent()), '<blockquote><p>text here</p></blockquote>');
+               QUnit.start();
+       }, editor.selection.getNode());
+});
+
+asyncTest('Forward delete after empty paragraphs does not delete all content', function () {
+       expect(1);
+
+       editor.setContent('<p></p><p></p><p></p>');
+       setSelection('p:nth-child(3)', 0);
+       editor.focus();
+       robot.forwardDelete(function() {
+               QUnit.notEqual(editor.getContent(), '<p>&nbsp;</p>', 'Editor contents should not be empty');
+               QUnit.start();
+       }, editor.selection.getNode());
+});
+
+var initTinyFunction = function(){
+       tinymce.init({
+               mode : "exact",
+               elements : "elm1",
+               add_unload_trigger : false,
+               theme_advanced_styles : 'test1=test1;test2=test2',
+               valid_styles : {
+                       '*' : 'text-align,padding-left,color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display'
+               },
+               init_instance_callback : function(ed) {
+                       editor = ed;
+               }
+       });
+};
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">Removing content tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content">
+               <textarea id="elm1" name="elm1"></textarea>
+       </div>
+       <script>
+               initWhenTinyAndRobotAreReady(initTinyFunction);
+       </script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/Quirks_remove.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilQuirks_webkithtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Webkit Quirks</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css"/>
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+       var editor, rng;
+
+       QUnit.config.reorder = false;
+       QUnit.config.autostart = false;
+
+       module("WebKit Quirks Tests", {
+               autostart: false
+       });
+
+       if (tinymce.isWebKit) {
+               test('Delete from beginning of P into H1', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b</p>';
+                       setSelection('p', 0);
+                       editor.execCommand('Delete');
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>ab</h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('Delete whole H1 before P', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b</p>';
+
+                       rng = editor.selection.getRng();
+                       rng.setStartBefore(editor.getBody().firstChild);
+                       rng.setEndAfter(editor.getBody().firstChild);
+                       editor.selection.setRng(rng);
+
+                       editor.execCommand('Delete');
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>b<br></h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('Delete from beginning of P with style span inside into H1', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b<span style="color:red">c</span></p>';
+                       setSelection('p', 0);
+                       editor.execCommand('Delete');
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>ab<span data-mce-style="color:red" style="color:red">c</span></h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('ForwardDelete from end of H1 into P', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b</p>';
+                       setSelection('h1', 1);
+                       editor.execCommand('ForwardDelete');
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>ab</h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('ForwardDelete whole H1 before P', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b</p>';
+
+                       rng = editor.selection.getRng();
+                       rng.setStartBefore(editor.getBody().firstChild);
+                       rng.setEndAfter(editor.getBody().firstChild);
+                       editor.selection.setRng(rng);
+
+                       editor.execCommand('ForwardDelete');
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>b<br></h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('ForwardDelete from end of H1 into P with style span inside', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b<span style="color:red">c</span></p>';
+                       setSelection('h1', 1);
+                       editor.execCommand('ForwardDelete');
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>ab<span data-mce-style="color:red" style="color:red">c</span></h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('Backspace key from beginning of P into H1', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b</p>';
+                       setSelection('p', 0);
+                       editor.fire("keydown", {keyCode: 8});
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>ab</h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+
+               test('Delete key from end of H1 into P', function() {
+                       editor.getBody().innerHTML ='<h1>a</h1><p>b</p>';
+                       setSelection('h1', 1);
+                       editor.fire("keydown", {keyCode: 46});
+                       equal(cleanHtml(editor.getBody().innerHTML), '<h1>ab</h1>');
+                       equal(editor.selection.getStart().nodeName, 'H1');
+               });
+       } else {
+               test("Skipped since the browser isn't WebKit", function() {
+                       ok(true, "Skipped");
+               });
+       }
+
+       var url = document.location.href.substring( 0, document.location.href.lastIndexOf('tinymce/') );
+       
+       tinymce.init({
+               mode : "exact",
+               external_plugins: {
+                       noneditable: url + 'external-plugins/table/plugin.js'
+               },
+               elements : "elm1",
+               indent: false,
+               init_instance_callback : function(ed) {
+                       editor = ed;
+                       QUnit.start();
+               }
+       });
+</script>
+</head>
+<body>
+<h1 id="qunit-header">Webkit Quirks</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="content">
+<textarea id="elm1" name="elm1"></textarea>
+
+<div>
+       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+</div>
+</div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/Quirks_webkit.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilQuirks_webkit_jsrobothtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html                         (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html    2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,205 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Webkit Quirks</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css"/>
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script src="../../js/jsrobot/robot.js"></script>
+<script>
+       var editor;
+
+       QUnit.config.reorder = false;
+       QUnit.config.autostart = false;
+
+       module("Quirks Tests", {
+               autostart: false
+       });
+
+       var defaultTableContent =
+                       "<p id='p'>p</p>" +
+                                       "<table>" +
+                                       "  <tbody>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='b'>b</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tbody>" +
+                                       "  <thead>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='a'>a</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </thead>" +
+                                       "  <tbody>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='c'>c</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  <tr>" +
+                                       "          <td>" +
+                                       "<p id='p'>p</p>" +
+                                       "<table>" +
+                                       "  <tbody>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='i'>i</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tbody>" +
+                                       "  <thead>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='h'>h</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </thead>" +
+                                       "  <tbody>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='j'>j</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='k'>k</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tbody>" +
+                                       "  <tfoot>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='m'>m</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tfoot>" +
+                                       "  <tbody>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='l'>l</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tbody>" +
+                                       "</table>" +
+                                       "<p id='g'>g</p>" +
+                                       "</td>" +
+                                       "          <td id='d'>d</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tbody>" +
+                                       "  <tfoot>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='f'>f</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tfoot>" +
+                                       "  <tbody>" +
+                                       "  <tr>" +
+                                       "          <td>z</td>" +
+                                       "          <td id='e'>e</td>" +
+                                       "          <td>z</td>" +
+                                       "  </tr>" +
+                                       "  </tbody>" +
+                                       "</table>" +
+                                       "<p id='g'>g</p>";
+
+       if (tinymce.isWebKit) {
+               asyncTest('tbody to tr', 1, function() {
+                       check('b', 40, 'c');
+               });
+               asyncTest('tr to tr', 1, function() {
+                       check('c', 40, 'd');
+               });
+               asyncTest('tr to tbody', 1, function() {
+                       check('d', 40, 'e');
+               });
+               asyncTest('tbody to tfoot', 1, function() {
+                       check('e', 40, 'f');
+               });
+               asyncTest('tfoot escaping down', 1, function() {
+                       check('f', 40, 'g');
+               });
+               asyncTest('thead to tbody', 1, function() {
+                       check('a', 40, 'b');
+               });
+               asyncTest('tfoot to tbody', 1, function() {
+                       check('f', 38, 'e');
+               });
+               asyncTest('tbody to thead', 1, function() {
+                       check('b', 38, 'a');
+               });
+               asyncTest('thead escaping up', 1, function() {
+                       check('a', 38, 'p');
+               });
+               asyncTest('nested tbody to tfoot', 1, function() {
+                       check('l', 40, 'm');
+               });
+               asyncTest('nested tfoot to tbody', 1, function() {
+                       check('m', 38, 'l');
+               });
+               asyncTest('nested tfoot to tbody', 1, function() {
+                       check('m', 38, 'l');
+               });
+               asyncTest('moving up around nested table', 1, function() {
+                       check('d', 38, 'c');
+               });
+       } else {
+               test("Skipped since the browser isn't WebKit", function() {
+                       ok(true, "Skipped");
+               });
+       }
+
+       function check(nodeId, keyStroke, expectedId) {
+               setSelection('#' + nodeId, 0);
+               editor.focus();
+               robot.type(keyStroke, false, getAssertFunction(expectedId), editor.getBody());
+       }
+
+       function getAssertFunction(expectedId) {
+               return function() {
+                       var actual = editor.selection.getNode().id;
+                       equal(actual, expectedId);
+                       start();
+               };
+       }
+
+       var initTinyFunction = function() {
+               tinymce.init({
+                       mode : "exact",
+                       plugins: 'table',
+                       elements : "elm1",
+                       indent: false,
+                       init_instance_callback : function(ed) {
+                               editor = ed;
+                               editor.setContent(defaultTableContent);
+                       }
+               });
+       }
+</script>
+</head>
+<body>
+<h1 id="qunit-header">Webkit Quirks</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="content">
+<textarea id="elm1" name="elm1"></textarea>
+
+<div>
+       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent({format : 'raw'}));">[getRawContents]</a>
+       <a href="javascript:alert(tinymce.EditorManager.get('elm1').getContent());">[getContents]</a>
+</div>
+</div>
+<script>
+initWhenTinyAndRobotAreReady(initTinyFunction);
+</script>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilURIhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/URI.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/URI.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/URI.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,111 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.util.URI tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.util.URI");
+
+QUnit.config.reorder = false;
+
+var URI = tinymce.util.URI;
+
+test('protocol relative url', function() {
+       var uri = new URI('//www.site.com/dir1/file?query#hash');
+
+       equal(uri.protocol, "");
+       equal(uri.host, "www.site.com");
+       equal(uri.path, "/dir1/file");
+       equal(uri.query, "query");
+       equal(uri.anchor, "hash");
+       equal(uri.source, "//www.site.com/dir1/file?query#hash");
+       equal(uri.getURI(), "//www.site.com/dir1/file?query#hash");
+       equal(uri.toRelative('//www.site.com/dir1/file2'), 'file2');
+       equal(uri.toRelative('//www.site2.com/dir1/file2'), '//www.site2.com/dir1/file2');
+       equal(uri.toAbsolute('../file2'), '//www.site.com/dir1/file2');
+       equal(uri.toAbsolute('//www.site2.com/dir1/file2'), '//www.site2.com/dir1/file2');
+});
+
+test('parseFullURLs', 3, function() {
+       equal(new URI('http://abc:123@www.site.com:8080/path/dir/file.ext?key1=val1&key2=val2#hash').getURI(), 'http://abc:123@www.site.com:8080/path/dir/file.ext?key1=val1&key2=val2#hash');
+       ok(new URI('http://a2bc:123@www.site.com:8080/path/dir/file.ext?key1=val1&key2=val2#hash').getURI() != 'http://abc:123@www.site.com:8080/path/dir/file.ext?key1=val1&key2=val2#hash');
+       equal(new URI('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890:8080/path/dir/file.ext?key1=val1&key2=val2#hash').getURI(), 'chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890:8080/path/dir/file.ext?key1=val1&key2=val2#hash');
+});
+
+test('relativeURLs', 29, function() {
+       equal(new URI('http://www.site.com/dir1/dir2/file.html').toRelative('http://www.site.com/dir1/dir3/file.html'), '../dir3/file.html');
+       equal(new URI('http://www.site.com/dir1/dir2/file.html').toRelative('http://www.site.com/dir3/dir4/file.html'), '../../dir3/dir4/file.html');
+       equal(new URI('http://www.site.com/dir1/').toRelative('http://www.site.com/dir1/dir3/file.htm'), 'dir3/file.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('http://www.site2.com/dir1/dir3/file.htm'), 'http://www.site2.com/dir1/dir3/file.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('http://www.site.com:8080/dir1/dir3/file.htm'), 'http://www.site.com:8080/dir1/dir3/file.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('https://www.site.com/dir1/dir3/file.htm'), 'https://www.site.com/dir1/dir3/file.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('/file.htm'), '../../file.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('/file.htm?id=1#a'), '../../file.htm?id=1#a');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('mailto:test@test.com'), 'mailto:test@test.com');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('news:test'), 'news:test');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('javascript:void(0);'), 'javascript:void(0);');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('about:blank'), 'about:blank');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('#test'), '#test');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('test.htm'), 'test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('http://www.site.com/dir1/dir2/test.htm'), 'test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('dir2/test.htm'), 'dir2/test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('../dir2/test.htm'), 'test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('../dir3/'), '../dir3/');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('../../../../../../test.htm'), '../../test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('//www.site.com/test.htm'), '../../test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('@@tinymce'), '@@tinymce'); // Zope 3 URL
+       equal(new URI('http://www.site.com/dir1/dir2/').toRelative('../@@tinymce'), '../@@tinymce'); // Zope 3 URL
+       equal(new URI('http://www.site.com/').toRelative('dir2/test.htm'), 'dir2/test.htm');
+       equal(new URI('http://www.site.com/').toRelative('./'), './');
+       equal(new URI('http://www.site.com/test/').toRelative('../'), '../');
+       equal(new URI('http://www.site.com/test/test/').toRelative('../'), '../');
+       equal(new URI('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890/dir1/dir2/').toRelative('/dir1', true), '../');
+       equal(new URI('http://www.site.com/').toRelative('http://www.site.com/'), 'http://www.site.com/');
+       equal(new URI('http://www.site.com/').toRelative('http://www.site.com'), 'http://www.site.com/');
+});
+
+test('absoluteURLs', 18, function() {
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('../dir3'), 'http://www.site.com/dir1/dir3');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('../dir3', 1), '/dir1/dir3');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('../../../../dir3'), 'http://www.site.com/dir3');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('../abc/def/../../abc/../dir3/file.htm'), 'http://www.site.com/dir1/dir3/file.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('http://www.site.com/dir2/dir3'), 'http://www.site.com/dir2/dir3');
+       equal(new URI('http://www.site2.com/dir1/dir2/').toAbsolute('http://www.site2.com/dir2/dir3'), 'http://www.site2.com/dir2/dir3');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('mailto:test@test.com'), 'mailto:test@test.com');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('news:test'), 'news:test');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('javascript:void(0);'), 'javascript:void(0);');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('about:blank'), 'about:blank');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('#test'), '#test');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('test.htm'), 'http://www.site.com/dir1/dir2/test.htm');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('../@@tinymce'), 'http://www.site.com/dir1/@@tinymce'); // Zope 3 URL
+       equal(new URI('http://www.site.com/dir1/dir2/').getURI(), 'http://www.site.com/dir1/dir2/');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('/dir1/dir1/'), 'http://www.site.com/dir1/dir1/');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('https://www.site.com/dir1/dir2/', true), 'https://www.site.com/dir1/dir2/');
+       equal(new URI('http://www.site.com/dir1/dir2/').toAbsolute('http://www.site.com/dir1/dir2/', true), '/dir1/dir2/');
+       equal(new URI('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890/dir1/dir2/').toAbsolute('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890/dir1/dir2/', true), '/dir1/dir2/');
+});
+
+test('strangeURLs', 6, function() {
+       equal(new URI('//www.site.com').getURI(), '//www.site.com');
+       equal(new URI('mailto:test@test.com').getURI(), 'mailto:test@test.com');
+       equal(new URI('news:somegroup').getURI(), 'news:somegroup');
+       equal(new URI('skype:somegroup').getURI(), 'skype:somegroup');
+       equal(new URI('tel:somegroup').getURI(), 'tel:somegroup');
+       equal(new URI('//www.site.com/a@b').getURI(), '//www.site.com/a@b');
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.html.Entities tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/URI.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutilXHRhtml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/XHR.html (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/XHR.html                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/XHR.html      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>tinymce.util.XHR tests</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
+<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
+<script src="../../js/qunit/reporter.js"></script>
+<script src="../../js/utils.js"></script>
+<script src="../../js/tinymce_loader.js"></script>
+<script>
+module("tinymce.util.XHR");
+
+QUnit.config.reorder = false;
+
+asyncTest("Successful request", function() {
+       expect(3);
+
+       tinymce.util.XHR.send({
+               url : 'json_rpc_ok.js',
+               success: function(data, xhr, input) {
+                       equal(tinymce.trim(data), '{"result": "Hello JSON-RPC", "error": null, "id": 1}');
+                       ok(!!xhr.status);
+                       equal(input.url, 'json_rpc_ok.js');
+                       start();
+               }
+       });
+});
+
+asyncTest("Unsuccessful request", function() {
+       expect(3);
+
+       tinymce.util.XHR.send({
+               url : '404.js',
+               error: function(type, xhr, input) {
+                       equal(type, 'GENERAL');
+                       ok(!!xhr.status);
+                       equal(input.url, '404.js');
+                       start();
+               }
+       });
+});
+</script>
+</head>
+<body>
+       <h1 id="qunit-header">tinymce.util.XHR tests</h1>
+       <h2 id="qunit-banner"></h2>
+       <div id="qunit-testrunner-toolbar"></div>
+       <h2 id="qunit-userAgent"></h2>
+       <ol id="qunit-tests"></ol>
+       <div id="content"></div>
+</body>
+</html>
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/XHR.html
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutiljson_rpc_errorjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/json_rpc_error.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/json_rpc_error.js                          (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/json_rpc_error.js     2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+{"result": null, "error": {"message":"General failure","code":42}, "id": 1}
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/json_rpc_error.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutiljson_rpc_okjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/json_rpc_ok.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/json_rpc_ok.js                             (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/json_rpc_ok.js        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+{"result": "Hello JSON-RPC", "error": null, "id": 1}
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/json_rpc_ok.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsquniteditortinymceutiltestxml"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/test.xml (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/test.xml                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/test.xml      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+<?xml version="1.0" encoding="ISO-8859-1"?>
+<root>
+       <tag>
+               \xC5\xC4\xD6
+       </tag>
+</root>
</ins></span></pre></div>
<a id="trunktestsquniteditortinymceutiltestsjs"></a>
<div class="addfile"><h4>Added: trunk/tests/qunit/editor/tinymce/util/tests.js (0 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/editor/tinymce/util/tests.js                           (rev 0)
+++ trunk/tests/qunit/editor/tinymce/util/tests.js      2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+{
+       "title": "tinymce.util",
+       "tests": [
+               {"title": "JSON", "url": "JSON.html"},
+               {"title": "JSONRequest", "url": "JSONRequest.html"},
+               {"title": "LocalStorage", "url": "LocalStorage.html"},
+               {"title": "URI", "url": "URI.html"},
+               {"title": "XHR", "url": "XHR.html"},
+               {"title": "All browser types", "url": "Quirks_all.html", "jsrobot": true},
+               {"title": "Quirks (Firefox)", "url": "Quirks_firefox.html", "jsrobot": true},
+               {"title": "Quirks (IE 8)", "url": "Quirks_ie8.html", "jsrobot": true},
+               {"title": "Quirks (Webkit)", "url": "Quirks_webkit.html"},
+               {"title": "Quirks JSRobot (Webkit)", "url": "Quirks_webkit_jsrobot.html", "jsrobot": true},
+               {"title": "Quirks (Remove)", "url": "Quirks_remove.html", "jsrobot": true}
+       ]
+}
</ins><span class="cx">Property changes on: trunk/tests/qunit/editor/tinymce/util/tests.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="trunktestsqunitindexhtml"></a>
<div class="modfile"><h4>Modified: trunk/tests/qunit/index.html (27154 => 27155)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/tests/qunit/index.html     2014-02-09 22:33:56 UTC (rev 27154)
+++ trunk/tests/qunit/index.html        2014-02-10 01:11:25 UTC (rev 27155)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx">     <h2 id="qunit-userAgent"></h2>
</span><span class="cx">     <ol id="qunit-tests"></ol>
</span><span class="cx">     <div id="qunit-fixture"></div>
</span><ins>+    <p><a href="editor">TinyMCE tests</a></p>
</ins><span class="cx">   </div>
</span><span class="cx"> </body>
</span><span class="cx"> </html>
</span></span></pre>
</div>
</div>

</body>
</html>