@progress/kendo-angular-editor
Version:
Kendo UI Editor for Angular
1,189 lines (1,176 loc) • 325 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import * as i0 from '@angular/core';
import { Injectable, Inject, Optional, Component, Input, ViewChild, InjectionToken, Directive, EventEmitter, Output, forwardRef, ElementRef, isDevMode, ViewContainerRef, HostBinding, ContentChild, NgModule } from '@angular/core';
import { NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault, NgStyle, NgFor } from '@angular/common';
import * as i3 from '@angular/forms';
import { FormControl, Validators, FormGroup, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject, BehaviorSubject, zip, fromEvent, interval } from 'rxjs';
import { take, map, filter as filter$1, concatMap, takeUntil } from 'rxjs/operators';
import * as i1$2 from '@progress/kendo-angular-toolbar';
import { ToolBarToolComponent, ToolBarComponent, ToolBarButtonGroupComponent, ToolBarButtonComponent, KENDO_TOOLBAR } from '@progress/kendo-angular-toolbar';
import * as i1$1 from '@progress/kendo-angular-dialog';
import { DialogContentBase, DialogTitleBarComponent, DialogActionsComponent, DialogContainerService, DialogService, WindowService, WindowContainerService } from '@progress/kendo-angular-dialog';
import { isDocumentAvailable, guid, shouldShowValidationUI, hasObservers, KendoInput, WatermarkOverlayComponent, isPresent as isPresent$1, Keys, ResizeBatchService } from '@progress/kendo-angular-common';
import { marks as marks$1, nodes as nodes$1, Schema, createTable, insertNode, alignBlocks, alignRemoveRules, expandToWordWrap, toggleInlineFormat, bold, cleanFormatting, applyLink, applyInlineStyle, insertText, italic, strikethrough, subscript, superscript, underline, removeLink, link, selectAll, isAligned, alignCenterRules, alignJustifyRules, alignLeftRules, alignRightRules, formatBlockElements, getHtml, indent, insertImage, toggleOrderedList, toggleUnorderedList, outdent, redo, setHtml, undo, blockquote, addColumnBefore, addColumnAfter, addRowBefore, addRowAfter, deleteRow, deleteColumn, mergeCells, splitCell, deleteTable, hasMark, activeNode, canIndentAsListItem, canBeIndented, indentRules, hasNode, canOutdentAsListItem, outdentRules, isIndented, getActiveMarks, expandSelection, getSelectionText as getSelectionText$1, getNodeFromSelection, getMark, removeComments, sanitize, removeAttribute, sanitizeStyleAttr, sanitizeClassAttr, TextSelection, parseContent, Plugin, PluginKey, history, keymap, buildListKeymap, buildKeymap, baseKeymap, gapCursor, imageResizing, tableResizing, tableEditing, caretColor, cspFix, placeholder, EditorState, EditorView, pasteCleanup, AllSelection } from '@progress/kendo-editor-common';
export { AllSelection, CellSelection, Decoration, DecorationSet, EditorState, EditorView, InputRule, Mark, MarkType, Node, NodeSelection, NodeType, Plugin, PluginKey, Schema, TextSelection, Transaction, baseKeymap, dropCursor, flattenNestedSpans, gapCursor, history, inputRules, keymap, tableNodes, textblockTypeInputRule, wrappingInputRule } from '@progress/kendo-editor-common';
import { validatePackage } from '@progress/kendo-licensing';
import * as i1 from '@progress/kendo-angular-l10n';
import { LocalizationService, L10N_PREFIX, RTL, ComponentMessages } from '@progress/kendo-angular-l10n';
import { TextAreaComponent, FormFieldComponent, TextBoxComponent, CheckBoxDirective, ColorPickerComponent } from '@progress/kendo-angular-inputs';
import { ButtonComponent } from '@progress/kendo-angular-buttons';
import { LabelComponent, LabelDirective } from '@progress/kendo-angular-label';
import { alignCenterIcon, alignJustifyIcon, alignLeftIcon, alignRightIcon, dropletIcon, rightDoubleQuotesIcon, boldIcon, clearCssIcon, linkIcon, foregroundColorIcon, indentIcon, fileAddIcon, fileImageIcon, listOrderedIcon, listUnorderedIcon, italicIcon, outdentIcon, printIcon, redoIcon, selectAllIcon, strikethroughIcon, subscriptIcon, supscriptIcon, underlineIcon, undoIcon, unlinkIcon, codeSnippetIcon, tableAddIcon, tableColumnInsertLeftIcon, tableColumnInsertRightIcon, tableRowInsertAboveIcon, tableRowInsertBelowIcon, tableRowDeleteIcon, tableColumnDeleteIcon, cellsMergeIcon, cellSplitHorizontallyIcon, tableDeleteIcon, applyFormatIcon, fontSizeIcon, fontFamilyIcon, tableWizardIcon } from '@progress/kendo-svg-icons';
import { IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons';
import { DropDownListComponent, ItemTemplateDirective } from '@progress/kendo-angular-dropdowns';
import * as i2 from '@progress/kendo-angular-popup';
import { PopupService } from '@progress/kendo-angular-popup';
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-editor',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 1745304237,
version: '18.5.2',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/**
* @hidden
*/
const hasAttrs = (attrs, exclude) => {
for (const attr in attrs) {
if (attr && attrs[attr] !== null && attr !== exclude) {
return true;
}
}
return false;
};
/**
* @hidden
*/
const getAttrs = (attrs, exclude) => {
const result = {};
for (const attr in attrs) {
if (attr && attrs[attr] !== null && attr !== exclude && attr !== 'constructor' && attr !== '__proto__' && attr !== 'prototype') {
result[attr] = attrs[attr];
}
}
return result;
};
/**
* @hidden
*/
const getAttributes = (dom) => {
const result = {};
const attributes = dom.attributes;
for (let i = 0; i < attributes.length; i++) {
const attr = attributes[i];
result[attr.name] = attr.value;
}
return result;
};
/**
* @hidden
*/
const serializeDOMAttrs = (el) => Array.from(el.attributes)
.reduce((acc, curr) => Object.assign({}, acc, { [curr.name]: curr.value }), {});
/**
* @hidden
*/
const commonAttributes = () => {
return {
...createDefaultAttributes(['class', 'id', 'style'])
};
};
/**
* @hidden
*/
const createDefaultAttributes = (attrs = []) => {
return {
...attrs.reduce((acc, curr) => ({ ...acc, [curr]: { default: null } }), {})
};
};
/**
* @hidden
*/
const hole = 0;
/**
* @hidden
*/
const isSchemaNode = (schemaNodeName) => (node) => node.type.name === schemaNodeName;
/**
* @hidden
*/
const isTable = isSchemaNode('table');
/**
* @hidden
*/
const isTableBody = isSchemaNode('table_body');
/**
* @hidden
*/
const isTableHead = isSchemaNode('table_head');
/**
* @hidden
*/
const isTableFoot = isSchemaNode('table_foot');
/**
* @hidden
*/
const isTableRow = isSchemaNode('table_row');
/**
* @hidden
*/
const isTableCell = isSchemaNode('table_cell');
/**
* @hidden
*/
const isTableHeaderCell = isSchemaNode('table_header');
const createSemanticNode = (tagName) => ({
// Uncaught SyntaxError: Mixing inline and block content (in content expression '(block | inline)*')
// content: '(block | inline)*',
content: 'block*',
group: 'block',
attrs: {
...commonAttributes()
},
parseDOM: [{
tag: tagName,
getAttrs: getAttributes
}],
toDOM: node => hasAttrs(node.attrs) ? [tagName, getAttrs(node.attrs), hole] : [tagName, hole]
});
/**
* @hidden
*/
const semanticTagNames = ['article', 'main', 'nav', 'header', 'footer', 'aside', 'section'];
/**
* @hidden
*/
const semanticNodes = semanticTagNames.reduce((acc, curr) => Object.assign(acc, { [curr]: createSemanticNode(curr) }), {});
/**
* @hidden
*/
const marks = marks$1;
const nodes = Object.assign(nodes$1, semanticNodes);
/**
* @hidden
*/
const schema = new Schema({
marks,
nodes
});
/**
* @hidden
*/
const insertTable = (attrs) => (state, dispatch) => {
const newTable = createTable(state.schema.nodes, attrs.rows, attrs.cols);
if (newTable) {
insertNode(newTable, true)(state, dispatch);
}
};
const alignRemove = (state, dispatch) => alignBlocks(alignRemoveRules)(state, dispatch);
const inlineCommand = {
bold: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...bold, applyToWord }),
cleanFormatting: (options) => cleanFormatting(options),
createLink: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: attrs.value, applyToWord: attrs.applyToWord }),
fontFamily: attrs => expandToWordWrap(applyInlineStyle, { style: 'font-family', value: attrs.value, applyToWord: attrs.applyToWord }),
fontSize: attrs => expandToWordWrap(applyInlineStyle, { style: 'font-size', value: attrs.value, applyToWord: attrs.applyToWord }),
insertFile: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: attrs, applyToWord: attrs.applyToWord }),
insertText: text => insertText(text),
italic: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...italic, applyToWord }),
strikethrough: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...strikethrough, applyToWord }),
subscript: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...subscript, applyToWord }),
superscript: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...superscript, applyToWord }),
underline: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...underline, applyToWord }),
unlink: () => removeLink(link),
foreColor: attrs => expandToWordWrap(applyInlineStyle, { style: 'color', value: attrs.value, applyToWord: attrs.applyToWord }),
backColor: attrs => expandToWordWrap(applyInlineStyle, { style: 'background-color', value: attrs.value, applyToWord: attrs.applyToWord }),
selectAll: () => (state, dispatch) => selectAll(state, dispatch)
};
const blockCommand = {
alignCenter: () => (state, dispatch) => isAligned(state, alignCenterRules) ? alignRemove(state, dispatch) : alignBlocks(alignCenterRules)(state, dispatch),
alignJustify: () => (state, dispatch) => isAligned(state, alignJustifyRules) ? alignRemove(state, dispatch) : alignBlocks(alignJustifyRules)(state, dispatch),
alignLeft: () => (state, dispatch) => isAligned(state, alignLeftRules) ? alignRemove(state, dispatch) : alignBlocks(alignLeftRules)(state, dispatch),
alignRight: () => (state, dispatch) => isAligned(state, alignRightRules) ? alignRemove(state, dispatch) : alignBlocks(alignRightRules)(state, dispatch),
format: formatAttr => formatBlockElements(formatAttr.tag),
getHTML: () => getHtml,
indent: () => indent,
insertImage: attrs => insertImage(attrs),
// think about changing the command name.
insertOrderedList: () => toggleOrderedList,
// think about changing the command name.
insertUnorderedList: () => toggleUnorderedList,
outdent: () => outdent,
redo: () => redo,
setHTML: ({ content, parseOptions }) => setHtml(content, 'setHTML', parseOptions),
undo: () => undo,
blockquote: () => blockquote
};
const tableCommand = {
insertTable: attr => insertTable(attr),
addColumnBefore: () => addColumnBefore,
addColumnAfter: () => addColumnAfter,
addRowBefore: () => addRowBefore,
addRowAfter: () => addRowAfter,
deleteRow: () => deleteRow,
deleteColumn: () => deleteColumn,
mergeCells: () => mergeCells,
splitCell: () => splitCell,
deleteTable: () => deleteTable
};
/**
* @hidden
*/
const editorCommands = Object.assign({}, inlineCommand, blockCommand, tableCommand);
/**
* @hidden
*/
const getToolbarState = (state, options) => ({
alignCenter: {
selected: isAligned(state, alignCenterRules),
disabled: false
},
alignJustify: {
selected: isAligned(state, alignJustifyRules),
disabled: false
},
alignLeft: {
selected: isAligned(state, alignLeftRules),
disabled: false
},
alignRight: {
selected: isAligned(state, alignRightRules),
disabled: false
},
bold: {
selected: hasMark(state, bold),
disabled: false
},
cleanFormatting: {
selected: false,
disabled: !cleanFormatting()(state)
},
format: {
selected: activeNode(state),
disabled: false
},
blockquote: {
selected: false,
disabled: !blockquote(state)
},
indent: {
selected: false,
disabled: !(canIndentAsListItem(state, state.schema.nodes['list_item']) || canBeIndented(state, indentRules))
},
insertOrderedList: {
selected: hasNode(state, state.schema.nodes['ordered_list']),
disabled: false
},
insertUnorderedList: {
selected: hasNode(state, state.schema.nodes['bullet_list']),
disabled: false
},
italic: {
selected: hasMark(state, italic),
disabled: false
},
unlink: {
selected: false,
disabled: !hasMark(state, link)
},
outdent: {
selected: false,
get disabled() {
return !(hasNode(state, state.schema.nodes['blockquote']) ||
canOutdentAsListItem(state, outdentRules) ||
isIndented(state, outdentRules.nodes));
}
},
redo: {
selected: false,
disabled: !redo(state)
},
selectAll: {
selected: false,
disabled: false
},
strikethrough: {
selected: hasMark(state, strikethrough),
disabled: false
},
style: {
selected: getActiveMarks(state, state.schema.marks['style']),
disabled: false
},
subscript: {
selected: hasMark(state, subscript),
disabled: false
},
superscript: {
selected: hasMark(state, superscript),
disabled: false
},
underline: {
selected: hasMark(state, underline),
disabled: false
},
undo: {
selected: false,
disabled: !undo(state)
},
//dialogs
createLink: {
selected: false,
get disabled() {
const empty = state.selection.empty;
const applyToWord = options && options.applyToWord;
if (applyToWord && empty) {
const extendedState = expandSelection(state, () => { }, options).state;
return extendedState.selection.empty;
}
return empty;
}
},
insertFile: {
selected: false,
disabled: state.selection.empty
},
insertImage: {
selected: false,
disabled: false
},
viewSource: {
selected: false,
disabled: false
},
// print
print: {
selected: false,
disabled: false
},
// table
insertTable: {
selected: false,
disabled: false
},
addColumnBefore: {
selected: false,
disabled: !addColumnBefore(state)
},
addColumnAfter: {
selected: false,
disabled: !addColumnAfter(state)
},
addRowBefore: {
selected: false,
disabled: !addRowBefore(state)
},
addRowAfter: {
selected: false,
disabled: !addRowAfter(state)
},
deleteRow: {
selected: false,
disabled: !deleteRow(state)
},
deleteColumn: {
selected: false,
disabled: !deleteColumn(state)
},
mergeCells: {
selected: false,
disabled: !mergeCells(state)
},
splitCell: {
selected: false,
disabled: !splitCell(state)
},
deleteTable: {
selected: false,
disabled: !deleteTable(state)
}
});
/**
* @hidden
*/
const initialToolBarState = {
//alignment
alignCenter: { selected: false, disabled: false },
alignJustify: { selected: false, disabled: false },
alignLeft: { selected: false, disabled: false },
alignRight: { selected: false, disabled: false },
//marks
bold: { selected: false, disabled: false },
italic: { selected: false, disabled: false },
underline: { selected: false, disabled: false },
strikethrough: { selected: false, disabled: false },
subscript: { selected: false, disabled: false },
superscript: { selected: false, disabled: false },
//tools
format: { selected: { text: 'Format', tag: null }, disabled: false },
style: { selected: { marks: [], hasNodesWithoutMarks: false }, disabled: false },
cleanFormatting: { selected: false, disabled: true },
blockquote: { selected: false, disabled: false },
//indent
indent: { selected: false, disabled: false },
outdent: { selected: false, disabled: false },
//lists
insertOrderedList: { selected: false, disabled: false },
insertUnorderedList: { selected: false, disabled: false },
//links
unlink: { selected: false, disabled: true },
//history
redo: { selected: false, disabled: true },
undo: { selected: false, disabled: true },
// print
print: { selected: false, disabled: false },
//dialogs
createLink: { selected: false, disabled: true },
insertFile: { selected: false, disabled: true },
insertImage: { selected: false, disabled: false },
viewSource: { selected: false, disabled: false },
//table
insertTable: { selected: false, disabled: false },
addColumnBefore: { selected: false, disabled: true },
addColumnAfter: { selected: false, disabled: true },
addRowBefore: { selected: false, disabled: true },
addRowAfter: { selected: false, disabled: true },
deleteRow: { selected: false, disabled: true },
deleteColumn: { selected: false, disabled: true },
mergeCells: { selected: false, disabled: true },
splitCell: { selected: false, disabled: true },
deleteTable: { selected: false, disabled: true },
// select all
selectAll: { selected: false, disabled: false }
};
/**
* @hidden
*/
const disabledToolBarState = {
//alignment
alignCenter: { selected: false, disabled: true },
alignJustify: { selected: false, disabled: true },
alignLeft: { selected: false, disabled: true },
alignRight: { selected: false, disabled: true },
//marks
bold: { selected: false, disabled: true },
italic: { selected: false, disabled: true },
underline: { selected: false, disabled: true },
strikethrough: { selected: false, disabled: true },
subscript: { selected: false, disabled: true },
superscript: { selected: false, disabled: true },
//tools
format: { selected: { text: 'Format', tag: null }, disabled: true },
style: { selected: { marks: [], hasNodesWithoutMarks: false }, disabled: true },
cleanFormatting: { selected: false, disabled: true },
blockquote: { selected: false, disabled: true },
//indent
indent: { selected: false, disabled: true },
outdent: { selected: false, disabled: true },
//lists
insertOrderedList: { selected: false, disabled: true },
insertUnorderedList: { selected: false, disabled: true },
//links
unlink: { selected: false, disabled: true },
//history
redo: { selected: false, disabled: true },
undo: { selected: false, disabled: true },
// print
print: { selected: false, disabled: true },
//dialogs
createLink: { selected: false, disabled: true },
insertFile: { selected: false, disabled: true },
insertImage: { selected: false, disabled: true },
viewSource: { selected: false, disabled: true },
//table
insertTable: { selected: false, disabled: true },
addColumnBefore: { selected: false, disabled: true },
addColumnAfter: { selected: false, disabled: true },
addRowBefore: { selected: false, disabled: true },
addRowAfter: { selected: false, disabled: true },
deleteRow: { selected: false, disabled: true },
deleteColumn: { selected: false, disabled: true },
mergeCells: { selected: false, disabled: true },
splitCell: { selected: false, disabled: true },
deleteTable: { selected: false, disabled: true },
// select all
selectAll: { selected: false, disabled: true }
};
/**
* @hidden
*/
function outerWidth(element) {
let width = element.offsetWidth;
const style = getComputedStyle(element);
width += parseFloat(style.marginLeft) || 0 + parseFloat(style.marginRight) || 0;
return width;
}
/**
* @hidden
*/
const removeEntries = (obj, predicate) => Object.keys(obj)
.filter(key => predicate(key))
.reduce((acc, curr) => Object.assign(acc, { [curr]: obj[curr] }), {});
/**
* @hidden
*/
const removeEmptyEntries = (obj) => {
const predicate = key => obj[key] !== null && obj[key] !== undefined && obj[key] !== '';
return removeEntries(obj, predicate);
};
/**
* @hidden
*/
const isEmpty = (obj) => Object.keys(obj).length === 0;
/**
* @hidden
*/
const isNullOrUndefined = (value) => value === undefined || value === null;
/**
* @hidden
*/
const isPresent = (value) => !isNullOrUndefined(value);
/**
* @hidden
*/
const detectIE = () => {
if (!isDocumentAvailable()) {
return false;
}
const ua = window.navigator.userAgent;
const msie = ua.indexOf('MSIE ');
const trident = ua.indexOf('Trident/');
return msie > 0 || trident > 0;
};
/**
* @hidden
*/
const safeString = (value) => (isNullOrUndefined(value) ? '' : value.toString());
/**
* @hidden
*/
const first = (arr) => arr[0];
/**
* @hidden
*/
const last = (arr) => arr[arr.length - 1];
/**
* @hidden
*/
const unique = (arr) => Array.from(new Set(arr));
/**
* @hidden
*/
const split = (splitter) => (value) => value.split(splitter);
/**
* @hidden
*/
const trim = (value) => value.trim();
/**
* @hidden
*/
const filter = (predicate) => (arr) => arr.filter(predicate);
/**
* @hidden
*/
const toArray = (x) => (x instanceof Array ? x : [x]);
/**
* @hidden
*/
const getUniqueStyleValues = (style, cssStyle) => {
if (style.hasNodesWithoutMarks) {
return '';
}
const uniqueMarkValues = style.marks
.filter(m => m.type.name === 'style')
.map(m => m.attrs['style'])
.map(safeString)
.map(split(';'))
.map(filter((m) => m.includes(cssStyle)))
// guards against empty array
.map((cssStyleValues) => (cssStyleValues.length !== 0 ? cssStyleValues : [`${cssStyle}: INVALID`]))
.map(first)
.map(split(':'))
.map(last)
.map(trim)
.reduce((acc, curr) => (acc.indexOf(curr) > -1 ? acc : [...acc, curr]), []);
if (uniqueMarkValues.indexOf('INVALID') > -1 || uniqueMarkValues.length !== 1) {
return '';
}
return uniqueMarkValues[0];
};
/**
* @hidden
*/
const conditionallyExecute = (fn) => (condition) => (param) => (condition ? fn(param) : param);
/**
* @hidden
*/
const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
// This re-declaration is necessary for proper API generation
/**
* A method for extracting the text from the current editor state's selection ([see example]({% slug plugins_editor %}#toc-popup-tools)).
*
* ```ts
* import {getSelectionText} from '@progress/kendo-angular-editor';
*
* export class AppComponent {
* @ViewChild('editor') public editor;
* public onClick(){
* const selection = getSelectionText(this.editor.view.state)
* }
* }
* ```
* @param state
* @returns the selection text.
*/
const getSelectionText = (state) => getSelectionText$1(state);
/**
* @hidden
*/
const replaceMessagePlaceholder = (message, replacements) => {
replacements.forEach((replacement) => message = message.replace(new RegExp(`\{\\s*${replacement.placeholder}\\s*\}`, 'g'), replacement.value));
return message;
};
/**
* @hidden
*/
class EditorLocalizationService extends LocalizationService {
constructor(prefix, messageService, _rtl) {
super(prefix, messageService, _rtl);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EditorLocalizationService, deps: [{ token: L10N_PREFIX }, { token: i1.MessageService, optional: true }, { token: RTL, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EditorLocalizationService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EditorLocalizationService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
type: Inject,
args: [L10N_PREFIX]
}] }, { type: i1.MessageService, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [RTL]
}] }]; } });
/**
* @hidden
*/
class SourceDialogComponent extends DialogContentBase {
dialog;
localization;
editor;
textarea;
data = '';
constructor(dialog, localization) {
super(dialog);
this.dialog = dialog;
this.localization = localization;
}
onCancelAction() {
this.dialog.close();
}
onConfirmAction() {
this.editor.exec('setHTML', this.getData());
this.dialog.close();
this.editor.view.focus();
}
getData() {
return this.textarea.value;
}
setData() {
this.data = this.indent(this.editor.getSource());
}
textFor(key) {
return this.localization.get(key);
}
indent(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$/, '');
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SourceDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: EditorLocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SourceDialogComponent, isStandalone: true, selector: "ng-component", inputs: { editor: "editor" }, viewQueries: [{ propertyName: "textarea", first: true, predicate: ["textarea"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
<kendo-dialog-titlebar (close)="onCancelAction()">
{{ textFor('viewSource') }}
</kendo-dialog-titlebar>
<kendo-textarea
#textarea
class="k-editor-textarea"
flow="horizontal"
resizable="none"
[value]="data"
[style.height.%]="100"
></kendo-textarea>
<kendo-dialog-actions layout="start">
<button
kendoButton
[primary]="true"
(click)="onConfirmAction()"
>{{ textFor('dialogUpdate') }}</button>
<button
kendoButton
(click)="onCancelAction()"
>{{ textFor('dialogCancel') }}</button>
</kendo-dialog-actions>
`, isInline: true, dependencies: [{ kind: "component", type: DialogTitleBarComponent, selector: "kendo-dialog-titlebar", inputs: ["id", "closeTitle"], outputs: ["close"] }, { kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "tabindex", "tabIndex", "resizable", "size", "rounded", "fillMode", "showPrefixSeparator", "showSuffixSeparator"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoTextArea"] }, { kind: "component", type: DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SourceDialogComponent, decorators: [{
type: Component,
args: [{
template: `
<kendo-dialog-titlebar (close)="onCancelAction()">
{{ textFor('viewSource') }}
</kendo-dialog-titlebar>
<kendo-textarea
#textarea
class="k-editor-textarea"
flow="horizontal"
resizable="none"
[value]="data"
[style.height.%]="100"
></kendo-textarea>
<kendo-dialog-actions layout="start">
<button
kendoButton
[primary]="true"
(click)="onConfirmAction()"
>{{ textFor('dialogUpdate') }}</button>
<button
kendoButton
(click)="onCancelAction()"
>{{ textFor('dialogCancel') }}</button>
</kendo-dialog-actions>
`,
standalone: true,
imports: [DialogTitleBarComponent, TextAreaComponent, DialogActionsComponent, ButtonComponent]
}]
}], ctorParameters: function () { return [{ type: i1$1.DialogRef }, { type: EditorLocalizationService }]; }, propDecorators: { editor: [{
type: Input
}], textarea: [{
type: ViewChild,
args: ['textarea', { static: true }]
}] } });
/**
* @hidden
*/
class ImageDialogComponent extends DialogContentBase {
dialog;
localization;
editor;
srcInput;
src = new FormControl('', Validators.required);
alt = new FormControl('');
width = new FormControl('', Validators.min(1));
height = new FormControl('', Validators.min(1));
data = {
alt: '',
height: '',
src: '',
width: ''
};
imageData = new FormGroup({
alt: this.alt,
height: this.height,
src: this.src,
width: this.width
});
srcInputId;
altTextInputId;
widthInputId;
heightInputId;
constructor(dialog, localization) {
super(dialog);
this.dialog = dialog;
this.localization = localization;
}
ngOnInit() {
this.srcInputId = `k-${guid()}`;
this.altTextInputId = `k-${guid()}`;
this.widthInputId = `k-${guid()}`;
this.heightInputId = `k-${guid()}`;
}
onCancelAction() {
this.dialog.close();
}
onConfirmAction() {
if (this.src.value) {
this.editor.exec('insertImage', this.getData());
this.dialog.close();
this.editor.view.focus();
}
}
setData(state) {
const node = getNodeFromSelection(state);
if (node) {
this.src.patchValue(node.attrs['src']);
this.alt.patchValue(node.attrs['alt']);
this.width.patchValue(node.attrs['width']);
this.height.patchValue(node.attrs['height']);
}
}
textFor(key) {
return this.localization.get(key);
}
getData() {
return {
alt: this.alt.value,
height: this.normalizeDimension(this.height.value),
src: this.src.value,
width: this.normalizeDimension(this.width.value)
};
}
normalizeDimension(value) {
return Number.isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 0 ? '' : safeString(parseInt(value, 10));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: EditorLocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ImageDialogComponent, isStandalone: true, selector: "ng-component", inputs: { editor: "editor" }, viewQueries: [{ propertyName: "srcInput", first: true, predicate: ["srcInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
<kendo-dialog-titlebar (close)="onCancelAction()">
{{ textFor('insertImage') }}
</kendo-dialog-titlebar>
<div class="k-form k-form-md">
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="srcInput"
[text]="textFor('imageWebAddress')"
></kendo-label>
<kendo-textbox
#srcInput
[formControl]="src"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="altTextInput"
[text]="textFor('imageAltText')"
></kendo-label>
<kendo-textbox
#altTextInput
[formControl]="alt"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="widthInput"
[text]="textFor('imageWidth')"
></kendo-label>
<kendo-textbox
#widthInput
[formControl]="width"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
[for]="heightInput"
[text]="textFor('imageHeight')"
labelCssClass="k-form-label"
></kendo-label>
<kendo-textbox
#heightInput
[formControl]="height"
></kendo-textbox>
</kendo-formfield>
</div>
<kendo-dialog-actions layout="start">
<button
kendoButton
[disabled]="imageData.invalid"
[primary]="true"
(click)="onConfirmAction()"
>{{ textFor('dialogInsert') }}</button>
<button
kendoButton
(click)="onCancelAction()"
>{{ textFor('dialogCancel') }}</button>
</kendo-dialog-actions>
`, isInline: true, dependencies: [{ kind: "component", type: DialogTitleBarComponent, selector: "kendo-dialog-titlebar", inputs: ["id", "closeTitle"], outputs: ["close"] }, { kind: "component", type: FormFieldComponent, selector: "kendo-formfield", inputs: ["showHints", "orientation", "showErrors"] }, { kind: "component", type: LabelComponent, selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }, { kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageDialogComponent, decorators: [{
type: Component,
args: [{
template: `
<kendo-dialog-titlebar (close)="onCancelAction()">
{{ textFor('insertImage') }}
</kendo-dialog-titlebar>
<div class="k-form k-form-md">
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="srcInput"
[text]="textFor('imageWebAddress')"
></kendo-label>
<kendo-textbox
#srcInput
[formControl]="src"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="altTextInput"
[text]="textFor('imageAltText')"
></kendo-label>
<kendo-textbox
#altTextInput
[formControl]="alt"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="widthInput"
[text]="textFor('imageWidth')"
></kendo-label>
<kendo-textbox
#widthInput
[formControl]="width"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
[for]="heightInput"
[text]="textFor('imageHeight')"
labelCssClass="k-form-label"
></kendo-label>
<kendo-textbox
#heightInput
[formControl]="height"
></kendo-textbox>
</kendo-formfield>
</div>
<kendo-dialog-actions layout="start">
<button
kendoButton
[disabled]="imageData.invalid"
[primary]="true"
(click)="onConfirmAction()"
>{{ textFor('dialogInsert') }}</button>
<button
kendoButton
(click)="onCancelAction()"
>{{ textFor('dialogCancel') }}</button>
</kendo-dialog-actions>
`,
standalone: true,
imports: [DialogTitleBarComponent, FormFieldComponent, LabelComponent, TextBoxComponent, ReactiveFormsModule, DialogActionsComponent, ButtonComponent]
}]
}], ctorParameters: function () { return [{ type: i1$1.DialogRef }, { type: EditorLocalizationService }]; }, propDecorators: { editor: [{
type: Input
}], srcInput: [{
type: ViewChild,
args: ['srcInput']
}] } });
/**
* @hidden
*/
class FileLinkDialogComponent extends DialogContentBase {
dialog;
localization;
editor;
command;
hrefInput;
linkForm = new FormGroup({
'href': new FormControl('', Validators.required),
'text': new FormControl({ value: '', disabled: true }, Validators.required),
'title': new FormControl('')
});
constructor(dialog, localization) {
super(dialog);
this.dialog = dialog;
this.localization = localization;
}
onCancelAction() {
this.dialog.close();
}
onConfirmAction() {
const linkData = this.getData();
this.editor.exec(this.command, linkData);
this.dialog.close();
this.editor.view.focus();
}
get titleText() {
return this.localization.get(this.command);
}
setData(state, options) {
if (this.command === 'createLink') {
this.linkForm.addControl('target', new FormControl());
}
const linkMark = getMark(state, state.schema.marks['link']);
if (linkMark) {
// const linkMarkRange = getMarkRange(state.selection.$cursor, schema.marks.link);
// const mark = parentNode.child(cursorNodeIndex).marks.find(m => m.type === markType);
this.linkForm.reset({
href: linkMark.attrs['href'],
title: linkMark.attrs['title'],
target: isPresent(linkMark.attrs['target']),
text: this.setLinkText(state)
});
return;
}
if (state.selection.empty) {
const currentState = options.applyToWord ? expandSelection(state, () => { }, options).state : state;
if (!currentState.selection.empty) {
this.linkForm.patchValue({
'text': getSelectionText$1(currentState)
});
}
}
else {
this.linkForm.patchValue({
'text': getSelectionText$1(state)
});
}
}
textForWithPrefix(key) {
const prefix = this.command === 'createLink' ? 'link' : 'file';
return this.textFor(prefix + key);
}
textFor(key) {
return this.localization.get(key);
}
setLinkText(state) {
const selection = state.selection;
if (selection.empty && selection.$cursor) {
const cursor = selection.$cursor;
const cursorNodeIndex = cursor.index();
const parentNode = cursor.parent;
return parentNode.child(cursorNodeIndex).text;
}
else {
return getSelectionText$1(state);
}
}
getData() {
const linkData = this.linkForm.value;
if (isPresent(this.linkForm.controls['target'])) {
linkData.target = linkData.target ? '_blank' : null;
}
return linkData;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileLinkDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: EditorLocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: FileLinkDialogComponent, isStandalone: true, selector: "ng-component", inputs: { editor: "editor", command: "command" }, viewQueries: [{ propertyName: "hrefInput", first: true, predicate: ["hrefInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
<kendo-dialog-titlebar (close)="onCancelAction()">
{{ titleText }}
</kendo-dialog-titlebar>
<form class="k-form k-form-md" novalidate [formGroup]="linkForm">
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="hrefInput"
[text]="textForWithPrefix('WebAddress')"
></kendo-label>
<kendo-textbox
#hrefInput
formControlName="href"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="textInput"
[text]="textForWithPrefix('Text')"
></kendo-label>
<kendo-textbox
#textInput
formControlName="text"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="titleInput"
[text]="textForWithPrefix('Title')"
></kendo-label>
<kendo-textbox
#titleInput
formControlName="title"
></kendo-textbox>
</kendo-formfield>
<ng-container *ngIf="command === 'createLink'">
<kendo-formfield>
<ng-container>
<span class="k-checkbox-wrap">
<input
id='k-target-blank'
type='checkbox'
kendoCheckBox
formControlName="target"
/>
</span>
<label [labelClass]="false" class='k-checkbox-label' for='k-target-blank'>{{ textForWithPrefix('OpenInNewWindow') }}</label>
</ng-container>
</kendo-formfield>
</ng-container>
</form>
<kendo-dialog-actions layout="start">
<button
kendoButton
[disabled]="linkForm.invalid"
[primary]="true"
(click)="onConfirmAction()"
>{{ textFor('dialogInsert') }}</button>
<button
kendoButton
(click)="onCancelAction()"
>{{ textFor('dialogCancel') }}</button>
</kendo-dialog-actions>
`, isInline: true, dependencies: [{ kind: "component", type: DialogTitleBarComponent, selector: "kendo-dialog-titlebar", inputs: ["id", "closeTitle"], outputs: ["close"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: FormFieldComponent, selector: "kendo-formfield", inputs: ["showHints", "orientation", "showErrors"] }, { kind: "component", type: LabelComponent, selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }, { kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CheckBoxDirective, selector: "input[kendoCheckBox]", inputs: ["size", "rounded"] }, { kind: "directive", type: LabelDirective, selector: "label[for]", inputs: ["for", "labelClass"] }, { kind: "component", type: DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FileLinkDialogComponent, decorators: [{
type: Component,
args: [{
template: `
<kendo-dialog-titlebar (close)="onCancelAction()">
{{ titleText }}
</kendo-dialog-titlebar>
<form class="k-form k-form-md" novalidate [formGroup]="linkForm">
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="hrefInput"
[text]="textForWithPrefix('WebAddress')"
></kendo-label>
<kendo-textbox
#hrefInput
formControlName="href"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="textInput"
[text]="textForWithPrefix('Text')"
></kendo-label>
<kendo-textbox
#textInput
formControlName="text"
></kendo-textbox>
</kendo-formfield>
<kendo-formfield>
<kendo-label
labelCssClass="k-form-label"
[for]="titleInput"
[text]="textForWithPrefix('Title')"
></kendo-label>
<kendo-textbox
#titleInput
formControlName="title"
></kendo-textbox>
</kendo-formfield>
<ng-container *ngIf="command === 'createLink'">
<kendo-formfield>
<ng-container>
<span class="k-checkbox-wrap">