@progress/kendo-angular-editor 25.2.1-develop.1 → 25.3.0-develop.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -12,7 +12,7 @@ import * as i1$2 from '@progress/kendo-angular-toolbar';
|
|
|
12
12
|
import { ToolBarToolComponent, ToolBarComponent, ToolBarButtonGroupComponent, ToolBarButtonComponent, KENDO_TOOLBAR } from '@progress/kendo-angular-toolbar';
|
|
13
13
|
import * as i1$1 from '@progress/kendo-angular-dialog';
|
|
14
14
|
import { DialogContentBase, DialogTitleBarComponent, DialogActionsComponent, DialogContainerService, DialogService, WindowService, WindowContainerService } from '@progress/kendo-angular-dialog';
|
|
15
|
-
import { isDocumentAvailable, guid, getLicenseMessage, shouldShowValidationUI, Keys, hasObservers, WatermarkOverlayComponent, KendoInput, KENDO_WEBMCP_HOST, provideComponentName, isPresent as isPresent$1, ResizeBatchService } from '@progress/kendo-angular-common';
|
|
15
|
+
import { isSafeUrl, isSafeImageUrl, isDocumentAvailable, guid, getLicenseMessage, shouldShowValidationUI, Keys, hasObservers, WatermarkOverlayComponent, KendoInput, KENDO_WEBMCP_HOST, provideComponentName, isPresent as isPresent$1, ResizeBatchService } from '@progress/kendo-angular-common';
|
|
16
16
|
import { marks as marks$1, nodes as nodes$1, Schema, createTable, insertNode, alignBlocks, alignRemoveRules, canIndentAsListItem, indent, canBeIndented, indentBlocks, hasNode, liftBlockquote, canOutdentAsListItem, outdent, selectAll, expandToWordWrap, applyInlineStyle, removeLink, link, toggleInlineFormat, underline, superscript, subscript, strikethrough, italic, insertText, applyLink, cleanFormatting, bold, blockquote, undo, setHtml, redo, toggleUnorderedList, toggleOrderedList, insertImage, getHtml, formatBlockElements, isAligned, alignRightRules, alignLeftRules, alignJustifyRules, alignCenterRules, deleteTable, splitCell, mergeCells, deleteColumn, deleteRow, addRowAfter, addRowBefore, addColumnAfter, addColumnBefore, expandSelection, hasMark, getActiveMarks, isIndented, 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, replaceImageSourcesFromRtf, AllSelection } from '@progress/kendo-editor-common';
|
|
17
17
|
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';
|
|
18
18
|
import { validatePackage } from '@progress/kendo-licensing';
|
|
@@ -36,8 +36,8 @@ const packageMetadata = {
|
|
|
36
36
|
productName: 'Kendo UI for Angular',
|
|
37
37
|
productCode: 'KENDOUIANGULAR',
|
|
38
38
|
productCodes: ['KENDOUIANGULAR'],
|
|
39
|
-
publishDate:
|
|
40
|
-
version: '25.
|
|
39
|
+
publishDate: 1790761643,
|
|
40
|
+
version: '25.3.0-develop.2',
|
|
41
41
|
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -234,6 +234,18 @@ const insertTable = (attrs) => (state, dispatch) => {
|
|
|
234
234
|
};
|
|
235
235
|
|
|
236
236
|
const alignRemove = (state, dispatch) => alignBlocks(alignRemoveRules)(state, dispatch);
|
|
237
|
+
const sanitizeLinkAttrs = (attrs) => {
|
|
238
|
+
if (attrs && typeof attrs === 'object' && attrs.href !== undefined && !isSafeUrl(attrs.href)) {
|
|
239
|
+
return { ...attrs, href: '' };
|
|
240
|
+
}
|
|
241
|
+
return attrs;
|
|
242
|
+
};
|
|
243
|
+
const sanitizeImageAttrs = (attrs) => {
|
|
244
|
+
if (attrs && typeof attrs === 'object' && attrs.src !== undefined && !isSafeImageUrl(attrs.src)) {
|
|
245
|
+
return { ...attrs, src: '' };
|
|
246
|
+
}
|
|
247
|
+
return attrs;
|
|
248
|
+
};
|
|
237
249
|
const customIndent = (state, dispatch) => {
|
|
238
250
|
const listItem = state.schema.nodes[indentRules.listsTypes.listItem];
|
|
239
251
|
if (canIndentAsListItem(state, listItem)) {
|
|
@@ -258,10 +270,10 @@ const customOutdent = (state, dispatch) => {
|
|
|
258
270
|
const inlineCommand = {
|
|
259
271
|
bold: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...bold, applyToWord }),
|
|
260
272
|
cleanFormatting: (options) => cleanFormatting(options),
|
|
261
|
-
createLink: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: attrs.value, applyToWord: attrs.applyToWord }),
|
|
273
|
+
createLink: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: sanitizeLinkAttrs(attrs.value), applyToWord: attrs.applyToWord }),
|
|
262
274
|
fontFamily: attrs => expandToWordWrap(applyInlineStyle, { style: 'font-family', value: attrs.value, applyToWord: attrs.applyToWord }),
|
|
263
275
|
fontSize: attrs => expandToWordWrap(applyInlineStyle, { style: 'font-size', value: attrs.value, applyToWord: attrs.applyToWord }),
|
|
264
|
-
insertFile: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: attrs, applyToWord: attrs.applyToWord }),
|
|
276
|
+
insertFile: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: sanitizeLinkAttrs(attrs), applyToWord: attrs.applyToWord }),
|
|
265
277
|
insertText: text => insertText(text),
|
|
266
278
|
italic: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...italic, applyToWord }),
|
|
267
279
|
strikethrough: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...strikethrough, applyToWord }),
|
|
@@ -281,7 +293,7 @@ const blockCommand = {
|
|
|
281
293
|
format: formatAttr => formatBlockElements(formatAttr.tag),
|
|
282
294
|
getHTML: () => getHtml,
|
|
283
295
|
indent: () => customIndent,
|
|
284
|
-
insertImage: attrs => insertImage(attrs),
|
|
296
|
+
insertImage: attrs => insertImage(sanitizeImageAttrs(attrs)),
|
|
285
297
|
// think about changing the command name.
|
|
286
298
|
insertOrderedList: () => toggleOrderedList,
|
|
287
299
|
// think about changing the command name.
|
|
@@ -708,6 +720,29 @@ const replaceMessagePlaceholder = (message, replacements) => {
|
|
|
708
720
|
replacements.forEach((replacement) => message = message.replace(new RegExp(`\\[\\[\\s*${replacement.placeholder}\\s*]]|{\\s*${replacement.placeholder}\\s*}`, 'g'), replacement.value));
|
|
709
721
|
return message;
|
|
710
722
|
};
|
|
723
|
+
/**
|
|
724
|
+
* @hidden
|
|
725
|
+
* Removes `href` and `src` attributes that use unsafe URL schemes (e.g. `javascript:`) from an HTML string.
|
|
726
|
+
* Uses `<template>` for inert parsing so element event handlers do not fire during sanitization.
|
|
727
|
+
*/
|
|
728
|
+
const sanitizeUnsafeUrls = (html) => {
|
|
729
|
+
if (!html || !isDocumentAvailable()) {
|
|
730
|
+
return html;
|
|
731
|
+
}
|
|
732
|
+
const template = document.createElement('template');
|
|
733
|
+
template.innerHTML = html;
|
|
734
|
+
template.content.querySelectorAll('a[href]').forEach(el => {
|
|
735
|
+
if (!isSafeUrl(el.getAttribute('href'))) {
|
|
736
|
+
el.removeAttribute('href');
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
template.content.querySelectorAll('img[src], source[src]').forEach(el => {
|
|
740
|
+
if (!isSafeImageUrl(el.getAttribute('src'))) {
|
|
741
|
+
el.removeAttribute('src');
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
return template.innerHTML;
|
|
745
|
+
};
|
|
711
746
|
|
|
712
747
|
/**
|
|
713
748
|
* @hidden
|
|
@@ -834,6 +869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
|
|
|
834
869
|
args: ['textarea', { static: true }]
|
|
835
870
|
}] } });
|
|
836
871
|
|
|
872
|
+
const safeImageUrlValidator = (control) => isSafeImageUrl(control.value) ? null : { unsafeUrl: true };
|
|
837
873
|
/**
|
|
838
874
|
* @hidden
|
|
839
875
|
*/
|
|
@@ -842,7 +878,7 @@ class ImageDialogComponent extends DialogContentBase {
|
|
|
842
878
|
localization;
|
|
843
879
|
editor;
|
|
844
880
|
srcInput;
|
|
845
|
-
src = new FormControl('', Validators.required);
|
|
881
|
+
src = new FormControl('', [Validators.required, safeImageUrlValidator]);
|
|
846
882
|
alt = new FormControl('');
|
|
847
883
|
width = new FormControl('', Validators.min(1));
|
|
848
884
|
height = new FormControl('', Validators.min(1));
|
|
@@ -1047,6 +1083,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
|
|
|
1047
1083
|
args: ['srcInput']
|
|
1048
1084
|
}] } });
|
|
1049
1085
|
|
|
1086
|
+
const safeUrlValidator = (control) => isSafeUrl(control.value) ? null : { unsafeUrl: true };
|
|
1050
1087
|
/**
|
|
1051
1088
|
* @hidden
|
|
1052
1089
|
*/
|
|
@@ -1057,7 +1094,7 @@ class FileLinkDialogComponent extends DialogContentBase {
|
|
|
1057
1094
|
command;
|
|
1058
1095
|
hrefInput;
|
|
1059
1096
|
linkForm = new FormGroup({
|
|
1060
|
-
'href': new FormControl('', Validators.required),
|
|
1097
|
+
'href': new FormControl('', [Validators.required, safeUrlValidator]),
|
|
1061
1098
|
'text': new FormControl({ value: '', disabled: true }, Validators.required),
|
|
1062
1099
|
'title': new FormControl('')
|
|
1063
1100
|
});
|
|
@@ -3257,13 +3294,28 @@ const defaultPasteCleanupSettings = {
|
|
|
3257
3294
|
};
|
|
3258
3295
|
const removeCommentsIf = conditionallyExecute(removeComments);
|
|
3259
3296
|
const removeInvalidHTMLIf = conditionallyExecute(sanitize);
|
|
3297
|
+
const sanitizeHrefAttr = (attr) => {
|
|
3298
|
+
if (!isSafeUrl(attr.value)) {
|
|
3299
|
+
removeAttribute(attr);
|
|
3300
|
+
}
|
|
3301
|
+
};
|
|
3302
|
+
const sanitizeSrcAttr = (attr) => {
|
|
3303
|
+
const owner = attr.ownerElement;
|
|
3304
|
+
const tag = owner ? owner.tagName : '';
|
|
3305
|
+
const check = (tag === 'IMG' || tag === 'SOURCE') ? isSafeImageUrl : isSafeUrl;
|
|
3306
|
+
if (!check(attr.value)) {
|
|
3307
|
+
removeAttribute(attr);
|
|
3308
|
+
}
|
|
3309
|
+
};
|
|
3260
3310
|
const getPasteCleanupAttributes = (config) => {
|
|
3261
3311
|
if (config.removeAttributes === 'all') {
|
|
3262
3312
|
return { '*': removeAttribute };
|
|
3263
3313
|
}
|
|
3264
3314
|
const initial = removeEmptyEntries({
|
|
3265
3315
|
style: config.removeMsStyles ? sanitizeStyleAttr : undefined,
|
|
3266
|
-
class: config.removeMsClasses ? sanitizeClassAttr : undefined
|
|
3316
|
+
class: config.removeMsClasses ? sanitizeClassAttr : undefined,
|
|
3317
|
+
href: sanitizeHrefAttr,
|
|
3318
|
+
src: sanitizeSrcAttr
|
|
3267
3319
|
});
|
|
3268
3320
|
return config.removeAttributes.reduce((acc, curr) => ({ ...acc, [curr]: removeAttribute }), initial);
|
|
3269
3321
|
};
|
|
@@ -3794,7 +3846,7 @@ class EditorComponent {
|
|
|
3794
3846
|
}
|
|
3795
3847
|
const currentSchema = this.schema || schema;
|
|
3796
3848
|
const containerNativeElement = this.container.element.nativeElement;
|
|
3797
|
-
const contentNode = parseContent((this.value || '').trim(), currentSchema, { preserveWhitespace: this.preserveWhitespace });
|
|
3849
|
+
const contentNode = parseContent(sanitizeUnsafeUrls((this.value || '').trim()), currentSchema, { preserveWhitespace: this.preserveWhitespace });
|
|
3798
3850
|
if (this.iframe) {
|
|
3799
3851
|
const iframeDoc = containerNativeElement.contentDocument;
|
|
3800
3852
|
const meta = iframeDoc.createElement('meta');
|
|
@@ -4005,7 +4057,7 @@ class EditorComponent {
|
|
|
4005
4057
|
return;
|
|
4006
4058
|
}
|
|
4007
4059
|
const state = this.view.state;
|
|
4008
|
-
const nextDoc = parseContent(value || '', state.schema, { preserveWhitespace: this.preserveWhitespace });
|
|
4060
|
+
const nextDoc = parseContent(sanitizeUnsafeUrls(value || ''), state.schema, { preserveWhitespace: this.preserveWhitespace });
|
|
4009
4061
|
const tr = state.tr
|
|
4010
4062
|
.setSelection(new AllSelection(state.doc))
|
|
4011
4063
|
.replaceSelectionWith(nextDoc);
|
package/package-metadata.mjs
CHANGED
|
@@ -7,7 +7,7 @@ export const packageMetadata = {
|
|
|
7
7
|
"productCodes": [
|
|
8
8
|
"KENDOUIANGULAR"
|
|
9
9
|
],
|
|
10
|
-
"publishDate":
|
|
11
|
-
"version": "25.
|
|
10
|
+
"publishDate": 1790761643,
|
|
11
|
+
"version": "25.3.0-develop.2",
|
|
12
12
|
"licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/"
|
|
13
13
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@progress/kendo-angular-editor",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.3.0-develop.2",
|
|
4
4
|
"description": "Kendo UI Editor for Angular",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "Progress",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"package": {
|
|
18
18
|
"productName": "Kendo UI for Angular",
|
|
19
19
|
"productCode": "KENDOUIANGULAR",
|
|
20
|
-
"publishDate":
|
|
20
|
+
"publishDate": 1790761643,
|
|
21
21
|
"licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
@@ -29,23 +29,23 @@
|
|
|
29
29
|
"@angular/platform-browser": "20 - 22",
|
|
30
30
|
"@progress/kendo-drawing": "^1.25.0",
|
|
31
31
|
"@progress/kendo-licensing": "^1.11.0",
|
|
32
|
-
"@progress/kendo-angular-buttons": "25.
|
|
33
|
-
"@progress/kendo-angular-common": "25.
|
|
34
|
-
"@progress/kendo-angular-dialog": "25.
|
|
35
|
-
"@progress/kendo-angular-dropdowns": "25.
|
|
36
|
-
"@progress/kendo-angular-inputs": "25.
|
|
37
|
-
"@progress/kendo-angular-intl": "25.
|
|
38
|
-
"@progress/kendo-angular-l10n": "25.
|
|
39
|
-
"@progress/kendo-angular-label": "25.
|
|
40
|
-
"@progress/kendo-angular-layout": "25.
|
|
41
|
-
"@progress/kendo-angular-icons": "25.
|
|
42
|
-
"@progress/kendo-angular-popup": "25.
|
|
43
|
-
"@progress/kendo-angular-toolbar": "25.
|
|
32
|
+
"@progress/kendo-angular-buttons": "25.3.0-develop.2",
|
|
33
|
+
"@progress/kendo-angular-common": "25.3.0-develop.2",
|
|
34
|
+
"@progress/kendo-angular-dialog": "25.3.0-develop.2",
|
|
35
|
+
"@progress/kendo-angular-dropdowns": "25.3.0-develop.2",
|
|
36
|
+
"@progress/kendo-angular-inputs": "25.3.0-develop.2",
|
|
37
|
+
"@progress/kendo-angular-intl": "25.3.0-develop.2",
|
|
38
|
+
"@progress/kendo-angular-l10n": "25.3.0-develop.2",
|
|
39
|
+
"@progress/kendo-angular-label": "25.3.0-develop.2",
|
|
40
|
+
"@progress/kendo-angular-layout": "25.3.0-develop.2",
|
|
41
|
+
"@progress/kendo-angular-icons": "25.3.0-develop.2",
|
|
42
|
+
"@progress/kendo-angular-popup": "25.3.0-develop.2",
|
|
43
|
+
"@progress/kendo-angular-toolbar": "25.3.0-develop.2",
|
|
44
44
|
"rxjs": "^6.5.3 || ^7.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"tslib": "^2.3.1",
|
|
48
|
-
"@progress/kendo-angular-schematics": "25.
|
|
48
|
+
"@progress/kendo-angular-schematics": "25.3.0-develop.2",
|
|
49
49
|
"@progress/kendo-editor-common": "1.12.8"
|
|
50
50
|
},
|
|
51
51
|
"schematics": "./schematics/collection.json",
|
|
@@ -9,12 +9,12 @@ const schematics_1 = require("@angular-devkit/schematics");
|
|
|
9
9
|
function default_1(options) {
|
|
10
10
|
const finalOptions = Object.assign(Object.assign({}, options), { mainNgModule: 'EditorModule', package: 'editor', peerDependencies: {
|
|
11
11
|
// peer dependencies of kendo-angular-dropdowns
|
|
12
|
-
'@progress/kendo-angular-navigation': '25.
|
|
13
|
-
'@progress/kendo-angular-treeview': '25.
|
|
12
|
+
'@progress/kendo-angular-navigation': '25.3.0-develop.2',
|
|
13
|
+
'@progress/kendo-angular-treeview': '25.3.0-develop.2',
|
|
14
14
|
// peer dependency of kendo-angular-layout
|
|
15
|
-
'@progress/kendo-angular-progressbar': '25.
|
|
15
|
+
'@progress/kendo-angular-progressbar': '25.3.0-develop.2',
|
|
16
16
|
// peer dependency of kendo-angular-inputs
|
|
17
|
-
'@progress/kendo-angular-dialog': '25.
|
|
17
|
+
'@progress/kendo-angular-dialog': '25.3.0-develop.2',
|
|
18
18
|
// Peer dependency of icons
|
|
19
19
|
'@progress/kendo-svg-icons': '^4.0.0'
|
|
20
20
|
} });
|