@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
13,172 lines • 487 kB
JavaScript
Object.defineProperties(exports, {
__esModule: { value: true },
[Symbol.toStringTag]: { value: "Module" }
});
const require_kendo_core = require("./kendo.core-kmRaf_Lg.js");
require("./kendo.html.icon.js");
require("./kendo.icons.js");
require("./kendo.html.button.js");
require("./kendo.html.input.js");
require("./kendo.draganddrop.js");
require("./kendo.dropdownlist.js");
require("./kendo.numerictextbox.js");
require("./kendo.combobox.js");
require("./kendo.form.js");
require("./kendo.window.js");
require("./kendo.resizable.js");
require("./kendo.buttongroup.js");
require("./kendo.toolbar.js");
require("./kendo.textarea.js");
require("./kendo.colorpicker.js");
require("./kendo.tabstrip.js");
require("./kendo.aiprompt-B8fknJle.js");
require("./kendo.filebrowser.js");
require("./kendo.imagebrowser.js");
require("./kendo.splitter.js");
require("./kendo.inlineaiprompt-eBy_sfFC.js");
//#region ../src/util/undoredostack.js
(function(kendo) {
var UndoRedoStack = kendo.Observable.extend({
init: function(options) {
kendo.Observable.fn.init.call(this, options);
this.clear();
},
events: ["undo", "redo"],
push: function(command) {
this.stack = this.stack.slice(0, this.currentCommandIndex + 1);
this.currentCommandIndex = this.stack.push(command) - 1;
},
undo: function() {
if (this.canUndo()) {
var command = this.stack[this.currentCommandIndex--];
command.undo();
this.trigger("undo", { command });
}
},
redo: function() {
if (this.canRedo()) {
var command = this.stack[++this.currentCommandIndex];
command.redo();
this.trigger("redo", { command });
}
},
clear: function() {
this.stack = [];
this.currentCommandIndex = -1;
},
canUndo: function() {
return this.currentCommandIndex >= 0;
},
canRedo: function() {
return this.currentCommandIndex != this.stack.length - 1;
}
});
kendo.deepExtend(kendo, { util: { UndoRedoStack } });
})(kendo);
//#endregion
//#region ../src/editor/main.js
(function($, undefined) {
var kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, os = kendo.support.mobileOS, browser = kendo.support.browser, extend = $.extend, deepExtend = kendo.deepExtend, keys = kendo.keys, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, NS = ".kendoEditor";
var SELECT = "select";
var SELECT_OVERLAY_SELECTOR = "select.k-select-overlay";
var PLACEHOLDER_CLASS = "k-placeholder";
var PLACEHOLDER_TAG_ID = "placeholder";
var REFRESH_INTERVAL = 200;
var DEFAULT_LANGUAGE = "en";
var NATIVE_TOOLS = [
"insertLineBreak",
"insertParagraph",
"redo",
"undo",
"autoLink"
];
const UNDO_REDO_REGEX = /^(undo|redo)$/i;
const TOOLBAR_ALLOWED_CLOSE_SELECTORS = ".k-icon,.k-svg-icon,svg,path,.k-editor-window,.k-editor-toolbar,.k-editortoolbar-dragHandle,[ref-toolbar-tool],[ref-toolbar-tool] *";
var EditorUtils = {
editorWrapperTemplate: () => "<div class=\"k-editor\"><div class=\"k-editor-toolbar\" role=\"toolbar\"></div><div class=\"k-editable-area k-editor-content\"></div></div>",
formatByName: function(name, format) {
for (var i = 0; i < format.length; i++) if ($.inArray(name, format[i].tags) >= 0) return format[i];
},
getToolCssClass: function(name, icon) {
var cssClass = {
superscript: "superscript",
subscript: "subscript",
justifyLeft: "align-left",
justifyCenter: "align-center",
justifyRight: "align-right",
justifyFull: "align-justify",
insertUnorderedList: "list-unordered",
insertOrderedList: "list-ordered",
insertUpperRomanList: "list-roman-upper",
insertLowerRomanList: "list-roman-lower",
"import": "import",
indent: "indent",
outdent: "outdent",
createLink: "link",
unlink: "unlink",
insertImage: "image",
insertFile: "file-add",
viewHtml: "code",
foreColor: "foreground-color",
backColor: "droplet",
createTable: "table-add",
addColumnLeft: "table-column-insert-left",
addColumnRight: "table-column-insert-right",
addRowAbove: "table-row-insert-above",
addRowBelow: "table-row-insert-below",
deleteRow: "table-row-delete",
deleteColumn: "table-column-delete",
mergeCellsHorizontally: "cells-merge-horizontally",
mergeCellsVertically: "cells-merge-vertically",
splitCellHorizontally: "cell-split-horizontally",
splitCellVertically: "cell-split-vertically",
tableProperties: "table-properties",
tableCellProperties: "table-cell-properties",
tableWizardInsert: "table-wizard",
tableAlignLeft: "table-position-start",
tableAlignCenter: "table-position-center",
tableAlignRight: "table-position-end",
cleanFormatting: "clear-css",
copyFormat: "copy-format",
applyFormat: "apply-format",
pdf: "file-pdf"
}[name];
if (cssClass) return cssClass;
if (icon) return icon;
return EditorUtils.nameToKebab(name);
},
nameToKebab: function(name) {
return name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
},
registerTool: function(toolName, tool) {
if (!tool.name) {
tool.options.name = toolName;
tool.name = toolName.toLowerCase();
}
if (!tool.options.ui) tool.options.ui = {};
tool.options.ui.command = toolName;
Editor.defaultTools[toolName] = tool;
},
registerFormat: function(formatName, format) {
Editor.fn.options.formats[formatName] = format;
},
cacheComments: function(content, comments) {
for (var index in comments) content = content.replace(comments[index], "{" + index + "}");
return content;
},
retrieveComments: function(content, comments) {
for (var index in comments) content = content.replace("{" + index + "}", comments[index]);
return content;
}
};
var messages = {
auto: "Auto",
bold: "Bold",
italic: "Italic",
underline: "Underline",
strikethrough: "Strikethrough",
superscript: "Superscript",
subscript: "Subscript",
fitToCell: "Fit to cell",
justifyCenter: "Center text",
justifyLeft: "Align text left",
justifyRight: "Align text right",
justifyFull: "Justify",
insertUnorderedList: "Insert unordered list",
insertOrderedList: "Insert ordered list",
lineHeight: "Set line height",
formattingMarks: "Toggle formatting marks",
indent: "Indent",
outdent: "Outdent",
createLink: "Insert hyperlink",
unlink: "Remove hyperlink",
insertImage: "Insert image",
insertFile: "Insert file",
insertHtml: "Insert HTML",
viewHtml: "View HTML",
fontName: "Select font family",
fontNameInherit: "(inherited font)",
fontSize: "Select font size",
fontSizeInherit: "(inherited size)",
formatBlock: "Format",
formatting: "Format",
foreColor: "Color",
backColor: "Background color",
style: "Styles",
emptyFolder: "Empty Folder",
editAreaTitle: "Editable area. Press F10 for toolbar.",
uploadFile: "Upload",
overflowAnchor: "More tools",
orderBy: "Arrange by:",
orderBySize: "Size",
orderByName: "Name",
invalidFileType: "The selected file {0} is not valid. Supported file types are {1}.",
deleteFile: "Are you sure you want to delete {0}?",
overwriteFile: "A file with name {0} already exists in the current directory. Do you want to overwrite it?",
directoryNotFound: "A directory with this name was not found.",
imageWebAddress: "Web address",
imageAltText: "Alternate text",
imageWidth: "Width (px)",
imageHeight: "Height (px)",
fileWebAddress: "Web address",
fileTitle: "Title",
fileText: "Text",
linkWebAddress: "Web address",
linkText: "Text",
linkToolTip: "ToolTip",
linkOpenInNewWindow: "Open link in new window",
dialogUpdate: "Update",
dialogInsert: "Insert",
dialogOk: "Confirm",
dialogCancel: "Cancel",
cleanFormatting: "Clean formatting",
createTable: "Create a table",
createTableHint: "Create a {0} x {1} table",
addColumnLeft: "Add column on the left",
addColumnRight: "Add column on the right",
addRowAbove: "Add row above",
addRowBelow: "Add row below",
deleteRow: "Delete row",
deleteColumn: "Delete column",
mergeCellsHorizontally: "Merge cells horizontally",
mergeCellsVertically: "Merge cells vertically",
splitCellHorizontally: "Split cells horizontally",
splitCellVertically: "Split cells vertically",
tableAlignLeft: "Table Align Left",
tableAlignCenter: "Table Align Center",
tableAlignRight: "Table Align Right",
tableWizard: "Table Wizard",
tableProperties: "Table Properties",
tableCellProperties: "Cell Properties",
tableTab: "General",
cellTab: "Cell",
accessibilityTab: "Advanced",
caption: "Caption",
summary: "Summary",
width: "Width",
height: "Height",
units: "Units",
cellSpacing: "Cell Spacing",
cellPadding: "Cell Padding",
topPadding: "Top",
leftPadding: "Left",
bottomPadding: "Bottom",
rightPadding: "Right",
independentCellPaddings: "Independent Cell Paddings",
cellMargin: "Cell Margin",
alignment: "Alignment",
captionAlignment: "Caption alignment",
position: "Position",
background: "Background",
tableBackground: "Table background",
cssClass: "CSS Class",
id: "ID",
border: "Border",
borderStyle: "Border Style",
borderWidth: "Border Width",
borderColor: "Border Color",
collapseBorders: "Collapse borders",
wrapText: "Wrap text",
associateCellsWithHeaders: "Associate headers",
alignLeft: "Align Left",
alignCenter: "Align Center",
alignRight: "Align Right",
alignLeftTop: "Align Left Top",
alignCenterTop: "Align Center Top",
alignRightTop: "Align Right Top",
alignLeftMiddle: "Align Left Middle",
alignCenterMiddle: "Align Center Middle",
alignRightMiddle: "Align Right Middle",
alignLeftBottom: "Align Left Bottom",
alignCenterBottom: "Align Center Bottom",
alignRightBottom: "Align Right Bottom",
alignRemove: "Remove Alignment",
columns: "Columns",
rows: "Rows",
selectAllCells: "Apply to all cells",
applyToColumn: "apply to column",
applyToRow: "apply to row",
exportAs: "Export As",
"import": "Import",
print: "Print",
headerRows: "Header Rows",
headerColumns: "Header Cols",
tableSummaryPlaceholder: "Summary attribute is not HTML5 compatible.",
associateNone: "None",
associateScope: "Associate using 'scope' attribute",
associateIds: "Associate using Ids",
copyFormat: "Copy format",
applyFormat: "Apply format",
borderNone: "None",
undo: "Undo",
redo: "Redo"
};
var supportedContentEditable = typeof document.documentElement.contentEditable != "undefined";
var toolGroups = {
basic: [
"bold",
"italic",
"underline",
"strikethrough"
],
undo: ["undo", "redo"],
scripts: ["subscript", "superscript"],
alignment: [
"justifyLeft",
"justifyCenter",
"justifyRight",
"justifyFull"
],
lines: ["lineHeight"],
symbols: ["formattingMarks"],
links: [
"insertImage",
"insertFile",
"createLink",
"unlink"
],
lists: [
"insertUnorderedList",
"insertOrderedList",
"insertUpperRomanList",
"insertLowerRomanList"
],
dent: ["indent", "outdent"],
tablesWizard: ["tableProperties", "tableCellProperties"],
tablesInsert: ["createTable"],
tablesAddDelete: [
"addColumnLeft",
"addColumnRight",
"addRowAbove",
"addRowBelow",
"deleteRow",
"deleteColumn"
],
tablesMerge: [
"mergeCellsHorizontally",
"mergeCellsVertically",
"splitCellHorizontally",
"splitCellVertically"
],
tablesPosition: [
"tableAlignLeft",
"tableAlignCenter",
"tableAlignRight"
],
formatPainter: ["copyFormat", "applyFormat"]
};
var Editor = Widget.extend({
__suppressEditableCheck: false,
init: function(element, options) {
var that = this, editorNS = kendo.ui.editor, dom = editorNS.Dom, toolbarContainer, type, domElement;
if (!supportedContentEditable && !that.__suppressEditableCheck) return;
Widget.fn.init.call(that, element, options);
that.options = deepExtend({}, that.options, options);
element = that.element;
domElement = element[0];
type = dom.name(domElement);
this._registerHandler(element.closest("form"), "submit", that.update.bind(that, undefined));
if (that._isAiPromptEnabled()) that._addAIPromptElements();
toolbarContainer = that._setupType(element);
that._initToolbar(toolbarContainer);
that._setupHeight(type);
that._resizable();
that._initializeContentElement(that);
that._setupKeyboard();
that.clipboard = new editorNS.Clipboard(this);
that.undoRedoStack = new kendo.util.UndoRedoStack();
that._populateValue(options, domElement);
that._registerHandler(document, {
"mousedown": function() {
that._endTyping();
},
"mouseup": function(e) {
that._mouseup(e);
}
});
that._registerHandler(window, "resize", that._handleSpaceAndNewLines.bind(that));
that._initializeImmutables();
if (type == "textarea") that._ariaLabel(that.wrapper.find("iframe"));
that.toolbar.resize();
that._initInlineOverflowWrapper();
kendo.notify(that);
if (that._showWatermarkOverlay) that._showWatermarkOverlay(that.wrapper && that.wrapper[0] || that.element[0]);
if (that._isAiPromptEnabled()) that._initAIPrompt();
if (that._isInlineAIPromptEnabled()) that._initInlineAIPrompt();
Widget.fn.endInit.call(this);
},
events: [
"select",
"change",
"execute",
"error",
"paste",
"keydown",
"keyup"
],
options: {
name: "Editor",
messages,
placeholder: "",
nonce: "",
unsafeInline: true,
formats: {},
encoded: true,
formattingMarksRefreshDelay: 250,
domain: null,
resizable: false,
deserialization: { custom: null },
serialization: {
entities: true,
semantic: true,
scripts: false,
optimizeTags: false,
keepEOL: false
},
pasteCleanup: {
all: false,
css: false,
custom: null,
keepNewLines: false,
msAllFormatting: false,
msConvertLists: true,
msTags: true,
none: false,
span: false
},
stylesheets: [],
dialogOptions: {
modal: true,
resizable: false,
draggable: true,
animation: false
},
imageBrowser: null,
fileBrowser: null,
navigateOnTab: false,
fontName: [
{
text: "Arial",
value: "Arial, Helvetica, sans-serif"
},
{
text: "Courier New",
value: "\"Courier New\", Courier, monospace"
},
{
text: "Georgia",
value: "Georgia, serif"
},
{
text: "Impact",
value: "Impact, Charcoal, sans-serif"
},
{
text: "Lucida Console",
value: "\"Lucida Console\", Monaco, monospace"
},
{
text: "Tahoma",
value: "Tahoma, Geneva, sans-serif"
},
{
text: "Times New Roman",
value: "\"Times New Roman\", Times, serif"
},
{
text: "Trebuchet MS",
value: "\"Trebuchet MS\", Helvetica, sans-serif"
},
{
text: "Verdana",
value: "Verdana, Geneva, sans-serif"
}
],
fontSize: [
{
text: "1 (8pt)",
value: "xx-small"
},
{
text: "2 (10pt)",
value: "x-small"
},
{
text: "3 (12pt)",
value: "small"
},
{
text: "4 (14pt)",
value: "medium"
},
{
text: "5 (18pt)",
value: "large"
},
{
text: "6 (24pt)",
value: "x-large"
},
{
text: "7 (36pt)",
value: "xx-large"
}
],
formatBlock: [
{
text: "Paragraph",
value: "p"
},
{
text: "Quotation",
value: "blockquote"
},
{
text: "Heading 1",
value: "h1"
},
{
text: "Heading 2",
value: "h2"
},
{
text: "Heading 3",
value: "h3"
},
{
text: "Heading 4",
value: "h4"
},
{
text: "Heading 5",
value: "h5"
},
{
text: "Heading 6",
value: "h6"
}
],
tools: [
"formatting",
"bold",
"italic",
"underline",
"undo",
"redo",
"justifyLeft",
"justifyCenter",
"justifyRight",
"copyFormat",
"applyFormat",
"insertUnorderedList",
"insertOrderedList",
"indent",
"outdent",
"createLink",
"unlink",
"insertImage",
"tableProperties",
"tableCellProperties",
"createTable",
"addRowAbove",
"addRowBelow",
"addColumnLeft",
"addColumnRight",
"deleteRow",
"deleteColumn",
"mergeCellsHorizontally",
"mergeCellsVertically",
"splitCellHorizontally",
"splitCellVertically",
"tableAlignLeft",
"tableAlignCenter",
"tableAlignRight"
],
ai: false
},
destroy: function() {
var editor = this;
Widget.fn.destroy.call(this);
this._endTyping(true);
this._deregisterHandlers();
clearTimeout(this._spellCorrectTimeout);
this._focusOutside();
this.toolbar.destroy();
if (this.windowInstance) this.windowInstance.destroy();
if (this.tablePopup) this.tablePopup.destroy();
editor._destroyUploadWidget();
if (this.interSectionObserver) {
this.interSectionObserver.disconnect();
this.interSectionObserver = null;
}
if (this.resizeObserver) {
this.resizeObserver.destroy();
this.resizeObserver = null;
this.wrapper.css("min-height", "");
this.wrapper.css("max-height", "");
}
editor._destroyResizings();
editor._destroyFormattingMarksOverlay();
kendo.destroy(this.wrapper);
},
setOptions: function(options) {
var editor = this;
Widget.fn.setOptions.call(editor, options);
if (options.tools) this._setOptionsTools(options.tools);
this._initializePlaceholder();
},
createRange: function(document) {
return kendo.ui.editor.RangeUtils.createRange(document || this.document);
},
encodedValue: function() {
return kendo.ui.editor.Dom.encode(this.value());
},
exec: function(name, params) {
var that = this;
var command = null;
var defaultTools = kendo.ui.Editor.defaultTools;
var range, tool, prevented;
if (!name) throw new Error("kendoEditor.exec(): `name` parameter cannot be empty");
if (that.body.getAttribute("contenteditable") !== "true" && name !== "print" && name !== "pdf" && name !== "exportAs") return false;
if (!that.keyboard.isTypingInProgress()) {
that._focusBody();
that.selectRange(that._range || that.getRange());
}
tool = that.tools[name] || defaultTools[name];
if (!tool) Object.keys(defaultTools).map((key) => {
if (key.toLowerCase() === name) tool = defaultTools[key];
});
if (tool) {
range = that.getRange();
if (tool.command) command = tool.command(extend({
range,
body: that.body,
immutables: !!that.immutables
}, params));
prevented = that.trigger("execute", {
name,
command
});
if (prevented) return;
if (UNDO_REDO_REGEX.test(name)) that.undoRedoStack[name]();
else if (command) {
that.execCommand(command);
if (command.async) {
command.change = that._commandChange.bind(that);
return;
}
}
if (name !== "formattingMarks") that._handleSpaceAndNewLines();
that._selectionChange();
}
},
_commandChange: function() {
const that = this;
that._selectionChange();
that._handleSpaceAndNewLines();
},
execCommand: function(command) {
if (!command.managesUndoRedo) this.undoRedoStack.push(command);
command.editor = this;
command.exec();
},
focus: function() {
this.restoreSelection();
},
getRange: function() {
var selection = this.getSelection(), range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : this.createRange(), doc = this.document;
if (range.startContainer == doc && range.endContainer == doc && !range.startOffset && !range.endOffset) {
range.setStart(this.body, 0);
range.collapse(true);
}
return range;
},
getSelection: function() {
return kendo.ui.editor.SelectionUtils.selectionFromDocument(this.document);
},
paste: function(html, options) {
this.focus();
var command = new kendo.ui.editor.InsertHtmlCommand($.extend({
range: this.getRange(),
html
}, options));
command.editor = this;
command.exec();
},
insertAfterSelection: function(html, options) {
this.focus();
const range = this.getRange();
range.collapse(false);
var command = new kendo.ui.editor.InsertHtmlCommand($.extend({
range,
html
}, options));
command.editor = this;
command.exec();
},
refresh: function() {
var that = this;
if (that.textarea) {
that._destroyResizings();
var value = that.value();
that.textarea.val(value);
that.wrapper.find("iframe").remove();
that._initializeContentElement(that);
that.value(value);
}
},
restoreSelection: function() {
this._focusBody();
if (this.selectionRestorePoint) this.selectRange(this.selectionRestorePoint.toRange());
},
saveSelection: function(range) {
range = range || this.getRange();
var container = range.commonAncestorContainer, body = this.body;
if (container == body || $.contains(body, container)) this.selectionRestorePoint = new kendo.ui.editor.RestorePoint(range, body);
},
selectedHtml: function() {
return kendo.ui.editor.Serializer.domToXhtml(this.getRange().cloneContents());
},
selectRange: function(range) {
this._focusBody();
var selection = this.getSelection();
selection.removeAllRanges();
selection.addRange(range);
this.saveSelection(range);
},
state: function(toolName) {
var tool = kendo.ui.Editor.defaultTools[toolName];
var finder = tool && (tool.options.finder || tool.finder);
var RangeUtils = kendo.ui.editor.RangeUtils;
var range, textNodes;
if (finder) {
range = this.getRange();
textNodes = RangeUtils.textNodes(range);
if (!textNodes.length && range.collapsed) textNodes = [range.startContainer];
return finder.getFormat ? finder.getFormat(textNodes) : finder.isFormatted(textNodes);
}
return false;
},
update: function(value) {
value = value || this.options.encoded ? this.encodedValue() : this.value();
if (this.textarea) {
this.textarea.val(value);
this._togglePlaceholder(!value.trim());
} else this._oldValue = value;
},
value: function(html) {
var body = this.body, editorNS = kendo.ui.editor, options = this.options, currentHtml = editorNS.Serializer.domToXhtml(body, options.serialization);
if (html === undefined) return currentHtml;
if (html == currentHtml) return;
editorNS.Serializer.htmlToDom(html, body, options.deserialization);
this.selectionRestorePoint = null;
this.update();
this._refreshTools();
},
_bindTools: function() {
var that = this, defaultTools = this.tools;
that.unbind("select", that.toolbar.resize.bind(that.toolbar));
that.toolbar.element.find("[data-command]").filter((i, el) => $(el).find("[data-command]").length === 0).each((i, el) => {
var tool = defaultTools[el.getAttribute("data-command")];
if (tool && tool.initialize) tool.initialize($(el), that);
});
that.bind("select", that.toolbar.resize.bind(that.toolbar));
},
_blur: function() {
var textarea = this.textarea;
var old = textarea ? textarea.val() : this._oldValue;
var value = this.options.encoded ? this.encodedValue() : this.value();
this.update();
if (textarea) textarea.trigger("blur");
if (value != old) {
this.trigger("change");
if (textarea) textarea.trigger("change");
}
},
_containsRange: function(range) {
var dom = kendo.ui.editor.Dom;
var body = this.body;
return range && dom.isAncestorOrSelf(body, range.startContainer) && dom.isAncestorOrSelf(body, range.endContainer);
},
_createContentElement: function(stylesheets) {
var editor = this;
var iframe, wnd, doc;
var textarea = editor.textarea;
var specifiedDomain = editor.options.domain;
var domain = specifiedDomain || document.domain;
var domainScript = "";
var src = "javascript:\"\"";
var lang = "";
textarea.hide();
iframe = $("<iframe />", {
title: editor.options.messages.editAreaTitle,
frameBorder: "0"
})[0];
$(iframe).css("display", "").addClass("k-content k-iframe").attr("tabindex", textarea[0].tabIndex).insertBefore(textarea);
if (specifiedDomain || domain != location.hostname) {
domainScript = `<script ${editor.options.nonce ? `nonce="${editor.options.nonce}"` : ""}>document.domain="${domain}"<\/script>`;
src = "javascript:document.write('" + domainScript + "')";
iframe.src = src;
}
if (!iframe.src) iframe.src = "";
wnd = iframe.contentWindow || iframe;
doc = wnd.document || iframe.contentDocument;
const observer = editor.interSectionObserver = new IntersectionObserver((entries) => {
for (const entry of entries) if (entry.isIntersecting) {
editor._decorateFormatting(doc.body);
observer.unobserve(iframe);
}
});
observer.observe(iframe);
lang = document.getElementsByTagName("html")[0].getAttribute("lang") || DEFAULT_LANGUAGE;
doc.open();
doc.write("<!DOCTYPE html><html lang='" + lang + `'><head><meta charset='utf-8' /><title>Kendo UI Editor content</title><style ${editor.options.nonce ? `nonce="${editor.options.nonce}"` : ""}>html{padding:0;margin:0;height:100%;min-height:100%;cursor:text;}body{padding:0;margin:0;}body{box-sizing:border-box;font-size:12px;font-family:Verdana,Geneva,sans-serif;margin-top:-1px;padding:5px .4em 0;word-wrap: break-word;-webkit-nbsp-mode: space;-webkit-line-break: after-white-space;` + (kendo.support.isRtl(textarea) ? "direction:rtl;" : "") + (os.ios ? "word-break:keep-all;" : "") + (browser.edge || browser.chrome ? "height:100%;" : "") + "}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em}h3{font-size:1.16em}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.7em}p{margin:0 0 1em;}.k-marker{display:none;}.k-paste-container,.Apple-style-span{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}ul,ol{padding-left:2.5em}span{-ms-high-contrast-adjust:none;}a{color:#00a}code{font-size:1.23em}telerik\\3Ascript{display: none;}.k-table{width:100%;border-spacing:0;margin: 0 0 1em;}.k-table td{min-width:1px;padding:.2em .3em;}.k-table,.k-table td{outline:0;border: 1px dotted #ccc;}.k-table th{outline:0;border: 1px dotted #999;}.k-table p{margin:0;padding:0;}.k-column-resize-handle-wrapper {position: absolute; height: 10px; width:10px; cursor: col-resize; z-index: 2;}.k-column-resize-handle {width: 100%; height: 100%;}.k-column-resize-handle > .k-column-resize-marker {width:2px; height:100%; margin:0 auto; background-color:#00b0ff; display:none; opacity:0.8;}.k-row-resize-handle-wrapper {position: absolute; cursor: row-resize; z-index:2; width: 10px; height: 10px;}.k-row-resize-handle {display: table; width: 100%; height: 100%;}.k-row-resize-marker-wrapper{display: table-cell; height:100%; width:100%; margin:0; padding:0; vertical-align: middle;}.k-row-resize-marker{margin: 0; padding:0; width:100%; height:2px; background-color: #00b0ff; opacity:0.8; display:none;}.k-element-resize-handle-wrapper {position: absolute; background-color: #fff; border: 1px solid #000; z-index: 100; width: 5px; height: 5px;}.k-element-resize-handle {width: 100%; height: 100%;}.k-element-resize-handle.k-resize-east{cursor:e-resize;}.k-element-resize-handle.k-resize-north{cursor:n-resize;}.k-element-resize-handle.k-resize-northeast{cursor:ne-resize;}.k-element-resize-handle.k-resize-northwest{cursor:nw-resize;}.k-element-resize-handle.k-resize-south{cursor:s-resize;}.k-element-resize-handle.k-resize-southeast{cursor:se-resize;}.k-element-resize-handle.k-resize-southwest{cursor:sw-resize;}.k-element-resize-handle.k-resize-west{cursor:w-resize;}.k-table.k-element-resizing{opacity:0.6;}.k-placeholder{color:grey}k\\:script{display:none;}</style>" + domainScript + $.map(stylesheets, function(href) {
return `<link rel='stylesheet' href='${href}' ${editor.options.nonce ? `nonce="${editor.options.nonce}"` : ""}>`;
}).join("") + `</head><body id='${editor.element.attr("id")}' autocorrect='off' contenteditable='true'></body></html>`);
doc.close();
return wnd;
},
_deleteSavedRange: function() {
if ("_range" in this) delete this._range;
},
_decorateFormatting: function(body) {
var formattingElement = this.toolbar.element.find("input[data-command=formatting]"), dom = kendo.ui.editor.Dom, component, dataSource, items, i, tag, className, style;
if (formattingElement.length) {
component = formattingElement.getKendoDropDownList();
if (!component) return;
dataSource = component.dataSource;
items = dataSource.data();
if (body) component.list.css("background-color", dom.getEffectiveBackground($(body)));
if (this.options.unsafeInline !== false) for (i = 0; i < items.length; i++) {
tag = items[i].tag || "span";
className = items[i].className;
style = dom.inlineStyle(body, tag, { className });
style = style.replace(/"/g, "'");
items[i].style = style + ";display:inline-block";
}
dataSource.trigger("change");
}
},
_appendFormattingMarksStyles: function() {
const that = this, elementId = that.element.attr("id");
let style, $head;
style = `<style id='${"formatting-marks-style-" + elementId}' ${that.options.nonce ? `nonce="${that.options.nonce}"` : ""} >
#${elementId} p::after,
#${elementId} li::after,
#${elementId} h1::after,
#${elementId} h2::after,
#${elementId} h3::after,
#${elementId} h4::after,
#${elementId} h5::after,
#${elementId} h6::after {content: '\\00B6'; color: #6098f2;}
#${"formatting-marks-overlay-wrapper-" + elementId} {
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 9999;
pointer-events: none;
}
#${"formatting-marks-overlay-" + elementId} {
width: 100%;
height: 100%;
}
</style>`;
$head = $(that.document.head);
$head.find("#formatting-marks-style-" + elementId).remove();
$head.append(style);
},
_appendFormattingMarksOverlay: function() {
const that = this, elementId = that.element.attr("id");
that._formattingMarksOverlayWrapper = $(`<div id='${"formatting-marks-overlay-wrapper-" + elementId}'></div>`);
that._formattingMarksOverlay = $(`<svg id='${"formatting-marks-overlay-" + elementId}'></svg>`).appendTo(that._formattingMarksOverlayWrapper);
that._bodyTopBottomPaddings = parseFloat($(that.body).css("padding-top")) + parseFloat($(that.body).css("padding-bottom"));
if (that._isInlineEditor()) that._formattingMarksOverlayWrapper.insertAfter(that.element);
else that._formattingMarksOverlayWrapper.appendTo($(that.document).find("html"));
},
_destroyFormattingMarksOverlay: function() {
const that = this, elementId = that.element.attr("id");
$(that.document).find("#formatting-marks-overlay-wrapper-" + elementId).remove();
$(that.document.head).find("#formatting-marks-style-" + elementId).remove();
},
_updateFormattingMarksOverlayHeight: function() {
const that = this;
if (that._isInlineEditor()) that._formattingMarksOverlayWrapper.height($(that.body).outerHeight());
else that._formattingMarksOverlayWrapper.height(that.body.scrollHeight - that._bodyTopBottomPaddings);
},
_initInlineOverflowWrapper: function() {
const that = this, inlineHeight = that.options.inlineHeight;
if (that._isInlineEditor() && inlineHeight > -1) {
that._inlineOverflowWrapper = that.element.wrap(`<div class='k-inline-editor-overflow-wrapper k-pos-relative k-overflow-auto'></div>`).parent();
that._inlineOverflowWrapper.height(inlineHeight);
}
},
_addAIPromptElements: function() {
const that = this;
const splitterElement = $("<div/>");
const aiPromptElement = $("<div/>");
that.splitterElement = splitterElement;
that.aiPromptElement = aiPromptElement;
splitterElement.insertBefore(that.element);
aiPromptElement.appendTo(splitterElement);
that.element.appendTo(splitterElement);
},
_initInlineAIPrompt: function() {
const that = this;
const element = $("<div/>").insertAfter(that.element);
const defaultCommands = that._mapCommands(that.options.ai?.inlineAIPrompt?.commands || that.options.ai?.commands || kendo.ui.InlineAIPrompt.fn.options.commands);
that.inlineAIPrompt = element.kendoInlineAIPrompt({
popup: { width: "768px" },
service: that.options.ai?.service,
commands: defaultCommands,
_isEditor: true,
systemPrompt: that.options.ai?.inlineAIPrompt?.systemPrompt,
commandExecute: (e) => {
e.context = that.getRange().toString();
},
outputAction: (e) => {
if (e.action === "insert") that.insertAfterSelection(e.content);
if (e.action === "replace") that.paste(e.content);
}
}).data("kendoInlineAIPrompt");
},
_mapCommands: function(commands, parentId = null) {
const that = this;
return commands.map((command, i) => {
const id = parentId ? `${parentId}-${i}` : `${i}`;
const item = {
id,
text: command.text,
icon: command.icon
};
if (command.prompt) item.prompt = command.prompt;
if (command.items) item.items = that._mapCommands(command.items, id);
return item;
});
},
_isAiPromptEnabled() {
const that = this;
return that.options.ai && that.options.ai.aiPrompt != false;
},
_isInlineAIPromptEnabled() {
const that = this;
return that.options.ai && that.options.ai.inlineAIPrompt != false;
},
_initAIPrompt: function() {
const that = this;
const defaultCommands = that.options.ai?.aiPrompt?.commands || that.options.ai?.commands || that._mapCommands(kendo.ui.InlineAIPrompt.fn.options.commands);
that.aiPrompt = that.aiPromptElement.kendoAIPrompt($.extend({
service: that.options.ai?.service,
speechToText: false,
promptTextArea: {
rows: 5,
suffixOptions: { template: () => `<div ref-select-context-buttongroup></div>` }
},
views: [
{
type: "prompt",
buttonIcon: "",
initializeComponents: (e) => {
e.view.contentElement.find("[ref-select-context-buttongroup]").kendoButtonGroup({
index: that._contextSelection,
items: [{
text: "Use with selection",
icon: "box-sizing"
}, {
text: "Use full content",
icon: "form-element"
}],
selection: "multiple",
fillMode: "flat",
select: (e) => {
let selectionToggleButton = e.sender._buttons[0];
let fullContentToggleButton = e.sender._buttons[1];
if (e.indices.length > 1) if (e.target[0] == selectionToggleButton.element[0]) {
fullContentToggleButton.toggle(false);
e.sender._toggleIndex(1);
} else {
selectionToggleButton.toggle(false);
e.sender._toggleIndex(0);
}
that._contextSelection = e.indices[0];
}
});
}
},
{ type: "output" },
{
type: "commands",
promptCommands: defaultCommands
}
],
promptRequest: (e) => {
const contextSelection = that._contextSelection;
let prompt = e.prompt;
if (contextSelection === 0) prompt = that._contextTemplate(prompt, that.getRange().toString());
else if (contextSelection === 1) prompt = that._contextTemplate(prompt, that.value());
else prompt = that._contextTemplate(prompt, "");
if (e.prompt != prompt) e.prompt = prompt;
},
commandExecute: (e) => {
const prompt = e.item.prompt;
if (prompt) that.aiPrompt.transport.read({
prompt: prompt(that.value()),
history: [],
isRetry: false
});
}
}, that.options.ai?.aiPrompt)).data("kendoAIPrompt");
that.aiPromptSplitter = that.splitterElement.kendoSplitter({ panes: [$.extend({
size: "50%",
collapsible: true,
collapsed: true,
min: "360px"
}, that.options.ai?.pane), {}] }).data("kendoSplitter");
if (that._isInlineAIPromptEnabled()) that.bind("select", that._selectionChangeHandler.bind(that));
},
_contextTemplate: function(query, context) {
const that = this;
const defaultTemplate = `You are an advanced AI language assistant.
A user has selected a portion of their text and provided a query regarding how they want it modified.
Your task is to accurately respond to their request while preserving the original intent of the text.
Follow the instructions strictly and provide only the requested output unless explicitly asked to explain your changes.
${context ? "Selected Text:" : ""}
${context}
User's Request:
${query}
Response:`;
if (!that.options.ai?.aiPrompt?.systemPrompt) return defaultTemplate;
return that.options.ai?.aiPrompt?.systemPrompt(query, context);
},
_selectionChangeHandler: function() {
const that = this, range = that.getRange(), selectionRect = range.getBoundingClientRect(), elementRect = that.wrapper[0].getBoundingClientRect();
if (kendo.ui.editor.RangeUtils.textNodes(range).length === 0) {
that.inlineAIPrompt._popup.close();
return;
}
that.inlineAIPrompt._popup.open();
const popupHeight = that.inlineAIPrompt._popup.element.outerHeight();
const popupWidth = that.inlineAIPrompt._popup.element.outerWidth();
let y = window.scrollY + elementRect.top + selectionRect.top + selectionRect.height;
let x = window.scrollX + elementRect.left + selectionRect.left + selectionRect.width / 2 - popupWidth / 2;
that.inlineAIPrompt._popup.close(true);
if (window.innerHeight - selectionRect.bottom < popupHeight) y -= popupHeight;
else y += popupHeight;
if (x + popupWidth > window.innerWidth + window.scrollX) x = window.innerWidth + window.scrollX - popupWidth;
that.inlineAIPrompt._popup.open(x, y);
},
_getSelectionPosition: function() {
this.getRange().getBoundingClientRect();
},
_initContextMenu: function() {
const that = this;
const html = $(`<ul>
<li>${kendo.html.renderIcon({ icon: "arrow-rotate-cw" })} Rewrite</li>
<li>${kendo.html.renderIcon({ icon: "spell-checker" })} Fix mistakes</li>
<li>${kendo.html.renderIcon({ icon: "tell-a-friend" })} Change tone
<ul>
<li>Neutral</li>
<li>Friendly</li>
<li>Casual</li>
<li>Formal</li>
</ul>
</li>
<li>${kendo.html.renderIcon({ icon: "apply-format" })} Polish formatting
<li>${kendo.html.renderIcon({ icon: "col-resize" })} Adjust length
<li>${kendo.html.renderIcon({ icon: "edit-tools" })} Translate
</ul>`);
$("body").append(html);
that._aiContextMenu = html.kendoContextMenu({ targe: "imposibru" }).data("kendoContextMenu");
},
_insertAIResult: function() {
this.paste("Test ai result");
},
_deregisterHandlers: function() {
var handlers = this._handlers;
for (var i = 0; i < handlers.length; i++) {
var h = handlers[i];
h.element.off(h.type, h.handler);
}
this._handlers = [];
},
_destroyUploadWidget: function() {
var editor = this;
if (editor._uploadWidget) {
editor._uploadWidget.destroy();
editor._uploadWidget = null;
}
},
_endTyping: function() {
var keyboard = this.keyboard;
try {
if (keyboard.isTypingInProgress()) {
keyboard.endTyping(true);
this.saveSelection();
}
} catch (e) {}
},
_focusBody: function() {
var body = this.body;
var iframe = this.wrapper && this.wrapper.find("iframe")[0];
var documentElement = this.document.documentElement;
var activeElement = kendo._activeElement();
var scrollTop;
if (!iframe) {
if (activeElement !== body) body.focus({ preventScroll: true });
} else if (activeElement !== body && activeElement !== iframe) {
scrollTop = documentElement.scrollTop;
body.focus();
documentElement.scrollTop = scrollTop;
}
},
_focusOutside: function() {
if (kendo.support.browser.msie && this.textarea) $("<input />").css({
position: "fixed",
left: "1px",
top: "1px",
width: "1px",
height: "1px",
"font-size": "0",
border: "0",
opacity: "0"
}).appendTo(document.body).trigger("focus").trigger("blur").remove();
},
_handleToolbarClick: function(e) {
var toolName = e.target.data("command");
if (toolName && toolName !== "createTable") this.exec(toolName);
},
_immutablesContext: function(range) {
var editorNS = kendo.ui.editor;
if (this.options.immutables) if (range.collapsed) return editorNS.Immutables.immutablesContext(range);
else return editorNS.RangeUtils.editableTextNodes(range).length === 0;
},
_initializeContentElement: function() {
var editor = this;
var doc;
var blurTrigger;
var mousedownTrigger;
if (editor.textarea) {
editor.window = editor._createContentElement(editor.options.stylesheets);
doc = editor.document = editor.window.contentDocument || editor.window.document;
if (!doc.body) {
var body = doc.createElement("body");
body.setAttribute("contenteditable", "true");
body.setAttribute("autocorrect", "off");
doc.getElementsByTagName("html")[0].appendChild(body);
var interval = setInterval(function() {
if ($(editor.document).find("body").length > 1) {
$(editor.document).find("body").last().remove();
window.clearInterval(interval);
}
}, 10);
}
editor.body = doc.body;
blurTrigger = editor.window;
mousedownTrigger = doc;
this._registerHandler(doc, "mouseup", this._mouseup.bind(this));
} else {
const editorElement = editor.element[0];
doc = editor.document = editorElement?.ownerDocument;
editor.window = doc?.defaultView || doc?.parentWindow;
editor.body = editorElement;
blurTrigger = editor.body;
mousedownTrigger = editor.body;
editor._wrapSingleTextNodeInParagraph();
setTimeout(() => {
editor._decorateFormatting(editor.body);
this.update();
});
}
this._registerHandler(blurTrigger, "blur", this._blur.bind(this));
editor._registerHandler(mousedownTrigger, "down", editor._mousedown.bind(editor));
try {
doc.execCommand("enableInlineTableEditing", null, false);
} catch (e) {}
if (kendo.support.touch) this._registerHandler(doc, { "keydown": function() {
if (kendo._activeElement() != doc.body) editor.window.focus();
} });
this._initializePlaceholder();
this._spellCorrect(editor);
this._registerHandler(editor.document, {
"mouseover dragenter": function(e) {
var height = $(editor.body).height();
if ($(editor.body.parentElement).height() > height && e.target.nodeName.toLowerCase() === "html") {
editor._cachedHeight = "" + editor.body.style.height;
editor.body.style.height = "100%";
}
},
"mouseout dragleave drop contextmenu": function(e) {
var restoreHeight = function() {
if (editor._cachedHeight !== undefined && e.target === editor.body) {
editor.body.style.height = editor._cachedHeight;
delete editor._cachedHeight;
}
};
if (e.type === "contextmenu") setTimeout(function() {
restoreHeight();
}, 10);
else restoreHeight();
}
});
this._registerHandler(editor.body, {
"keydown": function(e) {
var range;
if ((e.keyCode === keys.BACKSPACE || e.keyCode === keys.DELETE) && editor.body.getAttribute("contenteditable") !== "true") return false;
if (e.keyCode === keys.F10) {
editor.toolbar.element.find("[tabindex=0]").first().trigger("focus");
editor.toolbar.preventPopupHide = true;
e.preventDefault();
return;
} else if (e.keyCode == keys.LEFT || e.keyCode == keys.RIGHT) {
range = editor.getRange();
var left = e.keyCode == keys.LEFT;
var container = range[left ? "startContainer" : "endContainer"];
var offset = range[left ? "startOffset" : "endOffset"];
var next = offset + (left ? -1 : 1);
var nextChar = left ? next : offset;
if (container.nodeType == 3 && container.nodeValue[nextChar] == "") {
range.setStart(container, next);
range.collapse(true);
editor.selectRange(range);
}
}
var tools = editor.tools;
var toolName = editor.keyboard.toolFromShortcut(tools, e);
var toolOptions = toolName ? tools[toolName].options : {};
if (toolName && !toolOptions.keyPressCommand) {
e.preventDefault();
if (!UNDO_REDO_REGEX.test(toolName)) editor.keyboard.endTyping(true);
editor.trigger("keydown", e);
editor.exec(toolName);
editor._runPostContentKeyCommands(e);
return false;
}
editor.keyboard.clearTimeout();
editor.keyboard.keydown(e);
},
"keypress": function(e) {
setTimeout(function() {
editor._runPostContentKeyCommands(e);
editor._showElementResizeHandles();
}, 0);
},
"keyup": function(e) {
var selectionCodes = [
keys.BACKSPACE,
keys.TAB,
keys.PAGEUP,
keys.PAGEDOWN,
keys.END,
keys.HOME,
keys.LEFT,
keys.UP,
keys.RIGHT,
keys.DOWN,
keys.INSERT,
keys.DELETE
];
if ($.inArray(e.keyCode, selectionCodes) > -1 || e.keyCode == 65 && e.ctrlKey && !e.altKey && !e.shiftKey) {
window.clearTimeout(this._refreshInterval);
this._refreshInterval = window.setTimeout(function() {
editor._selectionChange();
}, REFRESH_INTERVAL);
}
if (e.keyCode === keys.BACKSPACE || e.keyCode === keys.DELETE) editor._handleSpaceAndNewLines();
editor.keyboard.keyup(e);
},
"click": function(e) {
var dom = kendo.ui.editor.Dom, range;
if (dom.name(e.target) === "img") {
range = editor.createRange();
range.selectNode(e.target);
editor.selectRange(range);
}
},
"cut copy paste drop dragover": function(e) {
editor.clipboard["on" + e.type](e);
editor._handleSpaceAndNewLines();
},
"focusin": function() {
if (editor.body.hasAttribute("contenteditable")) {
$(this).addClass("k-active");
editor._showWindow();
editor._togglePlaceholder(false);
}
},
"focusout": function() {
setTimeout(function() {
var active = kendo._activeElement();
var body = editor.body;
var toolbar = editor.toolbar;
if (toolbar.options.popup) {
var toolbarContainerElement = editor.windowInstance.element.get(0);
if (toolbarContainerElement && !($.contains(toolbarContainerElement, active) || toolbarContainerElement == active)) toolbar.preventPopupHide = false;
}
if (active != body && !$.contains(body, active) && !editor._toolbarFocused() && !toolbar.preventPopupHide && !$(active).hasClass("k-context-menu") && !$(active).hasClass("k-colorpalette")) {
$(body).removeClass("k-active");
editor._hideWindow();
}
editor._togglePlaceholder(!editor.value().trim());
}, 10);
}
});
editor._initializeColumnResizing();
editor._initializeRowResizing();
editor._initializeElementResizing();
},
_initializeImmutables: function() {
var that = this, editorNS = kendo.ui.editor;
if (that.options.immutables) that.immutables = new editorNS.Immutables(that);
},
_initializePlaceholder: function() {
var that = this, placeholder = that.options.placeholder, style, $head;
if (!that.textarea || !placeholder) return;
style = `<style id='${PLACEHOLDER_TAG_ID}' ${that.options.nonce ? `nonce="${that.options.nonce}"` : ""} >.` + PLACEHOLDER_CLASS + ":before { content: '" + placeholder + "'; }</style>";
$head = $(that.document.head);
$head.find("#" + PLACEHOLDER_TAG_ID).remove();
$head.append(style);
that._togglePlaceholder(!that.value().trim());
},
_initToolbar: function(toolbarContainer) {
var that = this, tools, defaults, toolbarOptions;
that.tools = [];
[tools, defaults] = that._processToolbarItems(that.options.tools);
that._setNativeTools();
toolbarOptions = {
tools,
defaultTools: defaults,
parentMessages: that.options.messages,
resizable: that.options.resizable === true || Boolean(that.options.resizable && that.options.resizable.toolbar && that.options.resizable.toolbar?.mode !== "none"),
toggle: that._handleToolbarClick.bind(this),
click: that._handleToolbarClick.bind(this),
navigateOnTab: that.options.navigateOnTab,
evaluateTemplates: true,
overflow: $.isPlainObject(that.options.resizable?.toolbar) ? that.options.resizable.toolbar : undefined
};
that.toolbar = new kendo.ui.ToolBar(toolbarContainer, toolbarOptions);
that._bindTools();
that.bind("select", that._refreshTools.bind(that));
toolbarContainer.on("mousedown" + NS, function(e) {
const target = $(e.target);
const tool = target.closest("[ref-toolbar-tool]");
if (!tool.length || !tool.data("command")) return;
if (tool.length) {
if (!target.is("input")) e.preventDefault();
} else e.preventDefault();
});
if (!that.textarea) {
const toolbarWidth = toolbarContainer.width();
if (toolbarWidth && toolbarWidth > 0) toolbarContainer.width(toolbarWidth);
that._initToolbarWindow(toolbarContainer);
}
},
_initToolbarWindow: function(toolbarEl) {
var that = this;
this.windowInstance = toolbarEl.wrap("<div class='editorToolbarWindow k-editor-window' />").parent().prepend("<span class='k-editortoolbar-dragHandle'>" + kendo.ui.icon("handle-drag") + "</span>").kendoWindow({
title: false,
resizable: false,
draggable: { dragHandle: ".k-editortoolbar-dragHandle" },
animation: {
open: { effects: "fade:in" },
close: { effects: "fade:out" }
},
minHeight: 42,
visible: false,
autoFocus: false,
actions: [],
dragend: function() {
this._moved = true;
}
}).on("mousedown", function(e) {
if (!$(e.target).is(TOOLBAR_ALLOWED_CLOSE_SELECTORS)) that.toolbar.preventPopupHide = true;
}).on("focusout", function() {
that.element.focusout();
}).data("kendoWindow");
},
_mousedown: function(e) {
var editor = this;
editor._selectionStarted = true;
if ($(editor.body).parents(".k-window").length) e.stopPropagation();
if (browser.gecko) return;
var target = $(e.target).closest("a[href]");
if ((e.which == 2 || e.which == 1 && e.ctrlKey) && target && target.is("a[href]")) window.open(target.attr("href"), "_new");
if (e.target.tagName && e.target.tagName.toLowerCase() === "html") setTimeout(function() {
editor.body.focus();
}, 0);
},
_mouseup: function(e) {
var that = this;
if (kendo.support.mobileOS.ios && e && $(e.target).is(SELECT_OVERLAY_SELECTOR)) return;
if (that._selectionStarted) setTimeout(function() {
that._selectionChange();
}, 1);
},
_populateValue: function(options, domElement) {
var that = this, editorNS = kendo.ui.editor, dom = editorNS.Dom, value, comments;
if (options && options.value) value = options.value;
else if (that.textarea) {
value = domElement.value;
if (!value.replace(/\s/g, "").length) value = value.replace(/\s/g, "");
if (that.options.encoded && domElement.defaultValue && domElement.defaultValue.trim().length) value = domElement.defaultValue;
var deserializedRoot = editorNS.Serializer.htmlToDom(value, $("<div></div>")[0], that.options.deserialization);
comments = dom.getAllComments(deserializedRoot);
value = EditorUtils.cacheComments(value, comments);
value = value.replace(/[\r\n\v\f\t ]+/gi, " ");
value = EditorUtils.retrieveComments(value, comments);
} else value = domElement.innerHTML;
that.value(value || "");
},
_resetGroups: function(current) {
var result = {};
Object.keys(current).map((key) => {
result[key + "_"] = current[key];
});
return result;
},
_processToolbarItems: function(optionsTools) {
var flatDefaultTools = {}, processedObject = {}, tools = [], currentGroups = $.extend(true, {}, toolGroups), i, j, t, name, guidGroupName;
for (i = 0; i < optionsTools.length; i++) {
t = optionsTools[i];
if (Array.isArray(t)) {
guidGroupName = kendo.guid();
for (j = 0; j < t.length; j++) {
[flatDefaultTools, name] = this._processToolOptions(t[j], flatDefaultTools);
if (!name) continue;
flatDefaultTools[name].gr = guidGroupName;
}
} else {
[flatDefaultTools, name] = this._processToolOptions(t, flatDefaultTools);
if (!name) continue;
else if (flatDefaultTools[name] && flatDefaultTools[name].type === "separator") currentGroups = this._resetGroups(currentGroups);
Object.keys(currentGroups).map((key) => {
if (currentGroups[key].includes(name)) flatDefaultTools[name].gr = key;
});
}
}
Object.values(flatDefaultTools).map((tool) => {
var group = tool.gr;
delete tool.gr;
if (group === undefined) processedObject[tool.name] = tool;
else {
if (!processedObject[group]) processedObject[group] = [];
processedObject[group].push(tool);
}
});
tools = Object.values(processedObject).map((g) => {
var result;
if (g.length) result = g.map((to) => to.name);
else result = g.name;
if (result.length === 1) result = result[0];
return result;
});
return [tools, flatDefaultTools];
},
_processDefaultTool: function(tool, defaultTools) {
var name = tool.name, result = {}, options;
if ($.isPlainObject(tool)) if (name && defaultTools[name]) {
result = extend({}, defaultTools[name]);
extend(result.options, tool);
} else {
options = extend({
icon: "gear",
type: "button"
}, tool);
if (!options.name) options.name = "custom";
options.cssClass = "k-" + options.name;
result = { options };
name = options.name;
}
else if (defaultTools[tool]) {
name = tool;
result = defaultTools[name];
} else return null;
this.tools[name] = result;
return result;
},
_processToolOptions: function(t, flatDefaultTools) {
var that = this, defaultTools = kendo.deepExtend({}, kendo.ui.Editor.defaultTools), tool = this._processDefaultTool(t, defaultTools), name, view, shortcuts, options, uiOptions, icon, toolOptions, originalOptions, palette;
if (!tool) return [flatDefaultTools, null];
options = tool.options;
name = options.name;
uiOptions = options.ui || {};
icon = EditorUtils.getToolCssClass(options.name, options.icon);
originalOptions = $.isPlainObject(t) ? $.extend({}, t) : {};
delete originalOptions.items;
toolOptions = $.extend({
name: options.name,
command: options.command,
template: options.template,
attributes: { class: options.cssClass },
type: "button",
icon,
showText: "overflow",
showIcon: "both"
}, uiOptions, originalOptions);
if (options.tooltip) {
if (!toolOptions.attributes) toolOptions.attributes = {};
toolOptions.attributes.title = options.tooltip;
}
if (options.exec) {
toolOptions.click = options.exec.bind(that);
delete toolOptions.exec;
}
if (toolOptions.component === "ColorPicker") {
if (options.palette !== undefined || uiOptions.palette !== kendo.ui.editor.ColorTool.fn.options.palette) {
palette = options.palette || kendo.ui.editor.ColorTool.fn.options.palette;
view = options.palette !== undefined && !options.palette ? "gradient" : "palette";
toolOptions.componentOptions.palette = view === "palette" ? palette : undefined;
toolOptions.componentOptions.views = [view];
toolOptions.componentOptions.preview = view === "gradient";
toolOptions.componentOptions.input = view === "gradient";
toolOptions.componentOptions.buttons = view === "gradient";
if (view === "gradient") delete toolOptions.componentOptions.columns;
}
if (view === "palette" && options.columns) toolOptions.componentOptions.columns = options.columns;
}
if (toolOptions.component === "DropDownList" || toolOptions.component === "ComboBox") {
if (!toolOptions.componentOptions) toolOptions.componentOptions = {};
if (!toolOptions.componentOptions.dataSource) if (that.options[name] && Array.isArray(that.options[name])) toolOptions.componentOptions.dataSource = that.options[name];
else toolOptions.componentOptions.dataSource = options.items;
}
if (toolOptions.template) delete toolOptions.type;
shortcuts = this._shortcutSequence(name);
if (shortcuts !== "") {
if (!toolOptions.attributes) toolOptions.attributes = {};
toolOptions.attributes["aria-keyshortcuts"] = shortcuts;
}
if (toolOptions.type === "separator") {
name = "separator_" + kendo.guid();
toolOptions.name = name;
}
flatDefaultTools[name] = toolOptions;
return [flatDefaultTools, name];
},
_refreshTools: function() {
var that = this, range = that.getRange(), editorNS = kendo.ui.editor, nodes = editorNS.RangeUtils.textNodes(range), immutables = that.options.immutables, immutablesContext = that._immutablesContext(range), defaultTools = that.tools;
nodes = editorNS.Dom.filterBy(nodes, editorNS.Dom.htmlIndentSpace, true);
if (!nodes.length) nodes = [range.startContainer];
that.toolbar.element.find("[data-command]").filter((i, el) => $(el).find("[data-command]").length === 0).each(function() {
var tool = defaultTools[this.getAttribute("data-command")], ui;
if (tool) {
ui = $(this);
if (tool.update) tool.update(ui, nodes, that.undoRedoStack, immutables && immutablesContext);
if (immutables) that._updateImmutablesState(tool, ui, immutablesContext);
}
});
},
_registerHandler: function(element, type, handler) {
var editor = this;
var NS = ".kendoEditor";
var eventNames;
var i;
element = $(element);
if (!this._handlers) this._handlers = [];
if (element.length) if ($.isPlainObject(type)) {
for (var t in type) if (type.hasOwnProperty(t)) this._registerHandler(element, t, type[t]);
} else {
eventNames = kendo.applyEventMap(type).split(" ");
for (i = 0; i < eventNames.length; i++) {
editor._handlers.push({
element,
type: eventNames[i] + NS,
handler
});
element.on(eventNames[i] + NS, handler);
}
}
},
_runPostContentKeyCommands: function(e) {
const range = this.getRange();
const tools = this.keyboard.toolsFromShortcut(this.tools, e);
for (var i = 0; i < tools.length; i++) {
var tool = tools[i];
var o = tool.options;
if (!o.keyPressCommand) continue;
if (new o.command({ range }).changesContent()) {
this.keyboard.endTyping(true);
this.exec(tool.name);
}
}
const toolName = this.keyboard.toolFromShortcut(this.tools, e);
this._wrapSingleTextNodeInParagraph(!UNDO_REDO_REGEX.test(toolName));
this._handleSpaceAndNewLines();
},
_wrapSingleTextNodeInParagraph: function(repositionCursor) {
const childNodes = this.body.childNodes;
const dom = kendo.ui.editor.Dom;
if (this.textarea) return;
if (childNodes.length === 1 && childNodes[0].nodeType === dom.nodeTypes.TEXT_NODE) {
const textNode = childNodes[0];
dom.wrap(textNode, this.document.createElement("p"));
if (repositionCursor && kendo._activeElement() === this.body) {
this.getSelection().collapse(textNode, textNode.length);
this.saveSelection();
}
}
},
_handleSpaceAndNewLines: function() {
const that = this, refreshDelay = that.options.formattingMarksRefreshDelay, editorNS = kendo.ui.editor, applyFormattingMarks = editorNS.applyFormattingMarks, clearFormattingMarksOverlay = editorNS.clearFormattingMarksOverlay;
if (that._toggledFormattingMarks) {
if (that._formattingMarksOverlay.children().length) clearFormattingMarksOverlay(that);
if (refreshDelay) {
clearTimeout(that._formattingMarksTimeout);
that._formattingMarksTimeout = setTimeout(() => applyFormattingMarks(that), refreshDelay);
} else applyFormattingMarks(that);
}
},
_selectionChange: function() {
this._selectionStarted = false;
this.saveSelection();
this.trigger("select", {});
},
_setOptionsTools: function(optionsTools) {
var that = this, toolbar = that.toolbar, toolbarContainer = toolbar.element, tools, defaults, toolbarOptions;
toolbar.destroy();
toolbarContainer.empty();
that.tools = [];
[tools, defaults] = that._processToolbarItems(optionsTools);
that._setNativeTools();
toolbarOptions = {
tools,
defaultTools: defaults,
parentMessages: that.options.messages,
resizable: that.options.resizable === true || Boolean(that.options.resizable && that.options.resizable.toolbar && that.options.resizable.toolbar?.mode !== "none"),
toggle: that._handleToolbarClick.bind(this),
click: that._handleToolbarClick.bind(this),
overflow: $.isPlainObject(that.options.resizable?.toolbar) ? that.options.resizable.toolbar : undefined
};
that.toolbar = new kendo.ui.ToolBar(toolbarContainer, toolbarOptions);
that._bindTools();
},
_setNativeTools: function() {
var defaultTools = kendo.deepExtend({}, kendo.ui.Editor.defaultTools), i;
for (i = 0; i < NATIVE_TOOLS.length; i++) if (!this.tools[NATIVE_TOOLS[i]]) this.tools[NATIVE_TOOLS[i]] = defaultTools[NATIVE_TOOLS[i]];
},
_setupHeight: function(type) {
var that = this;
if (type == "textarea") setTimeout(function() {
var heightStyle = that.wrapper[0].style.height;
var expectedHeight = parseInt(heightStyle, 10);
var actualHeight = that.wrapper.height();
if (heightStyle.indexOf("px") > 0 && !isNaN(expectedHeight) && actualHeight > expectedHeight) that.wrapper.height(expectedHeight - (actualHeight - expectedHeight));
});
},
_setupKeyboard: function() {
var that = this, editorNS = kendo.ui.editor;
that.keyboard = new editorNS.Keyboard([
new editorNS.BackspaceHandler(that),
new editorNS.TypingHandler(that),
new editorNS.SystemHandler(that),
new editorNS.SelectAllHandler(that)
]);
},
_setupType: function(element) {
var domElement = element[0], type = kendo.ui.editor.Dom.name(domElement), id = domElement.id, toolbarContainer;
if (!id) {
id = "editor-" + kendo.guid();
domElement.setAttribute("id", id);
}
if (type == "textarea") {
this._wrapTextarea();
toolbarContainer = this.wrapper.find(".k-editor-toolbar");
toolbarContainer.attr("aria-controls", id);
} else {
$(domElement).attr("contenteditable", true).addClass("k-editor k-editor-inline");
toolbarContainer = $("<div class=\"k-editor-toolbar\"/>").insertBefore(element);
}
return toolbarContainer;
},
_isInlineEditor: function() {
return this.element.hasClass("k-editor-inline");
},
_shortcutSequence: function(name) {
var tool = kendo.ui.Editor.defaultTools[name], res = "", options;
if (!tool || !tool.options) return res;
options = tool.options;
if (options.ctrl) res += "Ctrl+";
if (options.shift) res += "Shift+";
if (options.alt) res += "Alt+";
if (options.key) res += options.key;
return res;
},
_spellCorrect: function(editor) {
var beforeCorrection;
var falseTrigger = false;
this._registerHandler(editor.body, {
"contextmenu": function() {
editor.one("select", function() {
beforeCorrection = null;
});
editor._spellCorrectTimeout = setTimeout(function() {
beforeCorrection = new kendo.ui.editor.RestorePoint(editor.getRange(), editor.body);
falseTrigger = false;
}, 10);
},
"input": function() {
if (!beforeCorrection) return;
if (kendo.support.browser.mozilla && !falseTrigger) {
falseTrigger = true;
return;
}
kendo.ui.editor._finishUpdate(editor, beforeCorrection);
}
});
},
_togglePlaceholder: function(show) {
var that = this, body = that.body, $body = $(body), placeholder = that.options.placeholder;
if (!that.textarea || !placeholder) return;
$body.attr("aria-label", function() {
return show ? placeholder : "";
});
$body.toggleClass(PLACEHOLDER_CLASS, show);
},
_toolbarFocused: function() {
var active = kendo._activeElement(), popup = this.windowInstance, overflowPopup = this.overflowPopup;
return popup && $(active).closest(popup.wrapper).length || overflowPopup && overflowPopup.visible();
},
_updateImmutablesState: function(tool, ui, immutablesContext) {
let toolbar = this.toolbar, name = tool.name, overflowAnchor = toolbar.overflowAnchor, uiElement = ui.closest("[ref-toolbar-tool]"), trackImmutables = tool.options.trackImmutables, toolInOverflowMenuIsHidden = true, editorNS = kendo.ui.editor;
if (trackImmutables === undefined) trackImmutables = $.inArray(name, editorNS.Immutables.toolsToBeUpdated) > -1;
if (overflowAnchor && !overflowAnchor.hasClass("k-hidden")) toolInOverflowMenuIsHidden = (toolbar.overflowMenu?.element.find(`[data-command="${tool.options.name}"]`))?.hasClass("k-hidden");
if (trackImmutables) {
if (immutablesContext) toolbar.hide(uiElement);
else if (toolInOverflowMenuIsHidden) toolbar.show(uiElement);
}
},
_wrapTextarea: function() {
var that = this, textarea = that.element, w = textarea[0].style.width, h = textarea[0].style.height, editorWrap = $(EditorUtils.editorWrapperTemplate()).insertBefore(textarea), editArea = editorWrap.find(".k-editable-area");
editorWrap.css({
"width": w,
"height": h
});
textarea.attr("autocomplete", "off").appendTo(editArea).addClass("k-content k-raw-content").css("display", "none");
that.textarea = textarea;
that.wrapper = editorWrap;
},
_resizable: function() {
let that = this;
let resizable = this.options.resizable;
let isResizable = $.isPlainObject(resizable) ? resizable.content === undefined || resizable.content === true : resizable;
let resizableMin = $.isPlainObject(resizable.min) ? resizable.min : { minHeight: resizable.min };
let resizableMax = $.isPlainObject(resizable.max) ? resizable.max : { maxHeight: resizable.max };
if (isResizable && this.textarea) {
that.wrapper.addClass("k-editor-resizable");
if (resizableMin.minHeight) that.wrapper.css("min-height", resizableMin.minHeight);
if (resizableMax.maxHeight) that.wrapper.css("max-height", resizableMax.maxHeight);
if (resizableMin.minWidth) that.wrapper.css("min-width", resizableMin.minWidth);
if (resizableMax.maxWidth) that.wrapper.css("max-width", resizableMax.maxWidth);
that.resizeObserver = require_kendo_core.domUtilsService.createResizeObserver({
element: that.wrapper,
onResize: function() {
that.toolbar.resize();
that._handleSpaceAndNewLines();
}
});
}
},
_destroyResizings: function() {
var editor = this;
editor._destroyElementResizing();
kendo.ui.editor.ElementResizingFactory.current.dispose(editor);
editor._destroyRowResizing();
kendo.ui.editor.RowResizing.dispose(editor);
editor._destroyColumnResizing();
kendo.ui.editor.ColumnResizing.dispose(editor);
},
_initializeElementResizing: function() {
var editor = this;
kendo.ui.editor.ElementResizingFactory.current.create(editor);
editor._showElementResizeHandlesProxy = editor._showElementResizeHandles.bind(editor);
editor.bind(SELECT, editor._showElementResizeHandlesProxy);
},
_destroyElementResizing: function() {
var editor = this;
var elementResizing = editor.elementResizing;
if (elementResizing) {
elementResizing.destroy();
editor.elementResizing = null;
}
if (editor._showElementResizeHandlesProxy) editor.unbind(SELECT, editor._showElementResizeHandlesProxy);
},
_showElementResizeHandles: function() {
var editor = this;
var elementResizing = editor.elementResizing;
if (elementResizing && elementResizing.element && elementResizing.element.parentNode) elementResizing.showResizeHandles();
else if (elementResizing && (!elementResizing.element || !elementResizing.element.parentNode)) editor._destroyElementResizing();
},
_initializeColumnResizing: function() {
kendo.ui.editor.ColumnResizing.create(this);
},
_destroyColumnResizing: function() {
var editor = this;
if (editor.columnResizing) {
editor.columnResizing.destroy();
editor.columnResizing = null;
}
},
_initializeRowResizing: function() {
kendo.ui.editor.RowResizing.create(this);
},
_destroyRowResizing: function() {
var editor = this;
if (editor.rowResizing) {
editor.rowResizing.destroy();
editor.rowResizing = null;
}
},
_getWindowWidth: function() {
var that = this, wrapper = that.windowInstance.wrapper, editorElement = that.element;
return outerWidth(editorElement) - parseInt(wrapper.css("border-left-width"), 10) - parseInt(wrapper.css("border-right-width"), 10);
},
_hideWindow: function() {
if (this.windowInstance) this.windowInstance.close();
},
_overlapsWindow: function(box) {
var toolbarWrapper = this.windowInstance.wrapper, toolbarWrapperOffset = toolbarWrapper.offset(), toolbarWrapperLeft = toolbarWrapperOffset.left, toolbarWrapperTop = toolbarWrapperOffset.top, boxOffset = box.offset(), boxOffsetLeft = boxOffset.left, boxOffsetTop = boxOffset.top;
return !(boxOffsetLeft + box.width() < toolbarWrapperLeft || boxOffsetLeft > toolbarWrapperLeft + toolbarWrapper.width() || boxOffsetTop + box.height() < toolbarWrapperTop || boxOffsetTop > toolbarWrapperTop + toolbarWrapper.height());
},
_showWindow: function() {
var that = this, windowInstance = that.windowInstance, wrapper, editorElement, editorOffset, browser = kendo.support.browser;
if (windowInstance) {
wrapper = windowInstance.wrapper;
editorElement = that.element;
if (!wrapper.is(":visible") || !that.windowInstance.options.visible) {
if (!wrapper[0].style.width) wrapper.width(this._getWindowWidth());
if (!windowInstance._moved) {
editorOffset = editorElement.offset();
wrapper.css({
top: Math.max(0, parseInt(editorOffset.top, 10) - outerHeight(wrapper) - parseInt(that.windowInstance.element.css("padding-bottom"), 10)),
left: Math.max(0, parseInt(editorOffset.left, 10))
});
}
if ((browser.msie || browser.edge) && that._overlapsWindow(editorElement)) setTimeout(function() {
windowInstance.open();
}, 0);
else windowInstance.open();
}
}
}
});
Editor.defaultTools = {};
kendo.ui.plugin(Editor);
var Tool = Class.extend({
init: function(options) {
this.options = options;
},
command: function(commandArguments) {
return new this.options.command(commandArguments);
},
update: $.noop
});
Tool.exec = function(editor, name, value) {
editor.exec(name, { value });
};
var UndoTool = Tool.extend({
command: $.noop,
update: function(ui, nodes, undoRedoStack) {
var name = this.options.name, toolbar = ui.closest(".k-toolbar").data("kendoToolBar");
switch (name) {
case "undo":
toolbar.enable(ui, undoRedoStack.canUndo());
break;
case "redo":
toolbar.enable(ui, undoRedoStack.canRedo());
break;
default: break;
}
ui.removeAttr("disabled");
}
});
EditorUtils.registerTool("separator", new Tool({ ui: { type: "separator" } }));
EditorUtils.registerTool("undo", new UndoTool({
key: "Z",
ctrl: true
}));
EditorUtils.registerTool("redo", new UndoTool({
key: "Y",
ctrl: true
}));
var emptyElementContent = "";
var emptyTableCellContent = emptyElementContent;
if (browser.msie || browser.edge) emptyTableCellContent = emptyElementContent = " ";
extend(kendo.ui, { editor: {
EditorUtils,
Tool,
emptyElementContent,
emptyTableCellContent
} });
if (kendo.PDFMixin) {
kendo.PDFMixin.extend(Editor.prototype);
Editor.prototype._drawPDF = function() {
return kendo.drawing.drawDOM(this.body, this.options.pdf);
};
Editor.prototype.saveAsPDF = function() {
var progress = new $.Deferred();
var promise = progress.promise();
var args = { promise };
if (this.trigger("pdfExport", args)) return;
var options = this.options.pdf;
this._drawPDF(progress).then(function(root) {
return kendo.drawing.exportPDF(root, options);
}).done(function(dataURI) {
kendo.saveAs({
dataURI,
fileName: options.fileName,
proxyURL: options.proxyURL,
proxyTarget: options.proxyTarget,
forceProxy: options.forceProxy
});
progress.resolve();
}).fail(function(err) {
progress.reject(err);
});
return promise;
};
}
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/dom.js
(function($) {
var kendo = window.kendo, map = $.map, extend = $.extend, browser = kendo.support.browser, STYLE = "style", FLOAT = "float", CSSFLOAT = "cssFloat", STYLEFLOAT = "styleFloat", CLASS = "class", KMARKER = "k-marker";
function makeMap(items) {
var obj = {}, i, len;
for (i = 0, len = items.length; i < len; i++) obj[items[i]] = true;
return obj;
}
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed".split(",")), nonListBlockElements = "p,div,h1,h2,h3,h4,h5,h6,address,applet,blockquote,button,center,dd,dir,dl,dt,fieldset,form,frameset,hr,iframe,isindex,map,menu,noframes,noscript,object,pre,script,table,tbody,td,tfoot,th,thead,tr,header,article,nav,footer,section,aside,main,figure,figcaption".split(","), blockElements = nonListBlockElements.concat([
"ul",
"ol",
"li"
]), block = makeMap(blockElements), selfClosing = makeMap("area,base,br,col,command,embed,hr,img,input,keygen,link,menuitem,meta,param,source,track,wbr".split(",")), inlineElements = "span,em,a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,strike,strong,sub,sup,textarea,tt,u,var,data,time,mark,ruby".split(","), inline = makeMap(inlineElements), fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected".split(",")), nonEmptyNonTextContentElements = [
"hgroup",
"ol",
"ul",
"dl",
"object",
"video",
"audio",
"table",
"colgroup",
"tbody",
"thead",
"tfoot",
"tr",
"select",
"optgroup"
];
var normalize = function(node) {
if (node.nodeType == 1) node.normalize();
};
if (browser.msie && browser.version >= 8) normalize = function(parent) {
if (parent.nodeType == 1 && parent.firstChild) {
var prev = parent.firstChild, node = prev;
normalize(node);
while (true) {
node = node.nextSibling;
if (!node) break;
normalize(node);
if (node.nodeType == 3 && prev.nodeType == 3) {
node.nodeValue = prev.nodeValue + node.nodeValue;
Dom.remove(prev);
}
prev = node;
}
}
};
var whitespace = /^\s+$/, emptyspace = /^[\n\r\t]+$/, rgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i, bom = /\ufeff/g, whitespaceOrBom = /^(\s+|\ufeff)$/, persistedScrollTop, cssAttributes = "color,padding-left,padding-right,padding-top,padding-bottom,background-color,background-attachment,background-image,background-position,background-repeat,border-top-style,border-top-width,border-top-color,border-bottom-style,border-bottom-width,border-bottom-color,border-left-style,border-left-width,border-left-color,border-right-style,border-right-width,border-right-color,font-family,font-size,font-style,font-variant,font-weight,line-height".split(","), htmlRe = /[<>&]/g, entityRe = /[\u00A0-\u2666<>&]/g, entityTable = {
34: "quot",
38: "amp",
39: "apos",
60: "lt",
62: "gt",
160: "nbsp",
161: "iexcl",
162: "cent",
163: "pound",
164: "curren",
165: "yen",
166: "brvbar",
167: "sect",
168: "uml",
169: "copy",
170: "ordf",
171: "laquo",
172: "not",
173: "shy",
174: "reg",
175: "macr",
176: "deg",
177: "plusmn",
178: "sup2",
179: "sup3",
180: "acute",
181: "micro",
182: "para",
183: "middot",
184: "cedil",
185: "sup1",
186: "ordm",
187: "raquo",
188: "frac14",
189: "frac12",
190: "frac34",
191: "iquest",
192: "Agrave",
193: "Aacute",
194: "Acirc",
195: "Atilde",
196: "Auml",
197: "Aring",
198: "AElig",
199: "Ccedil",
200: "Egrave",
201: "Eacute",
202: "Ecirc",
203: "Euml",
204: "Igrave",
205: "Iacute",
206: "Icirc",
207: "Iuml",
208: "ETH",
209: "Ntilde",
210: "Ograve",
211: "Oacute",
212: "Ocirc",
213: "Otilde",
214: "Ouml",
215: "times",
216: "Oslash",
217: "Ugrave",
218: "Uacute",
219: "Ucirc",
220: "Uuml",
221: "Yacute",
222: "THORN",
223: "szlig",
224: "agrave",
225: "aacute",
226: "acirc",
227: "atilde",
228: "auml",
229: "aring",
230: "aelig",
231: "ccedil",
232: "egrave",
233: "eacute",
234: "ecirc",
235: "euml",
236: "igrave",
237: "iacute",
238: "icirc",
239: "iuml",
240: "eth",
241: "ntilde",
242: "ograve",
243: "oacute",
244: "ocirc",
245: "otilde",
246: "ouml",
247: "divide",
248: "oslash",
249: "ugrave",
250: "uacute",
251: "ucirc",
252: "uuml",
253: "yacute",
254: "thorn",
255: "yuml",
402: "fnof",
913: "Alpha",
914: "Beta",
915: "Gamma",
916: "Delta",
917: "Epsilon",
918: "Zeta",
919: "Eta",
920: "Theta",
921: "Iota",
922: "Kappa",
923: "Lambda",
924: "Mu",
925: "Nu",
926: "Xi",
927: "Omicron",
928: "Pi",
929: "Rho",
931: "Sigma",
932: "Tau",
933: "Upsilon",
934: "Phi",
935: "Chi",
936: "Psi",
937: "Omega",
945: "alpha",
946: "beta",
947: "gamma",
948: "delta",
949: "epsilon",
950: "zeta",
951: "eta",
952: "theta",
953: "iota",
954: "kappa",
955: "lambda",
956: "mu",
957: "nu",
958: "xi",
959: "omicron",
960: "pi",
961: "rho",
962: "sigmaf",
963: "sigma",
964: "tau",
965: "upsilon",
966: "phi",
967: "chi",
968: "psi",
969: "omega",
977: "thetasym",
978: "upsih",
982: "piv",
8226: "bull",
8230: "hellip",
8242: "prime",
8243: "Prime",
8254: "oline",
8260: "frasl",
8472: "weierp",
8465: "image",
8476: "real",
8482: "trade",
8501: "alefsym",
8592: "larr",
8593: "uarr",
8594: "rarr",
8595: "darr",
8596: "harr",
8629: "crarr",
8656: "lArr",
8657: "uArr",
8658: "rArr",
8659: "dArr",
8660: "hArr",
8704: "forall",
8706: "part",
8707: "exist",
8709: "empty",
8711: "nabla",
8712: "isin",
8713: "notin",
8715: "ni",
8719: "prod",
8721: "sum",
8722: "minus",
8727: "lowast",
8730: "radic",
8733: "prop",
8734: "infin",
8736: "ang",
8743: "and",
8744: "or",
8745: "cap",
8746: "cup",
8747: "int",
8756: "there4",
8764: "sim",
8773: "cong",
8776: "asymp",
8800: "ne",
8801: "equiv",
8804: "le",
8805: "ge",
8834: "sub",
8835: "sup",
8836: "nsub",
8838: "sube",
8839: "supe",
8853: "oplus",
8855: "otimes",
8869: "perp",
8901: "sdot",
8968: "lceil",
8969: "rceil",
8970: "lfloor",
8971: "rfloor",
9001: "lang",
9002: "rang",
9674: "loz",
9824: "spades",
9827: "clubs",
9829: "hearts",
9830: "diams",
338: "OElig",
339: "oelig",
352: "Scaron",
353: "scaron",
376: "Yuml",
710: "circ",
732: "tilde",
8194: "ensp",
8195: "emsp",
8201: "thinsp",
8204: "zwnj",
8205: "zwj",
8206: "lrm",
8207: "rlm",
8211: "ndash",
8212: "mdash",
8216: "lsquo",
8217: "rsquo",
8218: "sbquo",
8220: "ldquo",
8221: "rdquo",
8222: "bdquo",
8224: "dagger",
8225: "Dagger",
8240: "permil",
8249: "lsaquo",
8250: "rsaquo",
8364: "euro"
};
var Dom = {
block,
inline,
findNodeIndex: function(node, skipText) {
var i = 0;
if (!node) return -1;
while (true) {
node = node.previousSibling;
if (!node) break;
if (!(skipText && node.nodeType == 3)) i++;
}
return i;
},
isDataNode: function(node) {
return node && node.nodeValue !== null && node.data !== null;
},
isAncestorOf: function(parent, node) {
try {
return !Dom.isDataNode(parent) && ($.contains(parent, Dom.isDataNode(node) ? node.parentNode : node) || node.parentNode == parent);
} catch (e) {
return false;
}
},
isAncestorOrSelf: function(root, node) {
return Dom.isAncestorOf(root, node) || root == node;
},
findClosestAncestor: function(root, node) {
if (Dom.isAncestorOf(root, node)) while (node && node.parentNode != root) node = node.parentNode;
return node;
},
getAllComments: function(rootElem) {
var comments = [];
var iterator = document.createNodeIterator(rootElem, NodeFilter.SHOW_COMMENT, function() {
return NodeFilter.FILTER_ACCEPT;
}, false);
var curNode = iterator.nextNode();
while (curNode) {
comments.push(curNode.nodeValue);
curNode = iterator.nextNode();
}
return comments;
},
getNodeLength: function(node) {
return Dom.isDataNode(node) ? node.length : node.childNodes.length;
},
splitDataNode: function(node, offset) {
var newNode = node.cloneNode(false);
var denormalizedText = "";
var iterator = node.nextSibling;
var temp;
while (iterator && iterator.nodeType == 3 && iterator.nodeValue) {
denormalizedText += iterator.nodeValue;
temp = iterator;
iterator = iterator.nextSibling;
Dom.remove(temp);
}
node.deleteData(offset, node.length);
newNode.deleteData(0, offset);
newNode.nodeValue += denormalizedText;
Dom.insertAfter(newNode, node);
},
attrEquals: function(node, attributes) {
for (var key in attributes) {
var value = node[key];
if (key == FLOAT) value = node[kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT];
if (typeof value == "object") {
if (!Dom.attrEquals(value, attributes[key])) return false;
} else if (value != attributes[key]) return false;
}
return true;
},
blockParentOrBody: function(node) {
return Dom.parentOfType(node, blockElements) || node.ownerDocument.body;
},
blockParents: function(nodes) {
var blocks = [], i, len;
for (i = 0, len = nodes.length; i < len; i++) {
var block = Dom.parentOfType(nodes[i], Dom.blockElements);
if (block && $.inArray(block, blocks) < 0) blocks.push(block);
}
return blocks;
},
windowFromDocument: function(document) {
return document.defaultView || document.parentWindow;
},
normalize,
blockElements,
nonListBlockElements,
inlineElements,
empty,
fillAttrs,
nodeTypes: {
ELEMENT_NODE: 1,
ATTRIBUTE_NODE: 2,
TEXT_NODE: 3,
CDATA_SECTION_NODE: 4,
ENTITY_REFERENCE_NODE: 5,
ENTITY_NODE: 6,
PROCESSING_INSTRUCTION_NODE: 7,
COMMENT_NODE: 8,
DOCUMENT_NODE: 9,
DOCUMENT_TYPE_NODE: 10,
DOCUMENT_FRAGMENT_NODE: 11,
NOTATION_NODE: 12
},
toHex: function(color) {
var matches = rgb.exec(color);
if (!matches) return color;
return "#" + map(matches.slice(1), function(x) {
x = parseInt(x, 10).toString(16);
return x.length > 1 ? x : "0" + x;
}).join("");
},
encode: function(value, options) {
var encodableChars = !options || options.entities ? entityRe : htmlRe;
return value.replace(encodableChars, function(c) {
var entity = entityTable[c.charCodeAt(0)];
return entity ? "&" + entity + ";" : c;
});
},
isBom: function(node) {
return node && node.nodeType === 3 && /^[\ufeff]+$/.test(node.nodeValue);
},
stripBom: function(text) {
return (text || "").replace(bom, "");
},
stripBomNode: function(node) {
if (Dom.isBom(node)) node.parentNode.removeChild(node);
},
insignificant: function(node) {
var attr = node.attributes;
return node.className == "k-marker" || Dom.is(node, "br") && (node.className == "k-br" || attr._moz_dirty || attr._moz_editor_bogus_node) || Dom.is(node, "span") && node.className == "k-br";
},
tableCell: function(node) {
return Dom.is(node, "td") || Dom.is(node, "th");
},
significantNodes: function(nodes) {
return $.grep(nodes, function(child) {
var name = Dom.name(child);
if (name == "br" || Dom.insignificant(child) || Dom.emptyTextNode(child) || child.nodeType == 1 && !empty[name] && Dom.emptyNode(child)) return false;
return true;
});
},
emptyTextNode: function(node) {
return node && node.nodeType == 3 && whitespaceOrBom.test(node.nodeValue);
},
emptyNode: function(node) {
return node.nodeType == 1 && !Dom.significantNodes(node.childNodes).length;
},
name: function(node) {
return node.nodeName.toLowerCase();
},
significantChildNodes: function(node) {
return $.grep(node.childNodes, function(child) {
return child.nodeType != 3 || !Dom.isWhitespace(child);
});
},
getTextNodes: function(body, nodes) {
const childNodes = body.childNodes;
nodes = nodes || [];
for (const node of childNodes) if (node.nodeType === this.nodeTypes.TEXT_NODE && (blockElements.includes(Dom.name(node.parentNode)) || inlineElements.includes(Dom.name(node.parentNode)) || node.parentNode === body)) nodes.push(node);
else if (node.nodeType === this.nodeTypes.ELEMENT_NODE) this.getTextNodes(node, nodes);
return nodes;
},
lastTextNode: function(node) {
var result = null;
if (node.nodeType == 3) return node;
for (var child = node.lastChild; child; child = child.previousSibling) {
result = Dom.lastTextNode(child);
if (result) return result;
}
return result;
},
is: function(node, nodeName) {
return node && Dom.name(node) == nodeName;
},
isMarker: function(node) {
return node.className == KMARKER;
},
isWhitespace: function(node) {
return whitespace.test(node.nodeValue);
},
allowsTextContent: function(node) {
var result = true;
nonEmptyNonTextContentElements.every(function(name) {
if (Dom.is(node, name)) {
result = false;
return false;
} else return true;
});
return result;
},
allWhitespaceContent: function(node) {
var child = node.firstChild;
while (child && Dom.isWhitespace(child)) child = child.nextSibling;
return !child;
},
isEmptyspace: function(node) {
return emptyspace.test(node.nodeValue);
},
htmlIndentSpace: function(node) {
if (!(Dom.isDataNode(node) && Dom.isWhitespace(node))) return false;
if (emptyspace.test(node.nodeValue)) return true;
var sibling = function(el, direction) {
while (el[direction]) {
el = el[direction];
if (Dom.significantNodes([el]).length > 0) return el;
}
};
var parent = node.parentNode;
var prev = sibling(node, "previousSibling");
var next = sibling(node, "nextSibling");
if (bom.test(node.nodeValue)) return !!(prev || next);
if ($(parent).is("tr,tbody,thead,tfoot,table,ol,ul")) return true;
if (Dom.isBlock(parent) || Dom.is(parent, "body")) {
var isPrevBlock = prev && Dom.isBlock(prev);
var isNextBlock = next && Dom.isBlock(next);
if (!next && isPrevBlock || !prev && isNextBlock || isPrevBlock && isNextBlock) return true;
}
return false;
},
isBlock: function(node) {
return block[Dom.name(node)];
},
isSelfClosing: function(node) {
return selfClosing[Dom.name(node)];
},
isEmpty: function(node) {
return empty[Dom.name(node)];
},
isInline: function(node) {
return inline[Dom.name(node)];
},
isImg: function(node) {
return Dom.name(node) == "img";
},
isBr: function(node) {
return Dom.name(node) == "br";
},
list: function(node) {
var name = node ? Dom.name(node) : "";
return name == "ul" || name == "ol" || name == "dl";
},
scrollContainer: function(doc) {
var wnd = Dom.windowFromDocument(doc), scrollContainer = (wnd.contentWindow || wnd).document || wnd.ownerDocument || wnd;
if (scrollContainer.compatMode == "BackCompat") scrollContainer = scrollContainer.body;
else scrollContainer = scrollContainer.scrollingElement || scrollContainer.documentElement;
return scrollContainer;
},
scrollTo: function(node, toStart) {
var doc = node.ownerDocument;
var windowHeight = Dom.windowFromDocument(doc).innerHeight;
var scrollContainer = Dom.scrollContainer(doc);
var element, elementTop, elementHeight, marker;
if (Dom.isDataNode(node)) if (toStart) {
marker = Dom.create(doc, "span", { "innerHTML": "" });
Dom.insertBefore(marker, node);
element = $(marker);
} else element = $(node.parentNode);
else element = $(node);
elementTop = element.offset().top;
elementHeight = element[0].offsetHeight;
if (toStart || !elementHeight) elementHeight = parseInt(element.css("line-height"), 10) || Math.ceil(1.2 * parseInt(element.css("font-size"), 10)) || 15;
if (marker) Dom.remove(marker);
if (elementHeight + elementTop > scrollContainer.scrollTop + windowHeight) scrollContainer.scrollTop = elementHeight + elementTop - windowHeight;
},
persistScrollTop: function(doc) {
persistedScrollTop = Dom.scrollContainer(doc).scrollTop;
},
offset: function(target, offsetParent) {
var result = {
top: target.offsetTop,
left: target.offsetLeft
};
var parent = target.offsetParent;
while (parent && (!offsetParent || Dom.isAncestorOf(offsetParent, parent))) {
result.top += parent.offsetTop;
result.left += parent.offsetLeft;
parent = parent.offsetParent;
}
return result;
},
restoreScrollTop: function(doc) {
if (typeof persistedScrollTop == "number") {
Dom.scrollContainer(doc).scrollTop = persistedScrollTop;
persistedScrollTop = void 0;
}
},
insertAt: function(parent, newElement, position) {
parent.insertBefore(newElement, parent.childNodes[position] || null);
},
insertBefore: function(newElement, referenceElement) {
if (referenceElement.parentNode) return referenceElement.parentNode.insertBefore(newElement, referenceElement);
else return referenceElement;
},
insertAfter: function(newElement, referenceElement) {
return referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
},
remove: function(node) {
if (node.parentNode) node.parentNode.removeChild(node);
},
removeChildren: function(node) {
while (node.firstChild) node.removeChild(node.firstChild);
},
removeTextSiblings: function(node) {
var parentNode = node.parentNode;
while (node.nextSibling && node.nextSibling.nodeType == 3) parentNode.removeChild(node.nextSibling);
while (node.previousSibling && node.previousSibling.nodeType == 3) parentNode.removeChild(node.previousSibling);
},
trim: function(parent) {
for (var i = parent.childNodes.length - 1; i >= 0; i--) {
var node = parent.childNodes[i];
if (Dom.isDataNode(node)) {
if (!Dom.stripBom(node.nodeValue).length) Dom.remove(node);
} else if (node.className != KMARKER) {
Dom.trim(node);
if (!Dom.isEmpty(node) && node.childNodes.length === 0 || Dom.isBlock(node) && Dom.allWhitespaceContent(node)) Dom.remove(node);
}
}
return parent;
},
closest: function(node, tags) {
if (typeof tags === "string") tags = [tags];
while (node && tags.indexOf(Dom.name(node)) < 0) node = node.parentNode;
return node;
},
closestBy: function(node, condition, rootCondition) {
while (node && !condition(node)) {
if (rootCondition && rootCondition(node)) return null;
node = node.parentNode;
}
return node;
},
sibling: function(node, direction) {
do
node = node[direction];
while (node && node.nodeType != 1);
return node;
},
next: function(node) {
return Dom.sibling(node, "nextSibling");
},
prev: function(node) {
return Dom.sibling(node, "previousSibling");
},
parentOfType: function(node, tags) {
do
node = node.parentNode;
while (node && !Dom.ofType(node, tags));
return node;
},
ofType: function(node, tags) {
return $.inArray(Dom.name(node), tags) >= 0;
},
changeTag: function(referenceElement, tagName, skipAttributes) {
var newElement = Dom.create(referenceElement.ownerDocument, tagName), attributes = referenceElement.attributes, i, len, name, value, attribute;
if (!skipAttributes) for (i = 0, len = attributes.length; i < len; i++) {
attribute = attributes[i];
if (attribute.specified) {
name = attribute.nodeName;
value = attribute.nodeValue;
if (name == CLASS) newElement.className = value;
else if (name == STYLE) newElement.style.cssText = referenceElement.style.cssText;
else newElement.setAttribute(name, value);
}
}
while (referenceElement.firstChild) newElement.appendChild(referenceElement.firstChild);
Dom.insertBefore(newElement, referenceElement);
Dom.remove(referenceElement);
return newElement;
},
editableParent: function(node) {
while (node && (node.nodeType == 3 || node.contentEditable !== "true")) node = node.parentNode;
return node;
},
wrap: function(node, wrapper) {
Dom.insertBefore(wrapper, node);
wrapper.appendChild(node);
return wrapper;
},
unwrap: function(node) {
var parent = node.parentNode;
while (node.firstChild) parent.insertBefore(node.firstChild, node);
parent.removeChild(node);
},
wrapper: function(node) {
var wrapper = Dom.closestBy(node, function(el) {
return el.parentNode && Dom.significantNodes(el.parentNode.childNodes).length > 1;
});
return $(wrapper).is("body,.k-editor") ? void 0 : wrapper;
},
isChildOfBaseContainer: function(node) {
return $(node).parent().is("body,.k-editor");
},
create: function(document, tagName, attributes) {
return Dom.attr(document.createElement(tagName), attributes);
},
createEmptyNode: function(document, tagName, attributes) {
var node = Dom.attr(document.createElement(tagName), attributes);
node.innerHTML = "";
return node;
},
attr: function(element, attributes) {
attributes = extend({}, attributes);
if (attributes && STYLE in attributes) {
Dom.style(element, attributes.style);
delete attributes.style;
}
for (var attr in attributes) if (attributes[attr] === null) {
element.removeAttribute(attr);
delete attributes[attr];
} else if (attr == "className") element[attr] = attributes[attr];
return extend(element, attributes);
},
mergeAttributes: function(origin, target, traverseCss) {
if (!origin.attributes.length) return;
$.each(origin.attributes, function() {
if (this.name !== "contenteditable" && (!traverseCss || this.name !== STYLE)) $(target).attr(this.name, this.value);
if (traverseCss && this.name === STYLE) $.each(origin.style, function() {
target.style[this] = origin.style[this];
});
});
},
style: function(node, value) {
$(node).css(value || {});
},
unstyle: function(node, value) {
for (var key in value) if (key == FLOAT) node.style[kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT] = "";
else node.style[key] = "";
if (node.style.cssText === "") node.removeAttribute(STYLE);
},
inlineStyle: function(body, name, attributes) {
var span = $(Dom.create(body.ownerDocument, name, attributes)), style;
body.appendChild(span[0]);
style = map(cssAttributes, function(value) {
if (browser.msie && value == "line-height" && span.css(value) == "1px") return "line-height:1.5";
else return value + ":" + span.css(value);
}).join(";");
span.remove();
return style;
},
getEffectiveBackground: function(element) {
var backgroundStyle = element.css("background-color") || "";
if (backgroundStyle.indexOf("rgba(0, 0, 0, 0") < 0 && backgroundStyle !== "transparent") return backgroundStyle;
else if (element[0].tagName.toLowerCase() === "html") return "Window";
else return Dom.getEffectiveBackground(element.parent());
},
innerText: function(node) {
var text = node.innerHTML;
text = text.replace(/<!--(.|\s)*?-->/gi, "");
text = text.replace(/<\/?[^>]+?\/?>/gm, "");
return text;
},
removeClass: function(node, classNames) {
var className = " " + node.className + " ", classes = classNames.split(" "), i, len;
for (i = 0, len = classes.length; i < len; i++) className = className.replace(" " + classes[i] + " ", " ");
className = kendo.trim(className);
if (className.length) node.className = className;
else node.removeAttribute(CLASS);
},
commonAncestor: function() {
var count = arguments.length, paths = [], minPathLength = Infinity, output = null, i, ancestors, node, first, j;
if (!count) return null;
if (count == 1) return arguments[0];
for (i = 0; i < count; i++) {
ancestors = [];
node = arguments[i];
while (node) {
ancestors.push(node);
node = node.parentNode;
}
paths.push(ancestors.reverse());
minPathLength = Math.min(minPathLength, ancestors.length);
}
for (i = 0; i < minPathLength; i++) {
first = paths[0][i];
for (j = 1; j < count; j++) if (first != paths[j][i]) return output;
output = first;
}
return output;
},
closestSplittableParent: function(nodes) {
var result;
if (nodes.length == 1) result = Dom.parentOfType(nodes[0], ["ul", "ol"]);
else result = Dom.commonAncestor.apply(null, nodes);
if (!result) result = Dom.parentOfType(nodes[0], ["p", "td"]) || nodes[0].ownerDocument.body;
if (Dom.isInline(result)) result = Dom.blockParentOrBody(result);
var editableParents = map(nodes, Dom.editableParent);
var editableAncestor = Dom.commonAncestor(editableParents)[0];
if ($.contains(result, editableAncestor)) result = editableAncestor;
return result;
},
closestEditable: function(node, types) {
var closest;
var editable = Dom.editableParent(node);
if (Dom.ofType(node, types)) closest = node;
else closest = Dom.parentOfType(node, types);
if (closest && editable && $.contains(closest, editable) || !closest && editable) closest = editable;
return closest;
},
closestEditableOfType: function(node, types) {
var editable = Dom.closestEditable(node, types);
if (editable && Dom.ofType(editable, types) && !$(editable).is(".k-editor")) return editable;
},
filter: function(tagName, nodes, invert) {
var filterFn = function(node) {
return Dom.name(node) == tagName;
};
return Dom.filterBy(nodes, filterFn, invert);
},
filterBy: function(nodes, condition, invert) {
var i = 0;
var len = nodes.length;
var result = [];
var match;
for (; i < len; i++) {
match = condition(nodes[i]);
if (match && !invert || !match && invert) result.push(nodes[i]);
}
return result;
},
ensureTrailingBreaks: function(node) {
var elements = $(node).find("p,td,th");
var length = elements.length;
var i = 0;
if (length) for (; i < length; i++) Dom.ensureTrailingBreak(elements[i]);
else Dom.ensureTrailingBreak(node);
},
removeTrailingBreak: function(node) {
$(node).find("br[type=_moz],.k-br").remove();
},
ensureTrailingBreak: function(node) {
Dom.removeTrailingBreak(node);
var lastChild = node.lastChild;
var name = lastChild && Dom.name(lastChild);
var br;
if (!name || name != "br" && name != "img" || name == "br" && lastChild.className != "k-br") {
br = node.ownerDocument.createElement("br");
br.className = "k-br";
node.appendChild(br);
}
},
reMapTableColumns: function(table, colAttr) {
Dom._mapColIndices(table, colAttr);
},
clearTableMappings: function(table, colAttr) {
$(table).find("[" + colAttr + "]").removeAttr(colAttr);
},
_mapColIndices: function(table, colAttr) {
var registeredColumns = {};
for (var rowIndex = 0; rowIndex < table.rows.length; rowIndex++) {
var cells = table.rows[rowIndex].cells;
var colIndex = 0;
for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {
var cell = cells[cellIndex];
if (cell.rowSpan > 1) this._mapColspan(cell, rowIndex, colIndex, registeredColumns);
if (registeredColumns[rowIndex]) while (registeredColumns[rowIndex][colIndex]) colIndex++;
cell.setAttribute(colAttr, colIndex);
if (cell.colSpan > 1) colIndex = colIndex + cell.colSpan - 1;
colIndex++;
}
}
},
_mapColspan: function(cell, rowIndex, colIndex, registeredColumns) {
var rowSpan = cell.rowSpan, colSpan = cell.colSpan, index;
for (var ci = 0; ci < colSpan; ci++) {
index = colIndex + ci;
for (var ri = rowIndex + 1; ri < rowIndex + rowSpan; ri++) {
if (!registeredColumns[ri]) {
registeredColumns[ri] = {};
registeredColumns[ri].length = 0;
}
if (registeredColumns[rowIndex]) while (registeredColumns[rowIndex][index]) index++;
registeredColumns[ri][index] = true;
registeredColumns[ri].length++;
}
}
},
associateWithIds: function(table) {
var that = this;
var numberOfTheadRows = 0;
var tableRows = table.rows;
var numberOfTableRows = tableRows.length;
var theadMatrix = [];
var tbodyMatrix = [];
var theadRows, i;
if (table.tHead) {
theadRows = table.tHead.rows;
numberOfTheadRows = theadRows.length;
} else {
numberOfTheadRows = that._getNumberOfHeaderRows(table);
theadRows = [];
for (i = 0; i < numberOfTheadRows; i++) theadRows.push(tableRows[i]);
}
for (i = 0; i < numberOfTheadRows; i++) theadMatrix.push([]);
for (i = 0; i < numberOfTableRows; i++) tbodyMatrix.push([]);
that._generateIdsForColumns(theadMatrix, theadRows);
that._generateIdsForRows(theadMatrix, tbodyMatrix, numberOfTheadRows, tableRows);
that._assignIds(theadMatrix, tbodyMatrix, numberOfTheadRows, tableRows);
},
_generateIdsForColumns: function(theadMatrix, theadRows) {
var timestamp = (/* @__PURE__ */ new Date()).getTime();
var numberOfTheadRows = theadRows ? theadRows.length : 0;
var row, cells, cell, col, id, colspan, rowspan, i, j, k, l;
for (i = 0; i < numberOfTheadRows; i++) {
row = theadRows[i];
cells = row.cells;
col = 0;
for (j = 0; j < cells.length; j++) {
cell = cells[j];
id = "table" + i + j + ++timestamp;
cell.setAttribute("id", id);
colspan = cell.getAttribute("colspan") || 1;
rowspan = cell.getAttribute("rowspan") || 1;
while (theadMatrix[i][j + col]) col += 1;
for (k = 0; k < rowspan; k++) for (l = 0; l < colspan; l++) theadMatrix[i + k][j + col + l] = id;
}
}
},
_generateIdsForRows: function(theadMatrix, tbodyMatrix, numberOfTheadRows, tableRows) {
var that = this;
var timestamp = (/* @__PURE__ */ new Date()).getTime();
var numberOfTableRows = tableRows.length;
var row, cells, cell, col, id, colspan, rowspan, i, j, k, l, colIndex, headers;
var pushHeaderId = function(row) {
headers.push(row[colIndex]);
};
for (i = numberOfTheadRows; i < numberOfTableRows; i++) {
row = tableRows[i];
cells = $(row.cells).filter("th");
col = 0;
for (j = 0; j < cells.length; j++) {
cell = cells[j];
id = "table" + i + j + ++timestamp;
cell.setAttribute("id", id);
colspan = cell.getAttribute("colspan") || 1;
rowspan = cell.getAttribute("rowspan") || 1;
while (tbodyMatrix[i][j + col]) col += 1;
for (k = 0; k < rowspan; k++) for (l = 0; l < colspan; l++) tbodyMatrix[i + k][j + col + l] = id;
colIndex = cell.getAttribute("col-index");
headers = [];
theadMatrix.forEach(pushHeaderId);
headers = headers.filter(that._onlyUnique);
cell.setAttribute("headers", headers.join(" ").trim());
}
}
},
_assignIds: function(theadMatrix, tbodyMatrix, numberOfTheadRows, tableRows) {
var that = this;
var numberOfTableRows = tableRows.length;
var row, cells, cell, i, j, colIndex, headers;
var pushHeaderId = function(row) {
headers.push(row[colIndex]);
};
for (i = numberOfTheadRows; i < numberOfTableRows; i++) {
row = tableRows[i];
cells = $(row.cells).filter("td");
for (j = 0; j < cells.length; j++) {
cell = cells[j];
colIndex = cell.getAttribute("col-index");
headers = tbodyMatrix[i].slice();
theadMatrix.forEach(pushHeaderId);
headers = headers.filter(that._onlyUnique);
cell.setAttribute("headers", headers.join(" ").trim());
}
}
},
_getNumberOfColumns: function(table) {
var cells = $(table).find("th, td");
var numberOfCols = 0;
var cell, i, currentIndex;
for (i = 0; i < cells.length; i++) {
cell = cells[i];
currentIndex = Number(cell.getAttribute("col-index")) + 1;
if (currentIndex > numberOfCols) numberOfCols = currentIndex;
}
return numberOfCols;
},
_getNumberOfHeaderColumns: function(table, numberOfHeaderRows) {
var rows = table.rows;
var numberOfCols = 0;
var currentIndex, row, i, j, cell;
for (i = numberOfHeaderRows; i < rows.length; i++) {
row = rows[i];
for (j = 0; j < row.cells.length; j++) {
cell = row.cells[j];
if (this.is(cell, "th")) {
currentIndex = Number(cell.getAttribute("col-index")) + 1;
if (currentIndex > numberOfCols) numberOfCols = currentIndex;
}
}
}
return numberOfCols;
},
_getNumberOfHeaderRows: function(table) {
var rows = table.rows;
var number = table.tHead && table.tHead.rows ? table.tHead.rows.length : 0;
var j, row, cell, length;
if (number === 0) {
row = rows[0];
length = row.cells && row.cells.length;
while (row && length && this.is(row.cells[0], "th")) {
for (j = 0; j < length; j++) {
cell = row ? row.cells[j] : null;
if (!this.is(cell, "th")) row = null;
}
if (row) {
number += 1;
row = this.next(row);
length = row && row.cells && row.cells.length;
}
}
}
return number;
},
_onlyUnique: function(value, index, self) {
return self.indexOf(value) === index;
}
};
kendo.ui.editor.Dom = Dom;
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/serializer.js
(function($, undefined) {
var kendo = window.kendo;
var Editor = kendo.ui.editor;
var dom = Editor.Dom;
var extend = $.extend;
var fontSizeMappings = "xx-small,x-small,small,medium,large,x-large,xx-large".split(",");
var quoteRe = /"/g;
var brRe = /<br[^>]*>/i;
var pixelRe = /^\d+(\.\d*)?(px)?$/i;
var emptyPRe = /<p>(?: )?<\/p>/i;
var cssDeclaration = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/g;
var sizzleAttr = /^sizzle-\d+/i;
var scriptAttr = /^k-script-/i;
var onerrorRe = /\s*onerror\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/i;
var br = "<br class=\"k-br\">";
var bomSpan = "<span class='k-br'></span>";
var div = document.createElement("div");
div.innerHTML = " <hr>";
var supportsLeadingWhitespace = div.firstChild.nodeType === 3;
div = null;
var isFunction = kendo.isFunction;
var TD = "td";
var Serializer = {
toEditableHtml: function(html) {
return (html || "").replace(/<!\[CDATA\[(.*)?\]\]>/g, "<!--[CDATA[$1]]-->").replace(/<(\/?)script([^>]*)>/gi, "<$1k:script$2>").replace(/<img([^>]*)>/gi, function(match) {
return match.replace(onerrorRe, "");
}).replace(/(<\/?img[^>]*>)[\r\n\v\f\t ]+/gi, "$1").replace(/^<(table|blockquote)/i, br + "<$1").replace(/^[\s]*( |\u00a0)/i, "$1").replace(/<\/(table|blockquote)>$/i, "</$1>" + br);
},
_toEditableImmutables: function(body) {
var immutable = Editor.Immutables.immutable, emptyTextNode = dom.emptyTextNode, first = body.firstChild, last = body.lastChild;
while (emptyTextNode(first)) first = first.nextSibling;
while (emptyTextNode(last)) last = last.previousSibling;
if (first && immutable(first)) $(bomSpan).prependTo(body);
if (last && immutable(last)) $(bomSpan).appendTo(body);
},
_fillEmptyElements: function(body) {
$(body).find("p,td").each(function() {
var p = $(this);
if (/^\s*$/g.test(p.text()) && !p.find("img,input").length) {
var node = this;
while (node.children[0] && node.children[0].nodeType != 3) node = node.children[0];
if (node.nodeType == 1 && !dom.empty[dom.name(node)]) if (dom.is(node, "td")) node.innerHTML = kendo.ui.editor.emptyTableCellContent;
else node.innerHTML = kendo.ui.editor.emptyElementContent;
}
});
},
_removeSystemElements: function(body) {
$(".k-paste-container", body).remove();
},
_resetOrderedLists: function(root) {
var ols = root.getElementsByTagName("ol"), i, ol, originalStart;
for (i = 0; i < ols.length; i++) {
ol = ols[i];
originalStart = ol.getAttribute("start");
ol.setAttribute("start", 1);
if (originalStart) ol.setAttribute("start", originalStart);
else ol.removeAttribute(originalStart);
}
},
_preventScriptExecution: function(root) {
$(root).find("*").each(function() {
var attributes = this.attributes;
var attribute, i, l, name;
var attributesToRemove = [];
for (i = 0, l = attributes.length; i < l; i++) {
attribute = attributes[i];
name = attribute.nodeName;
if (attribute.specified && /^on/i.test(name)) {
this.setAttribute("k-script-" + name, attribute.value);
attributesToRemove.push(name);
}
}
for (i = 0, l = attributesToRemove.length; i < l; i++) this.removeAttribute(attributesToRemove[i]);
});
},
htmlToDom: function(html, root, options) {
var msie = kendo.support.browser.msie;
var o = options || {};
var immutables = o.immutables;
html = Serializer.toEditableHtml(html);
if (isFunction(o.custom)) html = o.custom(html) || html;
root.innerHTML = html;
if (immutables) immutables.deserialize(root);
if (msie) {
dom.normalize(root);
Serializer._resetOrderedLists(root);
}
Serializer._preventScriptExecution(root);
Serializer._fillEmptyElements(root);
Serializer._removeSystemElements(root);
Serializer._toEditableImmutables(root);
$("table", root).addClass("k-table");
return root;
},
domToXhtml: function(root, options) {
var result = [];
var immutables = options && options.immutables;
function semanticFilter(attributes) {
return $.grep(attributes, function(attr) {
return attr.name != "style";
});
}
function mapStart(node, tag) {
result.push("<" + tag);
attr(node);
result.push(">");
}
var tagMap = {
iframe: {
start: function(node) {
mapStart(node, "iframe");
},
end: function() {
result.push("</iframe>");
}
},
"k:script": {
start: function(node) {
mapStart(node, "script");
},
end: function() {
result.push("<\/script>");
},
skipEncoding: true
},
span: {
canOptimize: true,
semantic: true,
start: function(node) {
var style = node.style;
var semanticAttributes = semanticFilter(specifiedAttributes(node));
if (semanticAttributes.length) {
result.push("<span");
attr(node, semanticAttributes);
result.push(">");
}
if (style.textDecoration == "underline" || style.textDecorationLine == "underline") result.push("<u>");
var font = [];
if (style.color) font.push("color=\"" + dom.toHex(style.color) + "\"");
if (style.fontFamily) font.push("face=\"" + style.fontFamily + "\"");
if (style.fontSize) {
var size = $.inArray(style.fontSize, fontSizeMappings);
font.push("size=\"" + size + "\"");
}
var inlineStyles = [];
var ignoredStylePrefixes = [
"text-decoration",
"text-decoration-line",
"color",
"font"
];
for (let i = 0; i < style.length; i++) {
var inlineStyle = style[i];
if (ignoredStylePrefixes.filter((prop) => inlineStyle.startsWith(prop)).length <= 0) inlineStyles.push(`${inlineStyle}: ${style[inlineStyle]}`);
}
if (inlineStyles.length) font.push("style=\"" + inlineStyles.join(";") + "\"");
if (font.length) result.push("<font " + font.join(" ") + ">");
},
end: function(node) {
var style = node.style;
if (style.color || style.fontFamily || style.fontSize) result.push("</font>");
if (style.textDecoration == "underline" || style.textDecorationLine == "underline") result.push("</u>");
if (semanticFilter(specifiedAttributes(node)).length) result.push("</span>");
}
},
strong: {
semantic: true,
start: function(node) {
mapStart(node, "b");
},
end: function() {
result.push("</b>");
}
},
em: {
semantic: true,
start: function(node) {
mapStart(node, "i");
},
end: function() {
result.push("</i>");
}
},
b: {
semantic: false,
start: function(node) {
mapStart(node, "strong");
},
end: function() {
result.push("</strong>");
}
},
i: {
semantic: false,
start: function(node) {
mapStart(node, "em");
},
end: function() {
result.push("</em>");
}
},
u: {
semantic: false,
start: function(node) {
result.push("<span");
var attributes = specifiedAttributes(node);
var style = $(attributes).filter(function(i, item) {
return item.name == "style";
})[0];
var styleObj = {
nodeName: "style",
value: "text-decoration:underline;"
};
if (style) {
styleObj.value = style.value.replace(/text-decoration-line\s*:\s*underline;?/i, "");
if (!/text-decoration/i.test(styleObj.value)) styleObj.value = "text-decoration:underline;" + styleObj.value;
attributes.splice($.inArray(style, attributes), 1);
}
attributes.push(styleObj);
attr(node, attributes);
result.push(">");
},
end: function() {
result.push("</span>");
}
},
font: {
canOptimize: true,
semantic: false,
start: function(node) {
result.push("<span style=\"");
var color = node.getAttribute("color");
var size = fontSizeMappings[node.getAttribute("size")];
var face = node.getAttribute("face");
if (color) {
result.push("color:");
result.push(dom.toHex(color));
result.push(";");
}
if (face) {
result.push("font-family:");
result.push(face);
result.push(";");
}
if (size) {
result.push("font-size:");
result.push(size);
result.push(";");
}
result.push("\">");
},
end: function() {
result.push("</span>");
}
}
};
tagMap.script = tagMap["k:script"];
options = options || {};
if (typeof options.semantic == "undefined") options.semantic = true;
function cssProperties(cssText) {
var trim = kendo.trim;
var css = trim(cssText);
var match;
var property, value;
var properties = [];
cssDeclaration.lastIndex = 0;
while (true) {
match = cssDeclaration.exec(css);
if (!match) break;
property = trim(match[1].toLowerCase());
value = trim(match[2]);
if (property == "font-size-adjust" || property == "font-stretch") continue;
if (property.indexOf("color") >= 0) value = dom.toHex(value);
else if (property.indexOf("font") >= 0) value = value.replace(quoteRe, "'");
else if (/\burl\(/g.test(value)) value = value.replace(quoteRe, "");
properties.push({
property,
value
});
}
return properties;
}
function styleAttr(cssText) {
var properties = cssProperties(cssText);
var i;
for (i = 0; i < properties.length; i++) {
result.push(properties[i].property);
result.push(":");
result.push(properties[i].value);
result.push(";");
}
}
function specifiedAttributes(node) {
var result = [];
var attributes = node.attributes;
var attribute, i, l;
var name, value, specified;
for (i = 0, l = attributes.length; i < l; i++) {
attribute = attributes[i];
name = attribute.nodeName;
value = attribute.value;
specified = attribute.specified;
if (name == "value" && "value" in node && node.value) specified = true;
else if (name == "type" && value == "text") specified = true;
else if (name == "class" && !value) specified = false;
else if (sizzleAttr.test(name)) specified = false;
else if (name == "complete") specified = false;
else if (name == "altHtml") specified = false;
else if (name == "start" && dom.is(node, "ul")) specified = false;
else if (name == "start" && dom.is(node, "ol") && value == "1") specified = false;
else if (name.indexOf("_moz") >= 0) specified = false;
else if (scriptAttr.test(name)) specified = !!options.scripts;
else if (name == "data-role" && value == "resizable" && (dom.is(node, "tr") || dom.is(node, "td"))) specified = false;
if (specified) result.push(attribute);
}
return result;
}
function attr(node, attributes) {
var i, l, attribute, name, value;
attributes = attributes || specifiedAttributes(node);
if (dom.is(node, "img")) {
var width = node.style.width, height = node.style.height, $node = $(node);
if (width && pixelRe.test(width)) {
$node.attr("width", parseInt(width, 10));
dom.unstyle(node, { width: undefined });
}
if (height && pixelRe.test(height)) {
$node.attr("height", parseInt(height, 10));
dom.unstyle(node, { height: undefined });
}
}
if (!attributes.length) return;
for (i = 0, l = attributes.length; i < l; i++) {
attribute = attributes[i];
name = attribute.nodeName;
value = attribute.value;
if (name == "class" && value == "k-table") continue;
name = name.replace(scriptAttr, "");
result.push(" ");
result.push(name);
result.push("=\"");
if (name == "style") styleAttr(value || node.style.cssText);
else if (name == "src" || name == "href") result.push(kendo.htmlEncode(node.getAttribute(name, 2)));
else result.push(dom.fillAttrs[name] ? name : value);
result.push("\"");
}
}
function children(node, skip, skipEncoding) {
for (var childNode = node.firstChild; childNode; childNode = childNode.nextSibling) child(childNode, skip, skipEncoding);
}
function text(node) {
return node.nodeValue.replace(/\ufeff/g, "");
}
function isEmptyBomNode(node) {
if (dom.isBom(node)) {
do {
node = node.parentNode;
if (dom.is(node, TD) && node.childNodes.length === 1) return true;
if (node.childNodes.length !== 1) return false;
} while (!dom.isBlock(node));
return true;
}
return false;
}
function child(node, skip, skipEncoding) {
var nodeType = node.nodeType, tagName, mapper, parent, value, previous, jqNode;
if (immutables && Editor.Immutables.immutable(node)) result.push(immutables.serialize(node));
else if (nodeType == 1) {
tagName = dom.name(node);
jqNode = $(node);
if (jqNode.hasClass("k-element-resize-handle-wrapper") || jqNode.hasClass("k-column-resize-handle-wrapper") || jqNode.hasClass("k-row-resize-handle-wrapper")) return;
if (!tagName || dom.insignificant(node)) return;
if (!options.scripts && (tagName == "script" || tagName == "k:script")) return;
mapper = tagMap[tagName];
if (mapper) {
if (mapper.canOptimize && options.optimizeTags && shouldOptimize(node)) {
children(node, false, mapper.skipEncoding);
return;
}
if (typeof mapper.semantic == "undefined" || options.semantic ^ mapper.semantic) {
mapper.start(node);
children(node, false, mapper.skipEncoding);
mapper.end(node);
return;
}
}
result.push("<");
result.push(tagName);
attr(node);
if (dom.empty[tagName] || dom.isSelfClosing(node)) result.push(" />");
else {
result.push(">");
children(node, skip || dom.is(node, "pre"));
result.push("</");
result.push(tagName);
result.push(">");
}
} else if (nodeType == 3) {
if (isEmptyBomNode(node)) {
result.push(" ");
return;
}
value = text(node);
if (!skip && supportsLeadingWhitespace) {
parent = node.parentNode;
previous = node.previousSibling;
if (!previous) previous = (dom.isInline(parent) ? parent : node).previousSibling;
if (!previous || previous.innerHTML === "" || dom.isBlock(previous)) if (options.keepEOL) value = value.replace(/[\r\n\v\f\t ]+/, " ");
else value = value.replace(/^[\r\n\v\f\t ]+/, "");
value = value.replace(/ +/, " ");
}
result.push(skipEncoding ? value : dom.encode(value, options));
} else if (nodeType == 4) {
result.push("<![CDATA[");
result.push(node.data);
result.push("]]>");
} else if (nodeType == 8) if (node.data.indexOf("[CDATA[") < 0) {
result.push("<!--");
result.push(node.data);
result.push("-->");
} else {
result.push("<!");
result.push(node.data);
result.push(">");
}
}
function shouldOptimize(node) {
return node.attributes.length === 0;
}
function textOnly(root) {
var childrenCount = root.childNodes.length;
return childrenCount && root.firstChild.nodeType == 3 && (childrenCount == 1 || childrenCount == 2 && dom.insignificant(root.lastChild));
}
function runCustom() {
if (kendo.isFunction(options.custom)) result = options.custom(result) || result;
}
if (textOnly(root)) {
result = dom.encode(text(root.firstChild).replace(/[\r\n\v\f\t ]+/, " "), options);
runCustom();
return result;
}
children(root);
result = result.join("");
runCustom();
if (result.replace(brRe, "").replace(emptyPRe, "") === "") return "";
return result;
}
};
extend(Editor, { Serializer });
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/range.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, browser = kendo.support.browser, dom = Editor.Dom, findNodeIndex = dom.findNodeIndex, isDataNode = dom.isDataNode, findClosestAncestor = dom.findClosestAncestor, getNodeLength = dom.getNodeLength, normalize = dom.normalize;
var SelectionUtils = {
selectionFromWindow: function(window) {
if (!window) return;
if (!("getSelection" in window)) return new W3CSelection(window.document);
return window.getSelection();
},
selectionFromRange: function(range) {
var rangeDocument = RangeUtils.documentFromRange(range);
return SelectionUtils.selectionFromDocument(rangeDocument);
},
selectionFromDocument: function(document) {
return SelectionUtils.selectionFromWindow(dom.windowFromDocument(document));
}
};
var W3CRange = Class.extend({
init: function(doc) {
$.extend(this, {
ownerDocument: doc,
startContainer: doc,
endContainer: doc,
commonAncestorContainer: doc,
startOffset: 0,
endOffset: 0,
collapsed: true
});
},
setStart: function(node, offset) {
this.startContainer = node;
this.startOffset = offset;
updateRangeProperties(this);
fixIvalidRange(this, true);
},
setEnd: function(node, offset) {
this.endContainer = node;
this.endOffset = offset;
updateRangeProperties(this);
fixIvalidRange(this, false);
},
setStartBefore: function(node) {
this.setStart(node.parentNode, findNodeIndex(node));
},
setStartAfter: function(node) {
this.setStart(node.parentNode, findNodeIndex(node) + 1);
},
setEndBefore: function(node) {
this.setEnd(node.parentNode, findNodeIndex(node));
},
setEndAfter: function(node) {
this.setEnd(node.parentNode, findNodeIndex(node) + 1);
},
selectNode: function(node) {
this.setStartBefore(node);
this.setEndAfter(node);
},
selectNodeContents: function(node) {
this.setStart(node, 0);
this.setEnd(node, node[node.nodeType === 1 ? "childNodes" : "nodeValue"].length);
},
collapse: function(toStart) {
var that = this;
if (toStart) that.setEnd(that.startContainer, that.startOffset);
else that.setStart(that.endContainer, that.endOffset);
},
deleteContents: function() {
var that = this, range = that.cloneRange();
if (that.startContainer != that.commonAncestorContainer) that.setStartAfter(findClosestAncestor(that.commonAncestorContainer, that.startContainer));
that.collapse(true);
(function deleteSubtree(iterator) {
while (iterator.next()) if (iterator.hasPartialSubtree()) deleteSubtree(iterator.getSubtreeIterator());
else iterator.remove();
})(new RangeIterator(range));
},
cloneContents: function() {
var document = RangeUtils.documentFromRange(this);
return (function cloneSubtree(iterator) {
var node, frag = document.createDocumentFragment();
while (node = iterator.next()) {
node = node.cloneNode(!iterator.hasPartialSubtree());
if (iterator.hasPartialSubtree()) node.appendChild(cloneSubtree(iterator.getSubtreeIterator()));
frag.appendChild(node);
}
return frag;
})(new RangeIterator(this));
},
extractContents: function() {
var that = this, range = that.cloneRange();
if (that.startContainer != that.commonAncestorContainer) that.setStartAfter(findClosestAncestor(that.commonAncestorContainer, that.startContainer));
that.collapse(true);
var document = RangeUtils.documentFromRange(that);
return (function extractSubtree(iterator) {
var node, frag = document.createDocumentFragment();
while (node = iterator.next()) {
if (iterator.hasPartialSubtree()) {
node = node.cloneNode(false);
node.appendChild(extractSubtree(iterator.getSubtreeIterator()));
} else iterator.remove(that.originalRange);
frag.appendChild(node);
}
return frag;
})(new RangeIterator(range));
},
insertNode: function(node) {
var that = this;
if (isDataNode(that.startContainer)) {
if (that.startOffset != that.startContainer.nodeValue.length) dom.splitDataNode(that.startContainer, that.startOffset);
dom.insertAfter(node, that.startContainer);
} else dom.insertAt(that.startContainer, node, that.startOffset);
that.setStart(that.startContainer, that.startOffset);
},
cloneRange: function() {
return $.extend(new W3CRange(this.ownerDocument), {
startContainer: this.startContainer,
endContainer: this.endContainer,
commonAncestorContainer: this.commonAncestorContainer,
startOffset: this.startOffset,
endOffset: this.endOffset,
collapsed: this.collapsed,
originalRange: this
});
},
toString: function() {
var startNodeName = this.startContainer.nodeName, endNodeName = this.endContainer.nodeName;
return [
startNodeName == "#text" ? this.startContainer.nodeValue : startNodeName,
"(",
this.startOffset,
") : ",
endNodeName == "#text" ? this.endContainer.nodeValue : endNodeName,
"(",
this.endOffset,
")"
].join("");
}
});
W3CRange.fromNode = function(node) {
return new W3CRange(node.ownerDocument);
};
function compareBoundaries(start, end, startOffset, endOffset) {
if (start == end) return endOffset - startOffset;
var container = end;
while (container && container.parentNode != start) container = container.parentNode;
if (container) return findNodeIndex(container) - startOffset;
container = start;
while (container && container.parentNode != end) container = container.parentNode;
if (container) return endOffset - findNodeIndex(container) - 1;
var root = dom.commonAncestor(start, end);
var startAncestor = start;
while (startAncestor && startAncestor.parentNode != root) startAncestor = startAncestor.parentNode;
if (!startAncestor) startAncestor = root;
var endAncestor = end;
while (endAncestor && endAncestor.parentNode != root) endAncestor = endAncestor.parentNode;
if (!endAncestor) endAncestor = root;
if (startAncestor == endAncestor) return 0;
return findNodeIndex(endAncestor) - findNodeIndex(startAncestor);
}
function fixIvalidRange(range, toStart) {
function isInvalidRange(range) {
try {
return compareBoundaries(range.startContainer, range.endContainer, range.startOffset, range.endOffset) < 0;
} catch (ex) {
return true;
}
}
if (isInvalidRange(range)) {
if (toStart) {
range.commonAncestorContainer = range.endContainer = range.startContainer;
range.endOffset = range.startOffset;
} else {
range.commonAncestorContainer = range.startContainer = range.endContainer;
range.startOffset = range.endOffset;
}
range.collapsed = true;
}
}
function updateRangeProperties(range) {
range.collapsed = range.startContainer == range.endContainer && range.startOffset == range.endOffset;
var node = range.startContainer;
while (node && node != range.endContainer && !dom.isAncestorOf(node, range.endContainer)) node = node.parentNode;
range.commonAncestorContainer = node;
}
var RangeIterator = Class.extend({
init: function(range) {
$.extend(this, {
range,
_current: null,
_next: null,
_end: null
});
if (range.collapsed) return;
var root = range.commonAncestorContainer;
this._next = range.startContainer == root && !isDataNode(range.startContainer) ? range.startContainer.childNodes[range.startOffset] : findClosestAncestor(root, range.startContainer);
this._end = range.endContainer == root && !isDataNode(range.endContainer) ? range.endContainer.childNodes[range.endOffset] : findClosestAncestor(root, range.endContainer).nextSibling;
},
hasNext: function() {
return !!this._next;
},
next: function() {
var that = this, current = that._current = that._next;
that._next = that._current && that._current.nextSibling != that._end ? that._current.nextSibling : null;
if (isDataNode(that._current)) {
if (that.range.endContainer == that._current) {
current = current.cloneNode(true);
current.deleteData(that.range.endOffset, current.length - that.range.endOffset);
}
if (that.range.startContainer == that._current) {
current = current.cloneNode(true);
current.deleteData(0, that.range.startOffset);
}
}
return current;
},
traverse: function(callback) {
var that = this, current;
function next() {
that._current = that._next;
that._next = that._current && that._current.nextSibling != that._end ? that._current.nextSibling : null;
return that._current;
}
while (current = next()) if (that.hasPartialSubtree()) that.getSubtreeIterator().traverse(callback);
else callback(current);
return current;
},
remove: function(originalRange) {
var that = this, inStartContainer = that.range.startContainer == that._current, inEndContainer = that.range.endContainer == that._current, start, end, delta;
if (isDataNode(that._current) && (inStartContainer || inEndContainer)) {
start = inStartContainer ? that.range.startOffset : 0;
end = inEndContainer ? that.range.endOffset : that._current.length;
delta = end - start;
if (originalRange && (inStartContainer || inEndContainer)) {
if (that._current == originalRange.startContainer && start <= originalRange.startOffset) originalRange.startOffset -= delta;
if (that._current == originalRange.endContainer && end <= originalRange.endOffset) originalRange.endOffset -= delta;
}
that._current.deleteData(start, delta);
} else {
var parent = that._current.parentNode;
if (originalRange && (that.range.startContainer == parent || that.range.endContainer == parent)) {
var nodeIndex = findNodeIndex(that._current);
if (parent == originalRange.startContainer && nodeIndex <= originalRange.startOffset) originalRange.startOffset -= 1;
if (parent == originalRange.endContainer && nodeIndex < originalRange.endOffset) originalRange.endOffset -= 1;
}
dom.remove(that._current);
}
},
hasPartialSubtree: function() {
return !isDataNode(this._current) && (dom.isAncestorOrSelf(this._current, this.range.startContainer) || dom.isAncestorOrSelf(this._current, this.range.endContainer));
},
getSubtreeIterator: function() {
return new RangeIterator(this.getSubRange());
},
getSubRange: function() {
var that = this, subRange = that.range.cloneRange();
subRange.selectNodeContents(that._current);
if (dom.isAncestorOrSelf(that._current, that.range.startContainer)) subRange.setStart(that.range.startContainer, that.range.startOffset);
if (dom.isAncestorOrSelf(that._current, that.range.endContainer)) subRange.setEnd(that.range.endContainer, that.range.endOffset);
return subRange;
}
});
var W3CSelection = Class.extend({
init: function(doc) {
this.ownerDocument = doc;
this.rangeCount = 1;
},
addRange: function(range) {
var textRange = this.ownerDocument.body.createTextRange();
adoptContainer(textRange, range, false);
adoptContainer(textRange, range, true);
textRange.select();
},
removeAllRanges: function() {
var selection = this.ownerDocument.selection;
if (selection.type != "None") selection.empty();
},
getRangeAt: function() {
var textRange, range = new W3CRange(this.ownerDocument), selection = this.ownerDocument.selection, element, commonAncestor;
try {
textRange = selection.createRange();
element = textRange.item ? textRange.item(0) : textRange.parentElement();
if (element.ownerDocument != this.ownerDocument) return range;
} catch (ex) {
return range;
}
if (selection.type == "Control") range.selectNode(textRange.item(0));
else {
commonAncestor = textRangeContainer(textRange);
adoptEndPoint(textRange, range, commonAncestor, true);
adoptEndPoint(textRange, range, commonAncestor, false);
if (range.startContainer.nodeType == 9) range.setStart(range.endContainer, range.startOffset);
if (range.endContainer.nodeType == 9) range.setEnd(range.startContainer, range.endOffset);
if (textRange.compareEndPoints("StartToEnd", textRange) === 0) range.collapse(false);
var startContainer = range.startContainer, endContainer = range.endContainer, body = this.ownerDocument.body;
if (!range.collapsed && range.startOffset === 0 && range.endOffset == getNodeLength(range.endContainer) && !(startContainer == endContainer && isDataNode(startContainer) && startContainer.parentNode == body)) {
var movedStart = false, movedEnd = false;
while (findNodeIndex(startContainer) === 0 && startContainer == startContainer.parentNode.firstChild && startContainer != body) {
startContainer = startContainer.parentNode;
movedStart = true;
}
while (findNodeIndex(endContainer) == getNodeLength(endContainer.parentNode) - 1 && endContainer == endContainer.parentNode.lastChild && endContainer != body) {
endContainer = endContainer.parentNode;
movedEnd = true;
}
if (startContainer == body && endContainer == body && movedStart && movedEnd) {
range.setStart(startContainer, 0);
range.setEnd(endContainer, getNodeLength(body));
}
}
}
return range;
}
});
function textRangeContainer(textRange) {
var left = textRange.duplicate(), right = textRange.duplicate();
left.collapse(true);
right.collapse(false);
return dom.commonAncestor(textRange.parentElement(), left.parentElement(), right.parentElement());
}
function adoptContainer(textRange, range, start) {
var container = range[start ? "startContainer" : "endContainer"], offset = range[start ? "startOffset" : "endOffset"], textOffset = 0, isData = isDataNode(container), anchorNode = isData ? container : container.childNodes[offset] || null, anchorParent = isData ? container.parentNode : container, doc = range.ownerDocument, cursor = doc.body.createTextRange(), cursorNode;
if (container.nodeType == 3 || container.nodeType == 4) textOffset = offset;
if (!anchorParent) anchorParent = doc.body;
if (anchorParent.nodeName.toLowerCase() == "img") {
cursor.moveToElementText(anchorParent);
cursor.collapse(false);
textRange.setEndPoint(start ? "StartToStart" : "EndToStart", cursor);
} else {
cursorNode = anchorParent.insertBefore(dom.create(doc, "a"), anchorNode);
cursor.moveToElementText(cursorNode);
dom.remove(cursorNode);
cursor[start ? "moveStart" : "moveEnd"]("character", textOffset);
cursor.collapse(false);
textRange.setEndPoint(start ? "StartToStart" : "EndToStart", cursor);
}
}
function adoptEndPoint(textRange, range, commonAncestor, start) {
var cursorNode = dom.create(range.ownerDocument, "a"), cursor = textRange.duplicate(), comparison = start ? "StartToStart" : "StartToEnd", result, parent, target, previous, next, args, index, appended = false;
cursorNode.innerHTML = "";
cursor.collapse(start);
parent = cursor.parentElement();
if (!dom.isAncestorOrSelf(commonAncestor, parent)) parent = commonAncestor;
do {
if (appended) parent.insertBefore(cursorNode, cursorNode.previousSibling);
else {
parent.appendChild(cursorNode);
appended = true;
}
cursor.moveToElementText(cursorNode);
} while ((result = cursor.compareEndPoints(comparison, textRange)) > 0 && cursorNode.previousSibling);
target = cursorNode.nextSibling;
if (result == -1 && isDataNode(target)) {
cursor.setEndPoint(start ? "EndToStart" : "EndToEnd", textRange);
dom.remove(cursorNode);
args = [target, cursor.text.length];
} else {
previous = !start && cursorNode.previousSibling;
next = start && cursorNode.nextSibling;
if (isDataNode(next)) args = [next, 0];
else if (isDataNode(previous)) args = [previous, previous.length];
else {
index = findNodeIndex(cursorNode);
if (parent.nextSibling && index == parent.childNodes.length - 1) args = [parent.nextSibling, 0];
else args = [parent, index];
}
dom.remove(cursorNode);
}
range[start ? "setStart" : "setEnd"](...args);
}
var RangeEnumerator = Class.extend({ init: function(range) {
this.enumerate = function() {
var nodes = [];
function visit(node) {
if (dom.is(node, "img") || node.nodeType == 3 && (!dom.isEmptyspace(node) || node.nodeValue == "")) nodes.push(node);
else {
node = node.firstChild;
while (node) {
visit(node);
node = node.nextSibling;
}
}
}
new RangeIterator(range).traverse(visit);
return nodes;
};
} });
var ImmutablesRangeIterator = RangeIterator.extend({
hasPartialSubtree: function() {
var immutable = Editor.Immutables && Editor.Immutables.immutable;
return immutable && !immutable(this._current) && RangeIterator.fn.hasPartialSubtree.call(this);
},
getSubtreeIterator: function() {
return new ImmutablesRangeIterator(this.getSubRange());
}
});
var ImmutablesRangeEnumerator = Class.extend({ init: function(range) {
this.enumerate = function() {
var nodes = [];
var immutable = Editor.Immutables && Editor.Immutables.immutable;
function visit(node) {
if (immutable && !immutable(node)) if (dom.is(node, "img") || node.nodeType == 3 && (!dom.isEmptyspace(node) || node.nodeValue == "")) nodes.push(node);
else {
node = node.firstChild;
while (node) {
visit(node);
node = node.nextSibling;
}
}
}
new ImmutablesRangeIterator(range).traverse(visit);
return nodes;
};
} });
var RestorePoint = Class.extend({
init: function(range, body, options) {
var that = this;
that.range = range;
that.rootNode = RangeUtils.documentFromRange(range);
that.body = body || that.getEditable(range);
if (dom.name(that.body) != "body") that.rootNode = that.body;
that.startContainer = that.nodeToPath(range.startContainer);
that.endContainer = that.nodeToPath(range.endContainer);
that.startOffset = that.offset(range.startContainer, range.startOffset);
that.endOffset = that.offset(range.endContainer, range.endOffset);
that.immutables = options && options.immutables;
if (that.immutables) that.serializedImmutables = Editor.Immutables.removeImmutables(that.body);
that.html = that.body.innerHTML;
if (that.immutables && !that.serializedImmutables.empty) Editor.Immutables.restoreImmutables(that.body, that.serializedImmutables);
},
index: function(node) {
var result = 0, lastType = node.nodeType;
while (node = node.previousSibling) {
var nodeType = node.nodeType;
if (nodeType != 3 || lastType != nodeType) result++;
lastType = nodeType;
}
return result;
},
getEditable: function(range) {
var root = range.commonAncestorContainer;
while (root && (root.nodeType == 3 || root.attributes && (!root.attributes.contentEditable || root.attributes.contentEditable.nodeValue.toLowerCase() == "false"))) root = root.parentNode;
return root;
},
restoreHtml: function() {
var that = this;
dom.removeChildren(that.body);
that.body.innerHTML = that.html;
if (that.immutables && !that.serializedImmutables.empty) Editor.Immutables.restoreImmutables(that.body, that.serializedImmutables);
},
offset: function(node, value) {
if (node.nodeType == 3) while ((node = node.previousSibling) && node.nodeType == 3) value += node.nodeValue.length;
return value;
},
nodeToPath: function(node) {
var path = [];
while (node !== null && node != this.rootNode) {
path.push(this.index(node));
node = node.parentNode;
}
return path;
},
toRangePoint: function(range, start, path, denormalizedOffset) {
var node = this.rootNode, length = path.length, offset = denormalizedOffset;
while (length-- && node) node = node.childNodes[path[length]];
while (node && node.nodeType == 3 && node.nodeValue.length < offset) {
offset -= node.nodeValue.length;
node = node.nextSibling;
}
if (node && offset >= 0) range[start ? "setStart" : "setEnd"](node, offset);
},
toRange: function() {
var that = this, result = that.range.cloneRange();
that.toRangePoint(result, true, that.startContainer, that.startOffset);
that.toRangePoint(result, false, that.endContainer, that.endOffset);
return result;
}
});
var Marker = Class.extend({
init: function() {
this.caret = null;
},
addCaret: function(range) {
var that = this;
var caret = that.caret = dom.create(RangeUtils.documentFromRange(range), "span", { className: "k-marker" });
range.insertNode(caret);
dom.stripBomNode(caret.previousSibling);
dom.stripBomNode(caret.nextSibling);
range.selectNode(caret);
return caret;
},
removeCaret: function(range) {
var that = this, previous = that.caret.previousSibling, startOffset = 0;
if (previous) startOffset = isDataNode(previous) ? previous.nodeValue.length : findNodeIndex(previous);
var container = that.caret.parentNode;
var containerIndex = previous ? findNodeIndex(previous) : 0;
dom.remove(that.caret);
normalize(container);
var node = container.childNodes[containerIndex];
if (isDataNode(node)) range.setStart(node, startOffset);
else if (node) {
var textNode = dom.lastTextNode(node);
if (textNode) range.setStart(textNode, textNode.nodeValue.length);
else range[previous ? "setStartAfter" : "setStartBefore"](node);
} else {
if (!browser.msie && !container.innerHTML) container.innerHTML = "<br _moz_dirty=\"\" />";
range.selectNodeContents(container);
}
range.collapse(true);
},
add: function(range, expand) {
var that = this;
var collapsed = range.collapsed && !RangeUtils.isExpandable(range);
var doc = RangeUtils.documentFromRange(range);
if (expand && range.collapsed) {
that.addCaret(range);
range = RangeUtils.expand(range);
}
var rangeBoundary = range.cloneRange();
rangeBoundary.collapse(false);
that.end = dom.create(doc, "span", { className: "k-marker" });
rangeBoundary.insertNode(that.end);
rangeBoundary = range.cloneRange();
rangeBoundary.collapse(true);
that.start = that.end.cloneNode(true);
rangeBoundary.insertNode(that.start);
that._removeDeadMarkers(that.start, that.end);
if (collapsed) {
var bom = doc.createTextNode("");
dom.insertAfter(bom.cloneNode(), that.start);
dom.insertBefore(bom, that.end);
}
normalize(range.commonAncestorContainer);
range.setStartBefore(that.start);
range.setEndAfter(that.end);
return range;
},
_removeDeadMarkers: function(start, end) {
if (start.previousSibling && start.previousSibling.nodeValue == "") dom.remove(start.previousSibling);
if (end.nextSibling && end.nextSibling.nodeValue == "") dom.remove(end.nextSibling);
},
_normalizedIndex: function(node) {
var index = findNodeIndex(node);
var pointer = node;
while (pointer.previousSibling) {
if (pointer.nodeType == 3 && pointer.previousSibling.nodeType == 3) index--;
pointer = pointer.previousSibling;
}
return index;
},
remove: function(range) {
var that = this, start = that.start, end = that.end;
normalize(range.commonAncestorContainer);
while (!start.nextSibling && start.parentNode) start = start.parentNode;
while (!end.previousSibling && end.parentNode) end = end.parentNode;
start.previousSibling && start.previousSibling.nodeType == 3 && start.nextSibling && start.nextSibling.nodeType;
end.previousSibling && end.previousSibling.nodeType == 3 && end.nextSibling && end.nextSibling.nodeType;
start = start.nextSibling;
end = end.previousSibling;
var isBomSelected = start === end && dom.isBom(start);
if (isBomSelected && start.length > 1) start.nodeValue = start.nodeValue.charAt(0);
var collapsed = isBomSelected;
var collapsedToStart = false;
if (start == that.end) {
collapsedToStart = !!that.start.previousSibling;
start = end = that.start.previousSibling || that.end.nextSibling;
collapsed = true;
}
dom.remove(that.start);
dom.remove(that.end);
if (!start || !end) {
range.selectNodeContents(range.commonAncestorContainer);
range.collapse(true);
return;
}
var startOffset = collapsed ? isDataNode(start) ? start.nodeValue.length : start.childNodes.length : 0;
var endOffset = isDataNode(end) ? end.nodeValue.length : end.childNodes.length;
if (start.nodeType == 3) while (start.previousSibling && start.previousSibling.nodeType == 3) {
start = start.previousSibling;
startOffset += start.nodeValue.length;
}
if (end.nodeType == 3) while (end.previousSibling && end.previousSibling.nodeType == 3) {
end = end.previousSibling;
endOffset += end.nodeValue.length;
}
var startParent = start.parentNode;
var endParent = end.parentNode;
var startIndex = this._normalizedIndex(start);
var endIndex = this._normalizedIndex(end);
normalize(startParent);
if (start.nodeType == 3) start = startParent.childNodes[startIndex];
normalize(endParent);
if (end.nodeType == 3) end = endParent.childNodes[endIndex];
if (collapsed) {
if (start.nodeType == 3) range.setStart(start, startOffset);
else range[collapsedToStart ? "setStartAfter" : "setStartBefore"](start);
range.collapse(true);
} else {
if (start.nodeType == 3) range.setStart(start, startOffset);
else range.setStartBefore(start);
if (end.nodeType == 3) range.setEnd(end, endOffset);
else range.setEndAfter(end);
}
if (that.caret) that.removeCaret(range);
}
});
var boundary = /[\u0009-\u000d]|\u0020|\u00a0|\ufeff|\.|,|;|:|!|\(|\)|\?/;
var RangeUtils = {
nodes: function(range) {
var nodes = RangeUtils.textNodes(range);
if (!nodes.length) {
range.selectNodeContents(range.commonAncestorContainer);
nodes = RangeUtils.textNodes(range);
if (!nodes.length) nodes = dom.significantChildNodes(range.commonAncestorContainer);
}
return nodes;
},
textNodes: function(range) {
return new RangeEnumerator(range).enumerate().filter(function(node) {
return dom.allowsTextContent(node.parentElement);
});
},
editableTextNodes: function(range) {
var nodes = [], immutableParent = Editor.Immutables && Editor.Immutables.immutableParent, result = [];
if (immutableParent && !immutableParent(range.commonAncestorContainer)) {
nodes = new ImmutablesRangeEnumerator(range).enumerate();
result = nodes.filter(function(node) {
return dom.allowsTextContent(node.parentElement);
});
}
return result;
},
documentFromRange: function(range) {
var startContainer = range.startContainer;
return startContainer.nodeType == 9 ? startContainer : startContainer.ownerDocument;
},
createRange: function(document) {
return document.createRange();
},
selectRange: function(range) {
var image = RangeUtils.image(range);
if (image) {
range.setStartAfter(image);
range.setEndAfter(image);
}
var selection = SelectionUtils.selectionFromRange(range);
selection.removeAllRanges();
selection.addRange(range);
},
stringify: function(range) {
return kendo.format("{0}:{1} - {2}:{3}", dom.name(range.startContainer), range.startOffset, dom.name(range.endContainer), range.endOffset);
},
split: function(range, node, trim) {
function partition(start) {
var partitionRange = range.cloneRange();
partitionRange.collapse(start);
partitionRange[start ? "setStartBefore" : "setEndAfter"](node);
var contents = partitionRange.extractContents();
if (trim) contents = dom.trim(contents);
dom[start ? "insertBefore" : "insertAfter"](contents, node);
}
partition(true);
partition(false);
},
mapAll: function(range, map) {
var nodes = [];
new RangeIterator(range).traverse(function(node) {
var mapped = map(node);
if (mapped && $.inArray(mapped, nodes) < 0) nodes.push(mapped);
});
return nodes;
},
getAll: function(range, predicate) {
var selector = predicate;
if (typeof predicate == "string") predicate = function(node) {
return dom.is(node, selector);
};
return RangeUtils.mapAll(range, function(node) {
if (predicate(node)) return node;
});
},
getMarkers: function(range) {
return RangeUtils.getAll(range, function(node) {
return node.className == "k-marker";
});
},
image: function(range) {
var nodes = RangeUtils.getAll(range, "img");
if (nodes.length == 1) return nodes[0];
},
isStartOf: function(originalRange, node) {
if (originalRange.startOffset !== 0) return false;
var range = originalRange.cloneRange();
while (range.startOffset === 0 && range.startContainer != node) {
var index = dom.findNodeIndex(range.startContainer);
var parent = range.startContainer.parentNode;
while (index > 0 && parent[index - 1] && dom.insignificant(parent[index - 1])) index--;
range.setStart(parent, index);
}
return range.startOffset === 0 && range.startContainer == node;
},
isEndOf: function(originalRange, node) {
var range = originalRange.cloneRange();
range.collapse(false);
var start = range.startContainer;
if (dom.isDataNode(start) && range.startOffset == dom.getNodeLength(start)) {
range.setStart(start.parentNode, dom.findNodeIndex(start) + 1);
range.collapse(true);
}
range.setEnd(node, dom.getNodeLength(node));
var nodes = [];
function visit(node) {
if (!dom.insignificant(node) && !(dom.isDataNode(node) && /^[\ufeff]*$/.test(node.nodeValue))) nodes.push(node);
}
new RangeIterator(range).traverse(visit);
return !nodes.length;
},
wrapSelectedElements: function(range) {
var startEditable = dom.editableParent(range.startContainer);
var endEditable = dom.editableParent(range.endContainer);
while (range.startOffset === 0 && range.startContainer != startEditable) range.setStart(range.startContainer.parentNode, dom.findNodeIndex(range.startContainer));
function isEnd(offset, container) {
var length = dom.getNodeLength(container);
if (offset == length) return true;
for (var i = offset; i < length; i++) if (!dom.insignificant(container.childNodes[i])) return false;
return true;
}
while (isEnd(range.endOffset, range.endContainer) && range.endContainer != endEditable) range.setEnd(range.endContainer.parentNode, dom.findNodeIndex(range.endContainer) + 1);
return range;
},
expand: function(range) {
var result = range.cloneRange();
var startContainer = result.startContainer.childNodes[result.startOffset === 0 ? 0 : result.startOffset - 1];
var endContainer = result.endContainer.childNodes[result.endOffset];
if (!isDataNode(startContainer) || !isDataNode(endContainer)) return result;
var beforeCaret = startContainer.nodeValue;
var afterCaret = endContainer.nodeValue;
if (!beforeCaret || !afterCaret) return result;
var startOffset = beforeCaret.split("").reverse().join("").search(boundary);
var endOffset = afterCaret.search(boundary);
if (!startOffset || !endOffset) return result;
endOffset = endOffset == -1 ? afterCaret.length : endOffset;
startOffset = startOffset == -1 ? 0 : beforeCaret.length - startOffset;
result.setStart(startContainer, startOffset);
result.setEnd(endContainer, endOffset);
return result;
},
isExpandable: function(range) {
var node = range.startContainer;
var rangeDocument = RangeUtils.documentFromRange(range);
if (node == rangeDocument || node == rangeDocument.body) return false;
var result = range.cloneRange();
var value = node.nodeValue;
if (!value) return false;
var beforeCaret = value.substring(0, result.startOffset);
var afterCaret = value.substring(result.startOffset);
var startOffset = 0, endOffset = 0;
if (beforeCaret) startOffset = beforeCaret.split("").reverse().join("").search(boundary);
if (afterCaret) endOffset = afterCaret.search(boundary);
return startOffset && endOffset;
}
};
extend(Editor, {
SelectionUtils,
W3CRange,
RangeIterator,
W3CSelection,
RangeEnumerator,
RestorePoint,
Marker,
RangeUtils
});
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/immutables.js
(function($, undefined) {
var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, dom = Editor.Dom, template = kendo.template, RangeUtils = Editor.RangeUtils, complexBlocks = [
"ul",
"ol",
"tbody",
"thead",
"table"
], toolsToBeUpdated = [
"bold",
"italic",
"underline",
"strikethrough",
"superscript",
"subscript",
"forecolor",
"backcolor",
"fontname",
"fontsize",
"createlink",
"unlink",
"autolink",
"formatting",
"cleanformatting"
], IMMUTABALE = "k-immutable", IMMUTABALE_MARKER_SELECTOR = "[" + IMMUTABALE + "]", IMMUTABLE_SELECTOR = "[contenteditable='false']";
var rootCondition = function(node) {
return $(node).is("body,.k-editor");
};
var immutable = function(node) {
return node.getAttribute && node.getAttribute("contenteditable") == "false";
};
var immutableParent = function(node) {
return dom.closestBy(node, immutable, rootCondition);
};
var expandImmutablesIn = function(range) {
var startImmutableParent = immutableParent(range.startContainer);
var endImmutableParent = immutableParent(range.endContainer);
if (startImmutableParent || endImmutableParent) {
if (startImmutableParent) range.setStartBefore(startImmutableParent);
if (endImmutableParent) range.setEndAfter(endImmutableParent);
}
};
var immutablesContext = function(range) {
if (immutableParent(range.commonAncestorContainer)) return true;
else if (immutableParent(range.startContainer) || immutableParent(range.endContainer)) {
if (RangeUtils.editableTextNodes(range).length === 0) return true;
}
return false;
};
var randomId = function(length) {
var result = "";
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var i = length || 10; i > 0; --i) result += chars.charAt(Math.round(Math.random() * (chars.length - 1)));
return result;
};
var removeImmutables = function(root) {
var serializedImmutables = { empty: true }, nodeName, id, serialized;
$(root).find(IMMUTABLE_SELECTOR).each(function(i, node) {
nodeName = dom.name(node);
id = randomId();
serialized = "<" + nodeName + " " + IMMUTABALE + "='" + id + "'></" + nodeName + ">";
serializedImmutables[id] = {
node,
style: $(node).attr("style")
};
serializedImmutables.empty = false;
$(node).replaceWith(serialized);
});
return serializedImmutables;
};
var restoreImmutables = function(root, serializedImmutables) {
var id, immutable;
$(root).find(IMMUTABALE_MARKER_SELECTOR).each(function(i, node) {
id = node.getAttribute(IMMUTABALE);
immutable = serializedImmutables[id];
$(node).replaceWith(immutable.node);
if (immutable.style != $(immutable.node).attr("style")) $(immutable.node).removeAttr("style").attr("style", immutable.style);
});
};
var deletingKey = function(keyCode) {
var keys = kendo.keys;
return keyCode === keys.BACKSPACE || keyCode == keys.DELETE;
};
var updateToolOptions = function(tool) {
var options = tool ? tool.options : undefined;
if (options && options.finder) options.finder._initOptions({ immutables: true });
};
var Immutables = Class.extend({
init: function(editor) {
this.editor = editor;
this.serializedImmutables = {};
this.options = $.extend({}, editor && editor.options && editor.options.immutables);
var tools = kendo.ui.Editor.defaultTools;
updateToolOptions(tools.justifyLeft);
updateToolOptions(tools.justifyCenter);
updateToolOptions(tools.justifyRight);
updateToolOptions(tools.justifyFull);
},
serialize: function(node) {
var result = this._toHtml(node), id;
if (result.indexOf(IMMUTABALE) === -1) {
id = this.randomId();
result = result.replace(/>/, " " + IMMUTABALE + "=\"" + id + "\">");
} else id = result.match(/k-immutable\s*=\s*['"](.*)['"]/)[1];
this.serializedImmutables[id] = node;
return result;
},
_toHtml: function(node) {
var serialization = this.options.serialization;
var serializationType = typeof serialization;
var nodeName;
switch (serializationType) {
case "string": return template(serialization)(node);
case "function": return serialization(node);
default:
nodeName = dom.name(node);
return "<" + nodeName + "></" + nodeName + ">";
}
},
deserialize: function(node) {
var that = this;
var deserialization = this.options.deserialization;
$(IMMUTABALE_MARKER_SELECTOR, node).each(function() {
var id = this.getAttribute(IMMUTABALE);
var immutable = that.serializedImmutables[id];
if (kendo.isFunction(deserialization)) deserialization(this, immutable);
$(this).replaceWith(immutable);
});
that.serializedImmutables = {};
},
randomId: function(length) {
return randomId(length);
},
keydown: function(e, range) {
var isDeleting = deletingKey(e.keyCode);
if (isDeleting && this._cancelDeleting(e, range) || !isDeleting && this._cancelTyping(e, range)) {
e.preventDefault();
return true;
}
},
_cancelTyping: function(e, range) {
var keyboard = this.editor.keyboard;
return range.collapsed && !keyboard.typingInProgress && keyboard.isTypingKey(e) && immutablesContext(range);
},
_cancelDeleting: function(e, range) {
var keys = kendo.keys;
var backspace = e.keyCode === keys.BACKSPACE;
var del = e.keyCode == keys.DELETE;
if (!backspace && !del) return false;
var cancelDeleting = false;
if (range.collapsed) {
if (immutablesContext(range)) return true;
var immutable = this.nextImmutable(range, del);
if (immutable && backspace) {
var closestSelectionLi = dom.closest(range.commonAncestorContainer, "li");
if (closestSelectionLi) {
var closestImmutableLi = dom.closest(immutable, "li");
if (closestImmutableLi && closestImmutableLi !== closestSelectionLi) return cancelDeleting;
}
}
if (immutable && !dom.tableCell(immutable)) {
if (dom.parentOfType(immutable, complexBlocks) === dom.parentOfType(range.commonAncestorContainer, complexBlocks)) {
while (immutable && immutable.parentNode.childNodes.length == 1) immutable = immutable.parentNode;
if (dom.tableCell(immutable)) return cancelDeleting;
this._removeImmutable(immutable, range);
}
cancelDeleting = true;
}
}
return cancelDeleting;
},
nextImmutable: function(range, forwards) {
var commonContainer = range.commonAncestorContainer;
if (dom.isBom(commonContainer) || forwards && RangeUtils.isEndOf(range, commonContainer) || !forwards && RangeUtils.isStartOf(range, commonContainer)) {
var next = this._nextNode(commonContainer, forwards);
if (next && dom.isBlock(next) && !immutableParent(next)) while (next && next.children && next.children[forwards ? 0 : next.children.length - 1]) next = next.children[forwards ? 0 : next.children.length - 1];
return immutableParent(next);
}
},
_removeImmutable: function(immutable, range) {
var editor = this.editor;
var startRestorePoint = new Editor.RestorePoint(range, editor.body);
dom.remove(immutable);
Editor._finishUpdate(editor, startRestorePoint);
},
_nextNode: function(node, forwards) {
var sibling = forwards ? "nextSibling" : "previousSibling";
var current = node, next;
while (current && !next && !dom.isChildOfBaseContainer(current)) {
next = current[sibling];
if (next && dom.isDataNode(next) && /^\s|[\ufeff]$/.test(next.nodeValue)) {
current = next;
next = current[sibling];
}
if (!next) current = current.parentNode;
}
return next;
}
});
Immutables.immutable = immutable;
Immutables.immutableParent = immutableParent;
Immutables.expandImmutablesIn = expandImmutablesIn;
Immutables.immutablesContext = immutablesContext;
Immutables.toolsToBeUpdated = toolsToBeUpdated;
Immutables.removeImmutables = removeImmutables;
Immutables.restoreImmutables = restoreImmutables;
Editor.Immutables = Immutables;
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/command.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, dom = editorNS.Dom, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, extend = $.extend;
function finishUpdate(editor, startRestorePoint) {
var endRestorePoint = editor.selectionRestorePoint = new RestorePoint(editor.getRange(), editor.body);
var command = new GenericCommand(startRestorePoint, endRestorePoint);
command.editor = editor;
editor.undoRedoStack.push(command);
editor._refreshTools();
return endRestorePoint;
}
var Command = Class.extend({
init: function(options) {
this.options = options;
this.restorePoint = new RestorePoint(options.range, options.body, { immutables: options.immutables });
this.marker = new Marker();
this.formatter = options.formatter;
},
getRange: function() {
return this.restorePoint.toRange();
},
lockRange: function(expand) {
return this.marker.add(this.getRange(), expand);
},
releaseRange: function(range) {
this.marker.remove(range);
this.editor.selectRange(range);
},
undo: function() {
var point = this.restorePoint;
point.restoreHtml();
this.editor.selectRange(point.toRange());
},
redo: function() {
this.exec();
},
createDialog: function(content, options) {
var editor = this.editor;
return $(content).appendTo(document.body).kendoWindow(extend({}, editor.options.dialogOptions, options)).closest(".k-window").addClass("k-editor-window").toggleClass("k-rtl", kendo.support.isRtl(editor.wrapper)).end();
},
exec: function() {
var range = this.lockRange(true);
this.formatter.editor = this.editor;
this.formatter.toggle(range);
this.releaseRange(range);
},
postExec: function() {
this.editor._handleSpaceAndNewLines();
},
immutables: function() {
return this.editor && this.editor.options.immutables;
},
expandImmutablesIn: function(range) {
if (this.immutables()) {
kendo.ui.editor.Immutables.expandImmutablesIn(range);
this.restorePoint = new RestorePoint(range, this.editor.body);
}
},
_actionButtonsTemplate: function({ messages, insertButtonIcon, cancelButtonIcon }) {
return "<div class=\"k-actions k-actions-start k-actions-horizontal k-window-buttons\">" + kendo.html.renderButton(`<button class="k-dialog-insert">${messages.dialogInsert}</button>`, {
themeColor: "primary",
icon: insertButtonIcon
}) + kendo.html.renderButton(`<button class="k-dialog-close">${messages.dialogCancel}</button>`, { icon: cancelButtonIcon }) + "</div>";
}
});
var GenericCommand = Class.extend({
init: function(startRestorePoint, endRestorePoint) {
this.body = startRestorePoint.body;
this.startRestorePoint = startRestorePoint;
this.endRestorePoint = endRestorePoint;
},
redo: function() {
dom.removeChildren(this.body);
this.body.innerHTML = this.endRestorePoint.html;
this.editor.selectRange(this.endRestorePoint.toRange());
},
undo: function() {
dom.removeChildren(this.body);
this.body.innerHTML = this.startRestorePoint.html;
this.editor.selectRange(this.startRestorePoint.toRange());
}
});
extend(editorNS, {
_finishUpdate: finishUpdate,
Command,
GenericCommand
});
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/viewhtml.js
(function($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, dom = Editor.Dom;
var ViewHtmlCommand = Command.extend({
init: function(options) {
var cmd = this;
cmd.options = options;
Command.fn.init.call(cmd, options);
cmd.attributes = null;
cmd.async = true;
},
exec: function() {
var that = this, editor = that.editor, options = editor.options, messages = editor.options.messages, dialog = $(kendo.template(ViewHtmlCommand.template)(messages)).appendTo(document.body), textarea = ".k-editor-textarea > textarea", content, comments;
options.serialization.immutables = editor.immutables;
comments = dom.getAllComments(editor.body);
content = EditorUtils.cacheComments(editor.value(), comments);
content = ViewHtmlCommand.indent(content);
content = EditorUtils.retrieveComments(content, comments);
options.serialization.immutables = undefined;
function apply(e) {
options.deserialization.immutables = editor.immutables;
editor.value(dialog.find(textarea).val());
options.deserialization.immutables = undefined;
close(e);
if (that.change) that.change();
editor.trigger("change");
}
function close(e) {
e.preventDefault();
dialog.data("kendoWindow").destroy();
if (editor.immutables) editor.immutables.serializedImmutables = {};
editor.focus();
}
let window = this.createDialog(dialog, {
title: messages.viewHtml,
_footerTemplate: ViewHtmlCommand._footerTemplate,
_footerMessages: messages,
width: 600,
height: 400,
resizable: true,
close,
visible: false
}).find(textarea).val(content).end().data("kendoWindow");
window.center().open();
window.wrapper.find(".k-dialog-update").on("click", apply).end();
window.wrapper.find(".k-dialog-close").on("click", close).end();
dialog.find(textarea).trigger("focus");
}
});
extend(ViewHtmlCommand, {
template: () => "<div class=\"k-editor-dialog k-popup-edit-form k-viewhtml-dialog\"><span class=\"k-input k-textarea k-editor-textarea\"><textarea class=\"k-input-inner !k-overflow-auto !k-resize-none\"></textarea></span></div>",
_footerTemplate: ({ dialogUpdate, dialogCancel }) => `<div class="k-actions k-actions-start k-actions-horizontal k-window-actions">` + kendo.html.renderButton(`<button class="k-dialog-update">${kendo.htmlEncode(dialogUpdate)}</button>`, {
themeColor: "primary",
icon: "check"
}) + kendo.html.renderButton(`<button class="k-dialog-close">${kendo.htmlEncode(dialogCancel)}</button>`, { icon: "cancel" }) + `</div>`,
indent: function(content) {
return content.replace(/<\/(p|li|ul|ol|h[1-6]|table|tr|td|th)>/gi, "</$1>\n").replace(/<(ul|ol)([^>]*)><li/gi, "<$1$2>\n<li").replace(/<br \/>/gi, "<br />\n").replace(/\n$/, "");
}
});
kendo.ui.editor.ViewHtmlCommand = ViewHtmlCommand;
Editor.EditorUtils.registerTool("viewHtml", new Tool({ command: ViewHtmlCommand }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/format.js
(function($) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, Tool = Editor.Tool, Command = Editor.Command, EditorUtils = Editor.EditorUtils;
var FormatCommand = Command.extend({ init: function(options) {
options.formatter = options.formatter();
var finder = options.formatter.finder;
if (finder && EditorUtils.formatByName("immutable", finder.format)) {
finder._initOptions({ immutables: options.immutables });
options.finder && options.finder._initOptions({ immutables: options.immutables });
}
Command.fn.init.call(this, options);
} });
var FormatTool = Tool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
},
command: function(commandArguments) {
var that = this;
return new FormatCommand(extend(commandArguments, {
formatter: that.options.formatter,
finder: that.options.finder
}));
},
update: function(ui, nodes) {
var isFormatted = this.options.finder.isFormatted(nodes), toolbar = ui.closest(".k-toolbar").getKendoToolBar();
if (toolbar && ui.getKendoToggleButton()) toolbar.toggle(ui, isFormatted);
}
});
$.extend(Editor, {
FormatCommand,
FormatTool
});
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/inlineformat.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, Tool = Editor.Tool, FormatTool = Editor.FormatTool, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, extend = $.extend, registerTool = Editor.EditorUtils.registerTool, registerFormat = Editor.EditorUtils.registerFormat, MOUSEDOWN_NS = "mousedown.kendoEditor", KEYDOWN_NS = "keydown.kendoEditor", KMARKER = "k-marker";
var InlineFormatFinder = Class.extend({
init: function(format) {
this.format = format;
},
numberOfSiblings: function(referenceNode) {
var textNodesCount = 0, elementNodesCount = 0, markerCount = 0, parentNode = referenceNode.parentNode, node;
for (node = parentNode.firstChild; node; node = node.nextSibling) if (node != referenceNode) if (node.className == KMARKER) markerCount++;
else if (node.nodeType == 3) textNodesCount++;
else elementNodesCount++;
if (markerCount > 1 && parentNode.firstChild.className == KMARKER && parentNode.lastChild.className == KMARKER) return 0;
else return elementNodesCount + textNodesCount;
},
findSuitable: function(sourceNode, skip) {
if (!skip && this.numberOfSiblings(sourceNode) > 0) return null;
var node = sourceNode.parentNode;
var tags = this.format[0].tags;
while (!dom.ofType(node, tags)) {
if (this.numberOfSiblings(node) > 0) return null;
node = node.parentNode;
}
return node;
},
findFormat: function(sourceNode) {
var format = this.format, attrEquals = dom.attrEquals, i, len, node, tags, attributes;
for (i = 0, len = format.length; i < len; i++) {
node = sourceNode;
tags = format[i].tags;
attributes = format[i].attr;
if (node && dom.ofType(node, tags) && attrEquals(node, attributes)) return node;
while (node) {
node = dom.parentOfType(node, tags);
if (node && attrEquals(node, attributes)) return node;
}
}
return null;
},
isFormatted: function(nodes) {
var i, len;
for (i = 0, len = nodes.length; i < len; i++) if (this.findFormat(nodes[i])) return true;
return false;
}
});
var InlineFormatter = Class.extend({
init: function(format, values) {
this.finder = new InlineFormatFinder(format);
this.attributes = extend({}, format[0].attr, values);
this.tag = format[0].tags[0];
},
wrap: function(node) {
return dom.wrap(node, dom.create(node.ownerDocument, this.tag, this.attributes));
},
activate: function(range, nodes) {
if (this.finder.isFormatted(nodes)) {
this.split(range);
this.remove(nodes);
} else this.apply(nodes);
},
toggle: function(range) {
var nodes = (this.immutables() ? RangeUtils.editableTextNodes : RangeUtils.textNodes)(range);
nodes = dom.filterBy(nodes, function(node) {
return dom.htmlIndentSpace(node) && !dom.isBom(node);
}, true);
if (nodes.length > 0) this.activate(range, nodes);
},
immutables: function() {
return this.editor && this.editor.options.immutables;
},
apply: function(nodes) {
var formatNodes = [];
var i, l, node, formatNode;
if (nodes.length > 1) for (i = 0, l = nodes.length; i < l; i++) {
node = nodes[i];
formatNode = this.format(node, true);
formatNodes.push(formatNode);
}
else {
node = nodes[0];
this.format(node, false);
}
this.consolidate(formatNodes);
},
format: function(node, outerMostInline) {
var formatNode = this.finder.findSuitable(node);
var attributes = this.attributes;
var styleAttr = attributes ? attributes.style || {} : {};
if (formatNode) {
if (dom.is(formatNode, "font")) {
if (styleAttr.color) formatNode.removeAttribute("color");
if (styleAttr.fontName) formatNode.removeAttribute("face");
if (styleAttr.fontSize) formatNode.removeAttribute("size");
}
dom.attr(formatNode, attributes);
} else {
if (outerMostInline) while (!dom.isBlock(node.parentNode) && node.parentNode.childNodes.length == 1 && node.parentNode.contentEditable !== "true") node = node.parentNode;
formatNode = this.wrap(node);
}
return formatNode;
},
remove: function(nodes) {
var i, l, formatNode;
for (i = 0, l = nodes.length; i < l; i++) {
formatNode = this.finder.findFormat(nodes[i]);
if (formatNode) if (this.attributes && this.attributes.style) {
dom.unstyle(formatNode, this.attributes.style);
if (!formatNode.style.cssText && !formatNode.attributes["class"]) dom.unwrap(formatNode);
} else dom.unwrap(formatNode);
}
},
split: function(range) {
var nodes = RangeUtils.textNodes(range);
var l = nodes.length;
var i, formatNode;
if (l > 0) for (i = 0; i < l; i++) {
formatNode = this.finder.findFormat(nodes[i]);
if (formatNode) RangeUtils.split(range, formatNode, true);
}
},
consolidate: function(nodes) {
var node, last;
while (nodes.length > 1) {
node = nodes.pop();
last = nodes[nodes.length - 1];
if (node.previousSibling && node.previousSibling.className == KMARKER) last.appendChild(node.previousSibling);
if (node.tagName == last.tagName && node.previousSibling == last && node.style.cssText == last.style.cssText && node.className === last.className) {
while (node.firstChild) last.appendChild(node.firstChild);
dom.remove(node);
}
}
}
});
var GreedyInlineFormatFinder = InlineFormatFinder.extend({
init: function(format, greedyProperty, fontAttr, defaultValue) {
this.format = format;
this.greedyProperty = greedyProperty;
this.fontAttr = fontAttr;
this.defaultValue = defaultValue;
InlineFormatFinder.fn.init.call(this, format);
},
getInlineCssValue: function(node) {
var attributes = node.attributes;
var trim = kendo.trim;
var i, l, attribute, name, attributeValue, css, pair, cssIndex, len;
var propertyAndValue, property, value;
if (!attributes) return;
for (i = 0, l = attributes.length; i < l; i++) {
attribute = attributes[i];
name = attribute.nodeName;
attributeValue = attribute.nodeValue;
if (attribute.specified && name == "style") {
css = trim(attributeValue || node.style.cssText).split(";");
for (cssIndex = 0, len = css.length; cssIndex < len; cssIndex++) {
pair = css[cssIndex];
if (pair.length) {
propertyAndValue = pair.split(":");
property = trim(propertyAndValue[0].toLowerCase());
value = trim(propertyAndValue[1]);
if (property != this.greedyProperty) continue;
return property.indexOf("color") >= 0 ? dom.toHex(value) : value;
}
}
}
if (this.fontAttr && attribute.specified && name == this.fontAttr) {
property = attribute.nodeValue;
value = attribute.nodeValue;
return property.indexOf("color") >= 0 ? dom.toHex(value) : value;
}
}
},
getFormatInner: function(node) {
var parents = $(dom.isDataNode(node) ? node.parentNode : node).parentsUntil("[contentEditable]").addBack().toArray().reverse();
var i, len, value;
for (i = 0, len = parents.length; i < len; i++) {
value = this.greedyProperty == "className" ? parents[i].className : this.getInlineCssValue(parents[i]);
if (value) return value;
}
return this.defaultValue || "inherit";
},
getFormat: function(nodes) {
var result = this.getFormatInner(nodes[0]), i, len;
for (i = 1, len = nodes.length; i < len; i++) if (result != this.getFormatInner(nodes[i])) return "";
return result;
},
isFormatted: function(nodes) {
return this.getFormat(nodes) !== "";
}
});
var GreedyInlineFormatter = InlineFormatter.extend({
init: function(format, values, greedyProperty) {
InlineFormatter.fn.init.call(this, format, values);
this.values = values;
this.finder = new GreedyInlineFormatFinder(format, greedyProperty);
if (greedyProperty) this.greedyProperty = kendo.toCamelCase(greedyProperty);
},
activate: function(range, nodes) {
var greedyProperty = this.greedyProperty;
var action = "apply";
this.split(range);
if (greedyProperty && this.values.style[greedyProperty] == "inherit") action = "remove";
this[action](nodes);
}
});
var InlineFormatTool = FormatTool.extend({ init: function(options) {
FormatTool.fn.init.call(this, extend(options, {
finder: new InlineFormatFinder(options.format),
formatter: function() {
return new InlineFormatter(options.format);
}
}));
} });
var DelayedExecutionTool = Tool.extend({ update: function(ui, nodes) {
var list = ui.data(this.type);
list.close();
list.value(this.finder.getFormat(nodes));
} });
var FontTool = DelayedExecutionTool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
this.type = "kendoComboBox";
this.format = [{ tags: ["span", "font"] }];
this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr, options.fontAttr);
},
command: function(commandArguments) {
var options = this.options, format = this.format, style = {};
return new Editor.FormatCommand(extend(commandArguments, { formatter: function() {
style[options.domAttr] = commandArguments.value;
return new GreedyInlineFormatter(format, { style }, options.cssAttr);
} }));
},
initialize: function(ui, editor) {
var options = this.options, toolName = options.name, dataSource, range, widget = ui.data("kendoComboBox"), defaultValue = [];
if (!widget) return;
if (options.defaultValue) defaultValue = [{
text: editor.options.messages[options.defaultValue[0].text],
value: options.defaultValue[0].value
}];
dataSource = defaultValue.concat(options.items ? options.items : editor.options[toolName] || []);
widget.setDataSource(dataSource);
widget.bind("change", (e) => {
editor._range = range;
if (e.sender.value() !== "") Tool.exec(editor, toolName, e.sender.value());
});
widget.bind("close", () => {
setTimeout(function() {
editor._deleteSavedRange();
}, 0);
});
widget.value("inherit");
widget.wrapper.on(MOUSEDOWN_NS, ".k-select,.k-input-button,.k-input", function() {
var newRange = editor.getRange();
range = editor._containsRange(newRange) ? newRange : range;
}).on(KEYDOWN_NS, function(e) {
if (e.keyCode === kendo.keys.ENTER) {
editor._deleteSavedRange();
e.preventDefault();
}
});
}
});
var ColorTool = Tool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
this.format = [{ tags: ["span", "font"] }];
this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
},
options: {
palette: "websafe",
columns: 18
},
update: function() {
if (this._widget && typeof this._widget.close === "function") this._widget.close();
},
command: function(commandArguments) {
var options = this.options, format = this.format, style = {};
return new Editor.FormatCommand(extend(commandArguments, { formatter: function() {
style[options.domAttr] = commandArguments.value;
return new GreedyInlineFormatter(format, { style }, options.cssAttr);
} }));
},
initialize: function(ui, editor) {
var that = this, toolName = that.options.name, component = this._widget = ui.getKendoColorPicker();
if (!component) return;
component.bind("change", () => {
const color = component.value();
if (color) {
editor._range = that.storedRange;
Tool.exec(editor, toolName, color);
} else editor.focus();
delete that.storedRange;
delete that._inputFocused;
});
component.bind("open", () => {
that.storedRange = editor.getRange();
component._popup.element.on(MOUSEDOWN_NS, function(e) {
if (!$(e.target).closest("input, button").length) e.preventDefault();
});
if (!component._popup.element.is("[unselectable='on']")) component._popup.element.attr({ unselectable: "on" }).find("*:not(input)").attr("unselectable", "on").end().find("input").on("focus", function() {
that._inputFocused = true;
});
component._popup.one("activate", () => {
component._popup.element.find(".k-colorpalette").trigger("focus");
});
});
component.bind("close", (e) => {
component._popup.element.off(MOUSEDOWN_NS);
});
component.unbind("activate").bind("activate", (e) => {
if (!component._value || component._value.toCssRgba() === "rgba(255, 255, 255, 0)") return;
component.trigger("change");
});
component.wrapper.attr({ unselectable: "on" }).find("*:not(input)").attr("unselectable", "on");
component.value("transparent");
}
});
extend(Editor, {
InlineFormatFinder,
InlineFormatter,
DelayedExecutionTool,
GreedyInlineFormatFinder,
GreedyInlineFormatter,
InlineFormatTool,
FontTool,
ColorTool
});
registerFormat("bold", [{ tags: ["strong", "b"] }, {
tags: ["span"],
attr: { style: { fontWeight: "bold" } }
}]);
registerTool("bold", new InlineFormatTool({
key: "B",
ctrl: true,
format: formats.bold,
ui: { togglable: true }
}));
registerFormat("italic", [{ tags: ["em", "i"] }, {
tags: ["span"],
attr: { style: { fontStyle: "italic" } }
}]);
registerTool("italic", new InlineFormatTool({
key: "I",
ctrl: true,
format: formats.italic,
ui: { togglable: true }
}));
registerFormat("underline", [
{
tags: ["span"],
attr: { style: { textDecoration: "underline" } }
},
{
tags: ["span"],
attr: { style: { textDecorationLine: "underline" } }
},
{ tags: ["u"] }
]);
registerTool("underline", new InlineFormatTool({
key: "U",
ctrl: true,
format: formats.underline,
ui: { togglable: true }
}));
registerFormat("strikethrough", [{ tags: ["del", "strike"] }, {
tags: ["span"],
attr: { style: { textDecoration: "line-through" } }
}]);
registerTool("strikethrough", new InlineFormatTool({
format: formats.strikethrough,
ui: { togglable: true }
}));
registerFormat("superscript", [{ tags: ["sup"] }]);
registerTool("superscript", new InlineFormatTool({
format: formats.superscript,
ui: { togglable: true }
}));
registerFormat("subscript", [{ tags: ["sub"] }]);
registerTool("subscript", new InlineFormatTool({
format: formats.subscript,
ui: { togglable: true }
}));
registerTool("foreColor", new ColorTool({
cssAttr: "color",
fontAttr: "color",
domAttr: "color",
name: "foreColor",
ui: {
type: "component",
overflow: "never",
component: "ColorPicker",
componentOptions: {
views: ["palette"],
toolIcon: "foreground-color",
palette: "websafe",
columns: 18,
preview: false,
input: false,
buttons: false,
commandOn: "change",
closeOnSelect: true
}
}
}));
registerTool("backColor", new ColorTool({
cssAttr: "background-color",
domAttr: "backgroundColor",
name: "backColor",
ui: {
type: "component",
overflow: "never",
component: "ColorPicker",
componentOptions: {
views: ["palette"],
toolIcon: "droplet",
palette: "websafe",
columns: 18,
preview: false,
input: false,
buttons: false,
commandOn: "change",
closeOnSelect: true
}
}
}));
registerTool("fontName", new FontTool({
cssAttr: "font-family",
fontAttr: "face",
domAttr: "fontFamily",
name: "fontName",
defaultValue: [{
text: "fontNameInherit",
value: "inherit"
}],
ui: {
type: "component",
component: "ComboBox",
componentOptions: {
dataValueField: "value",
dataTextField: "text",
valuePrimitive: true
},
overflow: "never"
}
}));
registerTool("fontSize", new FontTool({
cssAttr: "font-size",
fontAttr: "size",
domAttr: "fontSize",
name: "fontSize",
defaultValue: [{
text: "fontSizeInherit",
value: "inherit"
}],
ui: {
type: "component",
component: "ComboBox",
componentOptions: {
dataValueField: "value",
dataTextField: "text",
valuePrimitive: true
},
overflow: "never"
}
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/link.js
(function($, undefined) {
var kendo = window.kendo, encode = kendo.htmlEncode, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, Command = Editor.Command, Tool = Editor.Tool, InlineFormatter = Editor.InlineFormatter, InlineFormatFinder = Editor.InlineFormatFinder, textNodes = RangeUtils.textNodes, editableTextNodes = RangeUtils.editableTextNodes, registerTool = Editor.EditorUtils.registerTool, keys = kendo.keys;
var HTTP_PROTOCOL = "http://";
var protocolRegExp = /^\w*:\/\//;
var endLinkCharsRegExp = /[\w\/\$\-_\*\?]/i;
var LinkFormatFinder = Class.extend({ findSuitable: function(sourceNode) {
return dom.parentOfType(sourceNode, ["a"]);
} });
var LinkFormatter = Class.extend({
init: function() {
this.finder = new LinkFormatFinder();
},
apply: function(range, attributes) {
var nodes = this.immutables ? editableTextNodes(range) : textNodes(range);
var markers, doc, formatter, a, parent;
if (attributes.innerText) {
doc = RangeUtils.documentFromRange(range);
markers = RangeUtils.getMarkers(range);
range.deleteContents();
a = dom.create(doc, "a", attributes);
range.insertNode(a);
parent = a.parentNode;
if (dom.name(parent) == "a") dom.insertAfter(a, parent);
if (dom.emptyNode(parent)) dom.remove(parent);
var ref = a;
for (var i = 0; i < markers.length; i++) {
dom.insertAfter(markers[i], ref);
ref = markers[i];
}
if (markers.length) {
dom.insertBefore(doc.createTextNode(""), markers[1] || markers[0]);
dom.insertAfter(doc.createTextNode(""), markers[1] || markers[0]);
range.setStartBefore(markers[0]);
range.setEndAfter(markers[markers.length - 1]);
}
} else {
formatter = new InlineFormatter([{ tags: ["a"] }], attributes);
formatter.finder = this.finder;
formatter.apply(nodes);
}
}
});
var UnlinkCommand = Command.extend({ init: function(options) {
var that = this;
options.formatter = ( /** @ignore */ { toggle: function(range) {
var nodes = that.immutables() ? editableTextNodes(range) : textNodes(range);
new InlineFormatter([{ tags: ["a"] }]).remove(nodes);
} });
this.options = options;
Command.fn.init.call(this, options);
} });
var LinkCommand = Command.extend({
init: function(options) {
var that;
this.options = options;
Command.fn.init.call(this, options);
this.formatter = new LinkFormatter();
if (!options.url) {
this.attributes = null;
this.async = true;
} else this.exec = function() {
this.formatter.immutables = that && that.immutables();
this.formatter.apply(options.range, {
href: options.url,
innerText: options.text || options.url,
target: options.target
});
};
},
exec: function() {
var messages = this.editor.options.messages;
this._initialText = "";
this._range = this.lockRange(true);
this.formatter.immutables = this.immutables();
var nodes = textNodes(this._range);
var a = nodes.length ? this.formatter.finder.findSuitable(nodes[0]) : null;
var img = nodes.length && dom.name(nodes[0]) == "img";
var dialog = this.createDialog("<div/>", {
title: messages.createLink,
minWidth: 340,
close: this._close.bind(this),
visible: false
}).data("kendoWindow");
this._form = this._createForm(dialog);
if (a) {
this._range.selectNodeContents(a);
nodes = textNodes(this._range);
}
this._initialText = this.linkText(nodes);
dialog.wrapper.find(".k-dialog-insert").on("click", this._apply.bind(this)).end().find(".k-dialog-close").on("click", this._close.bind(this)).end().find(".k-form-field input").on("keydown", this._keydown.bind(this)).end().find("#k-editor-link-url").val(this.linkUrl(a)).end().find("#k-editor-link-text").val(this._initialText).end().find("#k-editor-link-title").val(a ? a.title : "").end().find("#k-editor-link-target").prop("checked", a ? a.target == "_blank" : false).end().find(".k-editor-link-text-row").toggle(!img);
this._dialog = dialog.center().open();
$("#k-editor-link-url", dialog.element).trigger("focus").select();
},
_createForm: function(dialog) {
var that = this;
var formElement = $("<div/>").appendTo(dialog.element);
var messages = that.editor.options.messages;
var form = formElement.kendoForm({
renderButtons: false,
items: [
{
field: "k-editor-link-url",
label: encode(messages.linkWebAddress),
title: encode(messages.linkWebAddress),
editor: "TextBox"
},
{
field: "k-editor-link-text",
label: encode(messages.linkText),
title: encode(messages.linkText),
editor: "TextBox"
},
{
field: "k-editor-link-title",
label: encode(messages.linkToolTip),
title: encode(messages.linkToolTip),
editor: "TextBox"
},
{
field: "k-editor-link-target",
editorOptions: { label: encode(messages.linkOpenInNewWindow) },
label: "",
title: encode(messages.linkOpenInNewWindow),
editor: "CheckBox"
}
]
}).data("kendoForm");
formElement.find("#k-editor-link-text").parents(".k-form-field").addClass("k-editor-link-text-row");
dialog.element.after($(that._actionButtonsTemplate({
messages,
insertButtonIcon: "link",
cancelButtonIcon: "cancel"
})));
return form;
},
_keydown: function(e) {
var keys = kendo.keys;
if (e.keyCode == keys.ENTER) this._apply(e);
else if (e.keyCode == keys.ESC) this._close(e);
},
_apply: function(e) {
var element = this._dialog.element;
var href = $("#k-editor-link-url", element).val();
var title, text, target;
var textInput = $("#k-editor-link-text", element);
if (href && href != HTTP_PROTOCOL) {
if (href.indexOf("@") > 0 && !/^(\w+:)|(\/\/)/i.test(href)) href = "mailto:" + href;
this.attributes = { href };
title = $("#k-editor-link-title", element).val();
if (title) this.attributes.title = title;
if (textInput.is(":visible")) {
text = kendo.trim(textInput.val());
if (!text && !this._initialText) this.attributes.innerText = href;
else if (text && text !== this._initialText) this.attributes.innerText = dom.stripBom(text);
}
target = $("#k-editor-link-target", element).is(":checked");
this.attributes.target = target ? "_blank" : null;
this.formatter.apply(this._range, this.attributes);
}
this._close(e);
if (this.change) this.change();
},
_close: function(e) {
e.preventDefault();
this._form.destroy();
this._dialog.destroy();
dom.windowFromDocument(RangeUtils.documentFromRange(this._range)).focus();
this.releaseRange(this._range);
},
linkUrl: function(anchor) {
if (anchor) return anchor.getAttribute("href", 2);
return HTTP_PROTOCOL;
},
linkText: function(nodes) {
var text = "";
var i;
for (i = 0; i < nodes.length; i++) text += nodes[i].nodeValue;
return dom.stripBom(text || "");
},
redo: function() {
var range = this.lockRange(true);
this.formatter.apply(range, this.attributes);
this.releaseRange(range);
}
});
var AutoLinkCommand = Command.extend({
init: function(options) {
Command.fn.init.call(this, options);
this.formatter = new LinkFormatter();
},
exec: function() {
var detectedLink = this.detectLink();
if (!detectedLink) return;
var range = this.getRange();
var linkMarker = new kendo.ui.editor.Marker();
var linkRange = range.cloneRange();
linkRange.setStart(detectedLink.start.node, detectedLink.start.offset);
linkRange.setEnd(detectedLink.end.node, detectedLink.end.offset);
range = this.lockRange();
linkMarker.add(linkRange);
this.formatter.apply(linkRange, { href: this._ensureWebProtocol(detectedLink.text) });
linkMarker.remove(linkRange);
this.releaseRange(range);
},
detectLink: function() {
var range = this.getRange();
var startNode = range.startContainer;
var startOffset = range.startOffset;
if (!startNode.previousSibling && (dom.isBom(startNode) && !startNode.nextSibling || !startOffset && dom.isDataNode(startNode))) {
startNode = startNode.parentNode;
startOffset = 0;
}
return new DomTextLinkDetection(new LeftDomTextTraverser({
node: startNode,
offset: startOffset,
cancelAtNode: function(node) {
return node && dom.name(node) === "a";
}
})).detectLink();
},
changesContent: function() {
return !!this.detectLink();
},
_ensureWebProtocol: function(linkText) {
return this._hasProtocolPrefix(linkText) ? linkText : this._prefixWithWebProtocol(linkText);
},
_hasProtocolPrefix: function(linkText) {
return protocolRegExp.test(linkText);
},
_prefixWithWebProtocol: function(linkText) {
return HTTP_PROTOCOL + linkText;
}
});
var UnlinkTool = Tool.extend({
init: function(options) {
this.options = options;
this.finder = new InlineFormatFinder([{ tags: ["a"] }]);
Tool.fn.init.call(this, $.extend(options, { command: UnlinkCommand }));
},
update: function(ui, nodes) {
var isLink = this.finder.isFormatted(nodes), toolbar = ui.closest(".k-toolbar").data("kendoToolBar");
if (isLink) toolbar.enable(ui, true);
else toolbar.enable(ui, false);
}
});
var DomTextLinkDetection = Class.extend({
init: function(traverser) {
this.traverser = traverser;
this.start = DomPos();
this.end = DomPos();
this.text = "";
},
detectLink: function() {
var node = this.traverser.node;
var offset = this.traverser.offset;
if (dom.isDataNode(node)) {
var text = node.data.substring(0, offset);
if (/\s{2}$/.test(dom.stripBom(text))) return;
} else if (offset === 0) {
var p = dom.closestEditableOfType(node, dom.blockElements);
if (p && p.previousSibling) this.traverser.init({ node: p.previousSibling });
}
this.traverser.traverse(this._detectEnd.bind(this));
if (!this.end.blank()) {
this.traverser = this.traverser.clone(this.end);
this.traverser.traverse(this._detectStart.bind(this));
if (!this._isLinkDetected()) {
new RightDomTextTraverser(this.traverser.extendOptions(this.start)).traverse(this._skipStartPuntuation.bind(this));
if (!this._isLinkDetected()) this.start = DomPos();
}
}
if (this.start.blank()) return null;
else return {
start: this.start,
end: this.end,
text: this.text
};
},
_isLinkDetected: function() {
return protocolRegExp.test(this.text) || /^w{3}\./i.test(this.text);
},
_detectEnd: function(text, node) {
var i = lastIndexOfRegExp(text, endLinkCharsRegExp);
if (i > -1) {
this.end.node = node;
this.end.offset = i + 1;
return false;
}
},
_detectStart: function(text, node) {
var i = lastIndexOfRegExp(text, /\s/);
var ii = i + 1;
this.text = text.substring(ii) + this.text;
this.start.node = node;
this.start.offset = ii;
if (i > -1) return false;
},
_skipStartPuntuation: function(text, node, offset) {
var i = indexOfRegExp(text, /\w/);
var ii = i;
if (i === -1) ii = text.length;
this.text = this.text.substring(ii);
this.start.node = node;
this.start.offset = ii + (offset | 0);
if (i > -1) return false;
}
});
function lastIndexOfRegExp(str, search) {
var i = str.length;
while (i-- && !search.test(str[i]));
return i;
}
function indexOfRegExp(str, search) {
var r = search.exec(str);
return r ? r.index : -1;
}
var DomPos = function() {
return {
node: null,
offset: null,
blank: function() {
return this.node === null && this.offset === null;
}
};
};
var DomTextTraverser = Class.extend({
init: function(options) {
this.node = options.node;
this.offset = options.offset === undefined ? dom.isDataNode(this.node) && this.node.length || 0 : options.offset;
this.cancelAtNode = options.cancelAtNode || this.cancelAtNode || $.noop;
},
traverse: function(callback) {
if (!callback) return;
this.cancel = false;
this._traverse(callback, this.node, this.offset);
},
_traverse: function(callback, node, offset) {
if (!node || this.cancel) return;
if (node.nodeType === 3) {
var text = node.data;
if (offset !== undefined) text = this.subText(text, offset);
this.cancel = callback(text, node, offset) === false;
} else {
var edgeNode = this.edgeNode(node);
this.cancel = this.cancel || this.cancelAtNode(edgeNode);
return this._traverse(callback, edgeNode);
}
var next = this.next(node);
if (!next) {
var parent = node.parentNode;
while (!next && dom.isInline(parent)) {
next = this.next(parent);
parent = parent.parentNode;
}
}
this.cancel = this.cancel || this.cancelAtNode(next);
this._traverse(callback, next);
},
extendOptions: function(o) {
return $.extend({
node: this.node,
offset: this.offset,
cancelAtNode: this.cancelAtNode
}, o || {});
},
edgeNode: function(node) {},
next: function(node) {},
subText: function(text, offset) {}
});
var LeftDomTextTraverser = DomTextTraverser.extend({
subText: function(text, splitIndex) {
return text.substring(0, splitIndex);
},
next: function(node) {
return node.previousSibling;
},
edgeNode: function(node) {
return node.lastChild;
},
clone: function(options) {
return new LeftDomTextTraverser(this.extendOptions(options));
}
});
var RightDomTextTraverser = DomTextTraverser.extend({
subText: function(text, splitIndex) {
return text.substring(splitIndex);
},
next: function(node) {
return node.nextSibling;
},
edgeNode: function(node) {
return node.firstChild;
},
clone: function(options) {
return new RightDomTextTraverser(this.extendOptions(options));
}
});
extend(kendo.ui.editor, {
LinkFormatFinder,
LinkFormatter,
UnlinkCommand,
LinkCommand,
AutoLinkCommand,
UnlinkTool,
DomTextLinkDetection,
LeftDomTextTraverser,
RightDomTextTraverser
});
registerTool("createLink", new Tool({
key: "K",
ctrl: true,
command: LinkCommand
}));
registerTool("unlink", new UnlinkTool({
key: "K",
ctrl: true,
shift: true,
ui: { enable: false }
}));
registerTool("autoLink", new Tool({
key: [keys.ENTER, keys.SPACEBAR],
keyPressCommand: true,
command: AutoLinkCommand
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/formatblock.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, dom = Editor.Dom, FormatTool = Editor.FormatTool, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, registerFormat = EditorUtils.registerFormat, RangeUtils = Editor.RangeUtils;
var BlockFormatFinder = Class.extend({
init: function(format) {
this.format = format;
},
contains: function(node, children) {
var i, len, child;
for (i = 0, len = children.length; i < len; i++) {
child = children[i];
if (!child || !dom.isAncestorOrSelf(node, child)) return false;
}
return true;
},
findSuitable: function(nodes) {
var format = this.format, suitable = [], i, len, candidate;
for (i = 0, len = nodes.length; i < len; i++) {
for (var f = format.length - 1; f >= 0; f--) {
candidate = dom.ofType(nodes[i], format[f].tags) ? nodes[i] : dom.closestEditableOfType(nodes[i], format[f].tags);
if (candidate) break;
}
if (!candidate || candidate.contentEditable === "true") return [];
if ($.inArray(candidate, suitable) < 0) suitable.push(candidate);
}
this._resolveListsItems(suitable);
for (i = 0, len = suitable.length; i < len; i++) if (this.contains(suitable[i], suitable)) return [suitable[i]];
return suitable;
},
_resolveListsItems: function(nodes) {
var i, node, wrapper;
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
wrapper = dom.is(node, "li") ? node : dom.wrapper(node);
wrapper = wrapper && dom.list(wrapper) ? wrapper.children[0] : wrapper;
if (dom.is(wrapper, "li")) nodes[i] = wrapper;
}
},
findFormat: function(sourceNode, until) {
var format = this.format, i, len, node, tags, attributes;
var editableParent = dom.editableParent(sourceNode);
var immutables = this.options && this.options.immutables;
var ImmutablesNS = Editor.Immutables;
for (i = 0, len = format.length; i < len; i++) {
node = sourceNode;
tags = format[i].tags;
attributes = format[i].attr;
if (immutables && tags && tags[0] == "immutable") {
var immutable = ImmutablesNS.immutableParent(node);
if (immutable && dom.attrEquals(immutable, attributes)) return node;
}
while (node && dom.isAncestorOf(editableParent, node)) {
if (dom.ofType(node, tags) && dom.attrEquals(node, attributes)) return node;
if (until && until(node)) break;
node = node.parentNode;
}
}
return null;
},
getFormat: function(nodes) {
var that = this, findFormat = function(node) {
return that.findFormat(dom.isDataNode(node) ? node.parentNode : node);
}, result = findFormat(nodes[0]), i, len;
if (!result) return "";
for (i = 1, len = nodes.length; i < len; i++) if (result != findFormat(nodes[i])) return "";
return result.nodeName.toLowerCase();
},
isFormatted: function(nodes, until) {
for (var i = 0, len = nodes.length; i < len; i++) if (!this.findFormat(nodes[i], until)) return false;
return true;
}
});
var BlockFormatter = Class.extend({
init: function(format, values) {
this.format = format;
this.values = values;
this.finder = new BlockFormatFinder(format);
},
wrap: function(tag, attributes, nodes) {
var commonAncestor = nodes.length == 1 ? dom.blockParentOrBody(nodes[0]) : dom.commonAncestor.apply(null, nodes);
if (dom.isInline(commonAncestor)) commonAncestor = dom.blockParentOrBody(commonAncestor);
var ancestors = dom.significantChildNodes(commonAncestor), position = dom.findNodeIndex(ancestors[0]), wrapper = dom.create(commonAncestor.ownerDocument, tag, attributes), i, ancestor;
for (i = 0; i < ancestors.length; i++) {
ancestor = ancestors[i];
if (dom.isBlock(ancestor)) {
dom.attr(ancestor, attributes);
if (wrapper.childNodes.length) {
dom.insertBefore(wrapper, ancestor);
wrapper = wrapper.cloneNode(false);
}
position = dom.findNodeIndex(ancestor) + 1;
continue;
}
wrapper.appendChild(ancestor);
}
if (wrapper.firstChild) dom.insertAt(commonAncestor, wrapper, position);
},
apply: function(nodes) {
var format, values = this.values;
function attributes(format) {
return extend({}, format && format.attr, values);
}
this._handleImmutables(nodes, true);
var images = dom.filter("img", nodes);
var imageAttributes = attributes(EditorUtils.formatByName("img", this.format));
$.each(images, function() {
dom.attr(this, imageAttributes);
});
if (images.length == nodes.length) return;
var nonImages = dom.filter("img", nodes, true);
var formatNodes = this.finder.findSuitable(nonImages);
if (formatNodes.length) for (var i = 0, len = formatNodes.length; i < len; i++) {
format = EditorUtils.formatByName(dom.name(formatNodes[i]), this.format);
dom.attr(formatNodes[i], attributes(format));
}
else {
format = this.format[0];
this.wrap(format.tags[0], attributes(format), nonImages);
}
},
_handleImmutables: function(nodes, applyFormatting) {
if (!this.immutables()) return;
var immutableFormat = EditorUtils.formatByName("immutable", this.format);
if (!immutableFormat) return;
var ImmutablesNS = Editor.Immutables;
for (var i = nodes.length - 1; i >= 0; i--) {
var immutableParent = ImmutablesNS.immutableParent(nodes[i]);
if (!immutableParent) continue;
if (immutableParent !== nodes[i + 1]) if (applyFormatting) dom.attr(immutableParent, immutableFormat.attr);
else dom.unstyle(immutableParent, immutableFormat.attr.style);
nodes.splice(i, 1);
}
},
immutables: function() {
return this.editor && this.editor.options.immutables;
},
remove: function(nodes) {
var i, l, formatNode, namedFormat, name;
this._handleImmutables(nodes, false);
for (i = 0, l = nodes.length; i < l; i++) {
formatNode = this.finder.findFormat(nodes[i]);
if (formatNode) {
name = dom.name(formatNode);
namedFormat = EditorUtils.formatByName(name, this.format);
if (namedFormat.attr.style) dom.unstyle(formatNode, namedFormat.attr.style);
if (namedFormat.attr.className) dom.removeClass(formatNode, namedFormat.attr.className);
}
}
},
toggle: function(range) {
var that = this, nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
if (that.finder.isFormatted(nodes)) that.remove(nodes);
else that.apply(nodes);
}
});
var GreedyBlockFormatter = Class.extend({
init: function(format, values) {
var that = this;
that.format = format;
that.values = values;
that.finder = new BlockFormatFinder(format);
},
apply: function(nodes) {
var format = this.format;
var blocks = dom.blockParents(nodes);
var formatTag = format[0].tags[0];
var i, len, list, formatter, range;
var element;
var tagName;
var block;
var immutalbeParent;
if (blocks.length) for (i = 0, len = blocks.length; i < len; i++) {
block = blocks[i];
immutalbeParent = this.immutables() && Editor.Immutables.immutableParent(block);
if (!immutalbeParent) {
tagName = dom.name(block);
if (tagName == "li") {
list = block.parentNode;
formatter = new Editor.ListFormatter(list.nodeName.toLowerCase(), formatTag);
range = this.editor.createRange();
range.selectNode(blocks[i]);
formatter.toggle(range);
} else if (formatTag && (tagName == "td" || block.attributes.contentEditable)) new BlockFormatter(format, this.values).apply(block.childNodes);
else {
element = dom.changeTag(block, formatTag);
dom.attr(element, format[0].attr);
}
}
}
else {
var blockFormatter = new BlockFormatter(format, this.values);
blockFormatter.editor = this.editor;
blockFormatter.apply(nodes);
}
},
toggle: function(range) {
var nodes = RangeUtils.textNodes(range);
if (!nodes.length) {
range.selectNodeContents(range.commonAncestorContainer);
nodes = RangeUtils.textNodes(range);
if (!nodes.length) nodes = dom.significantChildNodes(range.commonAncestorContainer);
}
this.apply(nodes);
},
immutables: function() {
return this.editor && this.editor.options.immutables;
}
});
var BlockFormatTool = FormatTool.extend({ init: function(options) {
FormatTool.fn.init.call(this, extend(options, {
finder: new BlockFormatFinder(options.format),
formatter: function() {
return new BlockFormatter(options.format);
}
}));
} });
extend(Editor, {
BlockFormatFinder,
BlockFormatter,
GreedyBlockFormatter,
BlockFormatTool
});
var listElements = [
"ul",
"ol",
"li"
];
registerFormat("justifyLeft", [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: "left" } }
},
{
tags: ["img"],
attr: { style: {
"float": "left",
display: "",
marginLeft: "",
marginRight: ""
} }
},
{
tags: ["immutable"],
attr: { style: {
"float": "left",
display: "",
marginLeft: "",
marginRight: ""
} }
},
{
tags: listElements,
attr: { style: {
textAlign: "left",
listStylePosition: ""
} }
}
]);
registerTool("justifyLeft", new BlockFormatTool({
format: formats.justifyLeft,
ui: {
togglable: true,
group: "align"
}
}));
registerFormat("justifyCenter", [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: "center" } }
},
{
tags: ["img"],
attr: { style: {
display: "block",
marginLeft: "auto",
marginRight: "auto",
"float": ""
} }
},
{
tags: ["immutable"],
attr: { style: {
display: "block",
marginLeft: "auto",
marginRight: "auto",
"float": ""
} }
},
{
tags: listElements,
attr: { style: {
textAlign: "center",
listStylePosition: "inside"
} }
}
]);
registerTool("justifyCenter", new BlockFormatTool({
format: formats.justifyCenter,
ui: {
togglable: true,
group: "align"
}
}));
registerFormat("justifyRight", [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: "right" } }
},
{
tags: ["img"],
attr: { style: {
"float": "right",
display: "",
marginLeft: "",
marginRight: ""
} }
},
{
tags: ["immutable"],
attr: { style: {
"float": "right",
display: "",
marginLeft: "",
marginRight: ""
} }
},
{
tags: listElements,
attr: { style: {
textAlign: "right",
listStylePosition: "inside"
} }
}
]);
registerTool("justifyRight", new BlockFormatTool({
format: formats.justifyRight,
ui: {
togglable: true,
group: "align"
}
}));
registerFormat("justifyFull", [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: "justify" } }
},
{
tags: ["img"],
attr: { style: {
display: "block",
marginLeft: "auto",
marginRight: "auto",
"float": ""
} }
},
{
tags: ["immutable"],
attr: { style: {
display: "block",
marginLeft: "auto",
marginRight: "auto",
"float": ""
} }
},
{
tags: listElements,
attr: { style: {
textAlign: "justify",
listStylePosition: ""
} }
}
]);
registerTool("justifyFull", new BlockFormatTool({
format: formats.justifyFull,
ui: {
togglable: true,
group: "align"
}
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/lists.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, Command = Editor.Command, FormatTool = Editor.FormatTool, BlockFormatFinder = Editor.BlockFormatFinder, textNodes = RangeUtils.textNodes, registerTool = Editor.EditorUtils.registerTool;
var ListFormatFinder = BlockFormatFinder.extend({
init: function(options) {
this.tag = options.tag;
this.attr = options.attr;
this.altAttr = options.altAttr;
var tags = this.tags = [this.tag == "ul" ? "ol" : "ul", this.tag];
var format = [{
tags,
attr: this.attr
}];
if (this.altAttr) format.push({
tags,
attr: this.altAttr
});
BlockFormatFinder.fn.init.call(this, format);
},
matchesType: function(node) {
return dom.attrEquals(node, this.attr) || this.altAttr && dom.attrEquals(node, this.altAttr);
},
isList: function(node) {
return dom.list(node);
},
isFormatted: function(nodes) {
var formatNodes = [];
var formatNode, i;
for (i = 0; i < nodes.length; i++) {
formatNode = this.findFormat(nodes[i], this.isList);
if (formatNode && dom.name(formatNode) == this.tag && this.matchesType(formatNode)) formatNodes.push(formatNode);
}
if (formatNodes.length < 1) return false;
if (formatNodes.length != nodes.length) return false;
for (i = 0; i < formatNodes.length; i++) {
if (formatNodes[i].parentNode != formatNode.parentNode) break;
if (formatNodes[i] != formatNode) return false;
}
return true;
},
findSuitable: function(nodes) {
var candidate = this.findFormat(nodes[0], this.isList);
if (candidate && dom.name(candidate) == this.tag) return candidate;
return null;
}
});
var ListFormatter = Class.extend({
init: function(options, unwrapTag) {
var that = this;
options = $.isPlainObject(options) ? options : {
tag: options,
attr: null
};
that.tag = options.tag;
that.attr = options.attr;
that.finder = new ListFormatFinder(options);
that.unwrapTag = unwrapTag;
},
isList: function(node) {
return dom.list(node);
},
immutables: function() {
return this.editor && !!this.editor.options.immutables;
},
wrap: function(list, nodes) {
var li = dom.create(list.ownerDocument, "li"), i, node, isImmutable = this.immutables() ? Editor.Immutables.immutable : $.noop;
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
if (dom.is(node, "li")) {
list.appendChild(node);
continue;
}
if (this.isList(node)) {
while (node.firstChild) list.appendChild(node.firstChild);
continue;
}
if (dom.is(node, "td")) {
while (node.firstChild) li.appendChild(node.firstChild);
list.appendChild(li);
node.appendChild(list);
list = list.cloneNode(false);
li = li.cloneNode(false);
continue;
}
li.appendChild(node);
if (dom.isBlock(node)) {
list.appendChild(li);
if (!isImmutable(node)) dom.unwrap(node);
li = li.cloneNode(false);
}
}
if (li.firstChild) list.appendChild(li);
},
containsAny: function(parent, nodes) {
for (var i = 0; i < nodes.length; i++) if (dom.isAncestorOrSelf(parent, nodes[i])) return true;
return false;
},
suitable: function(candidate, nodes) {
if (candidate.className == "k-marker") {
var sibling = candidate.nextSibling;
if (sibling && dom.isBlock(sibling)) return false;
sibling = candidate.previousSibling;
if (sibling && dom.isBlock(sibling)) return false;
}
return this.containsAny(candidate, nodes) || dom.isInline(candidate) || candidate.nodeType == 3;
},
_parentLists: function(node) {
var editable = dom.closestEditable(node);
return $(node).parentsUntil(editable, "ul,ol");
},
split: function(range) {
var nodes = textNodes(range);
var start, end, parents;
if (nodes.length) {
start = dom.parentOfType(nodes[0], ["li"]);
end = dom.parentOfType(nodes[nodes.length - 1], ["li"]);
range.setStartBefore(start);
range.setEndAfter(end);
for (var i = 0, l = nodes.length; i < l; i++) {
var formatNode = this.finder.findFormat(nodes[i]);
if (formatNode) {
parents = this._parentLists(formatNode);
if (parents.length) RangeUtils.split(range, parents.last()[0], true);
else RangeUtils.split(range, formatNode, true);
}
}
}
},
merge: function(tag, formatNode) {
var prev = formatNode.previousSibling, next;
while (prev && (prev.className == "k-marker" || prev.nodeType == 3 && dom.isWhitespace(prev))) prev = prev.previousSibling;
if (prev && dom.name(prev) == tag && this.finder.matchesType(prev)) {
while (formatNode.firstChild) prev.appendChild(formatNode.firstChild);
dom.remove(formatNode);
formatNode = prev;
}
next = formatNode.nextSibling;
while (next && (next.className == "k-marker" || next.nodeType == 3 && dom.isWhitespace(next))) next = next.nextSibling;
if (next && dom.name(next) == tag && this.finder.matchesType(next)) {
while (formatNode.lastChild) next.insertBefore(formatNode.lastChild, next.firstChild);
dom.remove(formatNode);
}
},
breakable: function(node) {
return node != node.ownerDocument.body && !/table|tbody|thead|tr|td/.test(dom.name(node)) && !node.attributes.contentEditable;
},
findSuitableNode: function(nodes) {
var that = this, finder = that.finder, tag = that.tag, formatNode = finder.findSuitable(nodes);
if (!formatNode) {
finder = new ListFormatFinder({ tag: tag == "ul" ? "ol" : "ul" });
formatNode = finder.findSuitable(nodes);
}
if (!formatNode) {
finder = new ListFormatFinder({ tag });
formatNode = finder.findSuitable(nodes);
formatNode = formatNode && that.finder.matchesType(formatNode) ? null : formatNode;
}
return formatNode;
},
applyOnSection: function(section, nodes) {
var tag = this.tag;
var attr = this.attr;
var commonAncestor = dom.closestSplittableParent(nodes);
var ancestors = [];
var formatNode = this.findSuitableNode(nodes);
var childNodes;
if (/table|tbody|thead/.test(dom.name(commonAncestor))) childNodes = $.map(nodes, function(node) {
return dom.parentOfType(node, ["td"]);
});
else {
childNodes = dom.significantChildNodes(commonAncestor);
if ($.grep(childNodes, dom.isBlock).length) childNodes = $.grep(childNodes, (function(node) {
return this.containsAny(node, nodes);
}).bind(this));
if (!childNodes.length) childNodes = nodes;
}
function pushAncestor() {
ancestors.push(this);
}
for (var i = 0; i < childNodes.length; i++) {
var child = childNodes[i];
if (!((!formatNode || !dom.isAncestorOrSelf(formatNode, child)) && this.suitable(child, nodes))) continue;
if (formatNode && this.isList(child)) {
$.each(child.children, pushAncestor);
dom.remove(child);
} else ancestors.push(child);
}
if (ancestors.length == childNodes.length && this.breakable(commonAncestor)) ancestors = [commonAncestor];
if (!formatNode) {
formatNode = dom.create(commonAncestor.ownerDocument, tag, attr);
if (dom.isBlock(ancestors[0])) dom.mergeAttributes(ancestors[0], formatNode);
dom.insertBefore(formatNode, ancestors[0]);
}
this.wrap(formatNode, ancestors);
while (dom.isBom(formatNode.nextSibling)) dom.remove(formatNode.nextSibling);
if (!this.finder.matchesType(formatNode)) {
formatNode.removeAttribute("type");
formatNode.style.listStyleType = "";
dom.mergeAttributes(dom.create(commonAncestor.ownerDocument, tag, attr), formatNode, true);
}
if (formatNode && formatNode.getAttribute("type") === "") formatNode.removeAttribute("type");
if (!dom.is(formatNode, tag)) dom.changeTag(formatNode, tag);
this.merge(tag, formatNode);
},
apply: function(nodes) {
var i = 0, sections = [], lastSection, lastNodes, section, node, l = nodes.length, immutableParent = this.immutables() ? Editor.Immutables.immutableParent : $.noop;
function addLastSection() {
if (lastSection) sections.push({
section: lastSection,
nodes: lastNodes
});
}
for (i = 0; i < l; i++) {
node = immutableParent(nodes[i]) || nodes[i];
section = dom.closestEditable(node, [
"td",
"th",
"body"
]);
if (!lastSection || section != lastSection) {
addLastSection();
lastNodes = [node];
lastSection = section;
} else lastNodes.push(node);
}
addLastSection();
for (i = 0; i < sections.length; i++) this.applyOnSection(sections[i].section, sections[i].nodes);
},
unwrap: function(ul) {
var fragment = ul.ownerDocument.createDocumentFragment(), unwrapTag = this.unwrapTag, parents, li, p, child;
for (li = ul.firstChild; li; li = li.nextSibling) {
p = dom.create(ul.ownerDocument, unwrapTag || "p");
while (li.firstChild) {
child = li.firstChild;
if (dom.isBlock(child)) {
if (p.firstChild) {
fragment.appendChild(p);
p = dom.create(ul.ownerDocument, unwrapTag || "p");
}
fragment.appendChild(child);
} else p.appendChild(child);
}
if (p.firstChild) fragment.appendChild(p);
}
parents = this._parentLists(ul);
if (parents[0]) {
dom.insertAfter(fragment, parents.last()[0]);
parents.last().remove();
} else dom.insertAfter(fragment, ul);
dom.remove(ul);
},
remove: function(nodes) {
var formatNode;
for (var i = 0, l = nodes.length; i < l; i++) {
formatNode = this.finder.findFormat(nodes[i]);
if (formatNode) this.unwrap(formatNode);
}
},
toggle: function(range) {
var that = this, nodes = textNodes(range), ancestor = range.commonAncestorContainer;
if (!nodes.length) {
range.selectNodeContents(ancestor);
nodes = textNodes(range);
if (!nodes.length) {
var text = ancestor.ownerDocument.createTextNode("");
range.startContainer.appendChild(text);
nodes = [text];
range.selectNode(text.parentNode);
}
}
nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
if (that.finder.isFormatted(nodes)) {
that.split(range);
that.remove(nodes);
} else that.apply(nodes);
}
});
var ListCommand = Command.extend({ init: function(options) {
options.formatter = new ListFormatter({
tag: options.tag,
attr: options.attr
});
Command.fn.init.call(this, options);
} });
var ListTool = FormatTool.extend({
init: function(options) {
this.options = options;
FormatTool.fn.init.call(this, extend(options, { finder: new ListFormatFinder(options) }));
},
command: function(commandArguments) {
return new ListCommand(extend(commandArguments, {
tag: this.options.tag,
attr: this.options.attr
}));
}
});
extend(Editor, {
ListFormatFinder,
ListFormatter,
ListCommand,
ListTool
});
registerTool("insertUnorderedList", new ListTool({
tag: "ul",
attr: {
style: { listStyleType: "" },
type: ""
},
ui: {
togglable: true,
group: "lists"
}
}));
registerTool("insertOrderedList", new ListTool({
tag: "ol",
attr: {
style: { listStyleType: "" },
type: ""
},
ui: {
togglable: true,
group: "lists"
}
}));
registerTool("insertUpperRomanList", new ListTool({
tag: "ol",
attr: { style: { listStyleType: "upper-roman" } },
altAttr: { type: "I" },
ui: {
togglable: true,
group: "lists"
}
}));
registerTool("insertLowerRomanList", new ListTool({
tag: "ol",
attr: { style: { listStyleType: "lower-roman" } },
altAttr: { type: "i" },
ui: {
togglable: true,
group: "lists"
}
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/formatting.js
(function($) {
var kendo = window.kendo, Editor = kendo.ui.editor, Tool = Editor.Tool, DelayedExecutionTool = Editor.DelayedExecutionTool, Command = Editor.Command, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, registerTool = EditorUtils.registerTool;
var FormattingTool = DelayedExecutionTool.extend({
init: function(options) {
var that = this;
Tool.fn.init.call(that, kendo.deepExtend({}, that.options, options));
that.type = "kendoDropDownList";
that.finder = { getFormat: function() {
return "";
} };
},
options: {
items: [
{
text: "Paragraph",
value: "p"
},
{
text: "Quotation",
value: "blockquote"
},
{
text: "Heading 1",
value: "h1"
},
{
text: "Heading 2",
value: "h2"
},
{
text: "Heading 3",
value: "h3"
},
{
text: "Heading 4",
value: "h4"
},
{
text: "Heading 5",
value: "h5"
},
{
text: "Heading 6",
value: "h6"
}
],
width: 110
},
toFormattingItem: function(item) {
var value = item.value;
if (!value) return item;
if (item.tag || item.className) return item;
var dot = value.indexOf(".");
if (dot === 0) item.className = value.substring(1);
else if (dot == -1) item.tag = value;
else {
item.tag = value.substring(0, dot);
item.className = value.substring(dot + 1);
}
return item;
},
command: function(args) {
var that = this;
var item = args.value;
item = this.toFormattingItem(item);
return new Editor.FormatCommand({
range: args.range,
formatter: function() {
var formatter, tags = (item.tag || item.context || "span").split(","), format = [{
tags,
attr: { className: item.className || "" }
}];
if ($.inArray(tags[0], dom.inlineElements) >= 0) formatter = new Editor.GreedyInlineFormatter(format);
else formatter = new Editor.GreedyBlockFormatter(format);
formatter.editor = that.editor;
return formatter;
}
});
},
decorate: function(body) {
var component = this.component, dataSource = component.dataSource, items = dataSource.data(), i, tag, className, style;
if (body) component.list.css("background-color", dom.getEffectiveBackground($(body)));
if (this.component && this.component.options && this.component.options.unsafeInline !== false) for (i = 0; i < items.length; i++) {
tag = items[i].tag || "span";
className = items[i].className;
style = dom.inlineStyle(body, tag, { className });
style = style.replace(/"/g, "'");
items[i].style = style + ";display:inline-block";
}
dataSource.trigger("change");
},
initialize: function(ui, editor) {
var options = this.options;
var toolName = options.name;
var that = this;
var component = ui.getKendoDropDownList();
if (!component) return;
that.editor = editor;
that.component = component;
ui.closest(".k-dropdownlist").width(options.width);
component.setOptions({
optionLabel: editor.options.messages.formatting,
change: () => {
var dataItem = component.dataItem();
if (dataItem) Tool.exec(editor, toolName, dataItem.toJSON());
},
dataBound: function() {
var i, items = component.dataSource.data(), optionLabel = component.list.parent().find(".k-list-optionlabel");
for (i = 0; i < items.length; i++) items[i] = that.toFormattingItem(items[i]);
if (optionLabel.length) optionLabel.remove();
}
});
},
getFormattingValue: function(items, nodes) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
var selector = (item.tag || item.context || "") + (item.className ? "." + item.className : "");
if (!$(nodes[0]).closest(selector)[0]) continue;
if (nodes.length == 1) return item.value;
for (var n = 1; n < nodes.length; n++) if (!$(nodes[n]).closest(selector)[0]) break;
else if (n == nodes.length - 1) return item.value;
}
return "";
},
update: function(ui, nodes) {
var selectBox = $(ui).data(this.type);
if (!selectBox) return;
var dataSource = selectBox.dataSource, items = dataSource.data(), i, context, ancestor = dom.commonAncestor.apply(null, nodes);
if (ancestor != dom.closestEditable(ancestor) && this._ancestor == ancestor) return;
else this._ancestor = ancestor;
for (i = 0; i < items.length; i++) {
context = items[i].context;
items[i].visible = !context || !!$(ancestor).closest(context).length;
}
dataSource.filter([{
field: "visible",
operator: "eq",
value: true
}]);
DelayedExecutionTool.fn.update.call(this, ui, nodes);
selectBox.value(this.getFormattingValue(dataSource.view(), nodes));
selectBox.wrapper.toggleClass("k-disabled", !dataSource.view().length);
},
destroy: function() {
this._ancestor = null;
}
});
var CleanFormatCommand = Command.extend({
exec: function() {
var range = this.lockRange(true);
this.tagsToClean = this.options.remove || "strong,em,span,sup,sub,del,b,i,u,font".split(",");
RangeUtils.wrapSelectedElements(range);
var nodes = RangeUtils.mapAll(range, function(node) {
return node;
});
for (var c = nodes.length - 1; c >= 0; c--) {
var node = nodes[c];
if (!this.immutableParent(node)) this.clean(node);
}
this.releaseRange(range);
},
clean: function(node) {
if (!node || dom.isMarker(node)) return;
var name = dom.name(node);
if (name == "ul" || name == "ol") {
var listFormatter = new Editor.ListFormatter(name);
var prev = node.previousSibling;
var next = node.nextSibling;
listFormatter.unwrap(node);
for (; prev && prev != next; prev = prev.nextSibling) this.clean(prev);
} else if (name == "blockquote") dom.changeTag(node, "p");
else if (node.nodeType == 1 && !dom.insignificant(node)) {
for (var i = node.childNodes.length - 1; i >= 0; i--) this.clean(node.childNodes[i]);
node.removeAttribute("style");
node.removeAttribute("class");
} else unwrapListItem(node);
if ($.inArray(name, this.tagsToClean) > -1) dom.unwrap(node);
},
immutableParent: function(node) {
return this.immutables() && Editor.Immutables.immutableParent(node);
}
});
function unwrapListItem(node) {
var li = dom.closestEditableOfType(node, ["li"]);
if (li) {
var listFormatter = new Editor.ListFormatter(dom.name(li.parentNode));
var range = kendo.ui.editor.W3CRange.fromNode(node);
range.selectNode(li);
listFormatter.toggle(range);
}
}
$.extend(Editor, {
FormattingTool,
CleanFormatCommand
});
registerTool("formatting", new FormattingTool({ ui: {
type: "component",
component: "DropDownList",
componentOptions: {
dataTextField: "text",
dataValueField: "value",
highlightFirst: false,
autoWidth: true,
template: kendo.template((data) => `<span unselectable="on" ${data.style ? `class="k-d-block" style="display:block;${data.style || ""}` : ""}">${kendo.htmlEncode(data.text)}</span>`)
},
overflow: "never"
} }));
registerTool("cleanFormatting", new Tool({ command: CleanFormatCommand }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/image.js
(function($, undefined) {
var kendo = window.kendo, extend = $.extend, encode = kendo.htmlEncode, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, RangeUtils = Editor.RangeUtils, Command = Editor.Command, keys = kendo.keys, KEDITORIMAGEURL = "#k-editor-image-url", KEDITORIMAGETITLE = "#k-editor-image-title", KEDITORIMAGEWIDTH = "#k-editor-image-width", KEDITORIMAGEHEIGHT = "#k-editor-image-height";
var ImageCommand = Command.extend({
init: function(options) {
var that = this;
Command.fn.init.call(that, options);
that.async = true;
that.attributes = {};
},
insertImage: function(img, range) {
var attributes = this.attributes;
var doc = RangeUtils.documentFromRange(range);
if (attributes.src && attributes.src != "http://") {
var removeIEAttributes = function() {
setTimeout(function() {
if (!attributes.width) img.removeAttribute("width");
if (!attributes.height) img.removeAttribute("height");
img.removeAttribute("complete");
});
};
if (!img) {
img = dom.create(doc, "img", attributes);
img.onload = img.onerror = removeIEAttributes;
range.deleteContents();
range.insertNode(img);
if (!img.nextSibling) dom.insertAfter(doc.createTextNode(""), img);
removeIEAttributes();
range.setStartAfter(img);
range.setEndAfter(img);
RangeUtils.selectRange(range);
return true;
} else {
img.onload = img.onerror = removeIEAttributes;
dom.attr(img, attributes);
removeIEAttributes();
}
}
return false;
},
redo: function() {
var that = this, range = that.lockRange();
if (!that.insertImage(RangeUtils.image(range), range)) that.releaseRange(range);
},
exec: function() {
var that = this, range = that.lockRange(), applied = false, img = RangeUtils.image(range), imageWidth = img && img.getAttribute("width") || "", imageHeight = img && img.getAttribute("height") || "", dialog, form, isIE = kendo.support.browser.msie, options = that.editor.options, messages = options.messages, imageBrowser = options.imageBrowser, showBrowser = !!(kendo.ui.ImageBrowser && imageBrowser && imageBrowser.transport && imageBrowser.transport.read !== undefined), dialogOptions = {
title: messages.insertImage,
visible: false,
resizable: showBrowser
};
this.expandImmutablesIn(range);
function apply(e) {
var element = dialog.element, w = parseInt(element.find(KEDITORIMAGEWIDTH).val(), 10), h = parseInt(element.find(KEDITORIMAGEHEIGHT).val(), 10);
that.attributes = {
src: element.find(KEDITORIMAGEURL).val().replace(/ /g, "%20"),
alt: element.find(KEDITORIMAGETITLE).val()
};
that.attributes.width = null;
that.attributes.height = null;
if (!isNaN(w) && w > 0) that.attributes.width = w;
if (!isNaN(h) && h > 0) that.attributes.height = h;
applied = that.insertImage(img, range);
close(e);
if (that.change) that.change();
that.editor._handleSpaceAndNewLines();
}
function close(e) {
e.preventDefault();
form.destroy();
dialog.destroy();
dom.windowFromDocument(RangeUtils.documentFromRange(range)).focus();
if (!applied) that.releaseRange(range);
}
function keyDown(e) {
if (e.keyCode == keys.ENTER) apply(e);
else if (e.keyCode == keys.ESC) close(e);
}
dialogOptions.close = close;
if (showBrowser) dialogOptions.width = 750;
dialogOptions.minWidth = 350;
dialog = this.createDialog("<div/>", dialogOptions).data("kendoWindow");
form = that._createForm(dialog, showBrowser);
dialog.element.toggleClass("k-filebrowser-dialog", showBrowser);
dialog.wrapper.find(".k-dialog-insert").on("click", apply).end().find(".k-dialog-close").on("click", close).end().find(".k-form-field input").on("keydown", keyDown).end().find(KEDITORIMAGEURL).val(img ? img.getAttribute("src", 2) : "http://").end().find(KEDITORIMAGETITLE).val(img ? img.alt : "").end().find(KEDITORIMAGEWIDTH).val(imageWidth).end().find(KEDITORIMAGEHEIGHT).val(imageHeight).end();
var element = dialog.element;
if (showBrowser) {
this._imageBrowser = new kendo.ui.ImageBrowser(element.find(".k-imagebrowser"), extend({}, imageBrowser));
this._imageBrowser.bind("change", function(ev) {
if (ev.selected.get("type") === "f") element.find(KEDITORIMAGEURL).val(this.value());
});
this._imageBrowser.bind("apply", apply);
}
if (isIE) {
var dialogHeight = element.closest(".k-window").height();
element.css("max-height", dialogHeight);
}
dialog.center().open();
element.find(KEDITORIMAGEURL).trigger("focus").select();
},
_createForm: function(dialog, showBrowser) {
var that = this;
var formElement = $("<div/>").appendTo(dialog.element);
var messages = that.editor.options.messages;
var form = formElement.kendoForm({
renderButtons: false,
items: [
{
field: "k-editor-image-url",
label: encode(messages.imageWebAddress),
editor: "TextBox"
},
{
field: "k-editor-image-title",
label: encode(messages.imageAltText),
editor: "TextBox"
},
{
field: "k-editor-image-width",
label: encode(messages.imageWidth),
editor: "TextBox"
},
{
field: "k-editor-image-height",
label: encode(messages.imageHeight),
editor: "TextBox"
}
]
}).data("kendoForm");
if (showBrowser) formElement.prepend($("<div class=\"k-filebrowser k-imagebrowser\"></div>"));
dialog.element.after($(that._actionButtonsTemplate({
messages,
insertButtonIcon: "image-add",
cancelButtonIcon: "cancel"
})));
return form;
}
});
kendo.ui.editor.ImageCommand = ImageCommand;
registerTool("insertImage", new Editor.Tool({ command: ImageCommand }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/import.js
(function($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, registerTool = EditorUtils.registerTool, loadingOverlay = "<div contenteditable=\"false\" class=\"k-loading-mask\" style=\"width: 100%; height: 100%; position: absolute; top: 0px; left: 0px;\"><div class=\"k-loading-image\"></div><div class=\"k-loading-color\"></div></div>";
var ImportCommand = Command.extend({
exec: function() {
(this.editor._uploadWidget || this._initializeUploadWidget()).element.click();
},
_initializeUploadWidget: function() {
var cmd = this;
var editor = cmd.editor;
var importOptions = editor.options["import"];
var upload = $("<input id=\"editorImport\" name=\"files\" type=\"file\" />").kendoUpload({
success: cmd._onUploadSuccess.bind(cmd),
progress: cmd._onUploadProgress.bind(cmd),
select: cmd._onUploadSelect.bind(cmd),
error: cmd._onUploadError.bind(cmd),
complete: cmd._onUploadComplete.bind(cmd),
showFileList: false,
multiple: false,
async: {
saveUrl: importOptions.proxyURL,
autoUpload: true,
saveField: "file"
},
validation: {
allowedExtensions: importOptions.allowedExtensions,
maxFileSize: importOptions.maxFileSize
}
}).getKendoUpload();
editor._uploadWidget = upload;
return upload;
},
_onUploadComplete: function(ev) {
this._trigger("complete", ev);
ev.sender.clearAllFiles();
this._removeLoadingOverlay();
},
_onUploadSuccess: function(ev) {
this.editor.value(ev.response.html.replace(/<\/?body>/gi, ""));
this._trigger("success", ev);
},
_onUploadProgress: function(ev) {
this._trigger("progress", ev);
},
_onUploadSelect: function(ev) {
this._trigger("select", ev);
if (!ev.files[0].validationErrors) this._initLoadingOverlay();
},
_onUploadError: function(ev) {
this._trigger("error", ev);
},
_trigger: function(eventType, uploadEvent) {
var editor = this.editor;
var importOptions = editor.options["import"];
if (typeof importOptions[eventType] === "function") importOptions[eventType].call(editor, uploadEvent);
},
_initLoadingOverlay: function() {
var editable = this.editor.body;
if (Editor.Dom.is(editable, "body")) this._iframeWrapper = this._container = this.editor.wrapper.find("iframe").parent().css({ position: "relative" }).append(loadingOverlay);
else this._container = $(editable).append(loadingOverlay);
kendo.ui.progress(this._container, true);
},
_removeLoadingOverlay: function() {
kendo.ui.progress(this._container, false);
$(this._iframeWrapper).css({ position: "" });
delete this._container;
delete this._iframeWrapper;
}
});
var ImportTool = Tool.extend({ initialize: function(ui, editor) {
ui.find(".k-button-text").text(kendo.ui.Editor.fn.options.messages["import"]);
} });
extend(Editor, {
ImportCommand,
ImportTool
});
registerTool("import", new ImportTool({
command: ImportCommand,
ui: { showText: "both" }
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/insert.js
(function($) {
var editorNS = window.kendo.ui.editor, Command = editorNS.Command, GenericCommand = editorNS.GenericCommand, registerTool = editorNS.EditorUtils.registerTool, Tool = editorNS.Tool, RestorePoint = editorNS.RestorePoint, extend = $.extend;
var InsertHtmlCommand = Command.extend({
init: function(options) {
Command.fn.init.call(this, options);
this.managesUndoRedo = true;
},
exec: function() {
var editor = this.editor;
var options = this.options;
var range = options.range;
var body = editor.body;
var startRestorePoint = new RestorePoint(range, body);
var html = options.html || options.value || "";
editor.selectRange(range);
editor.clipboard.paste(html, options);
if (options.postProcess) options.postProcess(editor, editor.getRange());
var genericCommand = new GenericCommand(startRestorePoint, new RestorePoint(editor.getRange(), body));
genericCommand.editor = editor;
editor.undoRedoStack.push(genericCommand);
editor.focus();
}
});
var InsertHtmlTool = Tool.extend({
initialize: function(ui, editor) {
var options = this.options, dataSource = options.items ? options.items : editor.options.insertHtml, component = ui.getKendoDropDownList();
if (!component) return;
component.one("open", () => {
var optionLabel = component.list.parent().find(".k-list-optionlabel");
if (optionLabel.length) optionLabel.remove();
});
component.setOptions({
dataSource,
optionLabel: editor.options.messages.insertHtml
});
component.bind("change", () => {
Tool.exec(editor, "insertHtml", component.value());
});
},
command: function(commandArguments) {
return new InsertHtmlCommand(commandArguments);
},
update: function(ui) {
var component = ui.data("kendoDropDownList");
component.close();
component.value(null);
}
});
extend(editorNS, {
InsertHtmlCommand,
InsertHtmlTool
});
registerTool("insertHtml", new InsertHtmlTool({ ui: {
initialValue: "Insert HTML",
type: "component",
component: "DropDownList",
componentOptions: {
dataTextField: "text",
dataValueField: "value",
autoSize: true,
highlightFirst: false
},
overflow: "never"
} }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/export.js
(function($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, registerTool = EditorUtils.registerTool, defaultExportAsItems = [
{
text: "Docx",
value: "docx"
},
{
text: "Rtf",
value: "rtf"
},
{
text: "Pdf",
value: "pdf"
},
{
text: "Html",
value: "html"
},
{
text: "Plain Text",
value: "txt"
}
];
var ExportAsCommand = Command.extend({
init: function(options) {
var cmd = this;
cmd.options = options;
Command.fn.init.call(cmd, options);
cmd.attributes = null;
cmd.exportType = options.exportType;
},
exec: function() {
var cmd = this;
var range = this.lockRange(true);
cmd.postToProxy();
cmd.releaseRange(range);
},
postToProxy: function() {
this.generateForm().appendTo("body").submit().remove();
},
generateForm: function() {
var cmd = this;
var exportAsOptions = cmd.editor.options.exportAs;
var form = $("<form>").attr({
action: exportAsOptions && exportAsOptions.proxyURL || "",
method: "POST"
});
form.append([
cmd.valueInput(),
cmd.exportTypeInput(),
cmd.fileNameInput(),
cmd.antiForgeryInput()
]);
return form;
},
valueInput: function() {
var editor = this.editor;
return $("<input>").attr({
value: editor.encodedValue(),
name: "value",
type: "hidden"
});
},
exportTypeInput: function() {
var cmd = this;
return $("<input>").attr({
value: cmd.exportType,
name: "exportType",
type: "hidden"
});
},
fileNameInput: function() {
var editor = this.editor;
var exportAsOptions = editor.options.exportAs;
var fileName = exportAsOptions && exportAsOptions.fileName || editor.element.attr("id") || "editor";
return $("<input>").attr({
value: fileName,
name: "fileName",
type: "hidden"
});
},
antiForgeryInput: function() {
var csrf_param = $("meta[name=csrf-param],meta[name=_csrf_header]").attr("content");
return $("input[name^='__RequestVerificationToken']").clone().add($("input[name^='" + csrf_param + "']").clone());
}
});
var ExportAsTool = Tool.extend({
init: function(options) {
var tool = this;
Tool.fn.init.call(tool, kendo.deepExtend({}, tool.options, options));
tool.type = "kendoDropDownList";
},
options: { items: defaultExportAsItems },
command: function(args) {
var value = args.value;
return new Editor.ExportAsCommand({
range: args.range,
exportType: value.exportType
});
},
initialize: function(ui, editor) {
var tool = this, component = ui.getKendoDropDownList();
tool.editor = editor;
component.bind("change", this.changeHandler.bind(this));
},
changeHandler: function(e) {
this._exec(e.sender.value());
e.sender.value(null);
e.sender.wrapper.find(".k-export-tool-text").text(kendo.htmlEncode(kendo.ui.Editor.fn.options.messages.exportAs));
},
update: function(ui, editor) {
var component = ui.data("kendoDropDownList");
component.close();
component.value(null);
ui.closest(".k-dropdownlist").find(".k-export-tool-text").text(kendo.htmlEncode(kendo.ui.Editor.fn.options.messages.exportAs));
},
_exec: function(value) {
if (value) Tool.exec(this.editor, this.options.name, { exportType: value });
},
destroy: function() {
this._ancestor = null;
}
});
extend(Editor, {
ExportAsTool,
ExportAsCommand
});
registerTool("exportAs", new ExportAsTool({ ui: {
type: "component",
overflow: "never",
component: "DropDownList",
componentOptions: {
dataTextField: "text",
dataValueField: "value",
valuePrimitive: true,
value: null,
width: "140px",
highlightFirst: false,
autoWidth: true,
itemTemplate: (data) => `<span class="k-link k-menu-link" data-value="${data.value}">${data.text}</strong></span>`,
icon: "export",
valueTemplate: () => `<span class="k-editor-export">${kendo.ui.icon({
icon: "export",
iconClass: "k-button-icon"
})}<span class="k-export-tool-text"></span></span>`
}
} }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/indent.js
(function($, undefined) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, registerTool = Editor.EditorUtils.registerTool, Command = Editor.Command, Tool = Editor.Tool, RangeUtils = Editor.RangeUtils, blockElements = dom.blockElements, BlockFormatFinder = Editor.BlockFormatFinder, BlockFormatter = Editor.BlockFormatter;
function indent(node, value) {
var indentDirection = $(node).css("direction") == "rtl" ? "Right" : "Left", property = dom.name(node) != "td" ? "margin" + indentDirection : "padding" + indentDirection;
if (value === undefined) return node.style[property] || 0;
else if (value > 0) node.style[property] = value + "px";
else {
node.style[property] = "";
if (!node.style.cssText) node.removeAttribute("style");
}
}
var IndentFormatter = Class.extend({
init: function() {
this.finder = new BlockFormatFinder([{ tags: dom.blockElements }]);
},
apply: function(nodes) {
nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
var formatNodes = this.finder.findSuitable(nodes), targets = [], i, len, formatNode, parentList, sibling;
formatNodes = this.mapImmutables(formatNodes);
if (formatNodes.length) {
for (i = 0, len = formatNodes.length; i < len; i++) if (dom.is(formatNodes[i], "li")) {
if (!$(formatNodes[i]).index()) targets.push(formatNodes[i].parentNode);
else if ($.inArray(formatNodes[i].parentNode, targets) < 0) targets.push(formatNodes[i]);
} else targets.push(formatNodes[i]);
while (targets.length) {
formatNode = targets.shift();
if (dom.is(formatNode, "li")) {
parentList = formatNode.parentNode;
sibling = $(formatNode).prev("li");
var siblingList = sibling.find("ul,ol").last();
var nestedList = $(formatNode).children("ul,ol")[0];
if (nestedList && sibling[0]) if (siblingList[0]) {
siblingList.append(formatNode);
siblingList.append($(nestedList).children());
dom.remove(nestedList);
} else {
sibling.append(nestedList);
nestedList.insertBefore(formatNode, nestedList.firstChild);
}
else {
nestedList = sibling.children("ul,ol")[0];
if (!nestedList) {
nestedList = dom.create(formatNode.ownerDocument, dom.name(parentList), this.getListTypeAttr(parentList));
sibling.append(nestedList);
}
while (formatNode && formatNode.parentNode == parentList) {
nestedList.appendChild(formatNode);
formatNode = targets.shift();
}
}
} else {
var marginLeft = parseInt(indent(formatNode), 10) + 30;
indent(formatNode, marginLeft);
for (var targetIndex = 0; targetIndex < targets.length; targetIndex++) if ($.contains(formatNode, targets[targetIndex])) targets.splice(targetIndex, 1);
}
}
} else new BlockFormatter([{ tags: ["p"] }], { style: { marginLeft: 30 } }).apply(nodes);
},
getListTypeAttr: function(list) {
var type = list.getAttribute("type");
var styleType = list.style.listStyleType;
return type ? { type } : { style: { listStyleType: styleType } };
},
mapImmutables: function(nodes) {
if (!this.immutables) return nodes;
else {
var immutables = [];
return $.map(nodes, function(node) {
var immutable = Editor.Immutables.immutableParent(node);
if (immutable) if ($.inArray(immutable, immutables) === -1) immutables.push(immutable);
else return null;
return immutable || node;
});
}
},
remove: function(nodes) {
nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
var formatNodes = this.finder.findSuitable(nodes), targetNode, i, len, list, listParent, siblings, formatNode, marginLeft;
formatNodes = this.mapImmutables(formatNodes);
for (i = 0, len = formatNodes.length; i < len; i++) {
formatNode = $(formatNodes[i]);
if (formatNode.is("li")) {
list = formatNode.parent();
listParent = list.parent();
if (listParent.is("li,ul,ol") && !indent(list[0])) {
if (targetNode && $.contains(targetNode, listParent[0])) continue;
siblings = formatNode.nextAll("li");
if (siblings.length) $(list[0].cloneNode(false)).appendTo(formatNode).append(siblings);
if (listParent.is("li")) formatNode.insertAfter(listParent);
else formatNode.appendTo(listParent);
if (!list.children("li").length) list.remove();
continue;
} else {
if (targetNode == list[0]) continue;
targetNode = list[0];
}
} else targetNode = formatNodes[i];
marginLeft = parseInt(indent(targetNode), 10) - 30;
indent(targetNode, marginLeft);
}
}
});
var IndentCommand = Command.extend({ init: function(options) {
var that = this;
options.formatter = ( /** @ignore */ { toggle: (function(range) {
var indentFormatter = new IndentFormatter();
indentFormatter.immutables = this.editor && this.editor.options.immutables;
indentFormatter.apply(RangeUtils.nodes(range));
}).bind(that) });
Command.fn.init.call(this, options);
} });
var OutdentCommand = Command.extend({ init: function(options) {
var that = this;
options.formatter = { toggle: (function(range) {
var indentFormatter = new IndentFormatter();
indentFormatter.immutables = this.editor && this.editor.options.immutables;
indentFormatter.remove(RangeUtils.nodes(range));
}).bind(that) };
Command.fn.init.call(this, options);
} });
var OutdentTool = Tool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
this.finder = new BlockFormatFinder([{ tags: blockElements }]);
},
initialize: function(ui, editor) {
$.extend(this.options, { immutables: editor && editor.options.immutables });
},
update: function(ui, nodes) {
var suitableNodes = this.finder.findSuitable(nodes), toolbar = ui.closest(".k-toolbar").data("kendoToolBar"), isOutdentable, listParentsCount, i, len, suitable, immutableParent;
for (i = 0, len = suitableNodes.length; i < len; i++) {
suitable = suitableNodes[i];
if (this.options.immutables) {
immutableParent = Editor.Immutables.immutableParent(suitable);
if (immutableParent) suitable = immutableParent;
}
isOutdentable = indent(suitable);
if (!isOutdentable) {
listParentsCount = $(suitable).parents("ul,ol").length;
isOutdentable = dom.is(suitable, "li") && (listParentsCount > 1 || indent(suitable.parentNode)) || dom.ofType(suitable, ["ul", "ol"]) && listParentsCount > 0;
}
if (isOutdentable) {
toolbar.enable(ui, true);
return;
}
}
toolbar.enable(ui, false);
}
});
extend(Editor, {
IndentFormatter,
IndentCommand,
OutdentCommand,
OutdentTool
});
registerTool("indent", new Tool({ command: IndentCommand }));
registerTool("outdent", new OutdentTool({
command: OutdentCommand,
ui: { enable: false }
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/linebreak.js
(function($) {
var kendo = window.kendo, extend = $.extend, editorNS = kendo.ui.editor, dom = editorNS.Dom, Command = editorNS.Command, Tool = editorNS.Tool, BlockFormatter = editorNS.BlockFormatter, normalize = dom.normalize, RangeUtils = editorNS.RangeUtils, registerTool = editorNS.EditorUtils.registerTool;
var ParagraphCommand = Command.extend({
init: function(options) {
this.options = options;
Command.fn.init.call(this, options);
},
_insertMarker: function(doc, range) {
var marker = dom.create(doc, "a"), container;
marker.className = "k-marker";
range.insertNode(marker);
if (!marker.parentNode) {
container = range.commonAncestorContainer;
container.innerHTML = "";
container.appendChild(marker);
}
normalize(marker.parentNode);
return marker;
},
_moveFocus: function(range, candidate) {
if (dom.isEmpty(candidate)) range.setStartBefore(candidate);
else {
range.selectNodeContents(candidate);
var focusNode = RangeUtils.textNodes(range)[0];
if (!focusNode) {
while (candidate.childNodes.length && !dom.is(candidate.firstChild, "br")) candidate = candidate.firstChild;
focusNode = candidate;
}
if (dom.isEmpty(focusNode)) range.setStartBefore(focusNode);
else {
if (dom.emptyNode(focusNode)) focusNode.innerHTML = "";
var startNode = focusNode.firstChild || focusNode;
if (dom.isDataNode(startNode)) range.setStart(startNode, 0);
else range.setStartBefore(startNode);
}
}
},
shouldTrim: function(range) {
var blocks = "p,h1,h2,h3,h4,h5,h6".split(","), startInBlock = dom.parentOfType(range.startContainer, blocks), endInBlock = dom.parentOfType(range.endContainer, blocks);
return startInBlock && !endInBlock || !startInBlock && endInBlock;
},
_blankAfter: function(node) {
while (node && (dom.isMarker(node) || dom.stripBom(node.nodeValue) === "")) node = node.nextSibling;
return !node;
},
exec: function() {
const range = this.getRange();
const doc = RangeUtils.documentFromRange(range);
let parent, previous, next, paragraph, marker, li, heading, tableNode, rng, shouldTrim;
const emptyParagraphContent = editorNS.emptyElementContent;
this.expandImmutablesIn(range);
shouldTrim = this.shouldTrim(range);
range.deleteContents();
marker = this._insertMarker(doc, range);
dom.stripBomNode(marker.previousSibling);
dom.stripBomNode(marker.nextSibling);
li = dom.closestEditableOfType(marker, ["li"]);
heading = dom.closestEditableOfType(marker, "h1,h2,h3,h4,h5,h6".split(","));
tableNode = dom.is(marker.parentNode, "table") && marker.parentNode;
if (li) {
if (dom.emptyNode(li)) {
paragraph = dom.create(doc, "p");
if (dom.next(li)) {
rng = range.cloneRange();
rng.selectNode(li);
RangeUtils.split(rng, li.parentNode);
}
const br = $("br", li);
if (br.length == 1) br.remove();
const parentNode = li.parentNode;
const parentChildrenLength = li.parentNode.children.length;
const firstChild = parentChildrenLength >= 1 && li.childNodes.length == 1 && li.children[0];
dom.insertAfter(paragraph, parentNode);
dom.remove(parentChildrenLength == 1 ? li.parentNode : li);
if (firstChild && firstChild !== marker) {
paragraph.appendChild(firstChild);
paragraph.appendChild(marker);
} else paragraph.innerHTML = emptyParagraphContent;
next = paragraph;
}
} else if (heading && this._blankAfter(marker)) {
paragraph = this._insertParagraphAfter(heading);
dom.remove(marker);
next = paragraph;
} else if (tableNode) {
paragraph = this._insertParagraphAfter(tableNode);
dom.remove(marker);
next = paragraph;
}
if (!next) {
if (!(li || heading)) new BlockFormatter([{ tags: ["p"] }]).apply([marker]);
range.selectNode(marker);
const headingDomName = heading ? dom.name(heading) : "p";
parent = dom.parentOfType(marker, [li ? "li" : headingDomName]);
RangeUtils.split(range, parent, shouldTrim);
previous = parent.previousSibling;
if (dom.is(previous, "li") && previous.firstChild && !dom.is(previous.firstChild, "br")) previous = previous.firstChild;
next = parent.nextSibling;
this.clean(previous, { links: true });
this.clean(next, { links: true });
if (dom.is(next, "li") && next.firstChild && !dom.is(next.firstChild, "br")) next = next.firstChild;
dom.remove(parent);
normalize(previous);
}
normalize(next);
this._moveFocus(range, next);
range.collapse(true);
dom.scrollTo(next, true);
RangeUtils.selectRange(range);
},
_insertParagraphAfter: function(node) {
var range = this.getRange();
var doc = RangeUtils.documentFromRange(range);
var emptyElementContent = editorNS.emptyElementContent;
var paragraph = dom.create(doc, "p");
dom.insertAfter(paragraph, node);
paragraph.innerHTML = emptyElementContent;
return paragraph;
},
clean: function(node, options) {
var root = node;
if (node.firstChild && dom.is(node.firstChild, "br")) dom.remove(node.firstChild);
if (dom.isDataNode(node) && !node.nodeValue) node = node.parentNode;
if (node) {
var siblings = false;
while (node.firstChild && node.firstChild.nodeType == 1) {
siblings = siblings || dom.significantNodes(node.childNodes).length > 1;
node = node.firstChild;
}
if (!dom.isEmpty(node) && node.className != "k-br" && /^\s*$/.test(node.innerHTML) && !siblings) {
$(root).find(".k-br").remove();
node.innerHTML = editorNS.emptyElementContent;
}
if (options && options.links) while (node != root) {
if (dom.is(node, "a") && dom.emptyNode(node)) {
dom.unwrap(node);
break;
}
node = node.parentNode;
}
}
}
});
var NewLineCommand = Command.extend({
init: function(options) {
this.options = options;
Command.fn.init.call(this, options);
},
exec: function() {
var range = this.getRange();
this.expandImmutablesIn(range);
var br = dom.create(RangeUtils.documentFromRange(range), "br");
var node = range.startContainer;
var filler;
var browser = kendo.support.browser;
var oldIE = browser.msie && browser.version < 11;
var tableNode = dom.is(node, "table") && node;
var kbrParent;
range.deleteContents();
if (tableNode) dom.insertAfter(br, tableNode);
else {
kbrParent = $(node).closest(".k-br");
range.insertNode(br);
if (kbrParent.length) dom.unwrap(kbrParent[0]);
}
normalize(br.parentNode);
if (!oldIE && (!br.nextSibling || dom.isWhitespace(br.nextSibling))) {
if (!!br.nextSibling && dom.isWhitespace(br.nextSibling)) $(br.nextSibling).remove();
filler = br.cloneNode(true);
filler.className = "k-br";
dom.insertAfter(filler, br);
}
range.setStartAfter(br);
range.collapse(true);
dom.scrollTo(br.nextSibling || br, true);
RangeUtils.selectRange(range);
}
});
extend(editorNS, {
ParagraphCommand,
NewLineCommand
});
registerTool("insertLineBreak", new Tool({
key: 13,
shift: true,
command: NewLineCommand
}));
registerTool("insertParagraph", new Tool({
key: 13,
command: ParagraphCommand
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/file.js
(function($, undefined) {
var kendo = window.kendo, extend = $.extend, encode = kendo.htmlEncode, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, RangeUtils = Editor.RangeUtils, Command = Editor.Command, LinkFormatter = Editor.LinkFormatter, textNodes = RangeUtils.textNodes, keys = kendo.keys, KEDITORFILEURL = "#k-editor-file-url", KEDITORFILETEXT = "#k-editor-file-text", KEDITORFILETITLE = "#k-editor-file-title";
var FileCommand = Command.extend({
init: function(options) {
var that = this;
Command.fn.init.call(that, options);
that.formatter = new LinkFormatter();
that.async = true;
that.attributes = {};
},
insertFile: function(file, range) {
var attributes = this.attributes;
var doc = RangeUtils.documentFromRange(range);
if (attributes.href && attributes.href != "http://") if (!file) {
file = dom.create(doc, "a", { href: attributes.href });
file.innerHTML = attributes.innerHTML;
file.title = attributes.title;
range.deleteContents();
range.insertNode(file);
if (!file.nextSibling) dom.insertAfter(doc.createTextNode(""), file);
range.setStartAfter(file);
range.setEndAfter(file);
RangeUtils.selectRange(range);
return true;
} else dom.attr(file, attributes);
return false;
},
redo: function() {
var that = this, range = that.lockRange();
this.formatter.apply(range, this.attributes);
that.releaseRange(range);
},
exec: function() {
var that = this, range = that.lockRange(), nodes = textNodes(range), applied = false, file = nodes.length ? this.formatter.finder.findSuitable(nodes[0]) : null, dialog, form, isIE = kendo.support.browser.msie, options = that.editor.options, messages = options.messages, fileBrowser = options.fileBrowser, showBrowser = !!(kendo.ui.FileBrowser && fileBrowser && fileBrowser.transport && fileBrowser.transport.read !== undefined), dialogOptions = {
title: messages.insertFile,
visible: false,
resizable: showBrowser
};
this.expandImmutablesIn(range);
function apply(e) {
var element = dialog.element, href = element.find(KEDITORFILEURL).val().replace(/ /g, "%20"), innerHTML = element.find(KEDITORFILETEXT).val(), title = element.find(KEDITORFILETITLE).val();
that.attributes = {
href,
innerHTML: innerHTML !== "" ? innerHTML : href,
title
};
applied = that.insertFile(file, range);
close(e);
if (that.change) that.change();
}
function close(e) {
e.preventDefault();
form.destroy();
dialog.destroy();
dom.windowFromDocument(RangeUtils.documentFromRange(range)).focus();
if (!applied) that.releaseRange(range);
}
function keyDown(e) {
if (e.keyCode == keys.ENTER) apply(e);
else if (e.keyCode == keys.ESC) close(e);
}
dialogOptions.close = close;
if (showBrowser) dialogOptions.width = 750;
dialogOptions.minWidth = 350;
dialog = this.createDialog("<div/>", dialogOptions).data("kendoWindow");
form = that._createForm(dialog, showBrowser);
dialog.element.toggleClass("k-filebrowser-dialog", showBrowser);
dialog.wrapper.find(".k-dialog-insert").on("click", apply).end().find(".k-dialog-close").on("click", close).end().find(".k-form-field input").on("keydown", keyDown).end().find(KEDITORFILEURL).val(file ? file.getAttribute("href", 2) : "http://").end().find(KEDITORFILETEXT).val(file ? file.innerText : "").end().find(KEDITORFILETITLE).val(file ? file.title : "").end();
var element = dialog.element;
if (showBrowser) {
that._fileBrowser = new kendo.ui.FileBrowser(element.find(".k-filebrowser"), extend({}, fileBrowser));
that._fileBrowser.bind("change", function(ev) {
if (ev.selected.get("type") === "f") element.find(KEDITORFILEURL).val(this.value());
});
that._fileBrowser.bind("apply", apply);
}
if (isIE) {
var dialogHeight = element.closest(".k-window").height();
element.css("max-height", dialogHeight);
}
dialog.center().open();
element.find(KEDITORFILEURL).trigger("focus").select();
},
_createForm: function(dialog, showBrowser) {
var that = this;
var formElement = $("<div/>").appendTo(dialog.element);
var messages = that.editor.options.messages;
var form = formElement.kendoForm({
renderButtons: false,
items: [
{
field: "k-editor-file-url",
label: encode(messages.fileWebAddress),
editor: "TextBox"
},
{
field: "k-editor-file-text",
label: encode(messages.fileText),
editor: "TextBox"
},
{
field: "k-editor-file-title",
label: encode(messages.fileTitle),
editor: "TextBox"
}
]
}).data("kendoForm");
if (showBrowser) formElement.prepend($("<div class=\"k-filebrowser\"></div>"));
dialog.element.after($(that._actionButtonsTemplate({
messages,
insertButtonIcon: "file-add",
cancelButtonIcon: "cancel"
})));
return form;
}
});
kendo.ui.editor.FileCommand = FileCommand;
registerTool("insertFile", new Editor.Tool({ command: FileCommand }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/tables.js
(function($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, Command = Editor.Command, NS = "kendoEditor", ACTIVESTATE = "k-active", SELECTEDSTATE = "k-selected", SCOPE = "scope", ROW = "row", COL = "col", ROWGROUP = "rowgroup", COLGROUP = "colgroup", COLSPAN = "colspan", ROWSPAN = "rowspan", TABLE = "table", THEAD = "thead", TBODY = "tbody", TR = "tr", TD = "td", TH = "th", Tool = Editor.Tool, InsertHtmlCommand = Editor.InsertHtmlCommand, BlockFormatFinder = Editor.BlockFormatFinder, BlockFormatTool = Editor.BlockFormatTool, FormatCommand = Editor.FormatCommand, registerTool = Editor.EditorUtils.registerTool, registerFormat = Editor.EditorUtils.registerFormat, formats = kendo.ui.Editor.fn.options.formats, getTouches = kendo.getTouches;
var template = kendo.template;
var columnTemplate = ({ width, content }) => `<td style="width:${width}%;">${content}</td>`;
var tableFormatFinder = new BlockFormatFinder([{ tags: [TABLE] }]);
var TableCommand = InsertHtmlCommand.extend({
init: function(options) {
var o = $.extend({
postProcess: this.postProcess,
skipCleaners: true
}, options || {});
InsertHtmlCommand.fn.init.call(this, o);
},
_tableHtml: function(rows, columns) {
rows = rows || 1;
columns = columns || 1;
var columnHtml = template(columnTemplate)({
width: 100 / columns,
content: Editor.emptyTableCellContent
});
var rowHeight = 100 / rows;
return "<table class='k-table' data-last>" + new Array(rows + 1).join("<tr style='height:" + rowHeight + "%;'>" + new Array(columns + 1).join(columnHtml) + "</tr>") + "</table>";
},
postProcess: function(editor, range) {
var insertedTable = $("table[data-last]", editor.document).removeAttr("data-last");
range.setStart(insertedTable.find(TD)[0], 0);
range.collapse(true);
editor.selectRange(range);
},
exec: function() {
var options = this.options;
options.html = this._tableHtml(options.rows, options.columns);
InsertHtmlCommand.fn.exec.call(this);
}
});
var PopupTool = Tool.extend({
initialize: function(ui, editor) {
var that = this;
var btn = $("<button>" + editor.options.messages.tableWizard + "</button>");
var popup = $(this.options.popupTemplate).appendTo("body").kendoPopup({
anchor: ui,
copyAnchorStyles: false,
open: this._open.bind(this),
activate: this._activate.bind(this),
close: this._close.bind(this)
}).data("kendoPopup");
ui.on("click", this._toggle.bind(this)).on("keydown", this._keydown.bind(this));
this._editor = editor;
this._popup = popup;
editor.tablePopup = this._popup;
registerTool("tableWizardInsert", new Editor.TableWizardTool({
command: Editor.TableWizardCommand,
insertNewTable: true
}));
btn.appendTo(popup.element);
btn.kendoButton({ icon: "table-wizard" });
btn.on("click", () => {
that._editor.exec("tableWizardInsert");
});
},
popup: function() {
return this._popup;
},
_activate: $.noop,
_open: function() {
this._popup.options.anchor.addClass(ACTIVESTATE);
},
_close: function() {
this._popup.options.anchor.removeClass(ACTIVESTATE);
},
_keydown: function(e) {
var that = this, keys = kendo.keys, key = e.keyCode;
if (key == keys.ESC) that._popup.close();
else if (key == keys.DOWN && e.altKey) {
that._popup.open();
that._setTableSize({
row: 1,
col: 1
});
} else if (key === keys.ENTER) setTimeout(() => {
that._setTableSize({
row: 1,
col: 1
});
});
},
_toggle: function(e) {
if (!$(e.target).closest(".k-tool").hasClass("k-disabled")) this.popup().toggle();
},
update: function(ui) {
var popup = this.popup();
if (popup.wrapper && popup.wrapper.css("display") == "block") popup.close();
ui.removeClass("k-hover");
},
destroy: function() {
if (this._popup) this._popup.destroy();
}
});
var InsertTableTool = PopupTool.extend({
init: function(options) {
this.cols = 8;
this.rows = 6;
PopupTool.fn.init.call(this, $.extend(options, {
command: TableCommand,
popupTemplate: "<div class='k-ct-popup'><div>" + new Array(this.cols * this.rows + 1).join("<span class='k-ct-cell k-disabled'></span>") + "</div><div class='k-status'></div></div>"
}));
},
_activate: function() {
var that = this, element = that._popup.element, cells = element.find(".k-ct-cell"), firstCell = cells.eq(0), lastCell = cells.eq(cells.length - 1), start = kendo.getOffset(firstCell), end = kendo.getOffset(lastCell), cols = that.cols, rows = that.rows, cellWidth, cellHeight;
element.find("*").addBack().attr("unselectable", "on");
end.left += lastCell[0].offsetWidth;
end.top += lastCell[0].offsetHeight;
cellWidth = (end.left - start.left) / cols;
cellHeight = (end.top - start.top) / rows;
function tableFromLocation(e) {
var w = $(window);
return {
row: Math.floor((e.clientY + w.scrollTop() - start.top) / cellHeight) + 1,
col: Math.floor((e.clientX + w.scrollLeft() - start.left) / cellWidth) + 1
};
}
element.autoApplyNS(NS).on("mousemove", ".k-ct-cell", function(e) {
that._setTableSize(tableFromLocation(e));
}).on("mouseleave", ".k-ct-cell", function() {
that._setTableSize();
}).on("down", ".k-ct-cell", function(e) {
e.preventDefault();
var touch = getTouches(e)[0];
that._exec(tableFromLocation(touch.location));
});
},
_valid: function(size) {
return size && size.row > 0 && size.col > 0 && size.row <= this.rows && size.col <= this.cols;
},
_exec: function(size) {
if (this._valid(size)) {
this._editor.exec("createTable", {
rows: size.row,
columns: size.col
});
this._popup.close();
}
},
_setTableSize: function(size) {
var element = this._popup.element;
var status = element.find(".k-status");
var cells = element.find(".k-ct-cell");
var cols = this.cols;
var messages = this._editor.options.messages;
if (this._valid(size)) {
status.text(kendo.format(messages.createTableHint, size.row, size.col));
cells.each(function(i) {
$(this).toggleClass(SELECTEDSTATE, i % cols < size.col && i / cols < size.row);
});
} else {
status.text(messages.createTable);
cells.removeClass(SELECTEDSTATE);
}
},
_keydown: function(e) {
var initiallyVisible = this._popup.visible();
PopupTool.fn._keydown.call(this, e);
if (!this._popup.visible()) return;
var keys = kendo.keys;
var key = e.keyCode;
var cells = this._popup.element.find(".k-ct-cell");
var focus = Math.max(cells.filter(".k-selected").last().index(), 0);
var selectedRows = Math.floor(focus / this.cols);
var selectedColumns = focus % this.cols;
var changed = false, button;
if (key == keys.DOWN && !e.altKey) {
changed = true;
selectedRows++;
} else if (key == keys.UP) {
changed = true;
selectedRows--;
} else if (key == keys.RIGHT) {
changed = true;
selectedColumns++;
} else if (key == keys.LEFT) {
changed = true;
selectedColumns--;
} else if (key == keys.TAB) {
button = this._popup.element.find(".k-button");
if (button.length > 0) {
changed = true;
button.trigger("focus");
}
}
var tableSize = {
row: Math.max(1, Math.min(this.rows, selectedRows + 1)),
col: Math.max(1, Math.min(this.cols, selectedColumns + 1))
};
if (key == keys.ENTER && initiallyVisible) this._exec(tableSize);
else this._setTableSize(tableSize);
if (changed) {
e.preventDefault();
e.stopImmediatePropagation();
}
},
_open: function() {
var messages = this._editor.options.messages;
PopupTool.fn._open.call(this);
this.popup().element.find(".k-status").text(messages.createTable).end().find(".k-ct-cell").removeClass(SELECTEDSTATE);
},
_close: function() {
PopupTool.fn._close.call(this);
this.popup().element.off("." + NS);
}
});
var TableModificationCommand = Command.extend({
undo: function() {
var point = this.restorePoint;
point.restoreHtml();
$(this.editor.body).find(".k-element-resize-handle-wrapper").each(function(index, el) {
el.remove();
});
this.editor.selectRange(point.toRange());
},
_clearColIndexAttr: function(table) {
dom.clearTableMappings(table, "col-index");
},
_mapColIndices: function(table) {
dom.reMapTableColumns(table, "col-index");
},
_findRowSpanCell: function(parent, rowIndex, colIndex) {
var row, cell;
for (var i = rowIndex; i >= 0; i--) {
row = parent.rows[i];
cell = $(row).find("[col-index=" + colIndex + "]");
if (cell.length) return cell;
}
},
_resetElementResizing: function(editor) {
editor._destroyResizings();
editor._initializeColumnResizing();
editor._initializeRowResizing();
editor._initializeElementResizing();
},
_findNextTdInRow: function(row, colIndex) {
var lastTd = row.find("td:last-child"), lastIndex = parseInt(lastTd.attr("col-index"), 10) + lastTd.prop("colSpan") - 1, td;
for (var i = colIndex; i <= lastIndex; i++) {
td = row.find("[col-index=" + i + "]");
if (td.length) return td;
}
},
_adjustColgroups: function(row, table) {
var colElements = table.getElementsByTagName(COL), colgroupElements = table.getElementsByTagName(COLGROUP), cells = row.cells, numberOfCells = cells.length, i, colgroup, cell;
while (colElements.length > 0) colElements[0].remove();
while (colgroupElements.length > 0) colgroupElements[0].remove();
for (i = numberOfCells - 1; i >= 0; i--) {
cell = cells[i];
if (cell.getAttribute(SCOPE) === COLGROUP) {
colgroup = dom.createEmptyNode(this.editor.document, COLGROUP);
colgroup.setAttribute("span", cell.getAttribute(COLSPAN));
table.prepend(colgroup);
} else table.prepend(dom.createEmptyNode(this.editor.document, COL));
}
},
_associateHeaderIds: function(table) {
dom.clearTableMappings(table, "col-index");
dom.reMapTableColumns(table, "col-index");
$(table).find("th, td").removeAttr("id headers");
dom.associateWithIds(table);
},
_getNumberOfColumns: function(table) {
return dom._getNumberOfColumns(table, "td, th");
}
});
var InsertRowCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange(true), td = dom.closest(range.endContainer, [TD, TH]), table = dom.closest(td, TABLE), position = this.options.position || "after", cellCount, row, cell, newRow, rowIndex, rowSpanIndex, createdCell;
if (!table || this.immutables() && Editor.Immutables.immutableParent(td)) {
this.releaseRange(range);
return;
}
this._mapColIndices(table);
row = td.parentNode;
rowIndex = dom.findNodeIndex(row, true);
if (td.rowSpan > 1 && position === "after") row = table.rows[rowIndex + td.rowSpan - 1];
cellCount = this._getNumberOfColumns(table);
newRow = row.cloneNode(true);
$(newRow).empty();
for (var i = 0; i < cellCount; i = i + cell.prop("colSpan")) {
cell = $(row).find("[col-index=" + i + "]");
if (cell.length) if (cell.prop("rowSpan") > 1 && position === "after" && cell) cell.attr(ROWSPAN, cell.prop("rowSpan") + 1);
else this._appendCell(newRow, cell);
else {
rowIndex = dom.findNodeIndex(row, true);
cell = this._findRowSpanCell(row.parentElement, rowIndex, i);
rowSpanIndex = cell.closest(TR).index();
if (rowSpanIndex + cell.prop("rowSpan") - 1 === rowIndex && position === "after") this._appendCell(newRow, cell);
else cell.attr(ROWSPAN, cell.prop("rowSpan") + 1);
}
createdCell = $(newRow).find("[col-index=" + i + "]");
if (createdCell.attr(SCOPE) === ROWGROUP && !createdCell.attr(ROWSPAN)) createdCell.attr(SCOPE, ROW);
}
if (position == "before") dom.insertBefore(newRow, row);
else dom.insertAfter(newRow, row);
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
this._clearColIndexAttr(table);
this.releaseRange(range);
this._resetElementResizing(this.editor);
},
_appendCell: function(row, cell) {
var newCell = cell.clone();
newCell.html(Editor.emptyTableCellContent);
newCell.removeAttr(ROWSPAN);
newCell.appendTo(row);
}
});
var InsertColumnCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange(true), td = dom.closest(range.endContainer, [TD, TH]), table = dom.closest(td, TABLE), colElements = table.getElementsByTagName(COL), colgroupElements = table.getElementsByTagName(COLGROUP), columnIndex, i, rows = table && table.rows, cell, newCell, position = this.options.position || "after";
if (!td || this.immutables() && Editor.Immutables.immutableParent(td)) {
this.releaseRange(range);
return;
}
this._mapColIndices(table);
columnIndex = parseInt(td.getAttribute("col-index"), 10);
if (td.colSpan > 1 && position === "after") {
td.setAttribute("col-index", columnIndex + td.colSpan - 1);
columnIndex = columnIndex + td.colSpan - 1;
}
for (i = 0; i < rows.length; i++) {
cell = this._processForColSpan(rows[i], columnIndex, position, td);
if (!cell) continue;
newCell = cell.cloneNode();
newCell.innerHTML = Editor.emptyTableCellContent;
newCell.removeAttribute(COLSPAN);
if (newCell.getAttribute(SCOPE) && newCell.getAttribute(SCOPE) === COLGROUP) newCell.setAttribute(SCOPE, COL);
if (position == "before") dom.insertBefore(newCell, cell);
else dom.insertAfter(newCell, cell);
this._resizeCells(newCell, cell);
}
if (colElements.length > 0 || colgroupElements.length > 0) this._adjustColgroups(rows[0], table);
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
this._clearColIndexAttr(table);
this.releaseRange(range);
this._resetElementResizing(this.editor);
},
_processForColSpan: function(row, columnIndex, position, selectedCell) {
var cell, colSpanEffect, index = columnIndex - 1;
cell = $(row).find("[col-index=" + columnIndex + "]")[0];
if (cell && cell.colSpan > 1 && position === "after" && cell !== selectedCell) {
cell.colSpan += 1;
return;
}
if (cell) return cell;
for (; index >= 0; index--) {
cell = $(row).find("[col-index=" + index + "]")[0];
if (cell && cell.colSpan > 1) break;
}
if (!cell) return;
colSpanEffect = parseInt(cell.getAttribute("col-index"), 10) + cell.colSpan - 1;
if (colSpanEffect === columnIndex && position === "after") return cell;
else if (columnIndex <= colSpanEffect) cell.setAttribute(COLSPAN, cell.colSpan + 1);
},
_resizeCells: function(newCell, cell) {
var width = newCell.style.width, parsedWidth, unit, calculatedWidth;
if (!width) return;
parsedWidth = parseFloat(width);
unit = width.slice(parsedWidth.toString().length);
calculatedWidth = parsedWidth / 2 + unit;
newCell.style.width = calculatedWidth;
cell.style.width = calculatedWidth;
}
});
var DeleteRowCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange();
var rows = RangeUtils.mapAll(range, function(node) {
return $(node).closest(TR)[0];
});
var td = dom.closest(range.endContainer, [TD, TH]);
var row = rows[0];
var rowSpan = td ? td.rowSpan : 1;
var rowIndex = $(rows[0]).index();
var table = dom.closest(row, TABLE);
var rowParent = row.parentElement;
var focusElement;
if (!table || this.immutables() && Editor.Immutables.immutableParent(row)) {
this.releaseRange(range);
return;
}
for (var x = 0; x < rowSpan; x++) if (rows.indexOf(rowParent.rows[rowIndex + x]) < 0) rows.push(rowParent.rows[rowIndex + x]);
if (table.rows.length <= rows.length) {
focusElement = dom.next(table);
if (!focusElement || dom.insignificant(focusElement)) focusElement = dom.prev(table);
if (focusElement && focusElement.rows) focusElement = focusElement.rows[0].cells[0];
dom.remove(table);
this._resetElementResizing(this.editor);
} else if (rowParent.rows.length <= rows.length) {
focusElement = rowParent.nextSibling;
if (!focusElement) focusElement = rowParent.previousSibling;
dom.remove(rowParent);
} else {
this._mapColIndices(table);
for (var i = 0; i < rows.length; i++) {
row = rows[i];
dom.removeTextSiblings(row);
focusElement = dom.next(row) || dom.prev(row);
focusElement = focusElement.cells[0];
this._focusElement(range, focusElement);
focusElement = null;
this._handleRowSpanCells(table, row);
dom.remove(row);
}
this._clearColIndexAttr(table);
}
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
else if (dom.is(rowParent, THEAD) && $(table).find("[scope]").length > 0) this._adjustColgroups(rowParent.rows[0], table);
if (focusElement) this._focusElement(range, focusElement);
this._resetElementResizing(this.editor);
},
_focusElement: function(range, node) {
range.setStart(node, 0);
range.collapse(true);
this.editor.selectRange(range);
},
_handleRowSpanCells: function(table, row) {
var index, cell, adjacentCell, nextRow, rowIndex = dom.findNodeIndex(row, true), firstRow = table.rows[0], lastCell = firstRow.cells[firstRow.cells.length - 1], lastIndex = parseInt(lastCell.getAttribute("col-index"), 10) + lastCell.colSpan - 1;
for (index = 0; index <= lastIndex; index = index + cell.prop("colSpan")) {
cell = $(row).find("[col-index=" + index + "]");
if (cell.length && cell.prop("rowSpan") > 1) {
nextRow = table.rows[rowIndex + 1];
adjacentCell = $(nextRow).find("[col-index=" + (index + 1) + "]");
if (adjacentCell.length) adjacentCell.before(cell);
else $(nextRow).append(cell);
this._reduceRowSpan(cell);
}
if (!cell.length) {
cell = this._findRowSpanCell(row.parentElement, rowIndex, index);
this._reduceRowSpan(cell);
}
}
},
_reduceRowSpan: function(td) {
var rowSpanValue = td.prop("rowSpan") - 1;
if (rowSpanValue <= 1) {
td.removeAttr(ROWSPAN);
if (td.attr(SCOPE) === ROWGROUP) td.attr(SCOPE, ROW);
} else td.attr(ROWSPAN, rowSpanValue);
}
});
var DeleteColumnCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange(), td = dom.closest(range.endContainer, [TD, TH]), table = dom.closest(td, TABLE), rows = table && table.rows, columnCount = rows && rows[0].cells.length, colElements = table.getElementsByTagName(COL), colgroupElements = table.getElementsByTagName(COLGROUP), focusElement, columnIndex, i, cell, x;
if (!td || this.immutables() && Editor.Immutables.immutableParent(td)) {
this.releaseRange(range);
return;
}
if (columnCount == 1 || td.colSpan == columnCount) {
focusElement = dom.next(table);
if (!focusElement || dom.insignificant(focusElement)) focusElement = dom.prev(table);
if (focusElement && focusElement.rows) focusElement = focusElement.rows[0].cells[0];
dom.remove(table);
this._resetElementResizing(this.editor);
} else {
dom.removeTextSiblings(td);
focusElement = dom.next(td) || dom.prev(td);
this._mapColIndices(table);
columnIndex = parseInt(td.getAttribute("col-index"), 10);
for (x = 0; x < td.colSpan; x++) for (i = 0; i < rows.length; i = i + (cell.prop("rowSpan") || 1)) {
cell = $(rows[i]).find("[col-index=" + (columnIndex + x) + "]");
if (cell.length && cell.prop("colSpan") <= 1) cell.remove();
else this._handleColSpanCells(rows[i], columnIndex + x);
}
this._clearColIndexAttr(table);
}
if (colElements.length > 0 || colgroupElements.length > 0) this._adjustColgroups(rows[0], table);
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
if (focusElement) {
range.setStart(focusElement, 0);
range.collapse(true);
this.editor.selectRange(range);
}
this._resetElementResizing(this.editor);
},
_handleColSpanCells: function(row, colIndex) {
var cell = $(row).find("[col-index=" + colIndex + "]");
if (cell.length && cell.prop("colSpan") > 1) {
var clone = cell.clone(true);
cell.after(clone);
this._reduceColSpan(clone);
clone.attr("col-index", parseInt(cell.attr("col-index"), 10) + 1);
cell.remove();
return;
}
for (var i = colIndex; i >= 0; i--) {
cell = $(row).find("[col-index=" + i + "]");
if (cell.length) {
this._reduceColSpan(cell);
cell.attr("col-index", parseInt(cell.attr("col-index"), 10) + 1);
return;
}
}
},
_reduceColSpan: function(td) {
var colSpanValue = td.prop("colSpan") - 1;
if (colSpanValue <= 1) {
td.removeAttr(COLSPAN);
if (td.attr(SCOPE) === COLGROUP) td.attr(SCOPE, COL);
} else td.attr(COLSPAN, colSpanValue);
}
});
var MergeCellsHorizontallyCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange(), td = dom.closest(range.endContainer, [TD, TH]), table, row, columnIndex, nextTd, colspan;
if (!td) {
this.releaseRange(range);
return;
}
table = dom.closest(td, TABLE);
row = td.parentNode;
columnIndex = dom.findNodeIndex(td, true);
nextTd = row.children[columnIndex + 1];
if (this.immutables() && Editor.Immutables.immutableParent(td)) {
this.releaseRange(range);
return;
}
this._mapColIndices(table);
columnIndex = parseInt($(td).attr("col-index"), 10);
nextTd = $(row).find("[col-index=" + (columnIndex + 1 + this._getColspan(td) - 1) + "]").get(0);
if (!nextTd || nextTd.rowSpan !== td.rowSpan || td.tagName !== nextTd.tagName) {
this._clearColIndexAttr(table);
this.releaseRange(range);
return;
}
colspan = this._getColspan(td) + this._getColspan(nextTd);
$(td).prop(COLSPAN, colspan).append(dom.emptyNode(nextTd) ? "" : "<br/>" + nextTd.innerHTML);
$(td).width(td.offsetWidth);
$(nextTd).remove();
if (td.getAttribute(SCOPE) === COL) td.setAttribute(SCOPE, COLGROUP);
if (td.getAttribute(SCOPE) === COLGROUP) this._adjustColgroups(row, table);
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
this._clearColIndexAttr(table);
this.releaseRange(range);
this._resetElementResizing(this.editor);
},
_getColspan: function(td) {
return parseInt(td.getAttribute(COLSPAN), 10) || 1;
}
});
var MergeCellsVerticallyCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange(), td = dom.closest(range.endContainer, [TD, TH]), tr, parent, table, columnIndex, rowIndex, targetRow, bottomTd;
if (!td) {
this.releaseRange(range);
return;
}
tr = dom.closest(td, TR);
parent = dom.closest(td, [THEAD, TBODY]);
table = dom.closest(td, TABLE);
columnIndex = dom.findNodeIndex(td, true);
rowIndex = dom.findNodeIndex(tr, true);
if (rowIndex + 1 === parent.rows.length) {
this.releaseRange(range);
return;
}
targetRow = parent.rows[rowIndex + this._getRowspan(td)];
bottomTd = targetRow && targetRow.children[columnIndex];
if (this.immutables() && Editor.Immutables.immutableParent(td)) {
this.releaseRange(range);
return;
}
this._mapColIndices(table);
columnIndex = $(td).attr("col-index");
bottomTd = $(targetRow).find("[col-index=" + columnIndex + "]").get(0);
if (!bottomTd || bottomTd.colSpan !== td.colSpan || td.tagName !== bottomTd.tagName) {
this._clearColIndexAttr(table);
this.releaseRange(range);
return;
}
$(td).prop(ROWSPAN, this._getRowspan(td) + this._getRowspan(bottomTd)).append(dom.emptyNode(bottomTd) ? "" : "<br/>" + bottomTd.innerHTML);
if (td.getAttribute(SCOPE) === ROW) td.setAttribute(SCOPE, ROWGROUP);
$(bottomTd).remove();
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
this._clearColIndexAttr(table);
this.releaseRange(range);
},
_getRowspan: function(td) {
return parseInt(td.getAttribute(ROWSPAN), 10) || 1;
}
});
var SplitCellCommand = TableModificationCommand.extend({
exec: function() {
var range = this.lockRange(), type = this.options.type, attr = type === "row" ? COLSPAN : ROWSPAN, td = dom.closest(range.endContainer, [TD, TH]), parent = dom.closest(td, [THEAD, TBODY]), table = dom.closest(td, TABLE), emptyTd = dom.createEmptyNode(this.editor.document, td.nodeName.toLowerCase());
if (!td || this.immutables() && Editor.Immutables.immutableParent(td)) {
this.releaseRange(range);
return;
}
this._mapColIndices(table);
if (type === "row" && $(td).is("[" + attr + "]")) this._splitCellHorizontally(td, parent, attr, emptyTd);
else if (type === "column" && $(td).is("[" + attr + "]")) this._splitCellVertically(td, parent, attr, emptyTd);
if ($(td).prop(attr.toLowerCase()) <= 1) $(td).removeAttr(attr);
if ($(table).find("[headers]").length > 0) this._associateHeaderIds(table);
this._clearColIndexAttr(table);
this.releaseRange(range);
},
_getRowspanValue: function(td) {
return parseInt(td.getAttribute(ROWSPAN), 10);
},
_getColspanValue: function(td) {
return parseInt(td.getAttribute(COLSPAN), 10);
},
_splitCellHorizontally: function(td, parent, attr, emptyTd) {
var rowSpan = td.rowSpan, colSpan = td.colSpan, tdToAdd = $(emptyTd), colSpanResult = Math.floor(colSpan / 2);
if (colSpanResult > 1) tdToAdd.attr(COLSPAN, colSpanResult);
if (rowSpan > 1) tdToAdd.attr(ROWSPAN, rowSpan);
$(td).prop(attr, colSpan - colSpanResult).after(tdToAdd);
$(td).width(td.offsetWidth);
tdToAdd.width(tdToAdd[0].offsetWidth);
if (td.hasAttribute(SCOPE)) if (td.getAttribute(SCOPE) === COLGROUP) {
tdToAdd.attr(SCOPE, COL);
if (!td.getAttribute(COLSPAN) || td.getAttribute(COLSPAN) === "1") td.setAttribute(SCOPE, COL);
this._adjustColgroups(td.parentNode, parent.parentNode);
} else tdToAdd.attr(SCOPE, td.getAttribute(SCOPE));
},
_splitCellVertically: function(td, parent, attr, emptyTd) {
var tr = dom.closest(td, TR), columnIndex = parseInt($(td).attr("col-index"), 10), rowIndex = dom.findNodeIndex(tr, true), rowSpan = td.rowSpan, colSpan = td.colSpan, rowSpanResult = Math.floor(rowSpan / 2), targetRow = $(parent).find(TR).eq(rowIndex + rowSpan - rowSpanResult), nextTd = this._findNextTdInRow(targetRow, columnIndex + colSpan), tdToAdd = $(emptyTd);
if (rowSpanResult > 1) tdToAdd.attr(ROWSPAN, rowSpanResult);
if (colSpan > 1) tdToAdd.attr(COLSPAN, colSpan);
if (nextTd && nextTd.length) nextTd.before(tdToAdd);
else targetRow.append(tdToAdd);
$(td).prop(attr, rowSpan - rowSpanResult);
if (td.hasAttribute(SCOPE)) if (td.getAttribute(SCOPE) === ROWGROUP) {
tdToAdd.attr(SCOPE, ROW);
if (!td.getAttribute(ROWSPAN) || td.getAttribute(ROWSPAN) === "1") td.setAttribute(SCOPE, ROW);
} else tdToAdd.attr(SCOPE, td.getAttribute(SCOPE));
}
});
var TableModificationTool = Tool.extend({
command: function(options) {
var commandsMap = {
row: {
insert: InsertRowCommand,
"delete": DeleteRowCommand,
merge: MergeCellsHorizontallyCommand,
split: SplitCellCommand
},
column: {
insert: InsertColumnCommand,
"delete": DeleteColumnCommand,
merge: MergeCellsVerticallyCommand,
split: SplitCellCommand
}
};
options = extend(options, this.options);
options.action = options.action || "insert";
return new commandsMap[options.type][options.action](options);
},
update: function(ui, nodes, undoRedoStack, immutablesContext) {
var isFormatted = !tableFormatFinder.isFormatted(nodes), toolbar = ui.closest(".k-toolbar").getKendoToolBar();
if (isFormatted === true || immutablesContext) toolbar.hide(ui);
else toolbar.show(ui);
}
});
var TableFormatCommand = FormatCommand.extend({ exec: function() {
var editor = this.editor;
FormatCommand.fn.exec.call(this);
if (editor.elementResizing) editor.elementResizing._showResizeHandles();
} });
var TableFormatTool = BlockFormatTool.extend({
update: function(ui, nodes) {
var isTable = !tableFormatFinder.isFormatted(nodes), isFormatted = this.options.finder.isFormatted(nodes, this.isTable), toolbar = ui.closest(".k-toolbar").getKendoToolBar();
if (toolbar) toolbar.toggle(ui, isFormatted);
if (isTable === true) toolbar.hide(ui);
else toolbar.show(ui);
},
command: function(commandArguments) {
return new TableFormatCommand(extend(commandArguments, { formatter: this.options.formatter }));
},
isTable: function(node) {
return dom.is(node, "table");
}
});
extend(kendo.ui.editor, {
PopupTool,
TableCommand,
InsertTableTool,
TableFormatTool,
TableFormatCommand,
TableModificationTool,
InsertRowCommand,
InsertColumnCommand,
DeleteRowCommand,
DeleteColumnCommand,
MergeCellsHorizontallyCommand,
MergeCellsVerticallyCommand,
SplitCellCommand
});
registerTool("createTable", new InsertTableTool({ ui: {
popup: true,
overflow: "never"
} }));
registerTool("addColumnLeft", new TableModificationTool({
type: "column",
position: "before"
}));
registerTool("addColumnRight", new TableModificationTool({ type: "column" }));
registerTool("addRowAbove", new TableModificationTool({
type: "row",
position: "before"
}));
registerTool("addRowBelow", new TableModificationTool({ type: "row" }));
registerTool("deleteRow", new TableModificationTool({
type: "row",
action: "delete"
}));
registerTool("deleteColumn", new TableModificationTool({
type: "column",
action: "delete"
}));
registerTool("mergeCellsHorizontally", new TableModificationTool({
type: "row",
action: "merge"
}));
registerTool("mergeCellsVertically", new TableModificationTool({
type: "column",
action: "merge"
}));
registerTool("splitCellHorizontally", new TableModificationTool({
type: "row",
action: "split"
}));
registerTool("splitCellVertically", new TableModificationTool({
type: "column",
action: "split"
}));
registerFormat("tableAlignLeft", [{
tags: ["table"],
attr: { style: {
marginLeft: "",
marginRight: "auto"
} }
}, {
tags: ["table"],
attr: { align: "left" }
}]);
registerTool("tableAlignLeft", new TableFormatTool({
format: formats.tableAlignLeft,
ui: {
togglable: true,
group: "tableAlign"
}
}));
registerFormat("tableAlignCenter", [{
tags: ["table"],
attr: { style: {
marginLeft: "auto",
marginRight: "auto"
} }
}, {
tags: ["table"],
attr: { align: "center" }
}]);
registerTool("tableAlignCenter", new TableFormatTool({
format: formats.tableAlignCenter,
ui: {
togglable: true,
group: "tableAlign"
}
}));
registerFormat("tableAlignRight", [{
tags: ["table"],
attr: { style: {
marginLeft: "auto",
marginRight: ""
} }
}, {
tags: ["table"],
attr: { align: "right" }
}]);
registerTool("tableAlignRight", new TableFormatTool({
format: formats.tableAlignRight,
ui: {
togglable: true,
group: "tableAlign"
}
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/clipboard.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, RangeUtils = editorNS.RangeUtils, dom = editorNS.Dom, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, browser = kendo.support.browser, extend = $.extend;
var Clipboard = Class.extend({
init: function(editor) {
this.editor = editor;
var pasteCleanup = editor.options.pasteCleanup;
this.nonSplittableTagsOnPaste = editor.options.nonSplittableTagsOnPaste || [];
this.cleaners = [
new ScriptCleaner(pasteCleanup),
new TabCleaner(pasteCleanup),
new MSWordFormatCleaner(pasteCleanup),
new WebkitFormatCleaner(pasteCleanup),
new HtmlTagsCleaner(pasteCleanup),
new HtmlAttrCleaner(pasteCleanup),
new HtmlContentCleaner(pasteCleanup),
new CustomCleaner(pasteCleanup)
];
},
htmlToFragment: function(html) {
var doc = this.editor.document, container = dom.create(doc, "div"), fragment = doc.createDocumentFragment();
container.innerHTML = html;
while (container.firstChild) fragment.appendChild(container.firstChild);
return fragment;
},
isBlock: function(html) {
return /<(div|p|ul|ol|table|h[1-6])/i.test(html);
},
_startModification: function() {
var range;
var restorePoint;
var editor = this.editor;
if (this._inProgress) return;
this._inProgress = true;
range = editor.getRange();
restorePoint = new RestorePoint(range, editor.body);
dom.persistScrollTop(editor.document);
return {
range,
restorePoint
};
},
_endModification: function(modificationInfo) {
editorNS._finishUpdate(this.editor, modificationInfo.restorePoint);
this.editor._selectionChange();
this._inProgress = false;
},
_contentModification: function(before, after) {
var that = this;
var editor = that.editor;
var modificationInfo = that._startModification();
if (!modificationInfo) return;
before.call(that, editor, modificationInfo.range);
setTimeout(function() {
after.call(that, editor, modificationInfo.range);
that._endModification(modificationInfo);
});
},
_removeBomNodes: function(range) {
var nodes = RangeUtils.textNodes(range);
for (var i = 0; i < nodes.length; i++) nodes[i].nodeValue = dom.stripBom(nodes[i].nodeValue) || nodes[i].nodeValue;
},
_onBeforeCopy: function(range) {
var marker = new Marker();
marker.add(range);
this._removeBomNodes(range);
marker.remove(range);
this.editor.selectRange(range);
},
oncopy: function() {
this._onBeforeCopy(this.editor.getRange());
},
oncut: function() {
this._onBeforeCopy(this.editor.getRange());
this._contentModification($.noop, $.noop);
},
_fileToDataURL: function(blob) {
var deferred = $.Deferred();
var reader = new FileReader();
if (!(blob instanceof window.File) && blob.getAsFile) {
blob = blob.getAsFile();
if (!blob) return;
}
reader.onload = deferred.resolve.bind(deferred);
reader.readAsDataURL(blob);
return deferred.promise();
},
_triggerPaste: function(html, options) {
var args = { html: html || "" };
args.html = args.html.replace(/\ufeff/g, "");
this.editor.trigger("paste", args);
this.paste(args.html, options || {});
},
_handleImagePaste: function(e) {
if (!("FileReader" in window) || browser.msie && browser.version > 10) return;
var clipboardData = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData || {};
var items = clipboardData.items || clipboardData.files;
return this._insertImages(items);
},
_insertImages: function(items) {
if (!items) return;
var images = $.grep(items, function(item) {
return /^image\//i.test(item.type);
});
if ($.grep(items, function(item) {
return /^text\/html/i.test(item.type);
}).length || !images.length) return;
var modificationInfo = this._startModification();
if (!modificationInfo) return;
$.when.apply($, $.map(images, this._fileToDataURL)).done((function() {
var results = Array.prototype.slice.call(arguments);
var html = $.map(results, function(e) {
return "<img src=\"" + e.target.result + "\" />";
}).join("");
this._triggerPaste(html);
this._endModification(modificationInfo);
}).bind(this));
return true;
},
onpaste: function(e) {
if (this.editor.body.contentEditable === "false" || this.editor.body.contentEditable === "inherit") return;
if (this._handleImagePaste(e)) {
e.preventDefault();
return;
}
this.expandImmutablesIn();
this._contentModification(function beforePaste(editor, range) {
var clipboardNode = dom.create(editor.document, "div", {
className: "k-paste-container",
innerHTML: ""
});
var browser = kendo.support.browser;
var body = editor.body;
this._decoreateClipboardNode(clipboardNode, body);
body.appendChild(clipboardNode);
if (browser.webkit) this._moveToCaretPosition(clipboardNode, range);
if (browser.msie && browser.version < 11) {
e.preventDefault();
var r = editor.createRange();
r.selectNodeContents(clipboardNode);
editor.selectRange(r);
var textRange = editor.document.body.createTextRange();
textRange.moveToElementText(clipboardNode);
$(body).off("paste");
textRange.execCommand("Paste");
$(body).on("paste", this.onpaste.bind(this));
} else {
var clipboardRange = editor.createRange();
clipboardRange.selectNodeContents(clipboardNode);
editor.selectRange(clipboardRange);
}
range.deleteContents();
}, function afterPaste(editor, range) {
var html = "", containers;
editor.selectRange(range);
containers = $(editor.body).children(".k-paste-container");
containers.each(function() {
var lastChild = this.lastChild;
if (lastChild && dom.is(lastChild, "br")) dom.remove(lastChild);
html += this.innerHTML;
});
containers.remove();
this._triggerPaste(html, { clean: true });
});
},
ondragover: function(e) {
if (browser.msie || browser.edge) {
e.stopPropagation();
e.preventDefault();
}
},
ondrop: function(e) {
if (!("FileReader" in window)) return;
var dataTransfer = (e.originalEvent || e).dataTransfer || {};
var items = dataTransfer.items || dataTransfer.files;
if (this._insertImages(items)) e.preventDefault();
},
_decoreateClipboardNode: function(node, body) {
if (!browser.msie && !browser.webkit) return;
node = $(node);
node.css({
borderWidth: "0px",
width: "0px",
height: "0px",
overflow: "hidden",
margin: "0",
padding: "0"
});
if (browser.msie) {
var documentElement = $(body.ownerDocument.documentElement);
node.css({
fontVariant: "normal",
fontWeight: "normal",
lineSpacing: "normal",
lineHeight: "normal",
textDecoration: "none"
});
var color = documentElement.css("color");
if (color) node.css("color", color);
var fontFamily = documentElement.css("fontFamily");
if (fontFamily) node.css("fontFamily", fontFamily);
var fontSize = documentElement.css("fontSize");
if (fontSize) node.css("fontSize", fontSize);
}
},
_moveToCaretPosition: function(node, range) {
var that = this;
var body = that.editor.body;
var nodeOffset = dom.offset(node, body);
var caretOffset = that._caretOffset(range, body);
var translateX = caretOffset.left - nodeOffset.left;
var translateY = caretOffset.top - nodeOffset.top;
var translate = "translate(" + translateX + "px," + translateY + "px)";
$(node).css({
"-webkit-transform": translate,
"transform": translate
});
},
_caretOffset: function(range, body) {
var editor = this.editor;
var caret = dom.create(editor.document, "span", { innerHTML: "" });
var startContainer = range.startContainer;
var rangeChanged;
if (range.collapsed) {
var isStartTextNode = dom.isDataNode(startContainer);
if (isStartTextNode && (dom.isBom(startContainer) || range.startOffset === 0)) dom.insertBefore(caret, startContainer);
else if (isStartTextNode && range.startOffset === startContainer.length) dom.insertAfter(caret, startContainer);
else {
range.insertNode(caret);
rangeChanged = true;
}
} else {
startContainer = startContainer === body ? startContainer.childNodes[range.startOffset] : startContainer;
dom.insertBefore(caret, startContainer);
}
var offset = dom.offset(caret, body);
var prev = caret.previousSibling;
var next = caret.nextSibling;
dom.remove(caret);
if (rangeChanged && dom.isDataNode(prev) && dom.isDataNode(next) && !dom.isBom(prev) && !dom.isBom(next)) {
var prevLength = prev.length;
next.data = prev.data + next.data;
range.setStart(next, prevLength);
dom.remove(prev);
range.collapse(true);
editor.selectRange(range);
}
return offset;
},
expandImmutablesIn: function(range) {
var editor = this.editor;
if (editor && editor.options.immutables) {
var body = editor.body;
range = range || editor.getRange();
kendo.ui.editor.Immutables.expandImmutablesIn(range);
if (range.startContainer === body && range.startOffset === 0) {
var bomNode = body.ownerDocument.createTextNode("");
body.insertBefore(bomNode, body.childNodes[0]);
range.setStartBefore(bomNode);
}
editor.selectRange(range);
}
},
splittableParent: function(block, node) {
var parentNode, body;
if (block) return dom.closestEditableOfType(node, [
"p",
"ul",
"ol"
]) || node.parentNode;
parentNode = node.parentNode;
body = node.ownerDocument.body;
if (dom.isInline(parentNode)) while (parentNode.parentNode != body && !dom.isBlock(parentNode.parentNode)) parentNode = parentNode.parentNode;
return parentNode;
},
paste: function(html, options) {
var editor = this.editor, nonSplittableTagsOnPaste = this.nonSplittableTagsOnPaste, preventSplit = false, unwrapPasted = false, i, l, childNodes, isList;
this.expandImmutablesIn();
options = extend({
clean: false,
split: true
}, options);
if (!options.skipCleaners) {
for (i = 0, l = this.cleaners.length; i < l; i++) if (this.cleaners[i].applicable(html)) html = this.cleaners[i].clean(html);
}
if (options.clean) {
let brPrev;
do {
brPrev = html;
html = html.replace(/<br>(?:\s| )*(<\/?(div|p|li|col|t))/gi, "$1");
} while (html !== brPrev);
html = html.replace(/<(a|span)[^<>]*><\/\1>/gi, "");
}
html = html.replace(/<(a|span|font)([^<>]*)> <\/\1>/gi, "<$1$2> </$1>");
html = html.replace(/^<li/i, "<ul><li").replace(/li>$/g, "li></ul>");
var block = this.isBlock(html);
editor.focus();
var range = editor.getRange();
range.deleteContents();
if (range.startContainer == editor.document) range.selectNodeContents(editor.body);
var marker = new Marker();
var caret = marker.addCaret(range);
var parent = this.splittableParent(block, caret);
var unwrap = false;
for (i = 0; i < nonSplittableTagsOnPaste.length; i++) {
const splitter = nonSplittableTagsOnPaste[i], tag = splitter.tag || splitter;
if (dom.is(parent, tag)) {
preventSplit = true;
unwrapPasted = splitter.unwrap !== false;
break;
}
}
var splittable = parent != editor.body && !dom.is(parent, "td") && !preventSplit;
if (options.split && splittable && (block || dom.isInline(parent))) {
range.selectNode(caret);
RangeUtils.split(range, parent, true);
unwrap = true;
}
var fragment = this.htmlToFragment(html);
if (fragment.firstChild && fragment.firstChild.className === "k-paste-container") {
var fragmentsHtml = [];
for (i = 0, l = fragment.childNodes.length; i < l; i++) fragmentsHtml.push(fragment.childNodes[i].innerHTML);
fragment = this.htmlToFragment(fragmentsHtml.join("<br />"));
}
childNodes = fragment.childNodes;
if (unwrapPasted) {
isList = dom.list(childNodes[0]);
dom.unwrap(childNodes[0]);
if (isList) range.selectNode(caret.parentNode);
}
$(childNodes).filter("table").addClass("k-table").end().find("table").addClass("k-table");
$(childNodes).each(function(index, elm) {
if (dom.isBlock(elm) && !dom.isSelfClosing(elm) && elm.innerHTML === "") elm.appendChild(editor.document.createTextNode(""));
});
range.insertNode(fragment);
parent = this.splittableParent(block, caret);
if (unwrap) {
while (caret.parentNode != parent) dom.unwrap(caret.parentNode);
dom.unwrap(caret.parentNode);
}
dom.normalize(range.commonAncestorContainer);
caret.style.display = "inline";
dom.restoreScrollTop(editor.document);
dom.scrollTo(caret);
marker.removeCaret(range);
var rangeEnd = range.commonAncestorContainer.parentNode;
if (range.collapsed && dom.name(rangeEnd) == "tbody" || range.collapsed && dom.name(rangeEnd) == "thead") {
range.setStartAfter($(rangeEnd).closest("table")[0]);
range.collapse(true);
}
var focusedTable = $(range.commonAncestorContainer.parentNode).closest("table");
if (focusedTable.get(0)) {
var siblingNodes = focusedTable.parent().contents();
var lastSiblingIndex = siblingNodes.length - 1;
var lastSibling = siblingNodes.get(lastSiblingIndex);
while (lastSibling.nodeValue !== null && (lastSibling.nodeValue === " " || lastSibling.nodeValue === "")) {
lastSiblingIndex -= 1;
lastSibling = siblingNodes.get(lastSiblingIndex);
}
if (lastSibling === focusedTable.get(0) && !focusedTable.parents("table").length) dom.insertAfter(dom.createEmptyNode(editor.document, "p"), focusedTable[0]);
}
editor._handleSpaceAndNewLines();
editor.selectRange(range);
}
});
var Cleaner = Class.extend({
init: function(options) {
this.options = options || {};
this.replacements = [];
},
clean: function(html, customReplacements) {
var that = this, replacements = customReplacements || that.replacements, i, l;
for (i = 0, l = replacements.length; i < l; i += 2) html = html.replace(replacements[i], replacements[i + 1]);
return html;
}
});
var ScriptCleaner = Cleaner.extend({
init: function(options) {
Cleaner.fn.init.call(this, options);
this.replacements = [/<(\/?)script([^>]*)>/i, "<$1telerik:script$2>"];
},
applicable: function(html) {
return !this.options.none && /<script[^>]*>/i.test(html);
}
});
var TabCleaner = Cleaner.extend({
init: function(options) {
Cleaner.fn.init.call(this, options);
var replacement = " ";
this.replacements = [
/<span\s+class="Apple-tab-span"[^>]*>\s*<\/span>/gi,
replacement,
/\t/gi,
replacement,
/ /gi,
replacement
];
},
applicable: function(html) {
return / |class="?Apple-tab-span/i.test(html);
}
});
var MSWordFormatCleaner = Cleaner.extend({
init: function(options) {
Cleaner.fn.init.call(this, options);
this.junkReplacements = [
/<\?xml[^>]*>/gi,
"",
/<!--(.|\n)*?-->/g,
"",
/"/g,
"'",
/<o:p> <\/o:p>/gi,
" ",
/<\/?(meta|link|style|o:|v:|x:)[^>]*>((?:.|\n)*?<\/(meta|link|style|o:|v:|x:)[^>]*>)?/gi,
"",
/<\/o>/g,
""
];
this.replacements = this.junkReplacements.concat([
/(?:<br> [\s\r\n]+|<br>)*(<\/?(h[1-6]|hr|p|div|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|address|pre|form|blockquote|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br> [\s\r\n]+|<br>)*/g,
"$1",
/<br><br>/g,
"<BR><BR>",
/<br>\n/g,
"<br/>",
/<br>(?!\n)/g,
" ",
/<table([^>]*)>(\s| )+<t/gi,
"<table$1><t",
/<tr[^>]*>(\s| )*<\/tr>/gi,
"",
/<tbody[^>]*>(\s| )*<\/tbody>/gi,
"",
/<table[^>]*>(\s| )*<\/table>/gi,
"",
/<BR><BR>/g,
"<br>",
/^\s*( )+/gi,
"",
/( |<br[^>]*>)+\s*$/gi,
"",
/mso-[^;"]*;?/gi,
"",
/<(\/?)b(\s[^>]*)?>/gi,
"<$1strong$2>",
/<(\/?)font(\s[^>]*)?>/gi,
this.convertFontMatch,
/<(\/?)i(\s[^>]*)?>/gi,
"<$1em$2>",
/style=(["|'])\s*\1/g,
"",
/(<br[^>]*>)?\n/g,
function($0, $1) {
return $1 ? $0 : " ";
}
]);
},
convertFontMatch: function(match, closing, args) {
var face = /face=['"]([^'"]+)['"]/i.exec(args);
var family = args && face && face[1];
if (closing) return "</span>";
else if (family) return "<span style=\"font-family:" + family + "\">";
else return "<span>";
},
applicable: function(html) {
return /class="?Mso/i.test(html) || /style="[^"]*mso-/i.test(html) || /urn:schemas-microsoft-com:office/.test(html);
},
stripEmptyAnchors: function(html) {
return html.replace(/<a([^>]*)>\s*<\/a>/gi, function(a, attributes) {
if (!attributes || attributes.indexOf("href") < 0) return "";
return a;
});
},
listType: function(p, listData) {
var html = p.innerHTML;
var text = dom.innerText(p);
var startingSymbol;
var matchSymbol = html.match(/^(?:<span [^>]*texhtml[^>]*>)?<span [^>]*(?:Symbol|Wingdings)[^>]*>([^<]+)/i);
var symbol = matchSymbol && matchSymbol[1];
var isNumber = /^[a-z\d]/i.test(symbol);
var trimStartText = function(text) {
return text.replace(/^(?: |[\u00a0\n\r\s])+/, "");
};
if (matchSymbol) startingSymbol = true;
html = html.replace(/<\/?\w+[^>]*>/g, "").replace(/ /g, "\xA0");
if (!startingSymbol && /^[\u2022\u00b7\u00a7\u00d8o]\u00a0+/.test(html) || startingSymbol && /^.\u00a0+/.test(html) || symbol && !isNumber && listData) return {
tag: "ul",
style: this._guessUnorderedListStyle(trimStartText(text))
};
if (/^\s*\w+[\.\)][\u00a0 ]{2,}/.test(html)) return {
tag: "ol",
style: this._guessOrderedListStyle(trimStartText(text))
};
},
_convertToLi: function(p) {
var content;
if (p.childNodes.length == 1) {
content = p.firstChild.nodeType === dom.nodeTypes.TEXT_NODE ? dom.innerText(p) : p.firstChild.innerHTML.replace(/^\w+[\.\)]( )+ /, "");
content = this._checkForBullet(content);
} else content = this._getHtmlNoBullet(p);
dom.remove(p);
return dom.create(document, "li", { innerHTML: content });
},
_checkForBullet: function(html) {
var p = dom.create(document, "p", { innerHTML: html });
if (/^\s*\w+[\.\)]\s+/.test(p.innerText)) return this._getHtmlNoBullet(p);
return html;
},
_getHtmlNoBullet: function(element) {
var content, name = dom.name(element);
dom.remove(element.firstChild);
if (element.firstChild.nodeType == 3) {
if (/^[ivxlcdm]+\.$/i.test(element.firstChild.nodeValue)) dom.remove(element.firstChild);
}
if (/^( |\s)+$/i.test(element.firstChild.innerHTML)) dom.remove(element.firstChild);
if (name != "p") content = "<" + name + ">" + element.innerHTML + "</" + name + ">";
else content = element.innerHTML;
return content;
},
_guessUnorderedListStyle: function(symbol) {
if (/^[\u2022\u00b7\u00FC\u00D8\u002dv-]/.test(symbol)) return null;
else if (/^o/.test(symbol)) return "circle";
else return "square";
},
_guessOrderedListStyle: function(symbol) {
var listType = null;
if (!/^\d/.test(symbol)) listType = (/^[a-z]/.test(symbol) ? "lower-" : "upper-") + (/^[ivxlcdm]/i.test(symbol) ? "roman" : "alpha");
return listType;
},
extractListLevels: function(html) {
html = html.replace(/style=['"]?[^'"]*?mso-list:\s?[a-zA-Z]+(\d+)\s[a-zA-Z]+(\d+)\s(\w+)/gi, function(match, list, level) {
return kendo.format("data-list=\"{0}\" data-level=\"{1}\" {2}", list, level, match);
});
return html;
},
_createList: function(type, styleType) {
return dom.create(document, type, { style: { listStyleType: styleType } });
},
lists: function(placeholder) {
var blockChildren = $(placeholder).find(dom.blockElements.join(",")), lastMargin = -1, name, levels = {}, li, rootMargin, rootIndex, lastRootLi, isLastRootLi, rootList, i, p, type, margin, list, listData, acceptedNameTags = [
"p",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6"
], isParentTable = false;
for (i = 0; i < blockChildren.length; i++) {
p = blockChildren[i];
listData = $(p).data();
var listIndex = listData.list;
name = dom.name(p);
isParentTable = !!$(p).parents("table").length;
if (isParentTable) continue;
var listType = this.listType(p, listData);
type = listType && listType.tag;
if (!type || acceptedNameTags.indexOf(name) < 0) {
if (!p.innerHTML) dom.remove(p);
else if (li && !isLastRootLi) li.appendChild(p);
continue;
}
if (browser.msie) continue;
margin = listData.level || parseFloat(p.style.marginLeft || 0);
var levelType = type + listIndex;
if (!levels[margin]) levels[margin] = {};
if (!rootMargin || rootMargin < 0) {
rootMargin = margin;
rootIndex = listIndex;
lastRootLi = $(placeholder).find("[data-list='" + rootIndex + "']").last()[0];
rootList = this._createList(type, listType.style);
dom.insertBefore(rootList, p);
lastMargin = margin;
levels[margin][levelType] = rootList;
}
isLastRootLi = lastRootLi === p;
list = levels[margin][levelType];
if (margin > lastMargin || !list) {
list = this._createList(type, listType.style);
levels[margin][levelType] = list;
li.appendChild(list);
}
li = this._convertToLi(p);
list.appendChild(li);
if (isLastRootLi) rootMargin = lastMargin = -1;
else lastMargin = margin;
}
},
removeAttributes: function(element) {
var attributes = element.attributes, i = attributes.length, significantStyles = [], isSignificantCss = function(val) {
return [
"border",
"background",
"padding"
].filter(function(cssAttr) {
return val.trim().indexOf(cssAttr) === 0;
}).length > 0;
}, addSignificantStyles = function(val) {
if (isSignificantCss(val)) significantStyles.push(val.trim());
}, attr, attributeName, attributeValues;
while (i--) if (dom.name(attributes[i]) != "colspan") {
attr = attributes[i];
attributeName = attr.name;
if (attributeName === "style" && (element.nodeName === "TD" || element.nodeName === "TH")) {
attributeValues = attr.value.split(";");
attributeValues.forEach(addSignificantStyles);
}
element.removeAttributeNode(attributes[i]);
}
if (significantStyles.length > 0) element.setAttribute("style", significantStyles.join(";"));
},
createColGroup: function(row) {
var cells = row.cells;
var table = $(row).closest("table");
var colgroup = table.children("colgroup");
if (cells.length < 2) return;
else if (colgroup.length) {
cells = colgroup.children();
colgroup[0].parentNode.removeChild(colgroup[0]);
}
colgroup = $($.map(cells, function(cell) {
var width = cell.width;
if (width && parseInt(width, 10) !== 0) return kendo.format("<col style=\"width:{0}px;\"/>", width);
return "<col />";
}).join(""));
if (!colgroup.is("colgroup")) colgroup = $("<colgroup/>").append(colgroup);
colgroup.prependTo(table);
},
convertHeaders: function(row) {
var cells = row.cells, i, boldedCells = $.map(cells, function(cell) {
var child = $(cell).children("p").children("strong")[0];
if (child && dom.name(child) == "strong") return child;
});
if (boldedCells.length == cells.length) {
for (i = 0; i < boldedCells.length; i++) dom.unwrap(boldedCells[i]);
$(row).closest("table").find("colgroup").after("<thead></thead>").end().find("thead").append(row);
for (i = 0; i < cells.length; i++) dom.changeTag(cells[i], "th");
}
},
removeParagraphs: function(cells) {
var i, j, len, cell, paragraphs;
for (i = 0; i < cells.length; i++) {
this.removeAttributes(cells[i]);
cell = $(cells[i]);
paragraphs = cell.children("p");
for (j = 0, len = paragraphs.length; j < len; j++) {
if (j < len - 1) dom.insertAfter(dom.create(document, "br"), paragraphs[j]);
dom.unwrap(paragraphs[j]);
}
}
},
removeTextNodes: function(trs) {
var i, j, childNodes, currentNode, row;
for (i = 0; i < trs.length; i++) {
row = trs[i];
childNodes = row.childNodes;
for (j = 0; j < childNodes.length; j++) {
currentNode = childNodes[j];
if (currentNode.nodeType === dom.nodeTypes.TEXT_NODE) row.removeChild(currentNode);
}
}
},
tables: function(placeholder) {
var tables = $(placeholder).find("table"), that = this, rows, firstRow, longestRow, i, j;
for (i = 0; i < tables.length; i++) {
rows = tables[i].rows;
longestRow = firstRow = rows[0];
for (j = 1; j < rows.length; j++) if (rows[j].cells.length > longestRow.cells.length) longestRow = rows[j];
that.createColGroup(longestRow);
that.convertHeaders(firstRow);
that.removeAttributes(tables[i]);
that.removeParagraphs(tables.eq(i).find("td,th"));
that.removeTextNodes(tables.eq(i).find("tr"));
}
},
headers: function(placeholder) {
var titles = $(placeholder).find("p.MsoTitle");
for (var i = 0; i < titles.length; i++) dom.changeTag(titles[i], "h1");
},
removeFormatting: function(placeholder) {
$(placeholder).find("*").each(function() {
$(this).css({
fontSize: "",
fontFamily: ""
});
if (!this.getAttribute("style") && !this.style.cssText) this.removeAttribute("style");
});
},
clean: function(html) {
var that = this, placeholder;
var filters = this.options;
if (filters.none) {
html = Cleaner.fn.clean.call(that, html, this.junkReplacements);
html = that.stripEmptyAnchors(html);
} else {
html = filters.msConvertLists ? this.extractListLevels(html) : html;
html = Cleaner.fn.clean.call(that, html);
html = that.stripEmptyAnchors(html);
placeholder = dom.create(document, "div", { innerHTML: html });
that.headers(placeholder);
if (filters.msConvertLists) that.lists(placeholder);
that.tables(placeholder);
if (filters.msAllFormatting) that.removeFormatting(placeholder);
html = placeholder.innerHTML.replace(/(<[^>]*)\s+class="?[^"\s>]*"?/gi, "$1");
}
return html;
}
});
var WebkitFormatCleaner = Cleaner.extend({
init: function(options) {
Cleaner.fn.init.call(this, options);
this.replacements = [
/\s+class="Apple-style-span[^"]*"/gi,
"",
/<(div|p|h[1-6])\s+style="[^"]*"/gi,
"<$1",
/^<div>(.*)<\/div>$/,
"$1"
];
},
applicable: function(html) {
return /class="?Apple-style-span|style="[^"]*-webkit-nbsp-mode/i.test(html);
}
});
var DomCleaner = Cleaner.extend({
clean: function(html) {
var container = dom.create(document, "div", { innerHTML: html });
container = this.cleanDom(container);
return container.innerHTML;
},
cleanDom: function(container) {
return container;
}
});
var HtmlTagsCleaner = DomCleaner.extend({
cleanDom: function(container) {
var tags = this.collectTags();
$(container).find(tags).each(function() {
dom.unwrap(this);
});
return container;
},
collectTags: function() {
if (this.options.span) return "span";
},
applicable: function() {
return this.options.span;
}
});
var HtmlAttrCleaner = DomCleaner.extend({
cleanDom: function(container) {
var attributes = this.collectAttr();
$(container).find("[" + attributes.join("],[") + "]").removeAttr(attributes.join(" "));
return container;
},
collectAttr: function() {
if (this.options.css) return ["class", "style"];
return [];
},
applicable: function() {
return this.options.css;
}
});
var TextContainer = function() {
this.text = "";
this.add = function(text) {
this.text += text;
};
};
var HtmlTextLines = Class.extend({
init: function(separators) {
this.separators = separators || {
text: " ",
line: "<br/>"
};
this.lines = [];
this.inlineBlockText = [];
this.resetLine();
},
appendText: function(text) {
if (text.nodeType === 3) text = text.nodeValue;
this.textContainer.add(text);
},
appendInlineBlockText: function(text) {
this.inlineBlockText.push(text);
},
flashInlineBlockText: function() {
if (this.inlineBlockText.length) {
this.appendText(this.inlineBlockText.join(" "));
this.inlineBlockText = [];
}
},
endLine: function() {
this.flashInlineBlockText();
this.resetLine();
},
html: function() {
var separators = this.separators;
var result = "";
var lines = this.lines;
this.flashInlineBlockText();
for (var i = 0, il = lines.length, il1 = il - 1; i < il; i++) {
var line = lines[i];
for (var j = 0, jl = line.length, jl1 = jl - 1; j < jl; j++) {
var text = line[j].text;
result += text;
if (j !== jl1) result += separators.text;
}
if (i !== il1) result += separators.line;
}
return result;
},
resetLine: function() {
this.textContainer = new TextContainer();
this.line = [];
this.line.push(this.textContainer);
this.lines.push(this.line);
}
});
var DomEnumerator = Class.extend({
init: function(callback) {
this.callback = callback;
},
enumerate: function(node) {
if (!node) return;
var preventDown = this.callback(node);
var child = node.firstChild;
if (!preventDown && child) this.enumerate(child);
this.enumerate(node.nextSibling);
}
});
var HtmlContentCleaner = Cleaner.extend({
init: function(options) {
Cleaner.fn.init.call(this, options);
this.hasText = false;
this.enumerator = new DomEnumerator(this.buildText.bind(this));
},
clean: function(html) {
var container = dom.create(document, "div", { innerHTML: html });
return this.cleanDom(container);
},
cleanDom: function(container) {
this.separators = this.getDefaultSeparators();
this.htmlLines = new HtmlTextLines(this.separators);
this.enumerator.enumerate(container.firstChild);
this.hasText = false;
return this.htmlLines.html();
},
buildText: function(node) {
if (dom.isDataNode(node)) {
if (dom.isEmptyspace(node)) return;
this.htmlLines.appendText(node.nodeValue.replace("\n", this.separators.line));
this.hasText = true;
} else if (dom.isBlock(node) && this.hasText) return (this.actions[dom.name(node)] || this.actions.block)(this, node);
else if (dom.isBr(node)) this.htmlLines.appendText(this.separators.line);
},
applicable: function() {
var o = this.options;
return o.all || o.keepNewLines;
},
getDefaultSeparators: function() {
if (this.options.all) return {
text: " ",
line: " "
};
else return {
text: " ",
line: "<br/>"
};
},
actions: {
ul: $.noop,
ol: $.noop,
table: $.noop,
thead: $.noop,
tbody: $.noop,
td: function(cleaner, node) {
var cellText = new HtmlContentCleaner({ all: true }).cleanDom(node);
cleaner.htmlLines.appendInlineBlockText(cellText);
return true;
},
block: function(cleaner) {
cleaner.htmlLines.endLine();
}
}
});
var CustomCleaner = Cleaner.extend({
clean: function(html) {
return this.options.custom(html);
},
applicable: function() {
return typeof this.options.custom === "function";
}
});
extend(editorNS, {
Clipboard,
Cleaner,
ScriptCleaner,
TabCleaner,
MSWordFormatCleaner,
WebkitFormatCleaner,
HtmlTagsCleaner,
HtmlAttrCleaner,
HtmlContentCleaner,
HtmlTextLines,
CustomCleaner
});
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/keyboard.js
(function($) {
var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, RangeUtils = editorNS.RangeUtils, dom = editorNS.Dom, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, browser = kendo.support.browser, bomSpan = "<span class='k-br'></span>", extend = $.extend;
var nodeTypes = dom.nodeTypes;
var PREVIOUS_SIBLING = "previousSibling";
function selected(node, range) {
return range.startContainer === node && range.endContainer === node && range.startOffset === 0 && range.endOffset == node.childNodes.length;
}
function getSibling(node, direction, condition) {
var sibling = node ? node[direction] : null;
while (sibling && !condition(sibling)) sibling = sibling[direction];
return sibling;
}
var tableCells = "td,th,caption";
var tableCellsWrappers = "table,tbody,thead,tfoot,tr";
var tableElements = tableCellsWrappers + "," + tableCells;
var inTable = function(range) {
return !range.collapsed && $(range.commonAncestorContainer).is(tableCellsWrappers);
};
var RemoveTableContent = Class.extend({
remove: function(range) {
var that = this;
var marker = new Marker();
marker.add(range, false);
var nodes = RangeUtils.getAll(range, function(node) {
return $(node).is(tableElements);
});
var doc = RangeUtils.documentFromRange(range);
var start = marker.start;
var end = marker.end;
var cellsTypes = tableCells.split(",");
var startCell = dom.parentOfType(start, cellsTypes);
var endCell = dom.parentOfType(end, cellsTypes);
that._removeContent(start, startCell, true);
that._removeContent(end, endCell, false);
$(nodes).each(function(i, node) {
node = $(node);
(node.is(tableCells) ? node : node.find(tableCells)).each(function(j, cell) {
cell.innerHTML = "";
});
});
if (startCell && !start.previousSibling) dom.insertBefore(doc.createTextNode(""), start);
if (endCell && !end.nextSibling) dom.insertAfter(doc.createTextNode(""), end);
if (startCell) range.setStartBefore(start);
else if (nodes[0]) {
startCell = $(nodes[0]);
startCell = startCell.is(tableCells) ? startCell : startCell.find(tableCells).first();
if (startCell.length) range.setStart(startCell.get(0), 0);
}
range.collapse(true);
dom.remove(start);
dom.remove(end);
},
_removeContent: function(start, top, forwards) {
if (top) {
var sibling = forwards ? "nextSibling" : "previousSibling", next, getNext = function(node) {
while (node && !node[sibling]) node = node.parentNode;
return node && $.contains(top, node) ? node[sibling] : null;
};
start = getNext(start);
while (start) {
next = getNext(start);
dom.remove(start);
start = next;
}
}
}
});
var TypingHandler = Class.extend({
init: function(editor) {
this.editor = editor;
},
keydown: function(e) {
var that = this, editor = that.editor, keyboard = editor.keyboard, isTypingKey = keyboard.isTypingKey(e), evt = extend($.Event(), e);
that.editor.trigger("keydown", evt);
if (evt.isDefaultPrevented() || e && e.isDefaultPrevented()) {
e.preventDefault();
return true;
}
if (!evt.isDefaultPrevented() && isTypingKey && !keyboard.isTypingInProgress()) {
var range = editor.getRange();
var body = editor.body;
that.startRestorePoint = new RestorePoint(range, body);
if (inTable(range)) {
new RemoveTableContent(editor).remove(range);
editor.selectRange(range);
}
if (browser.webkit && !range.collapsed && selected(body, range)) body.innerHTML = "";
if (editor.immutables && editorNS.Immutables.immutablesContext(range)) new editorNS.BackspaceHandler(editor).deleteSelection(range);
keyboard.startTyping(function() {
that._removeBomSpan();
that.endRestorePoint = editorNS._finishUpdate(editor, that.startRestorePoint);
});
return true;
}
return false;
},
keyup: function(e) {
var keyboard = this.editor.keyboard;
this.editor.trigger("keyup", e);
if (keyboard.isTypingInProgress()) {
keyboard.endTyping();
return true;
}
return false;
},
_removeBomSpan: function() {
var node = this.editor.getRange().commonAncestorContainer;
if (!dom.emptyNode(node)) {
if (node.nodeType === 3) node = node.parentNode;
if (dom.insignificant(node)) {
node.textContent = dom.stripBom(node.textContent);
dom.unwrap(node);
}
}
}
});
var BackspaceHandler = Class.extend({
init: function(editor) {
this.editor = editor;
},
_addCaret: function(container) {
var caret = dom.create(this.editor.document, "a");
if (!kendo.support.browser.chrome && container.firstChild && container.firstChild.nodeType === nodeTypes.ELEMENT_NODE) container = container.firstChild;
dom.insertAt(container, caret, 0);
dom.stripBomNode(caret.previousSibling);
dom.stripBomNode(caret.nextSibling);
return caret;
},
_restoreCaret: function(caret) {
var range = this.editor.createRange();
if (!caret.nextSibling && dom.isDataNode(caret.previousSibling)) range.setStart(caret.previousSibling, caret.previousSibling.length);
else range.setStartAfter(caret);
range.collapse(true);
this.editor.selectRange(range);
dom.remove(caret);
},
_handleDelete: function(range) {
var node = range.endContainer;
var block = dom.closestEditableOfType(node, dom.blockElements);
if (block && editorNS.RangeUtils.isEndOf(range, block)) {
var next = dom.next(block);
if (!next || dom.name(next) != "p") return false;
var caretPlaceholder = dom.significantChildNodes(next)[0];
caretPlaceholder = caretPlaceholder && dom.isInline(caretPlaceholder) ? caretPlaceholder : next;
var caret = this._addCaret(caretPlaceholder);
this._merge(block, next);
this._restoreCaret(caret);
return true;
}
return false;
},
_cleanBomBefore: function(range) {
var offset = range.startOffset;
var node = range.startContainer;
var text = node.nodeValue;
var count = 0;
while (offset - count >= 0 && text[offset - count - 1] == "") count++;
if (count > 0) {
node.deleteData(offset - count, count);
range.setStart(node, Math.max(0, offset - count));
range.collapse(true);
this.editor.selectRange(range);
}
},
_handleBackspace: function(range) {
var node = range.startContainer;
var li = dom.closestEditableOfType(node, ["li"]);
var block = dom.closestEditableOfType(node, "p,h1,h2,h3,h4,h5,h6".split(","));
var editor = this.editor;
var previousSibling;
if (dom.isDataNode(node)) {
if (range.collapsed && /^\s[\ufeff]+$/.test(node.nodeValue)) {
range.setStart(node, 0);
range.setEnd(node, node.length);
editor.selectRange(range);
return false;
}
this._cleanBomBefore(range);
}
previousSibling = getSibling(block, PREVIOUS_SIBLING, function(sibling) {
return !dom.htmlIndentSpace(sibling);
});
if (range.collapsed && range.startOffset !== range.endOffset && range.startOffset < 0) {
range.startOffset = 0;
range.endOffset = 0;
editor.selectRange(range);
}
var startAtLi = li && editorNS.RangeUtils.isStartOf(range, li);
var liIndex = li && $(li).index();
var startAtNonFirstLi = startAtLi && liIndex > 0;
if (startAtNonFirstLi) {
block = li;
previousSibling = dom.prev(li);
}
if (block && previousSibling && dom.is(previousSibling, "table") && editorNS.RangeUtils.isStartOf(range, block)) {
if (block.innerText === "") block.innerHTML = "";
return true;
}
if (editorNS.RangeUtils.isStartOf(range, block) && parseInt(block.style.marginLeft, 10) > 0) {
editor.exec("outdent");
return true;
}
if (block && previousSibling && editorNS.RangeUtils.isStartOf(range, block) || startAtNonFirstLi) {
var caretPlaceholder = dom.significantChildNodes(block)[0];
caretPlaceholder = caretPlaceholder && dom.isInline(caretPlaceholder) && !dom.isImg(caretPlaceholder) ? caretPlaceholder : block;
var caret = this._addCaret(caretPlaceholder);
this._merge(previousSibling, block);
this._restoreCaret(caret);
return true;
}
if (startAtLi && liIndex === 0) {
var child = li.firstChild;
if (!child) {
li.innerHTML = editorNS.emptyElementContent;
child = li.firstChild;
}
var formatter = new editorNS.ListFormatter(dom.name(li.parentNode), "p");
range.selectNodeContents(li);
formatter.toggle(range);
if (dom.insignificant(child)) range.setStartBefore(child);
else range.setStart(child, 0);
editor.selectRange(range);
return true;
}
var rangeStartNode = node.childNodes[range.startOffset - 1];
var linkRange = range;
var anchor = rangeStartNode && dom.closestEditableOfType(rangeStartNode, ["a"]);
var previousNode = getSibling(rangeStartNode || node, PREVIOUS_SIBLING, function(sibling) {
return !dom.isDataNode(sibling) || !dom.isBom(sibling) && sibling.length > 0;
});
if (anchor || (range.startOffset === 0 || rangeStartNode) && dom.is(previousNode, "a")) {
anchor = anchor || previousNode;
linkRange = editor.createRange();
linkRange.setStart(anchor, anchor.childNodes.length);
linkRange.collapse(true);
}
anchor = anchor || dom.closestEditableOfType(rangeStartNode || linkRange.startContainer, ["a"]);
if (anchor && editorNS.RangeUtils.isEndOf(linkRange, anchor)) {
var command = new editorNS.UnlinkCommand({
range: linkRange,
body: editor.body,
immutables: !!editor.immutables
});
editor.execCommand(command);
editor._selectionChange();
}
return false;
},
_handleSelection: function(range) {
var ancestor = range.commonAncestorContainer;
var table = dom.closest(ancestor, "table");
var emptyParagraphContent = editorNS.emptyElementContent;
var editor = this.editor;
var parentElementOrNode;
if (inTable(range)) {
new RemoveTableContent(editor).remove(range);
editor.selectRange(range);
return true;
}
var marker = new Marker();
marker.add(range, false);
if (range.commonAncestorContainer === editor.body) this._surroundFullyContent(marker, range);
if (editor.immutables) this._handleImmutables(marker);
this._surroundFullySelectedAnchor(marker, range);
range.setStartAfter(marker.start);
range.setEndBefore(marker.end);
var start = range.startContainer;
var end = range.endContainer;
range.deleteContents();
if (end.tagName.toLocaleLowerCase() === "li" && dom.emptyNode(end)) {
range.selectNode(end);
range.deleteContents();
}
if (table && $(table).text() === "") {
range.selectNode(table);
range.deleteContents();
}
ancestor = range.commonAncestorContainer;
if (dom.name(ancestor) === "p" && ancestor.innerHTML === "") {
ancestor.innerHTML = emptyParagraphContent;
range.setStart(ancestor, 0);
}
this._join(start, end);
dom.insertAfter(editor.document.createTextNode(""), marker.start);
marker.remove(range);
start = range.startContainer;
if (dom.name(start) == "tr") {
start = start.childNodes[Math.max(0, range.startOffset - 1)];
range.setStart(start, dom.getNodeLength(start));
}
range.collapse(true);
editor.selectRange(range);
parentElementOrNode = start.parentElement || start.parentNode;
if (dom.isDataNode(start) && !dom.emptyNode(parentElementOrNode)) this._cleanBomBefore(range);
return true;
},
_handleImmutables: function(marker) {
var immutableParent = editorNS.Immutables.immutableParent;
var startImmutable = immutableParent(marker.start);
var endImmutable = immutableParent(marker.start);
if (startImmutable) dom.insertBefore(marker.start, startImmutable);
if (endImmutable) dom.insertAfter(marker.end, endImmutable);
if (startImmutable) dom.remove(startImmutable);
if (endImmutable && endImmutable.parentNode) dom.remove(endImmutable);
},
_surroundFullyContent: function(marker, range) {
var children = range.commonAncestorContainer.children, startParent = children[0], endParent = children[children.length - 1];
this._moveMarker(marker, range, startParent, endParent);
},
_surroundFullySelectedAnchor: function(marker, range) {
var start = marker.start, startParent = $(start).closest("a").get(0), end = marker.end, endParent = $(end).closest("a").get(0);
this._moveMarker(marker, range, startParent, endParent);
},
_moveMarker: function(marker, range, startParent, endParent) {
var start = marker.start, end = marker.end;
if (startParent && RangeUtils.isStartOf(range, startParent)) dom.insertBefore(start, startParent);
if (endParent && RangeUtils.isEndOf(range, endParent)) dom.insertAfter(end, endParent);
},
_root: function(node) {
while (node && dom.name(node) != "body" && node.parentNode && dom.name(node.parentNode) != "body") node = node.parentNode;
return node;
},
_join: function(start, end) {
start = this._root(start);
end = this._root(end);
if (start != end && dom.is(end, "p")) this._merge(start, end);
},
_merge: function(dest, src) {
dom.removeTrailingBreak(dest);
while (dest && src.firstChild) if (dest.nodeType == 1) {
dest = dom.list(dest) ? dest.children[dest.children.length - 1] : dest;
if (dest) dest.appendChild(src.firstChild);
} else if (dest.nodeType === nodeTypes.TEXT_NODE) this._mergeWithTextNode(dest, src.firstChild);
else dest.parentNode.appendChild(src.firstChild);
dom.remove(src);
},
_mergeWithTextNode: function(textNode, appendedNode) {
if (textNode && textNode.nodeType === nodeTypes.TEXT_NODE) if (textNode.nextSibling && this._isCaret(textNode.nextSibling)) dom.insertAfter(appendedNode, textNode.nextSibling);
else dom.insertAfter(appendedNode, textNode);
},
_isCaret: function(element) {
return $(element).is("a");
},
keydown: function(e) {
var method, startRestorePoint;
var editor = this.editor;
var range = editor.getRange();
var keyCode = e.keyCode;
var keys = kendo.keys;
var backspace = keyCode === keys.BACKSPACE;
var del = keyCode == keys.DELETE;
if (editor.immutables && editor.immutables.keydown(e, range)) return;
if ((backspace || del) && !range.collapsed) method = "_handleSelection";
else if (backspace) method = "_handleBackspace";
else if (del) method = "_handleDelete";
if (!method) return;
startRestorePoint = new RestorePoint(range, editor.body);
if (this[method](range)) {
e.preventDefault();
editorNS._finishUpdate(editor, startRestorePoint);
}
},
deleteSelection: function(range) {
this._handleSelection(range);
},
keyup: $.noop
});
extend(editorNS, {
TypingHandler,
SystemHandler: Class.extend({
init: function(editor) {
this.editor = editor;
this.systemCommandIsInProgress = false;
},
createUndoCommand: function() {
this.startRestorePoint = this.endRestorePoint = editorNS._finishUpdate(this.editor, this.startRestorePoint);
},
changed: function() {
if (this.startRestorePoint) return this.startRestorePoint.html != this.editor.body.innerHTML;
return false;
},
keydown: function(e) {
var that = this, editor = that.editor, keyboard = editor.keyboard;
if (keyboard.isModifierKey(e)) {
if (keyboard.isTypingInProgress()) keyboard.endTyping(true);
that.startRestorePoint = new RestorePoint(editor.getRange(), editor.body);
return true;
}
if (keyboard.isSystem(e)) {
that.systemCommandIsInProgress = true;
if (that.changed()) {
that.systemCommandIsInProgress = false;
that.createUndoCommand();
}
return true;
}
return false;
},
keyup: function() {
var that = this;
if (that.systemCommandIsInProgress && that.changed()) {
that.systemCommandIsInProgress = false;
that.createUndoCommand();
return true;
}
return false;
}
}),
BackspaceHandler,
SelectAllHandler: Class.extend({
init: function(editor) {
this.editor = editor;
},
keydown: function(e) {
if (!browser.webkit || e.isDefaultPrevented() || !(e.ctrlKey && e.keyCode == 65 && !e.altKey && !e.shiftKey)) return;
if (this.editor.options.immutables) this._toSelectableImmutables();
this._selectEditorBody();
},
_selectEditorBody: function() {
var editor = this.editor;
var range = editor.getRange();
range.selectNodeContents(editor.body);
setTimeout(function() {
editor.selectRange(range);
});
},
_toSelectableImmutables: function() {
var body = this.editor.body, immutable = editorNS.Immutables.immutable, emptyTextNode = dom.emptyTextNode, first = body.firstChild, last = body.lastChild;
while (emptyTextNode(first)) first = first.nextSibling;
while (emptyTextNode(last)) last = last.previousSibling;
if (first && immutable(first)) $(bomSpan).prependTo(body);
if (last && immutable(last)) $(bomSpan).appendTo(body);
},
keyup: $.noop
}),
Keyboard: Class.extend({
init: function(handlers) {
this.handlers = handlers;
this.typingInProgress = false;
},
isCharacter: function(keyCode) {
return keyCode >= 48 && keyCode <= 90 || keyCode >= 96 && keyCode <= 111 || keyCode >= 186 && keyCode <= 192 || keyCode >= 219 && keyCode <= 222 || keyCode == 229;
},
toolFromShortcut: function(tools, e) {
var key = String.fromCharCode(e.keyCode), toolName, toolOptions, modifier = this._getShortcutModifier(e, navigator.platform);
for (toolName in tools) {
toolOptions = $.extend({
ctrl: false,
alt: false,
shift: false
}, tools[toolName].options);
if ((toolOptions.key == key || toolOptions.key == e.keyCode) && toolOptions.ctrl == modifier && toolOptions.alt == e.altKey && toolOptions.shift == e.shiftKey) return toolName;
}
},
_getShortcutModifier: function(e, platform) {
return platform.toUpperCase().indexOf("MAC") >= 0 ? e.metaKey : e.ctrlKey;
},
toolsFromShortcut: function(tools, e) {
var key = String.fromCharCode(e.keyCode), toolName, o, matchesKey, found = [];
var matchKey = function(toolKey) {
return toolKey == key || toolKey == e.keyCode || toolKey == e.charCode;
};
for (toolName in tools) {
o = $.extend({
ctrl: false,
alt: false,
shift: false
}, tools[toolName].options);
matchesKey = Array.isArray(o.key) ? $.grep(o.key, matchKey).length > 0 : matchKey(o.key);
if (matchesKey && o.ctrl == e.ctrlKey && o.alt == e.altKey && o.shift == e.shiftKey) found.push(tools[toolName]);
}
return found;
},
isTypingKey: function(e) {
var keyCode = e.keyCode;
return this.isCharacter(keyCode) && !e.ctrlKey && !e.altKey || keyCode == 32 || keyCode == 13 || keyCode == 8 || keyCode == 46 && !e.shiftKey && !e.ctrlKey && !e.altKey;
},
isModifierKey: function(e) {
var keyCode = e.keyCode;
return keyCode == 17 && !e.shiftKey && !e.altKey || keyCode == 16 && !e.ctrlKey && !e.altKey || keyCode == 18 && !e.ctrlKey && !e.shiftKey;
},
isSystem: function(e) {
return e.keyCode == 46 && e.ctrlKey && !e.altKey && !e.shiftKey;
},
startTyping: function(callback) {
this.onEndTyping = callback;
this.typingInProgress = true;
},
stopTyping: function() {
if (this.typingInProgress && this.onEndTyping) this.onEndTyping();
this.typingInProgress = false;
},
endTyping: function(force) {
var that = this;
that.clearTimeout();
if (force) that.stopTyping();
else that.timeout = window.setTimeout(that.stopTyping.bind(that), 1e3);
},
isTypingInProgress: function() {
return this.typingInProgress;
},
clearTimeout: function() {
window.clearTimeout(this.timeout);
},
notify: function(e, what) {
var i, handlers = this.handlers;
for (i = 0; i < handlers.length; i++) if (handlers[i][what](e)) break;
},
keydown: function(e) {
this.notify(e, "keydown");
},
keyup: function(e) {
this.notify(e, "keyup");
}
})
});
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/exportpdf.js
(function($) {
var editorNS = window.kendo.ui.editor, Command = editorNS.Command, registerTool = editorNS.EditorUtils.registerTool, Tool = editorNS.Tool, extend = $.extend;
var ExportPdfCommand = Command.extend({
init: function(options) {
this.async = true;
Command.fn.init.call(this, options);
},
exec: function() {
var that = this;
var range = that.lockRange(true);
var editor = that.editor;
editor._destroyResizings();
editor.saveAsPDF().then(function() {
that.releaseRange(range);
editor._initializeColumnResizing();
editor._initializeRowResizing();
editor._initializeElementResizing();
});
}
});
extend(editorNS, { ExportPdfCommand });
registerTool("pdf", new Tool({ command: ExportPdfCommand }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/print.js
(function($) {
var kendo = window.kendo, editorNS = kendo.ui.editor, Command = editorNS.Command, registerTool = editorNS.EditorUtils.registerTool, Tool = editorNS.Tool, extend = $.extend;
var PrintCommand = Command.extend({
init: function(options) {
Command.fn.init.call(this, options);
this.managesUndoRedo = true;
},
exec: function() {
var editor = this.editor;
if (kendo.support.browser.msie) editor.document.execCommand("print", false, null);
else if (editor.window.print) editor.window.print();
}
});
extend(editorNS, { PrintCommand });
registerTool("print", new Tool({ command: PrintCommand }));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/formatpainter.js
(function($) {
var Editor = window.kendo.ui.editor, Tool = Editor.Tool, Command = Editor.Command, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, registerTool = EditorUtils.registerTool;
var CopyFormatCommand = Command.extend({
init: function(options) {
Command.fn.init.call(this, options);
},
exec: function() {
var range = this.lockRange(true);
this.inlineStyles = [];
this.blockStyles = [];
this.collectStyles(range);
this.editor.inlineStyles = this.inlineStyles;
this.editor.blockStyles = this.blockStyles;
this.releaseRange(range);
},
collectStyles: function(range) {
var rangeNodes = RangeUtils.nodes(range);
var node;
if (rangeNodes.length === 1) node = rangeNodes[0].parentNode;
else node = range.startContainer;
while (node && !dom.is(node, "body") && node.getAttribute("data-role") !== "editor") if (dom.isBlock(node)) {
this.populateStyles(node, "blockStyles");
if (dom.is(node, "li")) node = node.parentNode;
else node = null;
} else {
this.populateStyles(node, "inlineStyles");
node = node.parentNode;
}
},
populateStyles: function(node, destination) {
var styles = node.style;
var attributes = node.attributes;
var nodeStyles = {
tags: [node.tagName],
attr: { style: {} }
};
var styleValue, styleKey, attributeKey, attributeValue, i;
if (styles) for (i = 0; i < styles.length; i++) {
styleKey = styles[i];
styleValue = styles[styleKey];
nodeStyles.attr.style[styleKey] = styleValue;
}
if (attributes) for (i = 0; i < attributes.length; i++) {
attributeKey = attributes[i].nodeName;
attributeValue = attributes[i].nodeValue;
if (attributeKey === "style") continue;
else if (attributeKey === "class") nodeStyles.attr.className = attributeValue;
else nodeStyles.attr[attributeKey] = attributeValue;
}
this[destination].push(nodeStyles);
}
});
var ApplyFormatCommand = Command.extend({
init: function(options) {
Command.fn.init.call(this, options);
},
exec: function() {
var range = this.lockRange(true);
var markers = RangeUtils.getMarkers(range);
var editor = this.editor;
var inlineStyles = editor.inlineStyles;
var blockStyles = editor.blockStyles;
var nodes;
if ((!inlineStyles || inlineStyles.length === 0) && (!blockStyles || blockStyles.length === 0)) return;
if (markers.length === 3) {
this.marker.removeCaret(range);
this.marker.caret = null;
}
this.removeEmptyElementsFromRange(range);
nodes = RangeUtils.nodes(range);
this.cleanInlineParents(nodes);
dom.normalize(range.commonAncestorContainer);
if (markers.length === 2) {
range.setStartAfter(markers[0]);
range.setEndBefore(markers[1]);
} else {
range.setStartBefore(nodes[0]);
range.setEndAfter(nodes[0]);
}
nodes = RangeUtils.nodes(range);
if (nodes && blockStyles && blockStyles.length) this.applyBlockStyles(nodes, blockStyles);
if (nodes && inlineStyles && inlineStyles.length) this.applyInlineStyles(nodes, inlineStyles);
this.releaseRange(range);
},
removeEmptyElementsFromRange: function(range) {
var isEmptyInline = function(node) {
return dom.isInline(node) && !node.firstChild && !dom.isMarker(node);
};
var emptyElements = RangeUtils.getAll(range, isEmptyInline), i;
if (emptyElements && emptyElements.length > 0) for (i = 0; i < emptyElements.length; i++) emptyElements[i].parentNode.removeChild(emptyElements[i]);
},
cleanInlineParents: function(nodes) {
var i, node, parent, children, j, child, newNode;
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
parent = node.parentNode;
if (this.immutableParent(node)) continue;
while (parent && dom.isInline(parent)) {
children = parent.childNodes;
for (j = 0; j < children.length; j++) {
child = children[j];
if (!dom.isMarker(child) && child !== node) {
newNode = parent.cloneNode(true);
newNode.innerHTML = "";
dom.wrap(child, newNode);
}
}
dom.unwrap(parent);
parent = node.parentNode;
}
}
},
applyBlockStyles: function(nodes, blockStyles) {
var formatTag = blockStyles[0].tags[0];
var attr = blockStyles[0].attr;
var document = this.editor.document;
var i, len, node, wrapper, blockParent, outerWrapper;
var previousNodes, nextNodes, previous, next, prevWrapper, nextWrapper, child, j, listItems;
for (i = 0, len = nodes.length; i < len; i++) {
node = nodes[i];
if (dom.isWhitespace(node) || this.immutableParent(node)) continue;
blockParent = dom.blockParentOrBody(node);
if (blockParent.tagName !== "BODY" && blockParent.tagName !== formatTag) {
if (blockParent.tagName !== "LI" && blockParent.tagName !== "TD" && blockParent.tagName !== "TH") {
previousNodes = [];
nextNodes = [];
previous = node.previousSibling;
next = node.nextSibling;
while (previous) {
if (!dom.isMarker(previous)) previousNodes.push(previous);
previous = previous.previousSibling;
}
if (previousNodes.length) {
prevWrapper = blockParent.cloneNode(true);
prevWrapper.innerHTML = "";
dom.insertBefore(prevWrapper, previousNodes[0]);
for (j = 0; j < previousNodes.length; j++) {
child = previousNodes[j];
dom.insertAt(prevWrapper, child, 0);
}
}
while (next) {
if (!dom.isMarker(next)) nextNodes.push(next);
next = next.nextSibling;
}
if (nextNodes.length) {
nextWrapper = blockParent.cloneNode(true);
nextWrapper.innerHTML = "";
dom.insertBefore(nextWrapper, nextNodes[0]);
for (j = 0; j < nextNodes.length; j++) {
child = nextNodes[j];
nextWrapper.appendChild(child);
}
}
dom.unwrap(blockParent);
}
wrapper = dom.create(document, formatTag, attr);
dom.wrap(node, wrapper);
} else if (blockParent.tagName === formatTag) dom.attr(blockParent, attr);
}
if (blockParent && blockStyles.length === 2 && blockParent.tagName !== "LI" && formatTag === "LI") {
listItems = [];
while (dom.is(wrapper, "li")) {
listItems.push(wrapper);
wrapper = dom.prev(wrapper);
}
outerWrapper = dom.create(document, blockStyles[1].tags[0], blockStyles[1].attr);
dom.insertBefore(outerWrapper, listItems[listItems.length - 1]);
outerWrapper.appendChild(listItems[0]);
for (i = 1, len = listItems.length; i < len; i++) dom.insertBefore(listItems[i], outerWrapper.firstChild);
} else if (blockParent && blockStyles.length === 2 && blockParent.tagName !== "LI") {
outerWrapper = dom.create(document, blockStyles[1].tags[0], blockStyles[1].attr);
dom.wrap(wrapper, outerWrapper);
}
},
applyInlineStyles: function(nodes, inlineStyles) {
var document = this.editor.document;
var currentStyle, createdNode, topNode, i, newNode, node;
for (i = 0; i < inlineStyles.length; i++) {
currentStyle = inlineStyles[i];
createdNode = dom.create(document, currentStyle.tags[0], currentStyle.attr);
if (topNode) createdNode.appendChild(topNode);
topNode = createdNode;
}
if (topNode) for (i = 0; i < nodes.length; i++) {
node = nodes[i];
if (dom.isWhitespace(node) || this.immutableParent(node)) continue;
newNode = topNode.cloneNode(true);
dom.insertBefore(newNode, node);
while (newNode.children && newNode.children.length) newNode = newNode.children[0];
newNode.appendChild(node);
}
},
immutables: function() {
return this.editor && this.editor.options.immutables;
},
immutableParent: function(node) {
return this.immutables() && Editor.Immutables.immutableParent(node);
}
});
var CopyFormatTool = Tool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
},
command: function(commandArguments) {
return new CopyFormatCommand(commandArguments);
}
});
var ApplyFormatTool = Tool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
},
command: function(commandArguments) {
return new ApplyFormatCommand(commandArguments);
}
});
$.extend(Editor, {
CopyFormatCommand,
ApplyFormatCommand,
CopyFormatTool,
ApplyFormatTool
});
registerTool("copyFormat", new CopyFormatTool({}));
registerTool("applyFormat", new ApplyFormatTool({}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/lineheight.js
(function($) {
const kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, dom = Editor.Dom, Tool = Editor.Tool, DelayedExecutionTool = Editor.DelayedExecutionTool, BlockFormatter = Editor.BlockFormatter, FormatCommand = Editor.FormatCommand, GreedyInlineFormatFinder = Editor.GreedyInlineFormatFinder, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, registerFormat = EditorUtils.registerFormat, RangeUtils = Editor.RangeUtils, MOUSEDOWN_NS = "mousedown.kendoEditor", KEYDOWN_NS = "keydown.kendoEditor";
const LineHeightCommand = FormatCommand.extend({ exec: function() {
const cmd = this, range = cmd.lockRange(true), nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
cmd.formatter.format[0].attr.style.lineHeight = cmd.options.value.lineHeight;
cmd.formatter.apply(nodes);
cmd.releaseRange(range);
} });
const LineHeightFormatTool = DelayedExecutionTool.extend({
init: function(options) {
Tool.fn.init.call(this, options);
this.type = "kendoComboBox";
this.format = [{ tags: ["p", "lineHeight"] }];
this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr, options.fontAttr, options.defaultValue);
},
command: function(commandArguments) {
var that = this;
return new LineHeightCommand(extend(commandArguments, { formatter: function() {
return new BlockFormatter(that.options.format);
} }));
},
initialize: function(ui, editor) {
let tool = this, component = ui.getKendoComboBox();
tool.editor = editor;
component.bind("change", this.changeHandler.bind(this));
component.bind("close", this.closeHandler.bind(this));
component.wrapper.on(MOUSEDOWN_NS, ".k-input-button,.k-input-inner", this.mouseDownHandler.bind(this)).on(KEYDOWN_NS, this.keyDownHandler.bind(this));
},
changeHandler: function(e) {
this._exec(e.sender.value());
},
closeHandler: function() {
let that = this, editor = that.editor;
setTimeout(function() {
editor._deleteSavedRange();
that.currentRange = null;
}, 0);
},
mouseDownHandler: function() {
let newRange = this.editor.getRange();
this.currentRange = this.editor._containsRange(newRange) ? newRange : this.currentRange;
},
keyDownHandler: function(e) {
if (e.keyCode === kendo.keys.ENTER) {
this.editor._deleteSavedRange();
this.currentRange = null;
e.preventDefault();
}
},
_exec: function(value) {
let editor = this.editor;
editor._range = this.currentRange;
if (value) Tool.exec(this.editor, this.options.name, { lineHeight: value });
}
});
$.extend(Editor, {
LineHeightCommand,
LineHeightFormatTool
});
registerFormat("lineHeight", [{
tags: dom.blockElements,
attr: { style: { lineHeight: "normal" } }
}]);
registerTool("lineHeight", new LineHeightFormatTool({
cssAttr: "line-height",
format: formats.lineHeight,
defaultValue: 1.15,
ui: {
type: "component",
component: "ComboBox",
componentOptions: {
value: 1.15,
dataTextField: "text",
dataValueField: "value",
prefixOptions: { icon: "paragraphHeight" },
autoSize: true,
dataSource: [
{
text: "1",
value: "1"
},
{
text: "1.15",
value: "1.15"
},
{
text: "1.5",
value: "1.5"
},
{
text: "2",
value: "2"
},
{
text: "2.5",
value: "2.5"
}
]
}
}
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/plugins/formattingmarks.js
(function($) {
const Editor = window.kendo.ui.editor, Tool = Editor.Tool, Command = Editor.Command, registerTool = Editor.EditorUtils.registerTool, DOM = Editor.Dom, SPACE_UNICODE = "·", NEW_LINE_UNICODE = "↵";
const createMark = function(range, document, character, scrollTop, index, scrollableWrapper) {
const clonedRange = range.cloneRange(), container = clonedRange.startContainer;
let domRect, x, y, textNode, parentRect;
if (index !== void 0 && index !== null) {
clonedRange.setStart(container, index);
clonedRange.setEnd(container, index + 1);
}
domRect = clonedRange.getBoundingClientRect();
if (scrollableWrapper) {
parentRect = scrollableWrapper.getBoundingClientRect();
x = domRect.left - parentRect.left - domRect.width / 2;
y = domRect.top - parentRect.top + domRect.height + scrollTop;
} else if (character === SPACE_UNICODE) {
x = domRect.x - domRect.width / 4;
y = domRect.y + domRect.height + scrollTop;
} else if (character === NEW_LINE_UNICODE) {
x = domRect.x;
y = domRect.y + domRect.height + scrollTop;
}
textNode = document.createElementNS("http://www.w3.org/2000/svg", "text");
textNode.setAttributeNS(null, "x", x);
textNode.setAttributeNS(null, "y", y);
textNode.setAttributeNS(null, "fill", "#6098f2");
textNode.setAttributeNS(null, "font-size", `${Math.ceil(domRect.height + domRect.width)}px`);
textNode.textContent = character;
return textNode;
};
const appendSvgMarks = function() {
const that = this, range = that.getRange().cloneRange(), overlay = that._formattingMarksOverlay[0], fragment = that.document.createDocumentFragment(), document = that.document, isInlineEditor = that._isInlineEditor(), scrollableWrapper = isInlineEditor ? that.body.parentElement : null, scrollTop = isInlineEditor ? scrollableWrapper.scrollTop : document.documentElement.scrollTop;
if (!that.body.firstChild && !that.body.lastChild) return;
range.setStart(that.body.firstChild, 0);
range.setEnd(that.body.lastChild, 0);
DOM.getTextNodes(that.body).concat($(that.body).find("br").toArray()).forEach((node) => {
if (node.nodeType === DOM.nodeTypes.TEXT_NODE) {
range.selectNodeContents(node);
for (let i = range.startOffset; i < range.endOffset; i++) if (range.startContainer.textContent.charCodeAt(i) === 32 || range.startContainer.textContent.charCodeAt(i) === 160) fragment.appendChild(createMark(range, document, SPACE_UNICODE, scrollTop, i, scrollableWrapper));
} else {
range.selectNode(node);
fragment.appendChild(createMark(range, document, NEW_LINE_UNICODE, scrollTop, null, scrollableWrapper));
}
});
overlay.appendChild(fragment);
};
const clearFormattingMarksOverlay = function(editor) {
editor._formattingMarksOverlay.empty();
};
const applyFormattingMarks = function(editor) {
editor._updateFormattingMarksOverlayHeight();
appendSvgMarks.call(editor);
};
const FormattingMarksCommand = Command.extend({ exec: function() {
const cmd = this, range = cmd.lockRange(true), editor = cmd.editor;
if (!editor._toggledFormattingMarks) {
editor._toggledFormattingMarks = true;
editor._appendFormattingMarksOverlay();
editor._appendFormattingMarksStyles();
clearFormattingMarksOverlay(editor);
applyFormattingMarks(editor);
} else {
editor._toggledFormattingMarks = false;
editor._destroyFormattingMarksOverlay();
}
cmd.releaseRange(range);
} });
$.extend(Editor, {
FormattingMarksCommand,
applyFormattingMarks,
clearFormattingMarksOverlay
});
registerTool("formattingMarks", new Tool({
command: FormattingMarksCommand,
icon: "paragraphMark",
ui: { togglable: true }
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/resizing/resizing-utils.js
(function(kendo, undefined) {
var global = window;
var math = global.Math;
var min = math.min;
var max = math.max;
var parseFloat = global.parseFloat;
var $ = kendo.jQuery;
var extend = $.extend;
var Editor = kendo.ui.editor;
var PERCENTAGE = "%";
var PIXEL = "px";
var REGEX_NUMBER_IN_PERCENTAGES = /(\d+)(\.?)(\d*)%/;
var REGEX_NUMBER_IN_PIXELS = /(\d+)(\.?)(\d*)px/;
var STRING = "string";
function constrain(options) {
var value = options.value;
var lowerBound = options.min;
var upperBound = options.max;
return max(min(parseFloat(value), parseFloat(upperBound)), parseFloat(lowerBound));
}
function getScrollBarWidth(element) {
if (element && !$(element).is("body") && element.scrollHeight > element.clientHeight) return kendo.support.scrollbar();
return 0;
}
function calculatePercentageRatio(value, total) {
if (inPercentages(value)) return parseFloat(value);
else return parseFloat(value) / total * 100;
}
function inPercentages(value) {
return typeof value === STRING && REGEX_NUMBER_IN_PERCENTAGES.test(value);
}
function inPixels(value) {
return typeof value === STRING && REGEX_NUMBER_IN_PIXELS.test(value);
}
function toPercentages(value) {
return parseFloat(value) + PERCENTAGE;
}
function toPixels(value) {
return parseFloat(value) + PIXEL;
}
extend(Editor, { ResizingUtils: {
constrain,
getScrollBarWidth,
calculatePercentageRatio,
inPercentages,
inPixels,
toPercentages,
toPixels
} });
})(window.kendo);
//#endregion
//#region ../src/editor/resizing/table-element-resizing.js
(function(kendo, undefined) {
var $ = kendo.jQuery;
var extend = $.extend;
var noop = $.noop;
var Editor = kendo.ui.editor;
var Class = kendo.Class;
var KEY_DOWN = "keydown";
var MOUSE_DOWN = "mousedown";
var MOUSE_ENTER = "mouseenter";
var MOUSE_LEAVE = "mouseleave";
var MOUSE_MOVE = "mousemove";
var MOUSE_UP = "mouseup";
var COMMA = ",";
var DOT = ".";
var LAST_CHILD = ":last-child";
var TABLE = "table";
var TableElementResizing = Class.extend({
init: function(element, options) {
var that = this;
that.options = extend({}, that.options, options);
that.options.tags = Array.isArray(that.options.tags) ? that.options.tags : [that.options.tags];
if ($(element).is(TABLE)) {
that.element = element;
that._attachEventHandlers();
}
},
destroy: function() {
var that = this;
var eventNamespace = that.options.eventNamespace;
if (that.element) {
$(that.element).off(eventNamespace);
that.element = null;
}
$(that.options.rootElement).off(KEY_DOWN + eventNamespace);
that._destroyResizeHandle();
},
options: {
tags: [],
min: 0,
rootElement: null,
eventNamespace: "",
rtl: false,
handle: {
dataAttribute: "",
height: 0,
width: 0,
classNames: {},
template: ""
}
},
_attachEventHandlers: function() {
var that = this;
var options = that.options;
$(that.element).on(MOUSE_MOVE + options.eventNamespace, options.tags.join(COMMA), that.detectElementBorderHovering.bind(that));
},
resizingInProgress: function() {
var resizable = this._resizable;
if (resizable) return !!resizable.resizing;
return false;
},
resize: noop,
detectElementBorderHovering: function(e) {
var that = this;
var handleOptions = that.options.handle;
var tableElement = $(e.currentTarget);
var resizeHandle = that.resizeHandle;
var dataAttribute = handleOptions.dataAttribute;
if (!that.resizingInProgress()) {
if (!tableElement.is(LAST_CHILD) && that.elementBorderHovered(tableElement, e)) if (resizeHandle) {
if (resizeHandle.data(dataAttribute) && resizeHandle.data(dataAttribute) !== tableElement[0]) that.showResizeHandle(tableElement, e);
} else that.showResizeHandle(tableElement, e);
else if (resizeHandle) that._destroyResizeHandle();
}
},
elementBorderHovered: noop,
showResizeHandle: function(tableElement, e) {
var that = this;
if (e.buttons !== 0) return;
that._initResizeHandle();
that.setResizeHandlePosition(tableElement);
that.setResizeHandleDimensions();
that.setResizeHandleDataAttributes(tableElement[0]);
that._attachResizeHandleEventHandlers();
that._initResizable(tableElement);
that._hideResizeMarker();
that.resizeHandle.show();
},
_initResizeHandle: function() {
var that = this;
var options = that.options;
that._destroyResizeHandle();
that.resizeHandle = $(options.handle.template).appendTo(options.rootElement);
},
setResizeHandlePosition: noop,
setResizeHandleDimensions: noop,
setResizeHandleDataAttributes: function(tableElement) {
var that = this;
that.resizeHandle.data(that.options.handle.dataAttribute, tableElement);
},
_attachResizeHandleEventHandlers: function() {
var that = this;
var options = that.options;
var eventNamespace = options.eventNamespace;
var markerClass = options.handle.classNames.marker;
var resizeHandle = that.resizeHandle;
that.resizeHandle.on(MOUSE_DOWN + eventNamespace, function() {
resizeHandle.find(DOT + markerClass).show();
}).on(MOUSE_UP + eventNamespace, function() {
resizeHandle.find(DOT + markerClass).hide();
});
},
_hideResizeMarker: function() {
var that = this;
that.resizeHandle.find(DOT + that.options.handle.classNames.marker).hide();
},
_destroyResizeHandle: function() {
var that = this;
if (that.resizeHandle) {
that._destroyResizable();
that.resizeHandle.off(that.options.eventNamespace).remove();
that.resizeHandle = null;
}
},
_initResizable: function(tableElement) {
var that = this;
if (!that.resizeHandle) return;
that._destroyResizable();
that._resizable = new kendo.ui.Resizable(tableElement, {
draggableElement: that.resizeHandle[0],
start: that.onResizeStart.bind(that),
resize: that.onResize.bind(that),
resizeend: that.onResizeEnd.bind(that)
});
},
_destroyResizable: function() {
var that = this;
if (that._resizable) {
that._resizable.destroy();
that._resizable = null;
}
},
onResizeStart: function() {
this._disableKeyboard();
},
onResize: function(e) {
this.setResizeHandleDragPosition(e);
},
setResizeHandleDragPosition: noop,
onResizeEnd: function(e) {
var that = this;
that.resize(e);
that._destroyResizeHandle();
that._enableKeyboard();
if (this.options.editor) this.options.editor._handleSpaceAndNewLines();
},
_enableKeyboard: function() {
var options = this.options;
$(options.rootElement).off(KEY_DOWN + options.eventNamespace);
},
_disableKeyboard: function() {
var options = this.options;
$(options.rootElement).on(KEY_DOWN + options.eventNamespace, function(e) {
e.preventDefault();
});
},
_forceResizing: function(e) {
var resizable = this._resizable;
if (resizable && resizable.userEvents) resizable.userEvents._end(e);
}
});
var ResizingFactory = Class.extend({
create: function(editor, options) {
var that = this;
var resizingName = options.name;
var NS = options.eventNamespace;
$(editor.body).on(MOUSE_ENTER + NS, TABLE, function(e) {
var table = e.currentTarget;
var resizing = editor[resizingName];
e.stopPropagation();
if (resizing) {
if (resizing.element !== table && !resizing.resizingInProgress()) {
that._destroyResizing(editor, options);
that._initResizing(editor, table, options);
}
} else that._initResizing(editor, table, options);
}).on(MOUSE_LEAVE + NS, TABLE, function(e) {
var parentTable;
var resizing = editor[resizingName];
e.stopPropagation();
if (resizing && !resizing.resizingInProgress() && !resizing.resizeHandle) {
parentTable = $(resizing.element).parents(TABLE)[0];
if (parentTable) {
that._destroyResizing(editor, options);
that._initResizing(editor, parentTable, options);
}
}
}).on(MOUSE_LEAVE + NS, function() {
var resizing = editor[resizingName];
if (resizing && !resizing.resizingInProgress()) that._destroyResizing(editor, options);
}).on(MOUSE_UP + NS, function(e) {
var resizing = editor[resizingName];
var parentTable;
if (resizing && resizing.resizingInProgress()) {
parentTable = $(e.target).parents(TABLE)[0];
if (parentTable) {
resizing._forceResizing(e);
that._destroyResizing(editor, options);
that._initResizing(editor, parentTable, options);
}
}
});
},
dispose: function(editor, options) {
$(editor.body).off(options.eventNamespace);
},
_initResizing: function(editor, tableElement, options) {
var resizingName = options.name;
var resizingType = options.type;
editor[resizingName] = new resizingType(tableElement, {
rtl: kendo.support.isRtl(editor.element),
rootElement: editor.body,
editor
});
},
_destroyResizing: function(editor, options) {
var resizingName = options.name;
if (editor[resizingName]) {
editor[resizingName].destroy();
editor[resizingName] = null;
}
}
});
ResizingFactory.current = new ResizingFactory();
TableElementResizing.create = function(editor, options) {
ResizingFactory.current.create(editor, options);
};
TableElementResizing.dispose = function(editor, options) {
ResizingFactory.current.dispose(editor, options);
};
extend(Editor, { TableElementResizing });
})(window.kendo);
//#endregion
//#region ../src/editor/resizing/column-resizing.js
(function(kendo, undefined) {
var abs = window.Math.abs;
var $ = kendo.jQuery;
var extend = $.extend;
var Editor = kendo.ui.editor;
var dom = Editor.Dom;
var TableElementResizing = Editor.TableElementResizing;
var ResizingUtils = Editor.ResizingUtils;
var constrain = ResizingUtils.constrain;
var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
var getScrollBarWidth = ResizingUtils.getScrollBarWidth;
var inPercentages = ResizingUtils.inPercentages;
var toPercentages = ResizingUtils.toPercentages;
var toPixels = ResizingUtils.toPixels;
var outerWidth = kendo._outerWidth;
var NS = ".kendoEditorColumnResizing";
var RESIZE_HANDLE_CLASS = "k-column-resize-handle";
var RESIZE_MARKER_CLASS = "k-column-resize-marker";
var BODY = "body";
var TBODY = "tbody";
var THEAD = "thead";
var TD = "td";
var TH = "th";
var TR = "tr";
var COLATTR = "col-index";
var COMMA = ",";
var WIDTH = "width";
var ColumnResizing = TableElementResizing.extend({
options: {
tags: [TD, TH],
min: 20,
rootElement: null,
eventNamespace: NS,
rtl: false,
handle: {
dataAttribute: "column",
width: 10,
height: 0,
classNames: {
handle: RESIZE_HANDLE_CLASS,
marker: RESIZE_MARKER_CLASS
},
template: "<div class=\"k-column-resize-handle-wrapper\" unselectable=\"on\" contenteditable=\"false\"><div class=\"" + RESIZE_HANDLE_CLASS + "\"><div class=\"" + RESIZE_MARKER_CLASS + "\"></div></div></div>"
}
},
elementBorderHovered: function(column, e) {
var options = this.options;
var handleWidth = options.handle.width;
var borderOffset = column.offset().left + (options.rtl ? 0 : outerWidth(column));
var mousePosition = e.clientX + $(column[0].ownerDocument).scrollLeft();
if (mousePosition > borderOffset - handleWidth && mousePosition < borderOffset + handleWidth) return true;
else return false;
},
setResizeHandlePosition: function(column) {
var that = this;
var tableInnerElement = $(that.element.tHead || that.element.tBodies[0]);
var options = that.options;
var rtl = options.rtl;
var handleWidth = options.handle.width;
var rootElement = $(options.rootElement);
var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
var scrollLeftOffset = rootElement.is(BODY) ? 0 : kendo.scrollLeft(rootElement);
var columnWidthOffset = rtl ? 0 : outerWidth(column);
var scrollBarWidth = rtl ? getScrollBarWidth(rootElement[0]) : 0;
var columnOffsetLeft = column.offset().left - (rootElement.offset().left + parseFloat(rootElement.css("borderLeftWidth"))) - parseFloat(column.css("marginLeft"));
var innerElementOffsetTop = tableInnerElement.offset().top - (rootElement.offset().top + parseFloat(rootElement.css("borderTopWidth"))) - parseFloat(tableInnerElement.css("marginTop"));
var browser = kendo.support.browser;
if (rtl && (browser.mozilla || browser.webkit && browser.version >= 85)) scrollLeftOffset = scrollLeftOffset * -1;
that.resizeHandle.css({
top: innerElementOffsetTop + scrollTopOffset,
left: columnOffsetLeft + columnWidthOffset + (scrollLeftOffset - scrollBarWidth) - handleWidth / 2,
position: "absolute"
});
},
setResizeHandleDimensions: function() {
var that = this;
var tableHead = $(that.element).children(THEAD);
var tableBody = $(that.element).children(TBODY);
var fullHeight = tableHead.length > 0 ? tableHead.height() + tableBody.height() : tableBody.height();
that.resizeHandle.css({
width: that.options.handle.width,
height: fullHeight
});
},
setResizeHandleDragPosition: function(e) {
var that = this;
var column = $($(e.currentTarget).data(that.options.handle.dataAttribute));
var options = that.options;
var rootElement = $(options.rootElement);
var handleWidth = options.handle ? options.handle.width : 0;
var min = options.min;
var rtl = options.rtl;
var columnWidth = outerWidth(column);
var columnLeftOffset = column.offset().left - (rootElement.offset().left + parseFloat(rootElement.css("borderLeftWidth"))) - parseFloat(column.css("marginLeft"));
var adjacentColumnWidth = outerWidth(column.next());
var resizeHandle = $(that.resizeHandle);
var scrollLeftOffset = rootElement.is(BODY) ? 0 : kendo.scrollLeft(rootElement);
var scrollBarWidth = rtl ? getScrollBarWidth(rootElement[0]) : 0;
var resizeHandleOffsetLeft = resizeHandle.offset().left - (rootElement.offset().left + parseFloat(rootElement.css("borderLeftWidth"))) - parseFloat(resizeHandle.css("marginLeft"));
var browser = kendo.support.browser;
if (rtl && (browser.mozilla || browser.webkit && browser.version >= 85)) scrollLeftOffset = scrollLeftOffset * -1;
var handleOffset = constrain({
value: resizeHandleOffsetLeft + (scrollLeftOffset - scrollBarWidth) + e.x.delta,
min: columnLeftOffset + (scrollLeftOffset - scrollBarWidth) - (rtl ? adjacentColumnWidth : 0) + min,
max: columnLeftOffset + columnWidth + (scrollLeftOffset - scrollBarWidth) + (rtl ? 0 : adjacentColumnWidth) - handleWidth - min
});
resizeHandle.css({ left: handleOffset });
},
resize: function(e) {
var that = this;
var column = $($(e.currentTarget).data(that.options.handle.dataAttribute));
var options = that.options;
var rtlModifier = options.rtl ? -1 : 1;
var min = options.min;
var initialDeltaX = rtlModifier * e.x.initialDelta;
var newWidth;
var initialAdjacentColumnWidth;
var initialColumnWidth;
var colIndex;
var nextColumn;
dom.reMapTableColumns(that.element, COLATTR);
colIndex = parseInt(column.attr(COLATTR), 10);
if (column.prop("colSpan") > 1) {
column = $(that.element).find("[" + COLATTR + "=" + (colIndex + column.prop("colSpan") - 1) + "]").eq(0);
colIndex = parseInt(column.attr(COLATTR), 10);
}
nextColumn = $(that.element).find("[" + COLATTR + "=" + (colIndex + 1) + "]:not([colspan])");
that._setTableComputedWidth();
that._setColumnsComputedWidth();
initialColumnWidth = outerWidth(column);
initialAdjacentColumnWidth = outerWidth(nextColumn);
newWidth = constrain({
value: initialColumnWidth + initialDeltaX,
min,
max: initialColumnWidth + initialAdjacentColumnWidth - min
});
that._resizeColumn(column[0], newWidth);
that._resizeTopAndBottomColumns(column[0], newWidth);
that._resizeAdjacentColumns(parseInt(column.attr(COLATTR), 10), initialAdjacentColumnWidth, initialColumnWidth, initialColumnWidth - newWidth);
dom.clearTableMappings(that.element, COLATTR);
},
_setTableComputedWidth: function() {
var element = this.element;
if (element.style[WIDTH] === "") element.style[WIDTH] = toPixels(outerWidth($(element)));
},
_setColumnsComputedWidth: function() {
var that = this;
var tableInnerElement = $(that.element.tHead || that.element.tBodies[0]);
var innerElementWidth = outerWidth(tableInnerElement);
var columns = tableInnerElement.children(TR).children(TD);
var length = columns.length;
var currentColumnsWidths = columns.map(function() {
return outerWidth($(this));
});
var i;
for (i = 0; i < length; i++) if (inPercentages(columns[i].style[WIDTH])) columns[i].style[WIDTH] = toPercentages(calculatePercentageRatio(currentColumnsWidths[i], innerElementWidth));
else columns[i].style[WIDTH] = toPixels(currentColumnsWidths[i]);
},
_resizeTopAndBottomColumns: function(column, newWidth) {
var that = this;
var columnIndex = $(column).attr(COLATTR);
var topAndBottomColumns = $(that.element).children(TBODY + COMMA + THEAD).children(TR).children(that.options.tags.join(COMMA)).filter(function() {
var cell = this;
return $(cell).attr(COLATTR) === columnIndex && cell !== column;
});
var length = topAndBottomColumns.length;
var i;
for (i = 0; i < length; i++) that._resizeColumn(topAndBottomColumns[i], newWidth);
},
_resizeColumn: function(column, newWidth) {
var innerTableElement = $(this.element.tHead || this.element.tBodies[0]);
if (inPercentages(column.style[WIDTH])) column.style[WIDTH] = toPercentages(calculatePercentageRatio(newWidth, outerWidth(innerTableElement)));
else column.style[WIDTH] = toPixels(newWidth);
},
_resizeAdjacentColumns: function(columnIndex, initialAdjacentColumnWidth, initialColumnWidth, deltaWidth) {
var that = this;
var adjacentColumns = $(that.element).children(TBODY + COMMA + THEAD).children(TR).children(that.options.tags.join(COMMA)).filter(function() {
return parseInt($(this).attr(COLATTR), 10) === columnIndex + 1;
});
var length = adjacentColumns.length;
var i;
for (i = 0; i < length; i++) that._resizeAdjacentColumn(adjacentColumns[i], initialAdjacentColumnWidth, initialColumnWidth, deltaWidth);
},
_resizeAdjacentColumn: function(adjacentColumn, initialAdjacentColumnWidth, initialColumnWidth, deltaWidth) {
var that = this;
var min = that.options.min;
var newWidth = constrain({
value: initialAdjacentColumnWidth + deltaWidth,
min,
max: abs(initialColumnWidth + initialAdjacentColumnWidth - min)
});
that._resizeColumn(adjacentColumn, newWidth);
}
});
ColumnResizing.create = function(editor) {
TableElementResizing.create(editor, {
name: "columnResizing",
type: ColumnResizing,
eventNamespace: NS
});
};
ColumnResizing.dispose = function(editor) {
TableElementResizing.dispose(editor, { eventNamespace: NS });
};
extend(Editor, { ColumnResizing });
})(window.kendo);
//#endregion
//#region ../src/editor/resizing/row-resizing.js
(function(kendo, undefined) {
var abs = window.Math.abs;
var $ = kendo.jQuery;
var extend = $.extend;
var Editor = kendo.ui.editor;
var TableElementResizing = Editor.TableElementResizing;
var ResizingUtils = Editor.ResizingUtils;
var getScrollBarWidth = ResizingUtils.getScrollBarWidth;
var constrain = ResizingUtils.constrain;
var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
var inPercentages = ResizingUtils.inPercentages;
var toPercentages = ResizingUtils.toPercentages;
var toPixels = ResizingUtils.toPixels;
var outerHeight = kendo._outerHeight;
var NS = ".kendoEditorRowResizing";
var RESIZE_HANDLE_CLASS = "k-row-resize-handle";
var RESIZE_HANDLE_MARKER_WRAPPER_CLASS = "k-row-resize-marker-wrapper";
var RESIZE_MARKER_CLASS = "k-row-resize-marker";
var BODY = "body";
var TR = "tr";
var TBODY = "tbody";
var THEAD = "thead";
var COMMA = ",";
var HEIGHT = "height";
var RowResizing = TableElementResizing.extend({
options: {
tags: [TR],
min: 20,
rootElement: null,
eventNamespace: NS,
rtl: false,
handle: {
dataAttribute: "row",
width: 0,
height: 10,
classNames: {
handle: RESIZE_HANDLE_CLASS,
marker: RESIZE_MARKER_CLASS
},
template: "<div class=\"k-row-resize-handle-wrapper\" unselectable=\"on\" contenteditable=\"false\"><div class=\"" + RESIZE_HANDLE_CLASS + "\"><div class=\"" + RESIZE_HANDLE_MARKER_WRAPPER_CLASS + "\"><div class=\"" + RESIZE_MARKER_CLASS + "\"></div></div></div></div>"
}
},
elementBorderHovered: function(tableElement, e) {
var handleHeight = this.options.handle[HEIGHT];
var borderOffset = tableElement.offset().top + outerHeight(tableElement);
var mousePosition = e.clientY + $(tableElement[0].ownerDocument).scrollTop();
if (mousePosition > borderOffset - handleHeight && mousePosition < borderOffset + handleHeight) return true;
else return false;
},
setResizeHandlePosition: function(row) {
var that = this;
var options = that.options;
var handleHeight = options.handle[HEIGHT];
var rootElement = $(options.rootElement);
var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
var scrollLeftOffset = rootElement.is(BODY) ? 0 : kendo.scrollLeft(rootElement);
var scrollBarWidth = options.rtl ? getScrollBarWidth(rootElement[0]) : 0;
var rowOffsetLeft = row.offset().left - (rootElement.offset().left + parseFloat(rootElement.css("borderLeftWidth"))) - parseFloat(row.css("marginLeft"));
var rowOffsetTop = row.offset().top - (rootElement.offset().top + parseFloat(rootElement.css("borderTopWidth"))) - parseFloat(row.css("marginTop"));
var browser = kendo.support.browser;
if (options.rtl && (browser.mozilla || browser.webkit && browser.version >= 85)) scrollLeftOffset = scrollLeftOffset * -1;
that.resizeHandle.css({
top: rowOffsetTop + outerHeight(row) + scrollTopOffset - handleHeight / 2,
left: rowOffsetLeft + (scrollLeftOffset - scrollBarWidth),
position: "absolute"
});
},
setResizeHandleDimensions: function() {
var that = this;
var innerTableElement = $(that.element.tHead || that.element.tBodies[0]);
that.resizeHandle.css({
width: innerTableElement.width(),
height: that.options.handle[HEIGHT]
});
},
setResizeHandleDragPosition: function(e) {
var that = this;
var options = that.options;
var min = options.min;
var tableHead = $(that.element).children(THEAD);
var tableBody = $(that.element).children(TBODY);
var topInnerTableElement = tableHead.length > 0 ? tableHead : tableBody;
var resizeHandle = $(that.resizeHandle);
var $row = $($(e.currentTarget).data(options.handle.dataAttribute));
var rootElement = $(options.rootElement);
var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
var tableTopOffset = topInnerTableElement.offset().top - (rootElement.offset().top + parseFloat(rootElement.css("borderTopWidth"))) - parseFloat(topInnerTableElement.css("marginTop"));
var rowOffsetTop = $row.offset().top - (rootElement.offset().top + parseFloat(rootElement.css("borderTopWidth"))) - parseFloat($row.css("marginTop"));
var handleOffset = constrain({
value: resizeHandle.offset().top - (Math.max(0, rootElement.offset().top) + parseFloat(rootElement.css("borderTopWidth"))) - parseFloat(resizeHandle.css("marginTop")) + scrollTopOffset + e.y.delta,
min: rowOffsetTop + scrollTopOffset + min,
max: tableTopOffset + outerHeight(tableHead) + outerHeight(tableBody) + scrollTopOffset - options.handle[HEIGHT] - min
});
resizeHandle.css({ top: handleOffset });
},
resize: function(e) {
var that = this;
var options = that.options;
var row = $(e.currentTarget).data(options.handle.dataAttribute);
var currentRowHeight = outerHeight($(row));
var element = $(that.element);
var initialTableHeight = outerHeight(element);
var tableHead = element.children(THEAD);
var tableHeadHeight = tableHead.length > 0 ? tableHead.height() : 0;
var tableBodyHeight = element.children(TBODY).height();
var initialStyleHeight = row.style[HEIGHT];
var newRowHeight = constrain({
value: currentRowHeight + e.y.initialDelta,
min: options.min,
max: abs(tableHeadHeight + tableBodyHeight - options.min)
});
that._setRowsHeightInPixels();
row.style[HEIGHT] = toPixels(newRowHeight);
that._setTableHeight(initialTableHeight + (newRowHeight - currentRowHeight));
if (inPercentages(initialStyleHeight)) that._setRowsHeightInPercentages();
},
_setRowsHeightInPixels: function() {
var rows = $(this.element).children(TBODY + COMMA + THEAD).children(TR);
var length = rows.length;
var currentRowsHeights = rows.map(function() {
return outerHeight($(this));
});
var i;
for (i = 0; i < length; i++) rows[i].style[HEIGHT] = toPixels(currentRowsHeights[i]);
},
_setRowsHeightInPercentages: function() {
var that = this;
var tableHead = $(that.element).children(THEAD);
var tableHeadHeight = tableHead.length > 0 ? tableHead.height() : 0;
var tableBodyHeight = $(that.element).children(TBODY).height();
var rows = $(that.element).children(THEAD + COMMA + TBODY).children(TR);
var length = rows.length;
var currentRowsHeights = rows.map(function() {
return outerHeight($(this));
});
var i;
for (i = 0; i < length; i++) rows[i].style[HEIGHT] = toPercentages(calculatePercentageRatio(currentRowsHeights[i], tableHeadHeight + tableBodyHeight));
},
_setTableHeight: function(newHeight) {
var element = this.element;
if (inPercentages(element.style[HEIGHT])) element.style[HEIGHT] = toPercentages(calculatePercentageRatio(newHeight, $(element).parent().height()));
else element.style[HEIGHT] = toPixels(newHeight);
}
});
RowResizing.create = function(editor) {
TableElementResizing.create(editor, {
name: "rowResizing",
type: RowResizing,
eventNamespace: NS
});
};
RowResizing.dispose = function(editor) {
TableElementResizing.dispose(editor, { eventNamespace: NS });
};
extend(Editor, { RowResizing });
})(window.kendo);
//#endregion
//#region ../src/editor/resizing/element-resize-handle.js
(function(kendo, undefined) {
var $ = kendo.jQuery;
var extend = $.extend;
var noop = $.noop;
var Editor = kendo.ui.editor;
var Class = kendo.Class;
var Draggable = kendo.ui.Draggable;
var Observable = kendo.Observable;
var getScrollBarWidth = Editor.ResizingUtils.getScrollBarWidth;
var outerWidth = kendo._outerWidth;
var outerHeight = kendo._outerHeight;
var NS = ".kendoEditorElementResizeHandle";
var RESIZE_HANDLE_CLASS = "k-element-resize-handle";
var DRAG_START = "dragStart";
var DRAG = "drag";
var DRAG_END = "dragEnd";
var HALF_INSIDE = "halfInside";
var MOUSE_OVER = "mouseover";
var MOUSE_OUT = "mouseout";
var BODY = "body";
var TABLE = "table";
var EAST = "east";
var NORTH = "north";
var NORTHEAST = "northeast";
var NORTHWEST = "northwest";
var SOUTH = "south";
var SOUTHEAST = "southeast";
var SOUTHWEST = "southwest";
var WEST = "west";
var DOT = ".";
var ElementResizeHandle = Observable.extend({
init: function(options) {
var that = this;
Observable.fn.init.call(that);
that.options = extend({}, that.options, options);
that.element = $(that.options.template).appendTo(that.options.appendTo)[0];
that._attachEventHandlers();
that._addStyles();
that._initDraggable();
that._initPositioningStrategy();
that._initDraggingStrategy();
$(that.element).data(TABLE, that.options.resizableElement);
},
destroy: function() {
var that = this;
$(that.element).off(NS).remove();
that.element = null;
that._destroyDraggable();
that.unbind();
},
options: {
appendTo: null,
direction: SOUTHEAST,
resizableElement: null,
rtl: false,
template: "<div class='k-element-resize-handle-wrapper' unselectable='on' contenteditable='false'><div class='" + RESIZE_HANDLE_CLASS + "'></div></div>"
},
events: [
DRAG_START,
DRAG,
DRAG_END,
MOUSE_OVER,
MOUSE_OUT
],
show: function() {
this._setPosition();
},
_setPosition: function() {
var that = this;
var position = that._positioningStrategy.getPosition();
$(that.element).css({
top: position.top,
left: position.left,
position: "absolute"
});
},
_attachEventHandlers: function() {
var that = this;
$(that.element).on(MOUSE_OVER + NS, that._onMouseOver.bind(that)).on(MOUSE_OUT + NS, that._onMouseOut.bind(that));
},
_onMouseOver: function() {
this.trigger(MOUSE_OVER);
},
_onMouseOut: function() {
this.trigger(MOUSE_OUT);
},
_addStyles: function() {
var that = this;
$(that.element).children(DOT + RESIZE_HANDLE_CLASS).addClass("k-resize-" + that.options.direction);
},
_initPositioningStrategy: function() {
var that = this;
var options = that.options;
that._positioningStrategy = HandlePositioningStrategy.create({
name: options.direction,
handle: that.element,
resizableElement: options.resizableElement,
rootElement: options.rootElement,
rtl: options.rtl
});
},
_initDraggable: function() {
var that = this;
var element = that.element;
if (that._draggable || !element) return;
that._draggable = new Draggable(element, {
dragstart: that._onDragStart.bind(that),
drag: that._onDrag.bind(that),
dragend: that._onDragEnd.bind(that)
});
},
_onDragStart: function() {
this.trigger(DRAG_START);
},
_onDrag: function(e) {
var that = this;
that.trigger(DRAG, that._draggingStrategy.adjustDragDelta({
deltaX: e.x.delta,
deltaY: e.y.delta,
initialDeltaX: e.x.initialDelta,
initialDeltaY: e.y.initialDelta
}));
if (that.options.editor) that.options.editor._handleSpaceAndNewLines();
},
_onDragEnd: function() {
this.trigger(DRAG_END);
},
_destroyDraggable: function() {
var that = this;
if (that._draggable) {
that._draggable.destroy();
that._draggable = null;
}
},
_initDraggingStrategy: function() {
var that = this;
that._draggingStrategy = HandleDraggingStrategy.create({ name: that.options.direction });
}
});
var StrategyFactory = Class.extend({
init: function() {
this._items = [];
},
register: function(name, type) {
this._items.push({
name,
type
});
},
create: function(options) {
var items = this._items;
var itemsLength = items.length;
var name = options.name ? options.name.toLowerCase() : "";
var match;
var item;
var i;
for (i = 0; i < itemsLength; i++) {
item = items[i];
if (item.name.toLowerCase() === name) {
match = item;
break;
}
}
if (match) return new match.type(options);
}
});
var PositioningStrategyFactory = StrategyFactory.extend({});
PositioningStrategyFactory.current = new PositioningStrategyFactory();
var HandlePositioningStrategy = Class.extend({
init: function(options) {
var that = this;
that.options = extend({}, that.options, options);
},
options: {
handle: null,
offset: HALF_INSIDE,
resizableElement: null,
rootElement: null,
rtl: false
},
getPosition: function() {
var that = this;
var position = that.calculatePosition();
var handleOffsetPosition = that.applyHandleOffset(position);
return that.applyScrollOffset(handleOffsetPosition);
},
calculatePosition: noop,
applyHandleOffset: function(position) {
var options = this.options;
var handle = $(options.handle);
if (options.offset === HALF_INSIDE) return {
top: position.top - outerHeight(handle) / 2,
left: position.left - outerWidth(handle) / 2
};
return position;
},
applyScrollOffset: function(position) {
var options = this.options;
var rootElement = $(options.rootElement);
var scrollBarWidth = options.rtl ? getScrollBarWidth(rootElement[0]) : 0;
var browser = kendo.support.browser;
var rootLeft;
if (!rootElement.is(BODY)) {
rootLeft = kendo.scrollLeft(rootElement) || 0;
if (options.rtl && (browser.mozilla || browser.webkit && browser.version >= 85)) rootLeft = rootLeft * -1;
return {
top: position.top + (rootElement.scrollTop() || 0),
left: position.left + rootLeft - scrollBarWidth
};
}
return position;
}
});
HandlePositioningStrategy.create = function(options) {
return PositioningStrategyFactory.current.create(options);
};
var EastPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top + outerHeight(resizableElement) / 2,
left: offset.left + outerWidth(resizableElement) + marginLeft
};
} });
PositioningStrategyFactory.current.register(EAST, EastPositioningStrategy);
var NorthPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top,
left: offset.left + outerWidth(resizableElement) / 2 + marginLeft
};
} });
PositioningStrategyFactory.current.register(NORTH, NorthPositioningStrategy);
var NortheastPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top,
left: offset.left + outerWidth(resizableElement) + marginLeft
};
} });
PositioningStrategyFactory.current.register(NORTHEAST, NortheastPositioningStrategy);
var NorthwestPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top,
left: offset.left + marginLeft
};
} });
PositioningStrategyFactory.current.register(NORTHWEST, NorthwestPositioningStrategy);
var SouthPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top + outerHeight(resizableElement),
left: offset.left + outerWidth(resizableElement) / 2 + marginLeft
};
} });
PositioningStrategyFactory.current.register(SOUTH, SouthPositioningStrategy);
var SoutheastPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top + outerHeight(resizableElement),
left: offset.left + outerWidth(resizableElement) + marginLeft
};
} });
PositioningStrategyFactory.current.register(SOUTHEAST, SoutheastPositioningStrategy);
var SouthwestPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top + outerHeight(resizableElement),
left: offset.left + marginLeft
};
} });
PositioningStrategyFactory.current.register(SOUTHWEST, SouthwestPositioningStrategy);
var WestPositioningStrategy = HandlePositioningStrategy.extend({ calculatePosition: function() {
var resizableElement = $(this.options.resizableElement);
var offset = resizableElement.position();
var marginLeft = parseInt(resizableElement.css("marginLeft"), 10);
return {
top: offset.top + outerHeight(resizableElement) / 2,
left: offset.left + marginLeft
};
} });
PositioningStrategyFactory.current.register(WEST, WestPositioningStrategy);
var DraggingStrategyFactory = StrategyFactory.extend({});
DraggingStrategyFactory.current = new DraggingStrategyFactory();
var HandleDraggingStrategy = Class.extend({
init: function(options) {
var that = this;
that.options = extend({}, that.options, options);
},
options: {
deltaX: {
adjustment: null,
modifier: null
},
deltaY: {
adjustment: null,
modifier: null
}
},
adjustDragDelta: function(deltas) {
var options = this.options;
var xAxisAdjustment = options.deltaX.adjustment * options.deltaX.modifier;
var yAxisAdjustment = options.deltaY.adjustment * options.deltaY.modifier;
return {
deltaX: deltas.deltaX * xAxisAdjustment,
deltaY: deltas.deltaY * yAxisAdjustment,
initialDeltaX: deltas.initialDeltaX * xAxisAdjustment,
initialDeltaY: deltas.initialDeltaY * yAxisAdjustment
};
}
});
HandleDraggingStrategy.create = function(options) {
return DraggingStrategyFactory.current.create(options);
};
var HorizontalDraggingStrategy = HandleDraggingStrategy.extend({ options: {
deltaX: {
adjustment: 1,
modifier: 1
},
deltaY: {
adjustment: 0,
modifier: 0
}
} });
var EastDraggingStrategy = HorizontalDraggingStrategy.extend({ options: { deltaX: { modifier: 1 } } });
DraggingStrategyFactory.current.register(EAST, EastDraggingStrategy);
var WestDraggingStrategy = HorizontalDraggingStrategy.extend({ options: { deltaX: { modifier: -1 } } });
DraggingStrategyFactory.current.register(WEST, WestDraggingStrategy);
var VerticalDraggingStrategy = HandleDraggingStrategy.extend({ options: {
deltaX: {
adjustment: 0,
modifier: 0
},
deltaY: {
adjustment: 1,
modifier: 1
}
} });
var NorthDraggingStrategy = VerticalDraggingStrategy.extend({ options: { deltaY: { modifier: -1 } } });
DraggingStrategyFactory.current.register(NORTH, NorthDraggingStrategy);
var SouthDraggingStrategy = VerticalDraggingStrategy.extend({ options: { deltaY: { modifier: 1 } } });
DraggingStrategyFactory.current.register(SOUTH, SouthDraggingStrategy);
var HorizontalAndVerticalDraggingStrategy = HandleDraggingStrategy.extend({ options: {
deltaX: {
adjustment: 1,
modifier: 1
},
deltaY: {
adjustment: 1,
modifier: 1
}
} });
var NorthEastDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({ options: {
deltaX: { modifier: 1 },
deltaY: { modifier: -1 }
} });
DraggingStrategyFactory.current.register(NORTHEAST, NorthEastDraggingStrategy);
var NorthWestDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({ options: {
deltaX: { modifier: -1 },
deltaY: { modifier: -1 }
} });
DraggingStrategyFactory.current.register(NORTHWEST, NorthWestDraggingStrategy);
var SouthEastDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({ options: {
deltaX: { modifier: 1 },
deltaY: { modifier: 1 }
} });
DraggingStrategyFactory.current.register(SOUTHEAST, SouthEastDraggingStrategy);
var SouthWestDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({ options: {
deltaX: { modifier: -1 },
deltaY: { modifier: 1 }
} });
DraggingStrategyFactory.current.register(SOUTHWEST, SouthWestDraggingStrategy);
extend(Editor, { ElementResizeHandle });
})(window.kendo);
//#endregion
//#region ../src/editor/resizing/element-resizing.js
(function(kendo, undefined) {
var math = window.Math;
var min = math.min;
var max = math.max;
var $ = kendo.jQuery;
var contains = $.contains;
var extend = $.extend;
var browser = kendo.support.browser;
var Editor = kendo.ui.editor;
var Class = kendo.Class;
var ElementResizeHandle = Editor.ElementResizeHandle;
var ResizingUtils = Editor.ResizingUtils;
var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
var constrain = ResizingUtils.constrain;
var inPercentages = ResizingUtils.inPercentages;
var inPixels = ResizingUtils.inPixels;
var toPercentages = ResizingUtils.toPercentages;
var toPixels = ResizingUtils.toPixels;
var outerWidth = kendo._outerWidth;
var outerHeight = kendo._outerHeight;
var RangeUtils = Editor.RangeUtils;
var NS = ".kendoEditorElementResizing";
var RESIZE_HANDLE_WRAPPER_CLASS = "k-element-resize-handle-wrapper";
var TABLE_CLASS = "k-table";
var ELEMENT_RESIZING_CLASS = "k-element-resizing";
var DRAG_START = "dragStart";
var DRAG = "drag";
var DRAG_END = "dragEnd";
var KEY_DOWN = "keydown";
var MOUSE_DOWN = "mousedown";
var SELECT = "select";
var DROP = "drop";
var COLUMN = "td";
var ROW = "tr";
var TBODY = "tbody";
var THEAD = "thead";
var TABLE = "table";
var IMG = "img";
var ELEMENT_TYPES = ["TABLE", "IMG"];
var COMMA = ",";
var WIDTH = "width";
var HEIGHT = "height";
var EAST = "east";
var NORTH = "north";
var NORTHEAST = "northeast";
var NORTHWEST = "northwest";
var SOUTH = "south";
var SOUTHEAST = "southeast";
var SOUTHWEST = "southwest";
var WEST = "west";
var DOT = ".";
function isUndefined(value) {
return typeof value === "undefined";
}
var ElementResizing = Class.extend({
init: function(element, options) {
var that = this;
that.options = extend({}, that.options, options);
that.handles = [];
if (ELEMENT_TYPES.indexOf(element.nodeName) >= 0) that.element = element;
},
destroy: function() {
var that = this;
$(that.element).off(NS);
that.element = null;
$(that.options.rootElement).off(KEY_DOWN + NS);
that._destroyResizeHandles();
},
options: {
appendHandlesTo: null,
rtl: false,
rootElement: null,
minWidth: 10,
minHeight: 10,
handles: [
{ direction: NORTHWEST },
{ direction: NORTH },
{ direction: NORTHEAST },
{ direction: EAST },
{ direction: SOUTHEAST },
{ direction: SOUTH },
{ direction: SOUTHWEST },
{ direction: WEST }
]
},
resize: function(args) {
var that = this;
var deltas = extend({}, {
deltaX: 0,
deltaY: 0,
initialDeltaX: 0,
initialDeltaY: 0
}, args);
that._resizeWidth(deltas.deltaX, deltas.initialDeltaX);
that._resizeHeight(deltas.deltaY, deltas.initialDeltaY);
that.showResizeHandles();
},
_resizeWidth: function() {
return false;
},
_resizeHeight: function() {
return false;
},
_getMaxDimensionValue: function(dimension) {
var that = this;
var element = $(that.element);
var dimensionLowercase = dimension.toLowerCase();
var rtlModifier = that.options.rtl ? -1 : 1;
var parent = $(that.element).parent();
var parentElement = parent[0];
var parentDimension = parent[dimensionLowercase]();
var parentScrollOffset = rtlModifier * (dimension === WIDTH ? kendo.scrollLeft(parent) : parent.scrollTop());
if (parentElement && parentElement === element.closest(COLUMN)[0]) if (parentElement.style[dimensionLowercase] === "" && !inPercentages(that.element.style[dimensionLowercase])) return Infinity;
else return parentDimension + parentScrollOffset;
else return parentDimension + parentScrollOffset;
},
showResizeHandles: function() {
var that = this;
that._initResizeHandles();
that._showResizeHandles();
},
_initResizeHandles: function() {
var that = this;
var handles = that.handles;
var options = that.options;
var handleOptions = that.options.handles;
var length = handleOptions.length;
var i;
if (handles && handles.length > 0) return;
for (i = 0; i < length; i++) that.handles.push(new ElementResizeHandle(extend({
appendTo: options.appendHandlesTo,
resizableElement: that.element,
rootElement: options.rootElement,
rtl: options.rtl,
editor: that.options.editor
}, handleOptions[i])));
that._bindToResizeHandlesEvents();
},
_destroyResizeHandles: function() {
var that = this;
var length = that.handles ? that.handles.length : 0;
for (var i = 0; i < length; i++) that.handles[i].destroy();
that.handles = [];
},
_showResizeHandles: function() {
var that = this;
var length = (that.handles || []).length;
var i;
for (i = 0; i < length; i++) that.handles[i].show();
},
_bindToResizeHandlesEvents: function() {
return false;
},
_onResizeHandleDragStart: function() {
var that = this;
var element = $(that.element);
element.addClass(ELEMENT_RESIZING_CLASS);
that._initialElementHeight = outerHeight(element);
that._initialElementWidth = outerWidth(element);
that._disableKeyboard();
},
_onResizeHandleDrag: function(e) {
this.resize(e);
},
_onResizeHandleDragEnd: function() {
var that = this;
$(that.element).removeClass(ELEMENT_RESIZING_CLASS);
that._enableKeyboard();
},
_enableKeyboard: function() {
$(this.options.rootElement).off(KEY_DOWN + NS);
},
_disableKeyboard: function() {
$(this.options.rootElement).on(KEY_DOWN + NS, function(e) {
e.preventDefault();
});
}
});
var TableResizing = ElementResizing.extend({
_bindToResizeHandlesEvents: function() {
var that = this;
var handles = that.handles || [];
var length = handles.length;
var i;
var handle;
for (i = 0; i < length; i++) {
handle = handles[i];
handle.bind(DRAG_START, that._onResizeHandleDragStart.bind(that));
handle.bind(DRAG, that._onResizeHandleDrag.bind(that));
handle.bind(DRAG_END, that._onResizeHandleDragEnd.bind(that));
}
},
_hasRowsInPixels: function() {
var rows = $(this.element).children(THEAD + COMMA + TBODY).children(ROW);
for (var i = 0; i < rows.length; i++) if (rows[i].style.height === "" || inPixels(rows[i].style.height)) return true;
return false;
},
_resizeWidth: function(delta, initialDelta) {
var that = this;
var element = $(that.element);
var styleWidth = element[0].style[WIDTH];
var currentWidth = outerWidth(element);
var parentWidth = element.parent().width();
var maxWidth = that._getMaxDimensionValue(WIDTH);
var newWidth;
var ratioValue;
var ratioTotalValue;
var constrainedWidth;
if (delta === 0) return;
if (isUndefined(that._initialElementWidth)) that._initialElementWidth = currentWidth;
constrainedWidth = constrain({
value: that._initialElementWidth + initialDelta,
min: that.options.minWidth,
max: maxWidth
});
if (inPercentages(styleWidth)) {
if (currentWidth + delta > parentWidth) {
ratioValue = max(constrainedWidth, parentWidth);
ratioTotalValue = min(constrainedWidth, parentWidth);
} else {
ratioValue = min(constrainedWidth, parentWidth);
ratioTotalValue = max(constrainedWidth, parentWidth);
}
newWidth = toPercentages(calculatePercentageRatio(ratioValue, ratioTotalValue));
} else newWidth = toPixels(constrainedWidth);
that._setColumnsWidth();
element[0].style[WIDTH] = newWidth;
},
_resizeHeight: function(delta, initialDelta) {
var that = this;
var element = $(that.element);
var styleHeight = element[0].style[HEIGHT];
var currentHeight = outerHeight(element);
var parentHeight = element.parent().height();
var maxHeight = that._getMaxDimensionValue(HEIGHT);
var newHeight;
var ratioValue;
var ratioTotalValue;
var constrainedHeight;
var minHeight = that.options.minHeight;
var hasRowsInPixels = that._hasRowsInPixels();
if (delta === 0) return;
if (isUndefined(that._initialElementHeight)) that._initialElementHeight = currentHeight;
constrainedHeight = constrain({
value: that._initialElementHeight + initialDelta,
min: minHeight,
max: maxHeight
});
if (hasRowsInPixels && delta < 0) that._setRowsHeightInPercentages();
if (inPercentages(styleHeight)) {
if (currentHeight + delta > parentHeight) {
ratioValue = max(constrainedHeight, parentHeight);
ratioTotalValue = min(constrainedHeight, parentHeight);
} else {
ratioValue = min(constrainedHeight, parentHeight);
ratioTotalValue = max(constrainedHeight, parentHeight);
}
newHeight = toPercentages(calculatePercentageRatio(ratioValue, ratioTotalValue));
} else newHeight = toPixels(constrainedHeight);
element[0].style[HEIGHT] = newHeight;
if (hasRowsInPixels && delta < 0) that._setRowsHeightInPixels();
},
_setColumnsWidth: function() {
var element = $(this.element);
var parentElement = element.parent()[0];
var parentColumn = element.closest(COLUMN);
var columns = parentColumn.closest(ROW).children();
var columnsLength = columns.length;
var i;
function isWidthInPercentages(element) {
var styleWidth = element.style.width;
if (styleWidth !== "") return inPercentages(styleWidth) ? true : false;
else return $(element).hasClass(TABLE_CLASS) ? true : false;
}
if (isWidthInPercentages(element[0]) && parentElement === parentColumn[0] && parentElement.style[WIDTH] === "") for (i = 0; i < columnsLength; i++) columns[i].style[WIDTH] = toPixels($(columns[i]).width());
},
_setRowsHeightInPercentages: function() {
var that = this;
var tableHead = $(that.element).children(THEAD);
var tableHeadHeight = tableHead.length > 0 ? tableHead.height() : 0;
var tableBodyHeight = $(that.element).children(TBODY).height();
var rows = $(that.element).children(THEAD + COMMA + TBODY).children(ROW);
var length = rows.length;
var currentRowsHeights = rows.map(function() {
return outerHeight($(this));
});
var i;
for (i = 0; i < length; i++) rows[i].style[HEIGHT] = toPercentages(calculatePercentageRatio(currentRowsHeights[i], tableHeadHeight + tableBodyHeight));
},
_setRowsHeightInPixels: function() {
var rows = $(this.element).children(THEAD + COMMA + TBODY).children(ROW);
var length = rows.length;
var currentRowsHeights = rows.map(function() {
return outerHeight($(this));
});
var i;
for (i = 0; i < length; i++) rows[i].style[HEIGHT] = toPixels(currentRowsHeights[i]);
}
});
var ImageResizing = ElementResizing.extend({
_bindToResizeHandlesEvents: function() {
var that = this;
var handles = that.handles || [];
var length = handles.length;
var i;
var handle;
for (i = 0; i < length; i++) {
handle = handles[i];
handle.bind(DRAG_START, that._onResizeHandleDragStart.bind(that));
if (handle.options.direction === "north" || handle.options.direction === "south") handle.bind(DRAG, that._onResizeHandleDragVertical.bind(that));
else if (handle.options.direction === "east" || handle.options.direction === "west") handle.bind(DRAG, that._onResizeHandleDragHorizontal.bind(that));
else handle.bind(DRAG, that._onResizeHandleDragLocked.bind(that));
handle.bind(DRAG_END, that._onResizeHandleDragEnd.bind(that));
}
},
_getDeltas: function(args) {
return extend({}, {
deltaX: 0,
deltaY: 0,
initialDeltaX: 0,
initialDeltaY: 0
}, args);
},
_onResizeHandleDragVertical: function(args) {
var deltas = this._getDeltas(args);
this._resizeHeight(deltas.deltaY, deltas.initialDeltaY);
this.showResizeHandles();
},
_onResizeHandleDragHorizontal: function(args) {
var deltas = this._getDeltas(args);
this._resizeWidth(deltas.deltaX, deltas.initialDeltaX);
this.showResizeHandles();
},
_onResizeHandleDragLocked: function(args) {
var min = Math.min(Math.abs(args.initialDeltaX), Math.abs(args.initialDeltaY)), initialWidth = this._initialElementWidth, initialHeight = this._initialElementHeight, deltas;
if (min === args.initialDeltaX || min === args.initialDeltaX * -1) {
args.initialDeltaY = args.initialDeltaX * initialHeight / initialWidth;
args.deltaY = args.deltaX;
} else if (min === args.initialDeltaY || min === args.initialDeltaY * -1) {
args.initialDeltaX = args.initialDeltaY * initialWidth / initialHeight;
args.deltaX = args.deltaY;
}
deltas = this._getDeltas(args);
this._resizeWidth(deltas.deltaX, deltas.initialDeltaX);
this._resizeHeight(deltas.deltaY, deltas.initialDeltaY);
this.showResizeHandles();
},
_resizeWidth: function(delta, initialDelta) {
var that = this;
var element = $(that.element);
var currentWidth = outerWidth(element);
var newWidth;
var constrainedWidth;
if (delta === 0) return;
if (isUndefined(that._initialElementWidth)) that._initialElementWidth = currentWidth;
constrainedWidth = constrain({
value: that._initialElementWidth + initialDelta,
min: that.options.minWidth,
max: that._getMaxDimensionValue(WIDTH)
});
newWidth = toPixels(constrainedWidth);
element[0].style[WIDTH] = newWidth;
element.attr(WIDTH, Math.floor(constrainedWidth));
},
_resizeHeight: function(delta, initialDelta) {
var that = this;
var element = $(that.element);
var currentHeight = outerHeight(element);
var newHeight;
var constrainedHeight;
if (delta === 0) return;
if (isUndefined(that._initialElementHeight)) that._initialElementHeight = currentHeight;
constrainedHeight = constrain({
value: that._initialElementHeight + initialDelta,
min: that.options.minHeight,
max: Number.MAX_SAFE_INTEGER
});
newHeight = toPixels(constrainedHeight);
element[0].style[HEIGHT] = newHeight;
element.attr(HEIGHT, Math.floor(constrainedHeight));
}
});
const ElementResizingFactory = Class.extend({
create: function(editor) {
let factory = this;
$(editor.body).on("dragstart" + NS, function() {
var nodes = RangeUtils.nodes(editor.getRange()), hasImg = false;
nodes.forEach(function(node) {
if (node.nodeName === "IMG") hasImg = true;
});
if (hasImg && editor.elementResizing) editor.elementResizing._destroyResizeHandles();
}).on(DROP + NS, function() {
setTimeout(function() {
var image = RangeUtils.image(editor.getRange());
if (image) if (editor.elementResizing) {
editor.elementResizing._destroyResizeHandles();
editor.elementResizing.element = image;
editor.elementResizing.showResizeHandles();
} else {
factory._initResizing(editor, image);
editor._showElementResizeHandles();
}
});
}).on(MOUSE_DOWN + NS, TABLE + COMMA + IMG, function(e) {
var eventTarget = e.target;
var eventCurrentTarget = e.currentTarget;
var elementResizing = editor.elementResizing;
var element = elementResizing ? elementResizing.element : null;
if (elementResizing) {
if (element && eventCurrentTarget !== element) {
if (contains(eventCurrentTarget, element) && element !== eventTarget && contains(element, eventTarget)) return;
else if (element !== eventTarget) {
editor._destroyElementResizing();
factory._initResizing(editor, eventCurrentTarget);
}
}
} else factory._initResizing(editor, eventCurrentTarget);
editor._showElementResizeHandles();
}).on(MOUSE_DOWN + NS, function(e) {
var elementResizing = editor.elementResizing;
var element = elementResizing ? elementResizing.element : null;
var target = e.target;
var isResizeHandleOrChild = $(target).hasClass(RESIZE_HANDLE_WRAPPER_CLASS) || $(target).parents(DOT + RESIZE_HANDLE_WRAPPER_CLASS).length > 0;
if (elementResizing && element !== target && !contains(element, target) && !isResizeHandleOrChild) editor._destroyElementResizing();
});
},
dispose: function(editor) {
$(editor.body).off(NS);
},
_initResizing: function(editor, element) {
if (!browser.msie) {
if ($(element).is(TABLE)) editor.elementResizing = editor.tableResizing = new TableResizing(element, {
appendHandlesTo: editor.body,
rtl: kendo.support.isRtl(editor.element),
rootElement: editor.body,
editor
});
else if ($(element).is(IMG)) editor.elementResizing = new ImageResizing(element, {
appendHandlesTo: editor.body,
rtl: kendo.support.isRtl(editor.element),
rootElement: editor.body,
editor
});
if (editor._showElementResizeHandlesProxy) {
editor.unbind(SELECT, editor._showElementResizeHandlesProxy);
editor.bind(SELECT, editor._showElementResizeHandlesProxy);
}
}
}
});
ElementResizingFactory.current = new ElementResizingFactory();
extend(Editor, {
TableResizing,
ImageResizing,
ElementResizing,
ElementResizingFactory
});
})(window.kendo);
//#endregion
//#region ../src/editor/table-wizard/table-wizard-command.js
(function($, undefined) {
var kendo = window.kendo, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, Command = Editor.Command;
var tableFormatFinder = new Editor.BlockFormatFinder([{ tags: ["table"] }]);
var cellsFormatFinder = new Editor.BlockFormatFinder([{ tags: ["td", "th"] }]);
var reUnit = /([a-z]+|%)$/i;
var COL = "col";
var ROW = "row";
var COLGROUP = "colgroup";
var SCOPE = "scope";
var COL_INDEX = "col-index";
var TH = "th";
var TD = "td";
var THEAD = "thead";
var HEADERS = "headers";
var TABLE = "table";
var TableWizardCommand = Command.extend({
exec: function() {
var cmd = this;
var editor = cmd.editor;
var range = cmd.range = cmd.lockRange();
var isTableCellWizard = cmd.options.tableCellWizard;
var selectedTable = cmd._sourceTable = !cmd.options.insertNewTable ? cmd._selectedTable(range) : undefined;
var selectedCells = cmd._selectedTableCells = selectedTable ? cmd._selectedCells(range) : undefined;
var options = {
visible: false,
messages: editor.options.messages,
closeCallback: cmd.onDialogClose.bind(cmd),
table: cmd.parseTable(selectedTable, selectedCells),
dialogOptions: editor.options.dialogOptions,
isRtl: kendo.support.isRtl(editor.wrapper)
};
new Editor.TableWizardDialog(options).open(isTableCellWizard);
},
onDialogClose: function(data) {
var cmd = this;
cmd.releaseRange(cmd.range);
if (data) if (cmd.options.insertNewTable) cmd.insertTable(cmd.createNewTable(data));
else cmd.updateTable(data, cmd._sourceTable, cmd._selectedTableCells);
},
releaseRange: function(range) {
var cmd = this;
var doc = cmd.editor.document;
dom.windowFromDocument(doc).focus();
Command.fn.releaseRange.call(cmd, range);
},
insertTable: function(table) {
var range = this.range;
range.insertNode(table);
range.collapse(true);
this.editor.selectRange(range);
this._ensureFocusableAfterTable(table);
},
_ensureFocusableAfterTable: function(table) {
var siblingNodes = $(table).parent().contents();
var lastSiblingIndex = siblingNodes.length - 1;
var lastSibling = siblingNodes.get(lastSiblingIndex);
while (lastSibling.nodeValue !== null && (lastSibling.nodeValue === " " || lastSibling.nodeValue === "")) {
lastSiblingIndex -= 1;
lastSibling = siblingNodes.get(lastSiblingIndex);
}
if (lastSibling === table) dom.insertAfter(dom.createEmptyNode(this.editor.document, "p"), table);
},
updateTable: function(data, table, selectedCells) {
var cmd = this;
var tableRows = $(table.rows).toArray();
var tableProp = data.tableProperties;
var rows = tableProp.rows;
var tHead = table.tHead;
var last = cmd._lastInCollection;
var lastSelectedRow, cellProp;
while (selectedCells.length > 1) selectedCells.pop();
lastSelectedRow = selectedCells.length ? last(selectedCells).parentNode : last(tableRows);
cmd._deleteTableRows(tableRows, tableRows.length - rows);
if (tableRows.length < rows) cmd._addRows(lastSelectedRow, rows, tableRows);
dom.reMapTableColumns(table, COL_INDEX);
cmd._updateColumns(tableRows, tableProp.columns, selectedCells, lastSelectedRow);
cmd._updateTableProperties(table, tableProp);
cellProp = data.cellProperties;
if (selectedCells[0]) dom.attr(selectedCells[0], { id: (cellProp || {}).id || null });
if (cellProp) (cellProp.selectAllCells ? $(tableRows).children() : $(selectedCells)).each(function(i, cell) {
cmd._updateCellProperties(cell, cellProp, tableProp);
});
cmd._updateCaption(table, tableProp);
if (tHead) cmd._updateHeadersWithThead(table, data);
else cmd._updateHeadersNoThead(table, data);
cmd._updateHeaderAssociates(table, tableProp);
dom.clearTableMappings(table, COL_INDEX);
},
_isHeadingRow: function(row) {
return dom.is(row.cells[0], TH) && dom.is(row.parentNode, THEAD);
},
_isHeadingCell: function(cell) {
return dom.is(cell, TH);
},
cellsWithHeadersAssociated: function(table) {
var cells = $(table.rows).children();
var headingIds = [];
var checkHeader = function(header) {
return headingIds.indexOf(header) > -1;
};
cells.each(function(c, cell) {
if (cell.id && dom.is(cell, TH)) headingIds.push(cell.id);
});
return !!cells.filter(function(c, cell) {
var headersAttr = cell.getAttribute(HEADERS);
var headersArray;
if (headersAttr && !dom.is(cell, TH)) {
headersArray = headersAttr.split(" ");
if (headersArray && headersArray.length > 0) return headersArray.some(checkHeader);
}
return false;
}).length;
},
_insertCells: function(count, row, index) {
index = isNaN(index) ? -1 : index;
for (var i = 0, cell; i < count; i++) {
cell = row.insertCell(index);
cell.innerHTML = " ";
}
},
_deleteTableRows: function(rows, count) {
for (var i = 0, row, rowParent; i < count; i++) {
row = rows.pop();
rowParent = row.parentNode;
rowParent.removeChild(row);
if (!rowParent.rows.length) dom.remove(rowParent);
}
},
createNewTable: function(data) {
var cmd = this;
var doc = cmd.editor.document;
var tableProp = data.tableProperties;
var table = dom.create(doc, TABLE);
var rowIndex = 0;
var thead;
cmd._updateTableProperties(table, tableProp);
cmd._updateCaption(table, tableProp);
if (tableProp.headerRows && tableProp.headerRows > 0) {
thead = table.createTHead();
cmd._createTableRows(data, thead, rowIndex, true);
rowIndex += tableProp.headerRows;
}
var tbody = table.createTBody();
cmd._createTableRows(data, tbody, rowIndex, false);
dom.reMapTableColumns(table, COL_INDEX);
if (tableProp.cellsWithHeaders === "ids") dom.associateWithIds(table);
else if (tableProp.cellsWithHeaders === "scope") cmd._addScopes(table, tableProp.headerRows, tableProp.headerColumns);
dom.clearTableMappings(table, COL_INDEX);
return table;
},
_createTableRows: function(data, container, initialIndex, headerRows) {
var cmd = this;
var tableProp = data.tableProperties;
var cellProp = data.cellProperties;
var columns = tableProp.columns;
var rows = headerRows ? tableProp.headerRows : tableProp.rows;
var headerColumns = tableProp.headerColumns;
for (var r = initialIndex, row; r < rows; r++) {
row = container.insertRow();
for (var c = 0, cell; c < columns; c++) {
if (headerRows || headerColumns > c) cell = document.createElement(TH);
else cell = document.createElement(TD);
row.appendChild(cell);
cell.innerHTML = " ";
if (cellProp && r === 0 && c === 0 && cellProp.id) cell.id = cellProp.id;
cmd._updateCellProperties(cell, cellProp && (cellProp.selectAllCells || r === 0 && c === 0) ? cellProp : {}, tableProp);
}
}
},
_addRows: function(lastSelectedRow, rows, tableRows) {
var cmd = this;
var rowIndex = $(lastSelectedRow).index();
var cellsLength = lastSelectedRow.cells.length;
var newRowsCount = rows - tableRows.length;
var parent = lastSelectedRow.parentNode;
var row;
while (newRowsCount) {
row = parent.insertRow(rowIndex + 1);
cmd._insertCells(cellsLength - row.cells.length, row);
newRowsCount--;
}
},
_updateColumns: function(tableRows, columns, selectedCells, lastSelectedRow) {
var cmd = this;
var last = cmd._lastInCollection;
var firstRowLastCell = last(tableRows[0].cells);
var numberOfColumns = Number(firstRowLastCell.getAttribute(COL_INDEX)) + firstRowLastCell.colSpan;
if (numberOfColumns > columns) $(tableRows).each(function(i, row) {
var lastCurrentCell = last(row.cells);
var rowColumns = Number(lastCurrentCell.getAttribute(COL_INDEX)) + lastCurrentCell.colSpan;
while (rowColumns > columns) {
if (lastCurrentCell.colSpan && lastCurrentCell.colSpan > 1) lastCurrentCell.colSpan -= 1;
else row.deleteCell(-1);
lastCurrentCell = last(row.cells);
rowColumns = Number(lastCurrentCell.getAttribute(COL_INDEX)) + lastCurrentCell.colSpan;
}
});
if (numberOfColumns < columns) {
var cellIndex = $(last(selectedCells) || last(lastSelectedRow.cells)).index();
$(tableRows).each(function(i, row) {
var lastCurrentCell = last(row.cells);
cmd._insertCells(columns - Number(lastCurrentCell.getAttribute(COL_INDEX)) - lastCurrentCell.colSpan, row, cellIndex + 1);
});
}
},
_updateTableProperties: function(table, data) {
var style = this._getStylesData(data);
dom.attr(table, {
cellSpacing: data.cellSpacing || null,
topCellPadding: this._getNumericValue(data.topCellPadding) ?? "",
leftCellPadding: this._getNumericValue(data.leftCellPadding) ?? "",
bottomCellPadding: this._getNumericValue(data.bottomCellPadding) ?? "",
rightCellPadding: this._getNumericValue(data.rightCellPadding) ?? "",
className: data.className || null,
id: data.id || null,
summary: data.summary || null,
style: style || null
});
$(table).addClass("k-table");
},
_updateCellProperties: function(cell, data, tableData) {
var style = this._getStylesData(data);
style.paddingTop = this._getNumericValue(data.topCellPadding) ?? this._getNumericValue(tableData?.topCellPadding) ?? "";
style.paddingLeft = this._getNumericValue(data.leftCellPadding) ?? this._getNumericValue(tableData?.leftCellPadding) ?? "";
style.paddingBottom = this._getNumericValue(data.bottomCellPadding) ?? this._getNumericValue(tableData?.bottomCellPadding) ?? "";
style.paddingRight = this._getNumericValue(data.rightCellPadding) ?? this._getNumericValue(tableData?.rightCellPadding) ?? "";
style.margin = data.cellMargin || null;
dom.attr(cell, {
style: style || null,
className: data.className || null
});
},
_updateCaption: function(table, data) {
if (table.caption && !data.captionContent) table.deleteCaption();
else if (data.captionContent) {
var caption = table.createCaption();
caption.innerHTML = data.captionContent;
var alignment = this._getAlignmentData(data.captionAlignment);
dom.attr(caption, { style: {
textAlign: alignment.textAlign,
verticalAlign: alignment.verticalAlign
} });
}
},
_updateHeadersNoThead: function(table, data) {
var cmd = this;
var tableProp = data.tableProperties;
var rows = table.rows;
var row, cells, cell, i, j;
for (i = 0; i < rows.length; i++) {
row = rows[i];
cells = row.cells;
for (j = 0; j < cells.length; j++) {
cell = cells[j];
if (!cmd._isHeadingCell(cell) && (i < tableProp.headerRows || tableProp.headerColumns > cell.getAttribute(COL_INDEX))) dom.changeTag(cell, TH, false);
else if (cmd._isHeadingCell(cell) && i >= tableProp.headerRows && tableProp.headerColumns <= cell.getAttribute(COL_INDEX)) dom.changeTag(cell, TD, false);
}
}
},
_updateHeadersWithThead: function(table, data) {
var cmd = this;
var tableProp = data.tableProperties;
var thead = table.tHead;
var rowIndex = 0;
var tbody = table.tBodies[0];
var row, cell, i;
if (!tbody) tbody = table.createTBody();
if (tableProp.headerRows && tableProp.headerRows > 0) {
if (!thead) thead = table.createTHead();
while (thead.rows.length < tableProp.headerRows) thead.appendChild(tbody.rows[0]);
while (thead.rows.length > tableProp.headerRows) tbody.appendChild(thead.rows[0]);
cmd._swapToHeaderCells(thead);
} else if (thead) {
while (thead.rows.length > 0) tbody.appendChild(thead.rows[thead.rows.length - 1]);
table.deleteTHead();
}
while (tbody.rows.length > rowIndex) {
row = tbody.rows[rowIndex];
for (i = 0; i < row.cells.length; i++) {
cell = row.cells[i];
if (cmd._isHeadingCell(cell) && tableProp.headerColumns <= cell.getAttribute(COL_INDEX)) dom.changeTag(cell, TD, false);
else if (!cmd._isHeadingCell(cell) && tableProp.headerColumns > cell.getAttribute(COL_INDEX)) dom.changeTag(cell, TH, false);
}
rowIndex += 1;
}
},
_updateHeaderAssociates: function(table, tableProp) {
var cmd = this;
if (tableProp.cellsWithHeaders === "ids") {
if (!cmd.cellsWithHeadersAssociated(table)) cmd._removeScopes(table);
dom.associateWithIds(table);
} else if (tableProp.cellsWithHeaders === "scope") {
if (cmd.cellsWithHeadersAssociated(table)) cmd._removeAssociates(table);
cmd._addScopes(table, tableProp.headerRows, tableProp.headerColumns);
} else if (cmd.cellsWithHeadersAssociated(table)) cmd._removeAssociates(table);
else cmd._removeScopes(table);
},
_addScopes: function(table, headerRows, headerCols) {
var rows = table.rows;
var i, j, row, cell;
for (i = 0; i < rows.length; i++) {
row = rows[i];
for (j = 0; j < row.cells.length; j++) {
cell = row.cells[j];
if (i < headerRows) cell.setAttribute(SCOPE, COL);
else if (cell.getAttribute(COL_INDEX) < headerCols) cell.setAttribute(SCOPE, ROW);
}
}
},
_removeScopes: function(table) {
$(table).find(TH).removeAttr(SCOPE);
$(table).find(COL).remove();
$(table).find(COLGROUP).remove();
},
_removeAssociates: function(table) {
$(table).find("th, td").removeAttr("id headers");
},
_swapToHeaderCells: function(thead) {
var tds = $(thead).find("td");
var swapCell = function(index, cell) {
dom.changeTag(cell, TH, false);
};
tds.each(swapCell);
},
_getStylesData: function(data) {
var that = this;
var alignment = this._getAlignmentData(data.alignment);
var whiteSpace = "wrapText" in data ? data.wrapText ? "" : "nowrap" : null;
return $.extend({
width: data.width ? data.width + data.widthUnit : null,
height: data.height ? data.height + data.heightUnit : null,
textAlign: alignment.textAlign,
verticalAlign: alignment.verticalAlign,
backgroundColor: data.bgColor || "",
borderWidth: data.borderWidth,
borderStyle: data.borderStyle,
borderColor: data.borderColor || "",
borderCollapse: data.collapseBorders ? "collapse" : null,
whiteSpace
}, that._getTablePositionData(data.position));
},
_getAlignmentData: function(alignment) {
var textAlign = "";
var verticalAlign = textAlign;
if (alignment) if (alignment.indexOf(" ") != -1) {
var align = alignment.split(" ");
textAlign = align[0];
verticalAlign = align[1];
} else textAlign = alignment;
return {
textAlign,
verticalAlign
};
},
_getTablePositionData: function(position) {
if (!position) return {};
return {
marginLeft: position != "left" ? "auto" : "",
marginRight: position != "right" ? "auto" : ""
};
},
parseTable: function(table, selectedCells) {
if (!table) return {
tableProperties: {},
selectedCells: []
};
var cmd = this;
var tStyle = table.style;
var rows = table.rows;
var caption = table.caption;
var captionClone = $(caption ? caption.cloneNode(true) : undefined);
captionClone.find(".k-marker").remove();
var cssClass = table.className;
cssClass = cssClass.replace(/^k-table\s|\sk-table$/, "");
cssClass = cssClass.replace(/\sk-table\s/, " ");
cssClass = cssClass.replace(/^k-table$/, "");
var tableAlignment = cmd._getAlignment(table, true);
var tablePosition = cmd._getTablePosition(table);
var captionAlignment = caption ? cmd._getAlignment(caption) : undefined;
var numberOfHeaderRows = dom._getNumberOfHeaderRows(table);
var cellsWithHeaders;
if (cmd.cellsWithHeadersAssociated(table)) cellsWithHeaders = "ids";
else if ($(table).find("th[scope]").length > 0) cellsWithHeaders = "scope";
else cellsWithHeaders = "none";
dom.reMapTableColumns(table, COL_INDEX);
var numberOfColumns = dom._getNumberOfColumns(table);
var numberOfHeaderColumns = dom._getNumberOfHeaderColumns(table, numberOfHeaderRows);
dom.clearTableMappings(table, COL_INDEX);
var tableJson = {
tableProperties: {
width: tStyle.width || table.width ? parseFloat(tStyle.width || table.width) : null,
height: tStyle.height || table.height ? parseFloat(tStyle.height || table.height) : null,
columns: numberOfColumns,
rows: rows.length,
widthUnit: cmd._getUnit(tStyle.width),
heightUnit: cmd._getUnit(tStyle.height),
cellSpacing: table.cellSpacing,
topCellPadding: table.topCellPadding,
leftCellPadding: table.leftCellPadding,
bottomCellPadding: table.bottomCellPadding,
rightCellPadding: table.rightCellPadding,
alignment: tableAlignment.textAlign,
position: tablePosition,
bgColor: tStyle.backgroundColor || table.bgColor,
className: cssClass,
id: table.id,
borderWidth: tStyle.borderWidth || table.border,
borderColor: tStyle.borderColor,
borderStyle: tStyle.borderStyle || "",
collapseBorders: !!tStyle.borderCollapse,
summary: table.summary,
captionContent: caption ? captionClone.html() : "",
captionAlignment: caption && captionAlignment.textAlign ? captionAlignment.textAlign + " " + captionAlignment.verticalAlign : "",
headerRows: numberOfHeaderRows,
headerColumns: numberOfHeaderColumns,
cellsWithHeaders
},
selectedCells: []
};
tableJson.rows = cmd.parseTableRows(rows, selectedCells, tableJson);
return tableJson;
},
parseTableRows: function(rows, selectedCells, tableJson) {
var cmd = this;
var data = [], row, rowData, cells, cell, cellData;
for (var i = 0; i < rows.length; i++) {
row = rows[i];
rowData = { cells: [] };
cells = row.cells;
data.push(rowData);
for (var j = 0; j < cells.length; j++) {
cell = cells[j];
cellData = cmd.parseCell(cell);
if ($.inArray(cell, selectedCells) != -1) tableJson.selectedCells.push(cellData);
rowData.cells.push(cellData);
}
}
return data;
},
parseCell: function(cell) {
var cmd = this;
var cStyle = cell.style;
var alignment = cmd._getAlignment(cell);
alignment = alignment.textAlign ? alignment.textAlign + " " + alignment.verticalAlign : "";
return {
width: cStyle.width || cell.width ? parseFloat(cStyle.width || cell.width) : null,
height: cStyle.height || cell.height ? parseFloat(cStyle.height || cell.height) : null,
widthUnit: cmd._getUnit(cStyle.width),
heightUnit: cmd._getUnit(cStyle.height),
cellMargin: cStyle.margin,
topCellPadding: cStyle.paddingTop,
leftCellPadding: cStyle.paddingLeft,
bottomCellPadding: cStyle.paddingBottom,
rightCellPadding: cStyle.paddingRight,
alignment,
bgColor: cStyle.backgroundColor || cell.bgColor,
className: cell.className,
id: cell.id,
borderWidth: cStyle.borderWidth || cell.border,
borderColor: cStyle.borderColor,
borderStyle: cStyle.borderStyle,
wrapText: cStyle.whiteSpace != "nowrap"
};
},
_getTablePosition: function(element) {
var style = element.style;
if (style.marginLeft == "auto" && style.marginRight == "auto") return "center";
if (style.marginLeft == "auto") return "right";
return "left";
},
_getAlignment: function(element, horizontalOnly) {
var style = element.style;
var hAlign = style.textAlign || element.align || "";
if (horizontalOnly) return { textAlign: hAlign };
var vAlign = style.verticalAlign || element.vAlign || "";
if (hAlign && vAlign) return {
textAlign: hAlign,
verticalAlign: vAlign
};
if (!hAlign && vAlign) return {
textAlign: "left",
verticalAlign: vAlign
};
if (hAlign && !vAlign) return {
textAlign: hAlign,
verticalAlign: "top"
};
return {
textAlign: "",
verticalAlign: ""
};
},
_getUnit: function(value) {
var unit = (value || "").match(reUnit);
return unit ? unit[0] : "px";
},
_selectedTable: function(range) {
var nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
return tableFormatFinder.findSuitable(nodes)[0];
},
_selectedCells: function(range) {
var nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
return cellsFormatFinder.findSuitable(nodes);
},
_lastInCollection: function(collection) {
return collection[collection.length - 1];
},
_getNumericValue: function(value) {
return !isNaN(value) || typeof value === "string" ? value : null;
}
});
var TableWizardTool = Editor.Tool.extend({ command: function(options) {
options.insertNewTable = this.options.insertNewTable;
options.tableCellWizard = !!this.options.tableCellWizard;
return new TableWizardCommand(options);
} });
var TableWizardEditTool = TableWizardTool.extend({ update: function(ui, nodes) {
var isFormatted = !tableFormatFinder.isFormatted(nodes), toolbar = ui.closest(".k-toolbar").getKendoToolBar();
if (isFormatted === true) toolbar.hide(ui);
else toolbar.show(ui);
} });
var TableCellWizardEditTool = TableWizardTool.extend({ update: function(ui, nodes) {
var isFormatted = !tableFormatFinder.isFormatted(nodes), toolbar = ui.closest(".k-toolbar").getKendoToolBar();
if (isFormatted === true) toolbar.hide(ui);
else toolbar.show(ui);
} });
kendo.ui.editor.TableWizardTool = TableWizardTool;
kendo.ui.editor.TableWizardCommand = TableWizardCommand;
registerTool("tableProperties", new TableWizardEditTool({
command: TableWizardCommand,
insertNewTable: false,
property: "tableProperties"
}));
registerTool("tableCellProperties", new TableCellWizardEditTool({
command: TableWizardCommand,
tableCellWizard: true,
insertNewTable: false,
property: "tableCellProperties"
}));
})(window.kendo.jQuery);
//#endregion
//#region ../src/editor/table-wizard/table-wizard-dialog.js
(function($, undefined) {
const INVISIBLE_CLASS = "k-visibility-invisible";
var kendo = window.kendo, encode = kendo.htmlEncode, numericTextBoxSettings = {
format: "0",
min: 0
}, units = ["px", "em"], borderStyles = [
"solid",
"dotted",
"dashed",
"double",
"groove",
"ridge",
"inset",
"outset",
"initial",
"inherit",
"none",
"hidden"
];
var DEFAULT_NUMBER_OF_COLS_AND_ROWS = 4;
var textWrapDropDownSettings = {
dataSource: [{
className: "text-wrap-arrow",
value: "wrap"
}, {
className: "parameter-string",
value: "nowrap"
}],
dataTextField: "className",
dataValueField: "value",
template: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), { icon: encode(className) }) + encode(tooltip),
valueTemplate: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), {
icon: encode(className),
iconClass: "k-text-wrap"
}) + encode(tooltip)
};
var tablePositionDropDownSettings = {
dataSource: [
{
className: "table-position-start",
value: "left"
},
{
className: "table-position-center",
value: "center"
},
{
className: "table-position-end",
value: "right"
}
],
dataTextField: "className",
dataValueField: "value",
template: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), { icon: encode(className) }) + encode(tooltip),
valueTemplate: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), {
icon: encode(className),
iconClass: "k-align-group"
}) + encode(tooltip)
};
var tableAlignmentDropDownSettings = {
dataSource: [
{
className: "table-align-middle-left",
value: "left"
},
{
className: "table-align-middle-center",
value: "center"
},
{
className: "table-align-middle-right",
value: "right"
},
{
className: "align-remove",
value: ""
}
],
dataTextField: "className",
dataValueField: "value",
template: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), { icon: encode(className) }) + encode(tooltip),
valueTemplate: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), {
icon: encode(className),
iconClass: "k-align-group"
}) + encode(tooltip)
};
var cellAlignmentDropDownSettings = {
dataSource: [
{
className: "table-align-top-left",
value: "left top"
},
{
className: "table-align-top-center",
value: "center top"
},
{
className: "table-align-top-right",
value: "right top"
},
{
className: "table-align-middle-left",
value: "left middle"
},
{
className: "table-align-middle-center",
value: "center middle"
},
{
className: "table-align-middle-right",
value: "right middle"
},
{
className: "table-align-bottom-left",
value: "left bottom"
},
{
className: "table-align-bottom-center",
value: "center bottom"
},
{
className: "table-align-bottom-right",
value: "right bottom"
},
{
className: "align-remove",
value: ""
}
],
dataTextField: "className",
dataValueField: "value",
template: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), { icon: encode(className) }) + encode(tooltip),
valueTemplate: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), {
icon: encode(className),
iconClass: "k-align-group"
}) + encode(tooltip)
};
var accessibilityAlignmentDropDownSettings = {
dataSource: [
{
className: "table-align-top-left",
value: "left top"
},
{
className: "table-align-top-center",
value: "center top"
},
{
className: "table-align-top-right",
value: "right top"
},
{
className: "table-align-bottom-left",
value: "left bottom"
},
{
className: "table-align-bottom-center",
value: "center bottom"
},
{
className: "table-align-bottom-right",
value: "right bottom"
},
{
className: "align-remove",
value: ""
}
],
dataTextField: "className",
dataValueField: "value",
template: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), { icon: encode(className) }),
valueTemplate: ({ className, tooltip }) => kendo.ui.icon($(`<span title="${encode(tooltip)}"></span>`), {
icon: encode(className),
iconClass: "k-align-group"
})
};
var tablePropertiesDialogTemplate = ({ messages }) => `<div class="k-editor-dialog k-editor-table-wizard-window k-action-window k-popup-edit-form"><div id="k-table-wizard-tabs" class="k-root-tabs"><ul><li class="k-active">${messages.tableTab}</li><li>${messages.accessibilityTab}</li></ul><div id="k-table-properties"></div><div id="k-accessibility-properties"></div></div><div class="k-actions k-actions-start k-actions-horizontal k-window-buttons">` + kendo.html.renderButton(`<button class="k-dialog-ok"><span class="k-button-text">${messages.dialogOk}</span></button>`, {
icon: "check",
themeColor: "primary"
}) + kendo.html.renderButton(`<button class="k-dialog-close"><span class="k-button-text">${messages.dialogCancel}</span></button>`, { icon: "cancel" }) + "</div></div>";
var cellPropertiesDialogTemplate = ({ messages }) => "<div class=\"k-editor-dialog k-editor-table-wizard-window k-action-window k-popup-edit-form\"><div id=\"k-cell-properties\"></div><div class=\"k-actions k-actions-start k-actions-horizontal k-window-buttons\">" + kendo.html.renderButton(`<button class="k-dialog-ok"><span class="k-button-text">${messages.dialogOk}</span></button>`, {
icon: "check",
themeColor: "primary"
}) + kendo.html.renderButton(`<button class="k-dialog-close"><span class="k-button-text">${messages.dialogCancel}</span></button>`, { icon: "cancel" }) + "</div></div>";
var TableWizardDialog = kendo.Class.extend({
init: function(options) {
this.options = options;
},
_openTablePropertiesDialog: function() {
var that = this, options = that.options, dialogOptions = options.dialogOptions, tableData = options.table, dialog, messages = options.messages, isIE = kendo.support.browser.msie;
function close(e) {
e.preventDefault();
that.destroy();
dialog.destroy();
}
function okHandler(e) {
that.collectTableDialogValues(tableData);
close(e);
if (that.change) that.change();
options.closeCallback(tableData);
}
function closeHandler(e) {
close(e);
options.closeCallback();
}
dialogOptions.close = closeHandler;
dialogOptions.minWidth = 700;
dialogOptions.width = 700;
dialogOptions.title = messages.tableProperties;
dialogOptions.visible = options.visible;
dialog = $(that._dialogTemplate(messages)).appendTo(document.body).kendoWindow(dialogOptions).addClass("k-editor-window").closest(".k-window").toggleClass("k-rtl", options.isRtl).end().find(".k-dialog-ok").on("click", okHandler).end().find(".k-dialog-close").on("click", closeHandler).end().data("kendoWindow");
var element = dialog.element;
this.components = {};
that._initTabStripComponent(element);
that._tablePropertiesForm = that._createTablePropertiesForm(dialog, messages);
that._accessibilityPropertiesForm = that._createAccessibilityPropertiesForm(dialog, messages);
dialog.center();
dialog.open();
if (isIE) {
var dialogHeight = element.closest(".k-window").height();
element.css("max-height", dialogHeight);
}
},
_openCellPropertiesDialog: function() {
var that = this, options = that.options, dialogOptions = options.dialogOptions, tableData = options.table, dialog, messages = options.messages, isIE = kendo.support.browser.msie;
function close(e) {
e.preventDefault();
that.destroy();
dialog.destroy();
}
function okHandler(e) {
that.collectCellDialogValues(tableData);
close(e);
if (that.change) that.change();
options.closeCallback(tableData);
}
function closeHandler(e) {
close(e);
options.closeCallback();
}
dialogOptions.close = closeHandler;
dialogOptions.minWidth = 400;
dialogOptions.title = messages.tableCellProperties;
dialogOptions.visible = options.visible;
dialog = $(that._dialogTemplate(messages, cellPropertiesDialogTemplate)).appendTo(document.body).kendoWindow(dialogOptions).addClass("k-editor-window").closest(".k-window").toggleClass("k-rtl", options.isRtl).end().find(".k-dialog-ok").on("click", okHandler).end().find(".k-dialog-close").on("click", closeHandler).end().data("kendoWindow");
var element = dialog.element;
that._cellPropertiesForm = that._createCellPropertiesForm(dialog, messages);
dialog.center();
dialog.open();
if (isIE) {
var dialogHeight = element.closest(".k-window").height();
element.css("max-height", dialogHeight);
}
},
open: function(isCellProperties) {
if (!isCellProperties) this._openTablePropertiesDialog();
else this._openCellPropertiesDialog();
},
_initTabStripComponent: function(element) {
var components = this.components = {};
components.tabStrip = element.find("#k-table-wizard-tabs").kendoTabStrip({ animation: false }).data("kendoTabStrip");
},
collectTableDialogValues: function() {
var that = this;
var data = that.options.table;
that._collectTableViewValues(data);
that._collectAccessibilityViewValues(data);
},
collectCellDialogValues: function() {
var that = this;
var data = that.options.table;
that._collectCellViewValues(data);
},
_collectTableViewValues: function(tableData) {
var tableView = this.components.tableView;
var tableProperties = tableData.tableProperties;
var cellData = tableData.cellProperties = tableData.cellProperties || {};
tableProperties.width = tableView.width.value();
tableProperties.widthUnit = tableView.widthUnit.value();
tableProperties.height = tableView.height.value();
tableProperties.columns = tableView.columns.value();
tableProperties.rows = tableView.rows.value();
tableProperties.heightUnit = tableView.heightUnit.value();
tableProperties.cellSpacing = tableView.cellSpacing.value();
tableProperties.topCellPadding = tableView.topCellPadding.value();
tableProperties.leftCellPadding = tableView.leftCellPadding.value();
tableProperties.bottomCellPadding = tableView.bottomCellPadding.value();
tableProperties.rightCellPadding = tableView.rightCellPadding.value();
tableProperties.alignment = tableView.alignment.value();
tableProperties.position = tableView.position.value();
tableProperties.bgColor = tableView.bgColor.value();
tableProperties.borderWidth = tableView.borderWidth.value();
tableProperties.borderColor = tableView.borderColor.value();
tableProperties.borderStyle = tableView.borderStyle.value();
tableProperties.collapseBorders = tableView.collapseBorders.check();
if (!cellData.width) {
cellData.selectAllCells = true;
cellData.width = 100 / tableData.tableProperties.columns;
cellData.widthUnit = "%";
}
},
_collectCellViewValues: function(table) {
var cellData = table.cellProperties = table.cellProperties || {};
var cellView = this.components.cellView;
cellData.selectAllCells = cellView.selectAllCells.check();
cellData.width = cellView.width.value();
cellData.widthUnit = cellView.widthUnit.value();
cellData.height = cellView.height.value();
cellData.heightUnit = cellView.heightUnit.value();
cellData.independentCellPaddings = cellView.independentCellPaddings.check();
cellData.topCellPadding = cellView.topCellPadding.value();
cellData.leftCellPadding = cellView.leftCellPadding.value();
cellData.bottomCellPadding = cellView.bottomCellPadding.value();
cellData.rightCellPadding = cellView.rightCellPadding.value();
cellData.cellMargin = cellView.cellMargin.value();
cellData.alignment = cellView.alignment.value();
cellData.bgColor = cellView.bgColor.value();
cellData.className = cellView.className.value();
cellData.id = cellView.id.value();
cellData.borderWidth = cellView.borderWidth.value();
cellData.borderColor = cellView.borderColor.value();
cellData.borderStyle = cellView.borderStyle.value();
cellData.wrapText = cellView.wrapTextValue.value() == "wrap";
if (!cellData.width) {
cellData.selectAllCells = true;
cellData.width = 100 / table.tableProperties.columns;
cellData.widthUnit = "%";
}
},
_collectAccessibilityViewValues: function(table) {
var tableProperties = table.tableProperties;
var accessibilityView = this.components.accessibilityView;
tableProperties.captionContent = accessibilityView.captionContent.value();
tableProperties.captionAlignment = accessibilityView.captionAlignment.value();
tableProperties.summary = accessibilityView.summary.value();
tableProperties.cellsWithHeaders = accessibilityView.cellsWithHeaders.value();
tableProperties.className = accessibilityView.className.value();
tableProperties.id = accessibilityView.id.value();
tableProperties.headerRows = accessibilityView.headerRows.value();
tableProperties.headerColumns = accessibilityView.headerColumns.value();
},
_addUnit: function(units, value) {
if (value && $.inArray(value, units) == -1) units.push(value);
},
_initNumericTextbox: function(element, property, data, storage, settings) {
var component = storage[property] = element.kendoNumericTextBox(settings ? $.extend({}, numericTextBoxSettings, settings) : numericTextBoxSettings).data("kendoNumericTextBox");
if (property in data) component.value(parseInt(data[property], 10));
},
_initDropDownList: function(element, property, data, storage, dataSource) {
var component = storage[property] = element.kendoDropDownList({ dataSource }).data("kendoDropDownList");
this._setComponentValue(component, data, property);
},
_initBorderStyleDropDown: function(element, property, data, storage, dataSource) {
var component = storage[property] = element.kendoDropDownList({
dataSource,
optionLabel: this.options.messages.borderNone
}).data("kendoDropDownList");
this._setComponentValue(component, data, property);
},
_initTablePositionDropDown: function(element, data) {
var messages = this.options.messages;
var tableView = this.components.tableView;
var dataSource = tablePositionDropDownSettings.dataSource;
dataSource[0].tooltip = messages.tableAlignLeft;
dataSource[1].tooltip = messages.tableAlignCenter;
dataSource[2].tooltip = messages.tableAlignRight;
this._initPositionDropDown(element, tablePositionDropDownSettings, "position", data, tableView);
},
_initTableAlignmentDropDown: function(element, data) {
var messages = this.options.messages;
var tableView = this.components.tableView;
var dataSource = tableAlignmentDropDownSettings.dataSource;
dataSource[0].tooltip = messages.alignLeft;
dataSource[1].tooltip = messages.alignCenter;
dataSource[2].tooltip = messages.alignRight;
dataSource[3].tooltip = messages.alignRemove;
this._initAlignmentDropDown(element, tableAlignmentDropDownSettings, "alignment", data, tableView);
},
_initCellAlignmentDropDown: function(element, data) {
var messages = this.options.messages;
var cellView = this.components.cellView;
var dataSource = cellAlignmentDropDownSettings.dataSource;
dataSource[0].tooltip = messages.alignLeftTop;
dataSource[1].tooltip = messages.alignCenterTop;
dataSource[2].tooltip = messages.alignRightTop;
dataSource[3].tooltip = messages.alignLeftMiddle;
dataSource[4].tooltip = messages.alignCenterMiddle;
dataSource[5].tooltip = messages.alignRightMiddle;
dataSource[6].tooltip = messages.alignLeftBottom;
dataSource[7].tooltip = messages.alignCenterBottom;
dataSource[8].tooltip = messages.alignRightBottom;
dataSource[9].tooltip = messages.alignRemove;
this._initAlignmentDropDown(element, cellAlignmentDropDownSettings, "alignment", data, cellView);
},
_initAccessibilityAlignmentDropDown: function(element, data) {
var messages = this.options.messages;
var accessibilityView = this.components.accessibilityView;
var dataSource = accessibilityAlignmentDropDownSettings.dataSource;
dataSource[0].tooltip = messages.alignLeftTop;
dataSource[1].tooltip = messages.alignCenterTop;
dataSource[2].tooltip = messages.alignRightTop;
dataSource[3].tooltip = messages.alignLeftBottom;
dataSource[4].tooltip = messages.alignCenterBottom;
dataSource[5].tooltip = messages.alignRightBottom;
dataSource[6].tooltip = messages.alignRemove;
this._initAlignmentDropDown(element, accessibilityAlignmentDropDownSettings, "captionAlignment", data, accessibilityView);
},
_initTextWrapDropDown: function(element, data) {
var messages = this.options.messages;
var name = "wrapTextValue";
data.wrapTextValue = data.wrapText ? "wrap" : "nowrap";
var cellView = this.components.cellView;
var dataSource = textWrapDropDownSettings.dataSource;
dataSource[0].tooltip = messages.wrapText;
dataSource[1].tooltip = messages.fitToCell;
var component = cellView[name] = element.kendoDropDownList(textWrapDropDownSettings).data("kendoDropDownList");
component.list.addClass("k-text-wrap");
this._setComponentValue(component, data, name);
},
_initPositionDropDown: function(element, settings, name, data, storage) {
var component = storage[name] = element.kendoDropDownList(settings).data("kendoDropDownList");
component.list.addClass("k-position");
this._setComponentValue(component, data, name);
},
_initAlignmentDropDown: function(element, settings, name, data, storage) {
var component = storage[name] = element.kendoDropDownList(settings).data("kendoDropDownList");
component.list.addClass("k-align");
this._setComponentValue(component, data, name);
},
_initAssociationDropDown: function(element, name, settings, data, storage) {
var component = storage[name] = element.kendoDropDownList(settings).data("kendoDropDownList");
this._setComponentValue(component, data, name);
},
_setComponentValue: function(component, data, property) {
if (property in data) component.value(data[property]);
},
_initColorPicker: function(element, property, data, storage) {
var component = storage[property] = element.kendoColorPicker({
buttons: false,
clearButton: true
}).data("kendoColorPicker");
if (data[property]) component.value(data[property]);
},
_initInput: function(element, property, data, storage, settings) {
var component = storage[property] = element.kendoTextBox(settings || {}).data("kendoTextBox");
if (property in data) component.value(data[property]);
},
_initCheckbox: function(element, property, data, storage, settings) {
var component = storage[property] = element.kendoCheckBox(settings || {}).data("kendoCheckBox");
if (property in data) component.check(data[property]);
},
_initTextArea: function(element, property, data, storage, settings) {
var component = storage[property] = element.kendoTextArea(settings || {}).data("kendoTextArea");
if (property in data) component.value(data[property]);
},
destroy: function() {
var that = this;
that._destroyComponents(this.components);
delete that.components;
},
_destroyComponents: function(components) {
for (var widget in components) {
if (components[widget].destroy) components[widget].destroy();
delete components[widget];
}
},
_dialogTemplate: function(messages, dialogTemplate) {
return kendo.template(dialogTemplate || tablePropertiesDialogTemplate)({ messages });
},
_onPaddingTopChange: function(e) {
let viewType = this.components.tableView ? "tableView" : "cellView", view = this.components[viewType], independentCellPaddings = !view.independentCellPaddings.check(), topCellPaddingNumeric = view.topCellPadding, topCellPaddingValue = topCellPaddingNumeric.value(), leftCellPaddingNumeric = view.leftCellPadding, bottomCellPaddingNumeric = view.bottomCellPadding, rightCellPaddingNumeric = view.rightCellPadding;
if (independentCellPaddings) {
leftCellPaddingNumeric.value(topCellPaddingValue);
bottomCellPaddingNumeric.value(topCellPaddingValue);
rightCellPaddingNumeric.value(topCellPaddingValue);
}
topCellPaddingNumeric._cachedPadding = topCellPaddingValue;
},
_onPaddingCheckChange: function(e) {
let viewType = this.components.tableView ? "tableView" : "cellView", messages = this.options.messages, checked = e.sender.check(), view = this.components[viewType], topCellPaddingNumeric = view.topCellPadding, leftCellPaddingNumeric = view.leftCellPadding, bottomCellPaddingNumeric = view.bottomCellPadding, rightCellPaddingNumeric = view.rightCellPadding, topCellPaddingValue = topCellPaddingNumeric.value(), bottomCellPaddingValue = bottomCellPaddingNumeric.value(), leftCellPaddingValue = leftCellPaddingNumeric.value(), rightCellPaddingValue = rightCellPaddingNumeric.value();
if (!checked) {
if (topCellPaddingValue === bottomCellPaddingValue && topCellPaddingValue === leftCellPaddingValue && topCellPaddingValue === rightCellPaddingValue) {
leftCellPaddingNumeric.value(topCellPaddingValue);
bottomCellPaddingNumeric.value(topCellPaddingValue);
rightCellPaddingNumeric.value(topCellPaddingValue);
} else topCellPaddingNumeric.value(null);
leftCellPaddingNumeric.wrapper.closest(".k-form-field").addClass(INVISIBLE_CLASS);
bottomCellPaddingNumeric.wrapper.closest(".k-form-field").addClass(INVISIBLE_CLASS);
rightCellPaddingNumeric.wrapper.closest(".k-form-field").addClass(INVISIBLE_CLASS);
topCellPaddingNumeric.wrapper.closest(".k-form-field").find(".k-form-label").text(messages.cellPadding);
} else {
if (!isNaN(topCellPaddingNumeric._cachedPadding)) topCellPaddingNumeric.value(topCellPaddingNumeric._cachedPadding);
leftCellPaddingNumeric.wrapper.closest(".k-form-field").removeClass(INVISIBLE_CLASS);
bottomCellPaddingNumeric.wrapper.closest(".k-form-field").removeClass(INVISIBLE_CLASS);
rightCellPaddingNumeric.wrapper.closest(".k-form-field").removeClass(INVISIBLE_CLASS);
topCellPaddingNumeric.wrapper.closest(".k-form-field").find(".k-form-label").text(messages.topPadding);
}
},
_onColumnsNumberChange: function(args) {
var headerColumnsNumeric = this.components.accessibilityView.headerColumns;
var currentNumberOfColumnsHeaders = headerColumnsNumeric.value();
var numberOfColumns = args.sender.value();
if (numberOfColumns < currentNumberOfColumnsHeaders) headerColumnsNumeric.value(numberOfColumns);
headerColumnsNumeric.max(numberOfColumns);
},
_onRowsNumberChange: function(args) {
var headerRowsNumeric = this.components.accessibilityView.headerRows;
var currentNumberOfRowHeaders = headerRowsNumeric.value();
var numberOfRows = args.sender.value();
if (numberOfRows < currentNumberOfRowHeaders) headerRowsNumeric.value(numberOfRows);
headerRowsNumeric.max(numberOfRows);
},
_createTablePropertiesForm: function(dialog, messages) {
var that = this;
var table = that.options.table;
var formElement = dialog.element.find("#k-table-properties");
var components = that.components;
var tableView = components.tableView = {};
var tableProperties = table.tableProperties = table.tableProperties || {};
var form;
that._addUnit(units, tableProperties.widthUnit);
that._addUnit(units, tableProperties.heightUnit);
tableProperties.borderStyle = tableProperties.borderStyle || "";
form = formElement.kendoForm({
renderButtons: false,
layout: "grid",
grid: { cols: 4 },
items: [
{
colSpan: 2,
field: "k-editor-table-columns",
label: encode(messages.columns),
editor: function(container, options) {
that._initNumericTextbox($("<input type=\"numeric\" id=\"k-editor-table-columns\" />").appendTo(container), "columns", tableProperties, tableView, {
min: 1,
value: DEFAULT_NUMBER_OF_COLS_AND_ROWS,
change: that._onColumnsNumberChange.bind(that)
});
}
},
{
colSpan: 2,
field: "k-editor-table-rows",
label: encode(messages.rows),
editor: function(container, options) {
that._initNumericTextbox($("<input type=\"numeric\" id=\"k-editor-table-rows\" />").appendTo(container), "rows", tableProperties, tableView, {
min: 1,
value: DEFAULT_NUMBER_OF_COLS_AND_ROWS,
change: that._onRowsNumberChange.bind(that)
});
}
},
{
colSpan: 1,
field: "k-editor-table-width",
label: encode(messages.width),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-width\" />").appendTo(container), "width", tableProperties, tableView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-table-width-type",
label: {
encoded: false,
text: " "
},
editor: function(container, options) {
that._initDropDownList($(`<input id="k-editor-table-width-type" aria-label="${messages.units}" />`).appendTo(container), "widthUnit", tableProperties, tableView, units);
}
},
{
colSpan: 1,
field: "k-editor-table-height",
label: encode(messages.height),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-height\" />").appendTo(container), "height", tableProperties, tableView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-table-height-type",
label: {
encoded: false,
text: " "
},
editor: function(container, options) {
that._initDropDownList($(`<input id="k-editor-table-height-type" aria-label="${messages.units}" />`).appendTo(container), "heightUnit", tableProperties, tableView, units);
}
},
{
colSpan: 2,
field: "k-editor-table-position",
label: encode(messages.position),
editor: function(container, options) {
that._initTablePositionDropDown($("<input id=\"k-editor-table-position\" class=\"k-position\" />").appendTo(container), tableProperties);
}
},
{
colSpan: 2,
field: "k-editor-table-alignment",
label: encode(messages.alignment),
editor: function(container, options) {
that._initTableAlignmentDropDown($("<input id=\"k-editor-table-alignment\" class=\"k-align\" />").appendTo(container), tableProperties);
}
},
{
colSpan: 2,
field: "k-editor-table-cell-spacing",
label: encode(messages.cellSpacing),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cell-spacing\" />").appendTo(container), "cellSpacing", tableProperties, tableView, { placeholder: encode(messages.auto) });
}
},
{
type: "group",
label: "Cell Paddings",
layout: "grid",
colSpan: 4,
grid: {
cols: 4,
gutter: 20
},
items: [
{
colSpan: 4,
field: "k-editor-padding-all-sides",
label: "",
editor: function(container, options) {
that._initCheckbox($("<input id=\"k-editor-padding-all-sides\" />").appendTo(container), "independentCellPaddings", tableProperties, tableView, {
checked: true,
label: encode(messages.independentCellPaddings),
change: that._onPaddingCheckChange.bind(that)
});
}
},
{
colSpan: 1,
field: "k-editor-table-cell-padding-top",
label: encode(messages.topPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cell-padding-top\" />").appendTo(container), "topCellPadding", tableProperties, tableView, {
placeholder: encode(messages.auto),
change: that._onPaddingTopChange.bind(that)
});
}
},
{
colSpan: 1,
field: "k-editor-table-cell-padding-right",
label: encode(messages.rightPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cell-padding-right\" />").appendTo(container), "rightCellPadding", tableProperties, tableView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-table-cells-padding-bottom",
label: encode(messages.bottomPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cell-padding-bottom\" />").appendTo(container), "bottomCellPadding", tableProperties, tableView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-table-cell-padding-left",
label: encode(messages.leftPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cell-padding-left\" />").appendTo(container), "leftCellPadding", tableProperties, tableView, { placeholder: encode(messages.auto) });
}
}
]
},
{
type: "group",
label: "Borders",
layout: "grid",
colSpan: 4,
grid: {
cols: 4,
gutter: 10
},
items: [
{
colSpan: 4,
field: "k-editor-table-bg",
label: encode(messages.tableBackground),
editor: function(container, options) {
that._initColorPicker($("<input id=\"k-editor-table-bg\" />").appendTo(container), "bgColor", tableProperties, tableView);
}
},
{
colSpan: 1,
field: "k-editor-border-width",
label: encode(messages.borderWidth),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-border-width\" />").appendTo(container), "borderWidth", tableProperties, tableView);
}
},
{
colSpan: 1,
field: "k-editor-border-color",
label: encode(messages.borderColor),
editor: function(container, options) {
that._initColorPicker($("<input id=\"k-editor-border-color\" />").appendTo(container), "borderColor", tableProperties, tableView);
}
},
{
colSpan: 2,
field: "k-editor-border-style",
label: encode(messages.borderStyle),
editor: function(container, options) {
that._initBorderStyleDropDown($("<input id=\"k-editor-border-style\" />").appendTo(container), "borderStyle", tableProperties, tableView, borderStyles);
}
},
{
colSpan: 4,
field: "k-editor-collapse-borders",
label: "",
editor: function(container, options) {
that._initCheckbox($("<input id=\"k-editor-collapse-borders\"/>").appendTo(container), "collapseBorders", tableProperties, tableView, { label: encode(messages.collapseBorders) });
}
}
]
}
]
}).data("kendoForm");
form.layoutWrapper.addClass("k-gap-x-4");
return form;
},
_createCellPropertiesForm: function(dialog, messages) {
var that = this;
var table = that.options.table;
var formElement = dialog.element.find("#k-cell-properties");
var components = that.components = that.components || {};
var cellView = components.cellView = {};
var cellProperties = table.selectedCells && table.selectedCells[0] || {
borderStyle: "",
wrapText: true
};
var form;
that._addUnit(units, cellProperties.widthUnit);
that._addUnit(units, cellProperties.heightUnit);
form = formElement.kendoForm({
renderButtons: false,
layout: "grid",
grid: { cols: 4 },
items: [
{
colSpan: 4,
field: "k-editor-selectAllCells",
label: "",
editor: function(container, options) {
that._initCheckbox($("<input id=\"k-editor-selectAllCells\" />").appendTo(container), "selectAllCells", table.tableProperties, cellView, { label: encode(messages.selectAllCells) });
}
},
{
colSpan: 1,
field: "k-editor-cell-width",
label: encode(messages.width),
hint: encode(messages.applyToColumn),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-cell-width\" />").appendTo(container), "width", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-cell-width-type",
label: {
encoded: false,
text: " "
},
editor: function(container, options) {
that._initDropDownList($(`<input id="k-editor-cell-width-type" aria-label="${messages.units}" />`).appendTo(container), "widthUnit", cellProperties, cellView, units);
}
},
{
colSpan: 1,
field: "k-editor-cell-height",
label: encode(messages.height),
hint: encode(messages.applyToRow),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-cell-height\" />").appendTo(container), "height", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-cell-height-type",
label: {
encoded: false,
text: " "
},
editor: function(container, options) {
that._initDropDownList($(`<input id="k-editor-cell-height-type" aria-label="${messages.units}" />`).appendTo(container), "heightUnit", cellProperties, cellView, units);
}
},
{
colSpan: 2,
field: "k-editor-cell-alignment",
label: encode(messages.alignment),
editor: function(container, options) {
that._initCellAlignmentDropDown($("<input id=\"k-editor-cell-alignment\" class=\"k-align\" />").appendTo(container), cellProperties);
}
},
{
colSpan: 2,
field: "k-editor-wrap-text",
label: "Text control",
editor: function(container, options) {
that._initTextWrapDropDown($("<input id=\"k-editor-wrap-text\" />").appendTo(container), cellProperties);
}
},
{
colSpan: 4,
field: "k-editor-cell-bg",
label: encode(messages.background),
editor: function(container, options) {
that._initColorPicker($("<input id=\"k-editor-cell-bg\" />").appendTo(container), "bgColor", cellProperties, cellView);
}
},
{
colSpan: 2,
field: "k-editor-table-cell-margin",
label: encode(messages.cellMargin),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cell-margin\" />").appendTo(container), "cellMargin", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
type: "group",
label: "Cell Paddings",
layout: "grid",
colSpan: 4,
grid: {
cols: 4,
gutter: 20
},
items: [
{
colSpan: 4,
field: "k-editor-padding-all-sides",
label: "",
editor: function(container, options) {
that._initCheckbox($("<input id=\"k-editor-padding-all-sides\" />").appendTo(container), "independentCellPaddings", table.tableProperties, cellView, {
checked: true,
label: encode(messages.independentCellPaddings),
change: that._onPaddingCheckChange.bind(that)
});
}
},
{
colSpan: 1,
field: "k-editor-table-cells-padding-top",
label: encode(messages.topPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cells-padding-top\" />").appendTo(container), "topCellPadding", cellProperties, cellView, {
placeholder: encode(messages.auto),
change: that._onPaddingTopChange.bind(that)
});
}
},
{
colSpan: 1,
field: "k-editor-table-cells-padding-right",
label: encode(messages.rightPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cells-padding-right\" />").appendTo(container), "rightCellPadding", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-table-cells-padding-bottom",
label: encode(messages.bottomPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cells-padding-bottom\" />").appendTo(container), "bottomCellPadding", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-table-cells-padding-left",
label: encode(messages.leftPadding),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-cells-padding-left\" />").appendTo(container), "leftCellPadding", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
}
]
},
{
type: "group",
label: "Borders",
layout: "grid",
colSpan: 4,
grid: {
cols: 4,
gutter: 10
},
items: [
{
colSpan: 1,
field: "k-editor-cell-border-width",
label: encode(messages.borderWidth),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-cell-border-width\" />").appendTo(container), "borderWidth", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 1,
field: "k-editor-cell-border-color",
label: encode(messages.borderColor),
editor: function(container, options) {
that._initColorPicker($("<input id=\"k-editor-cell-border-color\" />").appendTo(container), "borderColor", cellProperties, cellView, { placeholder: encode(messages.auto) });
}
},
{
colSpan: 2,
field: "k-editor-cell-border-style",
label: encode(messages.borderStyle),
editor: function(container, options) {
that._initBorderStyleDropDown($("<input id=\"k-editor-cell-border-style\" />").appendTo(container), "borderStyle", cellProperties, cellView, borderStyles);
}
}
]
},
{
colSpan: 4,
field: "k-editor-cell-id",
label: {
text: encode(messages.id),
optional: true
},
editor: function(container, options) {
that._initInput($("<input id=\"k-editor-cell-id\" />").appendTo(container), "id", cellProperties, cellView);
}
},
{
colSpan: 4,
field: "k-editor-cell-css-class",
label: {
text: encode(messages.cssClass),
optional: true
},
editor: function(container, options) {
that._initInput($("<input id=\"k-editor-cell-css-class\" />").appendTo(container), "className", cellProperties, cellView);
}
}
]
}).data("kendoForm");
form.layoutWrapper.addClass("k-gap-x-4");
return form;
},
_createAccessibilityPropertiesForm: function(dialog, messages) {
var that = this;
var table = that.options.table;
var formElement = dialog.element.find("#k-accessibility-properties");
var components = that.components;
var accessibilityView = components.accessibilityView = {};
var tableProperties = table.tableProperties;
var form = formElement.kendoForm({
renderButtons: false,
layout: "grid",
grid: { cols: 4 },
items: [
{
colSpan: 4,
field: "k-editor-id",
label: {
text: encode(messages.id),
optional: true
},
editor: function(container, options) {
that._initInput($("<input id=\"k-editor-id\" />").appendTo(container), "id", tableProperties, accessibilityView);
}
},
{
colSpan: 4,
field: "k-editor-css-class",
label: {
text: encode(messages.cssClass),
optional: true
},
editor: function(container, options) {
that._initInput($("<input id=\"k-editor-css-class\" />").appendTo(container), "className", tableProperties, accessibilityView);
}
},
{
layout: "grid",
grid: {
cols: 4,
gutter: 16
},
colSpan: 4,
type: "group",
label: "Accessibility",
items: [
{
colSpan: 2,
field: "k-editor-table-caption",
label: {
text: encode(messages.caption),
optional: true
},
editor: function(container, options) {
that._initInput($("<input id=\"k-editor-table-caption\" />").appendTo(container), "captionContent", tableProperties, accessibilityView);
}
},
{
colSpan: 2,
field: "k-editor-accessibility-alignment",
label: encode(messages.captionAlignment),
editor: function(container, options) {
that._initAccessibilityAlignmentDropDown($("<input id=\"k-editor-accessibility-alignment\" />").appendTo(container), tableProperties);
}
},
{
colSpan: 1,
field: "k-editor-table-header-rows",
label: encode(messages.headerRows),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-header-rows\" />").appendTo(container), "headerRows", tableProperties, accessibilityView, { max: tableProperties.rows || DEFAULT_NUMBER_OF_COLS_AND_ROWS });
}
},
{
colSpan: 1,
field: "k-editor-table-header-columns",
label: encode(messages.headerColumns),
editor: function(container, options) {
that._initNumericTextbox($("<input id=\"k-editor-table-header-columns\" />").appendTo(container), "headerColumns", tableProperties, accessibilityView, { max: tableProperties.columns || DEFAULT_NUMBER_OF_COLS_AND_ROWS });
}
},
{
colSpan: 2,
field: "k-editor-cells-headers",
label: encode(messages.associateCellsWithHeaders),
editor: function(container, options) {
var element = $(`<select id="k-editor-cells-headers">
<option value="none">${messages.associateNone}</option>
<option value="scope">${messages.associateScope}</option>
<option value="ids">${messages.associateIds}</option>
</select>`).appendTo(container);
that._initAssociationDropDown(element, "cellsWithHeaders", { valuePrimitive: true }, tableProperties, accessibilityView);
}
},
{
colSpan: 4,
field: "k-editor-accessibility-summary",
label: {
text: encode(messages.summary),
optional: true
},
editor: function(container, options) {
that._initTextArea($("<textarea id=\"k-editor-accessibility-summary\"></textarea>").appendTo(container), "summary", tableProperties, accessibilityView, {
rows: 5,
placeholder: messages.tableSummaryPlaceholder
});
}
}
]
}
]
}).data("kendoForm");
form.layoutWrapper.addClass("k-gap-x-4");
return form;
}
});
kendo.ui.editor.TableWizardDialog = TableWizardDialog;
})(window.kendo.jQuery);
//#endregion
//#region ../src/kendo.editor.js
const __meta__ = {
id: "editor",
name: "Editor",
category: "web",
description: "Rich text editor component",
depends: [
"combobox",
"dropdownlist",
"window",
"colorpicker",
"toolbar",
"icons"
],
features: [
{
id: "editor-imagebrowser",
name: "Image Browser",
description: "Support for uploading and inserting images",
depends: ["imagebrowser"]
},
{
id: "editor-resizable",
name: "Resize handle",
description: "Support for resizing the content area via a resize handle",
depends: ["resizable"]
},
{
id: "editor-tablewizard",
name: "Table wizard dialog",
description: "Support for table properties configuration",
depends: [
"tabstrip",
"button",
"numerictextbox",
"textarea"
]
},
{
id: "editor-pdf-export",
name: "PDF export",
description: "Export Editor content as PDF",
depends: ["pdf", "drawing"]
},
{
id: "editor-ai",
name: "AI Prompt",
description: "The AIPrompt component simplifies the incorporation of external AI services into apps.",
depends: [
"aiprompt",
"inlineaiprompt",
"buttongroup",
"splitter",
"icons",
"html.input"
]
}
]
};
var kendo_editor_default = kendo;
//#endregion
exports.__meta__ = __meta__;
exports.default = kendo_editor_default;