UNPKG

@progress/kendo-angular-editor

Version:
1,201 lines (1,189 loc) 324 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2026 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 { Inject, Optional, Injectable, ViewChild, Input, Component, InjectionToken, Directive, EventEmitter, Output, ElementRef, forwardRef, isDevMode, ViewContainerRef, ContentChild, HostBinding, NgModule } from '@angular/core'; 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, getLicenseMessage, shouldShowValidationUI, Keys, hasObservers, WatermarkOverlayComponent, KendoInput, KENDO_WEBMCP_HOST, isPresent as isPresent$1, ResizeBatchService } from '@progress/kendo-angular-common'; import { marks as marks$1, nodes as nodes$1, Schema, createTable, insertNode, alignBlocks, alignRemoveRules, selectAll, expandToWordWrap, applyInlineStyle, removeLink, link, toggleInlineFormat, underline, superscript, subscript, strikethrough, italic, insertText, applyLink, cleanFormatting, bold, blockquote, undo, setHtml, redo, outdent, toggleUnorderedList, toggleOrderedList, insertImage, indent, getHtml, formatBlockElements, isAligned, alignRightRules, alignLeftRules, alignJustifyRules, alignCenterRules, deleteTable, splitCell, mergeCells, deleteColumn, deleteRow, addRowAfter, addRowBefore, addColumnAfter, addColumnBefore, expandSelection, hasMark, getActiveMarks, hasNode, canOutdentAsListItem, outdentRules, isIndented, canIndentAsListItem, canBeIndented, indentRules, activeNode, getSelectionText as getSelectionText$1, getNodeFromSelection, getMark, removeComments, sanitize, removeAttribute, sanitizeClassAttr, sanitizeStyleAttr, 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 { tableDeleteIcon, cellSplitHorizontallyIcon, cellsMergeIcon, tableColumnDeleteIcon, tableRowDeleteIcon, tableRowInsertBelowIcon, tableRowInsertAboveIcon, tableColumnInsertRightIcon, tableColumnInsertLeftIcon, tableAddIcon, codeSnippetIcon, unlinkIcon, undoIcon, underlineIcon, superscriptIcon, subscriptIcon, strikethroughIcon, selectAllIcon, redoIcon, printIcon, outdentIcon, italicIcon, listUnorderedIcon, listOrderedIcon, fileImageIcon, fileAddIcon, indentIcon, foregroundColorIcon, linkIcon, clearCssIcon, boldIcon, rightDoubleQuotesIcon, dropletIcon, alignRightIcon, alignLeftIcon, alignJustifyIcon, alignCenterIcon, 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'; import { NgStyle } from '@angular/common'; /** * @hidden */ const packageMetadata = { name: '@progress/kendo-angular-editor', productName: 'Kendo UI for Angular', productCode: 'KENDOUIANGULAR', productCodes: ['KENDOUIANGULAR'], publishDate: 1780593903, version: '24.1.0', 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 }, //disabled //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) { if (!isDocumentAvailable()) { return element.offsetWidth || 0; } 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 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); // This re-declaration is necessary for proper API generation /** * Extracts the text from the current editor state's selection ([see example](https://www.telerik.com/kendo-angular-ui/components/editor/plugins#popup-tools)). * * @example * ```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 The current `EditorState`. * @returns The selected 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: "19.2.25", 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: "19.2.25", ngImport: i0, type: EditorLocalizationService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: EditorLocalizationService, decorators: [{ type: Injectable }], ctorParameters: () => [{ 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: "19.2.25", ngImport: i0, type: SourceDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: EditorLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", 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 themeColor="primary" (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", "closable"], outputs: ["close"] }, { kind: "component", type: TextAreaComponent, selector: "kendo-textarea", inputs: ["focusableId", "flow", "inputAttributes", "adornmentsOrientation", "rows", "cols", "maxlength", "maxResizableRows", "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", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", 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 themeColor="primary" (click)="onConfirmAction()" >{{ textFor('dialogUpdate') }}</button> <button kendoButton (click)="onCancelAction()" >{{ textFor('dialogCancel') }}</button> </kendo-dialog-actions> `, standalone: true, imports: [DialogTitleBarComponent, TextAreaComponent, DialogActionsComponent, ButtonComponent] }] }], ctorParameters: () => [{ 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: "19.2.25", ngImport: i0, type: ImageDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: EditorLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", 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" themeColor="primary" (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", "closable"], outputs: ["close"] }, { kind: "component", type: FormFieldComponent, selector: "kendo-formfield", inputs: ["showHints", "orientation", "showErrors", "colSpan"] }, { 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", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", 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" themeColor="primary" (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: () => [{ 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) { 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: "19.2.25", ngImport: i0, type: FileLinkDialogComponent, deps: [{ token: i1$1.DialogRef }, { token: EditorLocalizationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", 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> @if (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> } </form> <kendo-dialog-actions layout="start"> <button kendoButton [disabled]="linkForm.invalid" themeColor="primary" (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", "closable"], 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", "colSpan"] }, { 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: 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", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", 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> @if (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> } </form> <kendo-dialog-actions layout="start"> <button kendoButton [disabled]="linkForm.invalid" themeColor="primary" (click)="onConfirmAction()" >{{ textFor('dialogInsert') }}</button> <button kendoButton (click)="onCancelAction()" >{{ textFor('dialogCancel') }}</button> </kendo-dialog-actions> `, standalone: true, imports: [DialogTitleBarComponent, ReactiveFormsModule, Fo