<!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, '<').replace(/>/g, '>');
+
+ // 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:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};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 ? ' ' : '<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 ? ' ' : '<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?" ":'<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]&
;&(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"
;===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?" ":'<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 "&";
+ case "\\": return "\\\\";
+ case '"': return '\"';
+ case "<": return "<";
+ case ">": return ">";
+ 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 ? ' ' : ' ';
+ },
+ 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,' ');
+ 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 ? '<' : '<',
+ close = this.HTML ? '>' : '>';
+
+ 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> <\/p>\n?/, '').replace(/\n?<p> <\/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| )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| )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| )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| )Test</p>$'));
+ TypingHTTPURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s| )Test</h1>$'));
+ TypingHTTPURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.ephox.com">http://www.ephox.com</a>(\\s| )Test</td><td> </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| )Test<br />Line 2</td><td> </td></tr></tbody></table>$'));
+
+ TypingEclipsedHTTPURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="http://www.ephox.com">http://www.ephox.com</a>\\)(\\s| )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| )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| )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| )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| )Test</p>$'));
+ TypingHTTPSURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s| )Test</h1>$'));
+ TypingHTTPSURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="https://www.ephox.com">https://www.ephox.com</a>(\\s| )Test</td><td> </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| )Test<br />Line 2</td><td> </td></tr></tbody></table>$'));
+
+ TypingEclipsedHTTPSURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="https://www.ephox.com">https://www.ephox.com</a>\\)(\\s| )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| )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| )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| )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| )Test</p>$'));
+ TypingSSHURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s| )Test</h1>$'));
+ TypingSSHURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="ssh://www.ephox.com">ssh://www.ephox.com</a>(\\s| )Test</td><td> </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| )Test<br />Line 2</td><td> </td></tr></tbody></table>$'));
+
+ TypingEclipsedSSHURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="ssh://www.ephox.com">ssh://www.ephox.com</a>\\)(\\s| )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| )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| )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| )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| )Test</p>$'));
+ TypingFTPURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s| )Test</h1>$'));
+ TypingFTPURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="ftp://www.ephox.com">ftp://www.ephox.com</a>(\\s| )Test</td><td> </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| )Test<br />Line 2</td><td> </td></tr></tbody></table>$'));
+
+ TypingEclipsedFTPURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="ftp://www.ephox.com">ftp://www.ephox.com</a>\\)(\\s| )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| )Test</p>$'));
+ TypingWWWURL.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="http://www.ephox.com">www.ephox.com</a>(\\s| )Test</p>$'));
+ TypingWWWURL.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="http://www.ephox.com">www.ephox.com</a>(\\s| )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| )Test</p>$'));
+ TypingWWWURL.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="http://www.ephox.com">www.ephox.com</a>(\\s| )Test</h1>$'));
+ TypingWWWURL.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.ephox.com">www.ephox.com</a>(\\s| )Test</td><td> </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| )Test<br />Line 2</td><td> </td></tr></tbody></table>$'));
+
+ TypingEclipsedWWWURL.inA(NonEmptyParagraph).gives(new RegExp('^<p>\\(<a href="http://www.ephox.com">www.ephox.com</a>\\)(\\s| )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| )Test</p>$'));
+ TypingWWWURLWithEndDot.inA(ParagraphWithMarginLeft).gives(new RegExp('^<p style="margin-left: 60px;"><a href="http://www.site.com">www.site.com</a>.(\\s| )Test</p>$'));
+ TypingWWWURLWithEndDot.inA(ParagraphWithPaddingLeft).gives(new RegExp('^<p style="padding-left: 60px;"><a href="http://www.site.com">www.site.com</a>.(\\s| )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| )Test</p>$'));
+ TypingWWWURLWithEndDot.inA(NonEmptyHeading).gives(new RegExp('^<h1><a href="http://www.site.com">www.site.com</a>.(\\s| )Test</h1>$'));
+ TypingWWWURLWithEndDot.inA(TableCellWithoutBrs2).gives(new RegExp('^<table><tbody><tr><td><a href="http://www.site.com">www.site.com</a>.(\\s| )Test</td><td> </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| )Test<br />Line 2</td><td> </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| )Test</p>$'));
+ TypingDashedMailAddr.inA(NonEmptyParagraph).gives(new RegExp('^<p><a href="mailto:first-last@domain.com">first-last@domain.com</a>(\\s| )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| )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> </td></tr></tbody></table>', 'td', 4);
+TableCellWithoutBrs2 = createState('<table><tbody><tr><td>Test</td><td> </td></tr></tbody></table>', 'td', 0);
+TableCellWithBrsFirstLine = createState('<table><tbody><tr><td>Test<br>Line 2</td><td> </td></tr></tbody></table>', 'td', 1);
+TableCellWithBrsFirstLine2 = createState('<table><tbody><tr><td>Test<br>Line 2</td><td> </td></tr></tbody></table>', 'td', 0);
+TableCellWithBrsMiddleLine = createState('<table><tbody><tr><td>Test<br/>Line 2<br/>Line 3</td><td> </td></tr></tbody></table>', 'td br:nth-child(1)', 'afterNextCharacter');
+TableCellWithBrsLastLine = createState('<table><tbody><tr><td>Test<br>Line 2</td><td> </td></tr></tbody></table>', 'td br:nth-child(1)', 'afterNextCharacter');
+TableCellWithAdjacentBrsFirstLine = createState('<table><tbody><tr><td>Test<br><br>Line 2</td><td> </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> </li><li>After</li></ol>', 'li:nth-child(2)', 0);
+EmptyUnorderedListItem = createState('<ul><li>Before</li><li> </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> </li></ol></li><li>After</li></ol>', 'li ol li', 0);
+NestedEmptyUnorderedListItem = createState('<ul><li>Before<ul><li> </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"> </div><div>a</div><div></div><div>b</div><div></div><div id="end"> </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/>
; <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="--"/> <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"/>
; <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"
; 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="">·<span style="font-family: "Times New Roman"; 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;">
; </span></span></span><!--[endif]-->Item 1</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--[endif]-->Item 2</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·
<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--[endif]-->Item 3</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--
[endif]-->Item 4</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--[endif]-->Item 5</p> <p class="MsoListParagraphCxSpLast" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </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 "Times New Roman""> </span></span></span><span lang="DE" style="font-family:Arial;mso-fareast-font-family:Arial;mso-bidi-font-family:Arial;color:black">Item Spaces.<o:p></o:p></span></p>'});
+ equal(editor.getContent().replace(/[\r\n]+/g, ''), '<ul><li>Item 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 "Times New Roman""> </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/>
; <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="--"/> <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"/>
; <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"
; 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="">·<span style="font-family: "Times New Roman"; 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;">
; </span></span></span><!--[endif]-->Item 1</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--[endif]-->Item 2</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·
<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--[endif]-->Item 3</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--
[endif]-->Item 4</p> <p class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </span></span></span><!--[endif]-->Item 5</p> <p class="MsoListParagraphCxSpLast" style="text-indent: -18pt;"><!--[if !supportLists]--><span style="font-family: Symbol;"><span style="">·<span style="font-family: "Times New Roman"; 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;"> </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"\'> </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/>
; <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="--"/> <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"/>
; <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"
; 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> </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> </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< & >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 /><b>b</b></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>( |<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> </caption>' +
+ '<tbody>' +
+ '<tr>' +
+ '<td> </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> </caption><tbody><tr><td>x</td></tr></tbody></table>'
+ );
+});
+
+test("Table properties dialog (remove caption)", function() {
+ editor.setContent('<table><caption> </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> </td></tr><tr><td>2</td><td> </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> </td><td>1</td></tr><tr><td> </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> </td><td> </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> </td><td> </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> </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’s my life – 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=""&<>">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=""&<>">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([^>]+|)>| /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([^>]+|)>| /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([^>]+|)>| /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([^>]+|)>| /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([^>]+|)>| /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 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<>"&'\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&<>"');
+ equal(DOM.decode('åäö&<>"'), '\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', '<>&" åäö');
+ equal(ser.serialize(DOM.get('test')), '<div id="test"><>&" åäö</div>');
+
+ ser = new tinymce.dom.Serializer({entity_encoding : 'named'});
+ DOM.setHTML('test', '<>&" åäö');
+ equal(ser.serialize(DOM.get('test')), '<div id="test"><>&" åäö</div>');
+
+ ser = new tinymce.dom.Serializer({entity_encoding : 'named+numeric', entities : '160,nbsp,34,quot,38,amp,60,lt,62,gt'});
+ DOM.setHTML('test', '<>&" åäö');
+ equal(ser.serialize(DOM.get('test')), '<div id="test"><>&" åäö</div>');
+
+ ser = new tinymce.dom.Serializer({entity_encoding : 'raw'});
+ DOM.setHTML('test', '<>&" åäö');
+ equal(ser.serialize(DOM.get('test')), '<div id="test"><>&"\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> </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'), '<>"\'&\u00e5\u00e4\u00f6', 'Raw encoding text');
+ equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&\u00e5\u00e4\u00f6', 'Raw encoding attribute');
+});
+
+test('encodeAllRaw', function() {
+ expect(1);
+
+ equal(tinymce.html.Entities.encodeAllRaw('<>"\'&\u00e5\u00e4\u00f6'), '<>"'&\u00e5\u00e4\u00f6', 'Raw encoding all');
+});
+
+test('encodeNumeric', function() {
+ expect(2);
+
+ equal(tinymce.html.Entities.encodeNumeric('<>"\'&\u00e5\u00e4\u00f6\u03b8\u2170\ufa11'), '<>"\'&åäöθⅰ﨑', 'Numeric encoding text');
+ equal(tinymce.html.Entities.encodeNumeric('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&åäö', 'Numeric encoding attribute');
+});
+
+test('encodeNamed', function() {
+ expect(4);
+
+ equal(tinymce.html.Entities.encodeNamed('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&åäö', 'Named encoding text');
+ equal(tinymce.html.Entities.encodeNamed('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&åäö', 'Named encoding attribute');
+ equal(tinymce.html.Entities.encodeNamed('<>"\'\u00e5\u00e4\u00f6', false, {'\u00e5' : 'å'}), '<>"\'å\u00e4\u00f6', 'Named encoding text');
+ equal(tinymce.html.Entities.encodeNamed('<>"\'\u00e5\u00e4\u00f6', true, {'\u00e5' : 'å'}), '<>"\'å\u00e4\u00f6', 'Named encoding attribute');
+});
+
+test('getEncodeFunc', function() {
+ var encodeFunc;
+
+ expect(10);
+
+ encodeFunc = tinymce.html.Entities.getEncodeFunc('raw');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&\u00e5\u00e4\u00f6', 'Raw encoding text');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&\u00e5\u00e4\u00f6', 'Raw encoding attribute');
+
+ encodeFunc = tinymce.html.Entities.getEncodeFunc('named');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&åäö', 'Named encoding text');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&åäö', 'Named encoding attribute');
+
+ encodeFunc = tinymce.html.Entities.getEncodeFunc('numeric');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&åäö', 'Named encoding text');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&åäö', 'Named encoding attribute');
+
+ encodeFunc = tinymce.html.Entities.getEncodeFunc('named+numeric', '229,aring');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&åäö', 'Named+numeric encoding text');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&åäö', 'Named+numeric encoding attribute');
+
+ encodeFunc = tinymce.html.Entities.getEncodeFunc('named,numeric', '229,aring');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&åäö', 'Named+numeric encoding text');
+ equal(encodeFunc('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&åäö', 'Named+numeric encoding attribute');
+});
+
+test('decode', function() {
+ expect(3);
+
+ equal(tinymce.html.Entities.decode('<>"'&åäö&unknown;'''), '<>"\'&\u00e5\u00e4\u00f6&unknown;\'\'', 'Decode text with various entities');
+
+ equal(tinymce.html.Entities.encodeNumeric(tinymce.html.Entities.decode(
+ '‚ƒ„…†‡ˆ‰Š' +
+ '‹ŒŽ‘’“”•–—˜' +
+ '™š›œžŸ')
+ ), '‚ƒ„…†‡ˆ‰Š‹ŒŽ' +
+ '‘’“”•–—˜™š' +
+ '›œžŸ',
+ 'Entity decode ascii');
+
+ equal(tinymce.html.Entities.encodeNumeric(tinymce.html.Entities.decode('你')), '你', "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=\'"&<>\'></b>');
+ equal(writer.getContent(), '<b href=""&<>"></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<t3</b></p>te>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="<test" data-test="test>"></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<text&');
+ 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: "&"')), "value: '&';");
+ 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<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<"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="<>"\'&\u00e5\u00e4\u00f6"><>"\'&\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="<>"\'&åäö"><>"\'&åäö</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="<>"\'&åäö"><>"\'&åäö</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> </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> </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> </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> </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> </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>