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
package/es2021/jodit.js CHANGED
@@ -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) {
@@ -24036,9 +24168,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.uploader = {
24036
24168
  insertImageAsBase64URI: false,
24037
24169
  imagesExtensions: [
24038
24170
  'jpg',
24039
- 'png',
24040
24171
  'jpeg',
24041
- 'gif'
24172
+ 'png',
24173
+ 'gif',
24174
+ 'webp',
24175
+ 'bmp',
24176
+ 'svg',
24177
+ 'tiff',
24178
+ 'avif'
24042
24179
  ],
24043
24180
  headers: null,
24044
24181
  data: null,
@@ -28001,7 +28138,11 @@ function filterStyleProperties(style, allowed) {
28001
28138
  if (!jodit.o.cleanHTML.removeEmptyElements) {
28002
28139
  return false;
28003
28140
  }
28004
- 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));
28141
+ // Never drop an empty inline element that currently holds the caret it is
28142
+ // a pending-format marker the user is about to type into (#1291). `current`
28143
+ // is captured before a click moves the caret, so also check the live caret.
28144
+ const liveCaret = jodit.s.isCollapsed() ? jodit.s.range.startContainer : null;
28145
+ 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));
28005
28146
  }
28006
28147
 
28007
28148
 
@@ -28307,8 +28448,9 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
28307
28448
  const update = (key, value)=>{
28308
28449
  if (value && value !== (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(editor.editor, key).toString()) {
28309
28450
  button.state.icon.fill = value;
28310
- return;
28451
+ return true;
28311
28452
  }
28453
+ return false;
28312
28454
  };
28313
28455
  if (color) {
28314
28456
  const mode = (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.dataBind)(button, 'color');
@@ -28318,8 +28460,16 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
28318
28460
  const current = editor.s.current();
28319
28461
  if (current && !button.state.disabled) {
28320
28462
  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;
28321
- update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
28322
- update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
28463
+ // The icon's fill mirrors the current text/background color so the
28464
+ // button reflects the formatting under the caret. Both calls run so
28465
+ // that a background color (the second call) wins over the text color
28466
+ // when both are set. Keep the computed fill instead of resetting it
28467
+ // below. See #195, #182
28468
+ const hasColor = update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
28469
+ const hasBackground = update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
28470
+ if (hasColor || hasBackground) {
28471
+ return;
28472
+ }
28323
28473
  }
28324
28474
  button.state.icon.fill = '';
28325
28475
  button.state.activated = false;
@@ -29127,11 +29277,33 @@ var DragState = /*#__PURE__*/ function(DragState) {
29127
29277
  */ class dragAndDropElement extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
29128
29278
  /** @override */ afterInit() {
29129
29279
  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()) : [];
29280
+ // Allow another plugin (e.g. a drag handle/anchor) to start dragging
29281
+ // an element programmatically, regardless of the `draggableTags` list.
29282
+ this.j.e.on('startDragElement', this.onStartDragElement);
29130
29283
  if (!this.dragList.length) {
29131
29284
  return;
29132
29285
  }
29133
29286
  this.j.e.on('mousedown dragstart', this.onDragStart);
29134
29287
  }
29288
+ /**
29289
+ * Start dragging a specific element programmatically.
29290
+ *
29291
+ * Allows a separate UI element (for example a drag handle/anchor shown next
29292
+ * to a block) to initiate the drag without the user pressing directly on the
29293
+ * draggable element itself.
29294
+ *
29295
+ * @example
29296
+ * ```js
29297
+ * handle.addEventListener('mousedown', e => {
29298
+ * editor.e.fire('startDragElement', preBlock, e);
29299
+ * });
29300
+ * ```
29301
+ */ onStartDragElement(element, event) {
29302
+ if (this.isInDestruct || this.state > 0 || !element) {
29303
+ return;
29304
+ }
29305
+ this.startDragging(element, event);
29306
+ }
29135
29307
  /**
29136
29308
  * Drag start handler
29137
29309
  */ onDragStart(event) {
@@ -29153,11 +29325,18 @@ var DragState = /*#__PURE__*/ function(DragState) {
29153
29325
  if (jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isTag(lastTarget.parentElement, 'a') && lastTarget.parentElement.firstChild === lastTarget && lastTarget.parentElement.lastChild === lastTarget) {
29154
29326
  lastTarget = lastTarget.parentElement;
29155
29327
  }
29328
+ this.startDragging(lastTarget, event);
29329
+ }
29330
+ /**
29331
+ * Prepare the ghost element and switch to the waiting state.
29332
+ * Shared by the native mousedown handler and the programmatic
29333
+ * `startDragElement` event handler.
29334
+ */ startDragging(target, event) {
29156
29335
  this.startX = event.clientX;
29157
29336
  this.startY = event.clientY;
29158
29337
  this.isCopyMode = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.ctrlKey)(event); // we can move only element from editor
29159
- this.draggable = lastTarget.cloneNode(true);
29160
- (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.dataBind)(this.draggable, 'target', lastTarget);
29338
+ this.draggable = target.cloneNode(true);
29339
+ (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.dataBind)(this.draggable, 'target', target);
29161
29340
  this.state = 1;
29162
29341
  this.addDragListeners();
29163
29342
  }
@@ -29226,6 +29405,18 @@ var DragState = /*#__PURE__*/ function(DragState) {
29226
29405
  }
29227
29406
  const { parentElement } = fragment;
29228
29407
  this.j.s.insertNode(fragment, true, false);
29408
+ // Dropping a non-editable block (e.g. a `<pre>` code sample) can leave an
29409
+ // invisible filler text node beside it. Remove it so the drop does not
29410
+ // introduce a stray empty line (which clean-html would otherwise strip
29411
+ // later, causing a flash).
29412
+ [
29413
+ fragment.previousSibling,
29414
+ fragment.nextSibling
29415
+ ].forEach((node)=>{
29416
+ if (jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isEmptyTextNode(node)) {
29417
+ jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.safeRemove(node);
29418
+ }
29419
+ });
29229
29420
  if (parentElement && jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isEmpty(parentElement) && !jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isCell(parentElement)) {
29230
29421
  jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.safeRemove(parentElement);
29231
29422
  }
@@ -29252,7 +29443,7 @@ var DragState = /*#__PURE__*/ function(DragState) {
29252
29443
  }
29253
29444
  /** @override */ beforeDestruct() {
29254
29445
  this.onDragEnd();
29255
- this.j.e.off('mousedown dragstart', this.onDragStart);
29446
+ this.j.e.off('mousedown dragstart', this.onDragStart).off('startDragElement', this.onStartDragElement);
29256
29447
  this.removeDragListeners();
29257
29448
  }
29258
29449
  constructor(...args){
@@ -29261,6 +29452,9 @@ var DragState = /*#__PURE__*/ function(DragState) {
29261
29452
  */ (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);
29262
29453
  }
29263
29454
  }
29455
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
29456
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
29457
+ ], dragAndDropElement.prototype, "onStartDragElement", null);
29264
29458
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
29265
29459
  jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
29266
29460
  ], dragAndDropElement.prototype, "onDragStart", null);
@@ -29760,12 +29954,17 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_2__.pluginSystem.add('dtd', dtd);
29760
29954
  if (beforeEnter !== undefined) {
29761
29955
  return beforeEnter;
29762
29956
  }
29763
- if (!editor.s.isCollapsed()) {
29764
- editor.execCommand('Delete');
29765
- }
29766
- editor.s.focus();
29767
- this.onEnter(event);
29768
- editor.e.fire('afterEnter', event);
29957
+ // Delete-of-selection + new block must be a single history step,
29958
+ // otherwise pressing Enter over a selection needs two Ctrl+Z to undo
29959
+ // (the first only reverts to the intermediate empty state). #1292
29960
+ editor.history.snapshot.transaction(()=>{
29961
+ if (!editor.s.isCollapsed()) {
29962
+ editor.execCommand('Delete');
29963
+ }
29964
+ editor.s.focus();
29965
+ this.onEnter(event);
29966
+ editor.e.fire('afterEnter', event);
29967
+ });
29769
29968
  editor.synchronizeValues(); // fire change
29770
29969
  return false;
29771
29970
  }
@@ -30871,7 +31070,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.commandToHotkeys = {
30871
31070
  'cmd+shift+7'
30872
31071
  ],
30873
31072
  insertUnorderedList: [
30874
- 'ctrl+shift+8, cmd+shift+8'
31073
+ 'ctrl+shift+8',
31074
+ 'cmd+shift+8'
30875
31075
  ],
30876
31076
  selectall: [
30877
31077
  'ctrl+a',
@@ -33093,13 +33293,29 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.indent = {
33093
33293
  jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.outdent = {
33094
33294
  isDisabled: (editor)=>{
33095
33295
  const current = editor.s.current();
33096
- if (current) {
33097
- const currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
33098
- if (currentBox) {
33099
- const arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
33100
- return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
33296
+ if (!current) {
33297
+ return true;
33298
+ }
33299
+ // A list item whose list is nested inside another list item can be
33300
+ // outdented (un-nested) by the `tab` plugin, even without an inline
33301
+ // indent margin. Keep the button enabled in that case. See #1247
33302
+ if (editor.o.tab?.tabInsideLiInsertNewList) {
33303
+ const li = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, 'li', editor.editor);
33304
+ if (li) {
33305
+ const list = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(li, [
33306
+ 'ul',
33307
+ 'ol'
33308
+ ], editor.editor);
33309
+ if (list && jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(list, 'li', editor.editor)) {
33310
+ return false;
33311
+ }
33101
33312
  }
33102
33313
  }
33314
+ const currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
33315
+ if (currentBox) {
33316
+ const arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
33317
+ return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
33318
+ }
33103
33319
  return true;
33104
33320
  },
33105
33321
  tooltip: 'Decrease Indent'
@@ -35967,7 +36183,7 @@ class pasteFromWord extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugi
35967
36183
  }
35968
36184
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_ONLY_TEXT:
35969
36185
  {
35970
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.stripTags)((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.cleanFromWord)(html));
36186
+ 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);
35971
36187
  break;
35972
36188
  }
35973
36189
  }
@@ -36522,10 +36738,15 @@ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.controls.paste = {
36522
36738
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.cleanFromWord)(html);
36523
36739
  break;
36524
36740
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_ONLY_TEXT:
36525
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags));
36741
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
36526
36742
  break;
36527
36743
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_AS_TEXT:
36528
36744
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.htmlspecialchars)(html);
36745
+ // Keep the source line breaks instead of letting the raw
36746
+ // newlines collapse into spaces when rendered. See #1093
36747
+ if (this.j.o.nl2brInPlainText) {
36748
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.nl2br)(html);
36749
+ }
36529
36750
  break;
36530
36751
  default:
36531
36752
  {
@@ -39236,13 +39457,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39236
39457
  /* unused harmony export select */
39237
39458
  /* harmony import */ var _swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25045);
39238
39459
  /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31635);
39239
- /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(84839);
39240
- /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(23211);
39241
- /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28077);
39242
- /* harmony import */ var jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(57821);
39243
- /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91206);
39244
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(4099);
39245
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(47670);
39460
+ /* harmony import */ var jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(81937);
39461
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(84839);
39462
+ /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(23211);
39463
+ /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28077);
39464
+ /* harmony import */ var jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(57821);
39465
+ /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(91206);
39466
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(4099);
39467
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(47670);
39246
39468
  /*!
39247
39469
  * Jodit Editor (https://xdsoft.net/jodit/)
39248
39470
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -39260,6 +39482,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39260
39482
 
39261
39483
 
39262
39484
 
39485
+
39263
39486
  /**
39264
39487
  * A utility plugin that allows you to subscribe to a click/mousedown/touchstart/mouseup on an element in DOM order
39265
39488
  *
@@ -39270,7 +39493,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39270
39493
  * console.log(img.src);
39271
39494
  * })
39272
39495
  * ```
39273
- */ class select extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
39496
+ */ class select extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__.Plugin {
39274
39497
  afterInit(jodit) {
39275
39498
  this.proxyEventsList.forEach((eventName)=>{
39276
39499
  jodit.e.on(eventName + '.select', this.onStartSelection);
@@ -39285,7 +39508,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39285
39508
  const { j } = this;
39286
39509
  let result, target = e.target;
39287
39510
  while(result === undefined && target && target !== j.editor){
39288
- result = j.e.fire((0,jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_5__.camelCase)(e.type + '_' + target.nodeName.toLowerCase()), target, e);
39511
+ result = j.e.fire((0,jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_6__.camelCase)(e.type + '_' + target.nodeName.toLowerCase()), target, e);
39289
39512
  target = target.parentElement;
39290
39513
  }
39291
39514
  if (e.type === 'click' && result === undefined && target === j.editor) {
@@ -39296,10 +39519,10 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39296
39519
  * @event outsideClick(e) - when user clicked on the outside of editor
39297
39520
  */ onOutsideClick(e) {
39298
39521
  const node = e.target;
39299
- if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.up(node, (elm)=>elm === this.j.editor)) {
39522
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.up(node, (elm)=>elm === this.j.editor)) {
39300
39523
  return;
39301
39524
  }
39302
- const box = jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.UIElement.closestElement(node, jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.Popup);
39525
+ const box = jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__.UIElement.closestElement(node, jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__.Popup);
39303
39526
  if (!box) {
39304
39527
  this.j.e.fire('outsideClick', e);
39305
39528
  }
@@ -39308,7 +39531,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39308
39531
  const { s } = this.j;
39309
39532
  if (!s.isCollapsed()) {
39310
39533
  const current = s.current();
39311
- if (current && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isOrContains(this.j.editor, current)) {
39534
+ if (current && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isOrContains(this.j.editor, current)) {
39312
39535
  this.onCopyNormalizeSelectionBound();
39313
39536
  }
39314
39537
  }
@@ -39327,14 +39550,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39327
39550
  */ onClickRightOfNestedListItem(e) {
39328
39551
  const { s } = this.j;
39329
39552
  const range = s.range;
39330
- if (!range.collapsed || range.startOffset !== 0 || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isText(range.startContainer)) {
39553
+ if (!range.collapsed || range.startOffset !== 0 || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(range.startContainer)) {
39331
39554
  return;
39332
39555
  }
39333
39556
  const text = range.startContainer;
39334
39557
  const li = text.parentNode;
39335
39558
  // The text must be the direct content of a list item that has a nested
39336
39559
  // list (the last level has no nested list and behaves correctly).
39337
- if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isTag(li, 'li') || !(li.querySelector('ul') || li.querySelector('ol'))) {
39560
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isTag(li, 'li') || !(li.querySelector('ul') || li.querySelector('ol'))) {
39338
39561
  return;
39339
39562
  }
39340
39563
  const measure = this.j.ed.createRange();
@@ -39345,6 +39568,34 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39345
39568
  s.setCursorAfter(text);
39346
39569
  }
39347
39570
  }
39571
+ /**
39572
+ * Keep pending inline formatting after a click. Toggling Bold/Italic/etc. on
39573
+ * a collapsed cursor leaves empty marker elements with the caret inside; a
39574
+ * click puts the caret right before them (outside), so they get cleaned up
39575
+ * and the formatting is lost. Move the caret back into the innermost marker
39576
+ * so the next typed character keeps every pending format (#1291).
39577
+ */ onClickKeepPendingFormat() {
39578
+ const { s } = this.j;
39579
+ const range = s.range;
39580
+ if (!range.collapsed || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(range.startContainer)) {
39581
+ return;
39582
+ }
39583
+ const text = range.startContainer;
39584
+ // Caret must sit at the very end of the text, right before the markers.
39585
+ if (range.startOffset !== (text.nodeValue?.length ?? 0)) {
39586
+ return;
39587
+ }
39588
+ const marker = text.nextSibling;
39589
+ 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)) {
39590
+ return;
39591
+ }
39592
+ let inner = marker;
39593
+ // Descend into the innermost empty formatting marker.
39594
+ 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)){
39595
+ inner = inner.firstElementChild;
39596
+ }
39597
+ s.setCursorIn(inner);
39598
+ }
39348
39599
  /**
39349
39600
  * Normalize selection after triple click
39350
39601
  */ onTripleClickNormalizeSelection(e) {
@@ -39353,8 +39604,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39353
39604
  }
39354
39605
  const { s } = this.j;
39355
39606
  const { startContainer, startOffset } = s.range;
39356
- if (startOffset === 0 && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isText(startContainer)) {
39357
- 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);
39607
+ if (startOffset === 0 && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(startContainer)) {
39608
+ 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);
39358
39609
  }
39359
39610
  }
39360
39611
  onCopyNormalizeSelectionBound(e) {
@@ -39362,7 +39613,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39362
39613
  if (!o.select.normalizeSelectionBeforeCutAndCopy || s.isCollapsed()) {
39363
39614
  return;
39364
39615
  }
39365
- 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))) {
39616
+ 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))) {
39366
39617
  return;
39367
39618
  }
39368
39619
  this.jodit.s.expandSelection();
@@ -39378,38 +39629,43 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39378
39629
  }
39379
39630
  }
39380
39631
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39381
- jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
39632
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.autobind
39382
39633
  ], select.prototype, "onStartSelection", null);
39383
39634
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39384
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)('ow:click')
39635
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)('ow:click')
39385
39636
  ], select.prototype, "onOutsideClick", null);
39386
39637
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39387
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39638
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39388
39639
  ':beforeCommandCut'
39389
39640
  ])
39390
39641
  ], select.prototype, "beforeCommandCut", null);
39391
39642
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39392
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39643
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39393
39644
  ':beforeCommandSelectall'
39394
39645
  ])
39395
39646
  ], select.prototype, "beforeCommandSelectAll", null);
39396
39647
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39397
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39648
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39398
39649
  ':click'
39399
39650
  ])
39400
39651
  ], select.prototype, "onClickRightOfNestedListItem", null);
39401
39652
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39402
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39653
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39654
+ ':click'
39655
+ ])
39656
+ ], select.prototype, "onClickKeepPendingFormat", null);
39657
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39658
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39403
39659
  ':click'
39404
39660
  ])
39405
39661
  ], select.prototype, "onTripleClickNormalizeSelection", null);
39406
39662
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39407
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39663
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39408
39664
  ':copy',
39409
39665
  ':cut'
39410
39666
  ])
39411
39667
  ], select.prototype, "onCopyNormalizeSelectionBound", null);
39412
- jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('select', select);
39668
+ jodit_core_global__WEBPACK_IMPORTED_MODULE_5__.pluginSystem.add('select', select);
39413
39669
 
39414
39670
 
39415
39671
  /***/ }),