TinyMCE: update to 4.0.28+. Includes all changes until 09-06-2014: 32cb108d41
. Changelog: 32cb108d41/changelog.txt
.
See #28391. git-svn-id: https://develop.svn.wordpress.org/trunk@28768 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
f1172ba195
commit
b8fd9d997e
|
@ -40,14 +40,27 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
img.src = url;
|
||||
}
|
||||
|
||||
function applyPreview(items) {
|
||||
tinymce.each(items, function(item) {
|
||||
item.textStyle = function() {
|
||||
return editor.formatter.getCssText({inline: 'img', classes: [item.value]});
|
||||
};
|
||||
});
|
||||
function buildListItems(inputList, itemCallback, startItems) {
|
||||
function appendItems(values, output) {
|
||||
output = output || [];
|
||||
|
||||
return items;
|
||||
tinymce.each(values, function(item) {
|
||||
var menuItem = {text: item.text || item.title};
|
||||
|
||||
if (item.menu) {
|
||||
menuItem.menu = appendItems(item.menu);
|
||||
} else {
|
||||
menuItem.value = item.value;
|
||||
itemCallback(menuItem);
|
||||
}
|
||||
|
||||
output.push(menuItem);
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return appendItems(inputList, startItems || []);
|
||||
}
|
||||
|
||||
function createImageList(callback) {
|
||||
|
@ -71,53 +84,7 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
|
||||
function showDialog(imageList) {
|
||||
var win, data = {}, dom = editor.dom, imgElm = editor.selection.getNode();
|
||||
var width, height, imageListCtrl, classListCtrl;
|
||||
|
||||
function buildValues(listSettingName, dataItemName, defaultItems) {
|
||||
var selectedItem, items = [];
|
||||
|
||||
tinymce.each(editor.settings[listSettingName] || defaultItems, function(target) {
|
||||
var item = {
|
||||
text: target.text || target.title,
|
||||
value: target.value
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
|
||||
if (data[dataItemName] === target.value || (!selectedItem && target.selected)) {
|
||||
selectedItem = item;
|
||||
}
|
||||
});
|
||||
|
||||
if (selectedItem && !data[dataItemName]) {
|
||||
data[dataItemName] = selectedItem.value;
|
||||
selectedItem.selected = true;
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function buildImageList() {
|
||||
function appendItems(values, output) {
|
||||
output = output || [];
|
||||
|
||||
tinymce.each(values, function(value) {
|
||||
var item = {text: value.text || value.title};
|
||||
|
||||
if (value.menu) {
|
||||
item.menu = appendItems(value.menu);
|
||||
} else {
|
||||
item.value = editor.convertURL(value.value || value.url, 'src');
|
||||
}
|
||||
|
||||
output.push(item);
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return appendItems(imageList, [{text: 'None', value: ''}]);
|
||||
}
|
||||
var width, height, imageListCtrl, classListCtrl, imageDimensions = editor.settings.image_dimensions !== false;
|
||||
|
||||
function recalcSize() {
|
||||
var widthCtrl, heightCtrl, newWidth, newHeight;
|
||||
|
@ -125,6 +92,10 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
widthCtrl = win.find('#width')[0];
|
||||
heightCtrl = win.find('#height')[0];
|
||||
|
||||
if (!widthCtrl || !heightCtrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
newWidth = widthCtrl.value();
|
||||
newHeight = heightCtrl.value();
|
||||
|
||||
|
@ -146,12 +117,15 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
function waitLoad(imgElm) {
|
||||
function selectImage() {
|
||||
imgElm.onload = imgElm.onerror = null;
|
||||
editor.selection.select(imgElm);
|
||||
editor.nodeChanged();
|
||||
|
||||
if (editor.selection) {
|
||||
editor.selection.select(imgElm);
|
||||
editor.nodeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
imgElm.onload = function() {
|
||||
if (!data.width && !data.height) {
|
||||
if (!data.width && !data.height && imageDimensions) {
|
||||
dom.setAttribs(imgElm, {
|
||||
width: imgElm.clientWidth,
|
||||
height: imgElm.clientHeight
|
||||
|
@ -188,6 +162,7 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
data.style = null;
|
||||
}
|
||||
|
||||
// Setup new data excluding style properties
|
||||
data = {
|
||||
src: data.src,
|
||||
alt: data.alt,
|
||||
|
@ -197,10 +172,6 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
"class": data["class"]
|
||||
};
|
||||
|
||||
if (!data["class"]) {
|
||||
delete data["class"];
|
||||
}
|
||||
|
||||
editor.undoManager.transact(function() {
|
||||
// WP
|
||||
var eventData = { node: imgElm, data: data, caption: caption };
|
||||
|
@ -251,7 +222,7 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
}
|
||||
|
||||
getImageSize(this.value(), function(data) {
|
||||
if (data.width && data.height) {
|
||||
if (data.width && data.height && imageDimensions) {
|
||||
width = data.width;
|
||||
height = data.height;
|
||||
|
||||
|
@ -283,7 +254,13 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
imageListCtrl = {
|
||||
type: 'listbox',
|
||||
label: 'Image list',
|
||||
values: buildImageList(),
|
||||
values: buildListItems(
|
||||
imageList,
|
||||
function(item) {
|
||||
item.value = editor.convertURL(item.value || item.url, 'src');
|
||||
},
|
||||
[{text: 'None', value: ''}]
|
||||
),
|
||||
value: data.src && editor.convertURL(data.src, 'src'),
|
||||
onselect: function(e) {
|
||||
var altCtrl = win.find('#alt');
|
||||
|
@ -305,7 +282,16 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
name: 'class',
|
||||
type: 'listbox',
|
||||
label: 'Class',
|
||||
values: applyPreview(buildValues('image_class_list', 'class'))
|
||||
values: buildListItems(
|
||||
editor.settings.image_class_list,
|
||||
function(item) {
|
||||
if (item.value) {
|
||||
item.textStyle = function() {
|
||||
return editor.formatter.getCssText({inline: 'img', classes: [item.value]});
|
||||
};
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -319,7 +305,7 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
generalFormItems.push({name: 'alt', type: 'textbox', label: 'Image description'});
|
||||
}
|
||||
|
||||
if (editor.settings.image_dimensions !== false) {
|
||||
if (imageDimensions) {
|
||||
generalFormItems.push({
|
||||
type: 'container',
|
||||
label: 'Dimensions',
|
||||
|
@ -430,11 +416,6 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
}
|
||||
}
|
||||
|
||||
// WP
|
||||
editor.addCommand( 'mceImage', function() {
|
||||
createImageList( showDialog )();
|
||||
});
|
||||
|
||||
editor.addButton('image', {
|
||||
icon: 'image',
|
||||
tooltip: 'Insert/edit image',
|
||||
|
@ -449,4 +430,6 @@ tinymce.PluginManager.add('image', function(editor) {
|
|||
context: 'insert',
|
||||
prependToContext: true
|
||||
});
|
||||
|
||||
editor.addCommand('mceImage', createImageList(showDialog));
|
||||
});
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -162,7 +162,23 @@ tinymce.PluginManager.add('media', function(editor, url) {
|
|||
}
|
||||
],
|
||||
onSubmit: function() {
|
||||
var beforeObjects, afterObjects, i, y;
|
||||
|
||||
beforeObjects = editor.dom.select('img[data-mce-object]');
|
||||
editor.insertContent(dataToHtml(this.toJSON()));
|
||||
afterObjects = editor.dom.select('img[data-mce-object]');
|
||||
|
||||
// Find new image placeholder so we can select it
|
||||
for (i = 0; i < beforeObjects.length; i++) {
|
||||
for (y = afterObjects.length - 1; y >= 0; y--) {
|
||||
if (beforeObjects[i] == afterObjects[y]) {
|
||||
afterObjects.splice(y, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editor.selection.select(afterObjects[0]);
|
||||
editor.nodeChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -223,7 +239,7 @@ tinymce.PluginManager.add('media', function(editor, url) {
|
|||
|
||||
if (data.embed) {
|
||||
html = updateHtml(data.embed, data, true);
|
||||
} else {
|
||||
} else {
|
||||
var videoScript = getVideoScriptMatch(data.source1);
|
||||
if (videoScript) {
|
||||
data.type = 'script';
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -361,7 +361,7 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
pasteBinElm = dom.add(editor.getBody(), 'div', {
|
||||
id: "mcepastebin",
|
||||
contentEditable: true,
|
||||
"data-mce-bogus": "1",
|
||||
"data-mce-bogus": "all",
|
||||
style: 'position: absolute; top: ' + top + 'px;' +
|
||||
'width: 10px; height: 10px; overflow: hidden; opacity: 0'
|
||||
}, pasteBinDefaultContent);
|
||||
|
@ -471,42 +471,44 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
* Checks if the clipboard contains image data if it does it will take that data
|
||||
* and convert it into a data url image and paste that image at the caret location.
|
||||
*
|
||||
* @param {ClipboardEvent} e Paste event object.
|
||||
* @param {Object} clipboardContent Collection of clipboard contents.
|
||||
* @param {ClipboardEvent} e Paste/drop event object.
|
||||
* @param {DOMRange} rng Optional rng object to move selection to.
|
||||
* @return {Boolean} true/false if the image data was found or not.
|
||||
*/
|
||||
function pasteImageData(e, clipboardContent) {
|
||||
function pasteImage(item) {
|
||||
if (items[i].type == 'image/png') {
|
||||
var reader = new FileReader();
|
||||
function pasteImageData(e, rng) {
|
||||
var dataTransfer = e.clipboardData || e.dataTransfer;
|
||||
|
||||
reader.onload = function() {
|
||||
pasteHtml('<img src="' + reader.result + '">');
|
||||
};
|
||||
function processItems(items) {
|
||||
var i, item, reader;
|
||||
|
||||
reader.readAsDataURL(item.getAsFile());
|
||||
function pasteImage() {
|
||||
if (rng) {
|
||||
editor.selection.setRng(rng);
|
||||
rng = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
pasteHtml('<img src="' + reader.result + '">');
|
||||
}
|
||||
}
|
||||
|
||||
// If paste data images are disabled or there is HTML or plain text
|
||||
// contents then proceed with the normal paste process
|
||||
if (!editor.settings.paste_data_images || "text/html" in clipboardContent || "text/plain" in clipboardContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.clipboardData) {
|
||||
var items = e.clipboardData.items;
|
||||
|
||||
if (items) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (pasteImage(items[i])) {
|
||||
for (i = 0; i < items.length; i++) {
|
||||
item = items[i];
|
||||
|
||||
if (/^image\/(jpeg|png|gif)$/.test(item.type)) {
|
||||
reader = new FileReader();
|
||||
reader.onload = pasteImage;
|
||||
reader.readAsDataURL(item.getAsFile ? item.getAsFile() : item);
|
||||
|
||||
e.preventDefault();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (editor.settings.paste_data_images && dataTransfer) {
|
||||
return processItems(dataTransfer.items) || processItems(dataTransfer.files);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -546,6 +548,13 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
|
||||
function registerEventHandlers() {
|
||||
editor.on('keydown', function(e) {
|
||||
function removePasteBinOnKeyUp(e) {
|
||||
// Ctrl+V or Shift+Insert
|
||||
if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
|
||||
removePasteBin();
|
||||
}
|
||||
}
|
||||
|
||||
// Ctrl+V or Shift+Insert
|
||||
if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
|
||||
keyboardPastePlainTextState = e.shiftKey && e.keyCode == 86;
|
||||
|
@ -571,13 +580,13 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
|
||||
removePasteBin();
|
||||
createPasteBin();
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('keyup', function(e) {
|
||||
// Ctrl+V or Shift+Insert
|
||||
if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
|
||||
removePasteBin();
|
||||
// Remove pastebin if we get a keyup and no paste event
|
||||
// For example pasting a file in IE 11 will not produce a paste event
|
||||
editor.once('keyup', removePasteBinOnKeyUp);
|
||||
editor.once('paste', function() {
|
||||
editor.off('keyup', removePasteBinOnKeyUp);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -593,7 +602,7 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
return;
|
||||
}
|
||||
|
||||
if (pasteImageData(e, clipboardContent)) {
|
||||
if (pasteImageData(e)) {
|
||||
removePasteBin();
|
||||
return;
|
||||
}
|
||||
|
@ -683,7 +692,15 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
editor.on('drop', function(e) {
|
||||
var rng = getCaretRangeFromEvent(e);
|
||||
|
||||
if (rng && !e.isDefaultPrevented()) {
|
||||
if (e.isDefaultPrevented()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pasteImageData(e, rng)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rng) {
|
||||
var dropContent = getDataTransferItems(e.dataTransfer);
|
||||
var content = dropContent['mce-internal'] || dropContent['text/html'] || dropContent['text/plain'];
|
||||
|
||||
|
@ -706,6 +723,20 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('dragover dragend', function(e) {
|
||||
var i, dataTransfer = e.dataTransfer;
|
||||
|
||||
if (editor.settings.paste_data_images && dataTransfer) {
|
||||
for (i = 0; i < dataTransfer.types.length; i++) {
|
||||
// Prevent default if we have files dragged into the editor since the pasteImageData handles that
|
||||
if (dataTransfer.types[i] == "Files") {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self.pasteHtml = pasteHtml;
|
||||
|
@ -722,7 +753,10 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
|
||||
while (i--) {
|
||||
var src = nodes[i].attributes.map.src;
|
||||
if (src && src.indexOf('data:image') === 0) {
|
||||
|
||||
// Some browsers automatically produce data uris on paste
|
||||
// Safari on Mac produces webkit-fake-url see: https://bugs.webkit.org/show_bug.cgi?id=49141
|
||||
if (src && /^(data:image|webkit\-fake\-url)/.test(src)) {
|
||||
if (!nodes[i].attr('data-mce-object') && src !== Env.transparentSrc) {
|
||||
nodes[i].remove();
|
||||
}
|
||||
|
@ -731,14 +765,6 @@ define("tinymce/pasteplugin/Clipboard", [
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
editor.on('BeforeAddUndo', function(e) {
|
||||
// Remove pastebin HTML incase it should be added to an undo
|
||||
// level for example when you paste a file on older IE
|
||||
if (e.level.content) {
|
||||
e.level.content = e.level.content.replace(/<div id="?mcepastebin"?[^>]+>%MCEPASTEBIN%<\/div>/gi, '');
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -12,6 +12,8 @@
|
|||
/*eslint consistent-this:0 */
|
||||
|
||||
tinymce.PluginManager.add('textcolor', function(editor) {
|
||||
var VK = tinymce.util.VK;
|
||||
|
||||
function mapColors() {
|
||||
var i, colors = [], colorMap;
|
||||
|
||||
|
@ -105,6 +107,29 @@ tinymce.PluginManager.add('textcolor', function(editor) {
|
|||
html += '</tr>';
|
||||
}
|
||||
|
||||
if (editor.settings.textcolor_enable_hex) {
|
||||
var hexIdN = last + 1;
|
||||
var hexInputColSpan = cols - 1;
|
||||
html += (
|
||||
'<tr>' +
|
||||
'<td>' +
|
||||
'<div id="' + ctrl._id + '-' + hexIdN + '"' +
|
||||
'data-mce-color=""' +
|
||||
'style="background-color: #FFFFFF"' +
|
||||
'data-mce-hex-picker="true"' +
|
||||
'role="option" ' +
|
||||
'>' +
|
||||
'</div>' +
|
||||
'</td>' +
|
||||
'<td colspan="' + hexInputColSpan + '">' +
|
||||
'# <input type="text" class="mce-textcolor-hexpicker"' +
|
||||
'role="textbox" name="mce-hexcolorpicker"' +
|
||||
'id="' + ctrl._id + '-hexcolorpicker" maxlength="6" >' +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
}
|
||||
|
||||
html += '</tbody></table>';
|
||||
|
||||
return html;
|
||||
|
@ -112,7 +137,10 @@ tinymce.PluginManager.add('textcolor', function(editor) {
|
|||
|
||||
function onPanelClick(e) {
|
||||
var buttonCtrl = this.parent(), value;
|
||||
|
||||
|
||||
if (e.target.getAttribute('disabled')) {
|
||||
return;
|
||||
}
|
||||
if ((value = e.target.getAttribute('data-mce-color'))) {
|
||||
if (this.lastId) {
|
||||
document.getElementById(this.lastId).setAttribute('aria-selected', false);
|
||||
|
@ -136,6 +164,95 @@ tinymce.PluginManager.add('textcolor', function(editor) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* isValidHex checks if the provided string is valid hex color string
|
||||
*
|
||||
* @param {string} hexString 3 or 6 chars string representing a color.
|
||||
* @return {Boolean} [true] the string is valid hex color
|
||||
* [false] the string is not valid hex color
|
||||
*/
|
||||
function isValidHex(hexString) {
|
||||
return /(^[0-9A-F]{3,6}$)/i.test(hexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* isSpecialStroke checks if the keyCode is currently a special one:
|
||||
* backspace, delete, arrow keys (left/right)
|
||||
* or if it's a special ctrl+x/c/v
|
||||
*
|
||||
* @param {string} keyCode
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isSpecialStroke(e) {
|
||||
var keyCode = e.keyCode;
|
||||
// Allow delete and backspace
|
||||
if (keyCode === VK.BACKSPACE || keyCode === VK.DELETE ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow arrow movements
|
||||
if (keyCode === VK.LEFT || keyCode === VK.RIGHT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow CTRL/CMD + C/V/X
|
||||
if ((tinymce.isMac ? e.metaKey : e.ctrlKey) && (keyCode == 67 || keyCode == 88 || keyCode == 86)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function initHexPicker(e) {
|
||||
if (!editor.settings.textcolor_enable_hex) {
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = document.querySelector('#' + e.target._id);
|
||||
var input = wrapper.querySelector('[name="mce-hexcolorpicker"]');
|
||||
var hexcolorDiv = wrapper.querySelector('[data-mce-hex-picker]');
|
||||
var inputEvent = 'input';
|
||||
|
||||
editor.dom.events.bind(input, 'keydown', function(e){
|
||||
var keyCode = e.keyCode;
|
||||
|
||||
if (isSpecialStroke(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for anything which is not A-Z or 0-9 and it is not a special char.
|
||||
if (!((keyCode >= 48 && keyCode <= 57) || (keyCode >= 65 && keyCode <= 70) || (keyCode >= 96 && keyCode <= 105)) ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// On Enter, take it like a click on the hexcolorDiv
|
||||
if ( (keyCode === VK.ENTER && isValidHex(input.value) ) ) {
|
||||
hexcolorDiv.click();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// If IE8 we can't use the input event, so we have to
|
||||
// listen for keypress and paste events.
|
||||
// In IE9 the input implementation is buggy so
|
||||
// we use the same events as we'd like on IE8
|
||||
if (tinymce.Env.ie && tinymce.Env.ie <= 9) {
|
||||
inputEvent = 'keypress paste blur keydown keyup propertychange';
|
||||
}
|
||||
|
||||
editor.dom.events.bind(input, inputEvent, function(){
|
||||
if (isValidHex(input.value)) {
|
||||
hexcolorDiv.setAttribute('data-mce-color', input.value);
|
||||
hexcolorDiv.setAttribute('style', 'background-color:#' + input.value);
|
||||
hexcolorDiv.removeAttribute('disabled');
|
||||
} else {
|
||||
hexcolorDiv.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
editor.addButton('forecolor', {
|
||||
type: 'colorbutton',
|
||||
tooltip: 'Text color',
|
||||
|
@ -144,7 +261,8 @@ tinymce.PluginManager.add('textcolor', function(editor) {
|
|||
role: 'application',
|
||||
ariaRemember: true,
|
||||
html: renderColorPicker,
|
||||
onclick: onPanelClick
|
||||
onclick: onPanelClick,
|
||||
onPostRender: initHexPicker
|
||||
},
|
||||
onclick: onButtonClick
|
||||
});
|
||||
|
@ -157,7 +275,8 @@ tinymce.PluginManager.add('textcolor', function(editor) {
|
|||
role: 'application',
|
||||
ariaRemember: true,
|
||||
html: renderColorPicker,
|
||||
onclick: onPanelClick
|
||||
onclick: onPanelClick,
|
||||
onPostRender: initHexPicker
|
||||
},
|
||||
onclick: onButtonClick
|
||||
});
|
||||
|
|
|
@ -1 +1 @@
|
|||
tinymce.PluginManager.add("textcolor",function(e){function t(){var t,o,l=[];for(o=e.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Red violet","C0C0C0","Silver","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum","FFFFFF","White"],t=0;t<o.length;t+=2)l.push({text:o[t+1],color:o[t]});return l}function o(){var o,l,r,a,c,i,n,F,d,s=this;for(o=t(),r='<table class="mce-grid mce-grid-border mce-colorbutton-grid" role="list" cellspacing="0"><tbody>',a=o.length-1,c=e.settings.textcolor_rows||5,i=e.settings.textcolor_cols||8,F=0;c>F;F++){for(r+="<tr>",n=0;i>n;n++)d=F*i+n,d>a?r+="<td></td>":(l=o[d],r+='<td><div id="'+s._id+"-"+d+'" data-mce-color="'+l.color+'" role="option" tabIndex="-1" style="'+(l?"background-color: #"+l.color:"")+'" title="'+l.text+'"></div></td>');r+="</tr>"}return r+="</tbody></table>"}function l(t){var o,l=this.parent();(o=t.target.getAttribute("data-mce-color"))&&(this.lastId&&document.getElementById(this.lastId).setAttribute("aria-selected",!1),t.target.setAttribute("aria-selected",!0),this.lastId=t.target.id,l.hidePanel(),o="#"+o,l.color(o),e.execCommand(l.settings.selectcmd,!1,o))}function r(){var t=this;t._color&&e.execCommand(t.settings.selectcmd,!1,t._color)}e.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",selectcmd:"ForeColor",panel:{role:"application",ariaRemember:!0,html:o,onclick:l},onclick:r}),e.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",selectcmd:"HiliteColor",panel:{role:"application",ariaRemember:!0,html:o,onclick:l},onclick:r})});
|
||||
tinymce.PluginManager.add("textcolor",function(e){function t(){var t,o,r=[];for(o=e.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Red violet","C0C0C0","Silver","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum","FFFFFF","White"],t=0;t<o.length;t+=2)r.push({text:o[t+1],color:o[t]});return r}function o(){var o,r,l,c,i,a,n,d,s,u=this;for(o=t(),l='<table class="mce-grid mce-grid-border mce-colorbutton-grid" role="list" cellspacing="0"><tbody>',c=o.length-1,i=e.settings.textcolor_rows||5,a=e.settings.textcolor_cols||8,d=0;i>d;d++){for(l+="<tr>",n=0;a>n;n++)s=d*a+n,s>c?l+="<td></td>":(r=o[s],l+='<td><div id="'+u._id+"-"+s+'" data-mce-color="'+r.color+'" role="option" tabIndex="-1" style="'+(r?"background-color: #"+r.color:"")+'" title="'+r.text+'"></div></td>');l+="</tr>"}if(e.settings.textcolor_enable_hex){var F=c+1,m=a-1;l+='<tr><td><div id="'+u._id+"-"+F+'"data-mce-color=""style="background-color: #FFFFFF"data-mce-hex-picker="true"role="option" ></div></td><td colspan="'+m+'"># <input type="text" class="mce-textcolor-hexpicker"role="textbox" name="mce-hexcolorpicker"id="'+u._id+'-hexcolorpicker" maxlength="6" ></td></tr>'}return l+="</tbody></table>"}function r(t){var o,r=this.parent();t.target.getAttribute("disabled")||(o=t.target.getAttribute("data-mce-color"))&&(this.lastId&&document.getElementById(this.lastId).setAttribute("aria-selected",!1),t.target.setAttribute("aria-selected",!0),this.lastId=t.target.id,r.hidePanel(),o="#"+o,r.color(o),e.execCommand(r.settings.selectcmd,!1,o))}function l(){var t=this;t._color&&e.execCommand(t.settings.selectcmd,!1,t._color)}function c(e){return/(^[0-9A-F]{3,6}$)/i.test(e)}function i(e){var t=e.keyCode;return t===n.BACKSPACE||t===n.DELETE?!0:t===n.LEFT||t===n.RIGHT?!0:(tinymce.isMac?e.metaKey:e.ctrlKey)&&(67==t||88==t||86==t)?!0:!1}function a(t){if(e.settings.textcolor_enable_hex){var o=document.querySelector("#"+t.target._id),r=o.querySelector('[name="mce-hexcolorpicker"]'),l=o.querySelector("[data-mce-hex-picker]"),a="input";e.dom.events.bind(r,"keydown",function(e){var t=e.keyCode;i(e)||(t>=48&&57>=t||t>=65&&70>=t||t>=96&&105>=t||e.preventDefault(),t===n.ENTER&&c(r.value)&&l.click())}),tinymce.Env.ie&&tinymce.Env.ie<=9&&(a="keypress paste blur keydown keyup propertychange"),e.dom.events.bind(r,a,function(){c(r.value)?(l.setAttribute("data-mce-color",r.value),l.setAttribute("style","background-color:#"+r.value),l.removeAttribute("disabled")):l.setAttribute("disabled","disabled")})}}var n=tinymce.util.VK;e.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",selectcmd:"ForeColor",panel:{role:"application",ariaRemember:!0,html:o,onclick:r,onPostRender:a},onclick:l}),e.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",selectcmd:"HiliteColor",panel:{role:"application",ariaRemember:!0,html:o,onclick:r,onPostRender:a},onclick:l})});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -6154,7 +6154,7 @@ define("tinymce/dom/DOMUtils", [
|
|||
outHtml += '<' + name;
|
||||
|
||||
for (key in attrs) {
|
||||
if (attrs.hasOwnProperty(key) && attrs[key] !== null) {
|
||||
if (attrs.hasOwnProperty(key) && attrs[key] !== null && typeof attrs[key] != 'undefined') {
|
||||
outHtml += ' ' + key + '="' + this.encode(attrs[key]) + '"';
|
||||
}
|
||||
}
|
||||
|
@ -6390,70 +6390,72 @@ define("tinymce/dom/DOMUtils", [
|
|||
* // Sets class attribute on a specific element in the current page
|
||||
* tinymce.dom.setAttrib('mydiv', 'class', 'myclass');
|
||||
*/
|
||||
setAttrib: function(e, n, v) {
|
||||
setAttrib: function(elm, name, value) {
|
||||
var self = this;
|
||||
|
||||
// What's the point
|
||||
if (!e || !n) {
|
||||
if (!elm || !name) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.run(e, function(e) {
|
||||
var s = self.settings;
|
||||
var originalValue = e.getAttribute(n);
|
||||
if (v !== null) {
|
||||
switch (n) {
|
||||
return this.run(elm, function(elm) {
|
||||
var settings = self.settings;
|
||||
var originalValue = elm.getAttribute(name);
|
||||
|
||||
if (value !== null) {
|
||||
switch (name) {
|
||||
case "style":
|
||||
if (!is(v, 'string')) {
|
||||
each(v, function(v, n) {
|
||||
self.setStyle(e, n, v);
|
||||
if (!is(value, 'string')) {
|
||||
each(value, function(value, name) {
|
||||
self.setStyle(elm, name, value);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// No mce_style for elements with these since they might get resized by the user
|
||||
if (s.keep_values) {
|
||||
if (v) {
|
||||
e.setAttribute('data-mce-style', v, 2);
|
||||
if (settings.keep_values) {
|
||||
if (value) {
|
||||
elm.setAttribute('data-mce-style', value, 2);
|
||||
} else {
|
||||
e.removeAttribute('data-mce-style', 2);
|
||||
elm.removeAttribute('data-mce-style', 2);
|
||||
}
|
||||
}
|
||||
|
||||
e.style.cssText = v;
|
||||
elm.style.cssText = value;
|
||||
break;
|
||||
|
||||
case "class":
|
||||
e.className = v || ''; // Fix IE null bug
|
||||
elm.className = value || ''; // Fix IE null bug
|
||||
break;
|
||||
|
||||
case "src":
|
||||
case "href":
|
||||
if (s.keep_values) {
|
||||
if (s.url_converter) {
|
||||
v = s.url_converter.call(s.url_converter_scope || self, v, n, e);
|
||||
if (settings.keep_values) {
|
||||
if (settings.url_converter) {
|
||||
value = settings.url_converter.call(settings.url_converter_scope || self, value, name, elm);
|
||||
}
|
||||
|
||||
self.setAttrib(e, 'data-mce-' + n, v, 2);
|
||||
self.setAttrib(elm, 'data-mce-' + name, value, 2);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "shape":
|
||||
e.setAttribute('data-mce-style', v);
|
||||
elm.setAttribute('data-mce-style', value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is(v) && v !== null && v.length !== 0) {
|
||||
e.setAttribute(n, '' + v, 2);
|
||||
|
||||
if (is(value) && value !== null && value.length !== 0) {
|
||||
elm.setAttribute(name, '' + value, 2);
|
||||
} else {
|
||||
e.removeAttribute(n, 2);
|
||||
elm.removeAttribute(name, 2);
|
||||
}
|
||||
|
||||
// fire onChangeAttrib event for attributes that have changed
|
||||
if (originalValue != v && s.onSetAttrib) {
|
||||
s.onSetAttrib({attrElm: e, attrName: n, attrValue: v});
|
||||
if (originalValue != value && settings.onSetAttrib) {
|
||||
settings.onSetAttrib({attrElm: elm, attrName: name, attrValue: value});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -9828,15 +9830,24 @@ define("tinymce/html/SaxParser", [
|
|||
/**
|
||||
* Returns the index of the end tag for a specific start tag. This can be
|
||||
* used to skip all children of a parent element from being processed.
|
||||
*
|
||||
* @private
|
||||
* @method findEndTag
|
||||
* @param {tinymce.html.Schema} schema Schema instance to use to match short ended elements.
|
||||
* @param {String} html HTML string to find the end tag in.
|
||||
* @param {Number} startIndex Indext to start searching at should be after the start tag.
|
||||
* @return {Number} Index of the end tag.
|
||||
*/
|
||||
function skipUntilEndTag(schema, html, startIndex) {
|
||||
var count = 1, matches, tokenRegExp, shortEndedElements;
|
||||
function findEndTag(schema, html, startIndex) {
|
||||
var count = 1, index, matches, tokenRegExp, shortEndedElements;
|
||||
|
||||
shortEndedElements = schema.getShortEndedElements();
|
||||
tokenRegExp = /<([!?\/])?([A-Za-z0-9\-\:\.]+)((?:\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\/|\s+)>/g;
|
||||
tokenRegExp.lastIndex = startIndex;
|
||||
tokenRegExp.lastIndex = index = startIndex;
|
||||
|
||||
while ((matches = tokenRegExp.exec(html))) {
|
||||
index = tokenRegExp.lastIndex;
|
||||
|
||||
if (matches[1] === '/') { // End element
|
||||
count--;
|
||||
} else if (!matches[1]) { // Start element
|
||||
|
@ -9852,7 +9863,7 @@ define("tinymce/html/SaxParser", [
|
|||
}
|
||||
}
|
||||
|
||||
return tokenRegExp.lastIndex;
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9863,7 +9874,7 @@ define("tinymce/html/SaxParser", [
|
|||
* @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks.
|
||||
* @param {tinymce.html.Schema} schema HTML Schema class to use when parsing.
|
||||
*/
|
||||
return function(settings, schema) {
|
||||
function SaxParser(settings, schema) {
|
||||
var self = this;
|
||||
|
||||
function noop() {}
|
||||
|
@ -10138,7 +10149,7 @@ define("tinymce/html/SaxParser", [
|
|||
// Invalidate element if it's marked as bogus
|
||||
if ((attr = attrList.map['data-mce-bogus'])) {
|
||||
if (attr === 'all') {
|
||||
index = skipUntilEndTag(schema, html, tokenRegExp.lastIndex);
|
||||
index = findEndTag(schema, html, tokenRegExp.lastIndex);
|
||||
tokenRegExp.lastIndex = index;
|
||||
continue;
|
||||
}
|
||||
|
@ -10225,7 +10236,11 @@ define("tinymce/html/SaxParser", [
|
|||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
SaxParser.findEndTag = findEndTag;
|
||||
|
||||
return SaxParser;
|
||||
});
|
||||
|
||||
// Included from: js/tinymce/classes/html/DomParser.js
|
||||
|
@ -11490,8 +11505,12 @@ define("tinymce/dom/Serializer", [
|
|||
|
||||
while (i--) {
|
||||
node = nodes[i];
|
||||
value = node.attr('class').replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
|
||||
node.attr('class', value.length > 0 ? value : null);
|
||||
value = node.attr('class');
|
||||
|
||||
if (value) {
|
||||
value = node.attr('class').replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
|
||||
node.attr('class', value.length > 0 ? value : null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -12423,6 +12442,7 @@ define("tinymce/dom/ControlSelection", [
|
|||
'margin: 5px 10px;' +
|
||||
'padding: 5px;' +
|
||||
'position: absolute;' +
|
||||
'z-index: 10001' +
|
||||
'}'
|
||||
);
|
||||
|
||||
|
@ -12463,7 +12483,7 @@ define("tinymce/dom/ControlSelection", [
|
|||
if (selectedElm.nodeName == "IMG" && editor.settings.resize_img_proportional !== false) {
|
||||
proportional = !VK.modifierPressed(e);
|
||||
} else {
|
||||
proportional = VK.modifierPressed(e) || selectedHandle[2] * selectedHandle[3] !== 0;
|
||||
proportional = VK.modifierPressed(e) || (selectedElm.nodeName == "IMG" && selectedHandle[2] * selectedHandle[3] !== 0);
|
||||
}
|
||||
|
||||
// Constrain proportions
|
||||
|
@ -12604,6 +12624,7 @@ define("tinymce/dom/ControlSelection", [
|
|||
|
||||
selectedElmGhost = selectedElm.cloneNode(true);
|
||||
dom.addClass(selectedElmGhost, 'mce-clonedresizable');
|
||||
dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
|
||||
selectedElmGhost.contentEditable = false; // Hides IE move layer cursor
|
||||
selectedElmGhost.unSelectabe = true;
|
||||
dom.setStyles(selectedElmGhost, {
|
||||
|
@ -12645,7 +12666,7 @@ define("tinymce/dom/ControlSelection", [
|
|||
|
||||
handleElm = dom.add(handlerContainerElm, 'div', {
|
||||
id: 'mceResizeHandle' + name,
|
||||
'data-mce-bogus': true,
|
||||
'data-mce-bogus': 'all',
|
||||
'class': 'mce-resizehandle',
|
||||
unselectable: true,
|
||||
style: 'cursor:' + name + '-resize; margin:0; padding:0'
|
||||
|
@ -17154,7 +17175,16 @@ define("tinymce/Formatter", [
|
|||
child = findFirstTextNode(node);
|
||||
|
||||
if (child.nodeValue.charAt(0) === INVISIBLE_CHAR) {
|
||||
child = child.deleteData(0, 1);
|
||||
child.deleteData(0, 1);
|
||||
|
||||
// Fix for bug #6976
|
||||
if (rng.startContainer == child) {
|
||||
rng.startOffset--;
|
||||
}
|
||||
|
||||
if (rng.endContainer == child) {
|
||||
rng.endOffset--;
|
||||
}
|
||||
}
|
||||
|
||||
dom.remove(node, 1);
|
||||
|
@ -17424,22 +17454,52 @@ define("tinymce/Formatter", [
|
|||
*/
|
||||
define("tinymce/UndoManager", [
|
||||
"tinymce/Env",
|
||||
"tinymce/util/Tools"
|
||||
], function(Env, Tools) {
|
||||
"tinymce/util/Tools",
|
||||
"tinymce/html/SaxParser"
|
||||
], function(Env, Tools, SaxParser) {
|
||||
var trim = Tools.trim, trimContentRegExp;
|
||||
|
||||
trimContentRegExp = new RegExp([
|
||||
'<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\\/span>', // Trim bogus spans like caret containers
|
||||
'<div[^>]+data-mce-bogus[^>]+>[^>]*<\\/div>', // Trim bogus divs like resize handles/resize helper
|
||||
'\\s?data-mce-selected="[^"]+"' // Trim temporaty data-mce prefixed attributes like data-mce-selected
|
||||
].join('|'), 'gi');
|
||||
|
||||
return function(editor) {
|
||||
var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, locks = 0;
|
||||
|
||||
// Returns a trimmed version of the current editor contents
|
||||
/**
|
||||
* Returns a trimmed version of the editor contents to be used for the undo level. This
|
||||
* will remove any data-mce-bogus="all" marked elements since these are used for UI it will also
|
||||
* remove the data-mce-selected attributes used for selection of objects and caret containers.
|
||||
* It will keep all data-mce-bogus="1" elements since these can be used to place the caret etc and will
|
||||
* be removed by the serialization logic when you save.
|
||||
*
|
||||
* @return {String} HTML contents of the editor excluding some internal bogus elements.
|
||||
*/
|
||||
function getContent() {
|
||||
return trim(editor.getContent({format: 'raw', no_events: 1}).replace(trimContentRegExp, ''));
|
||||
var content = trim(editor.getContent({format: 'raw', no_events: 1}));
|
||||
var bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
|
||||
var endTagIndex, index, matchLength, matches, shortEndedElements, schema = editor.schema;
|
||||
|
||||
content = content.replace(trimContentRegExp, '');
|
||||
shortEndedElements = schema.getShortEndedElements();
|
||||
|
||||
// Remove all bogus elements marked with "all"
|
||||
while ((matches = bogusAllRegExp.exec(content))) {
|
||||
index = bogusAllRegExp.lastIndex;
|
||||
matchLength = matches[0].length;
|
||||
|
||||
if (shortEndedElements[matches[1]]) {
|
||||
endTagIndex = index;
|
||||
} else {
|
||||
endTagIndex = SaxParser.findEndTag(schema, content, index);
|
||||
}
|
||||
|
||||
content = content.substring(0, index - matchLength) + content.substring(endTagIndex);
|
||||
bogusAllRegExp.lastIndex = index - matchLength;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function addNonTypingUndoLevel(e) {
|
||||
|
@ -17538,12 +17598,44 @@ define("tinymce/UndoManager", [
|
|||
editor.addShortcut('ctrl+z', '', 'Undo');
|
||||
editor.addShortcut('ctrl+y,ctrl+shift+z', '', 'Redo');
|
||||
|
||||
editor.on('AddUndo Undo Redo ClearUndos MouseUp', function(e) {
|
||||
editor.on('AddUndo Undo Redo ClearUndos', function(e) {
|
||||
if (!e.isDefaultPrevented()) {
|
||||
editor.nodeChanged();
|
||||
}
|
||||
});
|
||||
|
||||
// Selection range isn't updated until after the click events default handler is executed
|
||||
// so we need to wait for the selection to update on Gecko/WebKit it happens right away.
|
||||
// On IE it might take a while so we listen for the SelectionChange event.
|
||||
//
|
||||
// We can't use the SelectionChange on all browsers event since Gecko doesn't support that.
|
||||
if (Env.ie) {
|
||||
editor.on('MouseUp', function(e) {
|
||||
if (!e.isDefaultPrevented()) {
|
||||
editor.once('SelectionChange', function() {
|
||||
// Selection change might fire when focus is lost
|
||||
if (editor.dom.isChildOf(editor.selection.getStart(), editor.getBody())) {
|
||||
editor.nodeChanged();
|
||||
}
|
||||
});
|
||||
|
||||
editor.nodeChanged();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
editor.on('MouseUp', function() {
|
||||
editor.nodeChanged();
|
||||
});
|
||||
|
||||
editor.on('Click', function(e) {
|
||||
if (!e.isDefaultPrevented()) {
|
||||
setTimeout(function() {
|
||||
editor.nodeChanged();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self = {
|
||||
// Explose for debugging reasons
|
||||
data: data,
|
||||
|
@ -18176,56 +18268,9 @@ define("tinymce/EnterKey", [
|
|||
undoManager.add();
|
||||
}
|
||||
|
||||
// Walks the parent block to the right and look for BR elements
|
||||
function hasRightSideContent() {
|
||||
var walker = new TreeWalker(container, parentBlock), node;
|
||||
|
||||
while ((node = walker.next())) {
|
||||
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts a BR element if the forced_root_block option is set to false or empty string
|
||||
function insertBr() {
|
||||
var brElm, extraBr, marker;
|
||||
|
||||
if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
|
||||
// Insert extra BR element at the end block elements
|
||||
if (!isIE && !hasRightSideContent()) {
|
||||
brElm = dom.create('br');
|
||||
rng.insertNode(brElm);
|
||||
rng.setStartAfter(brElm);
|
||||
rng.setEndAfter(brElm);
|
||||
extraBr = true;
|
||||
}
|
||||
}
|
||||
|
||||
brElm = dom.create('br');
|
||||
rng.insertNode(brElm);
|
||||
|
||||
// Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
|
||||
if (isIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
|
||||
brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
|
||||
}
|
||||
|
||||
// Insert temp marker and scroll to that
|
||||
marker = dom.create('span', {}, ' ');
|
||||
brElm.parentNode.insertBefore(marker, brElm);
|
||||
selection.scrollIntoView(marker);
|
||||
dom.remove(marker);
|
||||
|
||||
if (!extraBr) {
|
||||
rng.setStartAfter(brElm);
|
||||
rng.setEndAfter(brElm);
|
||||
} else {
|
||||
rng.setStartBefore(brElm);
|
||||
rng.setEndBefore(brElm);
|
||||
}
|
||||
|
||||
selection.setRng(rng);
|
||||
undoManager.add();
|
||||
editor.execCommand("InsertLineBreak", false, evt);
|
||||
}
|
||||
|
||||
// Trims any linebreaks at the beginning of node user for example when pressing enter in a PRE element
|
||||
|
@ -18593,12 +18638,14 @@ define("tinymce/EditorCommands", [
|
|||
"tinymce/html/Serializer",
|
||||
"tinymce/Env",
|
||||
"tinymce/util/Tools",
|
||||
"tinymce/dom/ElementUtils"
|
||||
], function(Serializer, Env, Tools, ElementUtils) {
|
||||
"tinymce/dom/ElementUtils",
|
||||
"tinymce/dom/RangeUtils",
|
||||
"tinymce/dom/TreeWalker"
|
||||
], function(Serializer, Env, Tools, ElementUtils, RangeUtils, TreeWalker) {
|
||||
// Added for compression purposes
|
||||
var each = Tools.each, extend = Tools.extend;
|
||||
var map = Tools.map, inArray = Tools.inArray, explode = Tools.explode;
|
||||
var isGecko = Env.gecko, isIE = Env.ie;
|
||||
var isGecko = Env.gecko, isIE = Env.ie, isOldIE = Env.ie && Env.ie < 11;
|
||||
var TRUE = true, FALSE = false;
|
||||
|
||||
return function(editor) {
|
||||
|
@ -19248,6 +19295,93 @@ define("tinymce/EditorCommands", [
|
|||
|
||||
mceNewDocument: function() {
|
||||
editor.setContent('');
|
||||
},
|
||||
|
||||
"InsertLineBreak": function (command, ui, value) {
|
||||
// We load the current event in from EnterKey.js when appropriate to heed
|
||||
// certain event-specific variations such as ctrl-enter in a list
|
||||
var evt = value;
|
||||
var brElm, extraBr, marker;
|
||||
var rng = selection.getRng(true);
|
||||
new RangeUtils(dom).normalize(rng);
|
||||
|
||||
var offset = rng.startOffset;
|
||||
var container = rng.startContainer;
|
||||
|
||||
// Resolve node index
|
||||
if (container.nodeType == 1 && container.hasChildNodes()) {
|
||||
var isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
||||
|
||||
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
||||
if (isAfterLastNodeInContainer && container.nodeType == 3) {
|
||||
offset = container.nodeValue.length;
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var parentBlock = dom.getParent(container, dom.isBlock);
|
||||
var parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
|
||||
var containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
||||
var containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
|
||||
|
||||
// Enter inside block contained within a LI then split or insert before/after LI
|
||||
var isControlKey = evt && evt.ctrlKey;
|
||||
if (containerBlockName == 'LI' && !isControlKey) {
|
||||
parentBlock = containerBlock;
|
||||
parentBlockName = containerBlockName;
|
||||
}
|
||||
|
||||
// Walks the parent block to the right and look for BR elements
|
||||
function hasRightSideContent() {
|
||||
var walker = new TreeWalker(container, parentBlock), node;
|
||||
var nonEmptyElementsMap = editor.schema.getNonEmptyElements();
|
||||
|
||||
while ((node = walker.next())) {
|
||||
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
|
||||
// Insert extra BR element at the end block elements
|
||||
if (!isOldIE && !hasRightSideContent()) {
|
||||
brElm = dom.create('br');
|
||||
rng.insertNode(brElm);
|
||||
rng.setStartAfter(brElm);
|
||||
rng.setEndAfter(brElm);
|
||||
extraBr = true;
|
||||
}
|
||||
}
|
||||
|
||||
brElm = dom.create('br');
|
||||
rng.insertNode(brElm);
|
||||
|
||||
// Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
|
||||
var documentMode = dom.doc.documentMode;
|
||||
if (isOldIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
|
||||
brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
|
||||
}
|
||||
|
||||
// Insert temp marker and scroll to that
|
||||
marker = dom.create('span', {}, ' ');
|
||||
brElm.parentNode.insertBefore(marker, brElm);
|
||||
selection.scrollIntoView(marker);
|
||||
dom.remove(marker);
|
||||
|
||||
if (!extraBr) {
|
||||
rng.setStartAfter(brElm);
|
||||
rng.setEndAfter(brElm);
|
||||
} else {
|
||||
rng.setStartBefore(brElm);
|
||||
rng.setEndBefore(brElm);
|
||||
}
|
||||
|
||||
selection.setRng(rng);
|
||||
editor.undoManager.add();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -20000,6 +20134,11 @@ define("tinymce/util/EventDispatcher", [
|
|||
for (i = 0, l = handlers.length; i < l; i++) {
|
||||
handlers[i] = callback = handlers[i];
|
||||
|
||||
// Unbind handlers marked with "once"
|
||||
if (callback.once) {
|
||||
off(name, callback);
|
||||
}
|
||||
|
||||
// Stop immediate propagation if needed
|
||||
if (args.isImmediatePropagationStopped()) {
|
||||
args.stopPropagation();
|
||||
|
@ -20105,7 +20244,8 @@ define("tinymce/util/EventDispatcher", [
|
|||
hi = handlers.length;
|
||||
while (hi--) {
|
||||
if (handlers[hi] === callback) {
|
||||
handlers.splice(hi, 1);
|
||||
handlers = handlers.slice(0, hi).concat(handlers.slice(hi + 1));
|
||||
bindings[name] = handlers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20127,6 +20267,25 @@ define("tinymce/util/EventDispatcher", [
|
|||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds an event listener to a specific event by name
|
||||
* and automatically unbind the event once the callback fires.
|
||||
*
|
||||
* @method once
|
||||
* @param {String} name Event name or space separated list of events to bind.
|
||||
* @param {callback} callback Callback to be executed when the event occurs.
|
||||
* @param {Boolean} first Optional flag if the event should be prepended. Use this with care.
|
||||
* @return {Object} Current class instance.
|
||||
* @example
|
||||
* instance.once('event', function(e) {
|
||||
* // Callback logic
|
||||
* });
|
||||
*/
|
||||
function once(name, callback, prepend) {
|
||||
callback.once = true;
|
||||
return on(name, callback, prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true/false if the dispatcher has a event of the specified name.
|
||||
*
|
||||
|
@ -20143,6 +20302,7 @@ define("tinymce/util/EventDispatcher", [
|
|||
self.fire = fire;
|
||||
self.on = on;
|
||||
self.off = off;
|
||||
self.once = once;
|
||||
self.has = has;
|
||||
}
|
||||
|
||||
|
@ -25855,6 +26015,11 @@ define("tinymce/util/Quirks", [
|
|||
function removeHrOnBackspace() {
|
||||
editor.on('keydown', function(e) {
|
||||
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
||||
// Check if there is any HR elements this is faster since getRng on IE 7 & 8 is slow
|
||||
if (!editor.getBody().getElementsByTagName('hr').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
|
||||
var node = selection.getNode();
|
||||
var previousSibling = node.previousSibling;
|
||||
|
@ -26548,7 +26713,6 @@ define("tinymce/util/Quirks", [
|
|||
}
|
||||
|
||||
// All browsers
|
||||
disableBackspaceIntoATable();
|
||||
removeBlockQuoteOnBackSpace();
|
||||
emptyEditorWhenDeleting();
|
||||
normalizeSelection();
|
||||
|
@ -26560,6 +26724,7 @@ define("tinymce/util/Quirks", [
|
|||
selectControlElements();
|
||||
setDefaultBlockType();
|
||||
blockFormSubmitInsideEditor();
|
||||
disableBackspaceIntoATable();
|
||||
|
||||
// iOS
|
||||
if (Env.iOS) {
|
||||
|
@ -26587,6 +26752,7 @@ define("tinymce/util/Quirks", [
|
|||
if (Env.ie >= 11) {
|
||||
bodyHeight();
|
||||
doubleTrailingBrElements();
|
||||
disableBackspaceIntoATable();
|
||||
}
|
||||
|
||||
if (Env.ie) {
|
||||
|
@ -26604,6 +26770,7 @@ define("tinymce/util/Quirks", [
|
|||
removeGhostSelection();
|
||||
showBrokenImageIcon();
|
||||
blockCmdArrowNavigation();
|
||||
disableBackspaceIntoATable();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -26715,6 +26882,18 @@ define("tinymce/util/Observable", [
|
|||
return getEventDispatcher(this).off(name, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind the event callback and once it fires the callback is removed.
|
||||
*
|
||||
* @method once
|
||||
* @param {String} name Name of the event to bind.
|
||||
* @param {callback} callback Callback to bind only once.
|
||||
* @return {Object} Current class instance.
|
||||
*/
|
||||
once: function(name, callback) {
|
||||
return getEventDispatcher(this).once(name, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true/false if the object has a event of the specified name.
|
||||
*
|
||||
|
@ -26760,7 +26939,7 @@ define("tinymce/EditorObservable", [
|
|||
|
||||
// Need to bind mousedown/mouseup etc to document not body in iframe mode
|
||||
// Since the user might click on the HTML element not the BODY
|
||||
if (!editor.inline && /^mouse|click|contextmenu|drop/.test(eventName)) {
|
||||
if (!editor.inline && /^mouse|click|contextmenu|drop|dragover|dragend/.test(eventName)) {
|
||||
return editor.getDoc();
|
||||
}
|
||||
|
||||
|
@ -28150,8 +28329,9 @@ define("tinymce/Editor", [
|
|||
* need to update the UI states or element path etc.
|
||||
*
|
||||
* @method nodeChanged
|
||||
* @param {Object} args Optional args to pass to NodeChange event handlers.
|
||||
*/
|
||||
nodeChanged: function() {
|
||||
nodeChanged: function(args) {
|
||||
var self = this, selection = self.selection, node, parents, root;
|
||||
|
||||
// Fix for bug #1896577 it seems that this can not be fired while the editor is loading
|
||||
|
@ -28176,7 +28356,11 @@ define("tinymce/Editor", [
|
|||
parents.push(node);
|
||||
});
|
||||
|
||||
self.fire('NodeChange', {element: node, parents: parents});
|
||||
args = args || {};
|
||||
args.element = node;
|
||||
args.parents = parents;
|
||||
|
||||
self.fire('NodeChange', args);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -29022,8 +29206,8 @@ define("tinymce/Editor", [
|
|||
var self = this;
|
||||
|
||||
if (!self.removed) {
|
||||
self.removed = 1;
|
||||
self.save();
|
||||
self.removed = 1;
|
||||
|
||||
// Remove any hidden input
|
||||
if (self.hasHiddenInput) {
|
||||
|
@ -29620,9 +29804,9 @@ define("tinymce/EditorManager", [
|
|||
// Get base URL for the current document
|
||||
documentBaseURL = document.location.href;
|
||||
|
||||
// Check if the URL is a document based format like: http://site/dir/file
|
||||
// Check if the URL is a document based format like: http://site/dir/file and file:///
|
||||
// leave other formats like applewebdata://... intact
|
||||
if (/^[^:]+:\/\/[^\/]+\//.test(documentBaseURL)) {
|
||||
if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
|
||||
documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
||||
|
||||
if (!/[\/\\]$/.test(documentBaseURL)) {
|
||||
|
@ -30246,6 +30430,9 @@ define("tinymce/util/XHR", [], function() {
|
|||
|
||||
xhr.open(settings.type || (settings.data ? 'POST' : 'GET'), settings.url, settings.async);
|
||||
|
||||
if (settings.crossDomain) {
|
||||
xhr.withCredentials = true;
|
||||
}
|
||||
if (settings.content_type) {
|
||||
xhr.setRequestHeader('Content-Type', settings.content_type);
|
||||
}
|
||||
|
@ -34484,7 +34671,9 @@ define("tinymce/ui/ListBox", [
|
|||
|
||||
self._values = values = settings.values;
|
||||
if (values) {
|
||||
setSelected(values);
|
||||
if (typeof settings.value != "undefined") {
|
||||
setSelected(values);
|
||||
}
|
||||
|
||||
// Default with first item
|
||||
if (!selected && values.length > 0) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -18,7 +18,7 @@ $wp_db_version = 27916;
|
|||
*
|
||||
* @global string $tinymce_version
|
||||
*/
|
||||
$tinymce_version = '4028-20140528';
|
||||
$tinymce_version = '4028-20140617';
|
||||
|
||||
/**
|
||||
* Holds the required PHP version
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
/*jshint loopfunc:true */
|
||||
/*eslint no-loop-func:0 */
|
||||
/*global tinymce:true */
|
||||
|
||||
tinymce.PluginManager.add('noneditable', function(editor) {
|
||||
|
@ -184,7 +185,7 @@ tinymce.PluginManager.add('noneditable', function(editor) {
|
|||
if (offset < container.childNodes.length) {
|
||||
// Browser represents caret position as the offset at the start of an element. When moving right
|
||||
// this is the element we are moving into so we consider our container to be child node at offset-1
|
||||
var pos = !left && offset > 0 ? offset-1 : offset;
|
||||
var pos = !left && offset > 0 ? offset - 1 : offset;
|
||||
container = container.childNodes[pos];
|
||||
if (container.hasChildNodes()) {
|
||||
container = container.firstChild;
|
||||
|
|
|
@ -61,9 +61,11 @@
|
|||
<script src="tinymce/ui/Window.js"></script>
|
||||
|
||||
<!-- tinymce.util.* -->
|
||||
<script src="tinymce/util/EventDispatcher.js"></script>
|
||||
<script src="tinymce/util/JSON.js"></script>
|
||||
<script src="tinymce/util/JSONRequest.js"></script>
|
||||
<script src="tinymce/util/LocalStorage.js"></script>
|
||||
<script src="tinymce/util/Observable.js"></script>
|
||||
<script src="tinymce/util/Quirks_webkit.js"></script>
|
||||
<script src="tinymce/util/URI.js"></script>
|
||||
<script src="tinymce/util/XHR.js"></script>
|
||||
|
@ -78,13 +80,18 @@
|
|||
<script src="tinymce/Formatter_apply.js"></script>
|
||||
<script src="tinymce/Formatter_check.js"></script>
|
||||
<script src="tinymce/Formatter_remove.js"></script>
|
||||
<script src="tinymce/Shortcuts.js"></script>
|
||||
<script src="tinymce/UndoManager.js"></script>
|
||||
|
||||
<!-- tinymce.plugins.* -->
|
||||
<!--<script src="plugins/autosave.js"></script>
|
||||
<script src="plugins/fullpage.js"></script>
|
||||
<script src="plugins/autosave.js"></script>
|
||||
<script src="plugins/fullpage.js"></script> -->
|
||||
<script src="plugins/image.js"></script>
|
||||
<!--<script src="plugins/importcss.js"></script>
|
||||
<script src="plugins/jquery_plugin.js"></script>
|
||||
<script src="plugins/legacyoutput.js"></script>
|
||||
<script src="plugins/lists.js"></script>
|
||||
<script src="plugins/lists.js"></script> -->
|
||||
<script src="plugins/media.js"></script>
|
||||
<!--<script src="plugins/noneditable.js"></script> -->
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
(function() {
|
||||
module("tinymce.plugins.Autolink", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
plugins: 'autolink',
|
||||
autosave_ask_before_unload: false,
|
||||
indent: false,
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function typeUrl(url) {
|
||||
editor.setContent('<p>' + url + '</p>');
|
||||
Utils.setSelection('p', url.length);
|
||||
Utils.type(' ');
|
||||
return editor.getContent();
|
||||
}
|
||||
|
||||
function typeAnEclipsedURL(url) {
|
||||
url = "(" + url;
|
||||
editor.setContent('<p>' + url + '</p>');
|
||||
Utils.setSelection('p', url.length);
|
||||
Utils.type(')');
|
||||
return editor.getContent();
|
||||
}
|
||||
|
||||
function typeNewlineURL(url) {
|
||||
editor.setContent('<p>' + url + '</p>');
|
||||
Utils.setSelection('p', url.length);
|
||||
Utils.type('\n');
|
||||
return editor.getContent();
|
||||
}
|
||||
|
||||
if (tinymce.Env.ie) {
|
||||
test("Skipped on IE since it has built in logic for autolink", function() {
|
||||
ok(true);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
test("Urls ended with space", function() {
|
||||
equal(typeUrl('http://www.tinymce.com'), '<p><a href="http://www.tinymce.com">http://www.tinymce.com</a></p>');
|
||||
equal(typeUrl('https://www.tinymce.com'), '<p><a href="https://www.tinymce.com">https://www.tinymce.com</a></p>');
|
||||
equal(typeUrl('ssh://www.tinymce.com'), '<p><a href="ssh://www.tinymce.com">ssh://www.tinymce.com</a></p>');
|
||||
equal(typeUrl('ftp://www.tinymce.com'), '<p><a href="ftp://www.tinymce.com">ftp://www.tinymce.com</a></p>');
|
||||
equal(typeUrl('www.tinymce.com'), '<p><a href="http://www.tinymce.com">www.tinymce.com</a></p>');
|
||||
equal(typeUrl('www.tinymce.com.'), '<p><a href="http://www.tinymce.com">www.tinymce.com</a>.</p>');
|
||||
equal(typeUrl('user@domain.com'), '<p><a href="mailto:user@domain.com">user@domain.com</a></p>');
|
||||
equal(typeUrl('mailto:user@domain.com'), '<p><a href="mailto:user@domain.com">mailto:user@domain.com</a></p>');
|
||||
equal(typeUrl('first-last@domain.com'), '<p><a href="mailto:first-last@domain.com">first-last@domain.com</a></p>');
|
||||
});
|
||||
|
||||
test("Urls ended with )", function() {
|
||||
equal(typeAnEclipsedURL('http://www.tinymce.com'), '<p>(<a href="http://www.tinymce.com">http://www.tinymce.com</a>)</p>');
|
||||
equal(typeAnEclipsedURL('https://www.tinymce.com'), '<p>(<a href="https://www.tinymce.com">https://www.tinymce.com</a>)</p>');
|
||||
equal(typeAnEclipsedURL('ssh://www.tinymce.com'), '<p>(<a href="ssh://www.tinymce.com">ssh://www.tinymce.com</a>)</p>');
|
||||
equal(typeAnEclipsedURL('ftp://www.tinymce.com'), '<p>(<a href="ftp://www.tinymce.com">ftp://www.tinymce.com</a>)</p>');
|
||||
equal(typeAnEclipsedURL('www.tinymce.com'), '<p>(<a href="http://www.tinymce.com">www.tinymce.com</a>)</p>');
|
||||
equal(typeAnEclipsedURL('www.tinymce.com.'), '<p>(<a href="http://www.tinymce.com">www.tinymce.com</a>.)</p>');
|
||||
});
|
||||
|
||||
test("Urls ended with new line", function() {
|
||||
equal(typeNewlineURL('http://www.tinymce.com'), '<p><a href="http://www.tinymce.com">http://www.tinymce.com</a></p><p> </p>');
|
||||
equal(typeNewlineURL('https://www.tinymce.com'), '<p><a href="https://www.tinymce.com">https://www.tinymce.com</a></p><p> </p>');
|
||||
equal(typeNewlineURL('ssh://www.tinymce.com'), '<p><a href="ssh://www.tinymce.com">ssh://www.tinymce.com</a></p><p> </p>');
|
||||
equal(typeNewlineURL('ftp://www.tinymce.com'), '<p><a href="ftp://www.tinymce.com">ftp://www.tinymce.com</a></p><p> </p>');
|
||||
equal(typeNewlineURL('www.tinymce.com'), '<p><a href="http://www.tinymce.com">www.tinymce.com</a></p><p> </p>');
|
||||
equal(typeNewlineURL('www.tinymce.com.'), '<p><a href="http://www.tinymce.com">www.tinymce.com</a>.</p><p> </p>');
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,128 @@
|
|||
(function() {
|
||||
module("tinymce.plugins.Image", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: 'textarea',
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
plugins: "image",
|
||||
disable_nodechange: true,
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
delete editor.settings.image_dimensions;
|
||||
delete editor.settings.file_browser_callback;
|
||||
delete editor.settings.image_list;
|
||||
delete editor.settings.image_class_list;
|
||||
|
||||
var win = Utils.getFontmostWindow();
|
||||
|
||||
if (win) {
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function cleanHtml(html) {
|
||||
return Utils.cleanHtml(html).replace(/<p>( |<br[^>]+>)<\/p>$/, '');
|
||||
}
|
||||
|
||||
function fillAndSubmitWindowForm(data) {
|
||||
var win = Utils.getFontmostWindow();
|
||||
|
||||
win.fromJSON(data);
|
||||
win.find('form')[0].submit();
|
||||
win.close();
|
||||
}
|
||||
|
||||
test('Default image dialog on empty editor', function() {
|
||||
editor.setContent('');
|
||||
editor.execCommand('mceImage', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"alt": "",
|
||||
"constrain": true,
|
||||
"height": "",
|
||||
"src": "",
|
||||
"width": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"alt": "alt",
|
||||
"height": "100",
|
||||
"src": "src",
|
||||
"width": "200"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p><img src="src" alt="alt" width="200" height="100" /></p>'
|
||||
);
|
||||
});
|
||||
|
||||
test('Image dialog image_dimensions: false', function() {
|
||||
editor.settings.image_dimensions = false;
|
||||
editor.setContent('');
|
||||
editor.execCommand('mceImage', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"alt": "",
|
||||
"src": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"alt": "alt",
|
||||
"src": "src"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p><img src="src" alt="alt" /></p>'
|
||||
);
|
||||
});
|
||||
|
||||
test('All image dialog ui options on empty editor', function() {
|
||||
editor.settings.image_list = [
|
||||
{title: 'link1', value: 'link1'},
|
||||
{title: 'link2', value: 'link2'}
|
||||
];
|
||||
|
||||
editor.settings.image_class_list = [
|
||||
{title: 'class1', value: 'class1'},
|
||||
{title: 'class2', value: 'class2'}
|
||||
];
|
||||
|
||||
editor.setContent('');
|
||||
editor.execCommand('mceImage', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"alt": "",
|
||||
"class": "class1",
|
||||
"constrain": true,
|
||||
"height": "",
|
||||
"src": "",
|
||||
"width": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"alt": "alt",
|
||||
"class": "class1",
|
||||
"constrain": true,
|
||||
"height": "200",
|
||||
"src": "src",
|
||||
"width": "100"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p><img class="class1" src="src" alt="alt" width="100" height="200" /></p>'
|
||||
);
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,212 @@
|
|||
(function() {
|
||||
module("tinymce.plugins.ImportCSS", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
plugins: 'importcss',
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
editor.contentCSS = [];
|
||||
delete editor.settings.importcss_file_filter;
|
||||
delete editor.settings.importcss_merge_classes;
|
||||
delete editor.settings.importcss_append;
|
||||
delete editor.settings.importcss_selector_filter;
|
||||
delete editor.settings.importcss_groups;
|
||||
}
|
||||
});
|
||||
|
||||
function fireFormatsMenuEvent(styleSheets, items) {
|
||||
return editor.fire('renderFormatsMenu', {
|
||||
control: tinymce.ui.Factory.create('menu', {items: items}).renderTo(document.getElementById('view')),
|
||||
doc: {
|
||||
styleSheets: styleSheets
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getMenuItemFormat(item) {
|
||||
return editor.formatter.get(item.settings.format)[0];
|
||||
}
|
||||
|
||||
test("Import content_css files", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.contentCSS.push("test2.css");
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{
|
||||
href: 'test1.css',
|
||||
cssRules: [
|
||||
{selectorText: '.a'},
|
||||
{selectorText: 'p.b'},
|
||||
{selectorText: 'img.c'}
|
||||
]
|
||||
},
|
||||
|
||||
{href: 'test2.css', cssRules: [{selectorText: '.d'}]},
|
||||
{href: 'test3.css', cssRules: [{selectorText: '.e'}]}
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 4);
|
||||
|
||||
equal(evt.control.items()[0].text(), 'a');
|
||||
equal(getMenuItemFormat(evt.control.items()[0]).classes, 'a');
|
||||
|
||||
equal(evt.control.items()[1].text(), 'p.b');
|
||||
equal(getMenuItemFormat(evt.control.items()[1]).block, 'p');
|
||||
equal(getMenuItemFormat(evt.control.items()[1]).classes, 'b');
|
||||
|
||||
equal(evt.control.items()[2].text(), 'img.c');
|
||||
equal(getMenuItemFormat(evt.control.items()[2]).selector, 'img');
|
||||
equal(getMenuItemFormat(evt.control.items()[2]).classes, 'c');
|
||||
|
||||
equal(evt.control.items()[3].text(), 'd');
|
||||
});
|
||||
|
||||
test("Import custom importcss_merge_classes: false", function() {
|
||||
editor.contentCSS.push("test.css");
|
||||
editor.settings.importcss_merge_classes = false;
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test.css', cssRules: [{selectorText: '.a'}]}
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
deepEqual(getMenuItemFormat(evt.control.items()[0]).attributes, {"class": "a"});
|
||||
});
|
||||
|
||||
test("Import custom importcss_append: true", function() {
|
||||
editor.contentCSS.push("test.css");
|
||||
editor.settings.importcss_append = true;
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test.css', cssRules: [{selectorText: '.b'}]}
|
||||
], {text: 'a'});
|
||||
|
||||
equal(evt.control.items().length, 2);
|
||||
equal(evt.control.items()[0].text(), 'a');
|
||||
equal(evt.control.items()[1].text(), 'b');
|
||||
});
|
||||
|
||||
test("Import custom importcss_selector_filter (string)", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_selector_filter = ".a";
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [
|
||||
{selectorText: '.a'},
|
||||
{selectorText: '.b'}
|
||||
]},
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
equal(evt.control.items()[0].text(), 'a');
|
||||
});
|
||||
|
||||
test("Import custom importcss_selector_filter (function)", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_selector_filter = function(selector) {
|
||||
return selector === ".a";
|
||||
};
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [
|
||||
{selectorText: '.a'},
|
||||
{selectorText: '.b'}
|
||||
]},
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
equal(evt.control.items()[0].text(), 'a');
|
||||
});
|
||||
|
||||
test("Import custom importcss_selector_filter (regexp)", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_selector_filter = /a/;
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [
|
||||
{selectorText: '.a'},
|
||||
{selectorText: '.b'}
|
||||
]},
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
equal(evt.control.items()[0].text(), 'a');
|
||||
});
|
||||
|
||||
test("Import custom importcss_groups", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_groups = [
|
||||
{title: 'g1', filter: /a/},
|
||||
{title: 'g2', filter: /b/},
|
||||
{title: 'g3'}
|
||||
];
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [
|
||||
{selectorText: '.a'},
|
||||
{selectorText: '.b'},
|
||||
{selectorText: '.c'}
|
||||
]},
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 3);
|
||||
equal(evt.control.items()[0].text(), 'g1');
|
||||
equal(evt.control.items()[0].settings.menu[0].text, 'a');
|
||||
equal(evt.control.items()[1].text(), 'g2');
|
||||
equal(evt.control.items()[1].settings.menu[0].text, 'b');
|
||||
equal(evt.control.items()[2].text(), 'g3');
|
||||
equal(evt.control.items()[2].settings.menu[0].text, 'c');
|
||||
});
|
||||
|
||||
test("Import custom importcss_file_filter (string)", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_file_filter = "test2.css";
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [{selectorText: '.a'}]},
|
||||
{href: 'test2.css', cssRules: [{selectorText: '.b'}]}
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
equal(evt.control.items()[0].text(), 'b');
|
||||
});
|
||||
|
||||
test("Import custom importcss_file_filter (function)", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_file_filter = function(href) {
|
||||
return href === "test2.css";
|
||||
};
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [{selectorText: '.a'}]},
|
||||
{href: 'test2.css', cssRules: [{selectorText: '.b'}]}
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
equal(evt.control.items()[0].text(), 'b');
|
||||
});
|
||||
|
||||
test("Import custom importcss_file_filter (regexp)", function() {
|
||||
editor.contentCSS.push("test1.css");
|
||||
editor.settings.importcss_file_filter = /test2\.css/;
|
||||
|
||||
var evt = fireFormatsMenuEvent([
|
||||
{href: 'test1.css', cssRules: [{selectorText: '.a'}]},
|
||||
{href: 'test2.css', cssRules: [{selectorText: '.b'}]}
|
||||
]);
|
||||
|
||||
equal(evt.control.items().length, 1);
|
||||
equal(evt.control.items()[0].text(), 'b');
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,162 @@
|
|||
(function() {
|
||||
module("tinymce.plugins.Link", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: 'textarea',
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
indent: false,
|
||||
plugins: "link",
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
delete editor.settings.file_browser_callback;
|
||||
delete editor.settings.link_list;
|
||||
delete editor.settings.link_class_list;
|
||||
delete editor.settings.link_target_list;
|
||||
delete editor.settings.rel_list;
|
||||
|
||||
var win = Utils.getFontmostWindow();
|
||||
|
||||
if (win) {
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function cleanHtml(html) {
|
||||
return Utils.cleanHtml(html).replace(/<p>( |<br[^>]+>)<\/p>$/, '');
|
||||
}
|
||||
|
||||
function fillAndSubmitWindowForm(data) {
|
||||
var win = Utils.getFontmostWindow();
|
||||
|
||||
win.fromJSON(data);
|
||||
win.find('form')[0].submit();
|
||||
win.close();
|
||||
}
|
||||
|
||||
test('Default link dialog on empty editor', function() {
|
||||
editor.setContent('');
|
||||
editor.execCommand('mceLink', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"href": "",
|
||||
"target": "",
|
||||
"text": "",
|
||||
"title": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"href": "href",
|
||||
"target": "_blank",
|
||||
"text": "text",
|
||||
"title": "title"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p><a title="title" href="href" target="_blank">text</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
test('Default link dialog on text selection', function() {
|
||||
editor.setContent('<p>abc</p>');
|
||||
Utils.setSelection('p', 1, 'p', 2);
|
||||
editor.execCommand('mceLink', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"href": "",
|
||||
"target": "",
|
||||
"text": "b",
|
||||
"title": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"href": "href",
|
||||
"target": "_blank",
|
||||
"title": "title"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p>a<a title="title" href="href" target="_blank">b</a>c</p>'
|
||||
);
|
||||
});
|
||||
|
||||
test('Default link dialog on non pure text selection', function() {
|
||||
editor.setContent('<p>a</p><p>bc</p>');
|
||||
Utils.setSelection('p:nth-child(1)', 0, 'p:nth-child(2)', 2);
|
||||
editor.execCommand('mceLink', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"href": "",
|
||||
"target": "",
|
||||
"title": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"href": "href",
|
||||
"target": "_blank",
|
||||
"title": "title"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p><a title="title" href="href" target="_blank">a</a></p>' +
|
||||
'<p><a title="title" href="href" target="_blank">bc</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
test('All lists link dialog on empty editor', function() {
|
||||
editor.settings.link_list = [
|
||||
{title: 'link1', value: 'link1'},
|
||||
{title: 'link2', value: 'link2'}
|
||||
];
|
||||
|
||||
editor.settings.link_class_list = [
|
||||
{title: 'class1', value: 'class1'},
|
||||
{title: 'class2', value: 'class2'}
|
||||
];
|
||||
|
||||
editor.settings.target_list = [
|
||||
{title: 'target1', value: 'target1'},
|
||||
{title: 'target2', value: 'target2'}
|
||||
];
|
||||
|
||||
editor.settings.rel_list = [
|
||||
{title: 'rel1', value: 'rel1'},
|
||||
{title: 'rel2', value: 'rel2'}
|
||||
];
|
||||
|
||||
editor.setContent('');
|
||||
editor.execCommand('mceLink', true);
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"class": "class1",
|
||||
"href": "",
|
||||
"rel": "rel1",
|
||||
"target": "target1",
|
||||
"text": "",
|
||||
"title": ""
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"href": "href",
|
||||
"text": "text",
|
||||
"title": "title"
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanHtml(editor.getContent()),
|
||||
'<p><a class="class1" title="title" href="href" target="target1" rel="rel1">text</a></p>'
|
||||
);
|
||||
});
|
||||
})();
|
|
@ -22,7 +22,7 @@ module("tinymce.plugins.Lists", {
|
|||
indent: false,
|
||||
schema: 'html5',
|
||||
entities: 'raw',
|
||||
valid_elements: 'li,ol,ul,em,strong,span,#p,div,br',
|
||||
valid_elements: 'li,ol,ul,dl,dt,dd,em,strong,span,#p,div,br',
|
||||
valid_styles: {
|
||||
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left'
|
||||
},
|
||||
|
@ -1360,6 +1360,31 @@ test('Indent second LI to same level as nested LI 2', function() {
|
|||
equal(editor.selection.getNode().nodeName, 'LI');
|
||||
});
|
||||
|
||||
test('Indent second and third LI', function() {
|
||||
editor.getBody().innerHTML = trimBrs(
|
||||
'<ul>' +
|
||||
'<li>a</li>' +
|
||||
'<li>b</li>' +
|
||||
'<li>c</li>' +
|
||||
'</ul>'
|
||||
);
|
||||
|
||||
editor.focus();
|
||||
Utils.setSelection('li:nth-child(2)', 0, 'li:last', 0);
|
||||
execCommand('Indent');
|
||||
|
||||
equal(editor.getContent(),
|
||||
'<ul>' +
|
||||
'<li>a' +
|
||||
'<ul>' +
|
||||
'<li>b</li>' +
|
||||
'<li>c</li>' +
|
||||
'</ul>' +
|
||||
'</li>' +
|
||||
'</ul>'
|
||||
);
|
||||
});
|
||||
|
||||
// Backspace
|
||||
|
||||
test('Backspace at beginning of single LI in UL', function() {
|
||||
|
@ -1749,3 +1774,102 @@ test('Backspace in LI in UL in inline body element contained within LI', functio
|
|||
inlineEditor.plugins.lists.backspaceDelete();
|
||||
equal(inlineEditor.getContent(), '<p>a</p>');
|
||||
});
|
||||
|
||||
test('Apply DL list to multiple Ps', function() {
|
||||
editor.getBody().innerHTML = trimBrs(
|
||||
'<p>a</p>' +
|
||||
'<p>b</p>' +
|
||||
'<p>c</p>'
|
||||
);
|
||||
|
||||
editor.focus();
|
||||
Utils.setSelection('p', 0, 'p:last', 0);
|
||||
execCommand('InsertDefinitionList');
|
||||
|
||||
equal(editor.getContent(),
|
||||
'<dl>' +
|
||||
'<dt>a</dt>' +
|
||||
'<dt>b</dt>' +
|
||||
'<dt>c</dt>' +
|
||||
'</dl>'
|
||||
);
|
||||
equal(editor.selection.getStart().nodeName, 'DT');
|
||||
});
|
||||
|
||||
test('Apply OL list to single P', function() {
|
||||
editor.getBody().innerHTML = trimBrs(
|
||||
'<p>a</p>'
|
||||
);
|
||||
|
||||
editor.focus();
|
||||
Utils.setSelection('p', 0);
|
||||
execCommand('InsertDefinitionList');
|
||||
|
||||
equal(editor.getContent(),'<dl><dt>a</dt></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DT');
|
||||
});
|
||||
|
||||
test('Apply DL to P and merge with adjacent lists', function() {
|
||||
editor.getBody().innerHTML = trimBrs(
|
||||
'<dl>' +
|
||||
'<dt>a</dt>' +
|
||||
'</dl>' +
|
||||
'<p>b</p>' +
|
||||
'<dl>' +
|
||||
'<dt>c</dt>' +
|
||||
'</dl>'
|
||||
);
|
||||
|
||||
editor.focus();
|
||||
Utils.setSelection('p', 1);
|
||||
execCommand('InsertDefinitionList');
|
||||
|
||||
equal(editor.getContent(),
|
||||
'<dl>' +
|
||||
'<dt>a</dt>' +
|
||||
'<dt>b</dt>' +
|
||||
'<dt>c</dt>' +
|
||||
'</dl>'
|
||||
);
|
||||
equal(editor.selection.getStart().nodeName, 'DT');
|
||||
});
|
||||
|
||||
test('Indent single DT in DL', function() {
|
||||
editor.getBody().innerHTML = trimBrs(
|
||||
'<dl>' +
|
||||
'<dt>a</dt>' +
|
||||
'</dl>'
|
||||
);
|
||||
|
||||
editor.focus();
|
||||
Utils.setSelection('dt', 0);
|
||||
execCommand('Indent');
|
||||
|
||||
equal(editor.getContent(),
|
||||
'<dl>' +
|
||||
'<dd>a</dd>' +
|
||||
'</dl>'
|
||||
);
|
||||
|
||||
equal(editor.selection.getNode().nodeName, 'DD');
|
||||
});
|
||||
|
||||
test('Outdent single DD in DL', function() {
|
||||
editor.getBody().innerHTML = trimBrs(
|
||||
'<dl>' +
|
||||
'<dd>a</dd>' +
|
||||
'</dl>'
|
||||
);
|
||||
|
||||
editor.focus();
|
||||
Utils.setSelection('dd', 1);
|
||||
execCommand('Outdent');
|
||||
|
||||
equal(editor.getContent(),
|
||||
'<dl>' +
|
||||
'<dt>a</dt>' +
|
||||
'</dl>'
|
||||
);
|
||||
|
||||
equal(editor.selection.getNode().nodeName, 'DT');
|
||||
});
|
||||
|
|
|
@ -40,14 +40,12 @@ test("Object retain as is", function() {
|
|||
|
||||
test("Embed retain as is", function() {
|
||||
editor.setContent(
|
||||
'<video src="320x240.ogg" autoplay loop controls>text<a href="#">link</a></video>'
|
||||
'<embed src="320x240.ogg" width="100" height="200">text<a href="#">link</a></embed>'
|
||||
);
|
||||
|
||||
equal(editor.getContent(),
|
||||
// IE produces a different attribute order for some odd reason, I love IE
|
||||
tinymce.isIE ?
|
||||
'<p><video width="300" height="150" controls="controls" loop="loop" autoplay="autoplay" src="320x240.ogg">text<a href="#">link</a></video></p>' :
|
||||
'<p><video width="300" height="150" src="320x240.ogg" autoplay="autoplay" loop="loop" controls="controls">text<a href="#">link</a></video></p>'
|
||||
equal(
|
||||
editor.getContent(),
|
||||
'<p><embed src="320x240.ogg" width="100" height="200"></embed>text<a href="#">link</a></p>'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -56,11 +54,9 @@ test("Video retain as is", function() {
|
|||
'<video src="320x240.ogg" autoplay loop controls>text<a href="#">link</a></video>'
|
||||
);
|
||||
|
||||
equal(editor.getContent(),
|
||||
// IE produces a different attribute order for some odd reason, I love IE
|
||||
tinymce.isIE ?
|
||||
'<p><video width="300" height="150" controls="controls" loop="loop" autoplay="autoplay" src="320x240.ogg">text<a href="#">link</a></video></p>' :
|
||||
'<p><video width="300" height="150" src="320x240.ogg" autoplay="autoplay" loop="loop" controls="controls">text<a href="#">link</a></video></p>'
|
||||
equal(
|
||||
editor.getContent(),
|
||||
'<p><video src="320x240.ogg" autoplay="autoplay" loop="loop" controls="controls" width="300" height="150">text<a href="#">link</a></video></p>'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -114,7 +110,7 @@ test("Resize complex object", function() {
|
|||
|
||||
equal(editor.getContent(),
|
||||
'<p>' +
|
||||
'<video width="100" height="200" controls="controls">' +
|
||||
'<video controls="controls" width="100" height="200">' +
|
||||
'<source src="s" />' +
|
||||
'<object type="application/x-shockwave-flash" data="../../js/tinymce/plugins/media/moxieplayer.swf" width="100" height="200">' +
|
||||
'<param name="allowfullscreen" value="true" />' +
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,314 +1,343 @@
|
|||
module("tinymce.plugins.Table", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
(function() {
|
||||
module("tinymce.plugins.Table", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
plugins: 'table',
|
||||
valid_styles: {
|
||||
'*' : 'width,height,text-align,float'
|
||||
},
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
indent: false,
|
||||
plugins: 'table',
|
||||
valid_styles: {
|
||||
'*' : 'width,height,vertical-align,text-align,float'
|
||||
},
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function fillAndSubmitWindowForm(data) {
|
||||
var win = Utils.getFontmostWindow();
|
||||
|
||||
win.fromJSON(data);
|
||||
win.find('form')[0].submit();
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
|
||||
function fillAndSubmitWindowForm(data) {
|
||||
var win = Utils.getFontmostWindow();
|
||||
function cleanTableHtml(html) {
|
||||
return Utils.cleanHtml(html).replace(/<p>( |<br[^>]+>)<\/p>$/, '');
|
||||
}
|
||||
|
||||
win.fromJSON(data);
|
||||
win.find('form')[0].submit();
|
||||
win.close();
|
||||
}
|
||||
test("Table properties dialog (get data from plain table)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
|
||||
function cleanTableHtml(html) {
|
||||
return Utils.cleanHtml(html).replace(/<p>( |<br[^>]+>)<\/p>$/, '');
|
||||
}
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"border": "",
|
||||
"caption": false,
|
||||
"cellpadding": "",
|
||||
"cellspacing": "",
|
||||
"height": "",
|
||||
"width": ""
|
||||
});
|
||||
|
||||
test("Table properties dialog (get data from plain table)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"border": "",
|
||||
"caption": false,
|
||||
"cellpadding": "",
|
||||
"cellspacing": "",
|
||||
"height": "",
|
||||
"width": ""
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
test("Table properties dialog (get data from full table)", function() {
|
||||
editor.setContent(
|
||||
'<table style="width: 100px; height: 101px;" border="4" cellspacing="2" cellpadding="3">' +
|
||||
'<caption> </caption>' +
|
||||
'<tbody>' +
|
||||
'<tr>' +
|
||||
'<td> </td>' +
|
||||
'</tr>' +
|
||||
'</tbody>' +
|
||||
'</table>'
|
||||
);
|
||||
|
||||
test("Table properties dialog (get data from full table)", function() {
|
||||
editor.setContent(
|
||||
'<table style="width: 100px; height: 101px;" border="4" cellspacing="2" cellpadding="3">' +
|
||||
'<caption> </caption>' +
|
||||
'<tbody>' +
|
||||
'<tr>' +
|
||||
'<td> </td>' +
|
||||
'</tr>' +
|
||||
'</tbody>' +
|
||||
'</table>'
|
||||
);
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"border": "4",
|
||||
"caption": true,
|
||||
"cellpadding": "3",
|
||||
"cellspacing": "2",
|
||||
"height": "101",
|
||||
"width": "100"
|
||||
});
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"border": "4",
|
||||
"caption": true,
|
||||
"cellpadding": "3",
|
||||
"cellspacing": "2",
|
||||
"height": "101",
|
||||
"width": "100"
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
test("Table properties dialog (add caption)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
caption: true
|
||||
});
|
||||
|
||||
test("Table properties dialog (add caption)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
caption: true
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><caption> </caption><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><caption> </caption><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Table properties dialog (remove caption)", function() {
|
||||
editor.setContent('<table><caption> </caption><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
caption: false
|
||||
});
|
||||
|
||||
test("Table properties dialog (remove caption)", function() {
|
||||
editor.setContent('<table><caption> </caption><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
caption: false
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Table properties dialog (change size in pixels)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
width: 100,
|
||||
height: 101
|
||||
});
|
||||
|
||||
test("Table properties dialog (change size in pixels)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
width: 100,
|
||||
height: 101
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table style="width: 100px; height: 101px;"><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table style="width: 100px; height: 101px;"><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Table properties dialog (change size in %)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
width: "100%",
|
||||
height: "101%"
|
||||
});
|
||||
|
||||
test("Table properties dialog (change size in %)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
width: "100%",
|
||||
height: "101%"
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table style="width: 100%; height: 101%;"><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table style="width: 100%; height: 101%;"><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Table properties dialog (change: border,cellpadding,cellspacing,align)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
border: "1",
|
||||
cellpadding: "2",
|
||||
cellspacing: "3",
|
||||
align: "right"
|
||||
});
|
||||
|
||||
test("Table properties dialog (change: border,cellpadding,cellspacing,align)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceInsertTable');
|
||||
fillAndSubmitWindowForm({
|
||||
border: "1",
|
||||
cellpadding: "2",
|
||||
cellspacing: "3",
|
||||
align: "right"
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table style="float: right;" border="1" cellspacing="3" cellpadding="2"><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table style="float: right;" border="1" cellspacing="3" cellpadding="2"><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Table cell properties dialog (get data from plain cell)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableCellProps');
|
||||
|
||||
test("Table cell properties dialog (get data from plain cell)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableCellProps');
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"valign": "",
|
||||
"height": "",
|
||||
"scope": "",
|
||||
"type": "td",
|
||||
"width": ""
|
||||
});
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"height": "",
|
||||
"scope": "",
|
||||
"type": "td",
|
||||
"width": ""
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
test("Table cell properties dialog (get data from complex cell)", function() {
|
||||
editor.setContent('<table><tr><th style="text-align: right; vertical-align: top; width: 10px; height: 11px" scope="row">X</th></tr></table>');
|
||||
Utils.setSelection('th', 0);
|
||||
editor.execCommand('mceTableCellProps');
|
||||
|
||||
test("Table cell properties dialog (get data from complex cell)", function() {
|
||||
editor.setContent('<table><tr><th style="text-align: right; width: 10px; height: 11px" scope="row">X</th></tr></table>');
|
||||
Utils.setSelection('th', 0);
|
||||
editor.execCommand('mceTableCellProps');
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "right",
|
||||
"valign": "top",
|
||||
"height": "11",
|
||||
"scope": "row",
|
||||
"type": "th",
|
||||
"width": "10"
|
||||
});
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "right",
|
||||
"height": "11",
|
||||
"scope": "row",
|
||||
"type": "th",
|
||||
"width": "10"
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
test("Table cell properties dialog (update all)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableCellProps');
|
||||
|
||||
test("Table cell properties dialog (update all)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableCellProps');
|
||||
fillAndSubmitWindowForm({
|
||||
"align": "right",
|
||||
"height": "11",
|
||||
"scope": "row",
|
||||
"type": "th",
|
||||
"width": "10"
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"align": "right",
|
||||
"height": "11",
|
||||
"scope": "row",
|
||||
"type": "th",
|
||||
"width": "10"
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><tbody><tr><th style="width: 10px; height: 11px; text-align: right;" scope="row">x</th></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><tbody><tr><th style="width: 10px; height: 11px; text-align: right;" scope="row">x</th></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Table row properties dialog (get data from plain cell)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableRowProps');
|
||||
|
||||
test("Table row properties dialog (get data from plain cell)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableRowProps');
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"height": "",
|
||||
"type": "tbody"
|
||||
});
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "",
|
||||
"height": "",
|
||||
"type": "tbody"
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
test("Table row properties dialog (get data from complex cell)", function() {
|
||||
editor.setContent('<table><thead><tr style="height: 10px; text-align: right"><td>X</td></tr></thead></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableRowProps');
|
||||
|
||||
test("Table row properties dialog (get data from complex cell)", function() {
|
||||
editor.setContent('<table><thead><tr style="height: 10px; text-align: right"><td>X</td></tr></thead></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableRowProps');
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "right",
|
||||
"height": "10",
|
||||
"type": "thead"
|
||||
});
|
||||
|
||||
deepEqual(Utils.getFontmostWindow().toJSON(), {
|
||||
"align": "right",
|
||||
"height": "10",
|
||||
"type": "thead"
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
|
||||
Utils.getFontmostWindow().close();
|
||||
});
|
||||
test("Table row properties dialog (update all)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableRowProps');
|
||||
|
||||
test("Table row properties dialog (update all)", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableRowProps');
|
||||
fillAndSubmitWindowForm({
|
||||
"align": "right",
|
||||
"height": "10",
|
||||
"type": "thead"
|
||||
});
|
||||
|
||||
fillAndSubmitWindowForm({
|
||||
"align": "right",
|
||||
"height": "10",
|
||||
"type": "thead"
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><thead><tr style="height: 10px; text-align: right;"><td>x</td></tr></thead></table>'
|
||||
);
|
||||
});
|
||||
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><thead><tr style="height: 10px; text-align: right;"><td>x</td></tr></thead></table>'
|
||||
);
|
||||
});
|
||||
test("mceTableDelete command", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableDelete');
|
||||
equal(cleanTableHtml(editor.getContent()), '');
|
||||
});
|
||||
|
||||
test("mceTableDelete command", function() {
|
||||
editor.setContent('<table><tr><td>X</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableDelete');
|
||||
equal(cleanTableHtml(editor.getContent()), '');
|
||||
});
|
||||
test("mceTableDeleteCol command", function() {
|
||||
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableDeleteCol');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableDeleteCol command", function() {
|
||||
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableDeleteCol');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableDeleteRow command", function() {
|
||||
editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableDeleteRow');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableDeleteRow command", function() {
|
||||
editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableDeleteRow');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableInsertColAfter command", function() {
|
||||
editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertColAfter');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td> </td></tr><tr><td>2</td><td> </td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableInsertColAfter command", function() {
|
||||
editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertColAfter');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td> </td></tr><tr><td>2</td><td> </td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableInsertColBefore command", function() {
|
||||
editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertColBefore');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td> </td><td>1</td></tr><tr><td> </td><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableInsertColBefore command", function() {
|
||||
editor.setContent('<table><tr><td>1</td></tr><tr><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertColBefore');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td> </td><td>1</td></tr><tr><td> </td><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableInsertRowAfter command", function() {
|
||||
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertRowAfter');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td>2</td></tr><tr><td> </td><td> </td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableInsertRowAfter command", function() {
|
||||
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertRowAfter');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td>1</td><td>2</td></tr><tr><td> </td><td> </td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableInsertRowBefore command", function() {
|
||||
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertRowBefore');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td> </td><td> </td></tr><tr><td>1</td><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableInsertRowBefore command", function() {
|
||||
editor.setContent('<table><tr><td>1</td><td>2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableInsertRowBefore');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td> </td><td> </td></tr><tr><td>1</td><td>2</td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableMergeCells command with cell selection", function() {
|
||||
editor.setContent('<table><tr><td class="mce-item-selected">1</td><td class="mce-item-selected">2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableMergeCells');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
|
||||
});
|
||||
|
||||
test("mceTableMergeCells command with cell selection", function() {
|
||||
editor.setContent('<table><tr><td class="mce-item-selected">1</td><td class="mce-item-selected">2</td></tr></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableMergeCells');
|
||||
equal(cleanTableHtml(editor.getContent()), '<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
|
||||
});
|
||||
test("mceTableSplitCells command", function() {
|
||||
editor.setContent('<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableSplitCells');
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><tbody><tr><td>12</td><td> </td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
|
||||
test("mceTableSplitCells command", function() {
|
||||
editor.setContent('<table><tbody><tr><td colspan="2">12</td></tr></tbody></table>');
|
||||
Utils.setSelection('td', 0);
|
||||
editor.execCommand('mceTableSplitCells');
|
||||
equal(
|
||||
cleanTableHtml(editor.getContent()),
|
||||
'<table><tbody><tr><td>12</td><td> </td></tr></tbody></table>'
|
||||
);
|
||||
});
|
||||
test("Tab key navigation", function() {
|
||||
editor.setContent('<table><tbody><tr><td>A1</td><td>A2</td></tr><tr><td>B1</td><td>B2</td></tr></tbody></table><p>x</p>');
|
||||
|
||||
Utils.setSelection('td', 0);
|
||||
editor.fire('keydown', {keyCode: 9});
|
||||
equal(editor.selection.getStart().innerHTML, 'A2');
|
||||
|
||||
Utils.setSelection('td', 0);
|
||||
editor.fire('keydown', {keyCode: 9, shiftKey: true});
|
||||
equal(editor.selection.getStart().innerHTML, 'A1');
|
||||
|
||||
Utils.setSelection('td:nth-child(2)', 0);
|
||||
editor.fire('keydown', {keyCode: 9, shiftKey: true});
|
||||
equal(editor.selection.getStart().innerHTML, 'A1');
|
||||
|
||||
Utils.setSelection('tr:nth-child(2) td:nth-child(2)', 0);
|
||||
editor.fire('keydown', {keyCode: 9});
|
||||
equal(editor.selection.getStart().nodeName, 'TD');
|
||||
equal(
|
||||
editor.getContent(),
|
||||
'<table><tbody><tr><td>A1</td><td>A2</td></tr><tr><td>B1</td><td>B2</td></tr><tr><td> </td><td> </td></tr></tbody></table><p>x</p>'
|
||||
);
|
||||
});
|
||||
})();
|
|
@ -1,9 +1,10 @@
|
|||
module("tinymce.Editor", {
|
||||
setupModule: function() {
|
||||
document.getElementById('view').innerHTML = '<textarea id="elm1"></textarea><div id="elm2"></div>';
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
selector: "#elm1",
|
||||
add_unload_trigger: false,
|
||||
disable_nodechange: true,
|
||||
skin: false,
|
||||
|
@ -16,9 +17,35 @@ module("tinymce.Editor", {
|
|||
extended_valid_elements: 'custom1,custom2',
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
|
||||
if (window.inlineEditor) {
|
||||
QUnit.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tinymce.init({
|
||||
selector: "#elm2",
|
||||
add_unload_trigger: false,
|
||||
disable_nodechange: true,
|
||||
skin: false,
|
||||
entities: 'raw',
|
||||
indent: false,
|
||||
inline: true,
|
||||
init_instance_callback: function(ed) {
|
||||
window.inlineEditor = ed;
|
||||
|
||||
if (window.editor) {
|
||||
QUnit.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
Utils.unpatch(editor.getDoc());
|
||||
inlineEditor.show();
|
||||
editor.show();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -197,3 +224,129 @@ test('Store/restore tabindex', function() {
|
|||
equal(editor.getContent({format:'raw'}).toLowerCase(), '<p><span data-mce-tabindex="42">abc</span></p>');
|
||||
equal(editor.getContent(), '<p><span tabindex="42">abc</span></p>');
|
||||
});
|
||||
|
||||
test('show/hide/isHidden and events', function() {
|
||||
var lastEvent;
|
||||
|
||||
editor.on('show hide', function(e) {
|
||||
lastEvent = e;
|
||||
});
|
||||
|
||||
equal(editor.isHidden(), false, 'Initial isHidden state');
|
||||
|
||||
editor.hide();
|
||||
equal(editor.isHidden(), true, 'After hide isHidden state');
|
||||
equal(lastEvent.type, "hide");
|
||||
|
||||
lastEvent = null;
|
||||
editor.hide();
|
||||
strictEqual(lastEvent, null);
|
||||
|
||||
editor.show();
|
||||
equal(editor.isHidden(), false, 'After show isHidden state');
|
||||
equal(lastEvent.type, "show");
|
||||
|
||||
lastEvent = null;
|
||||
editor.show();
|
||||
strictEqual(lastEvent, null);
|
||||
});
|
||||
|
||||
test('show/hide/isHidden and events (inline)', function() {
|
||||
var lastEvent;
|
||||
|
||||
inlineEditor.on('show hide', function(e) {
|
||||
lastEvent = e;
|
||||
});
|
||||
|
||||
equal(inlineEditor.isHidden(), false, 'Initial isHidden state');
|
||||
|
||||
inlineEditor.hide();
|
||||
equal(inlineEditor.isHidden(), true, 'After hide isHidden state');
|
||||
equal(lastEvent.type, "hide");
|
||||
strictEqual(inlineEditor.getBody().contentEditable, "false", "ContentEditable after hide");
|
||||
|
||||
lastEvent = null;
|
||||
inlineEditor.hide();
|
||||
strictEqual(lastEvent, null);
|
||||
|
||||
inlineEditor.show();
|
||||
equal(inlineEditor.isHidden(), false, 'After show isHidden state');
|
||||
equal(lastEvent.type, "show");
|
||||
strictEqual(inlineEditor.getBody().contentEditable, "true", "ContentEditable after show");
|
||||
|
||||
lastEvent = null;
|
||||
inlineEditor.show();
|
||||
strictEqual(lastEvent, null);
|
||||
});
|
||||
|
||||
test('hide save content and hidden state while saving', function() {
|
||||
var lastEvent, hiddenStateWhileSaving;
|
||||
|
||||
editor.on('SaveContent', function(e) {
|
||||
lastEvent = e;
|
||||
hiddenStateWhileSaving = editor.isHidden();
|
||||
});
|
||||
|
||||
editor.setContent('xyz');
|
||||
editor.hide();
|
||||
|
||||
strictEqual(hiddenStateWhileSaving, false, 'False isHidden state while saving');
|
||||
strictEqual(lastEvent.content, '<p>xyz</p>');
|
||||
strictEqual(document.getElementById('elm1').value, '<p>xyz</p>');
|
||||
});
|
||||
|
||||
asyncTest('remove editor', function() {
|
||||
document.getElementById('view').appendChild(tinymce.DOM.create('textarea', {id: 'elmx'}));
|
||||
|
||||
tinymce.init({
|
||||
selector: "#elmx",
|
||||
add_unload_trigger: false,
|
||||
disable_nodechange: true,
|
||||
skin: false,
|
||||
init_instance_callback: function(editor) {
|
||||
window.setTimeout(function() {
|
||||
var lastEvent;
|
||||
|
||||
editor.on('SaveContent', function(e) {
|
||||
lastEvent = e;
|
||||
});
|
||||
|
||||
editor.setContent('xyz');
|
||||
editor.remove();
|
||||
|
||||
QUnit.start();
|
||||
|
||||
strictEqual(lastEvent.content, '<p>xyz</p>');
|
||||
strictEqual(document.getElementById('elmx').value, '<p>xyz</p>');
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('insertContent', function() {
|
||||
editor.setContent('<p>a</p>');
|
||||
Utils.setSelection('p', 1);
|
||||
editor.insertContent('b');
|
||||
equal(editor.getContent(), '<p>ab</p>');
|
||||
});
|
||||
|
||||
test('insertContent merge', function() {
|
||||
editor.setContent('<p><strong>a</strong></p>');
|
||||
Utils.setSelection('p', 1);
|
||||
editor.insertContent('<em><strong>b</strong></em>', {merge: true});
|
||||
equal(editor.getContent(), '<p><strong>a<em>b</em></strong></p>');
|
||||
});
|
||||
|
||||
test('execCommand return values for native commands', function() {
|
||||
var lastCmd;
|
||||
|
||||
strictEqual(editor.execCommand("NonExistingCommand"), false, "Return value for a completely unhandled command");
|
||||
|
||||
Utils.patch(editor.getDoc(), 'execCommand', function(orgFunc, cmd) {
|
||||
lastCmd = cmd;
|
||||
return true;
|
||||
});
|
||||
|
||||
strictEqual(editor.execCommand("ExistingCommand"), true, "Return value for an editor handled command");
|
||||
strictEqual(lastCmd, "ExistingCommand");
|
||||
});
|
||||
|
|
|
@ -311,6 +311,27 @@ test('mceInsertContent - block element with space before/after at middle of bloc
|
|||
equal(editor.getContent(), '<p>a</p><p>b</p><p>c</p>');
|
||||
});
|
||||
|
||||
test('mceInsertContent - strong in strong', function() {
|
||||
editor.getBody().innerHTML = '<strong>ac</strong>';
|
||||
Utils.setSelection('strong', 1);
|
||||
editor.execCommand('mceInsertContent', false, {content: '<strong>b</strong>', merge: true});
|
||||
equal(editor.getContent(), '<p><strong>abc</strong></p>');
|
||||
});
|
||||
|
||||
test('mceInsertContent - span in span same style color', function() {
|
||||
editor.getBody().innerHTML = '<span style="color:#ff0000">ac</strong>';
|
||||
Utils.setSelection('span', 1);
|
||||
editor.execCommand('mceInsertContent', false, {content: '<span style="color:#ff0000">b</span>', merge: true});
|
||||
equal(editor.getContent(), '<p><span style="color: #ff0000;">abc</span></p>');
|
||||
});
|
||||
|
||||
test('mceInsertContent - span in span different style color', function() {
|
||||
editor.getBody().innerHTML = '<span style="color:#ff0000">ac</strong>';
|
||||
Utils.setSelection('span', 1);
|
||||
editor.execCommand('mceInsertContent', false, {content: '<span style="color:#00ff00">b</span>', merge: true});
|
||||
equal(editor.getContent(), '<p><span style="color: #ff0000;">a<span style="color: #00ff00;">b</span>c</span></p>');
|
||||
});
|
||||
|
||||
test('InsertHorizontalRule', function() {
|
||||
var rng;
|
||||
|
||||
|
@ -720,4 +741,21 @@ test('RemoveFormat', function() {
|
|||
editor.execCommand('SelectAll');
|
||||
editor.execCommand('RemoveFormat');
|
||||
equal(editor.getContent(), '<p>dfn tag code tag samp tag kbd tag var tag cite tag mark tag q tag</p>');
|
||||
});
|
||||
});
|
||||
|
||||
test('InsertLineBreak', function() {
|
||||
editor.setContent('<p>123</p>');
|
||||
Utils.setSelection('p', 2);
|
||||
editor.execCommand('InsertLineBreak');
|
||||
equal(editor.getContent(), '<p>12<br />3</p>');
|
||||
|
||||
editor.setContent('<p>123</p>');
|
||||
Utils.setSelection('p', 0);
|
||||
editor.execCommand('InsertLineBreak');
|
||||
equal(editor.getContent(), '<p><br />123</p>');
|
||||
|
||||
editor.setContent('<p>123</p>');
|
||||
Utils.setSelection('p', 3);
|
||||
editor.execCommand('InsertLineBreak');
|
||||
equal(Utils.cleanHtml(editor.getBody().innerHTML), (tinymce.isIE && tinymce.Env.ie < 11) ? '<p>123<br></p>': '<p>123<br><br></p>');
|
||||
});
|
||||
|
|
|
@ -49,6 +49,32 @@ test('Re-init on same id', function() {
|
|||
strictEqual(tinymce.get().length, 1);
|
||||
});
|
||||
|
||||
asyncTest('Externally destroyed editor', function() {
|
||||
tinymce.remove();
|
||||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
init_instance_callback: function(editor1) {
|
||||
setTimeout(function() {
|
||||
// Destroy the editor by setting innerHTML common ajax pattern
|
||||
document.getElementById('view').innerHTML = '<textarea id="' + editor1.id + '"></textarea>';
|
||||
|
||||
// Re-init the editor will have the same id
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
init_instance_callback: function(editor2) {
|
||||
QUnit.start();
|
||||
|
||||
strictEqual(tinymce.get().length, 1);
|
||||
strictEqual(editor1.id, editor2.id);
|
||||
ok(editor1.destroyed, "First editor instance should be destroyed");
|
||||
}
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('Init/remove on same id', function() {
|
||||
var textArea = document.createElement('textarea');
|
||||
document.getElementById('view').appendChild(textArea);
|
||||
|
|
|
@ -10,7 +10,7 @@ module("tinymce.EnterKey", {
|
|||
skin: false,
|
||||
entities: 'raw',
|
||||
schema: 'html5',
|
||||
extended_valid_elements: 'div[id|style|contenteditable],span[id|style|contenteditable]',
|
||||
extended_valid_elements: 'div[id|style|contenteditable],span[id|style|contenteditable],#dt,#dd',
|
||||
valid_styles: {
|
||||
'*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display,position,top,left'
|
||||
},
|
||||
|
@ -552,7 +552,69 @@ test('Enter inside empty LI in end of OL in OL', function() {
|
|||
equal(editor.selection.getNode().nodeName, 'LI');
|
||||
});
|
||||
|
||||
test('Enter at beginning of first DT inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dt>a</dt></dl>';
|
||||
Utils.setSelection('dt', 0);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dt>\u00a0</dt><dt>a</dt></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DT');
|
||||
});
|
||||
|
||||
test('Enter at beginning of first DD inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dd>a</dd></dl>';
|
||||
Utils.setSelection('dd', 0);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dd>\u00a0</dd><dd>a</dd></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DD');
|
||||
});
|
||||
|
||||
test('Enter at beginning of middle DT inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dt>a</dt><dt>b</dt><dt>c</dt></dl>';
|
||||
Utils.setSelection('dt:nth-child(2)', 0);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dt>a</dt><dt>\u00a0</dt><dt>b</dt><dt>c</dt></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DT');
|
||||
});
|
||||
|
||||
test('Enter at beginning of middle DD inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dd>a</dd><dd>b</dd><dd>c</dd></dl>';
|
||||
Utils.setSelection('dd:nth-child(2)', 0);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dd>a</dd><dd>\u00a0</dd><dd>b</dd><dd>c</dd></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DD');
|
||||
});
|
||||
|
||||
test('Enter at end of last DT inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dt>a</dt></dl>';
|
||||
Utils.setSelection('dt', 1);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dt>a</dt><dt>\u00a0</dt></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DT');
|
||||
});
|
||||
|
||||
test('Enter at end of last DD inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dd>a</dd></dl>';
|
||||
Utils.setSelection('dd', 1);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dd>a</dd><dd>\u00a0</dd></dl>');
|
||||
equal(editor.selection.getNode().nodeName, 'DD');
|
||||
});
|
||||
|
||||
test('Enter at end of last empty DT inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dt>a</dt><dt></dt></dl>';
|
||||
Utils.setSelection('dt:nth-child(2)', 0);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dt>a</dt></dl><p>\u00a0</p>');
|
||||
equal(editor.selection.getNode().nodeName, 'P');
|
||||
});
|
||||
|
||||
test('Enter at end of last empty DD inside DL', function() {
|
||||
editor.getBody().innerHTML = '<dl><dd>a</dd><dd></dd></dl>';
|
||||
Utils.setSelection('dd:nth-child(2)', 0);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(),'<dl><dd>a</dd></dl><p>\u00a0</p>');
|
||||
equal(editor.selection.getNode().nodeName, 'P');
|
||||
});
|
||||
|
||||
test('Enter at beginning of P inside LI', function() {
|
||||
editor.getBody().innerHTML = '<ol><li><p>abcd</p></li></ol>';
|
||||
|
@ -928,6 +990,19 @@ test('Enter when forced_root_block: false and force_p_newlines: true', function(
|
|||
equal(editor.getContent(),'<p>te</p><p>xt</p>');
|
||||
});
|
||||
|
||||
test('Enter at end of br line', function() {
|
||||
editor.settings.forced_root_block = false;
|
||||
editor.settings.force_p_newlines = true;
|
||||
editor.getBody().innerHTML = '<p>a<br>b</p>';
|
||||
Utils.setSelection('p', 1);
|
||||
Utils.pressEnter();
|
||||
equal(editor.getContent(), '<p>a</p><p><br />b</p>');
|
||||
|
||||
var rng = editor.selection.getRng(true);
|
||||
equal(rng.startContainer.nodeName, 'P');
|
||||
equal(rng.startContainer.childNodes[rng.startOffset].nodeName, 'BR');
|
||||
});
|
||||
|
||||
// Ignore on IE 7, 8 this is a known bug not worth fixing
|
||||
if (!tinymce.Env.ie || tinymce.Env.ie > 8) {
|
||||
test('Enter before BR between DIVs', function() {
|
||||
|
|
|
@ -5,9 +5,7 @@ module("tinymce.Formatter - Apply", {
|
|||
|
||||
tinymce.init({
|
||||
selector: "#elm1",
|
||||
external_plugins: {
|
||||
noneditable: '../../../../tests/qunit/editor/external-plugins/noneditable/plugin.min.js'
|
||||
},
|
||||
external_plugins: { noneditable: '../../../../tests/qunit/editor/external-plugins/noneditable/plugin.min.js' }, // WP
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
indent: false,
|
||||
|
@ -1597,4 +1595,4 @@ test('Bug #6518 - Apply div blocks to inline editor paragraph', function() {
|
|||
});
|
||||
inlineEditor.formatter.apply('format');
|
||||
equal(inlineEditor.getContent(), '<div>a</div><p>b</p>');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,9 +5,7 @@ module("tinymce.Formatter - Remove", {
|
|||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
external_plugins: {
|
||||
noneditable: '../../../../tests/qunit/editor/external-plugins/noneditable/plugin.min.js'
|
||||
},
|
||||
external_plugins: { noneditable: '../../../../tests/qunit/editor/external-plugins/noneditable/plugin.min.js' }, // WP
|
||||
indent: false,
|
||||
add_unload_trigger: false,
|
||||
skin: false,
|
||||
|
@ -313,6 +311,16 @@ test('Caret format at end of text inside other format with text after 2', functi
|
|||
equal(editor.getContent(), '<p><em><b>abc</b></em><b>d</b>e</p>');
|
||||
});
|
||||
|
||||
test('Toggle styles at the end of the content don\' removes the format where it is not needed.', function() {
|
||||
editor.setContent('<p><em><b>abce</b></em></p>');
|
||||
editor.formatter.register('b', {inline: 'b'});
|
||||
editor.formatter.register('em', {inline: 'em'});
|
||||
Utils.setSelection('b', 4, 'b', 4);
|
||||
editor.formatter.remove('b');
|
||||
editor.formatter.remove('em');
|
||||
equal(editor.getContent(), '<p><em><b>abce</b></em></p>');
|
||||
});
|
||||
|
||||
test('Caret format on second word in table cell', function() {
|
||||
editor.setContent('<table><tbody><tr><td>one <b>two</b></td></tr></tbody></table>');
|
||||
editor.formatter.register('format', {inline: 'b'});
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
module("tinymce.Shortcuts", {
|
||||
setupModule: function() {
|
||||
QUnit.stop();
|
||||
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
add_unload_trigger: false,
|
||||
disable_nodechange: true,
|
||||
indent: false,
|
||||
skin: false,
|
||||
entities: 'raw',
|
||||
schema: 'html5',
|
||||
init_instance_callback: function(ed) {
|
||||
window.editor = ed;
|
||||
QUnit.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('Shortcuts formats', function() {
|
||||
function assertShortcut(shortcut, args) {
|
||||
var called;
|
||||
|
||||
editor.shortcuts.add(shortcut, '', function() {
|
||||
called = true;
|
||||
});
|
||||
|
||||
args = tinymce.extend({
|
||||
ctrlKey: false,
|
||||
altKey: false,
|
||||
shiftKey: false
|
||||
}, args);
|
||||
|
||||
if (tinymce.Env.mac && args.ctrlKey) {
|
||||
args.metaKey = true;
|
||||
args.ctrlKey = false;
|
||||
}
|
||||
|
||||
editor.fire('keydown', args);
|
||||
|
||||
ok(called, 'Shortcut wasn\'t called: ' + shortcut);
|
||||
}
|
||||
|
||||
assertShortcut('ctrl+d', {ctrlKey: true, keyCode: 68});
|
||||
assertShortcut('ctrl+shift+d', {ctrlKey: true, shiftKey: true, keyCode: 68});
|
||||
assertShortcut('ctrl+shift+alt+d', {ctrlKey: true, shiftKey: true, altKey: true, keyCode: 68});
|
||||
assertShortcut('ctrl+221', {ctrlKey: true, keyCode: 221});
|
||||
});
|
|
@ -241,15 +241,19 @@ test('Exclude internal elements', function() {
|
|||
editor.getBody().innerHTML = (
|
||||
'<span data-mce-bogus="1">\u200B</span>' +
|
||||
'<span data-mce-bogus="1">\uFEFF</span>' +
|
||||
'<div data-mce-bogus="1"></div>' +
|
||||
'<div data-mce-bogus="all"></div>' +
|
||||
'<div data-mce-bogus="all"><div><b>x</b></div></div>' +
|
||||
'<img src="about:blank" data-mce-bogus="all">' +
|
||||
'<br data-mce-bogus="1">' +
|
||||
'test' +
|
||||
'<img src="about:blank" />' +
|
||||
'<table><tr><td>x</td></tr></table>'
|
||||
);
|
||||
|
||||
editor.undoManager.add();
|
||||
equal(count, 1);
|
||||
equal(count, 2);
|
||||
equal(Utils.cleanHtml(lastLevel.content),
|
||||
'<br data-mce-bogus="1">' +
|
||||
'test' +
|
||||
'<img src="about:blank">' +
|
||||
'<table><tbody><tr><td>x</td></tr></tbody></table>'
|
||||
|
|
|
@ -169,9 +169,10 @@
|
|||
equal(e.innerHTML.toLowerCase(), 'content <b>abc</b>');
|
||||
});
|
||||
|
||||
test('createHTML', 4, function() {
|
||||
equal(DOM.createHTML('span', {'id' : 'id1', 'class' : 'abc 123'}, 'content <b>abc</b>'), '<span id="id1" class="abc 123">content <b>abc</b></span>');
|
||||
equal(DOM.createHTML('span', {'id' : 'id1', 'class' : 'abc 123'}), '<span id="id1" class="abc 123" />');
|
||||
test('createHTML', 5, function() {
|
||||
equal(DOM.createHTML('span', {'id': 'id1', 'class': 'abc 123'}, 'content <b>abc</b>'), '<span id="id1" class="abc 123">content <b>abc</b></span>');
|
||||
equal(DOM.createHTML('span', {'id': 'id1', 'class': 'abc 123'}), '<span id="id1" class="abc 123" />');
|
||||
equal(DOM.createHTML('span', {'id': null, 'class': undefined}), '<span />');
|
||||
equal(DOM.createHTML('span'), '<span />');
|
||||
equal(DOM.createHTML('span', null, 'content <b>abc</b>'), '<span>content <b>abc</b></span>');
|
||||
});
|
||||
|
@ -313,7 +314,7 @@
|
|||
DOM.remove('test');
|
||||
});
|
||||
|
||||
test('setGetStyles', 7, function() {
|
||||
test('setGetStyles', 9, function() {
|
||||
DOM.add(document.body, 'div', {id : 'test'});
|
||||
|
||||
DOM.setStyle('test', 'font-size', '20px');
|
||||
|
@ -332,6 +333,12 @@
|
|||
equal(DOM.getStyle('test3', 'fontSize'), '22px');
|
||||
equal(DOM.getStyle('test4', 'fontSize'), '22px');
|
||||
|
||||
DOM.setStyle('test', 'fontSize', 23);
|
||||
equal(DOM.getStyle('test', 'fontSize'), '23px', null, tinymce.isWebKit);
|
||||
|
||||
DOM.setStyle('test', 'fontSize', '24');
|
||||
equal(DOM.getStyle('test', 'fontSize'), '24px', null, tinymce.isWebKit);
|
||||
|
||||
DOM.setAttrib('test', 'style', '');
|
||||
|
||||
DOM.remove('test');
|
||||
|
|
|
@ -571,6 +571,45 @@ test('normalize to br from document', function() {
|
|||
|
||||
// Only run on non IE browsers since it's not an issue on IE
|
||||
if (!tinymce.isIE) {
|
||||
test('normalize with contentEditable:false element', function() {
|
||||
var rng;
|
||||
|
||||
editor.setContent('<p>a<b contentEditable="false">b</b>c</p>');
|
||||
rng = editor.dom.createRng();
|
||||
rng.setStart(editor.getBody().firstChild.lastChild, 0);
|
||||
rng.setEnd(editor.getBody().firstChild.lastChild, 0);
|
||||
editor.selection.setRng(rng);
|
||||
editor.selection.normalize();
|
||||
|
||||
rng = editor.selection.getRng(true);
|
||||
equal(rng.collapsed, true);
|
||||
equal(rng.startContainer.nodeType, 3);
|
||||
equal(rng.startContainer.data, 'c');
|
||||
});
|
||||
|
||||
test('normalize with contentEditable:false parent and contentEditable:true child element', function() {
|
||||
editor.setContent('<p contentEditable="false">a<em contentEditable="true">b</em></p>');
|
||||
Utils.setSelection('em', 0);
|
||||
editor.selection.normalize();
|
||||
|
||||
var rng = editor.selection.getRng(true);
|
||||
equal(rng.collapsed, true);
|
||||
equal(rng.startContainer.nodeType, 3);
|
||||
equal(rng.startContainer.data, 'b');
|
||||
});
|
||||
|
||||
test('normalize with contentEditable:true parent and contentEditable:false child element', function() {
|
||||
editor.setContent('<p contentEditable="true">a<em contentEditable="false">b</em></p>');
|
||||
Utils.setSelection('em', 0);
|
||||
editor.selection.normalize();
|
||||
|
||||
var rng = editor.selection.getRng(true);
|
||||
equal(rng.collapsed, true);
|
||||
equal(rng.startContainer.nodeType, 3);
|
||||
equal(rng.startContainer.data, 'a');
|
||||
equal(rng.startOffset, 1);
|
||||
});
|
||||
|
||||
test('normalize to text node from body', function() {
|
||||
var rng;
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ test('Script with type attrib and less than', 1, function() {
|
|||
ser.setRules('script[type|language|src]');
|
||||
|
||||
DOM.setHTML('test', '<s'+'cript type="text/javascript">1 < 2;</s'+'cript>');
|
||||
equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<script>// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
|
||||
equal(ser.serialize(DOM.get('test')).replace(/\r/g, ''), '<script type="text/javascript">// <![CDATA[\n1 < 2;\n// ]]></s'+'cript>');
|
||||
});
|
||||
|
||||
test('Script with whitespace in beginning/end', 1, function() {
|
||||
|
|
|
@ -162,6 +162,12 @@
|
|||
deepEqual(countNodes(root), {"body":1, "div":1, "section":1, "p":1, "#text":1}, 'P inside SECTION (count)');
|
||||
});
|
||||
|
||||
test('Remove empty nodes', function() {
|
||||
parser = new tinymce.html.DomParser({}, new tinymce.html.Schema({valid_elements: '-p,-span[id]'}));
|
||||
root = parser.parse('<p>a<span></span><span> </span><span id="x">b</span><span id="y"></span></p><p></p><p><span></span></p><p> </p>');
|
||||
equal(serializer.serialize(root), '<p>a <span id="x">b</span><span id="y"></span></p>');
|
||||
});
|
||||
|
||||
test('addNodeFilter', function() {
|
||||
var parser, result;
|
||||
|
||||
|
@ -479,5 +485,21 @@
|
|||
root = parser.parse('<p><span>1</span> <strong>2</strong></p>');
|
||||
equal(serializer.serialize(root), '<p>1 <strong>2</strong></p>');
|
||||
});
|
||||
|
||||
test('Valid classes', function() {
|
||||
var parser, root, schema = new tinymce.html.Schema({valid_classes: 'classA classB'});
|
||||
|
||||
parser = new tinymce.html.DomParser({}, schema);
|
||||
root = parser.parse('<p class="classA classB classC">a</p>');
|
||||
equal(serializer.serialize(root), '<p class="classA classB">a</p>');
|
||||
});
|
||||
|
||||
test('Valid classes multiple elements', function() {
|
||||
var parser, root, schema = new tinymce.html.Schema({valid_classes: {'*': 'classA classB', 'strong': 'classC'}});
|
||||
|
||||
parser = new tinymce.html.DomParser({}, schema);
|
||||
root = parser.parse('<p class="classA classB classC"><strong class="classA classB classC">a</strong></p>');
|
||||
equal(serializer.serialize(root), '<p class="classA classB"><strong class="classA classB">a</strong></p>');
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ module("tinymce.html.Entities");
|
|||
test('encodeRaw', function() {
|
||||
expect(2);
|
||||
|
||||
equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6'), '<>"\'&\u00e5\u00e4\u00f6', 'Raw encoding text');
|
||||
equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6', true), '<>"\'&\u00e5\u00e4\u00f6', 'Raw encoding attribute');
|
||||
equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6\u0060'), '<>"\'&\u00e5\u00e4\u00f6\u0060', 'Raw encoding text');
|
||||
equal(tinymce.html.Entities.encodeRaw('<>"\'&\u00e5\u00e4\u00f6\u0060', true), '<>"\'&\u00e5\u00e4\u00f6`', 'Raw encoding attribute');
|
||||
});
|
||||
|
||||
test('encodeAllRaw', function() {
|
||||
|
|
|
@ -609,9 +609,33 @@
|
|||
writer.reset();
|
||||
parser.parse(
|
||||
'<a href="javascript:alert(1)">1</a>' +
|
||||
'<a href=" 2 ">2</a>'
|
||||
'<a href=" 2 ">2</a>' +
|
||||
'<a href="data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">3</a>'
|
||||
);
|
||||
equal(
|
||||
writer.getContent(),
|
||||
'<a href="javascript:alert(1)">1</a><a href=" 2 ">2</a>' +
|
||||
'<a href="data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">3</a>'
|
||||
);
|
||||
});
|
||||
|
||||
test('Parse script urls (allowed html data uris)', function() {
|
||||
var counter, parser;
|
||||
|
||||
counter = createCounter(writer);
|
||||
counter.validate = false;
|
||||
counter.allow_html_data_urls = true;
|
||||
parser = new tinymce.html.SaxParser(counter, schema);
|
||||
writer.reset();
|
||||
parser.parse(
|
||||
'<a href="javascript:alert(1)">1</a>' +
|
||||
'<a href="data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">2</a>'
|
||||
);
|
||||
equal(
|
||||
writer.getContent(),
|
||||
'<a>1</a>' +
|
||||
'<a href="data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">2</a>'
|
||||
);
|
||||
equal(writer.getContent(), '<a href="javascript:alert(1)">1</a><a href=" 2 ">2</a>');
|
||||
});
|
||||
|
||||
test('Parse script urls (denied)', function() {
|
||||
|
@ -630,8 +654,61 @@
|
|||
'<a href="java\nscript:alert(5)">5</a>' +
|
||||
'<a href="java\tscript:alert(6)">6</a>' +
|
||||
'<a href="%6aavascript:alert(7)">7</a>' +
|
||||
'<a href="data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">8</a>' +
|
||||
'<a href=" dAt%61: tExt/html ; bAse64 , PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">9</a>' +
|
||||
'<object data="data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+">10</object>' +
|
||||
'<button formaction="javascript:alert(11)">11</button>' +
|
||||
'<table background="javascript:alert(12)"><tr><tr>12</tr></tr></table>' +
|
||||
'<a href="mhtml:13">13</a>' +
|
||||
'<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">' +
|
||||
'<a href="%E3%82%AA%E3%83%BC%E3%83">Invalid url</a>'
|
||||
);
|
||||
equal(writer.getContent(), '<a>1</a><a>2</a><a>3</a><a>4</a><a>5</a><a>6</a><a>7</a><a href="%E3%82%AA%E3%83%BC%E3%83">Invalid url</a>');
|
||||
|
||||
equal(
|
||||
writer.getContent(),
|
||||
'<a>1</a><a>2</a><a>3</a><a>4</a><a>5</a><a>6</a><a>7</a><a>8</a><a>9</a>' +
|
||||
'<object>10</object><button>11</button><table><tr></tr><tr>12</tr></table><a>13</a>' +
|
||||
'<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" />' +
|
||||
'<a href="%E3%82%AA%E3%83%BC%E3%83">Invalid url</a>'
|
||||
);
|
||||
});
|
||||
|
||||
test('Parse away bogus elements', function() {
|
||||
function testBogusSaxParse(inputHtml, outputHtml, counters) {
|
||||
var counter, parser;
|
||||
|
||||
counter = createCounter(writer);
|
||||
counter.validate = true;
|
||||
parser = new tinymce.html.SaxParser(counter, schema);
|
||||
writer.reset();
|
||||
parser.parse(inputHtml);
|
||||
equal(writer.getContent(), outputHtml);
|
||||
deepEqual(counter.counts, counters);
|
||||
}
|
||||
|
||||
testBogusSaxParse('a<b data-mce-bogus="1">b</b>c', 'abc', {text: 3});
|
||||
testBogusSaxParse('a<b data-mce-bogus="true">b</b>c', 'abc', {text: 3});
|
||||
testBogusSaxParse('a<b data-mce-bogus="1"></b>c', 'ac', {text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all">b</b>c', 'ac', {text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"><!-- x --><?xml?></b>c', 'ac', {text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"><b>b</b></b>c', 'ac', {text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"><br>b</b><b>c</b>', 'a<b>c</b>', {start: 1, end: 1, text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"><img>b</b><b>c</b>', 'a<b>c</b>', {start: 1, end: 1, text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"><b attr="x">b</b></b>c', 'ac', {text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"></b>c', 'ac', {text: 2});
|
||||
testBogusSaxParse('a<b data-mce-bogus="all"></b><b>c</b>', 'a<b>c</b>', {start: 1, end: 1, text:2});
|
||||
});
|
||||
|
||||
test('findEndTag', function() {
|
||||
function testFindEndTag(html, startIndex, expectedIndex) {
|
||||
equal(tinymce.html.SaxParser.findEndTag(schema, html, startIndex), expectedIndex);
|
||||
}
|
||||
|
||||
testFindEndTag('<b>', 3, 3);
|
||||
testFindEndTag('<img>', 3, 3);
|
||||
testFindEndTag('<b></b>', 3, 7);
|
||||
testFindEndTag('<b><img></b>', 3, 12);
|
||||
testFindEndTag('<b><!-- </b> --></b>', 3, 20);
|
||||
testFindEndTag('<span><b><i>a<img>b</i><b>c</b></b></span>', 9, 35);
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -256,6 +256,20 @@ test('getTextBlockElements', function() {
|
|||
});
|
||||
});
|
||||
|
||||
test('getTextInlineElements', function() {
|
||||
var schema;
|
||||
|
||||
expect(1);
|
||||
|
||||
schema = new tinymce.html.Schema();
|
||||
deepEqual(schema.getTextInlineElements(), {
|
||||
"B": {}, "CITE": {}, "CODE": {}, "DFN": {}, "EM": {}, "FONT": {}, "I": {}, "MARK": {}, "Q": {},
|
||||
"SAMP": {}, "SPAN": {}, "STRIKE": {}, "STRONG": {}, "SUB": {}, "SUP": {}, "U": {}, "VAR": {},
|
||||
"b": {}, "cite": {}, "code": {}, "dfn": {}, "em": {}, "font": {}, "i": {}, "mark": {}, "q": {},
|
||||
"samp": {}, "span": {}, "strike": {}, "strong": {}, "sub": {}, "sup": {}, "u": {}, "var": {}
|
||||
});
|
||||
});
|
||||
|
||||
test('isValidChild', function() {
|
||||
var schema;
|
||||
|
||||
|
@ -407,3 +421,116 @@ test('isValid', function() {
|
|||
ok(schema.isValid('i', 'id'));
|
||||
});
|
||||
|
||||
test('validStyles', function() {
|
||||
var schema;
|
||||
|
||||
schema = new tinymce.html.Schema({valid_styles: 'color,font-size'});
|
||||
deepEqual(schema.getValidStyles(), {
|
||||
"*": [
|
||||
"color",
|
||||
"font-size"
|
||||
]
|
||||
});
|
||||
|
||||
schema = new tinymce.html.Schema({valid_styles: 'color font-size'});
|
||||
deepEqual(schema.getValidStyles(), {
|
||||
"*": [
|
||||
"color",
|
||||
"font-size"
|
||||
]
|
||||
});
|
||||
|
||||
schema = new tinymce.html.Schema({
|
||||
valid_styles: {
|
||||
'*': 'color font-size',
|
||||
'a': 'background font-family'
|
||||
}
|
||||
});
|
||||
deepEqual(schema.getValidStyles(), {
|
||||
"*": [
|
||||
"color",
|
||||
"font-size"
|
||||
],
|
||||
|
||||
"a": [
|
||||
"background",
|
||||
"font-family"
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
test('invalidStyles', function() {
|
||||
var schema;
|
||||
|
||||
schema = new tinymce.html.Schema({invalid_styles: 'color,font-size'});
|
||||
deepEqual(schema.getInvalidStyles(), {
|
||||
'*': {
|
||||
'color': {},
|
||||
'font-size': {}
|
||||
}
|
||||
});
|
||||
|
||||
schema = new tinymce.html.Schema({invalid_styles: 'color font-size'});
|
||||
deepEqual(schema.getInvalidStyles(), {
|
||||
'*': {
|
||||
'color': {},
|
||||
'font-size': {}
|
||||
}
|
||||
});
|
||||
|
||||
schema = new tinymce.html.Schema({
|
||||
invalid_styles: {
|
||||
'*': 'color font-size',
|
||||
'a': 'background font-family'
|
||||
}
|
||||
});
|
||||
deepEqual(schema.getInvalidStyles(), {
|
||||
'*': {
|
||||
'color': {},
|
||||
'font-size': {}
|
||||
},
|
||||
|
||||
'a': {
|
||||
'background': {},
|
||||
'font-family': {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('validClasses', function() {
|
||||
var schema;
|
||||
|
||||
schema = new tinymce.html.Schema({valid_classes: 'classA,classB'});
|
||||
deepEqual(schema.getValidClasses(), {
|
||||
'*': {
|
||||
'classA': {},
|
||||
'classB': {}
|
||||
}
|
||||
});
|
||||
|
||||
schema = new tinymce.html.Schema({valid_classes: 'classA classB'});
|
||||
deepEqual(schema.getValidClasses(), {
|
||||
'*': {
|
||||
'classA': {},
|
||||
'classB': {}
|
||||
}
|
||||
});
|
||||
|
||||
schema = new tinymce.html.Schema({
|
||||
valid_classes: {
|
||||
'*': 'classA classB',
|
||||
'a': 'classC classD'
|
||||
}
|
||||
});
|
||||
deepEqual(schema.getValidClasses(), {
|
||||
'*': {
|
||||
'classA': {},
|
||||
'classB': {}
|
||||
},
|
||||
|
||||
'a': {
|
||||
'classC': {},
|
||||
'classD': {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -122,7 +122,7 @@ test('Font weight', function() {
|
|||
});
|
||||
|
||||
test('Valid styles', function() {
|
||||
var styles = new tinymce.html.Styles({}, new tinymce.html.Schema({valid_styles : {'*' : 'color,font-size', 'a' : 'margin-left'}}));
|
||||
var styles = new tinymce.html.Styles({}, new tinymce.html.Schema({valid_styles : {'*': 'color,font-size', 'a': 'margin-left'}}));
|
||||
|
||||
expect(2);
|
||||
|
||||
|
@ -130,16 +130,27 @@ test('Valid styles', function() {
|
|||
equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px; invalid: 2;'), 'a'), "color: #ff0000; font-size: 10px; margin-left: 10px;");
|
||||
});
|
||||
|
||||
test('Invalid styles', function() {
|
||||
var styles = new tinymce.html.Styles({}, new tinymce.html.Schema({invalid_styles : {'*': 'color,font-size', 'a': 'margin-left'}}));
|
||||
|
||||
equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px'), 'b'), "margin-left: 10px;");
|
||||
equal(styles.serialize(styles.parse('color: #ff0000; font-size: 10px; margin-left: 10px; margin-right: 10px;'), 'a'), "margin-right: 10px;");
|
||||
});
|
||||
|
||||
test('Script urls denied', function() {
|
||||
var styles = new tinymce.html.Styles();
|
||||
|
||||
equal(styles.serialize(styles.parse('behavior:url(test.htc)')), "");
|
||||
equal(styles.serialize(styles.parse('color:expression(alert(1))')), "");
|
||||
equal(styles.serialize(styles.parse('color:\\65xpression(alert(1))')), "");
|
||||
equal(styles.serialize(styles.parse('color:exp/**/ression(alert(1))')), "");
|
||||
equal(styles.serialize(styles.parse('color:/**/')), "");
|
||||
equal(styles.serialize(styles.parse('color: expression ( alert(1))')), "");
|
||||
equal(styles.serialize(styles.parse('background:url(jAvaScript:alert(1)')), "");
|
||||
equal(styles.serialize(styles.parse('background:url(javascript:alert(1)')), "");
|
||||
equal(styles.serialize(styles.parse('background:url(vbscript:alert(1)')), "");
|
||||
equal(styles.serialize(styles.parse('background:url(j\navas\u0000cr\tipt:alert(1)')), "");
|
||||
equal(styles.serialize(styles.parse('background:url(data:image/svg+xml,%3Csvg/%3E)')), "");
|
||||
});
|
||||
|
||||
test('Script urls allowed', function() {
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
module("tinymce.util.EventDispatcher");
|
||||
|
||||
test("fire (no event listeners)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), args;
|
||||
|
||||
args = dispatcher.fire('click', {test: 1});
|
||||
equal(args.test, 1);
|
||||
equal(args.isDefaultPrevented(), false);
|
||||
equal(args.isPropagationStopped(), false);
|
||||
equal(args.isImmediatePropagationStopped(), false);
|
||||
strictEqual(args.target, dispatcher);
|
||||
|
||||
args = dispatcher.fire('click');
|
||||
equal(args.isDefaultPrevented(), false);
|
||||
equal(args.isPropagationStopped(), false);
|
||||
equal(args.isImmediatePropagationStopped(), false);
|
||||
});
|
||||
|
||||
test("fire (event listeners)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
dispatcher.on('click', function() {data += 'a';});
|
||||
dispatcher.on('click', function() {data += 'b';});
|
||||
|
||||
args = dispatcher.fire('click', {test: 1});
|
||||
equal(data, 'ab');
|
||||
});
|
||||
|
||||
test("fire (event listeners) stopImmediatePropagation", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
dispatcher.on('click', function(e) { data += 'a'; e.stopImmediatePropagation(); });
|
||||
dispatcher.on('click', function() { data += 'b'; });
|
||||
|
||||
dispatcher.fire('click', {test: 1});
|
||||
equal(data, 'a');
|
||||
});
|
||||
|
||||
test("on", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
strictEqual(dispatcher.on('click', function() {data += 'a';}), dispatcher);
|
||||
strictEqual(dispatcher.on('click keydown', function() {data += 'b';}), dispatcher);
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'ab');
|
||||
|
||||
dispatcher.fire('keydown');
|
||||
equal(data, 'abb');
|
||||
});
|
||||
|
||||
test("on (prepend)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
strictEqual(dispatcher.on('click', function() {data += 'a';}), dispatcher);
|
||||
strictEqual(dispatcher.on('click', function() {data += 'b';}, true), dispatcher);
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'ba');
|
||||
});
|
||||
|
||||
test("once", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
strictEqual(dispatcher.on('click', function() {data += 'a';}), dispatcher);
|
||||
strictEqual(dispatcher.once('click', function() {data += 'b';}), dispatcher);
|
||||
strictEqual(dispatcher.on('click', function() {data += 'c';}), dispatcher);
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'abc');
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'abcac');
|
||||
});
|
||||
|
||||
test("once (prepend)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
strictEqual(dispatcher.on('click', function() {data += 'a';}), dispatcher);
|
||||
strictEqual(dispatcher.once('click', function() {data += 'b';}, true), dispatcher);
|
||||
strictEqual(dispatcher.on('click', function() {data += 'c';}), dispatcher);
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'bac');
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'bacac');
|
||||
});
|
||||
|
||||
test("once (unbind)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
function handler() {
|
||||
data += 'b';
|
||||
}
|
||||
|
||||
dispatcher.once('click', function() {data += 'a';});
|
||||
dispatcher.once('click', handler);
|
||||
dispatcher.off('click', handler);
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'a');
|
||||
});
|
||||
|
||||
test("once (multiple events)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
dispatcher.once('click', function() {data += 'a';});
|
||||
dispatcher.once('keydown', function() {data += 'b';});
|
||||
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'a');
|
||||
|
||||
dispatcher.fire('keydown');
|
||||
equal(data, 'ab');
|
||||
|
||||
dispatcher.fire('click');
|
||||
dispatcher.fire('keydown');
|
||||
|
||||
equal(data, 'ab');
|
||||
});
|
||||
|
||||
test("off (all)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
function listenerA() { data += 'a'; }
|
||||
function listenerB() { data += 'b'; }
|
||||
function listenerC() { data += 'c'; }
|
||||
|
||||
dispatcher.on('click', listenerA);
|
||||
dispatcher.on('click', listenerB);
|
||||
dispatcher.on('keydown', listenerC);
|
||||
|
||||
dispatcher.off();
|
||||
|
||||
data = '';
|
||||
dispatcher.fire('click');
|
||||
dispatcher.fire('keydown');
|
||||
equal(data, '');
|
||||
});
|
||||
|
||||
test("off (all named)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
function listenerA() { data += 'a'; }
|
||||
function listenerB() { data += 'b'; }
|
||||
function listenerC() { data += 'c'; }
|
||||
|
||||
dispatcher.on('click', listenerA);
|
||||
dispatcher.on('click', listenerB);
|
||||
dispatcher.on('keydown', listenerC);
|
||||
|
||||
dispatcher.off('click');
|
||||
|
||||
data = '';
|
||||
dispatcher.fire('click');
|
||||
dispatcher.fire('keydown');
|
||||
equal(data, 'c');
|
||||
});
|
||||
|
||||
test("off (all specific observer)", function() {
|
||||
var dispatcher = new tinymce.util.EventDispatcher(), data = '';
|
||||
|
||||
function listenerA() { data += 'a'; }
|
||||
function listenerB() { data += 'b'; }
|
||||
|
||||
dispatcher.on('click', listenerA);
|
||||
dispatcher.on('click', listenerB);
|
||||
dispatcher.off('click', listenerB);
|
||||
|
||||
data = '';
|
||||
dispatcher.fire('click');
|
||||
equal(data, 'a');
|
||||
});
|
||||
|
||||
test("scope setting", function() {
|
||||
var lastScope, lastEvent, dispatcher;
|
||||
|
||||
dispatcher = new tinymce.util.EventDispatcher();
|
||||
dispatcher.on('click', function() {
|
||||
lastScope = this;
|
||||
}).fire('click');
|
||||
strictEqual(dispatcher, lastScope);
|
||||
|
||||
var scope = {test: 1};
|
||||
dispatcher = new tinymce.util.EventDispatcher({scope: scope});
|
||||
dispatcher.on('click', function(e) {
|
||||
lastScope = this;
|
||||
lastEvent = e;
|
||||
}).fire('click');
|
||||
strictEqual(scope, lastScope);
|
||||
strictEqual(lastEvent.target, lastScope);
|
||||
});
|
||||
|
||||
test("beforeFire setting", function() {
|
||||
var lastArgs, dispatcher, args;
|
||||
|
||||
dispatcher = new tinymce.util.EventDispatcher({
|
||||
beforeFire: function(args) {
|
||||
lastArgs = args;
|
||||
}
|
||||
});
|
||||
|
||||
args = dispatcher.fire('click');
|
||||
strictEqual(lastArgs, args);
|
||||
});
|
||||
|
||||
test("beforeFire setting (stopImmediatePropagation)", function() {
|
||||
var lastArgs, dispatcher, args, data = '';
|
||||
|
||||
dispatcher = new tinymce.util.EventDispatcher({
|
||||
beforeFire: function(args) {
|
||||
lastArgs = args;
|
||||
args.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
|
||||
function listenerA() { data += 'a'; }
|
||||
|
||||
dispatcher.on('click', listenerA);
|
||||
args = dispatcher.fire('click');
|
||||
strictEqual(lastArgs, args);
|
||||
strictEqual(data, '');
|
||||
});
|
||||
|
||||
test("toggleEvent setting", function() {
|
||||
var lastName, lastState;
|
||||
|
||||
dispatcher = new tinymce.util.EventDispatcher({
|
||||
toggleEvent: function(name, state) {
|
||||
lastName = name;
|
||||
lastState = state;
|
||||
}
|
||||
});
|
||||
|
||||
function listenerA() { data += 'a'; }
|
||||
function listenerB() { data += 'b'; }
|
||||
|
||||
dispatcher.on('click', listenerA);
|
||||
strictEqual(lastName, 'click');
|
||||
strictEqual(lastState, true);
|
||||
|
||||
lastName = lastState = null;
|
||||
dispatcher.on('click', listenerB);
|
||||
strictEqual(lastName, null);
|
||||
strictEqual(lastState, null);
|
||||
|
||||
dispatcher.off('click', listenerA);
|
||||
strictEqual(lastName, null);
|
||||
strictEqual(lastState, null);
|
||||
|
||||
dispatcher.off('click', listenerB);
|
||||
strictEqual(lastName, 'click');
|
||||
strictEqual(lastState, false);
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
module("tinymce.util.Observable");
|
||||
|
||||
test("Event bubbling/removed state", function() {
|
||||
var lastName, lastState, data = '';
|
||||
|
||||
function Class(parentObj) {
|
||||
this.toggleNativeEvent = function(name, state) {
|
||||
lastName = name;
|
||||
lastState = state;
|
||||
};
|
||||
|
||||
this.parent = function() {
|
||||
return parentObj;
|
||||
};
|
||||
}
|
||||
|
||||
tinymce.util.Tools.extend(Class.prototype, tinymce.util.Observable);
|
||||
|
||||
var inst1 = new Class();
|
||||
|
||||
inst1.on('click', function() { data += 'a'; });
|
||||
strictEqual(lastName, 'click');
|
||||
strictEqual(lastState, true);
|
||||
|
||||
lastName = lastState = null;
|
||||
inst1.on('click', function() { data += 'b'; });
|
||||
strictEqual(lastName, null);
|
||||
strictEqual(lastState, null);
|
||||
|
||||
var inst2 = new Class(inst1);
|
||||
inst2.on('click', function() { data += 'c'; });
|
||||
|
||||
inst2.fire('click');
|
||||
strictEqual(data, 'cab');
|
||||
|
||||
inst2.on('click', function(e) { e.stopPropagation(); });
|
||||
|
||||
inst2.fire('click');
|
||||
strictEqual(data, 'cabc');
|
||||
|
||||
inst1.on('remove', function() { data += 'r'; });
|
||||
inst1.removed = true;
|
||||
inst1.fire('click');
|
||||
inst1.fire('remove');
|
||||
strictEqual(data, 'cabcr');
|
||||
});
|
|
@ -22,7 +22,7 @@ test('parseFullURLs', 3, function() {
|
|||
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() {
|
||||
test('relativeURLs', 31, 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');
|
||||
|
@ -52,9 +52,12 @@ test('relativeURLs', 29, function() {
|
|||
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/');
|
||||
equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('/file.htm?q=http://site.com/'), '../../file.htm?q=http://site.com/');
|
||||
equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toRelative('/file.htm#http://site.com/'), '../../file.htm#http://site.com/');
|
||||
});
|
||||
|
||||
test('absoluteURLs', 18, function() {
|
||||
test('absoluteURLs', 19, function() {
|
||||
equal(new tinymce.util.URI('http://www.site.com/dir1/dir2/').toAbsolute(''), 'http://www.site.com/dir1/dir2/');
|
||||
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');
|
||||
|
@ -83,3 +86,19 @@ test('strangeURLs', 6, function() {
|
|||
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');
|
||||
});
|
||||
|
||||
test('isSameOrigin', function() {
|
||||
ok(new tinymce.util.URI('http://www.site.com').isSameOrigin(new tinymce.util.URI('http://www.site.com')));
|
||||
ok(new tinymce.util.URI('//www.site.com').isSameOrigin(new tinymce.util.URI('//www.site.com')));
|
||||
ok(new tinymce.util.URI('http://www.site.com:80').isSameOrigin(new tinymce.util.URI('http://www.site.com')));
|
||||
ok(new tinymce.util.URI('https://www.site.com:443').isSameOrigin(new tinymce.util.URI('https://www.site.com')));
|
||||
ok(new tinymce.util.URI('//www.site.com:80').isSameOrigin(new tinymce.util.URI('//www.site.com:80')));
|
||||
ok(new tinymce.util.URI('mailto:test@site.com').isSameOrigin(new tinymce.util.URI('mailto:test@site.com')));
|
||||
ok(new tinymce.util.URI('mailto:test@site.com:25').isSameOrigin(new tinymce.util.URI('mailto:test@site.com')));
|
||||
ok(new tinymce.util.URI('ftp://www.site.com').isSameOrigin(new tinymce.util.URI('ftp://www.site.com')));
|
||||
ok(new tinymce.util.URI('ftp://www.site.com:21').isSameOrigin(new tinymce.util.URI('ftp://www.site.com')));
|
||||
ok(new tinymce.util.URI('https://www.site.com').isSameOrigin(new tinymce.util.URI('http://www.site.com')) == false);
|
||||
ok(new tinymce.util.URI('http://www.site.com:8080').isSameOrigin(new tinymce.util.URI('http://www.site.com')) == false);
|
||||
ok(new tinymce.util.URI('https://www.site.com:8080').isSameOrigin(new tinymce.util.URI('https://www.site.com')) == false);
|
||||
ok(new tinymce.util.URI('ftp://www.site.com:1021').isSameOrigin(new tinymce.util.URI('ftp://www.site.com')) == false);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue