jodit 4.12.17 → 4.12.20

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +7 -7
  4. package/es2015/jodit.js +338 -79
  5. package/es2015/jodit.min.js +7 -7
  6. package/es2015/plugins/debug/debug.css +1 -1
  7. package/es2015/plugins/debug/debug.js +1 -1
  8. package/es2015/plugins/debug/debug.min.js +1 -1
  9. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  10. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  11. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  12. package/es2018/jodit.fat.min.js +7 -7
  13. package/es2018/jodit.min.js +7 -7
  14. package/es2018/plugins/debug/debug.min.js +1 -1
  15. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  16. package/es2021/jodit.css +1 -1
  17. package/es2021/jodit.fat.min.js +9 -9
  18. package/es2021/jodit.js +335 -79
  19. package/es2021/jodit.min.js +9 -9
  20. package/es2021/plugins/debug/debug.css +1 -1
  21. package/es2021/plugins/debug/debug.js +1 -1
  22. package/es2021/plugins/debug/debug.min.js +1 -1
  23. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  24. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  25. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  26. package/es2021.en/jodit.css +1 -1
  27. package/es2021.en/jodit.fat.min.js +10 -10
  28. package/es2021.en/jodit.js +335 -79
  29. package/es2021.en/jodit.min.js +9 -9
  30. package/es2021.en/plugins/debug/debug.css +1 -1
  31. package/es2021.en/plugins/debug/debug.js +1 -1
  32. package/es2021.en/plugins/debug/debug.min.js +1 -1
  33. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  34. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  35. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  36. package/es5/jodit.css +2 -2
  37. package/es5/jodit.fat.min.js +2 -2
  38. package/es5/jodit.js +367 -85
  39. package/es5/jodit.min.css +2 -2
  40. package/es5/jodit.min.js +2 -2
  41. package/es5/plugins/debug/debug.css +1 -1
  42. package/es5/plugins/debug/debug.js +1 -1
  43. package/es5/plugins/debug/debug.min.js +1 -1
  44. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  45. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  46. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  47. package/es5/polyfills.fat.min.js +1 -1
  48. package/es5/polyfills.js +1 -1
  49. package/es5/polyfills.min.js +1 -1
  50. package/esm/core/constants.js +1 -1
  51. package/esm/core/helpers/html/apply-styles.js +11 -0
  52. package/esm/core/helpers/html/clean-from-word.js +9 -0
  53. package/esm/core/helpers/html/safe-html.js +71 -19
  54. package/esm/core/helpers/html/strip-tags.d.ts +1 -1
  55. package/esm/core/helpers/html/strip-tags.js +7 -3
  56. package/esm/core/helpers/utils/config-proto.js +15 -0
  57. package/esm/core/helpers/utils/convert-media-url-to-video-embed.js +41 -19
  58. package/esm/jodit.js +20 -0
  59. package/esm/modules/uploader/config.js +11 -1
  60. package/esm/plugins/clean-html/helpers/visitor/filters/try-remove-node.js +8 -1
  61. package/esm/plugins/color/config.js +12 -3
  62. package/esm/plugins/drag-and-drop-element/drag-and-drop-element.d.ts +21 -0
  63. package/esm/plugins/drag-and-drop-element/drag-and-drop-element.js +48 -3
  64. package/esm/plugins/enter/enter.js +11 -6
  65. package/esm/plugins/hotkeys/config.js +1 -1
  66. package/esm/plugins/indent/config.js +20 -6
  67. package/esm/plugins/paste/paste.js +6 -1
  68. package/esm/plugins/paste-from-word/paste-from-word.js +1 -1
  69. package/esm/plugins/select/select.d.ts +8 -0
  70. package/esm/plugins/select/select.js +37 -0
  71. package/package.json +1 -1
  72. package/types/core/helpers/html/strip-tags.d.ts +1 -1
  73. package/types/plugins/drag-and-drop-element/drag-and-drop-element.d.ts +21 -0
  74. package/types/plugins/select/select.d.ts +8 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.12.17
4
+ * Version: v4.12.20
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1802,7 +1802,7 @@ __webpack_require__.r(__webpack_exports__);
1802
1802
  * ```
1803
1803
  * @packageDocumentation
1804
1804
  * @module constants
1805
- */ const APP_VERSION = "4.12.17";
1805
+ */ const APP_VERSION = "4.12.20";
1806
1806
  // prettier-ignore
1807
1807
  const ES = "es2021";
1808
1808
  const IS_ES_MODERN = true;
@@ -5767,6 +5767,16 @@ function normalizeCSS(s) {
5767
5767
  iframeDoc.open();
5768
5768
  iframeDoc.write(html);
5769
5769
  iframeDoc.close();
5770
+ // Word marks its auto-generated list markers (the literal
5771
+ // bullet/number, e.g. `1.` or `·`) with `mso-list:Ignore`.
5772
+ // They are display-only and must not be imported, otherwise
5773
+ // the marker text leaks into the content. Drop them before any
5774
+ // style normalization strips the `mso-list` hint. See #948
5775
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.each(iframeDoc.body, (node)=>{
5776
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isElement(node) && /mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
5777
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
5778
+ }
5779
+ });
5770
5780
  try {
5771
5781
  for(let i = 0; i < iframeDoc.styleSheets.length; i += 1){
5772
5782
  const rules = iframeDoc.styleSheets[i].cssRules;
@@ -5864,6 +5874,15 @@ function normalizeCSS(s) {
5864
5874
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(node);
5865
5875
  break;
5866
5876
  default:
5877
+ // Word marks its auto-generated list markers
5878
+ // (the literal bullet/number, e.g. `1.` or `·`)
5879
+ // with `mso-list:Ignore`. They are display-only
5880
+ // and must not be imported, otherwise the marker
5881
+ // text leaks into the content. See #948
5882
+ if (/mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
5883
+ marks.push(node);
5884
+ break;
5885
+ }
5867
5886
  (0,jodit_core_helpers_array_to_array__WEBPACK_IMPORTED_MODULE_2__.toArray)(node.attributes).forEach((attr)=>{
5868
5887
  if ([
5869
5888
  'src',
@@ -6004,20 +6023,20 @@ function normalizeCSS(s) {
6004
6023
  return;
6005
6024
  }
6006
6025
  const removeEvents = options.removeEventAttributes ?? options.removeOnError;
6007
- if (removeEvents) {
6008
- removeAllEventAttributes(box);
6009
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('*', box).forEach((elm)=>removeAllEventAttributes(elm));
6010
- } else if (options.removeOnError) {
6011
- sanitizeHTMLElement(box, options);
6012
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('[onerror]', box).forEach((elm)=>sanitizeHTMLElement(elm, options));
6013
- }
6014
- if (options.safeJavaScriptLink) {
6015
- sanitizeHTMLElement(box, options);
6016
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('a[href^="javascript"]', box).forEach((elm)=>sanitizeHTMLElement(elm, options));
6017
- }
6018
- if (options.safeLinksTarget) {
6019
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('a[target="_blank"]', box).forEach((elm)=>{
6020
- const rel = elm.getAttribute('rel') || '';
6026
+ // Single synchronous traversal of the subtree. Besides removing event
6027
+ // handlers and `javascript:` links, `sanitizeHTMLElement` neutralises
6028
+ // executable `iframe[srcdoc]`, `data:text/html` / SVG `data:` document
6029
+ // sources and dangerous schemes in every URL-bearing attribute.
6030
+ const process = (node)=>{
6031
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement(node)) {
6032
+ return;
6033
+ }
6034
+ if (removeEvents) {
6035
+ removeAllEventAttributes(node);
6036
+ }
6037
+ sanitizeHTMLElement(node, options);
6038
+ if (options.safeLinksTarget && node.nodeName === 'A' && node.getAttribute('target') === '_blank') {
6039
+ const rel = node.getAttribute('rel') || '';
6021
6040
  const parts = rel.split(/\s+/).filter(Boolean);
6022
6041
  if (!parts.includes('noopener')) {
6023
6042
  parts.push('noopener');
@@ -6025,9 +6044,11 @@ function normalizeCSS(s) {
6025
6044
  if (!parts.includes('noreferrer')) {
6026
6045
  parts.push('noreferrer');
6027
6046
  }
6028
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'rel', parts.join(' '));
6029
- });
6030
- }
6047
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(node, 'rel', parts.join(' '));
6048
+ }
6049
+ };
6050
+ process(box);
6051
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.each(box, process);
6031
6052
  }
6032
6053
  /**
6033
6054
  * Remove all on* event handler attributes from an element
@@ -6048,6 +6069,41 @@ function normalizeCSS(s) {
6048
6069
  }
6049
6070
  return effected;
6050
6071
  }
6072
+ /**
6073
+ * URL-bearing attributes (besides `href`) that can load or execute content.
6074
+ */ const URL_ATTRIBUTES = [
6075
+ 'src',
6076
+ 'data',
6077
+ 'action',
6078
+ 'formaction',
6079
+ 'poster',
6080
+ 'background',
6081
+ 'xlink:href'
6082
+ ];
6083
+ /**
6084
+ * Tags that load their URL as a *document* (scripts inside run). An SVG data
6085
+ * URL is only an XSS vector here — as an `<img>` source it renders inertly.
6086
+ */ const DOCUMENT_EMBED_TAGS = new Set([
6087
+ 'iframe',
6088
+ 'frame',
6089
+ 'object',
6090
+ 'embed'
6091
+ ]);
6092
+ /**
6093
+ * Detects executable / script-bearing URL schemes. The attribute value is
6094
+ * already HTML-entity-decoded by `getAttribute`, so only whitespace and
6095
+ * control characters (which browsers ignore inside a scheme) need stripping.
6096
+ */ function isDangerousUrl(value, tagName) {
6097
+ // eslint-disable-next-line no-control-regex
6098
+ const normalized = value.replace(/[\u0000-\u0020]+/g, '').toLowerCase();
6099
+ if (/^(?:javascript|vbscript|livescript|mocha):/.test(normalized)) {
6100
+ return true;
6101
+ }
6102
+ if (/^data:(?:text\/html|application\/xhtml)/.test(normalized)) {
6103
+ return true;
6104
+ }
6105
+ return /^data:image\/svg/.test(normalized) && DOCUMENT_EMBED_TAGS.has(tagName);
6106
+ }
6051
6107
  function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
6052
6108
  safeJavaScriptLink: true,
6053
6109
  removeOnError: true
@@ -6065,6 +6121,22 @@ function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
6065
6121
  (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'href', location.protocol + '//' + href);
6066
6122
  effected = true;
6067
6123
  }
6124
+ if (safeJavaScriptLink) {
6125
+ // `srcdoc` runs its content as a full HTML document — drop it entirely.
6126
+ if (elm.hasAttribute('srcdoc')) {
6127
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'srcdoc', null);
6128
+ effected = true;
6129
+ }
6130
+ // Strip executable schemes from any other URL-bearing attribute.
6131
+ const tagName = elm.nodeName.toLowerCase();
6132
+ for (const name of URL_ATTRIBUTES){
6133
+ const value = elm.getAttribute(name);
6134
+ if (value && isDangerousUrl(value, tagName)) {
6135
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, name, null);
6136
+ effected = true;
6137
+ }
6138
+ }
6139
+ }
6068
6140
  return effected;
6069
6141
  }
6070
6142
 
@@ -6115,7 +6187,7 @@ const ALONE_TAGS = new Set([
6115
6187
  ]);
6116
6188
  /**
6117
6189
  * Extract plain text from HTML text
6118
- */ function stripTags(html, doc = document, exclude = null) {
6190
+ */ function stripTags(html, doc = document, exclude = null, blockBr = false) {
6119
6191
  const tmp = doc.createElement('div');
6120
6192
  if ((0,jodit_core_helpers_checker_is_string__WEBPACK_IMPORTED_MODULE_1__.isString)(html)) {
6121
6193
  tmp.innerHTML = html;
@@ -6129,7 +6201,7 @@ const ALONE_TAGS = new Set([
6129
6201
  }
6130
6202
  if (exclude && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, exclude)) {
6131
6203
  const tag = p.nodeName.toLowerCase();
6132
- const text = !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, ALONE_TAGS) ? `%%%jodit-${tag}%%%${stripTags(p.innerHTML, doc, exclude)}%%%/jodit-${tag}%%%` : `%%%jodit-single-${tag}%%%`;
6204
+ const text = !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, ALONE_TAGS) ? `%%%jodit-${tag}%%%${stripTags(p.innerHTML, doc, exclude, blockBr)}%%%/jodit-${tag}%%%` : `%%%jodit-single-${tag}%%%`;
6133
6205
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.before(p, doc.createTextNode(text));
6134
6206
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.safeRemove(p);
6135
6207
  return;
@@ -6146,7 +6218,11 @@ const ALONE_TAGS = new Set([
6146
6218
  return;
6147
6219
  }
6148
6220
  if (nx) {
6149
- pr.insertBefore(doc.createTextNode(' '), nx);
6221
+ // By default blocks are joined with a single space (single-line
6222
+ // plain text). When `blockBr` is set, separate them with a line
6223
+ // break instead, so paragraph structure survives — e.g. the
6224
+ // "Insert only Text" paste option. See #1232
6225
+ pr.insertBefore(doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '), nx);
6150
6226
  }
6151
6227
  });
6152
6228
  return restoreTags((0,jodit_core_helpers_string_trim__WEBPACK_IMPORTED_MODULE_2__.trim)(tmp.innerText));
@@ -7635,6 +7711,18 @@ const completeUrl = (url)=>{
7635
7711
 
7636
7712
 
7637
7713
 
7714
+ /**
7715
+ * Keys that must never be copied from a (potentially untrusted) config object —
7716
+ * assigning them during a recursive merge can reach and mutate
7717
+ * `Object.prototype` (prototype pollution, CWE-1321).
7718
+ */ const UNSAFE_PROTO_KEYS = [
7719
+ '__proto__',
7720
+ 'constructor',
7721
+ 'prototype'
7722
+ ];
7723
+ function isUnsafeProtoKey(key) {
7724
+ return UNSAFE_PROTO_KEYS.indexOf(key) !== -1;
7725
+ }
7638
7726
  /**
7639
7727
  * @example
7640
7728
  * ```js
@@ -7683,6 +7771,9 @@ const completeUrl = (url)=>{
7683
7771
  }
7684
7772
  const newOpt = {};
7685
7773
  Object.keys(options).forEach((key)=>{
7774
+ if (isUnsafeProtoKey(key)) {
7775
+ return;
7776
+ }
7686
7777
  const opt = options[key], protoKey = proto ? proto[key] : null;
7687
7778
  if ((0,jodit_core_helpers_checker_is_plain_object__WEBPACK_IMPORTED_MODULE_1__.isPlainObject)(opt) && (0,jodit_core_helpers_checker_is_plain_object__WEBPACK_IMPORTED_MODULE_1__.isPlainObject)(protoKey) && !(0,_extend__WEBPACK_IMPORTED_MODULE_5__.isAtom)(opt)) {
7688
7779
  newOpt[key] = ConfigProto(opt, protoKey, deep + 1);
@@ -7744,6 +7835,9 @@ function ConfigFlatten(obj) {
7744
7835
  * @see {@link ConfigProto} for the prototype-chain variant used at editor creation time
7745
7836
  */ function ConfigMerge(target, source) {
7746
7837
  Object.keys(source).forEach((key)=>{
7838
+ if (isUnsafeProtoKey(key)) {
7839
+ return;
7840
+ }
7747
7841
  const srcVal = source[key];
7748
7842
  const tgtVal = target[key];
7749
7843
  if ((0,jodit_core_helpers_checker_is_plain_object__WEBPACK_IMPORTED_MODULE_1__.isPlainObject)(srcVal) && (0,jodit_core_helpers_checker_is_plain_object__WEBPACK_IMPORTED_MODULE_1__.isPlainObject)(tgtVal) && !(0,_extend__WEBPACK_IMPORTED_MODULE_5__.isAtom)(srcVal)) {
@@ -7789,7 +7883,6 @@ function ConfigDeepFlatten(obj) {
7789
7883
  return url;
7790
7884
  }
7791
7885
  const parser = jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.globalDocument.createElement('a');
7792
- const pattern1 = /(?:http?s?:\/\/)?(?:www\.)?(?:vimeo\.com)\/?(.+)/g;
7793
7886
  parser.href = url;
7794
7887
  if (!width) {
7795
7888
  width = 400;
@@ -7801,19 +7894,41 @@ function ConfigDeepFlatten(obj) {
7801
7894
  switch(parser.hostname){
7802
7895
  case 'www.vimeo.com':
7803
7896
  case 'vimeo.com':
7804
- return pattern1.test(url) ? url.replace(pattern1, '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//player.vimeo.com/video/$1" frameborder="0" allowfullscreen></iframe>') : url;
7897
+ {
7898
+ // The numeric video id can be preceded by `channels/<name>/` or
7899
+ // `groups/<name>/videos/` and followed by tracking params (e.g.
7900
+ // `?share=copy`). Unlisted videos keep a hash right after the id
7901
+ // (`vimeo.com/<id>/<hash>`). Extract the id (+ hash) from the path
7902
+ // so all of those forms produce a valid embed. See #1209
7903
+ const segments = parser.pathname.split('/').filter(Boolean);
7904
+ const idIndex = segments.findIndex((s)=>/^\d+$/.test(s));
7905
+ if (idIndex === -1) {
7906
+ return url;
7907
+ }
7908
+ let path = segments[idIndex];
7909
+ const hash = segments[idIndex + 1];
7910
+ if (hash && idIndex === 0) {
7911
+ path += '/' + hash;
7912
+ }
7913
+ return '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//player.vimeo.com/video/' + path + '" frameborder="0" allowfullscreen></iframe>';
7914
+ }
7805
7915
  case 'youtube.com':
7806
7916
  case 'www.youtube.com':
7917
+ case 'm.youtube.com':
7918
+ case 'music.youtube.com':
7807
7919
  case 'youtu.be':
7808
7920
  case 'www.youtu.be':
7809
7921
  {
7810
- const query = parser.search ? (0,_parse_query__WEBPACK_IMPORTED_MODULE_2__.parseQuery)(parser.search) : {
7811
- v: parser.pathname.substring(1)
7812
- };
7813
- if (/^embed\/.*/.test(query.v)) {
7814
- query.v = query.v.substring(6);
7815
- }
7816
- return query.v ? '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//www.youtube.com/embed/' + query.v + '" frameborder="0" allowfullscreen></iframe>' : url;
7922
+ const query = parser.search ? (0,_parse_query__WEBPACK_IMPORTED_MODULE_2__.parseQuery)(parser.search) : {};
7923
+ // `youtube.com/watch` keeps the video id in the `v` query
7924
+ // parameter, while the short `youtu.be/<id>` links and the
7925
+ // `/embed/`, `/shorts/`, `/live/` paths keep it in the pathname.
7926
+ // Modern share urls add tracking params (e.g. `?si=`, `?t=`), so
7927
+ // the pathname must still be used as a fallback when there is no
7928
+ // `v`. See #1209
7929
+ let v = query.v || parser.pathname.substring(1);
7930
+ v = v.replace(/^(watch|embed|shorts|live|v)\//, '').replace(/\/$/, '');
7931
+ return v ? '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//www.youtube.com/embed/' + v + '" frameborder="0" allowfullscreen></iframe>' : url;
7817
7932
  }
7818
7933
  }
7819
7934
  return url;
@@ -17621,6 +17736,23 @@ class Jodit extends jodit_modules__WEBPACK_IMPORTED_MODULE_9__.ViewWithToolbar {
17621
17736
  }
17622
17737
  this.synchronizeValues();
17623
17738
  }
17739
+ }).on(this.ow, 'mouseup', (event)=>{
17740
+ if (this.o.readonly || this.__isSilentChange) {
17741
+ return;
17742
+ }
17743
+ // When a selection is started inside the editor and the
17744
+ // mouse button is released outside of it, the editable
17745
+ // area never receives the `mouseup` event, so the toolbar
17746
+ // state (active buttons) is not recalculated. Re-fire the
17747
+ // event manually for that case while the selection still
17748
+ // belongs to the editor. See #1251
17749
+ const target = event.target;
17750
+ const insideEditor = Boolean(target && (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.isNumber)(target.nodeType) && editor.contains(target));
17751
+ if (insideEditor || !this.s.isInsideArea) {
17752
+ return;
17753
+ }
17754
+ this.e.fire('changeSelection');
17755
+ this.synchronizeValues();
17624
17756
  });
17625
17757
  }
17626
17758
  fetch(url, options) {
@@ -24016,9 +24148,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.uploader = {
24016
24148
  insertImageAsBase64URI: false,
24017
24149
  imagesExtensions: [
24018
24150
  'jpg',
24019
- 'png',
24020
24151
  'jpeg',
24021
- 'gif'
24152
+ 'png',
24153
+ 'gif',
24154
+ 'webp',
24155
+ 'bmp',
24156
+ 'svg',
24157
+ 'tiff',
24158
+ 'avif'
24022
24159
  ],
24023
24160
  headers: null,
24024
24161
  data: null,
@@ -27931,7 +28068,11 @@ function filterStyleProperties(style, allowed) {
27931
28068
  if (!jodit.o.cleanHTML.removeEmptyElements) {
27932
28069
  return false;
27933
28070
  }
27934
- return jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isElement(node) && node.nodeName.match(jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_INLINE) != null && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTemporary(node) && (0,jodit_core_helpers_string_trim__WEBPACK_IMPORTED_MODULE_2__.trimInv)(node.innerHTML).length === 0 && (current == null || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isOrContains(node, current));
28071
+ // Never drop an empty inline element that currently holds the caret it is
28072
+ // a pending-format marker the user is about to type into (#1291). `current`
28073
+ // is captured before a click moves the caret, so also check the live caret.
28074
+ const liveCaret = jodit.s.isCollapsed() ? jodit.s.range.startContainer : null;
28075
+ return jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isElement(node) && node.nodeName.match(jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_INLINE) != null && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTemporary(node) && (0,jodit_core_helpers_string_trim__WEBPACK_IMPORTED_MODULE_2__.trimInv)(node.innerHTML).length === 0 && (current == null || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isOrContains(node, current)) && (liveCaret == null || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isOrContains(node, liveCaret));
27935
28076
  }
27936
28077
 
27937
28078
 
@@ -28237,8 +28378,9 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
28237
28378
  const update = (key, value)=>{
28238
28379
  if (value && value !== (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(editor.editor, key).toString()) {
28239
28380
  button.state.icon.fill = value;
28240
- return;
28381
+ return true;
28241
28382
  }
28383
+ return false;
28242
28384
  };
28243
28385
  if (color) {
28244
28386
  const mode = (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.dataBind)(button, 'color');
@@ -28248,8 +28390,16 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
28248
28390
  const current = editor.s.current();
28249
28391
  if (current && !button.state.disabled) {
28250
28392
  const currentBpx = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement, editor.editor) || editor.editor;
28251
- update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
28252
- update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
28393
+ // The icon's fill mirrors the current text/background color so the
28394
+ // button reflects the formatting under the caret. Both calls run so
28395
+ // that a background color (the second call) wins over the text color
28396
+ // when both are set. Keep the computed fill instead of resetting it
28397
+ // below. See #195, #182
28398
+ const hasColor = update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
28399
+ const hasBackground = update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
28400
+ if (hasColor || hasBackground) {
28401
+ return;
28402
+ }
28253
28403
  }
28254
28404
  button.state.icon.fill = '';
28255
28405
  button.state.activated = false;
@@ -28723,11 +28873,33 @@ var DragState = /*#__PURE__*/ function(DragState) {
28723
28873
  */ class dragAndDropElement extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
28724
28874
  /** @override */ afterInit() {
28725
28875
  this.dragList = this.j.o.draggableTags ? (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.splitArray)(this.j.o.draggableTags).filter(Boolean).map((item)=>item.toLowerCase()) : [];
28876
+ // Allow another plugin (e.g. a drag handle/anchor) to start dragging
28877
+ // an element programmatically, regardless of the `draggableTags` list.
28878
+ this.j.e.on('startDragElement', this.onStartDragElement);
28726
28879
  if (!this.dragList.length) {
28727
28880
  return;
28728
28881
  }
28729
28882
  this.j.e.on('mousedown dragstart', this.onDragStart);
28730
28883
  }
28884
+ /**
28885
+ * Start dragging a specific element programmatically.
28886
+ *
28887
+ * Allows a separate UI element (for example a drag handle/anchor shown next
28888
+ * to a block) to initiate the drag without the user pressing directly on the
28889
+ * draggable element itself.
28890
+ *
28891
+ * @example
28892
+ * ```js
28893
+ * handle.addEventListener('mousedown', e => {
28894
+ * editor.e.fire('startDragElement', preBlock, e);
28895
+ * });
28896
+ * ```
28897
+ */ onStartDragElement(element, event) {
28898
+ if (this.isInDestruct || this.state > 0 || !element) {
28899
+ return;
28900
+ }
28901
+ this.startDragging(element, event);
28902
+ }
28731
28903
  /**
28732
28904
  * Drag start handler
28733
28905
  */ onDragStart(event) {
@@ -28749,11 +28921,18 @@ var DragState = /*#__PURE__*/ function(DragState) {
28749
28921
  if (jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isTag(lastTarget.parentElement, 'a') && lastTarget.parentElement.firstChild === lastTarget && lastTarget.parentElement.lastChild === lastTarget) {
28750
28922
  lastTarget = lastTarget.parentElement;
28751
28923
  }
28924
+ this.startDragging(lastTarget, event);
28925
+ }
28926
+ /**
28927
+ * Prepare the ghost element and switch to the waiting state.
28928
+ * Shared by the native mousedown handler and the programmatic
28929
+ * `startDragElement` event handler.
28930
+ */ startDragging(target, event) {
28752
28931
  this.startX = event.clientX;
28753
28932
  this.startY = event.clientY;
28754
28933
  this.isCopyMode = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.ctrlKey)(event); // we can move only element from editor
28755
- this.draggable = lastTarget.cloneNode(true);
28756
- (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.dataBind)(this.draggable, 'target', lastTarget);
28934
+ this.draggable = target.cloneNode(true);
28935
+ (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.dataBind)(this.draggable, 'target', target);
28757
28936
  this.state = 1;
28758
28937
  this.addDragListeners();
28759
28938
  }
@@ -28822,6 +29001,18 @@ var DragState = /*#__PURE__*/ function(DragState) {
28822
29001
  }
28823
29002
  const { parentElement } = fragment;
28824
29003
  this.j.s.insertNode(fragment, true, false);
29004
+ // Dropping a non-editable block (e.g. a `<pre>` code sample) can leave an
29005
+ // invisible filler text node beside it. Remove it so the drop does not
29006
+ // introduce a stray empty line (which clean-html would otherwise strip
29007
+ // later, causing a flash).
29008
+ [
29009
+ fragment.previousSibling,
29010
+ fragment.nextSibling
29011
+ ].forEach((node)=>{
29012
+ if (jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isEmptyTextNode(node)) {
29013
+ jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.safeRemove(node);
29014
+ }
29015
+ });
28825
29016
  if (parentElement && jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isEmpty(parentElement) && !jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isCell(parentElement)) {
28826
29017
  jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.safeRemove(parentElement);
28827
29018
  }
@@ -28848,7 +29039,7 @@ var DragState = /*#__PURE__*/ function(DragState) {
28848
29039
  }
28849
29040
  /** @override */ beforeDestruct() {
28850
29041
  this.onDragEnd();
28851
- this.j.e.off('mousedown dragstart', this.onDragStart);
29042
+ this.j.e.off('mousedown dragstart', this.onDragStart).off('startDragElement', this.onStartDragElement);
28852
29043
  this.removeDragListeners();
28853
29044
  }
28854
29045
  constructor(...args){
@@ -28857,6 +29048,9 @@ var DragState = /*#__PURE__*/ function(DragState) {
28857
29048
  */ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "diffStep", 10), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "startX", 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "startY", 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "state", 0);
28858
29049
  }
28859
29050
  }
29051
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
29052
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
29053
+ ], dragAndDropElement.prototype, "onStartDragElement", null);
28860
29054
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
28861
29055
  jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
28862
29056
  ], dragAndDropElement.prototype, "onDragStart", null);
@@ -29356,12 +29550,17 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_2__.pluginSystem.add('dtd', dtd);
29356
29550
  if (beforeEnter !== undefined) {
29357
29551
  return beforeEnter;
29358
29552
  }
29359
- if (!editor.s.isCollapsed()) {
29360
- editor.execCommand('Delete');
29361
- }
29362
- editor.s.focus();
29363
- this.onEnter(event);
29364
- editor.e.fire('afterEnter', event);
29553
+ // Delete-of-selection + new block must be a single history step,
29554
+ // otherwise pressing Enter over a selection needs two Ctrl+Z to undo
29555
+ // (the first only reverts to the intermediate empty state). #1292
29556
+ editor.history.snapshot.transaction(()=>{
29557
+ if (!editor.s.isCollapsed()) {
29558
+ editor.execCommand('Delete');
29559
+ }
29560
+ editor.s.focus();
29561
+ this.onEnter(event);
29562
+ editor.e.fire('afterEnter', event);
29563
+ });
29365
29564
  editor.synchronizeValues(); // fire change
29366
29565
  return false;
29367
29566
  }
@@ -30467,7 +30666,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.commandToHotkeys = {
30467
30666
  'cmd+shift+7'
30468
30667
  ],
30469
30668
  insertUnorderedList: [
30470
- 'ctrl+shift+8, cmd+shift+8'
30669
+ 'ctrl+shift+8',
30670
+ 'cmd+shift+8'
30471
30671
  ],
30472
30672
  selectall: [
30473
30673
  'ctrl+a',
@@ -32689,13 +32889,29 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.indent = {
32689
32889
  jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.outdent = {
32690
32890
  isDisabled: (editor)=>{
32691
32891
  const current = editor.s.current();
32692
- if (current) {
32693
- const currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
32694
- if (currentBox) {
32695
- const arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
32696
- return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
32892
+ if (!current) {
32893
+ return true;
32894
+ }
32895
+ // A list item whose list is nested inside another list item can be
32896
+ // outdented (un-nested) by the `tab` plugin, even without an inline
32897
+ // indent margin. Keep the button enabled in that case. See #1247
32898
+ if (editor.o.tab?.tabInsideLiInsertNewList) {
32899
+ const li = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, 'li', editor.editor);
32900
+ if (li) {
32901
+ const list = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(li, [
32902
+ 'ul',
32903
+ 'ol'
32904
+ ], editor.editor);
32905
+ if (list && jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(list, 'li', editor.editor)) {
32906
+ return false;
32907
+ }
32697
32908
  }
32698
32909
  }
32910
+ const currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
32911
+ if (currentBox) {
32912
+ const arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
32913
+ return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
32914
+ }
32699
32915
  return true;
32700
32916
  },
32701
32917
  tooltip: 'Decrease Indent'
@@ -35213,7 +35429,7 @@ class pasteFromWord extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugi
35213
35429
  }
35214
35430
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_ONLY_TEXT:
35215
35431
  {
35216
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.stripTags)((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.cleanFromWord)(html));
35432
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.stripTags)((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.cleanFromWord)(html), this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
35217
35433
  break;
35218
35434
  }
35219
35435
  }
@@ -35768,10 +35984,15 @@ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.controls.paste = {
35768
35984
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.cleanFromWord)(html);
35769
35985
  break;
35770
35986
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_ONLY_TEXT:
35771
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags));
35987
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
35772
35988
  break;
35773
35989
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_AS_TEXT:
35774
35990
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.htmlspecialchars)(html);
35991
+ // Keep the source line breaks instead of letting the raw
35992
+ // newlines collapse into spaces when rendered. See #1093
35993
+ if (this.j.o.nl2brInPlainText) {
35994
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.nl2br)(html);
35995
+ }
35775
35996
  break;
35776
35997
  default:
35777
35998
  {
@@ -38482,13 +38703,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38482
38703
  /* unused harmony export select */
38483
38704
  /* harmony import */ var _swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25045);
38484
38705
  /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31635);
38485
- /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(84839);
38486
- /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(23211);
38487
- /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28077);
38488
- /* harmony import */ var jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(57821);
38489
- /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91206);
38490
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(4099);
38491
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(47670);
38706
+ /* harmony import */ var jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(81937);
38707
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(84839);
38708
+ /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(23211);
38709
+ /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28077);
38710
+ /* harmony import */ var jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(57821);
38711
+ /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(91206);
38712
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(4099);
38713
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(47670);
38492
38714
  /*!
38493
38715
  * Jodit Editor (https://xdsoft.net/jodit/)
38494
38716
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -38506,6 +38728,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38506
38728
 
38507
38729
 
38508
38730
 
38731
+
38509
38732
  /**
38510
38733
  * A utility plugin that allows you to subscribe to a click/mousedown/touchstart/mouseup on an element in DOM order
38511
38734
  *
@@ -38516,7 +38739,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38516
38739
  * console.log(img.src);
38517
38740
  * })
38518
38741
  * ```
38519
- */ class select extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
38742
+ */ class select extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__.Plugin {
38520
38743
  afterInit(jodit) {
38521
38744
  this.proxyEventsList.forEach((eventName)=>{
38522
38745
  jodit.e.on(eventName + '.select', this.onStartSelection);
@@ -38531,7 +38754,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38531
38754
  const { j } = this;
38532
38755
  let result, target = e.target;
38533
38756
  while(result === undefined && target && target !== j.editor){
38534
- result = j.e.fire((0,jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_5__.camelCase)(e.type + '_' + target.nodeName.toLowerCase()), target, e);
38757
+ result = j.e.fire((0,jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_6__.camelCase)(e.type + '_' + target.nodeName.toLowerCase()), target, e);
38535
38758
  target = target.parentElement;
38536
38759
  }
38537
38760
  if (e.type === 'click' && result === undefined && target === j.editor) {
@@ -38542,10 +38765,10 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38542
38765
  * @event outsideClick(e) - when user clicked on the outside of editor
38543
38766
  */ onOutsideClick(e) {
38544
38767
  const node = e.target;
38545
- if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.up(node, (elm)=>elm === this.j.editor)) {
38768
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.up(node, (elm)=>elm === this.j.editor)) {
38546
38769
  return;
38547
38770
  }
38548
- const box = jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.UIElement.closestElement(node, jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.Popup);
38771
+ const box = jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__.UIElement.closestElement(node, jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__.Popup);
38549
38772
  if (!box) {
38550
38773
  this.j.e.fire('outsideClick', e);
38551
38774
  }
@@ -38554,7 +38777,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38554
38777
  const { s } = this.j;
38555
38778
  if (!s.isCollapsed()) {
38556
38779
  const current = s.current();
38557
- if (current && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isOrContains(this.j.editor, current)) {
38780
+ if (current && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isOrContains(this.j.editor, current)) {
38558
38781
  this.onCopyNormalizeSelectionBound();
38559
38782
  }
38560
38783
  }
@@ -38573,14 +38796,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38573
38796
  */ onClickRightOfNestedListItem(e) {
38574
38797
  const { s } = this.j;
38575
38798
  const range = s.range;
38576
- if (!range.collapsed || range.startOffset !== 0 || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isText(range.startContainer)) {
38799
+ if (!range.collapsed || range.startOffset !== 0 || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(range.startContainer)) {
38577
38800
  return;
38578
38801
  }
38579
38802
  const text = range.startContainer;
38580
38803
  const li = text.parentNode;
38581
38804
  // The text must be the direct content of a list item that has a nested
38582
38805
  // list (the last level has no nested list and behaves correctly).
38583
- if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isTag(li, 'li') || !(li.querySelector('ul') || li.querySelector('ol'))) {
38806
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isTag(li, 'li') || !(li.querySelector('ul') || li.querySelector('ol'))) {
38584
38807
  return;
38585
38808
  }
38586
38809
  const measure = this.j.ed.createRange();
@@ -38591,6 +38814,34 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38591
38814
  s.setCursorAfter(text);
38592
38815
  }
38593
38816
  }
38817
+ /**
38818
+ * Keep pending inline formatting after a click. Toggling Bold/Italic/etc. on
38819
+ * a collapsed cursor leaves empty marker elements with the caret inside; a
38820
+ * click puts the caret right before them (outside), so they get cleaned up
38821
+ * and the formatting is lost. Move the caret back into the innermost marker
38822
+ * so the next typed character keeps every pending format (#1291).
38823
+ */ onClickKeepPendingFormat() {
38824
+ const { s } = this.j;
38825
+ const range = s.range;
38826
+ if (!range.collapsed || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(range.startContainer)) {
38827
+ return;
38828
+ }
38829
+ const text = range.startContainer;
38830
+ // Caret must sit at the very end of the text, right before the markers.
38831
+ if (range.startOffset !== (text.nodeValue?.length ?? 0)) {
38832
+ return;
38833
+ }
38834
+ const marker = text.nextSibling;
38835
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isElement(marker) || !marker.nodeName.match(jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.IS_INLINE) || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isEmpty(marker)) {
38836
+ return;
38837
+ }
38838
+ let inner = marker;
38839
+ // Descend into the innermost empty formatting marker.
38840
+ while(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isElement(inner.firstElementChild) && inner.firstElementChild.nodeName.match(jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.IS_INLINE)){
38841
+ inner = inner.firstElementChild;
38842
+ }
38843
+ s.setCursorIn(inner);
38844
+ }
38594
38845
  /**
38595
38846
  * Normalize selection after triple click
38596
38847
  */ onTripleClickNormalizeSelection(e) {
@@ -38599,8 +38850,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38599
38850
  }
38600
38851
  const { s } = this.j;
38601
38852
  const { startContainer, startOffset } = s.range;
38602
- if (startOffset === 0 && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isText(startContainer)) {
38603
- s.select(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.closest(startContainer, jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isBlock, this.j.editor) || startContainer, true);
38853
+ if (startOffset === 0 && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(startContainer)) {
38854
+ s.select(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.closest(startContainer, jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isBlock, this.j.editor) || startContainer, true);
38604
38855
  }
38605
38856
  }
38606
38857
  onCopyNormalizeSelectionBound(e) {
@@ -38608,7 +38859,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38608
38859
  if (!o.select.normalizeSelectionBeforeCutAndCopy || s.isCollapsed()) {
38609
38860
  return;
38610
38861
  }
38611
- if (e && (!e.isTrusted || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isNode(e.target) || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isOrContains(editor, e.target))) {
38862
+ if (e && (!e.isTrusted || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isNode(e.target) || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isOrContains(editor, e.target))) {
38612
38863
  return;
38613
38864
  }
38614
38865
  this.jodit.s.expandSelection();
@@ -38624,38 +38875,43 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
38624
38875
  }
38625
38876
  }
38626
38877
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38627
- jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
38878
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.autobind
38628
38879
  ], select.prototype, "onStartSelection", null);
38629
38880
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38630
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)('ow:click')
38881
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)('ow:click')
38631
38882
  ], select.prototype, "onOutsideClick", null);
38632
38883
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38633
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
38884
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
38634
38885
  ':beforeCommandCut'
38635
38886
  ])
38636
38887
  ], select.prototype, "beforeCommandCut", null);
38637
38888
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38638
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
38889
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
38639
38890
  ':beforeCommandSelectall'
38640
38891
  ])
38641
38892
  ], select.prototype, "beforeCommandSelectAll", null);
38642
38893
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38643
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
38894
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
38644
38895
  ':click'
38645
38896
  ])
38646
38897
  ], select.prototype, "onClickRightOfNestedListItem", null);
38647
38898
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38648
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
38899
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
38900
+ ':click'
38901
+ ])
38902
+ ], select.prototype, "onClickKeepPendingFormat", null);
38903
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38904
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
38649
38905
  ':click'
38650
38906
  ])
38651
38907
  ], select.prototype, "onTripleClickNormalizeSelection", null);
38652
38908
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
38653
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
38909
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
38654
38910
  ':copy',
38655
38911
  ':cut'
38656
38912
  ])
38657
38913
  ], select.prototype, "onCopyNormalizeSelectionBound", null);
38658
- jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('select', select);
38914
+ jodit_core_global__WEBPACK_IMPORTED_MODULE_5__.pluginSystem.add('select', select);
38659
38915
 
38660
38916
 
38661
38917
  /***/ }),