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 e565824aaf..0000000000 Binary files a/tests/qunit/editor/test.gif and /dev/null differ 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} - ] -}