EnVisageOnline/Main/Source/EnVisage/Scripts/Kendo/kendo.editor.js

7745 lines
344 KiB
JavaScript

/**
* Kendo UI v2016.1.226 (http://www.telerik.com/kendo-ui)
* Copyright 2016 Telerik AD. All rights reserved.
*
* Kendo UI commercial licenses may be obtained at
* http://www.telerik.com/purchase/license-agreement/kendo-ui-complete
* If you do not own a commercial license, this file shall be governed by the trial license terms.
*/
(function (f, define) {
define('util/undoredostack', ['kendo.core'], f);
}(function () {
(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: command });
}
},
redo: function () {
if (this.canRedo()) {
var command = this.stack[++this.currentCommandIndex];
command.redo();
this.trigger('redo', { command: 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: UndoRedoStack } });
}(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/main', [
'util/undoredostack',
'kendo.combobox',
'kendo.dropdownlist',
'kendo.window',
'kendo.colorpicker'
], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, os = kendo.support.mobileOS, browser = kendo.support.browser, extend = $.extend, proxy = $.proxy, deepExtend = kendo.deepExtend, keys = kendo.keys;
var ToolTemplate = Class.extend({
init: function (options) {
this.options = options;
},
getHtml: function () {
var options = this.options;
return kendo.template(options.template, { useWithBlock: false })(options);
}
});
var EditorUtils = {
editorWrapperTemplate: '<table cellspacing="4" cellpadding="0" class="k-widget k-editor k-header" role="presentation"><tbody>' + '<tr role="presentation"><td class="k-editor-toolbar-wrap" role="presentation"><ul class="k-editor-toolbar" role="toolbar" /></td></tr>' + '<tr><td class="k-editable-area" /></tr>' + '</tbody></table>',
buttonTemplate: '<a href="" role="button" class="k-tool"' + '#= data.popup ? " data-popup" : "" #' + ' unselectable="on" title="#= data.title #"><span unselectable="on" class="k-tool-icon #= data.cssClass #"></span><span class="k-tool-text">#= data.title #</span></a>',
colorPickerTemplate: '<div class="k-colorpicker #= data.cssClass #" />',
comboBoxTemplate: '<select title="#= data.title #" class="#= data.cssClass #" />',
dropDownListTemplate: '<span class="k-editor-dropdown"><select title="#= data.title #" class="#= data.cssClass #" /></span>',
separatorTemplate: '<span class="k-separator" />',
overflowAnchorTemplate: '<a href="" role="button" class="k-tool k-overflow-anchor" data-popup' + ' unselectable="on"><span unselectable="on" class="k-icon k-i-more"></span></a>',
formatByName: function (name, format) {
for (var i = 0; i < format.length; i++) {
if ($.inArray(name, format[i].tags) >= 0) {
return format[i];
}
}
},
registerTool: function (toolName, tool) {
var toolOptions = tool.options;
if (toolOptions && toolOptions.template) {
toolOptions.template.options.cssClass = 'k-' + toolName;
}
if (!tool.name) {
tool.options.name = toolName;
tool.name = toolName.toLowerCase();
}
Editor.defaultTools[toolName] = tool;
},
registerFormat: function (formatName, format) {
Editor.fn.options.formats[formatName] = format;
}
};
var messages = {
bold: 'Bold',
italic: 'Italic',
underline: 'Underline',
strikethrough: 'Strikethrough',
superscript: 'Superscript',
subscript: 'Subscript',
justifyCenter: 'Center text',
justifyLeft: 'Align text left',
justifyRight: 'Align text right',
justifyFull: 'Justify',
insertUnorderedList: 'Insert unordered list',
insertOrderedList: 'Insert ordered list',
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',
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',
linkWebAddress: 'Web address',
linkText: 'Text',
linkToolTip: 'ToolTip',
linkOpenInNewWindow: 'Open link in new window',
dialogUpdate: 'Update',
dialogInsert: 'Insert',
dialogCancel: 'Cancel',
createTable: 'Create 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'
};
var supportedBrowser = !os || os.ios && os.flatVersion >= 500 || !os.ios && typeof document.documentElement.contentEditable != 'undefined';
var toolGroups = {
basic: [
'bold',
'italic',
'underline'
],
alignment: [
'justifyLeft',
'justifyCenter',
'justifyRight'
],
lists: [
'insertUnorderedList',
'insertOrderedList'
],
indenting: [
'indent',
'outdent'
],
links: [
'createLink',
'unlink'
],
tables: [
'createTable',
'addColumnLeft',
'addColumnRight',
'addRowAbove',
'addRowBelow',
'deleteRow',
'deleteColumn'
]
};
var Editor = Widget.extend({
init: function (element, options) {
var that = this, value, editorNS = kendo.ui.editor, toolbarContainer, toolbarOptions, type;
var domElement;
var dom = editorNS.Dom;
if (!supportedBrowser) {
return;
}
Widget.fn.init.call(that, element, options);
that.options = deepExtend({}, that.options, options);
that.options.tools = that.options.tools.slice();
element = that.element;
domElement = element[0];
type = dom.name(domElement);
this._registerHandler(element.closest('form'), 'submit', proxy(that.update, that, undefined));
toolbarOptions = extend({}, that.options);
toolbarOptions.editor = that;
if (type == 'textarea') {
that._wrapTextarea();
toolbarContainer = that.wrapper.find('.k-editor-toolbar');
if (domElement.id) {
toolbarContainer.attr('aria-controls', domElement.id);
}
} else {
that.element.attr('contenteditable', true).addClass('k-widget k-editor k-editor-inline');
toolbarOptions.popup = true;
toolbarContainer = $('<ul class="k-editor-toolbar" role="toolbar" />').insertBefore(element);
}
that.toolbar = new editorNS.Toolbar(toolbarContainer[0], toolbarOptions);
that.toolbar.bindTo(that);
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));
}
});
}
that._resizable();
that._initializeContentElement(that);
that.keyboard = new editorNS.Keyboard([
new editorNS.BackspaceHandler(that),
new editorNS.TypingHandler(that),
new editorNS.SystemHandler(that)
]);
that.clipboard = new editorNS.Clipboard(this);
that.undoRedoStack = new kendo.util.UndoRedoStack();
if (options && options.value) {
value = options.value;
} else if (that.textarea) {
value = domElement.value;
if (that.options.encoded && $.trim(domElement.defaultValue).length) {
value = domElement.defaultValue;
}
value = value.replace(/[\r\n\v\f\t ]+/gi, ' ');
} else {
value = domElement.innerHTML;
}
that.value(value || kendo.ui.editor.emptyElementContent);
this._registerHandler(document, {
'mousedown': function () {
that._endTyping();
},
'mouseup': function () {
that._mouseup();
}
});
that.toolbar.resize();
kendo.notify(that);
},
_endTyping: function () {
var keyboard = this.keyboard;
try {
if (keyboard.isTypingInProgress()) {
keyboard.endTyping(true);
this.saveSelection();
}
} catch (e) {
}
},
_selectionChange: function () {
if (!browser.msie) {
kendo.ui.editor.Dom.ensureTrailingBreaks(this.body);
}
this._selectionStarted = false;
this.saveSelection();
this.trigger('select', {});
},
_resizable: function () {
var resizable = this.options.resizable;
var isResizable = $.isPlainObject(resizable) ? resizable.content === undefined || resizable.content === true : resizable;
if (isResizable && this.textarea) {
$('<div class=\'k-resize-handle\'><span class=\'k-icon k-resize-se\' /></div>').insertAfter(this.textarea);
this.wrapper.kendoResizable(extend({}, this.options.resizable, {
start: function (e) {
var editor = this.editor = $(e.currentTarget).closest('.k-editor');
this.initialSize = editor.height();
editor.find('td:last').append('<div class=\'k-overlay\' />');
},
resize: function (e) {
var delta = e.y.initialDelta;
var newSize = this.initialSize + delta;
var min = this.options.min || 0;
var max = this.options.max || Infinity;
newSize = Math.min(max, Math.max(min, newSize));
this.editor.height(newSize);
},
resizeend: function () {
this.editor.find('.k-overlay').remove();
this.editor = null;
}
}));
}
},
_wrapTextarea: function () {
var that = this, textarea = that.element, w = textarea[0].style.width, h = textarea[0].style.height, template = EditorUtils.editorWrapperTemplate, editorWrap = $(template).insertBefore(textarea).width(w).height(h), editArea = editorWrap.find('.k-editable-area');
textarea.attr('autocomplete', 'off').appendTo(editArea).addClass('k-content k-raw-content').css('display', 'none');
that.textarea = textarea;
that.wrapper = editorWrap;
},
_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:""';
if (specifiedDomain || domain != location.hostname) {
domainScript = '<script>document.domain="' + domain + '"</script>';
src = 'javascript:document.write(\'' + domainScript + '\')';
}
textarea.hide();
iframe = $('<iframe />', {
title: editor.options.messages.editAreaTitle,
frameBorder: '0'
})[0];
$(iframe).css('display', '').addClass('k-content').attr('tabindex', textarea[0].tabIndex).insertBefore(textarea);
iframe.src = src;
wnd = iframe.contentWindow || iframe;
doc = wnd.document || iframe.contentDocument;
$(iframe).one('load', function () {
editor.toolbar.decorateFrom(doc.body);
});
doc.open();
doc.write('<!DOCTYPE html><html><head>' + '<meta charset=\'utf-8\' />' + '<style>' + 'html,body{padding:0;margin:0;height:100%;min-height:100%;}' + 'body{font-size:12px;font-family:Verdana,Geneva,sans-serif;margin-top:-1px;padding:1px .2em 0;' + 'word-wrap: break-word;-webkit-nbsp-mode: space;-webkit-line-break: after-white-space;' + (kendo.support.isRtl(textarea) ? 'direction:rtl;' : '') + '}' + '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{table-layout:fixed;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 p{margin:0;padding:0;}' + 'k\\:script{display:none;}' + '</style>' + domainScript + '<script>(function(d,c){d[c](\'header\'),d[c](\'article\'),d[c](\'nav\'),d[c](\'section\'),d[c](\'footer\');})(document, \'createElement\');</script>' + $.map(stylesheets, function (href) {
return '<link rel=\'stylesheet\' href=\'' + href + '\'>';
}).join('') + '</head><body autocorrect=\'off\' contenteditable=\'true\'></body></html>');
doc.close();
return wnd;
},
_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');
}
},
_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());
falseTrigger = false;
}, 10);
},
'input': function () {
if (!beforeCorrection) {
return;
}
if (kendo.support.browser.mozilla && !falseTrigger) {
falseTrigger = true;
return;
}
kendo.ui.editor._finishUpdate(editor, beforeCorrection);
}
});
},
_registerHandler: function (element, type, handler) {
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 {
this._handlers.push({
element: element,
type: type,
handler: handler
});
element.on(type, handler);
}
}
},
_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 = [];
},
_initializeContentElement: function () {
var editor = this;
var doc;
var blurTrigger;
if (editor.textarea) {
editor.window = editor._createContentElement(editor.options.stylesheets);
doc = editor.document = editor.window.contentDocument || editor.window.document;
editor.body = doc.body;
blurTrigger = editor.window;
this._registerHandler(doc, 'mouseup', proxy(this._mouseup, this));
} else {
editor.window = window;
doc = editor.document = document;
editor.body = editor.element[0];
blurTrigger = editor.body;
editor.toolbar.decorateFrom(editor.body);
}
this._registerHandler(blurTrigger, 'blur', proxy(this._blur, this));
try {
doc.execCommand('enableInlineTableEditing', null, false);
} catch (e) {
}
if (kendo.support.touch) {
this._registerHandler(doc, {
'selectionchange': proxy(this._selectionChange, this),
'keydown': function () {
if (kendo._activeElement() != doc.body) {
editor.window.focus();
}
}
});
}
this._spellCorrect(editor);
this._registerHandler(editor.body, {
'dragstart': function (e) {
e.preventDefault();
},
'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) {
setTimeout(proxy(editor.toolbar.focus, editor.toolbar), 100);
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 direction = left ? -1 : 1;
if (left) {
offset -= 1;
}
if (offset + direction > 0 && container.nodeType == 3 && container.nodeValue[offset] == '\uFEFF') {
range.setStart(container, offset + direction);
range.collapse(true);
editor.selectRange(range);
}
}
var toolName = editor.keyboard.toolFromShortcut(editor.toolbar.tools, e);
if (toolName) {
e.preventDefault();
if (!/^(undo|redo)$/.test(toolName)) {
editor.keyboard.endTyping(true);
}
editor.trigger('keydown', e);
editor.exec(toolName);
return false;
}
editor.keyboard.clearTimeout();
editor.keyboard.keydown(e);
},
'keyup': function (e) {
var selectionCodes = [
8,
9,
33,
34,
35,
36,
37,
38,
39,
40,
40,
45,
46
];
if ($.inArray(e.keyCode, selectionCodes) > -1 || e.keyCode == 65 && e.ctrlKey && !e.altKey && !e.shiftKey) {
editor._selectionChange();
}
editor.keyboard.keyup(e);
},
'mousedown': function (e) {
editor._selectionStarted = true;
if (browser.gecko) {
return;
}
var target = $(e.target);
if ((e.which == 2 || e.which == 1 && e.ctrlKey) && target.is('a[href]')) {
window.open(target.attr('href'), '_new');
}
},
'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': function (e) {
editor.clipboard['on' + e.type](e);
},
'focusin': function () {
if (editor.body.hasAttribute('contenteditable')) {
$(this).addClass('k-state-active');
editor.toolbar.show();
}
},
'focusout': function () {
setTimeout(function () {
var active = kendo._activeElement();
var body = editor.body;
var toolbar = editor.toolbar;
if (active != body && !$.contains(body, active) && !$(active).is('.k-editortoolbar-dragHandle') && !toolbar.focused()) {
$(body).removeClass('k-state-active');
toolbar.hide();
}
}, 10);
}
});
},
_mouseup: function () {
var that = this;
if (that._selectionStarted) {
setTimeout(function () {
that._selectionChange();
}, 1);
}
},
refresh: function () {
var that = this;
if (that.textarea) {
that.textarea.val(that.value());
that.wrapper.find('iframe').remove();
that._initializeContentElement(that);
that.value(that.textarea.val());
}
},
events: [
'select',
'change',
'execute',
'error',
'paste',
'keydown',
'keyup'
],
options: {
name: 'Editor',
messages: messages,
formats: {},
encoded: true,
domain: null,
resizable: false,
serialization: {
entities: true,
semantic: true,
scripts: false
},
stylesheets: [],
dialogOptions: {
modal: true,
resizable: false,
draggable: true,
animation: false
},
imageBrowser: null,
fileBrowser: null,
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: [].concat.call(['formatting'], toolGroups.basic, toolGroups.alignment, toolGroups.lists, toolGroups.indenting, toolGroups.links, ['insertImage'], toolGroups.tables)
},
destroy: function () {
Widget.fn.destroy.call(this);
this._deregisterHandlers();
clearTimeout(this._spellCorrectTimeout);
this._focusOutside();
this.toolbar.destroy();
kendo.destroy(this.wrapper);
},
_focusOutside: function () {
if (kendo.support.browser.msie && this.textarea) {
var tempInput = $('<input style=\'position:absolute;left:-10px;top:-10px;width:1px;height:1px;font-size:0;border:0;\' />').appendTo(document.body).focus();
tempInput.blur().remove();
}
},
state: function (toolName) {
var tool = 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;
},
value: function (html) {
var body = this.body, editorNS = kendo.ui.editor, currentHtml = editorNS.Serializer.domToXhtml(body, this.options.serialization);
if (html === undefined) {
return currentHtml;
}
if (html == currentHtml) {
return;
}
editorNS.Serializer.htmlToDom(html, body);
if (!browser.msie) {
kendo.ui.editor.Dom.ensureTrailingBreaks(this.body);
}
this.selectionRestorePoint = null;
this.update();
this.toolbar.refreshTools();
},
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);
}
},
_focusBody: function () {
var body = this.body;
var iframe = this.wrapper && this.wrapper.find('iframe')[0];
var documentElement = this.document.documentElement;
var activeElement = kendo._activeElement();
if (activeElement != body && activeElement != iframe) {
var scrollTop = documentElement.scrollTop;
body.focus();
documentElement.scrollTop = scrollTop;
}
},
restoreSelection: function () {
this._focusBody();
if (this.selectionRestorePoint) {
this.selectRange(this.selectionRestorePoint.toRange());
}
},
focus: function () {
this.restoreSelection();
},
update: function (value) {
value = value || this.options.encoded ? this.encodedValue() : this.value();
if (this.textarea) {
this.textarea.val(value);
} else {
this._oldValue = value;
}
},
encodedValue: function () {
return kendo.ui.editor.Dom.encode(this.value());
},
createRange: function (document) {
return kendo.ui.editor.RangeUtils.createRange(document || this.document);
},
getSelection: function () {
return kendo.ui.editor.SelectionUtils.selectionFromDocument(this.document);
},
selectRange: function (range) {
this._focusBody();
var selection = this.getSelection();
selection.removeAllRanges();
selection.addRange(range);
this.saveSelection(range);
},
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;
},
selectedHtml: function () {
return kendo.ui.editor.Serializer.domToXhtml(this.getRange().cloneContents());
},
paste: function (html, options) {
this.focus();
var command = new kendo.ui.editor.InsertHtmlCommand($.extend({
range: this.getRange(),
html: html
}, options));
command.editor = this;
command.exec();
},
exec: function (name, params) {
var that = this;
var command = null;
var range, tool, prevented;
if (!name) {
throw new Error('kendoEditor.exec(): `name` parameter cannot be empty');
}
if (that.body.getAttribute('contenteditable') !== 'true' && name !== 'print') {
return false;
}
name = name.toLowerCase();
if (!that.keyboard.isTypingInProgress()) {
that.restoreSelection();
}
tool = that.toolbar.toolById(name);
if (!tool) {
for (var id in Editor.defaultTools) {
if (id.toLowerCase() == name) {
tool = Editor.defaultTools[id];
break;
}
}
}
if (tool) {
range = that.getRange();
if (tool.command) {
command = tool.command(extend({ range: range }, params));
}
prevented = that.trigger('execute', {
name: name,
command: command
});
if (prevented) {
return;
}
if (/^(undo|redo)$/i.test(name)) {
that.undoRedoStack[name]();
} else if (command) {
if (!command.managesUndoRedo) {
that.undoRedoStack.push(command);
}
command.editor = that;
command.exec();
if (command.async) {
command.change = proxy(that._selectionChange, that);
return;
}
}
that._selectionChange();
}
}
});
Editor.defaultTools = {
undo: {
options: {
key: 'Z',
ctrl: true
}
},
redo: {
options: {
key: 'Y',
ctrl: true
}
}
};
kendo.ui.plugin(Editor);
var Tool = Class.extend({
init: function (options) {
this.options = options;
},
initialize: function (ui, options) {
ui.attr({
unselectable: 'on',
title: options.title
});
ui.children('.k-tool-text').html(options.title);
},
command: function (commandArguments) {
return new this.options.command(commandArguments);
},
update: $.noop
});
Tool.exec = function (editor, name, value) {
editor.exec(name, { value: value });
};
var FormatTool = Tool.extend({
init: function (options) {
Tool.fn.init.call(this, options);
},
command: function (commandArguments) {
var that = this;
return new kendo.ui.editor.FormatCommand(extend(commandArguments, { formatter: that.options.formatter }));
},
update: function (ui, nodes) {
var isFormatted = this.options.finder.isFormatted(nodes);
ui.toggleClass('k-state-selected', isFormatted);
ui.attr('aria-pressed', isFormatted);
}
});
EditorUtils.registerTool('separator', new Tool({ template: new ToolTemplate({ template: EditorUtils.separatorTemplate }) }));
var bomFill = browser.msie && browser.version < 9 ? '\uFEFF' : '';
var emptyElementContent = '<br class="k-br" />';
if (browser.msie) {
if (browser.version < 10) {
emptyElementContent = '\uFEFF';
} else if (browser.version < 11) {
emptyElementContent = ' ';
}
}
extend(kendo.ui, {
editor: {
ToolTemplate: ToolTemplate,
EditorUtils: EditorUtils,
Tool: Tool,
FormatTool: FormatTool,
_bomFill: bomFill,
emptyElementContent: emptyElementContent
}
});
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: promise };
if (this.trigger('pdfExport', args)) {
return;
}
var options = this.options.pdf;
var paperSize = options.paperSize;
this._drawPDF(progress).then(function (root) {
options.paperSize = 'auto';
return kendo.drawing.exportPDF(root, options);
}).done(function (dataURI) {
kendo.saveAs({
dataURI: dataURI,
fileName: options.fileName,
proxyURL: options.proxyURL,
forceProxy: options.forceProxy
});
options.paperSize = paperSize;
progress.resolve();
}).fail(function (err) {
progress.reject(err);
});
return promise;
};
}
}(window.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/dom', ['editor/main'], f);
}(function () {
(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 = 'div,p,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), 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(','));
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;
while (true) {
node = node.nextSibling;
if (!node) {
break;
}
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: block,
inline: 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;
},
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: normalize,
blockElements: blockElements,
nonListBlockElements: nonListBlockElements,
inlineElements: inlineElements,
empty: empty,
fillAttrs: fillAttrs,
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 charCode = c.charCodeAt(0);
var entity = entityTable[charCode];
return entity ? '&' + entity + ';' : c;
});
},
stripBom: function (text) {
return (text || '').replace(bom, '');
},
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);
},
significantNodes: function (nodes) {
return $.grep(nodes, function (child) {
var name = Dom.name(child);
if (name == 'br') {
return false;
} else if (Dom.insignificant(child)) {
return false;
} else if (child.nodeType == 3 && whitespaceOrBom.test(child.nodeValue)) {
return false;
} else if (child.nodeType == 1 && !empty[name] && Dom.emptyNode(child)) {
return false;
}
return true;
});
},
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);
});
},
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 Dom.name(node) == nodeName;
},
isMarker: function (node) {
return node.className == KMARKER;
},
isWhitespace: function (node) {
return whitespace.test(node.nodeValue);
},
isEmptyspace: function (node) {
return emptyspace.test(node.nodeValue);
},
isBlock: function (node) {
return block[Dom.name(node)];
},
isEmpty: function (node) {
return empty[Dom.name(node)];
},
isInline: function (node) {
return inline[Dom.name(node)];
},
scrollContainer: function (doc) {
var wnd = Dom.windowFromDocument(doc), scrollContainer = (wnd.contentWindow || wnd).document || wnd.ownerDocument || wnd;
if (kendo.support.browser.webkit || scrollContainer.compatMode == 'BackCompat') {
scrollContainer = scrollContainer.body;
} else {
scrollContainer = scrollContainer.documentElement;
}
return scrollContainer;
},
scrollTo: function (node) {
var element = $(Dom.isDataNode(node) ? node.parentNode : node), wnd = Dom.windowFromDocument(node.ownerDocument), windowHeight = wnd.innerHeight, elementTop, elementHeight, scrollContainer = Dom.scrollContainer(node.ownerDocument);
elementTop = element.offset().top;
elementHeight = element[0].offsetHeight;
if (!elementHeight) {
elementHeight = parseInt(element.css('line-height'), 10) || Math.ceil(1.2 * parseInt(element.css('font-size'), 10)) || 15;
}
if (elementHeight + elementTop > scrollContainer.scrollTop + windowHeight) {
scrollContainer.scrollTop = elementHeight + elementTop - windowHeight;
}
},
persistScrollTop: function (doc) {
persistedScrollTop = Dom.scrollContainer(doc).scrollTop;
},
restoreScrollTop: function (doc) {
Dom.scrollContainer(doc).scrollTop = persistedScrollTop;
},
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) {
node.parentNode.removeChild(node);
},
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);
}
if (Dom.isWhitespace(node)) {
Dom.insertBefore(node, parent);
}
} else if (node.className != KMARKER) {
Dom.trim(node);
if (!node.childNodes.length && !Dom.isEmpty(node)) {
Dom.remove(node);
}
}
}
return parent;
},
closest: function (node, tag) {
while (node && Dom.name(node) != tag) {
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);
},
create: function (document, tagName, attributes) {
return Dom.attr(document.createElement(tagName), attributes);
},
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);
},
style: function (node, value) {
$(node).css(value || {});
},
unstyle: function (node, value) {
for (var key in value) {
if (key == FLOAT) {
key = kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT;
}
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());
}
},
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 = $.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);
}
if (count == 1) {
return paths[0][0];
}
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;
} else if (!closest && editable) {
closest = editable;
}
return closest;
},
closestEditableOfType: function (node, types) {
var editable = Dom.closestEditable(node, types);
if (editable && Dom.ofType(editable, types)) {
return editable;
}
},
filter: function (tagName, nodes, invert) {
var i = 0;
var len = nodes.length;
var result = [];
var name;
for (; i < len; i++) {
name = Dom.name(nodes[i]);
if (!invert && name == tagName || invert && name != tagName) {
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);
}
}
};
kendo.ui.editor.Dom = Dom;
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/serializer', ['editor/dom'], f);
}(function () {
(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 div = document.createElement('div');
div.innerHTML = ' <hr>';
var supportsLeadingWhitespace = div.firstChild.nodeType === 3;
div = null;
var Serializer = {
toEditableHtml: function (html) {
var br = '<br class="k-br">';
html = 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]*(&nbsp;|\u00a0)/i, '$1').replace(/<\/(table|blockquote)>$/i, '</$1>' + br);
},
_fillEmptyElements: function (body) {
$(body).find('p').each(function () {
var p = $(this);
if (/^\s*$/g.test(p.text()) && !p.find('img,input').length) {
var node = this;
while (node.firstChild && node.firstChild.nodeType != 3) {
node = node.firstChild;
}
if (node.nodeType == 1 && !dom.empty[dom.name(node)]) {
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;
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);
this.removeAttribute(name);
}
}
});
},
htmlToDom: function (html, root) {
var browser = kendo.support.browser;
var msie = browser.msie;
var legacyIE = msie && browser.version < 9;
var originalSrc = 'originalsrc';
var originalHref = 'originalhref';
html = Serializer.toEditableHtml(html);
if (legacyIE) {
html = '<br/>' + html;
html = html.replace(/href\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/, originalHref + '="$1"');
html = html.replace(/src\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/, originalSrc + '="$1"');
}
root.innerHTML = html;
if (legacyIE) {
dom.remove(root.firstChild);
$(root).find('k\\:script,script,link,img,a').each(function () {
var node = this;
if (node[originalHref]) {
node.setAttribute('href', node[originalHref]);
node.removeAttribute(originalHref);
}
if (node[originalSrc]) {
node.setAttribute('src', node[originalSrc]);
node.removeAttribute(originalSrc);
}
});
} else if (msie) {
dom.normalize(root);
Serializer._resetOrderedLists(root);
}
Serializer._preventScriptExecution(root);
Serializer._fillEmptyElements(root);
Serializer._removeSystemElements(root);
$('table', root).addClass('k-table');
return root;
},
domToXhtml: function (root, options) {
var result = [];
function semanticFilter(attributes) {
return $.grep(attributes, function (attr) {
return attr.name != 'style';
});
}
var tagMap = {
iframe: {
start: function (node) {
result.push('<iframe');
attr(node);
result.push('>');
},
end: function () {
result.push('</iframe>');
}
},
'k:script': {
start: function (node) {
result.push('<script');
attr(node);
result.push('>');
},
end: function () {
result.push('</script>');
},
skipEncoding: true
},
span: {
semantic: true,
start: function (node) {
var style = node.style;
var attributes = specifiedAttributes(node);
var semanticAttributes = semanticFilter(attributes);
if (semanticAttributes.length) {
result.push('<span');
attr(node, semanticAttributes);
result.push('>');
}
if (style.textDecoration == '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 + '"');
}
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') {
result.push('</u>');
}
if (semanticFilter(specifiedAttributes(node)).length) {
result.push('</span>');
}
}
},
strong: {
semantic: true,
start: function () {
result.push('<b>');
},
end: function () {
result.push('</b>');
}
},
em: {
semantic: true,
start: function () {
result.push('<i>');
},
end: function () {
result.push('</i>');
}
},
b: {
semantic: false,
start: function () {
result.push('<strong>');
},
end: function () {
result.push('</strong>');
}
},
i: {
semantic: false,
start: function () {
result.push('<em>');
},
end: function () {
result.push('</em>');
}
},
u: {
semantic: false,
start: function () {
result.push('<span style="text-decoration:underline;">');
},
end: function () {
result.push('</span>');
}
},
font: {
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 = $.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: property,
value: 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;
}
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;
}
attributes.sort(function (a, b) {
return a.nodeName > b.nodeName ? 1 : a.nodeName < b.nodeName ? -1 : 0;
});
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 child(node, skip, skipEncoding) {
var nodeType = node.nodeType, tagName, mapper, parent, value, previous;
if (nodeType == 1) {
tagName = dom.name(node);
if (!tagName || dom.insignificant(node)) {
return;
}
if (dom.isInline(node) && node.childNodes.length == 1 && node.firstChild.nodeType == 3 && !text(node.firstChild)) {
return;
}
if (!options.scripts && (tagName == 'script' || tagName == 'k:script')) {
return;
}
mapper = tagMap[tagName];
if (mapper) {
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]) {
result.push(' />');
} else {
result.push('>');
children(node, skip || dom.is(node, 'pre'));
result.push('</');
result.push(tagName);
result.push('>');
}
} else if (nodeType == 3) {
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)) {
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 textOnly(root) {
var childrenCount = root.childNodes.length;
var textChild = childrenCount && root.firstChild.nodeType == 3;
return textChild && (childrenCount == 1 || childrenCount == 2 && dom.insignificant(root.lastChild));
}
if (textOnly(root)) {
return dom.encode(text(root.firstChild).replace(/[\r\n\v\f\t ]+/, ' '), options);
}
children(root);
result = result.join('');
if (result.replace(brRe, '').replace(emptyPRe, '') === '') {
return '';
}
return result;
}
};
extend(Editor, { Serializer: Serializer });
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/range', ['editor/serializer'], f);
}(function () {
(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 (!('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: 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 () {
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 new RangeIterator(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 = '\uFEFF';
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'].apply(range, 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 == '\uFEFF')) {
nodes.push(node);
} else {
node = node.firstChild;
while (node) {
visit(node);
node = node.nextSibling;
}
}
}
new RangeIterator(range).traverse(visit);
return nodes;
};
}
});
var RestorePoint = Class.extend({
init: function (range, body) {
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.html = that.body.innerHTML;
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);
},
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 = root.parentNode;
}
return root;
},
restoreHtml: function () {
this.body.innerHTML = this.html;
},
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 != 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.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;
that.caret = dom.create(RangeUtils.documentFromRange(range), 'span', { className: 'k-marker' });
range.insertNode(that.caret);
range.selectNode(that.caret);
return that.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('\uFEFF');
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 == '\uFEFF') {
dom.remove(start.previousSibling);
}
if (end.nextSibling && end.nextSibling.nodeValue == '\uFEFF') {
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, shouldNormalizeStart, shouldNormalizeEnd, shouldNormalize;
normalize(range.commonAncestorContainer);
while (!start.nextSibling && start.parentNode) {
start = start.parentNode;
}
while (!end.previousSibling && end.parentNode) {
end = end.parentNode;
}
shouldNormalizeStart = start.previousSibling && start.previousSibling.nodeType == 3 && (start.nextSibling && start.nextSibling.nodeType == 3);
shouldNormalizeEnd = end.previousSibling && end.previousSibling.nodeType == 3 && (end.nextSibling && end.nextSibling.nodeType == 3);
shouldNormalize = shouldNormalizeStart && shouldNormalizeEnd;
start = start.nextSibling;
end = end.previousSibling;
var collapsed = false;
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();
},
documentFromRange: function (range) {
var startContainer = range.startContainer;
return startContainer.nodeType == 9 ? startContainer : startContainer.ownerDocument;
},
createRange: function (document) {
if (browser.msie && browser.version < 9) {
return new W3CRange(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)) {
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: SelectionUtils,
W3CRange: W3CRange,
RangeIterator: RangeIterator,
W3CSelection: W3CSelection,
RangeEnumerator: RangeEnumerator,
RestorePoint: RestorePoint,
Marker: Marker,
RangeUtils: RangeUtils
});
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/system', ['editor/range'], f);
}(function () {
(function ($) {
var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, EditorUtils = editorNS.EditorUtils, registerTool = EditorUtils.registerTool, dom = editorNS.Dom, Tool = editorNS.Tool, ToolTemplate = editorNS.ToolTemplate, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, extend = $.extend;
function finishUpdate(editor, startRestorePoint) {
var endRestorePoint = editor.selectionRestorePoint = new RestorePoint(editor.getRange());
var command = new GenericCommand(startRestorePoint, endRestorePoint);
command.editor = editor;
editor.undoRedoStack.push(command);
return endRestorePoint;
}
var Command = Class.extend({
init: function (options) {
this.options = options;
this.restorePoint = new RestorePoint(options.range);
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').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);
}
});
var GenericCommand = Class.extend({
init: function (startRestorePoint, endRestorePoint) {
this.body = startRestorePoint.body;
this.startRestorePoint = startRestorePoint;
this.endRestorePoint = endRestorePoint;
},
redo: function () {
this.body.innerHTML = this.endRestorePoint.html;
this.editor.selectRange(this.endRestorePoint.toRange());
},
undo: function () {
this.body.innerHTML = this.startRestorePoint.html;
this.editor.selectRange(this.startRestorePoint.toRange());
}
});
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, initOptions) {
var editor = initOptions.editor, options = this.options, dataSource = options.items ? options.items : editor.options.insertHtml;
this._selectBox = new editorNS.SelectBox(ui, {
dataSource: dataSource,
dataTextField: 'text',
dataValueField: 'value',
change: function () {
Tool.exec(editor, 'insertHtml', this.value());
},
title: editor.options.messages.insertHtml,
highlightFirst: false
});
},
command: function (commandArguments) {
return new InsertHtmlCommand(commandArguments);
},
update: function (ui) {
var selectbox = ui.data('kendoSelectBox') || ui.find('select').data('kendoSelectBox');
selectbox.close();
selectbox.value(selectbox.options.title);
}
});
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.preventDefault();
return true;
}
if (!evt.isDefaultPrevented() && isTypingKey && !keyboard.isTypingInProgress()) {
var range = editor.getRange();
that.startRestorePoint = new RestorePoint(range);
keyboard.startTyping(function () {
that.endRestorePoint = 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;
}
});
var BackspaceHandler = Class.extend({
init: function (editor) {
this.editor = editor;
},
_addCaret: function (container) {
var caret = dom.create(this.editor.document, 'a');
dom.insertAt(container, caret, 0);
return caret;
},
_restoreCaret: function (caret) {
var range = this.editor.createRange();
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 caret = this._addCaret(next);
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] == '\uFEFF') {
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(','));
if (dom.isDataNode(node)) {
this._cleanBomBefore(range);
}
if (block && block.previousSibling && editorNS.RangeUtils.isStartOf(range, block)) {
var prev = block.previousSibling;
var caret = this._addCaret(block);
this._merge(prev, block);
this._restoreCaret(caret);
return true;
}
if (li && editorNS.RangeUtils.isStartOf(range, li)) {
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);
}
this.editor.selectRange(range);
return true;
}
return false;
},
_handleSelection: function (range) {
var ancestor = range.commonAncestorContainer;
var table = dom.closest(ancestor, 'table');
var emptyParagraphContent = editorNS.emptyElementContent;
if (/t(able|body)/i.test(dom.name(ancestor))) {
range.selectNode(table);
}
var marker = new Marker();
marker.add(range, false);
range.setStartAfter(marker.start);
range.setEndBefore(marker.end);
var start = range.startContainer;
var end = range.endContainer;
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(this.editor.document.createTextNode('\uFEFF'), 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);
this.editor.selectRange(range);
return true;
},
_root: function (node) {
while (node && 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 (src.firstChild) {
if (dest.nodeType == 1) {
dest.appendChild(src.firstChild);
} else {
dest.parentNode.appendChild(src.firstChild);
}
}
dom.remove(src);
},
keydown: function (e) {
var method, startRestorePoint;
var range = this.editor.getRange();
var keyCode = e.keyCode;
var keys = kendo.keys;
var backspace = keyCode === keys.BACKSPACE;
var del = keyCode == keys.DELETE;
if ((backspace || del) && !range.collapsed) {
method = '_handleSelection';
} else if (backspace) {
method = '_handleBackspace';
} else if (del) {
method = '_handleDelete';
}
if (!method) {
return;
}
startRestorePoint = new RestorePoint(range);
if (this[method](range)) {
e.preventDefault();
finishUpdate(this.editor, startRestorePoint);
}
},
keyup: $.noop
});
var SystemHandler = Class.extend({
init: function (editor) {
this.editor = editor;
this.systemCommandIsInProgress = false;
},
createUndoCommand: function () {
this.startRestorePoint = this.endRestorePoint = 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());
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;
}
});
var 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;
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 == e.ctrlKey && toolOptions.alt == e.altKey && toolOptions.shift == e.shiftKey) {
return toolName;
}
}
},
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($.proxy(that.stopTyping, that), 1000);
}
},
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');
}
});
var Clipboard = Class.extend({
init: function (editor) {
this.editor = editor;
this.cleaners = [
new ScriptCleaner(),
new TabCleaner(),
new MSWordFormatCleaner(),
new WebkitFormatCleaner()
];
},
htmlToFragment: function (html) {
var editor = this.editor, doc = 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);
dom.persistScrollTop(editor.document);
return {
range: range,
restorePoint: restorePoint
};
},
_endModification: function (modificationInfo) {
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 = editorNS.RangeUtils.textNodes(range);
for (var i = 0; i < nodes.length; i++) {
nodes[i].nodeValue = dom.stripBom(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();
}
reader.onload = $.proxy(deferred.resolve, 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)) {
return;
}
var clipboardData = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData || {};
var items = clipboardData.items || clipboardData.files;
if (!items) {
return;
}
var images = $.grep(items, function (item) {
return /^image\//i.test(item.type);
});
var html = $.grep(items, function (item) {
return /^text\/html/i.test(item.type);
});
if (html.length || !images.length) {
return;
}
var modificationInfo = this._startModification();
if (!modificationInfo) {
return;
}
$.when.apply($, $.map(images, this._fileToDataURL)).done($.proxy(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);
}, this));
return true;
},
onpaste: function (e) {
if (this._handleImagePaste(e)) {
e.preventDefault();
return;
}
this._contentModification(function beforePaste(editor, range) {
var clipboardNode = dom.create(editor.document, 'div', {
className: 'k-paste-container',
innerHTML: '\uFEFF'
});
var browser = kendo.support.browser;
editor.body.appendChild(clipboardNode);
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);
$(editor.body).unbind('paste');
textRange.execCommand('Paste');
$(editor.body).bind('paste', $.proxy(this.onpaste, 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 });
});
},
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, i, l;
options = extend({
clean: false,
split: true
}, options);
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) {
html = html.replace(/(<br>(\s|&nbsp;)*)+(<\/?(div|p|li|col|t))/gi, '$3');
html = html.replace(/<(a|span)[^>]*><\/\1>/gi, '');
}
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;
var splittable = parent != editor.body && !dom.is(parent, 'td');
if (options.split && splittable && (block || dom.isInline(parent))) {
range.selectNode(caret);
editorNS.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 />'));
}
$(fragment.childNodes).filter('table').addClass('k-table').end().find('table').addClass('k-table');
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.setStartAfter($(rangeEnd).closest('table')[0]);
range.collapse(true);
}
editor.selectRange(range);
}
});
var Cleaner = Class.extend({
clean: function (html) {
var that = this, replacements = 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 () {
this.replacements = [
/<(\/?)script([^>]*)>/i,
'<$1telerik:script$2>'
];
},
applicable: function (html) {
return /<script[^>]*>/i.test(html);
}
});
var TabCleaner = Cleaner.extend({
init: function () {
var replacement = ' ';
this.replacements = [
/<span\s+class="Apple-tab-span"[^>]*>\s*<\/span>/gi,
replacement,
/\t/gi,
replacement,
/&nbsp;&nbsp; &nbsp;/gi,
replacement
];
},
applicable: function (html) {
return /&nbsp;&nbsp; &nbsp;|class="?Apple-tab-span/i.test(html);
}
});
var MSWordFormatCleaner = Cleaner.extend({
init: function () {
this.replacements = [
/<\?xml[^>]*>/gi,
'',
/<!--(.|\n)*?-->/g,
'',
/&quot;/g,
'\'',
/(?:<br>&nbsp;[\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>&nbsp;[\s\r\n]+|<br>)*/g,
'$1',
/<br><br>/g,
'<BR><BR>',
/<br>(?!\n)/g,
' ',
/<table([^>]*)>(\s|&nbsp;)+<t/gi,
'<table$1><t',
/<tr[^>]*>(\s|&nbsp;)*<\/tr>/gi,
'',
/<tbody[^>]*>(\s|&nbsp;)*<\/tbody>/gi,
'',
/<table[^>]*>(\s|&nbsp;)*<\/table>/gi,
'',
/<BR><BR>/g,
'<br>',
/^\s*(&nbsp;)+/gi,
'',
/(&nbsp;|<br[^>]*>)+\s*$/gi,
'',
/mso-[^;"]*;?/gi,
'',
/<(\/?)b(\s[^>]*)?>/gi,
'<$1strong$2>',
/<(\/?)font(\s[^>]*)?>/gi,
this.convertFontMatch,
/<(\/?)i(\s[^>]*)?>/gi,
'<$1em$2>',
/<o:p>&nbsp;<\/o:p>/gi,
'&nbsp;',
/<\/?(meta|link|style|o:|v:|x:)[^>]*>((?:.|\n)*?<\/(meta|link|style|o:|v:|x:)[^>]*>)?/gi,
'',
/<\/o>/g,
'',
/style=(["|'])\s*\1/g,
'',
/(<br[^>]*>)?\n/g,
function ($0, $1) {
return $1 ? $0 : ' ';
}
];
},
convertFontMatch: function (match, closing, args) {
var faceRe = /face=['"]([^'"]+)['"]/i;
var face = faceRe.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 (html) {
var startingSymbol;
if (/^(<span [^>]*texhtml[^>]*>)?<span [^>]*(Symbol|Wingdings)[^>]*>/i.test(html)) {
startingSymbol = true;
}
html = html.replace(/<\/?\w+[^>]*>/g, '').replace(/&nbsp;/g, '\xA0');
if (!startingSymbol && /^[\u2022\u00b7\u00a7\u00d8o]\u00a0+/.test(html) || startingSymbol && /^.\u00a0+/.test(html)) {
return 'ul';
}
if (/^\s*\w+[\.\)]\u00a0{2,}/.test(html)) {
return 'ol';
}
},
_convertToLi: function (p) {
var content;
if (p.childNodes.length == 1) {
content = p.firstChild.innerHTML.replace(/^\w+[\.\)](&nbsp;)+ /, '');
} else {
dom.remove(p.firstChild);
if (p.firstChild.nodeType == 3) {
if (/^[ivx]+\.$/i.test(p.firstChild.nodeValue)) {
dom.remove(p.firstChild);
}
}
if (/^(&nbsp;|\s)+$/i.test(p.firstChild.innerHTML)) {
dom.remove(p.firstChild);
}
content = p.innerHTML;
}
dom.remove(p);
return dom.create(document, 'li', { innerHTML: content });
},
lists: function (placeholder) {
var blockChildren = $(dom.blockElements.join(','), placeholder), lastMargin = -1, lastType, name, levels = {
'ul': {},
'ol': {}
}, li = placeholder, i, p, type, margin, list, key, child;
for (i = 0; i < blockChildren.length; i++) {
p = blockChildren[i];
type = this.listType(p.innerHTML);
name = dom.name(p);
if (name == 'td') {
continue;
}
if (!type || name != 'p') {
if (!p.innerHTML) {
dom.remove(p);
} else {
levels = {
'ul': {},
'ol': {}
};
li = placeholder;
lastMargin = -1;
}
continue;
}
margin = parseFloat(p.style.marginLeft || 0);
list = levels[type][margin];
if (margin > lastMargin || !list) {
list = dom.create(document, type);
if (li == placeholder) {
dom.insertBefore(list, p);
} else {
li.appendChild(list);
}
levels[type][margin] = list;
}
if (lastType != type) {
for (key in levels) {
for (child in levels[key]) {
if ($.contains(list, levels[key][child])) {
delete levels[key][child];
}
}
}
}
li = this._convertToLi(p);
list.appendChild(li);
lastMargin = margin;
lastType = type;
}
},
removeAttributes: function (element) {
var attributes = element.attributes, i = attributes.length;
while (i--) {
if (dom.name(attributes[i]) != 'colspan') {
element.removeAttributeNode(attributes[i]);
}
}
},
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]);
}
}
},
removeDefaultColors: function (spans) {
for (var i = 0; i < spans.length; i++) {
if (/^\s*color:\s*[^;]*;?$/i.test(spans[i].style.cssText)) {
dom.unwrap(spans[i]);
}
}
},
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.removeDefaultColors(tables.eq(i).find('span'));
}
},
headers: function (placeholder) {
var titles = $(placeholder).find('p.MsoTitle');
for (var i = 0; i < titles.length; i++) {
dom.changeTag(titles[i], 'h1');
}
},
clean: function (html) {
var that = this, placeholder;
html = Cleaner.fn.clean.call(that, html);
html = that.stripEmptyAnchors(html);
placeholder = dom.create(document, 'div', { innerHTML: html });
that.headers(placeholder);
that.lists(placeholder);
that.tables(placeholder);
html = placeholder.innerHTML.replace(/(<[^>]*)\s+class="?[^"\s>]*"?/gi, '$1');
return html;
}
});
var WebkitFormatCleaner = Cleaner.extend({
init: function () {
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 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();
}
}
});
var ExportPdfCommand = Command.extend({
init: function (options) {
this.async = true;
Command.fn.init.call(this, options);
},
exec: function () {
var that = this;
var range = this.lockRange(true);
this.editor.saveAsPDF().then(function () {
that.releaseRange(range);
});
}
});
extend(editorNS, {
_finishUpdate: finishUpdate,
Command: Command,
GenericCommand: GenericCommand,
InsertHtmlCommand: InsertHtmlCommand,
InsertHtmlTool: InsertHtmlTool,
TypingHandler: TypingHandler,
SystemHandler: SystemHandler,
BackspaceHandler: BackspaceHandler,
Keyboard: Keyboard,
Clipboard: Clipboard,
Cleaner: Cleaner,
TabCleaner: TabCleaner,
MSWordFormatCleaner: MSWordFormatCleaner,
WebkitFormatCleaner: WebkitFormatCleaner,
PrintCommand: PrintCommand,
ExportPdfCommand: ExportPdfCommand
});
registerTool('insertHtml', new InsertHtmlTool({
template: new ToolTemplate({
template: EditorUtils.dropDownListTemplate,
title: 'Insert HTML',
initialValue: 'Insert HTML'
})
}));
registerTool('print', new Tool({
command: PrintCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Print'
})
}));
registerTool('pdf', new Tool({
command: ExportPdfCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Export PDF'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/inlineformat', ['editor/system'], f);
}(function () {
(function ($) {
var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, EditorUtils = Editor.EditorUtils, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, extend = $.extend, registerTool = Editor.EditorUtils.registerTool, registerFormat = Editor.EditorUtils.registerFormat, 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 = RangeUtils.textNodes(range);
if (nodes.length > 0) {
this.activate(range, nodes);
}
},
apply: function (nodes) {
var formatNodes = [];
var i, l, node, formatNode;
for (i = 0, l = nodes.length; i < l; i++) {
node = nodes[i];
formatNode = this.finder.findSuitable(node);
if (formatNode) {
dom.attr(formatNode, this.attributes);
} else {
while (!dom.isBlock(node.parentNode) && node.parentNode.childNodes.length == 1) {
node = node.parentNode;
}
formatNode = this.wrap(node);
}
formatNodes.push(formatNode);
}
this.consolidate(formatNodes);
},
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) {
while (node.firstChild) {
last.appendChild(node.firstChild);
}
dom.remove(node);
}
}
}
});
var GreedyInlineFormatFinder = InlineFormatFinder.extend({
init: function (format, greedyProperty) {
this.format = format;
this.greedyProperty = greedyProperty;
InlineFormatFinder.fn.init.call(this, format);
},
getInlineCssValue: function (node) {
var attributes = node.attributes;
var trim = $.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;
}
}
}
}
},
getFormatInner: function (node) {
var $node = $(dom.isDataNode(node) ? node.parentNode : node);
var parents = $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 '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 = kendo.support.browser.msie || kendo.support.touch ? 'kendoDropDownList' : 'kendoComboBox';
this.format = [{ tags: ['span'] }];
this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
},
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: style }, options.cssAttr);
}
}));
},
initialize: function (ui, initOptions) {
var editor = initOptions.editor, options = this.options, toolName = options.name, dataSource, defaultValue = [];
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] || []);
ui[this.type]({
dataTextField: 'text',
dataValueField: 'value',
dataSource: dataSource,
change: function () {
Tool.exec(editor, toolName, this.value());
},
highlightFirst: false
});
ui.closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
ui.data(this.type).value('inherit');
}
});
var ColorTool = Tool.extend({
init: function (options) {
Tool.fn.init.call(this, options);
this.format = [{ tags: ['span'] }];
this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
},
options: { palette: 'websafe' },
update: 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: style }, options.cssAttr);
}
}));
},
initialize: function (ui, initOptions) {
var editor = initOptions.editor, toolName = this.name, options = extend({}, ColorTool.fn.options, this.options), palette = options.palette;
ui = this._widget = new kendo.ui.ColorPicker(ui, {
toolIcon: 'k-' + options.name,
palette: palette,
change: function () {
var color = ui.value();
if (color) {
Tool.exec(editor, toolName, color);
}
editor.focus();
},
activate: function (e) {
e.preventDefault();
ui.trigger('change');
}
});
ui.wrapper.attr({
title: initOptions.title,
unselectable: 'on'
}).find('*').attr('unselectable', 'on');
}
});
extend(Editor, {
InlineFormatFinder: InlineFormatFinder,
InlineFormatter: InlineFormatter,
DelayedExecutionTool: DelayedExecutionTool,
GreedyInlineFormatFinder: GreedyInlineFormatFinder,
GreedyInlineFormatter: GreedyInlineFormatter,
InlineFormatTool: InlineFormatTool,
FontTool: FontTool,
ColorTool: ColorTool
});
registerFormat('bold', [
{
tags: [
'strong',
'b'
]
},
{
tags: ['span'],
attr: { style: { fontWeight: 'bold' } }
}
]);
registerTool('bold', new InlineFormatTool({
key: 'B',
ctrl: true,
format: formats.bold,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Bold'
})
}));
registerFormat('italic', [
{
tags: [
'em',
'i'
]
},
{
tags: ['span'],
attr: { style: { fontStyle: 'italic' } }
}
]);
registerTool('italic', new InlineFormatTool({
key: 'I',
ctrl: true,
format: formats.italic,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Italic'
})
}));
registerFormat('underline', [
{
tags: ['span'],
attr: { style: { textDecoration: 'underline' } }
},
{ tags: ['u'] }
]);
registerTool('underline', new InlineFormatTool({
key: 'U',
ctrl: true,
format: formats.underline,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Underline'
})
}));
registerFormat('strikethrough', [
{
tags: [
'del',
'strike'
]
},
{
tags: ['span'],
attr: { style: { textDecoration: 'line-through' } }
}
]);
registerTool('strikethrough', new InlineFormatTool({
format: formats.strikethrough,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Strikethrough'
})
}));
registerFormat('superscript', [{ tags: ['sup'] }]);
registerTool('superscript', new InlineFormatTool({
format: formats.superscript,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Superscript'
})
}));
registerFormat('subscript', [{ tags: ['sub'] }]);
registerTool('subscript', new InlineFormatTool({
format: formats.subscript,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Subscript'
})
}));
registerTool('foreColor', new ColorTool({
cssAttr: 'color',
domAttr: 'color',
name: 'foreColor',
template: new ToolTemplate({
template: EditorUtils.colorPickerTemplate,
title: 'Color'
})
}));
registerTool('backColor', new ColorTool({
cssAttr: 'background-color',
domAttr: 'backgroundColor',
name: 'backColor',
template: new ToolTemplate({
template: EditorUtils.colorPickerTemplate,
title: 'Background Color'
})
}));
registerTool('fontName', new FontTool({
cssAttr: 'font-family',
domAttr: 'fontFamily',
name: 'fontName',
defaultValue: [{
text: 'fontNameInherit',
value: 'inherit'
}],
template: new ToolTemplate({
template: EditorUtils.comboBoxTemplate,
title: 'Font Name'
})
}));
registerTool('fontSize', new FontTool({
cssAttr: 'font-size',
domAttr: 'fontSize',
name: 'fontSize',
defaultValue: [{
text: 'fontSizeInherit',
value: 'inherit'
}],
template: new ToolTemplate({
template: EditorUtils.comboBoxTemplate,
title: 'Font Size'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/formatblock', ['editor/inlineformat'], f);
}(function () {
(function ($) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, dom = Editor.Dom, Command = Editor.Command, ToolTemplate = Editor.ToolTemplate, 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);
}
}
for (i = 0, len = suitable.length; i < len; i++) {
if (this.contains(suitable[i], suitable)) {
return [suitable[i]];
}
}
return suitable;
},
findFormat: function (sourceNode) {
var format = this.format, i, len, node, tags, attributes;
var editableParent = dom.editableParent(sourceNode);
for (i = 0, len = format.length; i < len; i++) {
node = sourceNode;
tags = format[i].tags;
attributes = format[i].attr;
while (node && dom.isAncestorOf(editableParent, node)) {
if (dom.ofType(node, tags) && dom.attrEquals(node, attributes)) {
return node;
}
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) {
for (var i = 0, len = nodes.length; i < len; i++) {
if (!this.findFormat(nodes[i])) {
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);
}
var images = dom.filter('img', nodes);
var imageFormat = EditorUtils.formatByName('img', this.format);
var imageAttributes = attributes(imageFormat);
$.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);
}
},
remove: function (nodes) {
var i, l, formatNode, namedFormat, name;
for (i = 0, l = nodes.length; i < l; i++) {
formatNode = this.finder.findFormat(nodes[i]);
if (formatNode) {
name = dom.name(formatNode);
if (name == 'div' && !formatNode.getAttribute('class')) {
dom.unwrap(formatNode);
} else {
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 = RangeUtils.nodes(range);
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;
if (blocks.length) {
for (i = 0, len = blocks.length; i < len; i++) {
tagName = dom.name(blocks[i]);
if (tagName == 'li') {
list = blocks[i].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' || blocks[i].attributes.contentEditable)) {
new BlockFormatter(format, this.values).apply(blocks[i].childNodes);
} else {
element = dom.changeTag(blocks[i], formatTag);
dom.attr(element, format[0].attr);
}
}
} else {
new BlockFormatter(format, this.values).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);
}
});
var FormatCommand = Command.extend({
init: function (options) {
options.formatter = options.formatter();
Command.fn.init.call(this, options);
}
});
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: BlockFormatFinder,
BlockFormatter: BlockFormatter,
GreedyBlockFormatter: GreedyBlockFormatter,
FormatCommand: FormatCommand,
BlockFormatTool: 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: listElements,
attr: {
style: {
textAlign: 'left',
listStylePosition: ''
}
}
}
]);
registerTool('justifyLeft', new BlockFormatTool({
format: formats.justifyLeft,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Justify Left'
})
}));
registerFormat('justifyCenter', [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: 'center' } }
},
{
tags: ['img'],
attr: {
style: {
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
'float': ''
}
}
},
{
tags: listElements,
attr: {
style: {
textAlign: 'center',
listStylePosition: 'inside'
}
}
}
]);
registerTool('justifyCenter', new BlockFormatTool({
format: formats.justifyCenter,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Justify Center'
})
}));
registerFormat('justifyRight', [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: 'right' } }
},
{
tags: ['img'],
attr: {
style: {
'float': 'right',
display: '',
marginLeft: '',
marginRight: ''
}
}
},
{
tags: listElements,
attr: {
style: {
textAlign: 'right',
listStylePosition: 'inside'
}
}
}
]);
registerTool('justifyRight', new BlockFormatTool({
format: formats.justifyRight,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Justify Right'
})
}));
registerFormat('justifyFull', [
{
tags: dom.nonListBlockElements,
attr: { style: { textAlign: 'justify' } }
},
{
tags: ['img'],
attr: {
style: {
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
'float': ''
}
}
},
{
tags: listElements,
attr: {
style: {
textAlign: 'justify',
listStylePosition: ''
}
}
}
]);
registerTool('justifyFull', new BlockFormatTool({
format: formats.justifyFull,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Justify Full'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/linebreak', ['editor/formatblock'], f);
}(function () {
(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 = '\uFEFF';
}
range.setStartBefore(focusNode.firstChild || focusNode);
}
}
},
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 () {
var range = this.getRange(), doc = RangeUtils.documentFromRange(range), parent, previous, next, emptyParagraphContent = editorNS.emptyElementContent, paragraph, marker, li, heading, rng, shouldTrim = this.shouldTrim(range);
range.deleteContents();
marker = this._insertMarker(doc, range);
li = dom.closestEditableOfType(marker, ['li']);
heading = dom.closestEditableOfType(marker, 'h1,h2,h3,h4,h5,h6'.split(','));
if (li) {
if (dom.emptyNode(li)) {
paragraph = dom.create(doc, 'p');
if (li.nextSibling) {
rng = range.cloneRange();
rng.selectNode(li);
RangeUtils.split(rng, li.parentNode);
}
dom.insertAfter(paragraph, li.parentNode);
dom.remove(li.parentNode.childNodes.length == 1 ? li.parentNode : li);
paragraph.innerHTML = emptyParagraphContent;
next = paragraph;
}
} else if (heading && this._blankAfter(marker)) {
paragraph = dom.create(doc, 'p');
dom.insertAfter(paragraph, heading);
paragraph.innerHTML = emptyParagraphContent;
dom.remove(marker);
next = paragraph;
}
if (!next) {
if (!(li || heading)) {
new BlockFormatter([{ tags: ['p'] }]).apply([marker]);
}
range.selectNode(marker);
parent = dom.parentOfType(marker, [li ? 'li' : heading ? dom.name(heading) : 'p']);
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);
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);
RangeUtils.selectRange(range);
},
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) && /^\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();
var br = dom.create(RangeUtils.documentFromRange(range), 'br');
var filler;
var browser = kendo.support.browser;
var oldIE = browser.msie && browser.version < 11;
range.deleteContents();
range.insertNode(br);
normalize(br.parentNode);
if (!oldIE && (!br.nextSibling || dom.isWhitespace(br.nextSibling))) {
filler = br.cloneNode(true);
filler.className = 'k-br';
dom.insertAfter(filler, br);
}
range.setStartAfter(br);
range.collapse(true);
dom.scrollTo(br.nextSibling || br);
RangeUtils.selectRange(range);
}
});
extend(editorNS, {
ParagraphCommand: ParagraphCommand,
NewLineCommand: NewLineCommand
});
registerTool('insertLineBreak', new Tool({
key: 13,
shift: true,
command: NewLineCommand
}));
registerTool('insertParagraph', new Tool({
key: 13,
command: ParagraphCommand
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/lists', ['editor/linebreak'], f);
}(function () {
(function ($) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, EditorUtils = Editor.EditorUtils, Command = Editor.Command, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, BlockFormatFinder = Editor.BlockFormatFinder, textNodes = RangeUtils.textNodes, registerTool = Editor.EditorUtils.registerTool;
var ListFormatFinder = BlockFormatFinder.extend({
init: function (tag) {
this.tag = tag;
var tags = this.tags = [
tag == 'ul' ? 'ol' : 'ul',
tag
];
BlockFormatFinder.fn.init.call(this, [{ tags: tags }]);
},
isFormatted: function (nodes) {
var formatNodes = [];
var formatNode, i;
for (i = 0; i < nodes.length; i++) {
formatNode = this.findFormat(nodes[i]);
if (formatNode && dom.name(formatNode) == this.tag) {
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]);
if (candidate && dom.name(candidate) == this.tag) {
return candidate;
}
return null;
}
});
var ListFormatter = Class.extend({
init: function (tag, unwrapTag) {
var that = this;
that.finder = new ListFormatFinder(tag);
that.tag = tag;
that.unwrapTag = unwrapTag;
},
isList: function (node) {
var name = dom.name(node);
return name == 'ul' || name == 'ol' || name == 'dl';
},
wrap: function (list, nodes) {
var li = dom.create(list.ownerDocument, 'li'), i, node;
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);
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) {
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) {
while (formatNode.lastChild) {
next.insertBefore(formatNode.lastChild, next.firstChild);
}
dom.remove(formatNode);
}
},
breakable: function (node) {
return node != node.ownerDocument.body && !/table|tbody|tr|td/.test(dom.name(node)) && !node.attributes.contentEditable;
},
applyOnSection: function (section, nodes) {
var tag = this.tag;
var commonAncestor = dom.closestSplittableParent(nodes);
var ancestors = [];
var formatNode = this.finder.findSuitable(nodes);
if (!formatNode) {
formatNode = new ListFormatFinder(tag == 'ul' ? 'ol' : 'ul').findSuitable(nodes);
}
var childNodes;
if (/table|tbody/.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, $.proxy(function (node) {
return this.containsAny(node, nodes);
}, this));
}
if (!childNodes.length) {
childNodes = nodes;
}
}
function pushAncestor() {
ancestors.push(this);
}
for (var i = 0; i < childNodes.length; i++) {
var child = childNodes[i];
var suitable = (!formatNode || !dom.isAncestorOrSelf(formatNode, child)) && this.suitable(child, nodes);
if (!suitable) {
continue;
}
if (formatNode && this.isList(child)) {
$.each(child.childNodes, 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);
dom.insertBefore(formatNode, ancestors[0]);
}
this.wrap(formatNode, ancestors);
if (!dom.is(formatNode, tag)) {
dom.changeTag(formatNode, tag);
}
this.merge(tag, formatNode);
},
apply: function (nodes) {
var i = 0, sections = [], lastSection, lastNodes, section;
do {
section = dom.closestEditable(nodes[i], [
'td',
'body'
]);
if (!lastSection || section != lastSection) {
if (lastSection) {
sections.push({
section: lastSection,
nodes: lastNodes
});
}
lastNodes = [nodes[i]];
lastSection = section;
} else {
lastNodes.push(nodes[i]);
}
i++;
} while (i < nodes.length);
sections.push({
section: lastSection,
nodes: lastNodes
});
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);
}
}
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(options.tag);
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.tag) }));
},
command: function (commandArguments) {
return new ListCommand(extend(commandArguments, { tag: this.options.tag }));
}
});
extend(Editor, {
ListFormatFinder: ListFormatFinder,
ListFormatter: ListFormatter,
ListCommand: ListCommand,
ListTool: ListTool
});
registerTool('insertUnorderedList', new ListTool({
tag: 'ul',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Insert unordered list'
})
}));
registerTool('insertOrderedList', new ListTool({
tag: 'ol',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Insert ordered list'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/link', ['editor/lists'], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, InlineFormatter = Editor.InlineFormatter, InlineFormatFinder = Editor.InlineFormatFinder, textNodes = RangeUtils.textNodes, registerTool = Editor.EditorUtils.registerTool;
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 = textNodes(range);
var markers, doc, formatter, a, parent;
if (attributes.innerHTML) {
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('\uFEFF'), markers[1]);
dom.insertAfter(doc.createTextNode('\uFEFF'), markers[1]);
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) {
options.formatter = {
toggle: function (range) {
new InlineFormatter([{ tags: ['a'] }]).remove(textNodes(range));
}
};
this.options = options;
Command.fn.init.call(this, options);
}
});
var LinkCommand = Command.extend({
init: function (options) {
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.apply(options.range, {
href: options.url,
innerHTML: options.text || options.url,
target: options.target
});
};
}
},
_dialogTemplate: function () {
return kendo.template('<div class="k-editor-dialog k-popup-edit-form k-edit-form-container">' + '<div class=\'k-edit-label\'>' + '<label for=\'k-editor-link-url\'>#: messages.linkWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type=\'text\' class=\'k-input k-textbox\' id=\'k-editor-link-url\'>' + '</div>' + '<div class=\'k-edit-label k-editor-link-text-row\'>' + '<label for=\'k-editor-link-text\'>#: messages.linkText #</label>' + '</div>' + '<div class=\'k-edit-field k-editor-link-text-row\'>' + '<input type=\'text\' class=\'k-input k-textbox\' id=\'k-editor-link-text\'>' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for=\'k-editor-link-title\'>#: messages.linkToolTip #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type=\'text\' class=\'k-input k-textbox\' id=\'k-editor-link-title\'>' + '</div>' + '<div class=\'k-edit-label\'></div>' + '<div class=\'k-edit-field\'>' + '<input type=\'checkbox\' class=\'k-checkbox\' id=\'k-editor-link-target\'>' + '<label for=\'k-editor-link-target\' class=\'k-checkbox-label\'>#: messages.linkOpenInNewWindow #</label>' + '</div>' + '<div class=\'k-edit-buttons k-state-default\'>' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>')({ messages: this.editor.options.messages });
},
exec: function () {
var messages = this.editor.options.messages;
this._initialText = '';
this._range = this.lockRange(true);
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(this._dialogTemplate(), {
title: messages.createLink,
close: proxy(this._close, this),
visible: false
});
if (a) {
this._range.selectNodeContents(a);
nodes = textNodes(this._range);
}
this._initialText = this.linkText(nodes);
dialog.find('.k-dialog-insert').click(proxy(this._apply, this)).end().find('.k-dialog-close').click(proxy(this._close, this)).end().find('.k-edit-field input').keydown(proxy(this._keydown, 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').attr('checked', a ? a.target == '_blank' : false).end().find('.k-editor-link-text-row').toggle(!img);
this._dialog = dialog.data('kendoWindow').center().open();
$('#k-editor-link-url', dialog).focus().select();
},
_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://') {
if (href.indexOf('@') > 0 && !/^(\w+:)|(\/\/)/i.test(href)) {
href = 'mailto:' + href;
}
this.attributes = { href: href };
title = $('#k-editor-link-title', element).val();
if (title) {
this.attributes.title = title;
}
if (textInput.is(':visible')) {
text = textInput.val();
if (!text && !this._initialText) {
this.attributes.innerHTML = href;
} else if (text && text !== this._initialText) {
this.attributes.innerHTML = 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._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://';
},
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 UnlinkTool = Tool.extend({
init: function (options) {
this.options = options;
this.finder = new InlineFormatFinder([{ tags: ['a'] }]);
Tool.fn.init.call(this, $.extend(options, { command: UnlinkCommand }));
},
initialize: function (ui, options) {
Tool.fn.initialize.call(this, ui, options);
ui.addClass('k-state-disabled');
},
update: function (ui, nodes) {
ui.toggleClass('k-state-disabled', !this.finder.isFormatted(nodes)).removeClass('k-state-hover');
}
});
extend(kendo.ui.editor, {
LinkFormatFinder: LinkFormatFinder,
LinkFormatter: LinkFormatter,
UnlinkCommand: UnlinkCommand,
LinkCommand: LinkCommand,
UnlinkTool: UnlinkTool
});
registerTool('createLink', new Tool({
key: 'K',
ctrl: true,
command: LinkCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Create Link'
})
}));
registerTool('unlink', new UnlinkTool({
key: 'K',
ctrl: true,
shift: true,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Remove Link'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/file', [
'kendo.filebrowser',
'editor/link'
], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, Command = Editor.Command, LinkFormatter = Editor.LinkFormatter, textNodes = RangeUtils.textNodes, keys = kendo.keys, KEDITORFILEURL = '#k-editor-file-url', 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;
range.deleteContents();
range.insertNode(file);
if (!file.nextSibling) {
dom.insertAfter(doc.createTextNode('\uFEFF'), file);
}
range.setStartAfter(file);
range.setEndAfter(file);
RangeUtils.selectRange(range);
return true;
} else {
dom.attr(file, attributes);
}
}
return false;
},
_dialogTemplate: function (showBrowser) {
return kendo.template('<div class="k-editor-dialog k-popup-edit-form k-edit-form-container">' + '# if (showBrowser) { #' + '<div class="k-filebrowser"></div>' + '# } #' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-url">#: messages.fileWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-file-url">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-title">#: messages.fileTitle #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-file-title">' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>')({
messages: this.editor.options.messages,
showBrowser: showBrowser
});
},
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, 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
};
function apply(e) {
var element = dialog.element, href = element.find(KEDITORFILEURL).val().replace(/ /g, '%20'), innerHTML = element.find(KEDITORFILETITLE).val();
that.attributes = {
href: href,
innerHTML: innerHTML !== '' ? innerHTML : href
};
applied = that.insertFile(file, range);
close(e);
if (that.change) {
that.change();
}
}
function close(e) {
e.preventDefault();
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;
}
dialog = this.createDialog(that._dialogTemplate(showBrowser), dialogOptions).toggleClass('k-filebrowser-dialog', showBrowser).find('.k-dialog-insert').click(apply).end().find('.k-dialog-close').click(close).end().find('.k-edit-field input').keydown(keyDown).end().find(KEDITORFILEURL).val(file ? file.getAttribute('href', 2) : 'http://').end().find(KEDITORFILETITLE).val(file ? file.title : '').end().data('kendoWindow');
if (showBrowser) {
that._fileBrowser = new kendo.ui.FileBrowser(dialog.element.find('.k-filebrowser'), extend({}, fileBrowser, {
change: function () {
dialog.element.find(KEDITORFILEURL).val(this.value());
},
apply: apply
}));
}
dialog.center().open();
dialog.element.find(KEDITORFILEURL).focus().select();
}
});
kendo.ui.editor.FileCommand = FileCommand;
registerTool('insertFile', new Editor.Tool({
command: FileCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Insert File'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/image', [
'kendo.imagebrowser',
'editor/link'
], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, 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('\uFEFF'), 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;
},
_dialogTemplate: function (showBrowser) {
return kendo.template('<div class="k-editor-dialog k-popup-edit-form k-edit-form-container">' + '# if (showBrowser) { #' + '<div class="k-filebrowser k-imagebrowser"></div>' + '# } #' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-url">#: messages.imageWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-url">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-title">#: messages.imageAltText #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-title">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-width">#: messages.imageWidth #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-width">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-height">#: messages.imageHeight #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-height">' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>')({
messages: this.editor.options.messages,
showBrowser: showBrowser
});
},
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, 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
};
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();
}
}
function close(e) {
e.preventDefault();
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;
}
dialog = this.createDialog(that._dialogTemplate(showBrowser), dialogOptions).toggleClass('k-filebrowser-dialog', showBrowser).find('.k-dialog-insert').click(apply).end().find('.k-dialog-close').click(close).end().find('.k-edit-field input').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().data('kendoWindow');
if (showBrowser) {
this._imageBrowser = new kendo.ui.ImageBrowser(dialog.element.find('.k-imagebrowser'), extend({}, imageBrowser, {
change: function () {
dialog.element.find(KEDITORIMAGEURL).val(this.value());
},
apply: apply
}));
}
dialog.center().open();
dialog.element.find(KEDITORIMAGEURL).focus().select();
}
});
kendo.ui.editor.ImageCommand = ImageCommand;
registerTool('insertImage', new Editor.Tool({
command: ImageCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Insert Image'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/components', ['editor/image'], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, DropDownList = kendo.ui.DropDownList, dom = kendo.ui.editor.Dom;
var SelectBox = DropDownList.extend({
init: function (element, options) {
var that = this;
DropDownList.fn.init.call(that, element, options);
if (kendo.support.mobileOS.ios) {
this._initSelectOverlay();
this.bind('dataBound', $.proxy(this._initSelectOverlay, this));
}
that.text(that.options.title);
that.bind('open', function () {
if (that.options.autoSize) {
var list = that.list, listWidth;
list.css({
whiteSpace: 'nowrap',
width: 'auto'
});
listWidth = list.width();
if (listWidth) {
listWidth += 20;
} else {
listWidth = that._listWidth;
}
list.css('width', listWidth + kendo.support.scrollbar());
that._listWidth = listWidth;
}
});
},
options: {
name: 'SelectBox',
index: -1
},
_initSelectOverlay: function () {
var selectBox = this;
var value = selectBox.value();
var view = this.dataSource.view();
var item;
var html = '';
var encode = kendo.htmlEncode;
for (var i = 0; i < view.length; i++) {
item = view[i];
html += '<option value=\'' + encode(item.value) + '\'';
if (item.value == value) {
html += ' selected';
}
html += '>' + encode(item.text) + '</option>';
}
var select = $('<select class=\'k-select-overlay\'>' + html + '</select>');
var wrapper = $(this.element).closest('.k-widget');
wrapper.next('.k-select-overlay').remove();
select.insertAfter(wrapper);
select.on('change', function () {
selectBox.value(this.value);
selectBox.trigger('change');
});
},
value: function (value) {
var that = this, result = DropDownList.fn.value.call(that, value);
if (value === undefined) {
return result;
}
if (!DropDownList.fn.value.call(that)) {
that.text(that.options.title);
}
},
decorate: function (body) {
var that = this, dataSource = that.dataSource, items = dataSource.data(), i, tag, className, style;
if (body) {
that.list.css('background-color', dom.getEffectiveBackground($(body)));
}
for (i = 0; i < items.length; i++) {
tag = items[i].tag || 'span';
className = items[i].className;
style = dom.inlineStyle(body, tag, { className: className });
style = style.replace(/"/g, '\'');
items[i].style = style + ';display:inline-block';
}
dataSource.trigger('change');
}
});
kendo.ui.plugin(SelectBox);
kendo.ui.editor.SelectBox = SelectBox;
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/indent', ['editor/components'], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, blockElements = dom.blockElements, BlockFormatFinder = Editor.BlockFormatFinder, BlockFormatter = Editor.BlockFormatter;
function indent(node, value) {
var isRtl = $(node).css('direction') == 'rtl', indentDirection = isRtl ? '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) {
var formatNodes = this.finder.findSuitable(nodes), targets = [], i, len, formatNode, parentList, sibling;
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));
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 {
var formatter = new BlockFormatter([{ tags: ['p'] }], { style: { marginLeft: 30 } });
formatter.apply(nodes);
}
},
remove: function (nodes) {
var formatNodes = this.finder.findSuitable(nodes), targetNode, i, len, list, listParent, siblings, formatNode, marginLeft;
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) {
options.formatter = {
toggle: function (range) {
new IndentFormatter().apply(RangeUtils.nodes(range));
}
};
Command.fn.init.call(this, options);
}
});
var OutdentCommand = Command.extend({
init: function (options) {
options.formatter = {
toggle: function (range) {
new IndentFormatter().remove(RangeUtils.nodes(range));
}
};
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, options) {
Tool.fn.initialize.call(this, ui, options);
ui.addClass('k-state-disabled');
},
update: function (ui, nodes) {
var suitable = this.finder.findSuitable(nodes), isOutdentable, listParentsCount, i, len;
for (i = 0, len = suitable.length; i < len; i++) {
isOutdentable = indent(suitable[i]);
if (!isOutdentable) {
listParentsCount = $(suitable[i]).parents('ul,ol').length;
isOutdentable = dom.is(suitable[i], 'li') && (listParentsCount > 1 || indent(suitable[i].parentNode)) || dom.ofType(suitable[i], [
'ul',
'ol'
]) && listParentsCount > 0;
}
if (isOutdentable) {
ui.removeClass('k-state-disabled');
return;
}
}
ui.addClass('k-state-disabled').removeClass('k-state-hover');
}
});
extend(Editor, {
IndentFormatter: IndentFormatter,
IndentCommand: IndentCommand,
OutdentCommand: OutdentCommand,
OutdentTool: OutdentTool
});
registerTool('indent', new Tool({
command: IndentCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Indent'
})
}));
registerTool('outdent', new OutdentTool({
command: OutdentCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Outdent'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/viewhtml', ['editor/indent'], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate;
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, messages = editor.options.messages, dialog = $(kendo.template(ViewHtmlCommand.template)(messages)).appendTo(document.body), content = ViewHtmlCommand.indent(editor.value()), textarea = '.k-editor-textarea';
function apply(e) {
editor.value(dialog.find(textarea).val());
close(e);
if (that.change) {
that.change();
}
editor.trigger('change');
}
function close(e) {
e.preventDefault();
dialog.data('kendoWindow').destroy();
editor.focus();
}
this.createDialog(dialog, {
title: messages.viewHtml,
close: close,
visible: false
}).find(textarea).val(content).end().find('.k-dialog-update').click(apply).end().find('.k-dialog-close').click(close).end().data('kendoWindow').center().open();
dialog.find(textarea).focus();
}
});
extend(ViewHtmlCommand, {
template: '<div class=\'k-editor-dialog k-popup-edit-form k-edit-form-container k-viewhtml-dialog\'>' + '<textarea class=\'k-editor-textarea k-input\'></textarea>' + '<div class=\'k-edit-buttons k-state-default\'>' + '<button class=\'k-dialog-update k-button k-primary\'>#: dialogUpdate #</button>' + '<button class=\'k-dialog-close k-button\'>#: dialogCancel #</button>' + '</div>' + '</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,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'View HTML'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/formatting', ['editor/viewhtml'], f);
}(function () {
(function ($) {
var kendo = window.kendo, Editor = kendo.ui.editor, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, 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 = 'kendoSelectBox';
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 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: tags,
attr: { className: item.className || '' }
}];
if ($.inArray(tags[0], dom.inlineElements) >= 0) {
formatter = new Editor.GreedyInlineFormatter(format);
} else {
formatter = new Editor.GreedyBlockFormatter(format);
}
return formatter;
}
});
},
initialize: function (ui, initOptions) {
var editor = initOptions.editor;
var options = this.options;
var toolName = options.name;
var that = this;
ui.width(options.width);
ui.kendoSelectBox({
dataTextField: 'text',
dataValueField: 'value',
dataSource: options.items || editor.options[toolName],
title: editor.options.messages[toolName],
autoSize: true,
change: function () {
var dataItem = this.dataItem();
if (dataItem) {
Tool.exec(editor, toolName, dataItem.toJSON());
}
},
dataBound: function () {
var i, items = this.dataSource.data();
for (i = 0; i < items.length; i++) {
items[i] = that.toFormattingItem(items[i]);
}
},
highlightFirst: false,
template: kendo.template('<span unselectable="on" style="display:block;#=(data.style||"")#">#:data.text#</span>')
});
ui.addClass('k-decorated').closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
},
getFormattingValue: function (items, nodes) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
var tag = item.tag || item.context || '';
var className = item.className ? '.' + item.className : '';
var selector = tag + className;
var element = $(nodes[0]).closest(selector)[0];
if (!element) {
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-state-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--) {
this.clean(nodes[c]);
}
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);
}
}
});
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: FormattingTool,
CleanFormatCommand: CleanFormatCommand
});
registerTool('formatting', new FormattingTool({
template: new ToolTemplate({
template: EditorUtils.dropDownListTemplate,
title: 'Format'
})
}));
registerTool('cleanFormatting', new Tool({
command: CleanFormatCommand,
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Clean formatting'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/toolbar', ['editor/formatting'], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo;
var ui = kendo.ui;
var editorNS = ui.editor;
var Widget = ui.Widget;
var extend = $.extend;
var proxy = $.proxy;
var keys = kendo.keys;
var NS = '.kendoEditor';
var EditorUtils = kendo.ui.editor.EditorUtils;
var ToolTemplate = kendo.ui.editor.ToolTemplate;
var Tool = kendo.ui.editor.Tool;
var OVERFLOWANCHOR = 'overflowAnchor';
var focusable = '.k-tool-group:visible a.k-tool:not(.k-state-disabled),' + '.k-tool.k-overflow-anchor,' + '.k-tool-group:visible .k-widget.k-colorpicker,' + '.k-tool-group:visible .k-selectbox,' + '.k-tool-group:visible .k-dropdown,' + '.k-tool-group:visible .k-combobox .k-input';
var OverflowAnchorTool = Tool.extend({
initialize: function (ui, options) {
ui.attr({ unselectable: 'on' });
var toolbar = options.editor.toolbar;
ui.on('click', $.proxy(function () {
this.overflowPopup.toggle();
}, toolbar));
},
options: { name: OVERFLOWANCHOR },
command: $.noop,
update: $.noop,
destroy: $.noop
});
EditorUtils.registerTool(OVERFLOWANCHOR, new OverflowAnchorTool({
key: '',
ctrl: true,
template: new ToolTemplate({ template: EditorUtils.overflowAnchorTemplate })
}));
var Toolbar = Widget.extend({
init: function (element, options) {
var that = this;
options = extend({}, options, { name: 'EditorToolbar' });
Widget.fn.init.call(that, element, options);
if (options.popup) {
that._initPopup();
}
if (options.resizable && options.resizable.toolbar) {
that._resizeHandler = kendo.onResize(function () {
that.resize();
});
that.element.addClass('k-toolbar-resizable');
}
},
events: ['execute'],
groups: {
basic: [
'bold',
'italic',
'underline',
'strikethrough'
],
scripts: [
'subscript',
'superscript'
],
alignment: [
'justifyLeft',
'justifyCenter',
'justifyRight',
'justifyFull'
],
links: [
'insertImage',
'insertFile',
'createLink',
'unlink'
],
lists: [
'insertUnorderedList',
'insertOrderedList',
'indent',
'outdent'
],
tables: [
'createTable',
'addColumnLeft',
'addColumnRight',
'addRowAbove',
'addRowBelow',
'deleteRow',
'deleteColumn'
],
advanced: [
'viewHtml',
'cleanFormatting',
'print',
'pdf'
],
fonts: [
'fontName',
'fontSize'
],
colors: [
'foreColor',
'backColor'
]
},
overflowFlaseTools: [
'formatting',
'fontName',
'fontSize',
'foreColor',
'backColor',
'insertHtml'
],
_initPopup: function () {
this.window = $(this.element).wrap('<div class=\'editorToolbarWindow k-header\' />').parent().prepend('<button class=\'k-button k-button-bare k-editortoolbar-dragHandle\'><span class=\'k-icon k-i-move\' /></button>').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('.k-icon')) {
e.preventDefault();
}
}).data('kendoWindow');
},
_toggleOverflowStyles: function (element, show) {
element.find('li').toggleClass('k-item k-state-default', show).find('.k-tool:not(.k-state-disabled),.k-overflow-button').toggleClass('k-overflow-button k-button', show);
},
_initOverflowPopup: function (ui) {
var that = this;
var popupTemplate = '<ul class=\'k-editor-overflow-popup k-overflow-container k-list-container\'></ul>';
that.overflowPopup = $(popupTemplate).appendTo('body').kendoPopup({
anchor: ui,
origin: 'bottom right',
position: 'top right',
copyAnchorStyles: false,
open: function (e) {
if (this.element.is(':empty')) {
e.preventDefault();
}
that._toggleOverflowStyles(this.element, true);
},
activate: proxy(that.focusOverflowPopup, that)
}).data('kendoPopup');
},
items: function () {
var isResizable = this.options.resizable && this.options.resizable.toolbar, popup, result;
result = this.element.children().find('> *, select');
if (isResizable) {
popup = this.overflowPopup;
result = result.add(popup.element.children().find('> *'));
}
return result;
},
focused: function () {
return this.element.find('.k-state-focused').length > 0;
},
toolById: function (name) {
var id, tools = this.tools;
for (id in tools) {
if (id.toLowerCase() == name) {
return tools[id];
}
}
},
toolGroupFor: function (toolName) {
var i, groups = this.groups;
if (this.isCustomTool(toolName)) {
return 'custom';
}
for (i in groups) {
if ($.inArray(toolName, groups[i]) >= 0) {
return i;
}
}
},
bindTo: function (editor) {
var that = this, window = that.window;
if (that._editor) {
that._editor.unbind('select', proxy(that.resize, that));
}
that._editor = editor;
if (that.options.resizable && that.options.resizable.toolbar) {
editor.options.tools.push(OVERFLOWANCHOR);
}
that.tools = that.expandTools(editor.options.tools);
that.render();
that.element.find('.k-combobox .k-input').keydown(function (e) {
var combobox = $(this).closest('.k-combobox').data('kendoComboBox'), key = e.keyCode;
if (key == keys.RIGHT || key == keys.LEFT) {
combobox.close();
} else if (key == keys.DOWN) {
if (!combobox.dropDown.isOpened()) {
e.stopImmediatePropagation();
combobox.open();
}
}
});
that._attachEvents();
that.items().each(function initializeTool() {
var toolName = that._toolName(this), tool = toolName !== 'more' ? that.tools[toolName] : that.tools.overflowAnchor, options = tool && tool.options, messages = editor.options.messages, description = options && options.tooltip || messages[toolName], ui = $(this);
if (!tool || !tool.initialize) {
return;
}
if (toolName == 'fontSize' || toolName == 'fontName') {
var inheritText = messages[toolName + 'Inherit'];
ui.find('input').val(inheritText).end().find('span.k-input').text(inheritText).end();
}
tool.initialize(ui, {
title: that._appendShortcutSequence(description, tool),
editor: that._editor
});
ui.closest('.k-widget', that.element).addClass('k-editor-widget');
ui.closest('.k-colorpicker', that.element).next('.k-colorpicker').addClass('k-editor-widget');
});
editor.bind('select', proxy(that.resize, that));
that.update();
if (window) {
window.wrapper.css({
top: '',
left: '',
width: ''
});
}
},
show: function () {
var that = this, window = that.window, editorOptions = that.options.editor, wrapper, editorElement, editorOffset;
if (window) {
wrapper = window.wrapper;
editorElement = editorOptions.element;
if (!wrapper.is(':visible') || !that.window.options.visible) {
if (!wrapper[0].style.width) {
wrapper.width(editorElement.outerWidth() - parseInt(wrapper.css('border-left-width'), 10) - parseInt(wrapper.css('border-right-width'), 10));
}
if (!window._moved) {
editorOffset = editorElement.offset();
wrapper.css({
top: Math.max(0, parseInt(editorOffset.top, 10) - wrapper.outerHeight() - parseInt(that.window.element.css('padding-bottom'), 10)),
left: Math.max(0, parseInt(editorOffset.left, 10))
});
}
window.open();
}
}
},
hide: function () {
if (this.window) {
this.window.close();
}
},
focus: function () {
var TABINDEX = 'tabIndex';
var element = this.element;
var tabIndex = this._editor.element.attr(TABINDEX);
element.attr(TABINDEX, tabIndex || 0).focus().find(focusable).first().focus();
if (!tabIndex && tabIndex !== 0) {
element.removeAttr(TABINDEX);
}
},
focusOverflowPopup: function () {
var TABINDEX = 'tabIndex';
var element = this.overflowPopup.element;
var tabIndex = this._editor.element.attr(TABINDEX);
element.closest('.k-animation-container').addClass('k-overflow-wrapper');
element.attr(TABINDEX, tabIndex || 0).find(focusable).first().focus();
if (!tabIndex && tabIndex !== 0) {
element.removeAttr(TABINDEX);
}
},
_appendShortcutSequence: function (localizedText, tool) {
if (!tool.key) {
return localizedText;
}
var res = localizedText + ' (';
if (tool.ctrl) {
res += 'Ctrl + ';
}
if (tool.shift) {
res += 'Shift + ';
}
if (tool.alt) {
res += 'Alt + ';
}
res += tool.key + ')';
return res;
},
_nativeTools: [
'insertLineBreak',
'insertParagraph',
'redo',
'undo'
],
tools: {},
isCustomTool: function (toolName) {
return !(toolName in kendo.ui.Editor.defaultTools);
},
expandTools: function (tools) {
var currentTool, i, nativeTools = this._nativeTools, options, defaultTools = kendo.deepExtend({}, kendo.ui.Editor.defaultTools), result = {}, name;
for (i = 0; i < tools.length; i++) {
currentTool = tools[i];
name = currentTool.name;
if ($.isPlainObject(currentTool)) {
if (name && defaultTools[name]) {
result[name] = extend({}, defaultTools[name]);
extend(result[name].options, currentTool);
} else {
options = extend({
cssClass: 'k-i-custom',
type: 'button',
title: ''
}, currentTool);
if (!options.name) {
options.name = 'custom';
}
options.cssClass = 'k-' + (options.name == 'custom' ? 'i-custom' : options.name);
if (!options.template && options.type == 'button') {
options.template = editorNS.EditorUtils.buttonTemplate;
options.title = options.title || options.tooltip;
}
result[name] = { options: options };
}
} else if (defaultTools[currentTool]) {
result[currentTool] = defaultTools[currentTool];
}
}
for (i = 0; i < nativeTools.length; i++) {
if (!result[nativeTools[i]]) {
result[nativeTools[i]] = defaultTools[nativeTools[i]];
}
}
return result;
},
render: function () {
var that = this, tools = that.tools, options, template, toolElement, toolName, editorElement = that._editor.element, element = that.element.empty(), groupName, newGroupName, toolConfig = that._editor.options.tools, browser = kendo.support.browser, group, i, groupPosition = 0, resizable = that.options.resizable && that.options.resizable.toolbar, overflowFlaseTools = this.overflowFlaseTools;
function stringify(template) {
var result;
if (template.getHtml) {
result = template.getHtml();
} else {
if (!$.isFunction(template)) {
template = kendo.template(template);
}
result = template(options);
}
return $.trim(result);
}
function endGroup() {
if (group.children().length) {
if (resizable) {
group.data('position', groupPosition);
groupPosition++;
}
group.appendTo(element);
}
}
function startGroup(toolName) {
if (toolName !== OVERFLOWANCHOR) {
group = $('<li class=\'k-tool-group\' role=\'presentation\' />');
group.data('overflow', $.inArray(toolName, overflowFlaseTools) === -1 ? true : false);
} else {
group = $('<li class=\'k-overflow-tools\' />');
}
}
element.empty();
if (toolConfig.length) {
toolName = toolConfig[0].name || toolConfig[0];
}
startGroup(toolName, overflowFlaseTools);
for (i = 0; i < toolConfig.length; i++) {
toolName = toolConfig[i].name || toolConfig[i];
options = tools[toolName] && tools[toolName].options;
if (!options && $.isPlainObject(toolName)) {
options = toolName;
}
template = options && options.template;
if (toolName == 'break') {
endGroup();
$('<li class=\'k-row-break\' />').appendTo(that.element);
startGroup(toolName, overflowFlaseTools);
}
if (!template) {
continue;
}
newGroupName = that.toolGroupFor(toolName);
if (groupName != newGroupName || toolName == OVERFLOWANCHOR) {
endGroup();
startGroup(toolName, overflowFlaseTools);
groupName = newGroupName;
}
template = stringify(template);
toolElement = $(template).appendTo(group);
if (newGroupName == 'custom') {
endGroup();
startGroup(toolName, overflowFlaseTools);
}
if (options.exec && toolElement.hasClass('k-tool')) {
toolElement.click(proxy(options.exec, editorElement[0]));
}
}
endGroup();
$(that.element).children(':has(> .k-tool)').addClass('k-button-group');
if (that.options.popup && browser.msie && browser.version < 9) {
that.window.wrapper.find('*').attr('unselectable', 'on');
}
that.updateGroups();
if (resizable) {
that._initOverflowPopup(that.element.find('.k-overflow-anchor'));
}
that.angular('compile', function () {
return { elements: that.element };
});
},
updateGroups: function () {
$(this.element).children().each(function () {
$(this).children().filter(function () {
return !$(this).hasClass('k-state-disabled');
}).removeClass('k-group-end').first().addClass('k-group-start').end().last().addClass('k-group-end').end();
});
},
decorateFrom: function (body) {
this.items().filter('.k-decorated').each(function () {
var selectBox = $(this).data('kendoSelectBox');
if (selectBox) {
selectBox.decorate(body);
}
});
},
destroy: function () {
Widget.fn.destroy.call(this);
var id, tools = this.tools;
for (id in tools) {
if (tools[id].destroy) {
tools[id].destroy();
}
}
if (this.window) {
this.window.destroy();
}
if (this._resizeHandler) {
kendo.unbindResize(this._resizeHandler);
}
if (this.overflowPopup) {
this.overflowPopup.destroy();
}
},
_attachEvents: function () {
var that = this, buttons = '[role=button].k-tool', enabledButtons = buttons + ':not(.k-state-disabled)', disabledButtons = buttons + '.k-state-disabled', popupElement = that.overflowPopup ? that.overflowPopup.element : $([]);
that.element.add(popupElement).off(NS).on('mouseenter' + NS, enabledButtons, function () {
$(this).addClass('k-state-hover');
}).on('mouseleave' + NS, enabledButtons, function () {
$(this).removeClass('k-state-hover');
}).on('mousedown' + NS, buttons, function (e) {
e.preventDefault();
}).on('keydown' + NS, focusable, function (e) {
var current = this;
var resizable = that.options.resizable && that.options.resizable.toolbar;
var focusElement, currentContainer, keyCode = e.keyCode;
function move(direction, container, constrain) {
var tools = container.find(focusable);
var index = tools.index(current) + direction;
if (constrain) {
index = Math.max(0, Math.min(tools.length - 1, index));
}
return tools[index];
}
if (keyCode == keys.RIGHT || keyCode == keys.LEFT) {
if (!$(current).hasClass('.k-dropdown')) {
focusElement = move(keyCode == keys.RIGHT ? 1 : -1, that.element, true);
}
} else if (resizable && (keyCode == keys.UP || keyCode == keys.DOWN)) {
focusElement = move(keyCode == keys.DOWN ? 1 : -1, that.overflowPopup.element, true);
} else if (keyCode == keys.ESC) {
if (that.overflowPopup.visible()) {
that.overflowPopup.close();
}
focusElement = that._editor;
} else if (keyCode == keys.TAB && !(e.ctrlKey || e.altKey)) {
if (resizable) {
currentContainer = $(current.parentElement).hasClass('k-overflow-tool-group') ? that.overflowPopup.element : that.element;
} else {
currentContainer = that.element;
}
if (e.shiftKey) {
focusElement = move(-1, currentContainer);
} else {
focusElement = move(1, currentContainer);
if (!focusElement) {
focusElement = that._editor;
}
}
}
if (focusElement) {
e.preventDefault();
focusElement.focus();
}
}).on('click' + NS, enabledButtons, function (e) {
var button = $(this);
e.preventDefault();
e.stopPropagation();
button.removeClass('k-state-hover');
if (!button.is('[data-popup]')) {
that._editor.exec(that._toolName(this));
}
}).on('click' + NS, disabledButtons, function (e) {
e.preventDefault();
});
},
_toolName: function (element) {
if (!element) {
return;
}
var className = element.className;
if (/k-tool\b/i.test(className)) {
className = element.firstChild.className;
}
var tool = $.grep(className.split(' '), function (x) {
return !/^k-(widget|tool|tool-icon|icon|state-hover|header|combobox|dropdown|selectbox|colorpicker)$/i.test(x);
});
return tool[0] ? tool[0].substring(tool[0].lastIndexOf('-') + 1) : 'custom';
},
refreshTools: function () {
var that = this, editor = that._editor, range = editor.getRange(), nodes = kendo.ui.editor.RangeUtils.textNodes(range);
if (!nodes.length) {
nodes = [range.startContainer];
}
that.items().each(function () {
var tool = that.tools[that._toolName(this)];
if (tool && tool.update) {
tool.update($(this), nodes);
}
});
this.update();
},
update: function () {
this.updateGroups();
},
_resize: function (e) {
var containerWidth = e.width;
var resizable = this.options.resizable && this.options.resizable.toolbar;
var popup = this.overflowPopup;
this.refreshTools();
if (!resizable) {
return;
}
if (popup.visible()) {
popup.close(true);
}
this._refreshWidths();
this._shrink(containerWidth);
this._stretch(containerWidth);
this._toggleOverflowStyles(this.element, false);
this._toggleOverflowStyles(this.overflowPopup.element, true);
this.element.children('li.k-overflow-tools').css('visibility', popup.element.is(':empty') ? 'hidden' : 'visible');
},
_refreshWidths: function () {
this.element.children('li').each(function (idx, element) {
var group = $(element);
group.data('outerWidth', group.outerWidth(true));
});
},
_shrink: function (width) {
var group, visibleGroups;
if (width < this._groupsWidth()) {
visibleGroups = this._visibleGroups().filter(':not(.k-overflow-tools)');
for (var i = visibleGroups.length - 1; i >= 0; i--) {
group = visibleGroups.eq(i);
if (width > this._groupsWidth()) {
break;
} else {
this._hideGroup(group);
}
}
}
},
_stretch: function (width) {
var group, hiddenGroups;
if (width > this._groupsWidth()) {
hiddenGroups = this._hiddenGroups();
for (var i = 0; i < hiddenGroups.length; i++) {
group = hiddenGroups.eq(i);
if (width < this._groupsWidth() || !this._showGroup(group, width)) {
break;
}
}
}
},
_hiddenGroups: function () {
var popup = this.overflowPopup;
var hiddenGroups = this.element.children('li.k-tool-group').filter(':hidden');
hiddenGroups = hiddenGroups.add(popup.element.children('li'));
hiddenGroups.sort(function (a, b) {
return $(a).data('position') > $(b).data('position') ? 1 : -1;
});
return hiddenGroups;
},
_visibleGroups: function () {
return this.element.children('li.k-tool-group, li.k-overflow-tools').filter(':visible');
},
_groupsWidth: function () {
var width = 0;
this._visibleGroups().each(function () {
width += $(this).data('outerWidth');
});
return Math.ceil(width);
},
_hideGroup: function (group) {
if (group.data('overflow')) {
var popup = this.overflowPopup;
group.detach().prependTo(popup.element).addClass('k-overflow-tool-group');
} else {
group.hide();
}
},
_showGroup: function (group, width) {
var position, previous;
if (group.length && width > this._groupsWidth() + group.data('outerWidth')) {
if (group.hasClass('k-overflow-tool-group')) {
position = group.data('position');
if (position === 0) {
group.detach().prependTo(this.element);
} else {
previous = this.element.children().filter(function (idx, element) {
return $(element).data('position') === position - 1;
});
group.detach().insertAfter(previous);
}
group.removeClass('k-overflow-tool-group');
} else {
group.show();
}
return true;
}
return false;
}
});
$.extend(editorNS, { Toolbar: Toolbar });
}(window.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('editor/tables', ['editor/toolbar'], f);
}(function () {
(function ($, undefined) {
var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, Command = Editor.Command, NS = '.kendoEditor', ACTIVESTATE = 'k-state-active', SELECTEDSTATE = 'k-state-selected', Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, InsertHtmlCommand = Editor.InsertHtmlCommand, BlockFormatFinder = Editor.BlockFormatFinder, registerTool = Editor.EditorUtils.registerTool;
var editableCell = '<td>' + Editor.emptyElementContent + '</td>';
var tableFormatFinder = new BlockFormatFinder([{ tags: ['table'] }]);
var TableCommand = InsertHtmlCommand.extend({
_tableHtml: function (rows, columns) {
rows = rows || 1;
columns = columns || 1;
return '<table class=\'k-table\' data-last>' + new Array(rows + 1).join('<tr>' + new Array(columns + 1).join(editableCell) + '</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);
options.postProcess = this.postProcess;
InsertHtmlCommand.fn.exec.call(this);
}
});
var PopupTool = Tool.extend({
initialize: function (ui, options) {
Tool.fn.initialize.call(this, ui, options);
var popup = $(this.options.popupTemplate).appendTo('body').kendoPopup({
anchor: ui,
copyAnchorStyles: false,
open: proxy(this._open, this),
activate: proxy(this._activate, this),
close: proxy(this._close, this)
}).data('kendoPopup');
ui.click(proxy(this._toggle, this)).keydown(proxy(this._keydown, this));
this._editor = options.editor;
this._popup = popup;
},
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 keys = kendo.keys;
var key = e.keyCode;
if (key == keys.DOWN && e.altKey) {
this._popup.open();
} else if (key == keys.ESC) {
this._popup.close();
}
},
_toggle: function (e) {
var button = $(e.target).closest('.k-tool');
if (!button.hasClass('k-state-disabled')) {
this.popup().toggle();
}
},
update: function (ui) {
var popup = this.popup();
if (popup.wrapper && popup.wrapper.css('display') == 'block') {
popup.close();
}
ui.removeClass('k-state-hover');
},
destroy: function () {
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\'>' + new Array(this.cols * this.rows + 1).join('<span class=\'k-ct-cell k-state-disabled\' />') + '<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.on('mousemove' + NS, function (e) {
that._setTableSize(tableFromLocation(e));
}).on('mouseleave' + NS, function () {
that._setTableSize();
}).on('mouseup' + NS, function (e) {
that._exec(tableFromLocation(e));
});
},
_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.dialogCancel);
cells.removeClass(SELECTEDSTATE);
}
},
_keydown: function (e) {
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-state-selected').last().index(), 0);
var selectedRows = Math.floor(focus / this.cols);
var selectedColumns = focus % this.cols;
var changed = false;
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--;
}
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) {
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.dialogCancel).end().find('.k-ct-cell').removeClass(SELECTEDSTATE);
},
_close: function () {
PopupTool.fn._close.call(this);
this.popup().element.off(NS);
},
update: function (ui, nodes) {
var isFormatted;
PopupTool.fn.update.call(this, ui);
isFormatted = tableFormatFinder.isFormatted(nodes);
ui.toggleClass('k-state-disabled', isFormatted);
}
});
var InsertRowCommand = Command.extend({
exec: function () {
var range = this.lockRange(true), td = range.endContainer, cellCount, row, newRow;
while (dom.name(td) != 'td') {
td = td.parentNode;
}
row = td.parentNode;
cellCount = row.children.length;
newRow = row.cloneNode(true);
for (var i = 0; i < row.cells.length; i++) {
newRow.cells[i].innerHTML = Editor.emptyElementContent;
}
if (this.options.position == 'before') {
dom.insertBefore(newRow, row);
} else {
dom.insertAfter(newRow, row);
}
this.releaseRange(range);
}
});
var InsertColumnCommand = Command.extend({
exec: function () {
var range = this.lockRange(true), td = dom.closest(range.endContainer, 'td'), table = dom.closest(td, 'table'), columnIndex, i, rows = table.rows, cell, newCell, position = this.options.position;
columnIndex = dom.findNodeIndex(td, true);
for (i = 0; i < rows.length; i++) {
cell = rows[i].cells[columnIndex];
newCell = cell.cloneNode();
newCell.innerHTML = Editor.emptyElementContent;
if (position == 'before') {
dom.insertBefore(newCell, cell);
} else {
dom.insertAfter(newCell, cell);
}
}
this.releaseRange(range);
}
});
var DeleteRowCommand = Command.extend({
exec: function () {
var range = this.lockRange();
var rows = RangeUtils.mapAll(range, function (node) {
return $(node).closest('tr')[0];
});
var table = dom.closest(rows[0], 'table');
var focusElement;
if (table.rows.length <= rows.length) {
focusElement = dom.next(table);
if (!focusElement || dom.insignificant(focusElement)) {
focusElement = dom.prev(table);
}
dom.remove(table);
} else {
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
dom.removeTextSiblings(row);
focusElement = dom.next(row) || dom.prev(row);
focusElement = focusElement.cells[0];
dom.remove(row);
}
}
if (focusElement) {
range.setStart(focusElement, 0);
range.collapse(true);
this.editor.selectRange(range);
}
}
});
var DeleteColumnCommand = Command.extend({
exec: function () {
var range = this.lockRange(), td = dom.closest(range.endContainer, 'td'), table = dom.closest(td, 'table'), rows = table.rows, columnIndex = dom.findNodeIndex(td, true), columnCount = rows[0].cells.length, focusElement, i;
if (columnCount == 1) {
focusElement = dom.next(table);
if (!focusElement || dom.insignificant(focusElement)) {
focusElement = dom.prev(table);
}
dom.remove(table);
} else {
dom.removeTextSiblings(td);
focusElement = dom.next(td) || dom.prev(td);
for (i = 0; i < rows.length; i++) {
dom.remove(rows[i].cells[columnIndex]);
}
}
if (focusElement) {
range.setStart(focusElement, 0);
range.collapse(true);
this.editor.selectRange(range);
}
}
});
var TableModificationTool = Tool.extend({
command: function (options) {
options = extend(options, this.options);
if (options.action == 'delete') {
if (options.type == 'row') {
return new DeleteRowCommand(options);
} else {
return new DeleteColumnCommand(options);
}
} else {
if (options.type == 'row') {
return new InsertRowCommand(options);
} else {
return new InsertColumnCommand(options);
}
}
},
initialize: function (ui, options) {
Tool.fn.initialize.call(this, ui, options);
ui.addClass('k-state-disabled');
},
update: function (ui, nodes) {
var isFormatted = !tableFormatFinder.isFormatted(nodes);
ui.toggleClass('k-state-disabled', isFormatted);
}
});
extend(kendo.ui.editor, {
PopupTool: PopupTool,
TableCommand: TableCommand,
InsertTableTool: InsertTableTool,
TableModificationTool: TableModificationTool,
InsertRowCommand: InsertRowCommand,
InsertColumnCommand: InsertColumnCommand,
DeleteRowCommand: DeleteRowCommand,
DeleteColumnCommand: DeleteColumnCommand
});
registerTool('createTable', new InsertTableTool({
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
popup: true,
title: 'Create table'
})
}));
registerTool('addColumnLeft', new TableModificationTool({
type: 'column',
position: 'before',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Add column on the left'
})
}));
registerTool('addColumnRight', new TableModificationTool({
type: 'column',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Add column on the right'
})
}));
registerTool('addRowAbove', new TableModificationTool({
type: 'row',
position: 'before',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Add row above'
})
}));
registerTool('addRowBelow', new TableModificationTool({
type: 'row',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Add row below'
})
}));
registerTool('deleteRow', new TableModificationTool({
type: 'row',
action: 'delete',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Delete row'
})
}));
registerTool('deleteColumn', new TableModificationTool({
type: 'column',
action: 'delete',
template: new ToolTemplate({
template: EditorUtils.buttonTemplate,
title: 'Delete column'
})
}));
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.editor', [
'kendo.combobox',
'kendo.dropdownlist',
'kendo.resizable',
'kendo.window',
'kendo.colorpicker',
'kendo.imagebrowser',
'util/undoredostack',
'editor/main',
'editor/dom',
'editor/serializer',
'editor/range',
'editor/system',
'editor/inlineformat',
'editor/formatblock',
'editor/linebreak',
'editor/lists',
'editor/link',
'editor/file',
'editor/image',
'editor/components',
'editor/indent',
'editor/viewhtml',
'editor/formatting',
'editor/toolbar',
'editor/tables'
], f);
}(function () {
var __meta__ = {
id: 'editor',
name: 'Editor',
category: 'web',
description: 'Rich text editor component',
depends: [
'combobox',
'dropdownlist',
'window',
'colorpicker'
],
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-pdf-export',
name: 'PDF export',
description: 'Export Editor content as PDF',
depends: [
'pdf',
'drawing'
]
}
]
};
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));