From 0898014ebd46e94f6e4c571358bb583f8f79c17b Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Mon, 24 Mar 2014 05:59:45 +0000 Subject: [PATCH] Update the TinyMCE tests. In 4.0.20 all tests were reworked. The 'testrunner' was removed and the PhantomJS Runner QUnit plugin was added making it possible to run the tests from cli. However it is still necessary to run the tests in all supported browsers to test the fixes for all browser quirks and normalization. Also all tests are loaded in one html file. See #27014 git-svn-id: https://develop.svn.wordpress.org/trunk@27679 602fd350-edb4-49c9-b593-d223f7449a82 --- .../editor/external-plugins/table/plugin.js | 2259 ------------- .../external-plugins/table/plugin.min.js | 1 - tests/qunit/editor/index.html | 104 +- tests/qunit/editor/js/init.js | 93 + tests/qunit/editor/js/qunit/qunit.css | 326 +- tests/qunit/editor/js/qunit/qunit.js | 2913 +++++++++++------ tests/qunit/editor/js/qunit/reporter.js | 13 - tests/qunit/editor/js/qunit/testrunner.css | 151 - tests/qunit/editor/js/qunit/testrunner.js | 543 --- tests/qunit/editor/js/runner.js | 148 + tests/qunit/editor/js/utils.js | 530 +-- tests/qunit/editor/plugins/autolink.html | 170 - .../plugins/{autosave.html => autosave.js} | 62 +- .../plugins/{fullpage.html => fullpage.js} | 103 +- tests/qunit/editor/plugins/jquery_plugin.html | 126 - tests/qunit/editor/plugins/jquery_plugin.js | 96 + .../editor/plugins/js/autolink.actions.js | 52 - tests/qunit/editor/plugins/js/dsl.js | 138 - tests/qunit/editor/plugins/js/states.js | 176 - .../{legacyoutput.html => legacyoutput.js} | 89 +- .../editor/plugins/{lists.html => lists.js} | 357 +- .../editor/plugins/{media.html => media.js} | 81 +- .../{noneditable.html => noneditable.js} | 135 +- .../editor/plugins/{paste.html => paste.js} | 109 +- .../plugins/plugin_dependency_chain.html | 59 - .../plugin_dependency_chain_legacy.html | 59 - .../plugin_dependency_init_call_order.html | 69 - .../plugin_dependency_specific_location.html | 58 - .../{searchreplace.html => searchreplace.js} | 65 +- tests/qunit/editor/plugins/spellchecker.html | 108 - tests/qunit/editor/plugins/spellchecker.js | 95 + .../editor/plugins/{table.html => table.js} | 148 +- tests/qunit/editor/plugins/table_robot.html | 189 -- tests/qunit/editor/plugins/tests.js | 24 - tests/qunit/editor/plugins/wordcount.html | 122 - tests/qunit/editor/plugins/wordcount.js | 81 + tests/qunit/editor/test.gif | Bin 43 -> 0 bytes .../editor/tinymce/{Editor.html => Editor.js} | 80 +- ...{EditorCommands.html => EditorCommands.js} | 159 +- .../tinymce/{EnterKey.html => EnterKey.js} | 686 ++-- tests/qunit/editor/tinymce/ForceBlocks.html | 116 - tests/qunit/editor/tinymce/ForceBlocks.js | 82 + ...ormatter_apply.html => Formatter_apply.js} | 1013 ++++-- ...ormatter_check.html => Formatter_check.js} | 190 +- ...matter_remove.html => Formatter_remove.js} | 157 +- .../qunit/editor/tinymce/Formatter_robot.html | 94 - .../{UndoManager.html => UndoManager.js} | 106 +- .../editor/tinymce/UndoManager_robot.html | 115 - tests/qunit/editor/tinymce/dom/DOMUtils.html | 27 - tests/qunit/editor/tinymce/dom/DOMUtils.js | 36 +- .../editor/tinymce/dom/DOMUtils_jquery.html | 29 - .../dom/{EventUtils.html => EventUtils.js} | 124 +- tests/qunit/editor/tinymce/dom/Range.html | 606 ---- tests/qunit/editor/tinymce/dom/Range.js | 548 ++++ .../dom/{Selection.html => Selection.js} | 89 +- .../dom/{Serializer.html => Serializer.js} | 53 +- ...dentSelection.html => TridentSelection.js} | 111 +- tests/qunit/editor/tinymce/dom/tests.js | 12 - .../qunit/editor/tinymce/html/DomParser.html | 506 --- tests/qunit/editor/tinymce/html/DomParser.js | 483 +++ .../html/{Entities.html => Entities.js} | 25 - .../tinymce/html/{Node.html => Node.js} | 32 +- .../html/{obsolete.html => Obsolete.js} | 128 +- .../qunit/editor/tinymce/html/SaxParser.html | 616 ---- tests/qunit/editor/tinymce/html/SaxParser.js | 637 ++++ .../tinymce/html/{Schema.html => Schema.js} | 203 +- .../html/{Serializer.html => Serializer.js} | 24 - .../tinymce/html/{Styles.html => Styles.js} | 24 - .../tinymce/html/{Writer.html => Writer.js} | 92 +- tests/qunit/editor/tinymce/html/tests.js | 14 - tests/qunit/editor/tinymce/tests.js | 15 - .../editor/tinymce/ui/AbsoluteLayout.html | 63 - .../qunit/editor/tinymce/ui/AbsoluteLayout.js | 31 + tests/qunit/editor/tinymce/ui/Button.html | 133 - tests/qunit/editor/tinymce/ui/Button.js | 104 + .../qunit/editor/tinymce/ui/ButtonGroup.html | 43 - tests/qunit/editor/tinymce/ui/Checkbox.html | 43 - tests/qunit/editor/tinymce/ui/Collection.html | 273 -- tests/qunit/editor/tinymce/ui/Collection.js | 253 ++ .../qunit/editor/tinymce/ui/ColorButton.html | 132 - tests/qunit/editor/tinymce/ui/ColorButton.js | 102 + tests/qunit/editor/tinymce/ui/ComboBox.html | 49 - tests/qunit/editor/tinymce/ui/Container.html | 43 - tests/qunit/editor/tinymce/ui/Control.html | 229 -- tests/qunit/editor/tinymce/ui/Control.js | 204 ++ tests/qunit/editor/tinymce/ui/DragHelper.html | 43 - .../qunit/editor/tinymce/ui/ElementPath.html | 43 - tests/qunit/editor/tinymce/ui/Factory.html | 43 - tests/qunit/editor/tinymce/ui/FieldSet.html | 43 - tests/qunit/editor/tinymce/ui/FilePicker.html | 43 - tests/qunit/editor/tinymce/ui/FitLayout.html | 87 - tests/qunit/editor/tinymce/ui/FitLayout.js | 57 + tests/qunit/editor/tinymce/ui/FlexLayout.html | 915 ------ tests/qunit/editor/tinymce/ui/FlexLayout.js | 884 +++++ tests/qunit/editor/tinymce/ui/FloatPanel.html | 43 - tests/qunit/editor/tinymce/ui/FlowLayout.html | 43 - tests/qunit/editor/tinymce/ui/Form.html | 43 - tests/qunit/editor/tinymce/ui/FormItem.html | 43 - tests/qunit/editor/tinymce/ui/GridLayout.html | 244 -- tests/qunit/editor/tinymce/ui/GridLayout.js | 212 ++ tests/qunit/editor/tinymce/ui/Iframe.html | 43 - .../editor/tinymce/ui/KeyboardNavigation.html | 43 - tests/qunit/editor/tinymce/ui/Label.html | 43 - tests/qunit/editor/tinymce/ui/Layout.html | 43 - tests/qunit/editor/tinymce/ui/ListBox.html | 43 - tests/qunit/editor/tinymce/ui/Menu.html | 43 - tests/qunit/editor/tinymce/ui/MenuBar.html | 43 - tests/qunit/editor/tinymce/ui/MenuButton.html | 139 - tests/qunit/editor/tinymce/ui/MenuButton.js | 108 + tests/qunit/editor/tinymce/ui/MenuItem.html | 43 - tests/qunit/editor/tinymce/ui/MessageBox.html | 43 - tests/qunit/editor/tinymce/ui/Movable.html | 43 - tests/qunit/editor/tinymce/ui/Panel.html | 67 - tests/qunit/editor/tinymce/ui/Panel.js | 38 + .../qunit/editor/tinymce/ui/PanelButton.html | 43 - tests/qunit/editor/tinymce/ui/Path.html | 43 - tests/qunit/editor/tinymce/ui/Radio.html | 43 - .../qunit/editor/tinymce/ui/ResizeHandle.html | 43 - tests/qunit/editor/tinymce/ui/Scrollable.html | 43 - tests/qunit/editor/tinymce/ui/Selector.html | 148 - tests/qunit/editor/tinymce/ui/Selector.js | 127 + tests/qunit/editor/tinymce/ui/Spacer.html | 43 - .../qunit/editor/tinymce/ui/SplitButton.html | 131 - tests/qunit/editor/tinymce/ui/SplitButton.js | 102 + .../qunit/editor/tinymce/ui/StackLayout.html | 43 - tests/qunit/editor/tinymce/ui/TabPanel.html | 164 - tests/qunit/editor/tinymce/ui/TabPanel.js | 133 + tests/qunit/editor/tinymce/ui/TextBox.html | 59 - tests/qunit/editor/tinymce/ui/TextBox.js | 29 + tests/qunit/editor/tinymce/ui/Throbber.html | 43 - tests/qunit/editor/tinymce/ui/Toolbar.html | 43 - tests/qunit/editor/tinymce/ui/Tooltip.html | 43 - tests/qunit/editor/tinymce/ui/Widget.html | 43 - tests/qunit/editor/tinymce/ui/Window.html | 118 - tests/qunit/editor/tinymce/ui/Window.js | 87 + tests/qunit/editor/tinymce/ui/tests.js | 55 - tests/qunit/editor/tinymce/util/JSON.html | 39 - tests/qunit/editor/tinymce/util/JSON.js | 31 + .../editor/tinymce/util/JSONRequest.html | 77 - .../qunit/editor/tinymce/util/JSONRequest.js | 55 + .../editor/tinymce/util/LocalStorage.html | 118 - .../qunit/editor/tinymce/util/LocalStorage.js | 99 + .../qunit/editor/tinymce/util/Quirks_all.html | 76 - .../editor/tinymce/util/Quirks_firefox.html | 75 - .../qunit/editor/tinymce/util/Quirks_ie8.html | 82 - .../editor/tinymce/util/Quirks_remove.html | 270 -- .../editor/tinymce/util/Quirks_webkit.html | 135 - .../editor/tinymce/util/Quirks_webkit.js | 98 + .../tinymce/util/Quirks_webkit_jsrobot.html | 205 -- tests/qunit/editor/tinymce/util/URI.html | 111 - tests/qunit/editor/tinymce/util/URI.js | 85 + tests/qunit/editor/tinymce/util/XHR.html | 53 - tests/qunit/editor/tinymce/util/XHR.js | 31 + tests/qunit/editor/tinymce/util/tests.js | 16 - 154 files changed, 9759 insertions(+), 15877 deletions(-) delete mode 100644 tests/qunit/editor/external-plugins/table/plugin.js delete mode 100644 tests/qunit/editor/external-plugins/table/plugin.min.js create mode 100644 tests/qunit/editor/js/init.js delete mode 100644 tests/qunit/editor/js/qunit/reporter.js delete mode 100644 tests/qunit/editor/js/qunit/testrunner.css delete mode 100644 tests/qunit/editor/js/qunit/testrunner.js create mode 100644 tests/qunit/editor/js/runner.js delete mode 100644 tests/qunit/editor/plugins/autolink.html rename tests/qunit/editor/plugins/{autosave.html => autosave.js} (60%) rename tests/qunit/editor/plugins/{fullpage.html => fullpage.js} (66%) delete mode 100644 tests/qunit/editor/plugins/jquery_plugin.html create mode 100644 tests/qunit/editor/plugins/jquery_plugin.js delete mode 100644 tests/qunit/editor/plugins/js/autolink.actions.js delete mode 100644 tests/qunit/editor/plugins/js/dsl.js delete mode 100644 tests/qunit/editor/plugins/js/states.js rename tests/qunit/editor/plugins/{legacyoutput.html => legacyoutput.js} (50%) rename tests/qunit/editor/plugins/{lists.html => lists.js} (82%) rename tests/qunit/editor/plugins/{media.html => media.js} (76%) rename tests/qunit/editor/plugins/{noneditable.html => noneditable.js} (54%) rename tests/qunit/editor/plugins/{paste.html => paste.js} (97%) delete mode 100644 tests/qunit/editor/plugins/plugin_dependency_chain.html delete mode 100644 tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html delete mode 100644 tests/qunit/editor/plugins/plugin_dependency_init_call_order.html delete mode 100644 tests/qunit/editor/plugins/plugin_dependency_specific_location.html rename tests/qunit/editor/plugins/{searchreplace.html => searchreplace.js} (70%) delete mode 100644 tests/qunit/editor/plugins/spellchecker.html create mode 100644 tests/qunit/editor/plugins/spellchecker.js rename tests/qunit/editor/plugins/{table.html => table.js} (74%) delete mode 100644 tests/qunit/editor/plugins/table_robot.html delete mode 100644 tests/qunit/editor/plugins/tests.js delete mode 100644 tests/qunit/editor/plugins/wordcount.html create mode 100644 tests/qunit/editor/plugins/wordcount.js delete mode 100644 tests/qunit/editor/test.gif rename tests/qunit/editor/tinymce/{Editor.html => Editor.js} (75%) rename tests/qunit/editor/tinymce/{EditorCommands.html => EditorCommands.js} (87%) rename tests/qunit/editor/tinymce/{EnterKey.html => EnterKey.js} (57%) delete mode 100644 tests/qunit/editor/tinymce/ForceBlocks.html create mode 100644 tests/qunit/editor/tinymce/ForceBlocks.js rename tests/qunit/editor/tinymce/{Formatter_apply.html => Formatter_apply.js} (72%) rename tests/qunit/editor/tinymce/{Formatter_check.html => Formatter_check.js} (50%) rename tests/qunit/editor/tinymce/{Formatter_remove.html => Formatter_remove.js} (76%) delete mode 100644 tests/qunit/editor/tinymce/Formatter_robot.html rename tests/qunit/editor/tinymce/{UndoManager.html => UndoManager.js} (55%) delete mode 100644 tests/qunit/editor/tinymce/UndoManager_robot.html delete mode 100644 tests/qunit/editor/tinymce/dom/DOMUtils.html delete mode 100644 tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html rename tests/qunit/editor/tinymce/dom/{EventUtils.html => EventUtils.js} (76%) delete mode 100644 tests/qunit/editor/tinymce/dom/Range.html create mode 100644 tests/qunit/editor/tinymce/dom/Range.js rename tests/qunit/editor/tinymce/dom/{Selection.html => Selection.js} (94%) rename tests/qunit/editor/tinymce/dom/{Serializer.html => Serializer.js} (92%) rename tests/qunit/editor/tinymce/dom/{TridentSelection.html => TridentSelection.js} (86%) delete mode 100644 tests/qunit/editor/tinymce/dom/tests.js delete mode 100644 tests/qunit/editor/tinymce/html/DomParser.html create mode 100644 tests/qunit/editor/tinymce/html/DomParser.js rename tests/qunit/editor/tinymce/html/{Entities.html => Entities.js} (84%) rename tests/qunit/editor/tinymce/html/{Node.html => Node.js} (94%) rename tests/qunit/editor/tinymce/html/{obsolete.html => Obsolete.js} (69%) delete mode 100644 tests/qunit/editor/tinymce/html/SaxParser.html create mode 100644 tests/qunit/editor/tinymce/html/SaxParser.js rename tests/qunit/editor/tinymce/html/{Schema.html => Schema.js} (72%) rename tests/qunit/editor/tinymce/html/{Serializer.html => Serializer.js} (59%) rename tests/qunit/editor/tinymce/html/{Styles.html => Styles.js} (90%) rename tests/qunit/editor/tinymce/html/{Writer.html => Writer.js} (62%) delete mode 100644 tests/qunit/editor/tinymce/html/tests.js delete mode 100644 tests/qunit/editor/tinymce/tests.js delete mode 100644 tests/qunit/editor/tinymce/ui/AbsoluteLayout.html create mode 100644 tests/qunit/editor/tinymce/ui/AbsoluteLayout.js delete mode 100644 tests/qunit/editor/tinymce/ui/Button.html create mode 100644 tests/qunit/editor/tinymce/ui/Button.js delete mode 100644 tests/qunit/editor/tinymce/ui/ButtonGroup.html delete mode 100644 tests/qunit/editor/tinymce/ui/Checkbox.html delete mode 100644 tests/qunit/editor/tinymce/ui/Collection.html create mode 100644 tests/qunit/editor/tinymce/ui/Collection.js delete mode 100644 tests/qunit/editor/tinymce/ui/ColorButton.html create mode 100644 tests/qunit/editor/tinymce/ui/ColorButton.js delete mode 100644 tests/qunit/editor/tinymce/ui/ComboBox.html delete mode 100644 tests/qunit/editor/tinymce/ui/Container.html delete mode 100644 tests/qunit/editor/tinymce/ui/Control.html create mode 100644 tests/qunit/editor/tinymce/ui/Control.js delete mode 100644 tests/qunit/editor/tinymce/ui/DragHelper.html delete mode 100644 tests/qunit/editor/tinymce/ui/ElementPath.html delete mode 100644 tests/qunit/editor/tinymce/ui/Factory.html delete mode 100644 tests/qunit/editor/tinymce/ui/FieldSet.html delete mode 100644 tests/qunit/editor/tinymce/ui/FilePicker.html delete mode 100644 tests/qunit/editor/tinymce/ui/FitLayout.html create mode 100644 tests/qunit/editor/tinymce/ui/FitLayout.js delete mode 100644 tests/qunit/editor/tinymce/ui/FlexLayout.html create mode 100644 tests/qunit/editor/tinymce/ui/FlexLayout.js delete mode 100644 tests/qunit/editor/tinymce/ui/FloatPanel.html delete mode 100644 tests/qunit/editor/tinymce/ui/FlowLayout.html delete mode 100644 tests/qunit/editor/tinymce/ui/Form.html delete mode 100644 tests/qunit/editor/tinymce/ui/FormItem.html delete mode 100644 tests/qunit/editor/tinymce/ui/GridLayout.html create mode 100644 tests/qunit/editor/tinymce/ui/GridLayout.js delete mode 100644 tests/qunit/editor/tinymce/ui/Iframe.html delete mode 100644 tests/qunit/editor/tinymce/ui/KeyboardNavigation.html delete mode 100644 tests/qunit/editor/tinymce/ui/Label.html delete mode 100644 tests/qunit/editor/tinymce/ui/Layout.html delete mode 100644 tests/qunit/editor/tinymce/ui/ListBox.html delete mode 100644 tests/qunit/editor/tinymce/ui/Menu.html delete mode 100644 tests/qunit/editor/tinymce/ui/MenuBar.html delete mode 100644 tests/qunit/editor/tinymce/ui/MenuButton.html create mode 100644 tests/qunit/editor/tinymce/ui/MenuButton.js delete mode 100644 tests/qunit/editor/tinymce/ui/MenuItem.html delete mode 100644 tests/qunit/editor/tinymce/ui/MessageBox.html delete mode 100644 tests/qunit/editor/tinymce/ui/Movable.html delete mode 100644 tests/qunit/editor/tinymce/ui/Panel.html create mode 100644 tests/qunit/editor/tinymce/ui/Panel.js delete mode 100644 tests/qunit/editor/tinymce/ui/PanelButton.html delete mode 100644 tests/qunit/editor/tinymce/ui/Path.html delete mode 100644 tests/qunit/editor/tinymce/ui/Radio.html delete mode 100644 tests/qunit/editor/tinymce/ui/ResizeHandle.html delete mode 100644 tests/qunit/editor/tinymce/ui/Scrollable.html delete mode 100644 tests/qunit/editor/tinymce/ui/Selector.html create mode 100644 tests/qunit/editor/tinymce/ui/Selector.js delete mode 100644 tests/qunit/editor/tinymce/ui/Spacer.html delete mode 100644 tests/qunit/editor/tinymce/ui/SplitButton.html create mode 100644 tests/qunit/editor/tinymce/ui/SplitButton.js delete mode 100644 tests/qunit/editor/tinymce/ui/StackLayout.html delete mode 100644 tests/qunit/editor/tinymce/ui/TabPanel.html create mode 100644 tests/qunit/editor/tinymce/ui/TabPanel.js delete mode 100644 tests/qunit/editor/tinymce/ui/TextBox.html create mode 100644 tests/qunit/editor/tinymce/ui/TextBox.js delete mode 100644 tests/qunit/editor/tinymce/ui/Throbber.html delete mode 100644 tests/qunit/editor/tinymce/ui/Toolbar.html delete mode 100644 tests/qunit/editor/tinymce/ui/Tooltip.html delete mode 100644 tests/qunit/editor/tinymce/ui/Widget.html delete mode 100644 tests/qunit/editor/tinymce/ui/Window.html create mode 100644 tests/qunit/editor/tinymce/ui/Window.js delete mode 100644 tests/qunit/editor/tinymce/ui/tests.js delete mode 100644 tests/qunit/editor/tinymce/util/JSON.html create mode 100644 tests/qunit/editor/tinymce/util/JSON.js delete mode 100644 tests/qunit/editor/tinymce/util/JSONRequest.html create mode 100644 tests/qunit/editor/tinymce/util/JSONRequest.js delete mode 100644 tests/qunit/editor/tinymce/util/LocalStorage.html create mode 100644 tests/qunit/editor/tinymce/util/LocalStorage.js delete mode 100644 tests/qunit/editor/tinymce/util/Quirks_all.html delete mode 100644 tests/qunit/editor/tinymce/util/Quirks_firefox.html delete mode 100644 tests/qunit/editor/tinymce/util/Quirks_ie8.html delete mode 100644 tests/qunit/editor/tinymce/util/Quirks_remove.html delete mode 100644 tests/qunit/editor/tinymce/util/Quirks_webkit.html create mode 100644 tests/qunit/editor/tinymce/util/Quirks_webkit.js delete mode 100644 tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html delete mode 100644 tests/qunit/editor/tinymce/util/URI.html create mode 100644 tests/qunit/editor/tinymce/util/URI.js delete mode 100644 tests/qunit/editor/tinymce/util/XHR.html create mode 100644 tests/qunit/editor/tinymce/util/XHR.js delete mode 100644 tests/qunit/editor/tinymce/util/tests.js diff --git a/tests/qunit/editor/external-plugins/table/plugin.js b/tests/qunit/editor/external-plugins/table/plugin.js deleted file mode 100644 index 729f48212a..0000000000 --- a/tests/qunit/editor/external-plugins/table/plugin.js +++ /dev/null @@ -1,2259 +0,0 @@ -/** - * 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') || (selectedCell && 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 ? ' ' : '
'; - } - - 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 = '
'; - } - } - - 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(); - - // If we have a valid startPos object - if (startPos) { - // 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, but make sure startPos is valid before accessing - if (startPos) { - 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; - } - }); - - // If posY is undefined there is nothing for us to do here...just return to avoid crashing below - if (posY === undefined) { - return; - } - - 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 ? ' ' : '
' - ); - } 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 ? '
' : '\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]; - - if (!cellElm) { - // If this element is null, return now to avoid crashing. - return; - } - - 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]; - if (!rowElm) { - // If this element is null, return now to avoid crashing. - return; - } - - 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 = ''; - - for (y = 0; y < rows; y++) { - html += ''; - - for (x = 0; x < cols; x++) { - html += ''; - } - - html += ''; - } - - html += '
' + (Env.ie ? " " : '
') + '
'; - - 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 = ''; - - for (var y = 0; y < 10; y++) { - html += ''; - - for (var x = 0; x < 10; x++) { - html += ''; - } - - html += ''; - } - - html += '
'; - - html += ''; - - return html; - } - - function selectGrid(tx, ty, control) { - var table = control.getEl().getElementsByTagName('table')[0]; - var rel = control.parent().rel, x, y, focusCell, cell; - - if (control.isRtl() || rel == 'tl-tr') { - for (y = 9; y >= 0; y--) { - for (x = 0; x < 10; x++) { - cell = table.rows[y].childNodes[x].firstChild; - - editor.dom.toggleClass( - cell, - 'mce-active', - x >= tx && y <= ty - ); - - if (x >= tx && y <= ty) { - focusCell = cell; - } - } - } - - tx = 9 - tx; - table.nextSibling.innerHTML = tx + ' x '+ (ty + 1); - } else { - for (y = 0; y < 10; y++) { - for (x = 0; x < 10; x++) { - cell = table.rows[y].childNodes[x].firstChild; - - editor.dom.toggleClass( - cell, - 'mce-active', - x <= tx && y <= ty - ); - - if (x <= tx && y <= ty) { - focusCell = cell; - } - } - } - - table.nextSibling.innerHTML = (tx + 1) + ' x '+ (ty + 1); - } - - return focusCell.parentNode; - } - - editor.addMenuItem('inserttable', { - text: 'Insert table', - icon: 'table', - context: 'table', - onhide: function() { - var elements = this.menu.items()[0].getEl().getElementsByTagName('a'); - editor.dom.removeClass(elements, 'mce-active'); - editor.dom.addClass(elements[0], 'mce-active'); - }, - menu: [ - { - type: 'container', - html: generateTableGrid(), - - onPostRender: function() { - this.lastX = this.lastY = 0; - }, - - onmousemove: function(e) { - var target = e.target, x, y; - - if (target.nodeName == 'A') { - x = parseInt(target.getAttribute('data-mce-x'), 10); - y = parseInt(target.getAttribute('data-mce-y'), 10); - - if (x !== this.lastX || y !== this.lastY) { - selectGrid(x, y, e.control); - - this.lastX = x; - this.lastY = y; - } - } - }, - - onkeydown: function(e) { - var x = this.lastX, y = this.lastY, isHandled; - - switch (e.keyCode) { - case 37: // DOM_VK_LEFT - if (x > 0) { - x--; - isHandled = true; - } - break; - - case 39: // DOM_VK_RIGHT - isHandled = true; - - if (x < 9) { - x++; - } - break; - - case 38: // DOM_VK_UP - isHandled = true; - - if (y > 0) { - y--; - } - break; - - case 40: // DOM_VK_DOWN - isHandled = true; - - if (y < 9) { - y++; - } - break; - } - - if (isHandled) { - e.preventDefault(); - e.stopPropagation(); - - selectGrid(x, y, e.control).focus(); - - this.lastX = x; - this.lastY = y; - } - }, - - onclick: function(e) { - if (e.target.nodeName == 'A') { - e.preventDefault(); - e.stopPropagation(); - this.parent().cancel(); - - insertTable(this.lastX + 1, this.lastY + 1); - } - } - } - ] - }); - - 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); \ No newline at end of file diff --git a/tests/qunit/editor/external-plugins/table/plugin.min.js b/tests/qunit/editor/external-plugins/table/plugin.min.js deleted file mode 100644 index 1e2d1d8438..0000000000 --- a/tests/qunit/editor/external-plugins/table/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;i "+t+" tr",a);i(n,function(n,o){o+=e,i(H.select("> td, > th",n),function(e,n){var i,a,s,l;if(A[o])for(;A[o][n];)n++;for(s=r(e,"rowspan"),l=r(e,"colspan"),a=o;o+s>a;a++)for(A[a]||(A[a]=[]),i=n;n+l>i;i++)A[a][i]={part:t,real:a==o&&i==n,elm:e,rowspan:s,colspan:l}})}),e+=n.length})}function l(e,t){return e=e.cloneNode(t),e.removeAttribute("id"),e}function c(e,t){var n;return n=A[t],n?n[e]:void 0}function d(e,t,n){e&&(n=parseInt(n,10),1===n?e.removeAttribute(t,1):e.setAttribute(t,n,1))}function u(e){return e&&(H.hasClass(e.elm,"mce-item-selected")||e==L)}function f(){var e=[];return i(a.rows,function(t){i(t.cells,function(n){return H.hasClass(n,"mce-item-selected")||L&&n==L.elm?(e.push(t),!1):void 0})}),e}function p(){var e=H.createRng();e.setStartAfter(a),e.setEndAfter(a),M.setRng(e),H.remove(a)}function m(t){var r,a={};return o.settings.table_clone_elements!==!1&&(a=e.makeMap((o.settings.table_clone_elements||"strong em b i span font h1 h2 h3 h4 h5 h6 p div").toUpperCase(),/[ ,]/)),e.walk(t,function(e){var o;return 3==e.nodeType?(i(H.getParents(e.parentNode,null,t).reverse(),function(e){a[e.nodeName]&&(e=l(e,!1),r?o&&o.appendChild(e):r=o=e,o=e)}),o&&(o.innerHTML=n.ie?" ":'
'),!1):void 0},"childNodes"),t=l(t,!1),d(t,"rowSpan",1),d(t,"colSpan",1),r?t.appendChild(r):n.ie||(t.innerHTML='
'),t}function h(){var e=H.createRng(),t;return i(H.select("tr",a),function(e){0===e.cells.length&&H.remove(e)}),0===H.select("tr",a).length?(e.setStartBefore(a),e.setEndBefore(a),M.setRng(e),void H.remove(a)):(i(H.select("thead,tbody,tfoot",a),function(e){0===e.rows.length&&H.remove(e)}),s(),void(B&&(t=A[Math.min(A.length-1,B.y)],t&&(M.select(t[Math.min(t.length-1,B.x)].elm,!0),M.collapse(!0)))))}function g(e,t,n,r){var i,o,a,s,l;for(i=A[t][e].elm.parentNode,a=1;n>=a;a++)if(i=H.getNext(i,"tr")){for(o=e;o>=0;o--)if(l=A[t+a][o].elm,l.parentNode==i){for(s=1;r>=s;s++)H.insertAfter(m(l),l);break}if(-1==o)for(s=1;r>=s;s++)i.insertBefore(m(i.cells[0]),i.cells[0])}}function v(){i(A,function(e,t){i(e,function(e,n){var i,o,a;if(u(e)&&(e=e.elm,i=r(e,"colspan"),o=r(e,"rowspan"),i>1||o>1)){for(d(e,"rowSpan",1),d(e,"colSpan",1),a=0;i-1>a;a++)H.insertAfter(m(e),e);g(n,t,o-1,i)}})})}function y(t,n,r){var o,a,l,f,p,m,g,y,b,C,x;if(t?(o=S(t),a=o.x,l=o.y,f=a+(n-1),p=l+(r-1)):(B=P=null,i(A,function(e,t){i(e,function(e,n){u(e)&&(B||(B={x:n,y:t}),P={x:n,y:t})})}),B&&(a=B.x,l=B.y,f=P.x,p=P.y)),y=c(a,l),b=c(f,p),y&&b&&y.part==b.part){for(v(),s(),y=c(a,l).elm,d(y,"colSpan",f-a+1),d(y,"rowSpan",p-l+1),g=l;p>=g;g++)for(m=a;f>=m;m++)A[g]&&A[g][m]&&(t=A[g][m].elm,t!=y&&(C=e.grep(t.childNodes),i(C,function(e){y.appendChild(e)}),C.length&&(C=e.grep(y.childNodes),x=0,i(C,function(e){"BR"==e.nodeName&&H.getAttrib(e,"data-mce-bogus")&&x++0&&A[n-1][s]&&(h=A[n-1][s].elm,g=r(h,"rowSpan"),g>1)){d(h,"rowSpan",g+1);continue}}else if(g=r(o,"rowspan"),g>1){d(o,"rowSpan",g+1);continue}p=m(o),d(p,"colSpan",o.colSpan),f.appendChild(p),a=o}f.hasChildNodes()&&(e?c.parentNode.insertBefore(f,c):H.insertAfter(f,c))}}function C(e){var t,n;i(A,function(n){return i(n,function(n,r){return u(n)&&(t=r,e)?!1:void 0}),e?!t:void 0}),i(A,function(i,o){var a,s,l;i[t]&&(a=i[t].elm,a!=n&&(l=r(a,"colspan"),s=r(a,"rowspan"),1==l?e?(a.parentNode.insertBefore(m(a),a),g(t,o,s-1,l)):(H.insertAfter(m(a),a),g(t,o,s-1,l)):d(a,"colSpan",a.colSpan+1),n=a))})}function x(){var t=[];i(A,function(n){i(n,function(n,o){u(n)&&-1===e.inArray(t,o)&&(i(A,function(e){var t=e[o].elm,n;n=r(t,"colSpan"),n>1?d(t,"colSpan",n-1):H.remove(t)}),t.push(o))})}),h()}function w(){function e(e){var t,n,o;t=H.getNext(e,"tr"),i(e.cells,function(e){var t=r(e,"rowSpan");t>1&&(d(e,"rowSpan",t-1),n=S(e),g(n.x,n.y,1,1))}),n=S(e.cells[0]),i(A[n.y],function(e){var t;e=e.elm,e!=o&&(t=r(e,"rowSpan"),1>=t?H.remove(e):d(e,"rowSpan",t-1),o=e)})}var t;t=f(),i(t.reverse(),function(t){e(t)}),h()}function _(){var e=f();return H.remove(e),h(),e}function N(){var e=f();return i(e,function(t,n){e[n]=l(t,!0)}),e}function k(e,t){var n=f(),r=n[t?0:n.length-1],o=r.cells.length;e&&(i(A,function(e){var t;return o=0,i(e,function(e){e.real&&(o+=e.colspan),e.elm.parentNode==r&&(t=1)}),t?!1:void 0}),t||e.reverse(),i(e,function(e){var n,i=e.cells.length,a;for(n=0;i>n;n++)a=e.cells[n],d(a,"colSpan",1),d(a,"rowSpan",1);for(n=i;o>n;n++)e.appendChild(m(e.cells[i-1]));for(n=o;i>n;n++)H.remove(e.cells[n]);t?r.parentNode.insertBefore(e,r):H.insertAfter(e,r)}),H.removeClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"))}function S(e){var t;return i(A,function(n,r){return i(n,function(n,i){return n.elm==e?(t={x:i,y:r},!1):void 0}),!t}),t}function E(e){B=S(e)}function T(){var e,t;return e=t=0,i(A,function(n,r){i(n,function(n,i){var o,a;u(n)&&(n=A[r][i],i>e&&(e=i),r>t&&(t=r),n.real&&(o=n.colspan-1,a=n.rowspan-1,o&&i+o>e&&(e=i+o),a&&r+a>t&&(t=r+a)))})}),{x:e,y:t}}function R(e){var t,n,r,i,o,a,s,l,c,d;if(P=S(e),B&&P){for(t=Math.min(B.x,P.x),n=Math.min(B.y,P.y),r=Math.max(B.x,P.x),i=Math.max(B.y,P.y),o=r,a=i,d=n;a>=d;d++)e=A[d][t],e.real||t-(e.colspan-1)=c;c++)e=A[n][c],e.real||n-(e.rowspan-1)=d;d++)for(c=t;r>=c;c++)e=A[d][c],e.real&&(s=e.colspan-1,l=e.rowspan-1,s&&c+s>o&&(o=c+s),l&&d+l>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++)A[d][c]&&H.addClass(A[d][c].elm,"mce-item-selected")}}var A,B,P,L,M=o.selection,H=M.dom;a=a||H.getParent(M.getStart(),"table"),s(),L=H.getParent(M.getStart(),"th,td"),L&&(B=S(L),P=T(),L=c(B.x,B.y)),e.extend(this,{deleteTable:p,split:v,merge:y,insertRow:b,insertCol:C,deleteCols:x,deleteRows:w,cutRows:_,copyRows:N,pasteRows:k,getPos:S,setStartCell:E,setEndCell:R})}}),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.endContainer,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&&t.ie<11?" ":'
'):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)&&("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 void(r?i.setStart(e,0):i.setEnd(e,e.nodeValue.length));if("BR"==e.nodeName)return void(r?i.setStartBefore(e):i.setEndBefore(e))}while(e=r?o.next():o.prev())}var i,o=r.selection,d,u,f,p,m;if(l){if(s&&(r.getBody().style.webkitUserSelect=""),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")||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:"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":'
',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:"rows",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],t&&(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],o&&(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.create(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="",n=0;t>n;n++){for(a+="",i=0;e>i;i++)a+="";a+=""}a+="
"+(o.ie?" ":"
")+"
",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='';for(var t=0;10>t;t++){e+="";for(var n=0;10>n;n++)e+='";e+=""}return e+="
",e+=''}function b(e,t,n){var i=n.getEl().getElementsByTagName("table")[0],o=n.parent().rel,a,s,l,c;if(n.isRtl()||"tl-tr"==o){for(s=9;s>=0;s--)for(a=0;10>a;a++)c=i.rows[s].childNodes[a].firstChild,r.dom.toggleClass(c,"mce-active",a>=e&&t>=s),a>=e&&t>=s&&(l=c);e=9-e,i.nextSibling.innerHTML=e+" x "+(t+1)}else{for(s=0;10>s;s++)for(a=0;10>a;a++)c=i.rows[s].childNodes[a].firstChild,r.dom.toggleClass(c,"mce-active",e>=a&&t>=s),e>=a&&t>=s&&(l=c);i.nextSibling.innerHTML=e+1+" x "+(t+1)}return l.parentNode}var C,x,w=this;r.addMenuItem("inserttable",{text:"Insert table",icon:"table",context:"table",onhide:function(){var e=this.menu.items()[0].getEl().getElementsByTagName("a");r.dom.removeClass(e,"mce-active"),r.dom.addClass(e[0],"mce-active")},menu:[{type:"container",html:y(),onPostRender:function(){this.lastX=this.lastY=0},onmousemove:function(e){var t=e.target,n,r;"A"==t.nodeName&&(n=parseInt(t.getAttribute("data-mce-x"),10),r=parseInt(t.getAttribute("data-mce-y"),10),(n!==this.lastX||r!==this.lastY)&&(b(n,r,e.control),this.lastX=n,this.lastY=r))},onkeydown:function(e){var t=this.lastX,n=this.lastY,r;switch(e.keyCode){case 37:t>0&&(t--,r=!0);break;case 39:r=!0,9>t&&t++;break;case 38:r=!0,n>0&&n--;break;case 40:r=!0,9>n&&n++}r&&(e.preventDefault(),e.stopPropagation(),b(t,n,e.control).focus(),this.lastX=t,this.lastY=n)},onclick:function(e){"A"==e.target.nodeName&&(e.preventDefault(),e.stopPropagation(),this.parent().cancel(),m(this.lastX+1,this.lastY+1))}}]}),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"),onPostRender: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 _=[];l("inserttable tableprops deletetable | cell row column".split(" "),function(e){_.push("|"==e?{text:"-"}:r.menuItems[e])}),r.addButton("table",{type:"menubutton",title:"Table",menu:_}),o.isIE||r.on("click",function(e){e=e.target,"TABLE"===e.nodeName&&(r.selection.select(e),r.nodeChanged())}),w.quirks=new t(r),r.on("Init",function(){C=r.windowManager,w.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){x=e.cutRows()},mceTableCopyRow:function(e){x=e.copyRows()},mceTablePasteRowBefore:function(e){e.pasteRows(x,!0)},mceTablePasteRowAfter:function(e){e.pasteRows(x)},mceTableDelete:function(e){e.deleteTable()}},function(t,n){r.addCommand(n,function(){var n=new e(r);n&&(t(n),r.execCommand("mceRepaint"),w.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.add("table",s)}),a([l,u,p,h])}(this); \ No newline at end of file diff --git a/tests/qunit/editor/index.html b/tests/qunit/editor/index.html index 2faaa077a3..081fc6d45c 100644 --- a/tests/qunit/editor/index.html +++ b/tests/qunit/editor/index.html @@ -1,22 +1,96 @@ - -Test Runner - - - - + + TinyMCE QUnit tests + + + QUnit tests + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/qunit/editor/js/init.js b/tests/qunit/editor/js/init.js new file mode 100644 index 0000000000..fa603dc7f5 --- /dev/null +++ b/tests/qunit/editor/js/init.js @@ -0,0 +1,93 @@ +(function() { + var coverObjects = [], modulesExecuted = {}; + + QUnit.config.reorder = false; + + var oldModule = module; + + QUnit.moduleStart(function(details) { + modulesExecuted[details.name] = true; + + tinymce.remove(); + document.getElementById('view').innerHTML = ''; + }); + + QUnit.moduleDone(function() { + tinymce.remove(); + window.editor = window.inlineEditor = null; + }); + + QUnit.done(function() { + document.getElementById("view").style.display = 'none'; + + if (window.__$coverObject) { + coverObjects.push(window.__$coverObject); + + $('').on('click', function() { + window.open('coverage/index.html', 'coverage'); + }).appendTo(document.body); + } + }); + + window.module = function(name, settings) { + settings = settings || {}; + + if (settings.setupModule) { + QUnit.moduleStart(function(details) { + if (details.name == name) { + settings.setupModule(); + } + }); + } + + if (settings.teardownModule) { + QUnit.moduleDone(function(details) { + if (details.name == name) { + settings.teardownModule(); + } + }); + } + + oldModule(name, settings); + }; + + window.getCoverObject = function() { + var coverObject = {}, fileName, gaps, gap, count, targetModuleName; + var isScoped = document.location.search.indexOf('module=') != -1; + + for (var i = 0, length = coverObjects.length; i < length; i++) { + for (fileName in coverObjects[i]) { + gaps = coverObjects[i][fileName]; + + if (isScoped && fileName.indexOf('js/tinymce/classes') === 0) { + targetModuleName = "tinymce." + fileName.substr('js/tinymce/classes'.length + 1).replace(/\//g, '.'); + targetModuleName = targetModuleName.replace(/\.js$/, ''); + + if (!modulesExecuted[targetModuleName]) { + continue; + } + } + + 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; + }; +})(); diff --git a/tests/qunit/editor/js/qunit/qunit.css b/tests/qunit/editor/js/qunit/qunit.css index 5714bf4a59..93026e3ba3 100644 --- a/tests/qunit/editor/js/qunit/qunit.css +++ b/tests/qunit/editor/js/qunit/qunit.css @@ -1,119 +1,237 @@ +/*! + * QUnit 1.14.0 + * http://qunitjs.com/ + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-01-31T16:40Z + */ -ol#qunit-tests { - font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; - margin:0; - padding:0; - list-style-position:inside; +/** Font Family and Sizes */ - 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; +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } -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; +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { + margin: 0; + padding: 0; } -ol#qunit-tests li.pass{ - background-color:#D2E0E6; - color:#528CE0; + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699A4; + background-color: #0D3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: 400; + + border-radius: 5px 5px 0 0; } -ol#qunit-tests li.fail{ - background-color:#EE5757; - color:#000; + +#qunit-header a { + text-decoration: none; + color: #C2CCD1; } -ol#qunit-tests li strong { - cursor:pointer; + +#qunit-header a:hover, +#qunit-header a:focus { + color: #FFF; } -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; + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 0.5em 0 0.1em; } -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-banner { + height: 5px; } + #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; + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #EEE; + overflow: hidden; } -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; + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2B81AF; + color: #FFF; 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; + +#qunit-modulefilter-container { + float: right; +} + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #FFF; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #C2CCD1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests li .runtime { + float: right; + font-size: smaller; +} + +.qunit-assert-list { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #FFF; + + border-radius: 5px; +} + +.qunit-collapsed { + display: none; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: 0.2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 0.5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #E0F2BE; + color: #374E0C; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #FFCACA; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: #000; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #FFF; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3C510C; + background-color: #FFF; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #FFF; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; +} + +#qunit-tests .fail { color: #000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: #008000; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2B81AF; + background-color: #D2E0E6; + + border-bottom: 1px solid #FFF; +} +#qunit-testresult .module-name { + font-weight: 700; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; } -strong b.fail{ - color:#710909; - } -strong b.pass{ - color:#5E740B; - } diff --git a/tests/qunit/editor/js/qunit/qunit.js b/tests/qunit/editor/js/qunit/qunit.js index f7867a5002..0e279fde17 100644 --- a/tests/qunit/editor/js/qunit/qunit.js +++ b/tests/qunit/editor/js/qunit/qunit.js @@ -1,400 +1,358 @@ -/* - * QUnit - A JavaScript Unit Testing Framework - * - * http://docs.jquery.com/QUnit +/*! + * QUnit 1.14.0 + * http://qunitjs.com/ * - * Copyright (c) 2009 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-01-31T16:40Z */ -(function(window) { +(function( window ) { -var QUnit = { +var QUnit, + assert, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + defined = { + document: typeof window.document !== "undefined", + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. + /*jshint newcap: false */ + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[key]; + vals[key] = val === Object(val) ? objectValues(val) : val; + } + } + return vals; + }; + + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { // call on start of module test to prepend name to all tests - module: function(name, testEnvironment) { + 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 ); - }); + config.currentModuleTestEnvironment = testEnvironment; + config.modules[name] = true; }, - 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 = '' + testName + '', testEnvironment, testEnvironmentArg; - + asyncTest: function( testName, expected, callback ) { if ( arguments.length === 2 ) { callback = expected; expected = null; } - // is 2nd argument a testEnvironment? - if ( expected && typeof expected === 'object') { - testEnvironmentArg = expected; + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + nameHtml = "" + escapeText( testName ) + ""; + + if ( arguments.length === 2 ) { + callback = expected; expected = null; } if ( config.currentModule ) { - name = '' + config.currentModule + ": " + name; + nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; } - if ( !validTest(config.currentModule + ": " + testName) ) { + test = new Test({ + nameHtml: nameHtml, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnvironment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { return; } - synchronize(function() { + test.queue(); + }, - testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, config.moduleTestEnvironment); - if (testEnvironmentArg) { - extend(testEnvironment,testEnvironmentArg); - } + // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if (arguments.length === 1) { + config.current.expected = asserts; + } else { + return config.current.expected; + } + }, - 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 + " (" + bad + ", " + good + ", " + config.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.nextSibling, display = next.style.display; - next.style.display = display === "none" ? "block" : "none"; + start: function( count ) { + // QUnit hasn't been initialized yet. + // Note: RequireJS (et al) may delay onLoad + if ( config.semaphore === undefined ) { + QUnit.begin(function() { + // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first + setTimeout(function() { + QUnit.start( count ); }); - - 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); + }); + return; } - }, - - /** - * 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 ); + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; } - catch (e) { - ok( true, message ); + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); + return; } - }, - - start: function() { // A slight delay, to avoid any current callbacks - if ( window.setTimeout ) { - window.setTimeout(function() { + if ( defined.setTimeout ) { + setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } if ( config.timeout ) { - clearTimeout(config.timeout); + clearTimeout( config.timeout ); } config.blocking = false; - process(); + process( true ); }, 13); } else { config.blocking = false; - process(); + process( true ); } }, - - stop: function(timeout) { + + stop: function( count ) { + config.semaphore += count || 1; config.blocking = true; - if ( timeout && window.setTimeout ) { - config.timeout = window.setTimeout(function() { + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = setTimeout(function() { QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; QUnit.start(); - }, timeout); + }, config.testTimeout ); } } - }; -// Backwards compatibility, deprecated -QUnit.equals = QUnit.equal; -QUnit.same = QUnit.deepEqual; +// We use the prototype to distinguish between properties that should +// be exposed as globals (and in exports) and those that shouldn't +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); -// Maintain internal state -var config = { +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { // The queue of tests to run queue: [], // block until document ready - blocking: true + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // by default, scroll to top of the page when suite is done + scrolltop: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: {}, + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] }; -// Load parameters +// Initialize more QUnit.config and QUnit.urlParams (function() { - var location = window.location || { search: "", protocol: "file:" }, - GETParams = location.search.slice(1).split('&'); + var i, current, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}; - 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--; + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + if ( urlParams[ current[ 0 ] ] ) { + urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); + } else { + urlParams[ current[ 0 ] ] = current[ 1 ]; + } } } - - // restrict modules/tests by get parameters - config.filters = GETParams; - + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = []; + if ( urlParams.testNumber ) { + + // Ensure that urlParams.testNumber is an array + urlParams.testNumber = [].concat( urlParams.testNumber ); + for ( i = 0; i < urlParams.testNumber.length; i++ ) { + current = urlParams.testNumber[ i ]; + config.testNumber.push( parseInt( current, 10 ) ); + } + } + // Figure out if we're running the tests from a server or not - QUnit.isLocal = !!(location.protocol === 'file:'); -})(); + 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; -} +extend( 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, { + extend( config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, - started: +new Date, + started: +new Date(), updateRate: 1000, blocking: false, autostart: true, autorun: false, - assertions: [], - filters: [], - queue: [] + filter: "", + queue: [], + semaphore: 1 }); - var tests = id("qunit-tests"), - banner = id("qunit-banner"), - result = id("qunit-testresult"); + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "

" + escapeText( document.title ) + "

" + + "

" + + "
" + + "

" + + "
    "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; @@ -407,325 +365,709 @@ extend(QUnit, { 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); + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
     "; } }, - + + // Resets the test setup. Useful for tests that modify the DOM. + /* + DEPRECATED: Use multiple tests instead of resetting inside a test. + Use testStart or testDone for custom cleanup. + This method will throw an error in 2.0, and will be removed in 2.1 + */ + reset: function() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + }, + // Safe object type checking is: function( type, obj ) { - return QUnit.objectType( obj ) == type; + return QUnit.objectType( obj ) === type; }, - + objectType: function( obj ) { - if (typeof obj === "undefined") { - return "undefined"; - - // consider: typeof null === object - } - if (obj === null) { - return "null"; + if ( typeof obj === "undefined" ) { + return "undefined"; } - 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(); + // Consider: typeof null === object + if ( obj === null ) { + return "null"; } - if (typeof obj === "object") { - return "object"; + + var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), + type = match && match[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + 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) {} + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeText( message ) || ( result ? "okay" : "failed" ); + message = "" + message + ""; + output = message; + + if ( !result ) { + expected = escapeText( QUnit.jsDump.parse(expected) ); + actual = escapeText( QUnit.jsDump.parse(actual) ); + output += ""; + + if ( actual !== expected ) { + output += ""; + output += ""; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Expected:
    " + expected + "
    Result:
    " + actual + "
    Diff:
    " + QUnit.diff( expected, actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + module: config.current.module, + name: config.current.testName, + result: false, + message: message + }; + + message = escapeText( message ) || "error"; + message = "" + message + ""; + output = message; + + output += ""; + + if ( actual ) { + output += ""; + } + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Result:
    " + escapeText( actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( hasOwn.call( params, key ) ) { + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + } + return window.location.protocol + "//" + window.location.host + + window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent, + addClass: addClass, + hasClass: hasClass, + removeClass: removeClass + // load, equiv, jsDump, diff: Attached later }); -if ( typeof document === "undefined" || document.readyState === "complete" ) { +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total, runtime } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( !defined.document || document.readyState === "complete" ) { config.autorun = true; } -addEvent(window, "load", function() { - QUnit.begin(); - +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + // Initialize the config, saving the execution queue - var oldconfig = extend({}, config); + var banner, filter, i, j, label, len, main, ol, toolbar, val, selection, + urlConfigContainer, moduleFilter, userAgent, + numModules = 0, + moduleNames = [], + moduleFilterHtml = "", + urlConfigHtml = "", + oldconfig = extend( {}, config ); + QUnit.init(); extend(config, oldconfig); config.blocking = false; - var userAgent = id("qunit-userAgent"); + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + if ( !val.value || typeof val.value === "string" ) { + urlConfigHtml += ""; + } else { + urlConfigHtml += ""; + } + } + for ( i in config.modules ) { + if ( config.modules.hasOwnProperty( i ) ) { + moduleNames.push(i); + } + } + numModules = moduleNames.length; + moduleNames.sort( function( a, b ) { + return a.localeCompare( b ); + }); + moduleFilterHtml += ""; + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); if ( userAgent ) { userAgent.innerHTML = navigator.userAgent; } - - var toolbar = id("qunit-testrunner-toolbar"); + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "" + banner.innerHTML + " "; + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); if ( toolbar ) { - toolbar.style.display = "none"; - - var filter = document.createElement("input"); + // `filter` initialized at top of scope + 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" : ""; + var tmp, + ol = id( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); } } }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = id( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } toolbar.appendChild( filter ); - var label = document.createElement("label"); - label.setAttribute("for", "qunit-filter-pass"); + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); 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"; - } - } + urlConfigContainer = document.createElement("span"); + urlConfigContainer.innerHTML = urlConfigHtml; + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" for checkboxes + // * Fallback from event.target to event.srcElement + addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) { + var params = {}, + target = event.target || event.srcElement; + params[ target.name ] = target.checked ? + target.defaultValue || true : + undefined; + window.location = QUnit.url( params ); }); - toolbar.appendChild( missing ); + addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) { + var params = {}, + target = event.target || event.srcElement; + params[ target.name ] = target.options[ target.selectedIndex ].value || undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigContainer ); - label = document.createElement("label"); - label.setAttribute("for", "qunit-filter-missing"); - label.innerHTML = "Hide missing tests (untested code is broken code)"; - toolbar.appendChild( label ); + if (numModules > 1) { + moduleFilter = document.createElement( "span" ); + moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); + moduleFilter.innerHTML = moduleFilterHtml; + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName("select")[0], + selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); + + window.location = QUnit.url({ + module: ( selectedModule === "" ) ? undefined : selectedModule, + // Remove any existing filters + filter: undefined, + testNumber: undefined + }); + }); + toolbar.appendChild(moduleFilter); + } } - var main = id('main') || id('qunit-fixture'); + // `main` initialized at top of scope + main = id( "qunit-fixture" ); if ( main ) { config.fixture = main.innerHTML; } - if (config.autostart) { + if ( config.autostart ) { QUnit.start(); } -}); +}; + +if ( defined.document ) { + addEvent( window, "load", QUnit.load ); +} + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will suppress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not suppressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend( function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: validTest } ) ); + } + return false; + } + + return ret; +}; 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 ); + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); } + delete config.previousModule; - var banner = id("qunit-banner"), - tests = id("qunit-tests"), - html = ['Tests completed in ', - +new Date - config.started, ' milliseconds.
    ', - '', config.stats.all - config.stats.bad, ' tests of ', config.stats.all, ' passed, ', config.stats.bad,' failed.'].join(''); + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.
    ", + "", + passed, + " assertions of ", + config.stats.all, + " passed, ", + config.stats.bad, + " failed." + ].join( "" ); if ( banner ) { - banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); } - if ( tests ) { - var result = id("qunit-testresult"); + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } - if ( !result ) { - result = document.createElement("p"); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests.nextSibling ); + if ( config.altertitle && defined.document && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } } - - result.innerHTML = html; } - QUnit.done( config.stats.bad, config.stats.all ); + // scroll back to top to show results + if ( config.scrolltop && window.scrollTo ) { + window.scrollTo(0, 0); + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); } -function validTest( name ) { - var i = config.filters.length, - run = false; +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = ( test.module + ": " + test.testName ).toLowerCase(); - if ( !i ) { + // Internally-generated tests are always valid + if ( test.callback && test.callback.validTest === validTest ) { + delete test.callback.validTest; 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; + if ( config.testNumber.length > 0 ) { + if ( inArray( test.testNumber, config.testNumber ) < 0 ) { + return false; } } - return run; + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; } -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; +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +/** + * Escape text for attribute or text content. + */ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch( s ) { + case "'": + return "'"; + case "\"": + return """; + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; } }); } -function push(result, actual, expected, message) { - message = escapeHtml(message) || (result ? "okay" : "failed"); - message = '' + message + ""; - expected = escapeHtml(QUnit.jsDump.parse(expected)); - actual = escapeHtml(QUnit.jsDump.parse(actual)); - var output = message + ', expected: ' + expected + ''; - if (actual != expected) { - output += ' result: ' + actual + ', 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 ) { +function synchronize( callback, last ) { config.queue.push( callback ); if ( config.autorun && !config.blocking ) { - process(); + process( last ); } } -function process() { - var start = (new Date()).getTime(); +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; while ( config.queue.length && !config.blocking ) { - if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { config.queue.shift()(); - } else { - setTimeout( process, 13 ); + setTimeout( next, 13 ); break; } } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } } function saveGlobal() { config.pollution = []; - + if ( config.noglobals ) { for ( var key in window ) { - config.pollution.push( key ); + if ( hasOwn.call( window, key ) ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } } } } -function checkPollution( name ) { - var old = config.pollution; +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + saveGlobal(); - - var newGlobals = diff( old, config.pollution ); + + newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { - ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); - config.expected++; + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); } - var deletedGlobals = diff( config.pollution, old ); + deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { - ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); - config.expected++; + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); } } // 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++ ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { if ( result[i] === b[j] ) { - result.splice(i, 1); + result.splice( i, 1 ); i--; break; } @@ -734,210 +1076,826 @@ function diff( a, b ) { 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) { +function extend( a, b ) { for ( var prop in b ) { - a[prop] = b[prop]; + if ( hasOwn.call( b, prop ) ) { + // Avoid "Member not found" error in IE8 caused by messing with window.constructor + if ( !( prop === "constructor" && a === window ) ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + } else { + a[ prop ] = b[ prop ]; + } + } + } } return a; } -function addEvent(elem, type, fn) { +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { if ( elem.addEventListener ) { + + // Standards-based browsers elem.addEventListener( type, fn, false ); } else if ( elem.attachEvent ) { + + // support: IE <9 elem.attachEvent( "on" + type, fn ); } else { - fn(); + + // Caller must ensure support for event listeners is present + throw new Error( "addEvent() was called in a context without event listener support" ); } } -function id(name) { - return !!(typeof document !== "undefined" && document && document.getElementById) && - document.getElementById( name ); +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[i], type, fn ); + } } -// Test for equality any JavaScript type. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv -// Author: Philippe Rathé -QUnit.equiv = function () { +function hasClass( elem, name ) { + return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; +} - var innerEquiv; // the real equiv function - var callers = []; // stack to decide between skip/abort functions - var parents = []; // stack to avoiding loops from circular referencing +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += (elem.className ? " " : "") + name; + } +} - // 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 () { +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + // Class name may appear multiple times + while ( set.indexOf(" " + name + " ") > -1 ) { + set = set.replace(" " + name + " " , " "); + } + // If possible, trim it for prettiness, but not necessarily + elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, ""); +} - // 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; - } - } +function id( name ) { + return defined.document && document.getElementById && document.getElementById( name ); +} - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} - "nan": function (b) { - return isNaN(b); - }, +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} - "date": function (b, a) { - return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); - }, +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } - "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; - }, + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } - // - 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"; - }, + return -1; +} - "array": function (b, a) { - var i, j, loop; - var len; +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} - // 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(" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.parentNode.lastChild, + collapsed = hasClass( next, "qunit-collapsed" ); + ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); + }); + + 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 = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `time` initialized at top of scope + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = this.runtime + " ms"; + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( time ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + runtime: this.runtime, + // DEPRECATED: this property will be removed in 2.0.0, use runtime instead + duration: this.runtime + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// `assert` initialized at top of scope +// Assert helpers +// All of these must either call QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +assert = QUnit.assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + msg = msg || ( result ? "okay" : "failed" ); + + var source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: msg + }; + + msg = "" + escapeText( msg ) + ""; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "
    Source:
    " +
    +					escapeText( source ) +
    +					"
    "; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, + expectedOutput = expected, + ok = false; + + // 'expected' is optional + if ( !message && typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + + // expected is an Error object + } else if ( expected instanceof Error ) { + ok = actual instanceof Error && + actual.name === expected.name && + actual.message === expected.message; + + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( errorString( actual ) ); + + // expected is a string + } else if ( QUnit.objectType( expected ) === "string" ) { + ok = expected === errorString( actual ); + + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + QUnit.push( ok, actual, expectedOutput, message ); + } else { + QUnit.pushFailure( message, null, "No exception was thrown." ); + } + } +}; /** - * 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 + * @deprecated since 1.8.0 + * Kept assertion helpers in root for backwards compatibility. + */ +extend( QUnit.constructor.prototype, assert ); + +/** + * @deprecated since 1.9.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.constructor.prototype.raises = function() { + QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" ); +}; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.constructor.prototype.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.constructor.prototype.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // 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 + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + parentsB = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + /*jshint camelcase:false */ + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotation 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" && + // the regex itself + a.source === b.source && + // and its modifiers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - 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, len, loop, aCircular, bCircular; + + // 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 ); + parentsB.push( b ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[j] === a[i]; + bCircular = parentsB[j] === b[i]; + if ( aCircular || bCircular ) { + if ( a[i] === b[i] || aCircular && bCircular ) { + loop = true; + } else { + parents.pop(); + parentsB.pop(); + return false; + } + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + parentsB.pop(); + return false; + } + } + parents.pop(); + parentsB.pop(); + return true; + }, + + "object": function( b, a ) { + /*jshint forin:false */ + var i, j, loop, aCircular, bCircular, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + + // be strict: don't ensure hasOwnProperty and go deep + for ( i in a ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[j] === a[i]; + bCircular = parentsB[j] === b[i]; + if ( aCircular || bCircular ) { + if ( a[i] === b[i] || aCircular && bCircular ) { + loop = true; + } else { + eq = false; + break; + } + } + } + aProperties.push(i); + if ( !loop && !innerEquiv(a[i], b[i]) ) { + eq = false; + break; + } + } + + parents.pop(); + parentsB.pop(); + callers.pop(); // unstack, we are done + + 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 = [].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] ) && innerEquiv.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 @@ -945,185 +1903,224 @@ QUnit.equiv = function () { */ QUnit.jsDump = (function() { function quote( str ) { - return '"' + str.toString().replace(/"/g, '\\"') + '"'; - }; + return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; + } function literal( o ) { - return 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 ? '
    ' : '\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 ); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); } - return ret; -}; + var reName = /^function (\w+)/, + jsDump = { + // type is used mostly internally, you can fix a (custom)type in advance + parse: function( obj, type, stack ) { + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + if ( type === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( 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 ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new 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: function(error) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + // functions never have name in IE + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + /*jshint forin:false */ + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[i].nodeValue; + // IE6 includes all attributes in .attributes, even ones not explicitly set. + // Those have values like undefined, null, 0, false, "" or "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + // 97 is 'a' + args[l] = String.fromCharCode(97+l); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return jsDump; +}()); /* * Javascript Diff Algorithm @@ -1134,132 +2131,158 @@ function getText( elems ) { * * 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 brown fox jumped jumps over" + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps 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(), + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[i] ) ) { + ns[ n[i] ] = { + rows: [], o: null }; - ns[n[i]].rows.push(i); + } + 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(), + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[i] ) ) { + os[ o[i] ] = { + rows: [], n: null }; - os[o[i]].rows.push(i); + } + 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 ( i in ns ) { + if ( hasOwn.call( ns, i ) ) { + if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && 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], + + for ( 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], + 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], + + for ( 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], + 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 = [" "]; + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; } else { - oSpace.push(" "); + oSpace.push( " " ); } - var nSpace = n.match(/\s+/g); - if (nSpace == null) { - nSpace = [" "]; + + if ( nSpace == null ) { + nSpace = [ " " ]; } else { - nSpace.push(" "); + nSpace.push( " " ); } - - if (out.n.length == 0) { - for (var i = 0; i < out.o.length; i++) { - str += '' + out.o[i] + oSpace[i] + ""; + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[i] + oSpace[i] + ""; } } else { - if (out.n[0].text == null) { - for (n = 0; n < out.o.length && out.o[n].text == null; n++) { - str += '' + out.o[n] + oSpace[n] + ""; + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "" + out.o[n] + oSpace[n] + ""; } } - - for (var i = 0; i < out.n.length; i++) { + + for ( i = 0; i < out.n.length; i++ ) { if (out.n[i].text == null) { - str += '' + out.n[i] + nSpace[i] + ""; + str += "" + out.n[i] + nSpace[i] + ""; } else { - var pre = ""; - - for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { - pre += '' + out.o[n] + oSpace[n] + ""; + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "" + out.o[n] + oSpace[n] + ""; } str += " " + out.n[i].text + nSpace[i] + pre; } } } - - return str; - } -})(); -})(this); + return str; + }; +}()); + +// For browser, export only select globals +if ( typeof window !== "undefined" ) { + extend( window, QUnit.constructor.prototype ); + window.QUnit = QUnit; +} + +// For CommonJS environments, export everything +if ( typeof module !== "undefined" && module.exports ) { + module.exports = QUnit; +} + + +// Get a reference to the global object, like window in browsers +}( (function() { + return this; +})() )); diff --git a/tests/qunit/editor/js/qunit/reporter.js b/tests/qunit/editor/js/qunit/reporter.js deleted file mode 100644 index 205cf45cb1..0000000000 --- a/tests/qunit/editor/js/qunit/reporter.js +++ /dev/null @@ -1,13 +0,0 @@ -(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); - } - }; - } -})(); diff --git a/tests/qunit/editor/js/qunit/testrunner.css b/tests/qunit/editor/js/qunit/testrunner.css deleted file mode 100644 index 09fadf83f9..0000000000 --- a/tests/qunit/editor/js/qunit/testrunner.css +++ /dev/null @@ -1,151 +0,0 @@ -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); -} \ No newline at end of file diff --git a/tests/qunit/editor/js/qunit/testrunner.js b/tests/qunit/editor/js/qunit/testrunner.js deleted file mode 100644 index 2deb59b961..0000000000 --- a/tests/qunit/editor/js/qunit/testrunner.js +++ /dev/null @@ -1,543 +0,0 @@ -// 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(); - // Auto-start - started = true; - start(); - } - } - - 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 += ''; - - html += ''; - - // coverage - html += '
    '; - html += '
    '; - html += 'x'; - html += ''; - html += '
    '; - - 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 = ( - '(' + failed + ', ' + - '' + (total - failed) + ', ' + - '' + total + ')' - ); - - 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; -})(); diff --git a/tests/qunit/editor/js/runner.js b/tests/qunit/editor/js/runner.js new file mode 100644 index 0000000000..c42d1dacf8 --- /dev/null +++ b/tests/qunit/editor/js/runner.js @@ -0,0 +1,148 @@ +/* + * PhantomJS Runner QUnit Plugin 1.2.0 + * + * PhantomJS binaries: http://phantomjs.org/download.html + * Requires PhantomJS 1.6+ (1.7+ recommended) + * + * Run with: + * phantomjs runner.js [url-of-your-qunit-testsuite] + * + * e.g. + * phantomjs runner.js http://localhost/qunit/test/index.html + */ + +/*global phantom:false, require:false, console:false, window:false, QUnit:false */ + +(function() { + 'use strict'; + + var url, page, timeout, + args = require('system').args; + + // arg[0]: scriptName, args[1...]: arguments + if (args.length < 2 || args.length > 3) { + console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]'); + phantom.exit(1); + } + + url = args[1]; + page = require('webpage').create(); + if (args[2] !== undefined) { + timeout = parseInt(args[2], 10); + } + + // Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`) + page.onConsoleMessage = function(msg) { + console.log(msg); + }; + + page.onInitialized = function() { + page.evaluate(addLogging); + }; + + page.onCallback = function(message) { + var result, + failed; + + if (message) { + if (message.name === 'QUnit.done') { + result = message.data; + failed = !result || !result.total || result.failed; + + if (!result.total) { + console.error('No tests were executed. Are you loading tests asynchronously?'); + } + + phantom.exit(failed ? 1 : 0); + } + } + }; + + page.open(url, function(status) { + if (status !== 'success') { + console.error('Unable to access network: ' + status); + phantom.exit(1); + } else { + // Cannot do this verification with the 'DOMContentLoaded' handler because it + // will be too late to attach it if a page does not have any script tags. + var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); }); + if (qunitMissing) { + console.error('The `QUnit` object is not present on this page.'); + phantom.exit(1); + } + + // Set a timeout on the test running, otherwise tests with async problems will hang forever + if (typeof timeout === 'number') { + setTimeout(function() { + console.error('The specified timeout of ' + timeout + ' seconds has expired. Aborting...'); + phantom.exit(1); + }, timeout * 1000); + } + + // Do nothing... the callback mechanism will handle everything! + } + }); + + function addLogging() { + window.document.addEventListener('DOMContentLoaded', function() { + var currentTestAssertions = []; + + QUnit.log(function(details) { + var response; + + // Ignore passing assertions + if (details.result) { + return; + } + + response = details.message || ''; + + if (typeof details.expected !== 'undefined') { + if (response) { + response += ', '; + } + + response += 'expected: ' + details.expected + ', but was: ' + details.actual; + } + + if (details.source) { + response += "\n" + details.source; + } + + currentTestAssertions.push('Failed assertion: ' + response); + }); + + QUnit.testDone(function(result) { + var i, + len, + name = ''; + + if (result.module) { + name += result.module + ': '; + } + name += result.name; + + if (result.failed) { + console.log('\n' + 'Test failed: ' + name); + + for (i = 0, len = currentTestAssertions.length; i < len; i++) { + console.log(' ' + currentTestAssertions[i]); + } + } + + currentTestAssertions.length = 0; + }); + + QUnit.done(function(result) { + console.log('\n' + 'Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.'); + + if (typeof window.callPhantom === 'function') { + window.callPhantom({ + 'name': 'QUnit.done', + 'data': result + }); + } + }); + }, false); + } +})(); \ No newline at end of file diff --git a/tests/qunit/editor/js/utils.js b/tests/qunit/editor/js/utils.js index f0c344ccac..fe88c59fbd 100644 --- a/tests/qunit/editor/js/utils.js +++ b/tests/qunit/editor/js/utils.js @@ -1,299 +1,339 @@ -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); +(function() { + function fontFace(face) { + if (tinymce.isOpera) { + return "'" + face + "'"; } else { - rng.setEnd(container, offset); + return face; } } - setRange(startContainer, startOffset, true); - setRange(endContainer, endOffset, false); - editor.selection.setRng(rng); -} - -function initWhenTinyAndRobotAreReady(initTinyFunction) { - function loaded() { - QUnit.start(); + 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; } - tinymce.on('AddEditor', function(e) { - e.editor.on('Init', function() { - loaded(); - }); - }); + 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(); - window.robot.onload(initTinyFunction); -} + function setRange(container, offset, start) { + offset = offset || 0; -function trimContent(content) { - return content.replace(/^

     <\/p>\n?/, '').replace(/\n?

     <\/p>$/, ''); -} + 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); + } + } -/** - * 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; + setRange(startContainer, startOffset, true); + setRange(endContainer, endOffset, false); + editor.selection.setRng(rng); } - 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); + function trimContent(content) { + return content.replace(/^

     <\/p>\n?/, '').replace(/\n?

     <\/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; } - } 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); } - 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); + } -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; } - 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); - } + // 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; - return rng; -} + function fakeEvent(target, type, evt) { + editor.dom.fire(target, type, evt); + } -// 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); + // 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 { - charCode = chr.charCodeAt(0); - keyCode = charCode; + evt = chr; } - } else { - evt = chr; - } - evt = evt || {keyCode: keyCode, charCode: charCode}; + evt = evt || {keyCode: keyCode, charCode: charCode}; - startElm = editor.selection.getStart(); - fakeEvent(startElm, 'keydown', evt); - fakeEvent(startElm, 'keypress', evt); + 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 (!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

    abc|

    and after the abc text node then move it to the end of the text node - // Expand the range to include the last char

    ab[c]

    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); + 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

    abc|

    and after the abc text node then move it to the end of the text node + // Expand the range to include the last char

    ab[c]

    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); - 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)); + 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); } - 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(/]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>|]+data-mce-bogus[^>]+><\/div>/gi, ''); + html = html.replace(/ style="([^"]+)"/gi, function(val1, val2) { + val2 = val2.replace(/;$/, ''); + return ' style="' + val2.replace(/\:([^ ])/g, ': $1') + ';"'; + }); -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(/]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>|]+data-mce-bogus[^>]+><\/div>/gi, ''); + return html; + } - return html; -} + function normalizeHtml(html) { + var writer = new tinymce.html.Writer(); -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, - 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; + } - start: function(name, attrs, empty) { - attrs.sort(function(a, b) { - if (a.name === b.name) { - return 0; - } + return a.name > b.name ? 1 : -1; + }); - return a.name > b.name ? 1 : -1; - }); + writer.start(name, attrs, empty); + } + }).parse(html); - writer.start(name, attrs, empty); + 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(); } - }).parse(html); - return writer.getContent(); -} + outerRect = document.getElementById('view').getBoundingClientRect(); -/** - * 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(); + 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) + ]; } - outerRect = document.getElementById('view').getBoundingClientRect(); + function size(ctrl) { + return rect(ctrl).slice(2); + } - 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 resetScroll(elm) { + elm.scrollTop = 0; + elm.scrollLeft = 0; + } -function size(ctrl) { - return rect(ctrl).slice(2); -} + // Needed since fonts render differently on different platforms + function nearlyEqualRects(rect1, rect2, diff) { + diff = diff || 1; -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; + for (var i = 0; i < 4; i++) { + if (Math.abs(rect1[i] - rect2[i]) > diff) { + deepEqual(rect1, rect2); + return; + } } + + ok(true); } - ok(true); -} + function getFontmostWindow() { + return editor.windowManager.windows[editor.windowManager.windows.length - 1]; + } + + 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); + } + + 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(/]*>/gi, ''); + } + + window.Utils = { + fontFace: fontFace, + findContainer: findContainer, + setSelection: setSelection, + trimContent: trimContent, + fakeKeyEvent: fakeKeyEvent, + normalizeRng: normalizeRng, + type: type, + cleanHtml: cleanHtml, + normalizeHtml: normalizeHtml, + rect: rect, + size: size, + resetScroll: resetScroll, + nearlyEqualRects: nearlyEqualRects, + getFontmostWindow: getFontmostWindow, + pressArrowKey: pressArrowKey, + pressEnter: pressEnter, + trimBrsOnIE: trimBrsOnIE + }; +})(); diff --git a/tests/qunit/editor/plugins/autolink.html b/tests/qunit/editor/plugins/autolink.html deleted file mode 100644 index 46a83cad63..0000000000 --- a/tests/qunit/editor/plugins/autolink.html +++ /dev/null @@ -1,170 +0,0 @@ - - - -Automatic link tests - - - - - - - - - - - -

    Automatic link tests

    -

    -
    -

    -
      -
      - -
      - - - - diff --git a/tests/qunit/editor/plugins/autosave.html b/tests/qunit/editor/plugins/autosave.js similarity index 60% rename from tests/qunit/editor/plugins/autosave.html rename to tests/qunit/editor/plugins/autosave.js index b167df586b..77240133ba 100644 --- a/tests/qunit/editor/plugins/autosave.html +++ b/tests/qunit/editor/plugins/autosave.js @@ -1,23 +1,20 @@ - - - -Unit tests for the Autosave plugin - - - - - - - - - - -

      Unit tests for the Table plugin

      -

      -
      -

      -
        - - - - - diff --git a/tests/qunit/editor/plugins/fullpage.html b/tests/qunit/editor/plugins/fullpage.js similarity index 66% rename from tests/qunit/editor/plugins/fullpage.html rename to tests/qunit/editor/plugins/fullpage.js index 310db10496..1f4dd91943 100644 --- a/tests/qunit/editor/plugins/fullpage.html +++ b/tests/qunit/editor/plugins/fullpage.js @@ -1,42 +1,38 @@ - - - -Fullpage plugin tests - - - - - - - - -

        Fullpage plugin tests

        -

        -
        -

        -
          - - - diff --git a/tests/qunit/editor/plugins/jquery_plugin.html b/tests/qunit/editor/plugins/jquery_plugin.html deleted file mode 100644 index a2e3d6b2c1..0000000000 --- a/tests/qunit/editor/plugins/jquery_plugin.html +++ /dev/null @@ -1,126 +0,0 @@ - - - -jQuery Plugin tests - - - - - - - - - - -

          TinyMCE jQuery plugin tests

          -

          -
          -

          -
            -
            - - - -
            - - diff --git a/tests/qunit/editor/plugins/jquery_plugin.js b/tests/qunit/editor/plugins/jquery_plugin.js new file mode 100644 index 0000000000..c550662726 --- /dev/null +++ b/tests/qunit/editor/plugins/jquery_plugin.js @@ -0,0 +1,96 @@ +module("tinymce.plugins.jQuery", { + setupModule: function() { + document.getElementById('view').innerHTML = ( + '' + + '' + + '' + ); + + QUnit.stop(); + + $(function() { + $('#elm1,#elm2').tinymce({ + plugins: [ + "pagebreak,layer,table,save,emoticons,insertdatetime,preview,media,searchreplace", + "print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,template" + ], + + init_instance_callback: function() { + var ed1 = tinymce.get('elm1'), ed2 = tinymce.get('elm2'); + + // When both editors are initialized + if (ed1 && ed1.initialized && ed2 && ed2.initialized) { + QUnit.start(); + } + } + }); + }); + } +}); + +test("Get editor instance", function() { + equal($('#elm1').tinymce().id, 'elm1'); + equal($('#elm2').tinymce().id, 'elm2'); + equal($('#elm3').tinymce(), null); +}); + +test("Get contents using jQuery", function() { + expect(4); + + tinymce.get('elm1').setContent('

            Editor 1

            '); + + equal($('#elm1').html(), '

            Editor 1

            '); + equal($('#elm1').val(), '

            Editor 1

            '); + equal($('#elm1').attr('value'), '

            Editor 1

            '); + equal($('#elm1').text(), 'Editor 1'); +}); + +test("Set contents using jQuery", function() { + expect(4); + + $('#elm1').html('Test 1'); + equal($('#elm1').html(), '

            Test 1

            '); + + $('#elm1').val('Test 2'); + equal($('#elm1').html(), '

            Test 2

            '); + + $('#elm1').text('Test 3'); + equal($('#elm1').html(), '

            Test 3

            '); + + $('#elm1').attr('value', 'Test 4'); + equal($('#elm1').html(), '

            Test 4

            '); +}); + +test("append/prepend contents using jQuery", function() { + expect(2); + + tinymce.get('elm1').setContent('

            Editor 1

            '); + + $('#elm1').append('

            Test 1

            '); + equal($('#elm1').html(), '

            Editor 1

            \n

            Test 1

            '); + + $('#elm1').prepend('

            Test 2

            '); + equal($('#elm1').html(), '

            Test 2

            \n

            Editor 1

            \n

            Test 1

            '); +}); + +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(), '

            Test 1

            '); + equal($('#elm2').val(), '

            Test 1

            '); + equal($('#elm3').val(), 'Textarea'); +}); + +test("Get contents using :tinymce selector", function() { + expect(1); + + $('textarea:tinymce').val('Test get'); + equal($('textarea:tinymce').val(), '

            Test get

            '); +}); diff --git a/tests/qunit/editor/plugins/js/autolink.actions.js b/tests/qunit/editor/plugins/js/autolink.actions.js deleted file mode 100644 index 53d50e32c8..0000000000 --- a/tests/qunit/editor/plugins/js/autolink.actions.js +++ /dev/null @@ -1,52 +0,0 @@ -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)); diff --git a/tests/qunit/editor/plugins/js/dsl.js b/tests/qunit/editor/plugins/js/dsl.js deleted file mode 100644 index 742321572e..0000000000 --- a/tests/qunit/editor/plugins/js/dsl.js +++ /dev/null @@ -1,138 +0,0 @@ -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); -} \ No newline at end of file diff --git a/tests/qunit/editor/plugins/js/states.js b/tests/qunit/editor/plugins/js/states.js deleted file mode 100644 index 611ffdee8e..0000000000 --- a/tests/qunit/editor/plugins/js/states.js +++ /dev/null @@ -1,176 +0,0 @@ -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('
            • Item
            Test'); - setSelection(editor.dom.getRoot().lastChild, 2); -} - -function TextAfterOL() { - editor.setContent('
            1. Item
            Test'); - setSelection(editor.dom.getRoot().lastChild, 2); -} - -EmptyContent = createState('', 'body', 0); -PlainText = createState('Test', 'body', 0); -NonEmptyParagraph = createState('

            Test

            ', 'p', 0); -ParagraphWithMarginLeft = createState('

            Test

            ', 'p', 0); -ParagraphWithPaddingLeft = createState('

            Test

            ', 'p', 0); -ParagraphWithMarginAndPaddingLeft = createState('

            Test

            ', 'p', 0); - -CenteredListItem = createState('
            • Item1
            • Item2
            ', 'li:nth-child(1)', 2); -ItemInCenteredList = createState('
            • Item1
            • Item2
            ', 'li:nth-child(1)', 2); -RightAlignedListItem = createState('
            • Item1
            • Item2
            ', 'li:nth-child(1)', 2); -ItemInRightAlignedList = createState('
            • Item1
            • Item2
            ', 'li:nth-child(1)', 2); - -ParagraphBetweenOrderedLists = createState('
            1. Item1

            Test

            1. Item2
            ', 'p', 2); -ParagraphBetweenUnorderedLists = createState('
            • Item1

            Test

            • Item2
            ', 'p', 2); -ParagraphBetweenMixedLists = createState('
            1. Item1

            Test

            • Item2
            ', 'p', 2); - -NonEmptyHeading = createState('

            Test

            ', 'h1', 0); -TableCellWithoutBrs = createState('
            Test 
            ', 'td', 4); -TableCellWithoutBrs2 = createState('
            Test 
            ', 'td', 0); -TableCellWithBrsFirstLine = createState('
            Test
            Line 2
             
            ', 'td', 1); -TableCellWithBrsFirstLine2 = createState('
            Test
            Line 2
             
            ', 'td', 0); -TableCellWithBrsMiddleLine = createState('
            Test
            Line 2
            Line 3
             
            ', 'td br:nth-child(1)', 'afterNextCharacter'); -TableCellWithBrsLastLine = createState('
            Test
            Line 2
             
            ', 'td br:nth-child(1)', 'afterNextCharacter'); -TableCellWithAdjacentBrsFirstLine = createState('
            Test

            Line 2
             
            ', 'td', 1); - -HeadingInOrderedList = createState('
            1. Test

            ', 'h2', '2'); -HeadingInUnorderedList = createState('
            • Test

            ', 'h2', '2'); -HeadingInOrderedListBeforeParagraph = createState('
            1. Test

            Content
            After

            ', 'h2', '2'); - -DefinitionListDescription = createState('
            Term
            Description
            ', 'dd', 2); -DefinitionListTerm = createState('
            Term
            Description
            ', 'dt', 2); -EndOfParagraphBeforeOL = createState('

            Test

            1. Item
            ', 'p', 4); -EndOfParagraphBeforeOLWithListType = createState('

            Test

            1. Item
            ', 'p', 4); -EndOfParagraphBeforeUL = createState('

            Test

            • Item
            ', 'p', 4); -StartOfParagraphAfterOL = createState('
            1. Item

            Test

            ', 'p', 1); -StartOfParagraphAfterUL = createState('
            • Item

            Test

            ', 'p', 1); -StartOfParagraphAfterOLWithListType = createState('
            1. Item

            Test

            ', 'p', 1); -EmptyOrderedListItem = createState('
            1. Before
            2.  
            3. After
            ', 'li:nth-child(2)', 0); -EmptyUnorderedListItem = createState('
            • Before
            •  
            • After
            ', 'li:nth-child(2)', 0); -NonEmptyOrderedListItem = createState('
            1. Before
            2. Test
            3. After
            ', 'li:nth-child(2)', 0); -NonEmptyUnorderedListItem = createState('
            • Before
            • Test
            • After
            ', 'li:nth-child(2)', 0); -NestedEmptyOrderedListItem = createState('
            1. Before
              1.  
            2. After
            ', 'li ol li', 0); -NestedEmptyUnorderedListItem = createState('
            • Before
              •  
            • After
            ', 'li ul li', 0); -NestedNonEmptyOrderedListItem = createState('
            1. Before
              1. Test
            2. After
            ', 'li ol li', 0); -NestedNonEmptyUnorderedListItem = createState('
            • Before
              • Test
            • After
            ', 'li ul li', 0); -NestedOrderedListWithMultipleItems = createState('
            1. Before
              1. Item1
              2. Item2
            ', 'li ol li', 0); -NestedUnorderedListWithMultipleItems = createState('
            • Before
              • Item1
              • Item2
            ', 'li ul li', 0); -OrderedLowerAlphaListItem = createState('
            1. Item 1
            2. Item 2
            ', 'li:nth-child(2)', 0); -UnorderedSquareListItem = createState('
            • Item 1
            • Item 2
            ', 'li:nth-child(2)', 0); - -OrderedListItemWithNestedChild = createState('
            1. Item1
              1. Nested
            ', 'li:nth-child(1)', 2); -UnorderedListItemWithNestedChild = createState('
            • Item1
              • Nested
            ', 'li:nth-child(1)', 2); - -OrderedListWithAdjacentNestedLists = createState('
              1. Item 1
            1. Item 2
              1. Item 3
            ', 'li:nth-child(2)', 4); -UnorderedListWithAdjacentNestedLists = createState('
              • Item 1
            • Item 2
              • Item 3
            ', 'li:nth-child(2)', 4); - -OrderedListItemWithMargin = createState('
            1. Test
            ', 'li', 0); -UnorderedListItemWithMargin = createState('
            • Test
            ', 'li', 0); - -OrderedListItemWithNestedAlphaList = createState('
            1. Item
              1. Nested
            ', 'li', 2); - -/** Collapsed DIV Tests **/ -OrderedListItemInsideDiv = createState('
              \n
            1. Item1
            2. Item2
            ', 'li:nth-child(1)', 2); -UnorderedListItemInsideDiv = createState('
              \n
            • Item1
            • Item2
            ', 'li:nth-child(1)', 2); - -ParagraphInDiv = createState('

            Item

            ', 'p', 2); -TextInDiv = createState('
            Item
            ', 'div', 2); -TextWithBrsInDivFirstLine = createState('
            Item1
            Item2
            ', 'div', 2); -TextWithBrsInDivMiddleLine = createState('
            Item1
            Item2
            Item3
            ', 'br:nth-child(1)', 'afterNextCharacter'); -TextWithBrsInDivLastLine = createState('
            Item1
            Item2
            ', 'br:nth-child(1)', 'afterNextCharacter'); -TextWithBrsInFormattingInDiv = function() { - var rng; - editor.setContent('
            Before
            Item1
            Item2
            Item3
            '); - 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('
            Before
            Item1
            Item2
            Item3
            '); - 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('

            This is a test

            ', 'p', 5, 'p', 7); -MultipleParagraphSelection = createState('

            This is a test

            Second paragraph

            ', 'p:nth-child(1)', 5, 'p:nth-child(2)', 6); -SingleHeadingSelection = createState('

            This is a test

            ', 'h1', 5, 'h1', 7); -MultipleHeadingSelection = createState('

            This is a test

            Second paragraph

            ', 'h1:nth-child(1)', 5, 'h1:nth-child(2)', 6); -SingleBlockSelection = createState('
            This is a test
            ', 'div', 5, 'div', 7); -MultipleBlockSelection = createState('
            This is a test
            Second paragraph
            ', 'div:nth-child(1)', 5, 'div:nth-child(2)', 6); - -SingleBlockWithBrSelection = createState('
            Item1
            Item2
            ', 'div', 3, 'br', 'afterNextCharacter'); -MultipleBlockWithBrSelection = createState('
            Item1
            Item2
            Item3
            ', 'div:nth-child(1)', 2, 'div:nth-child(2)', 3); -MultipleBlockWithBrPartialSelection = createState('
            Item1
            Item2
            Item3
            Item4
            ', 'div:nth-child(1)', 2, 'div:nth-child(2)', 3); -MultipleBlockWithBrPartialSelectionAtEnd = createState('
            Item1
            Item2
            Item3
            Item4
            ', 'div:nth-child(1) br', 'afterNextCharacter', 'div:nth-child(2) br', 'afterNextCharacter'); -MultipleBlockWithEmptyDivsAllSelected = createState('
             
            a
            b
             
            ', '#start', 0, '#end', 0); - -CellWithoutBrSelection = createState('
            Cell 1
            ', 'td', 1, 'td', 1); //selection is a single point so it will avoid table selection bugs in ie9. -CellWithBrSingleLineSelection = createState('
            Cell 1
            Line 2
            ', 'td', 1, 'td', 4); -CellWithBrMultipleLineSelection = createState('
            Cell 1
            Line 2
            ', 'td', 1, 'td', 4); - -TableCellWithTextAfterUL = createState('
            • Existing
            Line1
            Line2
            Line3
            Line4
            ', '#start', 1, '#end', 'afterNextCharacter'); - -ParagraphToHeadingSelection = createState('

            This is a test

            Second paragraph

            ', 'p', 5, 'h1', 6); -ParagraphToBlockSelection = createState('

            This is a test

            Second paragraph
            ', 'p', 5, 'div', 6); -HeadingToParagraphSelection = createState('

            This is a test

            Second paragraph

            ', 'h1', 5, 'p', 6); -BlockToParagraphSelection = createState('
            This is a test

            Second paragraph

            ', 'div', 5, 'p', 6); -MultipleParagraphAndHeadingSelection = createState('

            This is a test

            Second paragraph

            Third paragraph
            ', 'p', 5, 'div', 5); -ThreeBoldDivsWithBrSelection = createState('
            One
            Two
            Three
            ', 'div:nth-child(1) strong', 2, 'div:nth-child(3) strong', 2); - -SingleLiOlSelection = createState('
            1. Item 1
            ', 'li', 1, 'li', 4); -MultiLiOlSelection = createState('
            1. Item 1
            2. Item 2
            ', 'li:nth-child(1)', 1, 'li:nth-child(2)', 4); -SingleLiUlSelection = createState('
            • Item 1
            ', 'li', 1, 'li', 4); -MultiLiUlSelection = createState('
            • Item 1
            • Item 2
            ', 'li:nth-child(1)', 1, 'li:nth-child(2)', 4); -MultiNestedLiUlSelection = createState('
              • Item 1
              • Item 2
            ', 'li li:nth-child(1)', 1, 'li li:nth-child(2)', 4); -MultiNestedLiOlSelection = createState('
              1. Item 1
              2. Item 2
            ', 'li li:nth-child(1)', 1, 'li li:nth-child(2)', 4); - -IndentedOlInOlCorrectSelection = createState('
            1. Item 1
              1. Indented
            ', 'li', 1, 'li li', 4); -IndentedUlInUlCorrectSelection = createState('
            • Item 1
              • Indented
            ', 'li', 1, 'li li', 4); -IndentedOlInOlIncorrectSelection = createState('
            1. Item 1
              1. Indented
            ', 'li', 1, 'ol ol li', 4); -IndentedUlInUlIncorrectSelection = createState('
            • Item 1
              • Indented
            ', 'li', 1, 'ul ul li', 4); - -IndentedOlInUlCorrectSelection = createState('
            • Item 1
              1. Indented
            ', 'li', 1, 'li li', 4); -IndentedUlInOlCorrectSelection = createState('
            1. Item 1
              • Indented
            ', 'li', 1, 'li li', 4); -IndentedOlInUlIncorrectSelection = createState('
            • Item 1
              1. Indented
            ', 'li', 1, 'ul ol li', 4); -IndentedUlInOlIncorrectSelection = createState('
            1. Item 1
              • Indented
            ', 'li', 1, 'ol ul li', 4); - -// TODO: Paragraph/heading to list combinations. -ParagraphBeforeOlSelection = createState('

            Before

            1. Item 1
            ', 'p', 3, 'li', 4); -ParagraphBeforeUlSelection = createState('

            Before

            • Item 1
            ', 'p', 3, 'li', 4); -ParagraphAfterOlSelection = createState('
            1. Item 1

            After

            ', 'li', 4, 'p', 3); -ParagraphAfterUlSelection = createState('
            • Item 1

            After

            ', 'li', 4, 'p', 3); -ParagraphBeforeAndAfterOlSelection = createState('

            Before

            1. Item 1

            After

            ', 'p', 4, '#after', 3); -ParagraphBeforeAndAfterUlSelection = createState('

            Before

            • Item 1

            After

            ', 'p', 4, '#after', 3); - -SelectionEndingAtBr = createState('

            Item
            After

            ', 'p', 2, 'br', 'after'); -SelectionStartingAtBr = createState('

            Before
            Item

            ', 'p', 'after', 'br', 'afterNextCharacter'); diff --git a/tests/qunit/editor/plugins/legacyoutput.html b/tests/qunit/editor/plugins/legacyoutput.js similarity index 50% rename from tests/qunit/editor/plugins/legacyoutput.html rename to tests/qunit/editor/plugins/legacyoutput.js index cb5896e887..13e3a8488b 100644 --- a/tests/qunit/editor/plugins/legacyoutput.html +++ b/tests/qunit/editor/plugins/legacyoutput.js @@ -1,130 +1,93 @@ - - - -Unit tests for Media Plugin - - - - - - - - - -

            Unit tests for Legacyoutput Plugin

            -

            -
            -

            -
              - - - - - +}); \ No newline at end of file diff --git a/tests/qunit/editor/plugins/lists.html b/tests/qunit/editor/plugins/lists.js similarity index 82% rename from tests/qunit/editor/plugins/lists.html rename to tests/qunit/editor/plugins/lists.js index b96881324c..47bf196aed 100644 --- a/tests/qunit/editor/plugins/lists.html +++ b/tests/qunit/editor/plugins/lists.js @@ -1,22 +1,53 @@ - - - -Unit tests for lists plugin - - - - - - - - - -

              Unit tests for lists plugin

              -

              -
              -

              -
                - - [Get raw] - -
                - [Get raw] - - diff --git a/tests/qunit/editor/plugins/media.html b/tests/qunit/editor/plugins/media.js similarity index 76% rename from tests/qunit/editor/plugins/media.html rename to tests/qunit/editor/plugins/media.js index 34b7d5bb11..f1956b3a3e 100644 --- a/tests/qunit/editor/plugins/media.html +++ b/tests/qunit/editor/plugins/media.js @@ -1,20 +1,23 @@ - - - -Unit tests for Media Plugin - - - - - - - - -

                Unit tests for Media Plugin

                -

                -
                -

                -
                  - - - - - diff --git a/tests/qunit/editor/plugins/noneditable.html b/tests/qunit/editor/plugins/noneditable.js similarity index 54% rename from tests/qunit/editor/plugins/noneditable.html rename to tests/qunit/editor/plugins/noneditable.js index c21b242b8a..f0743de396 100644 --- a/tests/qunit/editor/plugins/noneditable.html +++ b/tests/qunit/editor/plugins/noneditable.js @@ -1,32 +1,38 @@ - - - -Unit tests for noneditable - - - - - - - - - -

                  Unit tests noneditable plugin

                  -

                  -
                  -

                  -
                    - - - - diff --git a/tests/qunit/editor/plugins/paste.html b/tests/qunit/editor/plugins/paste.js similarity index 97% rename from tests/qunit/editor/plugins/paste.html rename to tests/qunit/editor/plugins/paste.js index 0bf1b41f74..b531012b9a 100644 --- a/tests/qunit/editor/plugins/paste.html +++ b/tests/qunit/editor/plugins/paste.js @@ -1,23 +1,21 @@ - - - -Unit tests for the Paste plugin - - - - - - - - - - -

                    Unit tests for the Paste plugin

                    -

                    -
                    -

                    -
                      - - - - - diff --git a/tests/qunit/editor/plugins/plugin_dependency_chain.html b/tests/qunit/editor/plugins/plugin_dependency_chain.html deleted file mode 100644 index 748f201f9c..0000000000 --- a/tests/qunit/editor/plugins/plugin_dependency_chain.html +++ /dev/null @@ -1,59 +0,0 @@ - - - -Basic editor functionality tests - - - - - - - - - -

                      Plugin Dependency Functional tests

                      -

                      -
                      -

                      -
                        - - - diff --git a/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html b/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html deleted file mode 100644 index 08cef239e5..0000000000 --- a/tests/qunit/editor/plugins/plugin_dependency_chain_legacy.html +++ /dev/null @@ -1,59 +0,0 @@ - - - -Plugin Dependency Functional tests - - - - - - - - - -

                        Plugin Dependency Functional tests

                        -

                        -
                        -

                        -
                          - - - diff --git a/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html b/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html deleted file mode 100644 index 7f87ed1473..0000000000 --- a/tests/qunit/editor/plugins/plugin_dependency_init_call_order.html +++ /dev/null @@ -1,69 +0,0 @@ - - - -Basic editor functionality tests - - - - - - - - - -

                          Plugin Dependency Functional tests

                          -

                          -
                          -

                          -
                            - - - diff --git a/tests/qunit/editor/plugins/plugin_dependency_specific_location.html b/tests/qunit/editor/plugins/plugin_dependency_specific_location.html deleted file mode 100644 index 1feef33c00..0000000000 --- a/tests/qunit/editor/plugins/plugin_dependency_specific_location.html +++ /dev/null @@ -1,58 +0,0 @@ - - - -Basic editor functionality tests - - - - - - - - - -

                            Plugin Dependency Functional tests

                            -

                            -
                            -

                            -
                              - - - diff --git a/tests/qunit/editor/plugins/searchreplace.html b/tests/qunit/editor/plugins/searchreplace.js similarity index 70% rename from tests/qunit/editor/plugins/searchreplace.html rename to tests/qunit/editor/plugins/searchreplace.js index a3fa93f2b3..2dc31644e5 100644 --- a/tests/qunit/editor/plugins/searchreplace.html +++ b/tests/qunit/editor/plugins/searchreplace.js @@ -1,21 +1,23 @@ - - - -Unit tests for searchreplace plugin - - - - - - - - - -

                              Unit tests for lists plugin

                              -

                              -
                              -

                              -
                                - - [Get raw] - - diff --git a/tests/qunit/editor/plugins/spellchecker.html b/tests/qunit/editor/plugins/spellchecker.html deleted file mode 100644 index 3be00e2b72..0000000000 --- a/tests/qunit/editor/plugins/spellchecker.html +++ /dev/null @@ -1,108 +0,0 @@ - - - -Unit tests for spellchecker plugin - - - - - - - - - -

                                Unit tests for spellchecker plugin

                                -

                                -
                                -

                                -
                                  - - [Get raw] - - [Get raw] - - [Get raw] - - diff --git a/tests/qunit/editor/plugins/spellchecker.js b/tests/qunit/editor/plugins/spellchecker.js new file mode 100644 index 0000000000..e51f9afc39 --- /dev/null +++ b/tests/qunit/editor/plugins/spellchecker.js @@ -0,0 +1,95 @@ +(function() { + var count = 0; + + module("tinymce.plugins.Spellchecker", { + setupModule: function() { + document.getElementById('view').innerHTML = ( + '' + + '' + + '' + ); + + QUnit.stop(); + + function wait() { + if (++count == 3) { + QUnit.start(); + } + } + + tinymce.init({ + selector: '#no_lang', + plugins: "spellchecker", + add_unload_trigger: false, + skin: false, + disable_nodechange: true, + toolbar: 'spellchecker', + init_instance_callback: function(ed) { + window.editor = ed; + wait(); + } + }); + + tinymce.init({ + selector: '#one_lang', + plugins: "spellchecker", + add_unload_trigger: false, + skin: false, + spellchecker_languages: 'English=en', + disable_nodechange: true, + toolbar: 'spellchecker', + init_instance_callback: function(ed) { + window.editor = ed; + wait(); + } + }); + + tinymce.init({ + selector: '#many_lang', + plugins: "spellchecker", + add_unload_trigger: false, + skin: false, + spellchecker_languages: 'English=en,French=fr,German=de', + disable_nodechange: true, + toolbar: 'spellchecker', + init_instance_callback: function(ed) { + window.editor = ed; + wait(); + } + }); + }, + + teardown: function() { + editor.settings.forced_root_block = 'p'; + } + }); + + // Default spellchecker language should match editor language + test('Check default language', function() { + var mainLanguage = tinymce.get('no_lang').settings.language || 'en'; + equal(tinymce.get('no_lang').settings.spellchecker_language, mainLanguage); + }); + + // Spellchecker button may include a language menu + + // When no languages are specified, the default list of languages should be + // used, matching the list in the old TinyMCE 3 spellchecker plugin. + test('Check spellcheck button is a splitbutton (no languages)', function() { + var spellcheckButton = tinymce.get('no_lang').buttons.spellchecker; + equal(spellcheckButton.type, 'splitbutton'); + }); + + // When exactly one spellchecker language is specified, there's no need to + // display a selection menu. + test('Check spellcheck button is a normal button (one language)', function() { + var spellcheckButton = tinymce.get('one_lang').buttons.spellchecker; + equal(spellcheckButton.type, 'button'); + }); + + // When more than one spellchecker language is specified, a selection menu + // should be provided to choose between them. + test('Check spellcheck button is a splitbutton (many languages)', function() { + var spellcheckButton = tinymce.get('many_lang').buttons.spellchecker; + equal(spellcheckButton.type, 'splitbutton'); + }); +})(); diff --git a/tests/qunit/editor/plugins/table.html b/tests/qunit/editor/plugins/table.js similarity index 74% rename from tests/qunit/editor/plugins/table.html rename to tests/qunit/editor/plugins/table.js index 9cbc3219c3..b2a4a737d8 100644 --- a/tests/qunit/editor/plugins/table.html +++ b/tests/qunit/editor/plugins/table.js @@ -1,31 +1,25 @@ - - - -Unit tests for the Table plugin - - - - - - - - - - -

                                  Unit tests for the Table plugin

                                  -

                                  -
                                  -

                                  -
                                    - - - - - diff --git a/tests/qunit/editor/plugins/table_robot.html b/tests/qunit/editor/plugins/table_robot.html deleted file mode 100644 index 351cea6f3b..0000000000 --- a/tests/qunit/editor/plugins/table_robot.html +++ /dev/null @@ -1,189 +0,0 @@ - - - -Table plugin tests - - - - - - - - - - -

                                    Table plugin tests

                                    -

                                    -
                                    -

                                    -
                                      - - - - diff --git a/tests/qunit/editor/plugins/tests.js b/tests/qunit/editor/plugins/tests.js deleted file mode 100644 index b2d4b40eb2..0000000000 --- a/tests/qunit/editor/plugins/tests.js +++ /dev/null @@ -1,24 +0,0 @@ -{ - "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"} - ] -} diff --git a/tests/qunit/editor/plugins/wordcount.html b/tests/qunit/editor/plugins/wordcount.html deleted file mode 100644 index 99595ff584..0000000000 --- a/tests/qunit/editor/plugins/wordcount.html +++ /dev/null @@ -1,122 +0,0 @@ - - - -Unit tests for the Wordcount plugin - - - - - - - - - - -

                                      Unit tests for the Wordcount plugin

                                      -

                                      -
                                      -

                                      -
                                        - -
                                        - Current Count: -
                                        - - - - - diff --git a/tests/qunit/editor/plugins/wordcount.js b/tests/qunit/editor/plugins/wordcount.js new file mode 100644 index 0000000000..508f8be0bf --- /dev/null +++ b/tests/qunit/editor/plugins/wordcount.js @@ -0,0 +1,81 @@ +module("tinymce.plugins.Wordcount", { + setupModule: function() { + QUnit.stop(); + + tinymce.init({ + selector: "textarea", + add_unload_trigger: false, + skin: false, + wordcount_target_id: 'current-count', + plugins: 'wordcount', + init_instance_callback: function(ed) { + window.editor = ed; + QUnit.start(); + } + }); + } +}); + +test("Blank document has 0 words", function() { + expect(1); + + editor.setContent(''); + var result = editor.plugins.wordcount.getCount(); + equal(result, 0); +}); + +test("Simple word count", function() { + expect(1); + + editor.setContent('

                                        My sentence is this.

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 4); +}); + +test("Does not count dashes", function() { + expect(1); + + editor.setContent('

                                        Something -- ok

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 2); +}); + +test("Does not count asterisks, non-word characters", function() { + expect(1); + + editor.setContent('

                                        * something\n\u00b7 something else

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 3); +}); + +test("Does not count numbers", function() { + expect(1); + + editor.setContent('

                                        Something 123 ok

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 2); +}); + +test("Does not count htmlentities", function() { + expect(1); + + editor.setContent('

                                        It’s my life – – – don\'t you forget.

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 6); +}); + +test("Counts hyphenated words as one word", function() { + expect(1); + + editor.setContent('

                                        Hello some-word here.

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 3); +}); + +test("Counts words between blocks as two words", function() { + expect(1); + + editor.setContent('

                                        Hello

                                        world

                                        '); + var result = editor.plugins.wordcount.getCount(); + equal(result, 2); +}); diff --git a/tests/qunit/editor/test.gif b/tests/qunit/editor/test.gif deleted file mode 100644 index e565824aafafe632011b281cba976baf8b3ba89a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43 qcmZ?wbhEHbWMp7uXkcLY4+e@qSs1y10y+#p0Fq%~V)9{Rum%7ZWeN!Z diff --git a/tests/qunit/editor/tinymce/Editor.html b/tests/qunit/editor/tinymce/Editor.js similarity index 75% rename from tests/qunit/editor/tinymce/Editor.html rename to tests/qunit/editor/tinymce/Editor.js index 76ac3bd358..f555bd26d0 100644 --- a/tests/qunit/editor/tinymce/Editor.html +++ b/tests/qunit/editor/tinymce/Editor.js @@ -1,20 +1,24 @@ - - - -Unit tests for tinymce.Editor - - - - - - - - - -

                                        Unit tests for tinymce.Editor

                                        -

                                        -
                                        -

                                        -
                                          - - - - \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/EditorCommands.html b/tests/qunit/editor/tinymce/EditorCommands.js similarity index 87% rename from tests/qunit/editor/tinymce/EditorCommands.html rename to tests/qunit/editor/tinymce/EditorCommands.js index 0631372dd7..3464fc480a 100644 --- a/tests/qunit/editor/tinymce/EditorCommands.html +++ b/tests/qunit/editor/tinymce/EditorCommands.js @@ -1,25 +1,29 @@ - - - -Unit tests for tinymce.EditorCommands - - - - - - - - - -

                                          Unit tests for tinymce.EditorCommands

                                          -

                                          -
                                          -

                                          -
                                            - - - - +}); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/EnterKey.html b/tests/qunit/editor/tinymce/EnterKey.js similarity index 57% rename from tests/qunit/editor/tinymce/EnterKey.html rename to tests/qunit/editor/tinymce/EnterKey.js index 2ed67a06f4..7517273a00 100644 --- a/tests/qunit/editor/tinymce/EnterKey.html +++ b/tests/qunit/editor/tinymce/EnterKey.js @@ -1,22 +1,27 @@ - - - -Unit tests for EnterKey - - - - - - - - - -

                                            Unit tests for tinymce.EnterKey

                                            -

                                            -
                                            -

                                            -
                                              - - - diff --git a/tests/qunit/editor/tinymce/ForceBlocks.html b/tests/qunit/editor/tinymce/ForceBlocks.html deleted file mode 100644 index ea1bd32a3f..0000000000 --- a/tests/qunit/editor/tinymce/ForceBlocks.html +++ /dev/null @@ -1,116 +0,0 @@ - - - -Unit tests for tinymce.ForceBlocks - - - - - - - - - -

                                              Unit tests for tinymce.ForceBlocks

                                              -

                                              -
                                              -

                                              -
                                                - - - diff --git a/tests/qunit/editor/tinymce/ForceBlocks.js b/tests/qunit/editor/tinymce/ForceBlocks.js new file mode 100644 index 0000000000..92b319590d --- /dev/null +++ b/tests/qunit/editor/tinymce/ForceBlocks.js @@ -0,0 +1,82 @@ +module("tinymce.ForceBlocks", { + autostart: false, + setupModule: function() { + QUnit.stop(); + + tinymce.init({ + selector: "textarea", + add_unload_trigger: false, + indent: false, + skin: false, + entities: 'raw', + valid_styles: { + '*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display' + }, + init_instance_callback: function(ed) { + window.editor = ed; + QUnit.start(); + } + }); + }, + + teardown: function() { + editor.settings.forced_root_block = 'p'; + editor.settings.forced_root_block_attrs = null; + } +}); + +test('Wrap single root text node in P', function() { + editor.getBody().innerHTML = 'abcd'; + Utils.setSelection('body', 2); + Utils.pressArrowKey(); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                abcd

                                                '); + 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'; + Utils.setSelection('body', 2); + Utils.pressArrowKey(); + equal(editor.getContent(), '

                                                abcd

                                                '); + equal(editor.selection.getNode().nodeName, 'P'); +}); + +test('Wrap single root text node in P but not table sibling', function() { + editor.getBody().innerHTML = 'abcd
                                                x
                                                '; + Utils.setSelection('body', 2); + Utils.pressArrowKey(); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                abcd

                                                x
                                                '); + equal(editor.selection.getNode().nodeName, 'P'); +}); + +test('Wrap root em in P but not table sibling', function() { + editor.getBody().innerHTML = 'abcd
                                                x
                                                '; + Utils.setSelection('em', 2); + Utils.pressArrowKey(); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                abcd

                                                x
                                                '); + 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'; + Utils.setSelection('body', 2); + Utils.pressArrowKey(); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '
                                                abcd
                                                '); + 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
                                                abcd
                                                '; + Utils.setSelection('body', 2); + body.insertBefore(editor.getDoc().createTextNode(''), body.firstChild); + body.appendChild(editor.getDoc().createTextNode('')); + Utils.pressArrowKey(); + equal(Utils.cleanHtml(body.innerHTML), '
                                                abcd
                                                abcd
                                                '); + equal(editor.selection.getNode().nodeName, 'DIV'); + equal(body.childNodes.length, 2); +}); diff --git a/tests/qunit/editor/tinymce/Formatter_apply.html b/tests/qunit/editor/tinymce/Formatter_apply.js similarity index 72% rename from tests/qunit/editor/tinymce/Formatter_apply.html rename to tests/qunit/editor/tinymce/Formatter_apply.js index cb0fd015af..2326dade60 100644 --- a/tests/qunit/editor/tinymce/Formatter_apply.html +++ b/tests/qunit/editor/tinymce/Formatter_apply.js @@ -1,30 +1,67 @@ - - - -Unit tests for apply formatting - - - - - - - - - -

                                                Unit tests for text formatting

                                                -

                                                -
                                                -

                                                -
                                                  - - -
                                                  - - diff --git a/tests/qunit/editor/tinymce/Formatter_check.html b/tests/qunit/editor/tinymce/Formatter_check.js similarity index 50% rename from tests/qunit/editor/tinymce/Formatter_check.html rename to tests/qunit/editor/tinymce/Formatter_check.js index 793efcff11..eb54b50377 100644 --- a/tests/qunit/editor/tinymce/Formatter_check.html +++ b/tests/qunit/editor/tinymce/Formatter_check.js @@ -1,30 +1,53 @@ - - - -Unit tests for check formatting - - - - - - - - - -

                                                  Unit tests for text formatting

                                                  -

                                                  -
                                                  -

                                                  -
                                                    - - -
                                                    - - diff --git a/tests/qunit/editor/tinymce/Formatter_remove.html b/tests/qunit/editor/tinymce/Formatter_remove.js similarity index 76% rename from tests/qunit/editor/tinymce/Formatter_remove.html rename to tests/qunit/editor/tinymce/Formatter_remove.js index 82add1f17b..2a0747ac65 100644 --- a/tests/qunit/editor/tinymce/Formatter_remove.html +++ b/tests/qunit/editor/tinymce/Formatter_remove.js @@ -1,30 +1,38 @@ - - - -Unit tests for remove formatting - - - - - - - - - -

                                                    Unit tests for text formatting

                                                    -

                                                    -
                                                    -

                                                    -
                                                      - - - - diff --git a/tests/qunit/editor/tinymce/Formatter_robot.html b/tests/qunit/editor/tinymce/Formatter_robot.html deleted file mode 100644 index 34a6e8ffc0..0000000000 --- a/tests/qunit/editor/tinymce/Formatter_robot.html +++ /dev/null @@ -1,94 +0,0 @@ - - - -Basic editor functionality tests - - - - - - - - - - -

                                                      Plugin Dependency Functional tests

                                                      - -

                                                      - -
                                                      -

                                                      -
                                                        - - - - diff --git a/tests/qunit/editor/tinymce/UndoManager.html b/tests/qunit/editor/tinymce/UndoManager.js similarity index 55% rename from tests/qunit/editor/tinymce/UndoManager.html rename to tests/qunit/editor/tinymce/UndoManager.js index ab2d65f796..caac9f1fd6 100644 --- a/tests/qunit/editor/tinymce/UndoManager.html +++ b/tests/qunit/editor/tinymce/UndoManager.js @@ -1,21 +1,17 @@ - - - -tinymce.UndoManager tests - - - - - - - - - -

                                                        tinymce.UndoManager tests

                                                        -

                                                        -
                                                        -

                                                        -
                                                          -
                                                          - - diff --git a/tests/qunit/editor/tinymce/UndoManager_robot.html b/tests/qunit/editor/tinymce/UndoManager_robot.html deleted file mode 100644 index 8c7c285b0d..0000000000 --- a/tests/qunit/editor/tinymce/UndoManager_robot.html +++ /dev/null @@ -1,115 +0,0 @@ - - - -Undo Tests - - - - - - - - - -

                                                          Undo Tests

                                                          -

                                                          -
                                                          -

                                                          -
                                                            -
                                                            - -
                                                            - - - diff --git a/tests/qunit/editor/tinymce/dom/DOMUtils.html b/tests/qunit/editor/tinymce/dom/DOMUtils.html deleted file mode 100644 index 11b85cad48..0000000000 --- a/tests/qunit/editor/tinymce/dom/DOMUtils.html +++ /dev/null @@ -1,27 +0,0 @@ - - - -Unit tests for tinymce.dom.DOMUtils - - - - - - - - - - -

                                                            Unit tests for tinymce.dom.DOMUtils

                                                            -

                                                            -
                                                            -

                                                            -
                                                              -
                                                              - - diff --git a/tests/qunit/editor/tinymce/dom/DOMUtils.js b/tests/qunit/editor/tinymce/dom/DOMUtils.js index d5e180e690..3744131cab 100644 --- a/tests/qunit/editor/tinymce/dom/DOMUtils.js +++ b/tests/qunit/editor/tinymce/dom/DOMUtils.js @@ -1,4 +1,6 @@ (function() { + module("tinymce.dom.DOMUtils"); + var DOM = new tinymce.dom.DOMUtils(document, {keep_values : true, schema : new tinymce.html.Schema()}); test('parseStyle', 11, function() { @@ -6,7 +8,7 @@ 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) { + dom = new tinymce.dom.DOMUtils(document, {hex_colors : true, keep_values : true, url_converter : function(u) { return 'X' + u + 'Y'; }}); @@ -218,10 +220,10 @@ equal(DOM.select('div', 'test').length, 4); ok(DOM.select('div', 'test').reverse); - DOM.setHTML('test', '
                                                              test 1
                                                              test 2
                                                              test 3
                                                              test 4
                                                              ') + DOM.setHTML('test', '
                                                              test 1
                                                              test 2
                                                              test 3
                                                              test 4
                                                              '); equal(DOM.select('div.test2', 'test').length, 2); - DOM.setHTML('test', '
                                                              test 1
                                                              test 2
                                                              test 3
                                                              test 4
                                                              ') + DOM.setHTML('test', '
                                                              test 1
                                                              test 2
                                                              test 3
                                                              test 4
                                                              '); 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); @@ -264,7 +266,7 @@ 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) { + dom = new tinymce.dom.DOMUtils(document, {keep_values : true, url_converter : function(u, n) { return '&<>"' + u + '&<>"' + n; }}); @@ -286,20 +288,19 @@ }); 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) + if (tinymce.inArray(val, o.nodeName.toLowerCase()) != -1 && o.specified) { count++; + } }); return count == obj.length; - }; + } DOM.add(document.body, 'div', {id : 'test'}); @@ -356,7 +357,7 @@ 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', function() {return false;}), null); equal(DOM.getParent('test2', 'SPAN').nodeName, 'SPAN'); equal(DOM.getParent('test2', 'body', DOM.get('test')), null); @@ -435,8 +436,6 @@ }); test('getNext', 5, function() { - var r; - DOM.add(document.body, 'div', {id : 'test'}); DOM.get('test').innerHTML = 'ABC'; @@ -444,14 +443,12 @@ equal(DOM.getNext(DOM.get('test').firstChild, 'em').nodeName, 'EM'); equal(DOM.getNext(DOM.get('test').firstChild, 'div'), null); equal(DOM.getNext(null, 'div'), null); - equal(DOM.getNext(DOM.get('test').firstChild, function(n) {return n.nodeName == 'EM'}).nodeName, 'EM'); + equal(DOM.getNext(DOM.get('test').firstChild, 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 = 'ABC'; @@ -459,7 +456,7 @@ equal(DOM.getPrev(DOM.get('test').lastChild, 'strong').nodeName, 'STRONG'); equal(DOM.getPrev(DOM.get('test').lastChild, 'div'), null); equal(DOM.getPrev(null, 'div'), null); - equal(DOM.getPrev(DOM.get('test').lastChild, function(n) {return n.nodeName == 'STRONG'}).nodeName, 'STRONG'); + equal(DOM.getPrev(DOM.get('test').lastChild, function(n) {return n.nodeName == 'STRONG';}).nodeName, 'STRONG'); DOM.remove('test'); }); @@ -467,11 +464,12 @@ test('loadCSS', 1, function() { var c = 0; - DOM.loadCSS('css/test.css?a=1,css/test.css?a=2,css/test.css?a=3'); + DOM.loadCSS('tinymce/dom/test.css?a=1,tinymce/dom/test.css?a=2,tinymce/dom/test.css?a=3'); tinymce.each(document.getElementsByTagName('link'), function(n) { - if (n.href.indexOf('test.css?a=') != -1) + if (n.href.indexOf('test.css?a=') != -1) { c++; + } }); equal(c, 3, null, tinymce.isOpera); @@ -576,7 +574,7 @@ 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), '
                                                              • first line
                                                                • second line
                                                              • third line
                                                              '); + equal(Utils.cleanHtml(DOM.get('test').innerHTML), '
                                                              • first line
                                                                • second line
                                                              • third line
                                                              '); DOM.remove('test'); }); @@ -630,7 +628,7 @@ DOM.setHTML('test', '
                                                              '); ok(!DOM.isEmpty(DOM.get('test')), 'Non empty complex HTML with achor name'); - DOM.setHTML('test', ''); + DOM.setHTML('test', ''); ok(!DOM.isEmpty(DOM.get('test')), 'Non empty html with img element'); DOM.setHTML('test', ''); diff --git a/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html b/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html deleted file mode 100644 index f9086822e6..0000000000 --- a/tests/qunit/editor/tinymce/dom/DOMUtils_jquery.html +++ /dev/null @@ -1,29 +0,0 @@ - - - -Unit tests for tinymce.dom.DOMUtils - - - - - - - - - - - - -

                                                              Unit tests for tinymce.dom.DOMUtils

                                                              -

                                                              -
                                                              -

                                                              -
                                                                -
                                                                - - diff --git a/tests/qunit/editor/tinymce/dom/EventUtils.html b/tests/qunit/editor/tinymce/dom/EventUtils.js similarity index 76% rename from tests/qunit/editor/tinymce/dom/EventUtils.html rename to tests/qunit/editor/tinymce/dom/EventUtils.js index b2d65be5fc..ff0a47d85d 100644 --- a/tests/qunit/editor/tinymce/dom/EventUtils.html +++ b/tests/qunit/editor/tinymce/dom/EventUtils.js @@ -1,40 +1,31 @@ - - - -Unit tests for the EventUtils class - - - - - - - - - -

                                                                Unit tests for DOM Selection IE implementation

                                                                -

                                                                -
                                                                -

                                                                -
                                                                  -
                                                                  -
                                                                  -
                                                                  - - diff --git a/tests/qunit/editor/tinymce/dom/Range.html b/tests/qunit/editor/tinymce/dom/Range.html deleted file mode 100644 index c8750377ea..0000000000 --- a/tests/qunit/editor/tinymce/dom/Range.html +++ /dev/null @@ -1,606 +0,0 @@ - - - -Unit tests for DOM Range IE implementation - - - - - - - - -

                                                                  Unit tests for DOM Range IE implementation

                                                                  -

                                                                  -
                                                                  -

                                                                  -
                                                                    -
                                                                    -

                                                                    first strong strong second em strong.

                                                                    -

                                                                    bar

                                                                    -

                                                                    some textem textmore text

                                                                    - - - - - - - - - -
                                                                    1abc
                                                                    34
                                                                    -

                                                                    textabcspan

                                                                    -
                                                                    - - diff --git a/tests/qunit/editor/tinymce/dom/Range.js b/tests/qunit/editor/tinymce/dom/Range.js new file mode 100644 index 0000000000..04184e6faa --- /dev/null +++ b/tests/qunit/editor/tinymce/dom/Range.js @@ -0,0 +1,548 @@ +(function() { + module("tinymce.dom.Range", { + setup: function() { + document.getElementById('view').innerHTML = ( + '
                                                                    ' + + '

                                                                    first strong strong second em strong.

                                                                    ' + + '

                                                                    bar

                                                                    ' + + '

                                                                    some textem textmore text

                                                                    ' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
                                                                    1abc
                                                                    34
                                                                    ' + + '

                                                                    textabcspan

                                                                    ' + + '
                                                                    ' + ); + } + }); + + 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; + } + + test("Initial state", function() { + var r = createRng(); + + 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(); + + 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(); + + 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(); + + 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(); + + 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(); + + 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(); + + 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(); + + 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(); + + 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(); + + expect(77); + + r.setStart(document.getElementById('first').firstChild, 1); + r.setEnd(document.getElementById('two').firstChild, 2); + + equal(getHTML(r.cloneContents()), '

                                                                    irst strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1ab
                                                                    '); + 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()), '
                                                                    bc
                                                                    34

                                                                    te

                                                                    '); + 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 strong strong second 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()), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    '); + 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()), '

                                                                    strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    textabc

                                                                    '); + 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()), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1abc
                                                                    34
                                                                    '); + 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()), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    t

                                                                    '); + 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()), '

                                                                    irst strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    '); + 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()), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem text

                                                                    '); + 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()), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some text

                                                                    '); + 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(); + + 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')), '

                                                                    ft strong strong second em strong.

                                                                    '); + }); + + test("test_extractContents2", function() { + var r = createRng(); + + expect(9); + + r.setStart(document.getElementById('two').firstChild, 1); + r.setEnd(document.getElementById('last').firstChild, 2); + + equal(getHTML(r.extractContents()), '
                                                                    bc
                                                                    34

                                                                    te

                                                                    '); + equal(r.startContainer.nodeType, 1); + equal(getHTML(r.startContainer), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1a

                                                                    xtabcspan

                                                                    '); + equal(r.startOffset, 4); + equal(r.endContainer.nodeType, 1); + equal(r.endOffset, 4); + equal(getHTML(r.endContainer), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1a

                                                                    xtabcspan

                                                                    '); + equal(r.collapsed, true); + equal(r.commonAncestorContainer.nodeName, 'DIV'); + }); + + test("test_extractContents3", function() { + var r = createRng(); + + expect(9); + + r.setStart(document.getElementById('sample'), 0); + r.setEnd(document.getElementById('traverse'), 2); + + equal(getHTML(r.extractContents()), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem text

                                                                    '); + equal(getHTML(r.startContainer), '

                                                                    more text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(r.startOffset, 0); + equal(r.endContainer.nodeType, 1); + equal(r.endOffset, 0); + equal(getHTML(r.endContainer), '

                                                                    more text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(getHTML(document.getElementById('sample')), '

                                                                    more text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(r.collapsed, true); + equal(r.commonAncestorContainer.nodeName, 'DIV'); + }); + + test("test_deleteContents1", function() { + var r = createRng(); + + expect(8); + + r.setStart(document.getElementById('two').firstChild, 1); + r.setEnd(document.getElementById('last').firstChild, 2); + r.deleteContents(); + + equal(getHTML(r.startContainer), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1a

                                                                    xtabcspan

                                                                    '); + equal(r.startOffset, 4); + equal(r.endContainer.nodeType, 1); + equal(r.endOffset, 4); + equal(getHTML(r.endContainer), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1a

                                                                    xtabcspan

                                                                    '); + equal(getHTML(document.getElementById('sample')), '

                                                                    first strong strong second em strong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1a

                                                                    xtabcspan

                                                                    '); + equal(r.collapsed, true); + equal(r.commonAncestorContainer.nodeName, 'DIV'); + }); + + test("test_deleteContents2", function() { + var r = createRng(); + + expect(8); + + r.setStart(document.getElementById('first').firstChild, 1); + r.setEnd(document.getElementById('first').lastChild, 4); + r.deleteContents(); + + equal(getHTML(r.startContainer), '

                                                                    fong.

                                                                    '); + equal(r.startOffset, 1); + equal(r.endContainer.nodeType, 1); + equal(r.endOffset, 1); + equal(getHTML(r.endContainer), '

                                                                    fong.

                                                                    '); + equal(getHTML(document.getElementById('sample')), '

                                                                    fong.

                                                                    bar

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(r.collapsed, true); + equal(r.commonAncestorContainer.nodeName, 'P'); + }); + + test("test_deleteContents3", function() { + var r = createRng(); + + expect(8); + + r.setStart(document.getElementById('sample'), 0); + r.setEnd(document.getElementById('sample'), 2); + r.deleteContents(); + + equal(getHTML(r.startContainer), '

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(r.startOffset, 0); + equal(r.endContainer.nodeType, 1); + equal(r.endOffset, 0); + equal(getHTML(r.endContainer), '

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(getHTML(document.getElementById('sample')), '

                                                                    some textem textmore text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(r.collapsed, true); + equal(r.commonAncestorContainer.nodeName, 'DIV'); + }); + + test("test_deleteContents4", function() { + var r = createRng(); + + expect(8); + + r.setStart(document.getElementById('sample'), 0); + r.setEnd(document.getElementById('traverse'), 2); + r.deleteContents(); + + equal(getHTML(r.startContainer), '

                                                                    more text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(r.startOffset, 0); + equal(r.endContainer.nodeType, 1); + equal(r.endOffset, 0); + equal(getHTML(r.endContainer), '

                                                                    more text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + equal(getHTML(document.getElementById('sample')), '

                                                                    more text

                                                                    1abc
                                                                    34

                                                                    textabcspan

                                                                    '); + 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; + + 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"); + }); + } +})(); diff --git a/tests/qunit/editor/tinymce/dom/Selection.html b/tests/qunit/editor/tinymce/dom/Selection.js similarity index 94% rename from tests/qunit/editor/tinymce/dom/Selection.html rename to tests/qunit/editor/tinymce/dom/Selection.js index 90ca2b5ba5..16ef9f57a7 100644 --- a/tests/qunit/editor/tinymce/dom/Selection.html +++ b/tests/qunit/editor/tinymce/dom/Selection.js @@ -1,20 +1,24 @@ - - - -Unit tests for tinymce.dom.Selection - - - - - - - - - -

                                                                    Unit tests for tinymce.dom.Selection

                                                                    -

                                                                    -
                                                                    -

                                                                    -
                                                                      - - - - diff --git a/tests/qunit/editor/tinymce/dom/Serializer.html b/tests/qunit/editor/tinymce/dom/Serializer.js similarity index 92% rename from tests/qunit/editor/tinymce/dom/Serializer.html rename to tests/qunit/editor/tinymce/dom/Serializer.js index 1a5310f364..ea2cde9bfa 100644 --- a/tests/qunit/editor/tinymce/dom/Serializer.html +++ b/tests/qunit/editor/tinymce/dom/Serializer.js @@ -1,20 +1,9 @@ - - - -Unit tests for tinymce.dom.Serializer - - - - - - - - - -

                                                                      Unit tests for tinymce.dom.Serializer

                                                                      -

                                                                      -
                                                                      -

                                                                      -
                                                                        -
                                                                        -
                                                                        -
                                                                        - - diff --git a/tests/qunit/editor/tinymce/dom/TridentSelection.html b/tests/qunit/editor/tinymce/dom/TridentSelection.js similarity index 86% rename from tests/qunit/editor/tinymce/dom/TridentSelection.html rename to tests/qunit/editor/tinymce/dom/TridentSelection.js index 3d5cb87cbb..c36abbb52c 100644 --- a/tests/qunit/editor/tinymce/dom/TridentSelection.html +++ b/tests/qunit/editor/tinymce/dom/TridentSelection.js @@ -1,25 +1,27 @@ - - - -Unit tests for DOM Selection IE implementation - - - - - - - - - - -

                                                                        Unit tests for DOM Selection IE implementation

                                                                        -

                                                                        -
                                                                        -

                                                                        -
                                                                          - - - diff --git a/tests/qunit/editor/tinymce/dom/tests.js b/tests/qunit/editor/tinymce/dom/tests.js deleted file mode 100644 index a31786a801..0000000000 --- a/tests/qunit/editor/tinymce/dom/tests.js +++ /dev/null @@ -1,12 +0,0 @@ -{ - "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"} - ] -} diff --git a/tests/qunit/editor/tinymce/html/DomParser.html b/tests/qunit/editor/tinymce/html/DomParser.html deleted file mode 100644 index a79b84ea0b..0000000000 --- a/tests/qunit/editor/tinymce/html/DomParser.html +++ /dev/null @@ -1,506 +0,0 @@ - - - -tinymce.html.DomParser tests - - - - - - - - - -

                                                                          tinymce.html.DomParser tests

                                                                          -

                                                                          -
                                                                          -

                                                                          -
                                                                            -
                                                                            - - diff --git a/tests/qunit/editor/tinymce/html/DomParser.js b/tests/qunit/editor/tinymce/html/DomParser.js new file mode 100644 index 0000000000..3c5e290c8d --- /dev/null +++ b/tests/qunit/editor/tinymce/html/DomParser.js @@ -0,0 +1,483 @@ +(function() { + module("tinymce.html.DomParser"); + + 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('test'); + equal(serializer.serialize(root), 'test', '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 - - - - - - -

                                                                            tinymce.html.Entities tests

                                                                            -

                                                                            -
                                                                            -

                                                                            -
                                                                              -
                                                                              - - diff --git a/tests/qunit/editor/tinymce/html/Node.html b/tests/qunit/editor/tinymce/html/Node.js similarity index 94% rename from tests/qunit/editor/tinymce/html/Node.html rename to tests/qunit/editor/tinymce/html/Node.js index e3cd5a9a6e..6e51bc7a9e 100644 --- a/tests/qunit/editor/tinymce/html/Node.html +++ b/tests/qunit/editor/tinymce/html/Node.js @@ -1,18 +1,5 @@ - - - -tinymce.html.Node tests - - - - - - - - - -

                                                                              tinymce.html.Node tests

                                                                              -

                                                                              -
                                                                              -

                                                                              -
                                                                                -
                                                                                - - diff --git a/tests/qunit/editor/tinymce/html/obsolete.html b/tests/qunit/editor/tinymce/html/Obsolete.js similarity index 69% rename from tests/qunit/editor/tinymce/html/obsolete.html rename to tests/qunit/editor/tinymce/html/Obsolete.js index aed9260fa9..8295987880 100644 --- a/tests/qunit/editor/tinymce/html/obsolete.html +++ b/tests/qunit/editor/tinymce/html/Obsolete.js @@ -1,26 +1,23 @@ - - - -Support for obsolete tags and attributes in the default HTML 5.0 schema - - - - - - - - - -

                                                                                Support for obsolete tags and attributes in the default HTML 5.0 schema

                                                                                -

                                                                                -
                                                                                -

                                                                                -
                                                                                  - - - - diff --git a/tests/qunit/editor/tinymce/html/SaxParser.html b/tests/qunit/editor/tinymce/html/SaxParser.html deleted file mode 100644 index 584995667c..0000000000 --- a/tests/qunit/editor/tinymce/html/SaxParser.html +++ /dev/null @@ -1,616 +0,0 @@ - - - -tinymce.html.SaxParser tests - - - - - - - - - -

                                                                                  tinymce.html.SaxParser tests

                                                                                  -

                                                                                  -
                                                                                  -

                                                                                  -
                                                                                    -
                                                                                    - - diff --git a/tests/qunit/editor/tinymce/html/SaxParser.js b/tests/qunit/editor/tinymce/html/SaxParser.js new file mode 100644 index 0000000000..d712fc401b --- /dev/null +++ b/tests/qunit/editor/tinymce/html/SaxParser.js @@ -0,0 +1,637 @@ +(function() { + module("tinymce.html.SaxParser"); + + 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() { + var counter, parser; + + expect(46); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Parse attribute formats.'); + deepEqual(counter.counts, {start:1, end:1}, 'Parse attribute formats counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('\'>'); + equal(writer.getContent(), '', 'Parse attributes with <> in them.'); + deepEqual(counter.counts, {start:1, end:1}, 'Parse attributes with <> in them (count).'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Parse compressed attributes.'); + deepEqual(counter.counts, {start:1, end:1}, 'Parse compressed attributes (count).'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Single empty attribute.'); + deepEqual(counter.counts, {start:1, end:1}, 'Single empty attributes (count).'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Empty attribute at end.'); + deepEqual(counter.counts, {start:1, end:1}, 'Empty attribute at end (count).'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Empty attribute at start.'); + deepEqual(counter.counts, {start:1, end:1}, 'Empty attribute at start (count).'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Parse empty element.'); + deepEqual(counter.counts, {start:1}, 'Parse empty element counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Parse attributes with linebreak.'); + deepEqual(counter.counts, {start: 1}, 'Parse attributes with linebreak counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse(''); + equal(writer.getContent(), '', 'Parse attributes with whitespace.'); + deepEqual(counter.counts, {start: 1}, 'Parse attributes with whitespace counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text'); + equal(writer.getContent(), 'text', 'Parse element with namespace.'); + deepEqual(counter.counts, {start:1, text:1, end: 1}, 'Parse element with namespace counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text'); + equal(writer.getContent(), 'text', 'Parse element with dash name.'); + deepEqual(counter.counts, {start:1, text:1, end:1}, 'Parse element with dash name counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text1

                                                                                    text2text3

                                                                                    text4text5'); + equal(writer.getContent(), 'text1

                                                                                    text2text3

                                                                                    text4text5', 'Parse tag soup 1.'); + deepEqual(counter.counts, {text:5, start: 2, end: 2}, 'Parse tag soup 1 counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text1

                                                                                    text2text3

                                                                                    text4text5'); + equal(writer.getContent(), 'text1

                                                                                    text2text3

                                                                                    text4text5', 'Parse tag soup 2.'); + deepEqual(counter.counts, {text: 5, start: 2, end: 2}, 'Parse tag soup 2 counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text1

                                                                                    text2texte>xt4text5'); + equal(writer.getContent(), 'text1

                                                                                    text2tex<t3

                                                                                    te>xt4text5', 'Parse tag soup 3.'); + deepEqual(counter.counts, {text: 5, start: 2, end: 2}, 'Parse tag soup 3 counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text1

                                                                                    text2text3'); + equal(writer.getContent(), 'text1

                                                                                    text2text3

                                                                                    ', 'Parse tag soup 4.'); + deepEqual(counter.counts, {text: 3, start: 2, end: 2}, 'Parse tag soup 4 counts.'); + + counter = createCounter(writer); + parser = new tinymce.html.SaxParser(counter, schema); + writer.reset(); + parser.parse('text1 - - - - - - -

                                                                                    tinymce.html.Schema tests

                                                                                    -

                                                                                    -
                                                                                    -

                                                                                    -
                                                                                      -
                                                                                      - - + diff --git a/tests/qunit/editor/tinymce/html/Serializer.html b/tests/qunit/editor/tinymce/html/Serializer.js similarity index 59% rename from tests/qunit/editor/tinymce/html/Serializer.html rename to tests/qunit/editor/tinymce/html/Serializer.js index ba8bf091a6..151bee8322 100644 --- a/tests/qunit/editor/tinymce/html/Serializer.html +++ b/tests/qunit/editor/tinymce/html/Serializer.js @@ -1,18 +1,5 @@ - - - -tinymce.html.Serializer tests - - - - - - - - - -

                                                                                      tinymce.html.Serializer tests

                                                                                      -

                                                                                      -
                                                                                      -

                                                                                      -
                                                                                        -
                                                                                        - - diff --git a/tests/qunit/editor/tinymce/html/Styles.html b/tests/qunit/editor/tinymce/html/Styles.js similarity index 90% rename from tests/qunit/editor/tinymce/html/Styles.html rename to tests/qunit/editor/tinymce/html/Styles.js index 7c737c9b41..db8dd5c84e 100644 --- a/tests/qunit/editor/tinymce/html/Styles.html +++ b/tests/qunit/editor/tinymce/html/Styles.js @@ -1,18 +1,5 @@ - - - -tinymce.html.Styles tests - - - - - - - - - -

                                                                                        tinymce.html.Styles tests

                                                                                        -

                                                                                        -
                                                                                        -

                                                                                        -
                                                                                          -
                                                                                          - - diff --git a/tests/qunit/editor/tinymce/html/Writer.html b/tests/qunit/editor/tinymce/html/Writer.js similarity index 62% rename from tests/qunit/editor/tinymce/html/Writer.html rename to tests/qunit/editor/tinymce/html/Writer.js index 9516ee0480..8b8dd2f0c2 100644 --- a/tests/qunit/editor/tinymce/html/Writer.html +++ b/tests/qunit/editor/tinymce/html/Writer.js @@ -1,126 +1,131 @@ - - - -tinymce.html.Writer tests - - - - - - - - - -

                                                                                          tinymce.html.Writer tests

                                                                                          -

                                                                                          -
                                                                                          -

                                                                                          -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/html/tests.js b/tests/qunit/editor/tinymce/html/tests.js deleted file mode 100644 index 266c7e9141..0000000000 --- a/tests/qunit/editor/tinymce/html/tests.js +++ /dev/null @@ -1,14 +0,0 @@ -{ - "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"} - ] -} diff --git a/tests/qunit/editor/tinymce/tests.js b/tests/qunit/editor/tinymce/tests.js deleted file mode 100644 index 9e961b6305..0000000000 --- a/tests/qunit/editor/tinymce/tests.js +++ /dev/null @@ -1,15 +0,0 @@ -{ - "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} - ] -} diff --git a/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html b/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html deleted file mode 100644 index 4fa6cd7d84..0000000000 --- a/tests/qunit/editor/tinymce/ui/AbsoluteLayout.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - -ui.AbsoluteLayout Test Suite - - - - - - - - - - - -

                                                                                            ui.AbsoluteLayout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/AbsoluteLayout.js b/tests/qunit/editor/tinymce/ui/AbsoluteLayout.js new file mode 100644 index 0000000000..a239d31f3a --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/AbsoluteLayout.js @@ -0,0 +1,31 @@ +(function() { + module("tinymce.ui.AbsoluteLayout", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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() { + var panel = createPanel({ + items: [ + {type: 'spacer', x: 10, y: 20, w: 100, h: 120, classes: 'red'} + ] + }); + + deepEqual(Utils.rect(panel), [0, 0, 200, 200]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [10, 20, 100, 120]); + }); +})(); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/ui/Button.html b/tests/qunit/editor/tinymce/ui/Button.html deleted file mode 100644 index 51c62319ef..0000000000 --- a/tests/qunit/editor/tinymce/ui/Button.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -Button Test Suite - - - - - - - - - - - -

                                                                                            Button Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Button.js b/tests/qunit/editor/tinymce/ui/Button.js new file mode 100644 index 0000000000..e78fbd164a --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/Button.js @@ -0,0 +1,104 @@ +(function() { + module("tinymce.ui.Button", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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'}); + + Utils.nearlyEqualRects(Utils.rect(button), [0, 0, 34, 30], 4); + }); + + test("button text, size large", function() { + var button = createButton({text: 'X', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(button), [0, 0, 41, 39], 4); + }); + + test("button text, size small", function() { + var button = createButton({text: 'X', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(button), [0, 0, 100, 100]); + deepEqual(Utils.rect(button.getEl().firstChild), [1, 1, 98, 98]); + }); + + test("button icon, size default", function() { + var button = createButton({icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(button), [0, 0, 40, 30], 4); + }); + + test("button icon, size small", function() { + var button = createButton({icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.rect(button), [0, 0, 28, 24], 4); + }); + + test("button icon, size large", function() { + var button = createButton({icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(button), [0, 0, 100, 100]); + deepEqual(Utils.rect(button.getEl().firstChild), [1, 1, 98, 98]); + }); + + test("button text & icon, size default", function() { + var button = createButton({text: 'X', icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(button), [0, 0, 52, 30], 4); + }); + + test("button text & icon, size large", function() { + var button = createButton({text: 'X', icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(button), [0, 0, 59, 40], 4); + }); + + test("button text & icon, size small", function() { + var button = createButton({text: 'X', icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(button), [0, 0, 100, 100]); + deepEqual(Utils.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'}); + }); +})(); + diff --git a/tests/qunit/editor/tinymce/ui/ButtonGroup.html b/tests/qunit/editor/tinymce/ui/ButtonGroup.html deleted file mode 100644 index 3b59e12c47..0000000000 --- a/tests/qunit/editor/tinymce/ui/ButtonGroup.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.ButtonGroup Test Suite - - - - - - - - - - - -

                                                                                            ui.ButtonGroup Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Checkbox.html b/tests/qunit/editor/tinymce/ui/Checkbox.html deleted file mode 100644 index 2674930a3d..0000000000 --- a/tests/qunit/editor/tinymce/ui/Checkbox.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Checkbox Test Suite - - - - - - - - - - - -

                                                                                            ui.Checkbox Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Collection.html b/tests/qunit/editor/tinymce/ui/Collection.html deleted file mode 100644 index dfcb1001c5..0000000000 --- a/tests/qunit/editor/tinymce/ui/Collection.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - -Collection Test Suite - - - - - - - - - - - -

                                                                                            ui.Collection Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Collection.js b/tests/qunit/editor/tinymce/ui/Collection.js new file mode 100644 index 0000000000..5d99672f30 --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/Collection.js @@ -0,0 +1,253 @@ +(function() { + var panel; + + module("tinymce.ui.Collection", { + setupModule: 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')); + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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) { + 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); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/ColorButton.html b/tests/qunit/editor/tinymce/ui/ColorButton.html deleted file mode 100644 index 8a34d49777..0000000000 --- a/tests/qunit/editor/tinymce/ui/ColorButton.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - -Button Test Suite - - - - - - - - - - - -

                                                                                            Button Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/ColorButton.js b/tests/qunit/editor/tinymce/ui/ColorButton.js new file mode 100644 index 0000000000..3b12624275 --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/ColorButton.js @@ -0,0 +1,102 @@ +(function() { + module("tinymce.ui.ColorButton", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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'}); + + Utils.nearlyEqualRects(Utils.rect(colorButton), [0, 0, 42, 30], 4); + }); + + test("colorbutton text, size large", function() { + var colorButton = createColorButton({text: 'X', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(colorButton), [0, 0, 49, 39], 4); + }); + + test("colorbutton text, size small", function() { + var colorButton = createColorButton({text: 'X', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(colorButton), [0, 0, 100, 100]); + deepEqual(Utils.rect(colorButton.getEl().firstChild), [1, 1, 98, 98]); + }); + + test("colorbutton icon, size default", function() { + var colorButton = createColorButton({icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(colorButton), [0, 0, 50, 30], 4); + }); + + test("colorbutton icon, size small", function() { + var colorButton = createColorButton({icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.rect(colorButton), [0, 0, 43, 24], 4); + }); + + test("colorbutton icon, size large", function() { + var colorButton = createColorButton({icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(colorButton), [0, 0, 100, 100]); + deepEqual(Utils.rect(colorButton.getEl().firstChild), [1, 1, 98, 98]); + }); + + test("colorbutton text & icon, size default", function() { + var colorButton = createColorButton({text: 'X', icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(colorButton), [0, 0, 62, 30], 4); + }); + + test("colorbutton text & icon, size large", function() { + var colorButton = createColorButton({text: 'X', icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(colorButton), [0, 0, 69, 40], 4); + }); + + test("colorbutton text & icon, size small", function() { + var colorButton = createColorButton({text: 'X', icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(colorButton), [0, 0, 100, 100]); + deepEqual(Utils.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'}); + }); +})(); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/ui/ComboBox.html b/tests/qunit/editor/tinymce/ui/ComboBox.html deleted file mode 100644 index 09972eef48..0000000000 --- a/tests/qunit/editor/tinymce/ui/ComboBox.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - -ui.ComboBox Test Suite - - - - - - - - - - - -

                                                                                            ui.ComboBox Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Container.html b/tests/qunit/editor/tinymce/ui/Container.html deleted file mode 100644 index a3f18b7d5a..0000000000 --- a/tests/qunit/editor/tinymce/ui/Container.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Container Test Suite - - - - - - - - - - - -

                                                                                            ui.Container Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Control.html b/tests/qunit/editor/tinymce/ui/Control.html deleted file mode 100644 index 7720d3d0c4..0000000000 --- a/tests/qunit/editor/tinymce/ui/Control.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - -Control Test Suite - - - - - - - - - - - -

                                                                                            ui.Control Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Control.js b/tests/qunit/editor/tinymce/ui/Control.js new file mode 100644 index 0000000000..616d3d129c --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/Control.js @@ -0,0 +1,204 @@ +(function() { + module("tinymce.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')); + }); + */ +})(); diff --git a/tests/qunit/editor/tinymce/ui/DragHelper.html b/tests/qunit/editor/tinymce/ui/DragHelper.html deleted file mode 100644 index 5b8f910e56..0000000000 --- a/tests/qunit/editor/tinymce/ui/DragHelper.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.DragHelper Test Suite - - - - - - - - - - - -

                                                                                            ui.DragHelper Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/ElementPath.html b/tests/qunit/editor/tinymce/ui/ElementPath.html deleted file mode 100644 index 85d514c432..0000000000 --- a/tests/qunit/editor/tinymce/ui/ElementPath.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.ElementPath Test Suite - - - - - - - - - - - -

                                                                                            ui.ElementPath Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Factory.html b/tests/qunit/editor/tinymce/ui/Factory.html deleted file mode 100644 index 3bb2ff7aed..0000000000 --- a/tests/qunit/editor/tinymce/ui/Factory.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Factory Test Suite - - - - - - - - - - - -

                                                                                            ui.Factory Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FieldSet.html b/tests/qunit/editor/tinymce/ui/FieldSet.html deleted file mode 100644 index fa61533fb4..0000000000 --- a/tests/qunit/editor/tinymce/ui/FieldSet.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.FieldSet Test Suite - - - - - - - - - - - -

                                                                                            ui.FieldSet Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FilePicker.html b/tests/qunit/editor/tinymce/ui/FilePicker.html deleted file mode 100644 index fbf10ca22b..0000000000 --- a/tests/qunit/editor/tinymce/ui/FilePicker.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.FilePicker Test Suite - - - - - - - - - - - -

                                                                                            ui.FilePicker Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FitLayout.html b/tests/qunit/editor/tinymce/ui/FitLayout.html deleted file mode 100644 index ecae41b288..0000000000 --- a/tests/qunit/editor/tinymce/ui/FitLayout.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - -ui.FitLayout Test Suite - - - - - - - - - - - -

                                                                                            ui.FitLayout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FitLayout.js b/tests/qunit/editor/tinymce/ui/FitLayout.js new file mode 100644 index 0000000000..3ef1acf2a4 --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/FitLayout.js @@ -0,0 +1,57 @@ +(function() { + var panel; + + module("tinymce.ui.FitLayout", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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(Utils.rect(panel), [0, 0, 200, 200]); + deepEqual(Utils.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(Utils.rect(panel), [0, 0, 200, 200]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [4, 4, 192, 192]); + }); + + test("fit with panel inside", function() { + panel = createFitPanel({ + items: [ + {type: 'panel', border: 1} + ] + }); + + deepEqual(Utils.rect(panel), [0, 0, 200, 200]); + deepEqual(Utils.rect(panel.find('panel')[0]), [1, 1, 198, 198]); + }); +})(); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/ui/FlexLayout.html b/tests/qunit/editor/tinymce/ui/FlexLayout.html deleted file mode 100644 index a709dbd538..0000000000 --- a/tests/qunit/editor/tinymce/ui/FlexLayout.html +++ /dev/null @@ -1,915 +0,0 @@ - - - - -ui.FlexLayout Test Suite - - - - - - - - - - - -

                                                                                            ui.FlexLayout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FlexLayout.js b/tests/qunit/editor/tinymce/ui/FlexLayout.js new file mode 100644 index 0000000000..f3bd2681a9 --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/FlexLayout.js @@ -0,0 +1,884 @@ +(function() { + var panel; + + module("tinymce.ui.FlexLayout", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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(); + + Utils.resetScroll(panel.getEl('body')); + + return panel; + } + + test("pack: default, align: default, flex: default", function() { + panel = renderPanel({}); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [40, 0, 20, 20]); + }); + + test("pack: default, align: default, flex: default, borders", function() { + panel = renderPanel({defaults: {border: 1}}); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 22, 22]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [22, 0, 22, 22]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [44, 0, 22, 22]); + }); + + test("pack: default, flex: 1", function() { + panel = renderPanel({ + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [67, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 62, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [62, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [128, 0, 72, 20]); + }); + + test("pack: start, flex: default", function() { + panel = renderPanel({ + pack: "start" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [40, 0, 20, 20]); + }); + + test("pack: start, flex: 1", function() { + panel = renderPanel({ + pack: "start", + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [67, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [133, 0, 67, 20]); + }); + + test("pack: end, flex: default", function() { + panel = renderPanel({ + pack: "end" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [140, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [160, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [180, 0, 20, 20]); + }); + + test("pack: end, flex: 1", function() { + panel = renderPanel({ + pack: "end", + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [67, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [133, 0, 67, 20]); + }); + + test("pack: center, flex: default", function() { + panel = renderPanel({ + pack: "center" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [70, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [90, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [110, 0, 20, 20]); + }); + + test("pack: center, flex: 1", function() { + panel = renderPanel({ + pack: "center", + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [67, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [133, 0, 67, 20]); + }); + + test("pack: start, spacing: 3", function() { + panel = renderPanel({ + layout: "flex", + pack: "start", + spacing: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [23, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [46, 0, 20, 20]); + }); + + test("pack: end, spacing: 3", function() { + panel = renderPanel({ + pack: "end", + spacing: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [134, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [157, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [180, 0, 20, 20]); + }); + + test("pack: center, spacing: 3", function() { + panel = renderPanel({ + pack: "center", + spacing: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [67, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [90, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [113, 0, 20, 20]); + }); + + test("pack: start, padding: 3", function() { + panel = renderPanel({ + pack: "start", + padding: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [23, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.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 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [26, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [49, 3, 20, 20]); + }); + + test("pack: start, align: start", function() { + panel = renderPanel({ + pack: "start", + align: "start" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [40, 0, 20, 20]); + }); + + test("pack start, align: center", function() { + panel = renderPanel({ + pack: "start", + align: "center" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 90, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 90, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [40, 90, 20, 20]); + }); + + test("pack: start, align: end", function() { + panel = renderPanel({ + pack: "start", + align: "end" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 180, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 180, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [40, 180, 20, 20]); + }); + + test("pack: start, align: stretch", function() { + panel = renderPanel({ + pack: "start", + align: "stretch" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 200]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 0, 20, 200]); + Utils.nearlyEqualRects(Utils.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 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 194]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [23, 3, 20, 194]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 43, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [43, 0, 98, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [141, 0, 59, 20]); + }); + + test("pack: justify", function() { + panel = renderPanel({ + pack: "justify" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [90, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [180, 0, 20, 20]); + }); + + test("pack: justify, padding: 3", function() { + panel = renderPanel({ + pack: "justify", + padding: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [90, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [45, 3, 80, 20]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 160, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [160, 0, 80, 20]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 90, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [90, 0, 220, 20]); + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [20, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [40, 0, 20, 20]); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 60, 20]); + panel.items().eq(0).hide(); + panel.reflow(); + + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [67, 0, 67, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [133, 0, 67, 20]); + + panel.layoutRect({w: 400, h: 400}).reflow(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 400, 400]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 133, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [133, 0, 133, 20]); + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 100, 100]); + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 100, 100]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [20, 20, 100, 100]); + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 200, 20]); + Utils.nearlyEqualRects(Utils.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(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 402, 402]); + Utils.nearlyEqualRects(Utils.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(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 110, 40]); + Utils.nearlyEqualRects(Utils.rect(panel.find("panel")[0]), [20, 0, 70, 40]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [30, 10, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [60, 10, 20, 20]); + Utils.nearlyEqualRects(Utils.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(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 80, 40]); + Utils.nearlyEqualRects(Utils.rect(panel.find("panel")[0]), [20, 0, 40, 40]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [30, 10, 20, 20]); + Utils.nearlyEqualRects(Utils.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({}); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 40, 20, 20]); + }); + + test("direction: column, pack: default, flex: 1", function() { + panel = renderColumnPanel({ + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 67, 20, 67]); + Utils.nearlyEqualRects(Utils.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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 62]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 62, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 128, 20, 72]); + }); + + test("direction: column, pack: start, flex: default", function() { + panel = renderColumnPanel({ + pack: "start" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 40, 20, 20]); + }); + + test("direction: column, pack: start, flex: 1", function() { + panel = renderColumnPanel({ + pack: "start", + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 67, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 133, 20, 67]); + }); + + test("direction: column, pack: end, flex: default", function() { + panel = renderColumnPanel({ + pack: "end" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 140, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 160, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 180, 20, 20]); + }); + + test("direction: column, pack: end, flex: 1", function() { + panel = renderColumnPanel({ + pack: "end", + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 67, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 133, 20, 67]); + }); + + test("direction: column, pack: center, flex: default", function() { + panel = renderColumnPanel({ + pack: "center" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 70, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 90, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 110, 20, 20]); + }); + + test("direction: column, pack: center, flex: 1", function() { + panel = renderColumnPanel({ + pack: "center", + defaults: {flex: 1} + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 67, 20, 67]); + Utils.nearlyEqualRects(Utils.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 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 23, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 46, 20, 20]); + }); + + test("direction: column, pack: end, spacing: 3", function() { + panel = renderColumnPanel({ + pack: "end", + spacing: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 134, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 157, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 180, 20, 20]); + }); + + test("direction: column, pack: center, spacing: 3", function() { + panel = renderColumnPanel({ + pack: "center", + spacing: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 67, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 90, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 113, 20, 20]); + }); + + test("direction: column, pack: start, padding: 3", function() { + panel = renderColumnPanel({ + pack: "start", + padding: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [3, 23, 20, 20]); + Utils.nearlyEqualRects(Utils.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 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [3, 26, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [3, 49, 20, 20]); + }); + + test("direction: column, pack: start, align: start", function() { + panel = renderColumnPanel({ + pack: "start", + align: "start" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 40, 20, 20]); + }); + + test("direction: column, pack start, align: center", function() { + panel = renderColumnPanel({ + pack: "start", + align: "center" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [90, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [90, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [90, 40, 20, 20]); + }); + + test("direction: column, pack: start, align: end", function() { + panel = renderColumnPanel({ + pack: "start", + align: "end" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [180, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [180, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [180, 40, 20, 20]); + }); + + test("direction: column, pack: start, align: stretch", function() { + panel = renderColumnPanel({ + pack: "start", + align: "stretch" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 200, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 20, 200, 20]); + Utils.nearlyEqualRects(Utils.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 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 194, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [3, 23, 194, 20]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 43]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 43, 20, 98]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 141, 20, 59]); + }); + + test("direction: column, pack: justify", function() { + panel = renderColumnPanel({ + pack: "justify" + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 90, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 180, 20, 20]); + }); + + test("direction: column, pack: justify, padding: 3", function() { + panel = renderColumnPanel({ + pack: "justify", + padding: 3 + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [3, 90, 20, 20]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [3, 45, 20, 80]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 160]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 160, 20, 80]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 90]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 90, 20, 220]); + Utils.nearlyEqualRects(Utils.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} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 67, 20, 67]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [0, 133, 20, 67]); + + panel.layoutRect({w: 400, h: 400}).reflow(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 400, 400]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 133]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [0, 133, 20, 133]); + Utils.nearlyEqualRects(Utils.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(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 402, 402]); + Utils.nearlyEqualRects(Utils.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(); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 110, 40]); + Utils.nearlyEqualRects(Utils.rect(panel.find("panel")[0]), [20, 0, 70, 40]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[0]), [0, 20, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[1]), [30, 10, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[2]), [60, 10, 20, 20]); + Utils.nearlyEqualRects(Utils.rect(panel.find('spacer')[3]), [90, 20, 20, 20]); + }); +})(); \ No newline at end of file diff --git a/tests/qunit/editor/tinymce/ui/FloatPanel.html b/tests/qunit/editor/tinymce/ui/FloatPanel.html deleted file mode 100644 index 706e8c5b72..0000000000 --- a/tests/qunit/editor/tinymce/ui/FloatPanel.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.FloatPanel Test Suite - - - - - - - - - - - -

                                                                                            ui.FloatPanel Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FlowLayout.html b/tests/qunit/editor/tinymce/ui/FlowLayout.html deleted file mode 100644 index 2e1a0c8970..0000000000 --- a/tests/qunit/editor/tinymce/ui/FlowLayout.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.FlowLayout Test Suite - - - - - - - - - - - -

                                                                                            ui.FlowLayout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Form.html b/tests/qunit/editor/tinymce/ui/Form.html deleted file mode 100644 index 0a79072704..0000000000 --- a/tests/qunit/editor/tinymce/ui/Form.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Form Test Suite - - - - - - - - - - - -

                                                                                            ui.Form Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/FormItem.html b/tests/qunit/editor/tinymce/ui/FormItem.html deleted file mode 100644 index c506d5f21b..0000000000 --- a/tests/qunit/editor/tinymce/ui/FormItem.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.FormItem Test Suite - - - - - - - - - - - -

                                                                                            ui.FormItem Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/GridLayout.html b/tests/qunit/editor/tinymce/ui/GridLayout.html deleted file mode 100644 index 8724cfc0c2..0000000000 --- a/tests/qunit/editor/tinymce/ui/GridLayout.html +++ /dev/null @@ -1,244 +0,0 @@ - - - - -ui.GridLayout Test Suite - - - - - - - - - - - -

                                                                                            ui.GridLayout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/GridLayout.js b/tests/qunit/editor/tinymce/ui/GridLayout.js new file mode 100644 index 0000000000..f4a427ae3e --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/GridLayout.js @@ -0,0 +1,212 @@ +(function() { + module("tinymce.ui.GridLayout", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + function renderGridPanel(settings) { + var panel = tinymce.ui.Factory.create(tinymce.extend({ + type: "panel", + layout: "grid", + defaults: {type: 'spacer'} + }, settings)).renderTo(document.getElementById('view')).reflow(); + + Utils.resetScroll(panel.getEl('body')); + + return panel; + } + + test("automatic grid size 2x2", function() { + var panel = renderGridPanel({ + items: [ + {classes: 'red'}, {classes: 'green'}, + {classes: 'blue'}, {classes: 'cyan'} + ] + }); + + deepEqual(Utils.rect(panel), [0, 0, 40, 40]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [20, 0, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [0, 20, 20, 20]); + deepEqual(Utils.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(Utils.rect(panel), [0, 0, 200, 200]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [0, 0, 17, 22]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [17, 0, 17, 22]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [0, 22, 16, 22]); + deepEqual(Utils.rect(panel.find('spacer')[3]), [17, 22, 17, 22]); + }); + */ + + test("spacing: 3, automatic grid size 2x2", function() { + var panel = renderGridPanel({ + spacing: 3, + items: [ + {classes: 'red'}, {classes: 'green'}, + {classes: 'blue'}, {classes: 'cyan'} + ] + }); + + deepEqual(Utils.rect(panel), [0, 0, 43, 43]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [0, 0, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [23, 0, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [0, 23, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[3]), [23, 23, 20, 20]); + }); + + test("padding: 3, automatic grid size 2x2", function() { + var panel = renderGridPanel({ + padding: 3, + items: [ + {classes: 'red'}, {classes: 'green'}, + {classes: 'blue'}, {classes: 'cyan'} + ] + }); + + deepEqual(Utils.rect(panel), [0, 0, 46, 46]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [23, 3, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [3, 23, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[3]), [23, 23, 20, 20]); + }); + + test("spacing: 3, padding: 3, automatic grid size 2x2", function() { + var panel = renderGridPanel({ + padding: 3, + spacing: 3, + items: [ + {classes: 'red'}, {classes: 'green'}, + {classes: 'blue'}, {classes: 'cyan'} + ] + }); + + deepEqual(Utils.rect(panel), [0, 0, 49, 49]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [3, 3, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [26, 3, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [3, 26, 20, 20]); + deepEqual(Utils.rect(panel.find('spacer')[3]), [26, 26, 20, 20]); + }); + + test("inner elements 100x100 maxWidth/maxHeight: 118 (overflow W+H)", function() { + var 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(Utils.rect(panel), [0, 0, 118, 118]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [0, 0, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [100, 0, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [0, 100, 100, 100]); + deepEqual(Utils.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() { + var 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(Utils.rect(panel), [0, 0, 118, 118]); + deepEqual(Utils.rect(panel.find('spacer')[0]), [20, 20, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [130, 20, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [20, 130, 100, 100]); + deepEqual(Utils.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() { + var 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(Utils.rect(panel.find('spacer')[0]), [0, 0, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [100, 0, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [0, 100, 100, 100]); + deepEqual(Utils.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() { + var 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(Utils.rect(panel.find('spacer')[0]), [0, 0, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[1]), [100, 0, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[2]), [0, 100, 100, 100]); + deepEqual(Utils.rect(panel.find('spacer')[3]), [100, 100, 100, 100]); + equal(panel.layoutRect().contentW, 200); + equal(panel.layoutRect().contentH, 200); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/Iframe.html b/tests/qunit/editor/tinymce/ui/Iframe.html deleted file mode 100644 index 7c2186a4b4..0000000000 --- a/tests/qunit/editor/tinymce/ui/Iframe.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Iframe Test Suite - - - - - - - - - - - -

                                                                                            ui.Iframe Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html b/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html deleted file mode 100644 index f7f289b812..0000000000 --- a/tests/qunit/editor/tinymce/ui/KeyboardNavigation.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.KeyboardNavigation Test Suite - - - - - - - - - - - -

                                                                                            ui.KeyboardNavigation Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Label.html b/tests/qunit/editor/tinymce/ui/Label.html deleted file mode 100644 index 8ef0a538e6..0000000000 --- a/tests/qunit/editor/tinymce/ui/Label.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Label Test Suite - - - - - - - - - - - -

                                                                                            ui.Label Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Layout.html b/tests/qunit/editor/tinymce/ui/Layout.html deleted file mode 100644 index 7209e6bab4..0000000000 --- a/tests/qunit/editor/tinymce/ui/Layout.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Layout Test Suite - - - - - - - - - - - -

                                                                                            ui.Layout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/ListBox.html b/tests/qunit/editor/tinymce/ui/ListBox.html deleted file mode 100644 index 44f79b39d2..0000000000 --- a/tests/qunit/editor/tinymce/ui/ListBox.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.ListBox Test Suite - - - - - - - - - - - -

                                                                                            ui.ListBox Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Menu.html b/tests/qunit/editor/tinymce/ui/Menu.html deleted file mode 100644 index 42843c6f2c..0000000000 --- a/tests/qunit/editor/tinymce/ui/Menu.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Menu Test Suite - - - - - - - - - - - -

                                                                                            ui.Menu Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/MenuBar.html b/tests/qunit/editor/tinymce/ui/MenuBar.html deleted file mode 100644 index 61d0c6cd30..0000000000 --- a/tests/qunit/editor/tinymce/ui/MenuBar.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.MenuBar Test Suite - - - - - - - - - - - -

                                                                                            ui.MenuBar Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/MenuButton.html b/tests/qunit/editor/tinymce/ui/MenuButton.html deleted file mode 100644 index eb7415e570..0000000000 --- a/tests/qunit/editor/tinymce/ui/MenuButton.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - -ui.MenuButton Test Suite - - - - - - - - - - - -

                                                                                            MenuButton Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/MenuButton.js b/tests/qunit/editor/tinymce/ui/MenuButton.js new file mode 100644 index 0000000000..bee2964a7b --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/MenuButton.js @@ -0,0 +1,108 @@ +(function() { + module("tinymce.ui.MenuButton", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 46, 30], 4); + }); + + test("menubutton text, size large", function() { + var menuButton = createMenuButton({text: 'X', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 53, 39], 4); + }); + + test("menubutton text, size small", function() { + var menuButton = createMenuButton({text: 'X', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(menuButton), [0, 0, 100, 100]); + deepEqual(Utils.rect(menuButton.getEl().firstChild), [1, 1, 98, 98]); + }); + + test("menubutton icon, size default", function() { + var menuButton = createMenuButton({icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 52, 30], 4); + }); + + test("menubutton icon, size small", function() { + var menuButton = createMenuButton({icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 39, 24], 4); + }); + + test("menubutton icon, size large", function() { + var menuButton = createMenuButton({icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 56, 40], 6); + }); + + test("menubutton icon, width 100, height 100", function() { + var menuButton = createMenuButton({icon: 'test', width: 100, height: 100}); + + deepEqual(Utils.rect(menuButton), [0, 0, 100, 100]); + deepEqual(Utils.rect(menuButton.getEl().firstChild), [1, 1, 98, 98]); + }); + + test("menubutton text & icon, size default", function() { + var menuButton = createMenuButton({text: 'X', icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 64, 30], 4); + }); + + test("menubutton text & icon, size large", function() { + var menuButton = createMenuButton({text: 'X', icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(menuButton), [0, 0, 71, 40], 4); + }); + + test("menubutton text & icon, size small", function() { + var menuButton = createMenuButton({text: 'X', icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(menuButton), [0, 0, 100, 100]); + deepEqual(Utils.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.on('click', function() {clicks.c = 'c';}); + menuButton.fire('click'); + + deepEqual(clicks, {a: 'a', b: 'b', c: 'c'}); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/MenuItem.html b/tests/qunit/editor/tinymce/ui/MenuItem.html deleted file mode 100644 index b6c06869a9..0000000000 --- a/tests/qunit/editor/tinymce/ui/MenuItem.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.MenuItem Test Suite - - - - - - - - - - - -

                                                                                            ui.MenuItem Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/MessageBox.html b/tests/qunit/editor/tinymce/ui/MessageBox.html deleted file mode 100644 index 20ddc8a3ca..0000000000 --- a/tests/qunit/editor/tinymce/ui/MessageBox.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.MessageBox Test Suite - - - - - - - - - - - -

                                                                                            ui.MessageBox Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Movable.html b/tests/qunit/editor/tinymce/ui/Movable.html deleted file mode 100644 index d62ea1638d..0000000000 --- a/tests/qunit/editor/tinymce/ui/Movable.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Movable Test Suite - - - - - - - - - - - -

                                                                                            ui.Movable Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Panel.html b/tests/qunit/editor/tinymce/ui/Panel.html deleted file mode 100644 index 7e383c3a9a..0000000000 --- a/tests/qunit/editor/tinymce/ui/Panel.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - -ui.Panel - - - - - - - - - - - -

                                                                                            ui.Panel Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Panel.js b/tests/qunit/editor/tinymce/ui/Panel.js new file mode 100644 index 0000000000..80784bdf75 --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/Panel.js @@ -0,0 +1,38 @@ +(function() { + var panel; + + module("tinymce.ui.Panel", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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 + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 100, 100], 4); + }); + + test("panel border: 1, width: 100, height: 100", function() { + panel = createPanel({ + width: 100, + height: 100, + border: 1 + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 100, 100], 4); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/PanelButton.html b/tests/qunit/editor/tinymce/ui/PanelButton.html deleted file mode 100644 index 0b1d66e768..0000000000 --- a/tests/qunit/editor/tinymce/ui/PanelButton.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.PanelButton Test Suite - - - - - - - - - - - -

                                                                                            ui.PanelButton Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Path.html b/tests/qunit/editor/tinymce/ui/Path.html deleted file mode 100644 index 56609f706b..0000000000 --- a/tests/qunit/editor/tinymce/ui/Path.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Path Test Suite - - - - - - - - - - - -

                                                                                            ui.Path Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Radio.html b/tests/qunit/editor/tinymce/ui/Radio.html deleted file mode 100644 index ab95e781be..0000000000 --- a/tests/qunit/editor/tinymce/ui/Radio.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Radio Test Suite - - - - - - - - - - - -

                                                                                            ui.Radio Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/ResizeHandle.html b/tests/qunit/editor/tinymce/ui/ResizeHandle.html deleted file mode 100644 index 95fd6ddaac..0000000000 --- a/tests/qunit/editor/tinymce/ui/ResizeHandle.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.ResizeHandle Test Suite - - - - - - - - - - - -

                                                                                            ui.ResizeHandle Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Scrollable.html b/tests/qunit/editor/tinymce/ui/Scrollable.html deleted file mode 100644 index 2d5df68257..0000000000 --- a/tests/qunit/editor/tinymce/ui/Scrollable.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Scrollable Test Suite - - - - - - - - - - - -

                                                                                            ui.Scrollable Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Selector.html b/tests/qunit/editor/tinymce/ui/Selector.html deleted file mode 100644 index 5c0cb1ab81..0000000000 --- a/tests/qunit/editor/tinymce/ui/Selector.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - -ui.Selector Test Suite - - - - - - - - - - - -

                                                                                            ui.Selector Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Selector.js b/tests/qunit/editor/tinymce/ui/Selector.js new file mode 100644 index 0000000000..b7e1fc4e9b --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/Selector.js @@ -0,0 +1,127 @@ +(function() { + var panel; + + module("tinymce.ui.Selector", { + setupModule: 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')); + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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); + }); +})(); + diff --git a/tests/qunit/editor/tinymce/ui/Spacer.html b/tests/qunit/editor/tinymce/ui/Spacer.html deleted file mode 100644 index e62842a593..0000000000 --- a/tests/qunit/editor/tinymce/ui/Spacer.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Spacer Test Suite - - - - - - - - - - - -

                                                                                            ui.Spacer Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/SplitButton.html b/tests/qunit/editor/tinymce/ui/SplitButton.html deleted file mode 100644 index 63e64396a4..0000000000 --- a/tests/qunit/editor/tinymce/ui/SplitButton.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - -ui.SplitButton Test Suite - - - - - - - - - - - -

                                                                                            Button Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/SplitButton.js b/tests/qunit/editor/tinymce/ui/SplitButton.js new file mode 100644 index 0000000000..ab49c7608f --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/SplitButton.js @@ -0,0 +1,102 @@ +(function() { + module("tinymce.ui.SplitButton", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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'}); + + Utils.nearlyEqualRects(Utils.rect(splitButton), [0, 0, 42, 30], 4); + }); + + test("splitbutton text, size large", function() { + var splitButton = createSplitButton({text: 'X', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(splitButton), [0, 0, 49, 39], 4); + }); + + test("splitbutton text, size small", function() { + var splitButton = createSplitButton({text: 'X', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(splitButton), [0, 0, 100, 100]); + deepEqual(Utils.rect(splitButton.getEl().firstChild), [1, 1, 82, 98]); + }); + + test("splitbutton icon, size default", function() { + var splitButton = createSplitButton({icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(splitButton), [0, 0, 50, 30], 4); + }); + + test("splitbutton icon, size small", function() { + var splitButton = createSplitButton({icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.rect(splitButton), [0, 0, 45, 24], 4); + }); + + test("splitbutton icon, size large", function() { + var splitButton = createSplitButton({icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(splitButton), [0, 0, 100, 100]); + deepEqual(Utils.rect(splitButton.getEl().firstChild), [1, 1, 82, 98]); + }); + + test("splitbutton text & icon, size default", function() { + var splitButton = createSplitButton({text: 'X', icon: 'test'}); + + Utils.nearlyEqualRects(Utils.rect(splitButton), [0, 0, 62, 30], 4); + }); + + test("splitbutton text & icon, size large", function() { + var splitButton = createSplitButton({text: 'X', icon: 'test', size: 'large'}); + + Utils.nearlyEqualRects(Utils.rect(splitButton), [0, 0, 69, 40], 4); + }); + + test("splitbutton text & icon, size small", function() { + var splitButton = createSplitButton({text: 'X', icon: 'test', size: 'small'}); + + Utils.nearlyEqualRects(Utils.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(Utils.rect(splitButton), [0, 0, 100, 100]); + deepEqual(Utils.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'}); + }); +})(); + diff --git a/tests/qunit/editor/tinymce/ui/StackLayout.html b/tests/qunit/editor/tinymce/ui/StackLayout.html deleted file mode 100644 index b1f680ff72..0000000000 --- a/tests/qunit/editor/tinymce/ui/StackLayout.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.StackLayout Test Suite - - - - - - - - - - - -

                                                                                            ui.StackLayout Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/TabPanel.html b/tests/qunit/editor/tinymce/ui/TabPanel.html deleted file mode 100644 index 41c4b9712a..0000000000 --- a/tests/qunit/editor/tinymce/ui/TabPanel.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - -ui.TabPanel Test Suite - - - - - - - - - - - -

                                                                                            ui.TabPanel Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/TabPanel.js b/tests/qunit/editor/tinymce/ui/TabPanel.js new file mode 100644 index 0000000000..512c88341e --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/TabPanel.js @@ -0,0 +1,133 @@ +(function() { + module("tinymce.ui.TabPanel", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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() { + var panel = createTabPanel({ + width: 100, + height: 100, + layout: 'fit' + }); + + deepEqual(Utils.rect(panel), [0, 0, 100, 100]); + Utils.nearlyEqualRects(Utils.rect(panel.items()[0]), [0, 31, 100, 69], 4); + }); + + test("panel width: 100, height: 100, border: 1", function() { + var panel = createTabPanel({ + width: 100, + height: 100, + border: 1, + layout: 'fit' + }); + + deepEqual(Utils.rect(panel), [0, 0, 100, 100]); + Utils.nearlyEqualRects(Utils.rect(panel.items()[0]), [0, 31, 100, 69], 4); + }); + + test("panel width: 100, height: 100, activeTab: 1", function() { + var panel = createTabPanel({ + width: 100, + height: 100, + activeTab: 1, + layout: 'fit' + }); + + deepEqual(Utils.rect(panel), [0, 0, 100, 100]); + Utils.nearlyEqualRects(Utils.rect(panel.items()[1]), [0, 31, 100, 69], 4); + }); + + test("panel width: auto, height: auto, mixed sized widgets", function() { + var 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'} + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 120, 151], 4); + Utils.nearlyEqualRects(Utils.rect(panel.items()[0]), [0, 31, 120, 120], 4); + + panel.activateTab(1); + Utils.nearlyEqualRects(Utils.rect(panel.items()[1]), [0, 31, 120, 120], 4); + + panel.activateTab(2); + Utils.nearlyEqualRects(Utils.rect(panel.items()[2]), [0, 31, 120, 120], 4); + }); + + test("panel width: auto, height: auto, mixed sized containers", function() { + var 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 + } + } + ] + }); + + Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 120, 151], 4); + Utils.nearlyEqualRects(Utils.rect(panel.items()[0]), [0, 31, 120, 120], 4); + + panel.activateTab(1); + Utils.nearlyEqualRects(Utils.rect(panel.items()[1]), [0, 31, 120, 120], 4); + + panel.activateTab(2); + Utils.nearlyEqualRects(Utils.rect(panel.items()[2]), [0, 31, 120, 120], 4); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/TextBox.html b/tests/qunit/editor/tinymce/ui/TextBox.html deleted file mode 100644 index cf0e93f469..0000000000 --- a/tests/qunit/editor/tinymce/ui/TextBox.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - -ui.TextBox Test Suite - - - - - - - - - - - -

                                                                                            ui.TextBox Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/TextBox.js b/tests/qunit/editor/tinymce/ui/TextBox.js new file mode 100644 index 0000000000..069d1939cd --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/TextBox.js @@ -0,0 +1,29 @@ +(function() { + module("tinymce.ui.TextBox", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + } + }); + + 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}); + + Utils.nearlyEqualRects(Utils.size(textBox), [69, 30], 30); + }); + + test("textbox text, size 100x100", function() { + var textBox = createTextBox({text: 'X', width: 100, height: 100}); + + deepEqual(Utils.size(textBox), [100, 100]); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/Throbber.html b/tests/qunit/editor/tinymce/ui/Throbber.html deleted file mode 100644 index fa32591140..0000000000 --- a/tests/qunit/editor/tinymce/ui/Throbber.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Throbber Test Suite - - - - - - - - - - - -

                                                                                            ui.Throbber Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Toolbar.html b/tests/qunit/editor/tinymce/ui/Toolbar.html deleted file mode 100644 index f0c00418b9..0000000000 --- a/tests/qunit/editor/tinymce/ui/Toolbar.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Toolbar Test Suite - - - - - - - - - - - -

                                                                                            ui.Toolbar Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Tooltip.html b/tests/qunit/editor/tinymce/ui/Tooltip.html deleted file mode 100644 index a01db34abe..0000000000 --- a/tests/qunit/editor/tinymce/ui/Tooltip.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Tooltip Test Suite - - - - - - - - - - - -

                                                                                            ui.Tooltip Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Widget.html b/tests/qunit/editor/tinymce/ui/Widget.html deleted file mode 100644 index 77cf19edee..0000000000 --- a/tests/qunit/editor/tinymce/ui/Widget.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - -ui.Widget Test Suite - - - - - - - - - - - -

                                                                                            ui.Widget Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Window.html b/tests/qunit/editor/tinymce/ui/Window.html deleted file mode 100644 index de07e8fec7..0000000000 --- a/tests/qunit/editor/tinymce/ui/Window.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - -ui.Window - - - - - - - - - - - -

                                                                                            ui.Window Test Suite

                                                                                            -

                                                                                            -

                                                                                            -
                                                                                              -
                                                                                            -
                                                                                            - - diff --git a/tests/qunit/editor/tinymce/ui/Window.js b/tests/qunit/editor/tinymce/ui/Window.js new file mode 100644 index 0000000000..461bb98fdc --- /dev/null +++ b/tests/qunit/editor/tinymce/ui/Window.js @@ -0,0 +1,87 @@ +(function() { + module("tinymce.ui.Window", { + setup: function() { + document.getElementById('view').innerHTML = ''; + }, + + teardown: function() { + tinymce.dom.Event.clean(document.getElementById('view')); + tinymce.DOM.remove(document.getElementById('mce-modal-block')); + } + }); + + 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() { + var win = createWindow({x: 100, y: 120, width: 200, height: 210}); + + Utils.nearlyEqualRects(Utils.size(win), [200, 210]); + }); + + test("no title, no buttonbar, autoResize", function() { + var win = createWindow({ + x: 100, + y: 120, + items: [ + {type: 'spacer', classes: 'red'} + ] + }); + + Utils.nearlyEqualRects(Utils.size(win), [22, 22]); + Utils.nearlyEqualRects(Utils.size(win.find("spacer")[0]), [20, 20]); + }); + + test("title, no buttonbar, autoResize, title is widest", function() { + var win = createWindow({ + x: 100, + y: 120, + title: "XXXXXXXXXXXXXXXXXXXXXX", + items: [ + {type: 'spacer', classes: 'red', flex: 1} + ] + }); + + Utils.nearlyEqualRects(Utils.size(win), [326, 61], 60); + Utils.nearlyEqualRects(Utils.size(win.find("spacer")[0]), [324, 20], 60); + }); + + test("buttonbar, autoResize, buttonbar is widest", function() { + var win = createWindow({ + x: 100, + y: 120, + items: [ + {type: 'spacer', classes: 'red', flex: 1} + ], + buttons: [ + {type: 'spacer', classes: 'green', minWidth: 400} + ] + }); + + Utils.nearlyEqualRects(Utils.size(win), [422, 63]); + Utils.nearlyEqualRects(Utils.size(win.find("spacer")[0]), [420, 20]); + Utils.nearlyEqualRects(Utils.size(win.statusbar.find("spacer")[0]), [400, 20]); + }); + + test("buttonbar, title, autoResize, content is widest", function() { + var win = createWindow({ + x: 100, + y: 120, + title: "X", + items: [ + {type: 'spacer', classes: 'red', minWidth: 400} + ], + buttons: [ + {type: 'spacer', classes: 'green'} + ] + }); + + Utils.nearlyEqualRects(Utils.size(win), [402, 102]); + Utils.nearlyEqualRects(Utils.size(win.getEl("head")), [400, 39]); + Utils.nearlyEqualRects(Utils.size(win.find("spacer")[0]), [400, 20]); + Utils.nearlyEqualRects(Utils.size(win.statusbar.find("spacer")[0]), [20, 20]); + }); +})(); diff --git a/tests/qunit/editor/tinymce/ui/tests.js b/tests/qunit/editor/tinymce/ui/tests.js deleted file mode 100644 index db7f74f3d8..0000000000 --- a/tests/qunit/editor/tinymce/ui/tests.js +++ /dev/null @@ -1,55 +0,0 @@ -{ - "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"} - ] -} diff --git a/tests/qunit/editor/tinymce/util/JSON.html b/tests/qunit/editor/tinymce/util/JSON.html deleted file mode 100644 index a27f6acf51..0000000000 --- a/tests/qunit/editor/tinymce/util/JSON.html +++ /dev/null @@ -1,39 +0,0 @@ - - - -tinymce.util.JSON tests - - - - - - - - - -

                                                                                            tinymce.util.JSON tests

                                                                                            -

                                                                                            -
                                                                                            -

                                                                                            -
                                                                                              -
                                                                                              - - diff --git a/tests/qunit/editor/tinymce/util/JSON.js b/tests/qunit/editor/tinymce/util/JSON.js new file mode 100644 index 0000000000..846779710f --- /dev/null +++ b/tests/qunit/editor/tinymce/util/JSON.js @@ -0,0 +1,31 @@ +module("tinymce.util.JSON"); + +test('serialize', 2, function() { + equal( + tinymce.util.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( + tinymce.util.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(tinymce.util.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'); +}); diff --git a/tests/qunit/editor/tinymce/util/JSONRequest.html b/tests/qunit/editor/tinymce/util/JSONRequest.html deleted file mode 100644 index 4698f03385..0000000000 --- a/tests/qunit/editor/tinymce/util/JSONRequest.html +++ /dev/null @@ -1,77 +0,0 @@ - - - -tinymce.util.JSONRequest tests - - - - - - - - - -

                                                                                              tinymce.util.JSONRequest tests

                                                                                              -

                                                                                              -
                                                                                              -

                                                                                              -
                                                                                                -
                                                                                                - - diff --git a/tests/qunit/editor/tinymce/util/JSONRequest.js b/tests/qunit/editor/tinymce/util/JSONRequest.js new file mode 100644 index 0000000000..94cd44ba16 --- /dev/null +++ b/tests/qunit/editor/tinymce/util/JSONRequest.js @@ -0,0 +1,55 @@ +if (location.protocol != "file:") { + module("tinymce.util.JSONRequest"); + + asyncTest("Successful request - send method", function() { + expect(1); + + new tinymce.util.JSONRequest({}).send({ + type : 'GET', + url : 'tinymce/util/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 : 'tinymce/util/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 : 'tinymce/util/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 : 'tinymce/util/json_rpc_error.js', + error: function(error) { + equal(error.code, 42); + start(); + } + }); + }); +} diff --git a/tests/qunit/editor/tinymce/util/LocalStorage.html b/tests/qunit/editor/tinymce/util/LocalStorage.html deleted file mode 100644 index 2c405a6d0e..0000000000 --- a/tests/qunit/editor/tinymce/util/LocalStorage.html +++ /dev/null @@ -1,118 +0,0 @@ - - - -tinymce.util.LocalStorage tests - - - - - - - - - -

                                                                                                tinymce.util.Cookie tests

                                                                                                -

                                                                                                -
                                                                                                -

                                                                                                -
                                                                                                  -
                                                                                                  - - diff --git a/tests/qunit/editor/tinymce/util/LocalStorage.js b/tests/qunit/editor/tinymce/util/LocalStorage.js new file mode 100644 index 0000000000..1a4d0f4da4 --- /dev/null +++ b/tests/qunit/editor/tinymce/util/LocalStorage.js @@ -0,0 +1,99 @@ +(function() { + 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"); + }); +})(); + diff --git a/tests/qunit/editor/tinymce/util/Quirks_all.html b/tests/qunit/editor/tinymce/util/Quirks_all.html deleted file mode 100644 index 282aab41d5..0000000000 --- a/tests/qunit/editor/tinymce/util/Quirks_all.html +++ /dev/null @@ -1,76 +0,0 @@ - - - -All browser types Quirks - - - - - - - - - - -

                                                                                                  All browser types Quirks

                                                                                                  -

                                                                                                  -
                                                                                                  -

                                                                                                  -
                                                                                                    - - - - diff --git a/tests/qunit/editor/tinymce/util/Quirks_firefox.html b/tests/qunit/editor/tinymce/util/Quirks_firefox.html deleted file mode 100644 index 01ebd756f5..0000000000 --- a/tests/qunit/editor/tinymce/util/Quirks_firefox.html +++ /dev/null @@ -1,75 +0,0 @@ - - - -Firefox Quirks - - - - - - - - - - -

                                                                                                    Firefox Quirks

                                                                                                    -

                                                                                                    -
                                                                                                    -

                                                                                                    -
                                                                                                      - - - - diff --git a/tests/qunit/editor/tinymce/util/Quirks_ie8.html b/tests/qunit/editor/tinymce/util/Quirks_ie8.html deleted file mode 100644 index aa3f61e745..0000000000 --- a/tests/qunit/editor/tinymce/util/Quirks_ie8.html +++ /dev/null @@ -1,82 +0,0 @@ - - - -Internet Explorer 8 Quirks - - - - - - - - - - -

                                                                                                      Internet Explorer 8 Quirks

                                                                                                      -

                                                                                                      -
                                                                                                      -

                                                                                                      -
                                                                                                        - - - - diff --git a/tests/qunit/editor/tinymce/util/Quirks_remove.html b/tests/qunit/editor/tinymce/util/Quirks_remove.html deleted file mode 100644 index 15508ef312..0000000000 --- a/tests/qunit/editor/tinymce/util/Quirks_remove.html +++ /dev/null @@ -1,270 +0,0 @@ - - - -Removing content tests - - - - - - - - - - -

                                                                                                        Removing content tests

                                                                                                        -

                                                                                                        -
                                                                                                        -

                                                                                                        -
                                                                                                          -
                                                                                                          - -
                                                                                                          - - - diff --git a/tests/qunit/editor/tinymce/util/Quirks_webkit.html b/tests/qunit/editor/tinymce/util/Quirks_webkit.html deleted file mode 100644 index 8684a3de1a..0000000000 --- a/tests/qunit/editor/tinymce/util/Quirks_webkit.html +++ /dev/null @@ -1,135 +0,0 @@ - - - -Webkit Quirks - - - - - - - - - -

                                                                                                          Webkit Quirks

                                                                                                          -

                                                                                                          -
                                                                                                          -

                                                                                                          -
                                                                                                            - - - diff --git a/tests/qunit/editor/tinymce/util/Quirks_webkit.js b/tests/qunit/editor/tinymce/util/Quirks_webkit.js new file mode 100644 index 0000000000..78de7939a0 --- /dev/null +++ b/tests/qunit/editor/tinymce/util/Quirks_webkit.js @@ -0,0 +1,98 @@ +module("tinymce.utils.Quirks_WebKit", { + setupModule: function() { + QUnit.stop(); + + tinymce.init({ + selector: "textarea", + elements: "elm1", + add_unload_trigger: false, + skin: false, + indent: false, + disable_nodechange: true, + init_instance_callback : function(ed) { + window.editor = ed; + QUnit.start(); + } + }); + } +}); + +if (tinymce.isWebKit) { + test('Delete from beginning of P into H1', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            b

                                                                                                            '; + Utils.setSelection('p', 0); + editor.execCommand('Delete'); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                                                                            ab

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('Delete whole H1 before P', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            b

                                                                                                            '; + + var rng = editor.selection.getRng(); + rng.setStartBefore(editor.getBody().firstChild); + rng.setEndAfter(editor.getBody().firstChild); + editor.selection.setRng(rng); + + editor.execCommand('Delete'); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                                                                            b

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('Delete from beginning of P with style span inside into H1', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            bc

                                                                                                            '; + Utils.setSelection('p', 0); + editor.execCommand('Delete'); + equal(Utils.normalizeHtml(Utils.cleanHtml(editor.getBody().innerHTML)), '

                                                                                                            abc

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('ForwardDelete from end of H1 into P', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            b

                                                                                                            '; + Utils.setSelection('h1', 1); + editor.execCommand('ForwardDelete'); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                                                                            ab

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('ForwardDelete whole H1 before P', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            b

                                                                                                            '; + + var rng = editor.selection.getRng(); + rng.setStartBefore(editor.getBody().firstChild); + rng.setEndAfter(editor.getBody().firstChild); + editor.selection.setRng(rng); + + editor.execCommand('ForwardDelete'); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                                                                            b

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('ForwardDelete from end of H1 into P with style span inside', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            bc

                                                                                                            '; + Utils.setSelection('h1', 1); + editor.execCommand('ForwardDelete'); + equal(Utils.normalizeHtml(Utils.cleanHtml(editor.getBody().innerHTML)), '

                                                                                                            abc

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('Backspace key from beginning of P into H1', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            b

                                                                                                            '; + Utils.setSelection('p', 0); + editor.fire("keydown", {keyCode: 8}); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                                                                            ab

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); + + test('Delete key from end of H1 into P', function() { + editor.getBody().innerHTML ='

                                                                                                            a

                                                                                                            b

                                                                                                            '; + Utils.setSelection('h1', 1); + editor.fire("keydown", {keyCode: 46}); + equal(Utils.cleanHtml(editor.getBody().innerHTML), '

                                                                                                            ab

                                                                                                            '); + equal(editor.selection.getStart().nodeName, 'H1'); + }); +} else { + test("Skipped since the browser isn't WebKit", function() { + ok(true, "Skipped"); + }); +} diff --git a/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html b/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html deleted file mode 100644 index 9a996a01ca..0000000000 --- a/tests/qunit/editor/tinymce/util/Quirks_webkit_jsrobot.html +++ /dev/null @@ -1,205 +0,0 @@ - - - -Webkit Quirks - - - - - - - - - - -

                                                                                                            Webkit Quirks

                                                                                                            -

                                                                                                            -
                                                                                                            -

                                                                                                            -
                                                                                                              - - - - diff --git a/tests/qunit/editor/tinymce/util/URI.html b/tests/qunit/editor/tinymce/util/URI.html deleted file mode 100644 index 91adc88b64..0000000000 --- a/tests/qunit/editor/tinymce/util/URI.html +++ /dev/null @@ -1,111 +0,0 @@ - - - -tinymce.util.URI tests - - - - - - - - - -

                                                                                                              tinymce.html.Entities tests

                                                                                                              -

                                                                                                              -
                                                                                                              -

                                                                                                              -
                                                                                                                -
                                                                                                                - - diff --git a/tests/qunit/editor/tinymce/util/URI.js b/tests/qunit/editor/tinymce/util/URI.js new file mode 100644 index 0000000000..4de84509ee --- /dev/null +++ b/tests/qunit/editor/tinymce/util/URI.js @@ -0,0 +1,85 @@ +module("tinymce.util.URI"); + +test('protocol relative url', function() { + var uri = new tinymce.util.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 tinymce.util.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 tinymce.util.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 tinymce.util.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 tinymce.util.URI('http://www.site.com/dir1/dir2/file.html').toRelative('http://www.site.com/dir1/dir3/file.html'), '../dir3/file.html'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/file.html').toRelative('http://www.site.com/dir3/dir4/file.html'), '../../dir3/dir4/file.html'); + equal(new tinymce.util.URI('http://www.site.com/dir1/').toRelative('http://www.site.com/dir1/dir3/file.htm'), 'dir3/file.htm'); + equal(new tinymce.util.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 tinymce.util.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 tinymce.util.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 tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('/file.htm'), '../../file.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('/file.htm?id=1#a'), '../../file.htm?id=1#a'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('mailto:test@test.com'), 'mailto:test@test.com'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('news:test'), 'news:test'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('javascript:void(0);'), 'javascript:void(0);'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('about:blank'), 'about:blank'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('#test'), '#test'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('test.htm'), 'test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('http://www.site.com/dir1/dir2/test.htm'), 'test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('dir2/test.htm'), 'dir2/test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('../dir2/test.htm'), 'test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('../dir3/'), '../dir3/'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('../../../../../../test.htm'), '../../test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('//www.site.com/test.htm'), '../../test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('@@tinymce'), '@@tinymce'); // Zope 3 URL + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('../@@tinymce'), '../@@tinymce'); // Zope 3 URL + equal(new tinymce.util.URI('http://www.site.com/').toRelative('dir2/test.htm'), 'dir2/test.htm'); + equal(new tinymce.util.URI('http://www.site.com/').toRelative('./'), './'); + equal(new tinymce.util.URI('http://www.site.com/test/').toRelative('../'), '../'); + equal(new tinymce.util.URI('http://www.site.com/test/test/').toRelative('../'), '../'); + equal(new tinymce.util.URI('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890/dir1/dir2/').toRelative('/dir1', true), '../'); + equal(new tinymce.util.URI('http://www.site.com/').toRelative('http://www.site.com/'), 'http://www.site.com/'); + equal(new tinymce.util.URI('http://www.site.com/').toRelative('http://www.site.com'), 'http://www.site.com/'); +}); + +test('absoluteURLs', 18, function() { + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('../dir3'), 'http://www.site.com/dir1/dir3'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('../dir3', 1), '/dir1/dir3'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('../../../../dir3'), 'http://www.site.com/dir3'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('../abc/def/../../abc/../dir3/file.htm'), 'http://www.site.com/dir1/dir3/file.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('http://www.site.com/dir2/dir3'), 'http://www.site.com/dir2/dir3'); + equal(new tinymce.util.URI('http://www.site2.com/dir1/dir2/').toAbsolute('http://www.site2.com/dir2/dir3'), 'http://www.site2.com/dir2/dir3'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('mailto:test@test.com'), 'mailto:test@test.com'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('news:test'), 'news:test'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('javascript:void(0);'), 'javascript:void(0);'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('about:blank'), 'about:blank'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('#test'), '#test'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('test.htm'), 'http://www.site.com/dir1/dir2/test.htm'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('../@@tinymce'), 'http://www.site.com/dir1/@@tinymce'); // Zope 3 URL + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').getURI(), 'http://www.site.com/dir1/dir2/'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('/dir1/dir1/'), 'http://www.site.com/dir1/dir1/'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('https://www.site.com/dir1/dir2/', true), 'https://www.site.com/dir1/dir2/'); + equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute('http://www.site.com/dir1/dir2/', true), '/dir1/dir2/'); + equal(new tinymce.util.URI('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890/dir1/dir2/').toAbsolute('chrome-extension://abcdefghijklmnopqrstuvwzyz1234567890/dir1/dir2/', true), '/dir1/dir2/'); +}); + +test('strangeURLs', 6, function() { + equal(new tinymce.util.URI('//www.site.com').getURI(), '//www.site.com'); + equal(new tinymce.util.URI('mailto:test@test.com').getURI(), 'mailto:test@test.com'); + equal(new tinymce.util.URI('news:somegroup').getURI(), 'news:somegroup'); + equal(new tinymce.util.URI('skype:somegroup').getURI(), 'skype:somegroup'); + equal(new tinymce.util.URI('tel:somegroup').getURI(), 'tel:somegroup'); + equal(new tinymce.util.URI('//www.site.com/a@b').getURI(), '//www.site.com/a@b'); +}); diff --git a/tests/qunit/editor/tinymce/util/XHR.html b/tests/qunit/editor/tinymce/util/XHR.html deleted file mode 100644 index 90b33eb758..0000000000 --- a/tests/qunit/editor/tinymce/util/XHR.html +++ /dev/null @@ -1,53 +0,0 @@ - - - -tinymce.util.XHR tests - - - - - - - - - -

                                                                                                                tinymce.util.XHR tests

                                                                                                                -

                                                                                                                -
                                                                                                                -

                                                                                                                -
                                                                                                                  -
                                                                                                                  - - diff --git a/tests/qunit/editor/tinymce/util/XHR.js b/tests/qunit/editor/tinymce/util/XHR.js new file mode 100644 index 0000000000..8b72c1915c --- /dev/null +++ b/tests/qunit/editor/tinymce/util/XHR.js @@ -0,0 +1,31 @@ +if (location.protocol != "file:") { + module("tinymce.util.XHR"); + + asyncTest("Successful request", function() { + expect(3); + + tinymce.util.XHR.send({ + url : 'tinymce/util/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, 'tinymce/util/json_rpc_ok.js'); + start(); + } + }); + }); + + asyncTest("Unsuccessful request", function() { + expect(3); + + tinymce.util.XHR.send({ + url : 'tinymce/util/404.js', + error: function(type, xhr, input) { + equal(type, 'GENERAL'); + ok(!!xhr.status); + equal(input.url, 'tinymce/util/404.js'); + start(); + } + }); + }); +} diff --git a/tests/qunit/editor/tinymce/util/tests.js b/tests/qunit/editor/tinymce/util/tests.js deleted file mode 100644 index 642d6701e8..0000000000 --- a/tests/qunit/editor/tinymce/util/tests.js +++ /dev/null @@ -1,16 +0,0 @@ -{ - "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} - ] -}