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/es2015/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
  */
@@ -1808,7 +1808,7 @@ __webpack_require__.r(__webpack_exports__);
1808
1808
  * ```
1809
1809
  * @packageDocumentation
1810
1810
  * @module constants
1811
- */ const APP_VERSION = "4.12.17";
1811
+ */ const APP_VERSION = "4.12.20";
1812
1812
  // prettier-ignore
1813
1813
  const ES = "es2015";
1814
1814
  const IS_ES_MODERN = true;
@@ -5790,6 +5790,16 @@ function normalizeCSS(s) {
5790
5790
  iframeDoc.open();
5791
5791
  iframeDoc.write(html);
5792
5792
  iframeDoc.close();
5793
+ // Word marks its auto-generated list markers (the literal
5794
+ // bullet/number, e.g. `1.` or `·`) with `mso-list:Ignore`.
5795
+ // They are display-only and must not be imported, otherwise
5796
+ // the marker text leaks into the content. Drop them before any
5797
+ // style normalization strips the `mso-list` hint. See #948
5798
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.each(iframeDoc.body, (node)=>{
5799
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isElement(node) && /mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
5800
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
5801
+ }
5802
+ });
5793
5803
  try {
5794
5804
  for(let i = 0; i < iframeDoc.styleSheets.length; i += 1){
5795
5805
  const rules = iframeDoc.styleSheets[i].cssRules;
@@ -5887,6 +5897,15 @@ function normalizeCSS(s) {
5887
5897
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(node);
5888
5898
  break;
5889
5899
  default:
5900
+ // Word marks its auto-generated list markers
5901
+ // (the literal bullet/number, e.g. `1.` or `·`)
5902
+ // with `mso-list:Ignore`. They are display-only
5903
+ // and must not be imported, otherwise the marker
5904
+ // text leaks into the content. See #948
5905
+ if (/mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
5906
+ marks.push(node);
5907
+ break;
5908
+ }
5890
5909
  (0,jodit_core_helpers_array_to_array__WEBPACK_IMPORTED_MODULE_2__.toArray)(node.attributes).forEach((attr)=>{
5891
5910
  if ([
5892
5911
  'src',
@@ -6028,20 +6047,20 @@ function normalizeCSS(s) {
6028
6047
  return;
6029
6048
  }
6030
6049
  const removeEvents = (_options_removeEventAttributes = options.removeEventAttributes) !== null && _options_removeEventAttributes !== void 0 ? _options_removeEventAttributes : options.removeOnError;
6031
- if (removeEvents) {
6032
- removeAllEventAttributes(box);
6033
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('*', box).forEach((elm)=>removeAllEventAttributes(elm));
6034
- } else if (options.removeOnError) {
6035
- sanitizeHTMLElement(box, options);
6036
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('[onerror]', box).forEach((elm)=>sanitizeHTMLElement(elm, options));
6037
- }
6038
- if (options.safeJavaScriptLink) {
6039
- sanitizeHTMLElement(box, options);
6040
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('a[href^="javascript"]', box).forEach((elm)=>sanitizeHTMLElement(elm, options));
6041
- }
6042
- if (options.safeLinksTarget) {
6043
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('a[target="_blank"]', box).forEach((elm)=>{
6044
- const rel = elm.getAttribute('rel') || '';
6050
+ // Single synchronous traversal of the subtree. Besides removing event
6051
+ // handlers and `javascript:` links, `sanitizeHTMLElement` neutralises
6052
+ // executable `iframe[srcdoc]`, `data:text/html` / SVG `data:` document
6053
+ // sources and dangerous schemes in every URL-bearing attribute.
6054
+ const process = (node)=>{
6055
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement(node)) {
6056
+ return;
6057
+ }
6058
+ if (removeEvents) {
6059
+ removeAllEventAttributes(node);
6060
+ }
6061
+ sanitizeHTMLElement(node, options);
6062
+ if (options.safeLinksTarget && node.nodeName === 'A' && node.getAttribute('target') === '_blank') {
6063
+ const rel = node.getAttribute('rel') || '';
6045
6064
  const parts = rel.split(/\s+/).filter(Boolean);
6046
6065
  if (!parts.includes('noopener')) {
6047
6066
  parts.push('noopener');
@@ -6049,9 +6068,11 @@ function normalizeCSS(s) {
6049
6068
  if (!parts.includes('noreferrer')) {
6050
6069
  parts.push('noreferrer');
6051
6070
  }
6052
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'rel', parts.join(' '));
6053
- });
6054
- }
6071
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(node, 'rel', parts.join(' '));
6072
+ }
6073
+ };
6074
+ process(box);
6075
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.each(box, process);
6055
6076
  }
6056
6077
  /**
6057
6078
  * Remove all on* event handler attributes from an element
@@ -6072,6 +6093,41 @@ function normalizeCSS(s) {
6072
6093
  }
6073
6094
  return effected;
6074
6095
  }
6096
+ /**
6097
+ * URL-bearing attributes (besides `href`) that can load or execute content.
6098
+ */ const URL_ATTRIBUTES = [
6099
+ 'src',
6100
+ 'data',
6101
+ 'action',
6102
+ 'formaction',
6103
+ 'poster',
6104
+ 'background',
6105
+ 'xlink:href'
6106
+ ];
6107
+ /**
6108
+ * Tags that load their URL as a *document* (scripts inside run). An SVG data
6109
+ * URL is only an XSS vector here — as an `<img>` source it renders inertly.
6110
+ */ const DOCUMENT_EMBED_TAGS = new Set([
6111
+ 'iframe',
6112
+ 'frame',
6113
+ 'object',
6114
+ 'embed'
6115
+ ]);
6116
+ /**
6117
+ * Detects executable / script-bearing URL schemes. The attribute value is
6118
+ * already HTML-entity-decoded by `getAttribute`, so only whitespace and
6119
+ * control characters (which browsers ignore inside a scheme) need stripping.
6120
+ */ function isDangerousUrl(value, tagName) {
6121
+ // eslint-disable-next-line no-control-regex
6122
+ const normalized = value.replace(/[\u0000-\u0020]+/g, '').toLowerCase();
6123
+ if (/^(?:javascript|vbscript|livescript|mocha):/.test(normalized)) {
6124
+ return true;
6125
+ }
6126
+ if (/^data:(?:text\/html|application\/xhtml)/.test(normalized)) {
6127
+ return true;
6128
+ }
6129
+ return /^data:image\/svg/.test(normalized) && DOCUMENT_EMBED_TAGS.has(tagName);
6130
+ }
6075
6131
  function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
6076
6132
  safeJavaScriptLink: true,
6077
6133
  removeOnError: true
@@ -6089,6 +6145,22 @@ function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
6089
6145
  (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'href', location.protocol + '//' + href);
6090
6146
  effected = true;
6091
6147
  }
6148
+ if (safeJavaScriptLink) {
6149
+ // `srcdoc` runs its content as a full HTML document — drop it entirely.
6150
+ if (elm.hasAttribute('srcdoc')) {
6151
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'srcdoc', null);
6152
+ effected = true;
6153
+ }
6154
+ // Strip executable schemes from any other URL-bearing attribute.
6155
+ const tagName = elm.nodeName.toLowerCase();
6156
+ for (const name of URL_ATTRIBUTES){
6157
+ const value = elm.getAttribute(name);
6158
+ if (value && isDangerousUrl(value, tagName)) {
6159
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, name, null);
6160
+ effected = true;
6161
+ }
6162
+ }
6163
+ }
6092
6164
  return effected;
6093
6165
  }
6094
6166
 
@@ -6139,7 +6211,7 @@ const ALONE_TAGS = new Set([
6139
6211
  ]);
6140
6212
  /**
6141
6213
  * Extract plain text from HTML text
6142
- */ function stripTags(html, doc = document, exclude = null) {
6214
+ */ function stripTags(html, doc = document, exclude = null, blockBr = false) {
6143
6215
  const tmp = doc.createElement('div');
6144
6216
  if ((0,jodit_core_helpers_checker_is_string__WEBPACK_IMPORTED_MODULE_1__.isString)(html)) {
6145
6217
  tmp.innerHTML = html;
@@ -6153,7 +6225,7 @@ const ALONE_TAGS = new Set([
6153
6225
  }
6154
6226
  if (exclude && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, exclude)) {
6155
6227
  const tag = p.nodeName.toLowerCase();
6156
- 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}%%%`;
6228
+ 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}%%%`;
6157
6229
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.before(p, doc.createTextNode(text));
6158
6230
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.safeRemove(p);
6159
6231
  return;
@@ -6170,7 +6242,11 @@ const ALONE_TAGS = new Set([
6170
6242
  return;
6171
6243
  }
6172
6244
  if (nx) {
6173
- pr.insertBefore(doc.createTextNode(' '), nx);
6245
+ // By default blocks are joined with a single space (single-line
6246
+ // plain text). When `blockBr` is set, separate them with a line
6247
+ // break instead, so paragraph structure survives — e.g. the
6248
+ // "Insert only Text" paste option. See #1232
6249
+ pr.insertBefore(doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '), nx);
6174
6250
  }
6175
6251
  });
6176
6252
  return restoreTags((0,jodit_core_helpers_string_trim__WEBPACK_IMPORTED_MODULE_2__.trim)(tmp.innerText));
@@ -7661,6 +7737,18 @@ const completeUrl = (url)=>{
7661
7737
 
7662
7738
 
7663
7739
 
7740
+ /**
7741
+ * Keys that must never be copied from a (potentially untrusted) config object —
7742
+ * assigning them during a recursive merge can reach and mutate
7743
+ * `Object.prototype` (prototype pollution, CWE-1321).
7744
+ */ const UNSAFE_PROTO_KEYS = [
7745
+ '__proto__',
7746
+ 'constructor',
7747
+ 'prototype'
7748
+ ];
7749
+ function isUnsafeProtoKey(key) {
7750
+ return UNSAFE_PROTO_KEYS.indexOf(key) !== -1;
7751
+ }
7664
7752
  /**
7665
7753
  * @example
7666
7754
  * ```js
@@ -7709,6 +7797,9 @@ const completeUrl = (url)=>{
7709
7797
  }
7710
7798
  const newOpt = {};
7711
7799
  Object.keys(options).forEach((key)=>{
7800
+ if (isUnsafeProtoKey(key)) {
7801
+ return;
7802
+ }
7712
7803
  const opt = options[key], protoKey = proto ? proto[key] : null;
7713
7804
  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)) {
7714
7805
  newOpt[key] = ConfigProto(opt, protoKey, deep + 1);
@@ -7770,6 +7861,9 @@ function ConfigFlatten(obj) {
7770
7861
  * @see {@link ConfigProto} for the prototype-chain variant used at editor creation time
7771
7862
  */ function ConfigMerge(target, source) {
7772
7863
  Object.keys(source).forEach((key)=>{
7864
+ if (isUnsafeProtoKey(key)) {
7865
+ return;
7866
+ }
7773
7867
  const srcVal = source[key];
7774
7868
  const tgtVal = target[key];
7775
7869
  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)) {
@@ -7815,7 +7909,6 @@ function ConfigDeepFlatten(obj) {
7815
7909
  return url;
7816
7910
  }
7817
7911
  const parser = jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.globalDocument.createElement('a');
7818
- const pattern1 = /(?:http?s?:\/\/)?(?:www\.)?(?:vimeo\.com)\/?(.+)/g;
7819
7912
  parser.href = url;
7820
7913
  if (!width) {
7821
7914
  width = 400;
@@ -7827,19 +7920,41 @@ function ConfigDeepFlatten(obj) {
7827
7920
  switch(parser.hostname){
7828
7921
  case 'www.vimeo.com':
7829
7922
  case 'vimeo.com':
7830
- return pattern1.test(url) ? url.replace(pattern1, '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//player.vimeo.com/video/$1" frameborder="0" allowfullscreen></iframe>') : url;
7923
+ {
7924
+ // The numeric video id can be preceded by `channels/<name>/` or
7925
+ // `groups/<name>/videos/` and followed by tracking params (e.g.
7926
+ // `?share=copy`). Unlisted videos keep a hash right after the id
7927
+ // (`vimeo.com/<id>/<hash>`). Extract the id (+ hash) from the path
7928
+ // so all of those forms produce a valid embed. See #1209
7929
+ const segments = parser.pathname.split('/').filter(Boolean);
7930
+ const idIndex = segments.findIndex((s)=>/^\d+$/.test(s));
7931
+ if (idIndex === -1) {
7932
+ return url;
7933
+ }
7934
+ let path = segments[idIndex];
7935
+ const hash = segments[idIndex + 1];
7936
+ if (hash && idIndex === 0) {
7937
+ path += '/' + hash;
7938
+ }
7939
+ return '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//player.vimeo.com/video/' + path + '" frameborder="0" allowfullscreen></iframe>';
7940
+ }
7831
7941
  case 'youtube.com':
7832
7942
  case 'www.youtube.com':
7943
+ case 'm.youtube.com':
7944
+ case 'music.youtube.com':
7833
7945
  case 'youtu.be':
7834
7946
  case 'www.youtu.be':
7835
7947
  {
7836
- const query = parser.search ? (0,_parse_query__WEBPACK_IMPORTED_MODULE_2__.parseQuery)(parser.search) : {
7837
- v: parser.pathname.substring(1)
7838
- };
7839
- if (/^embed\/.*/.test(query.v)) {
7840
- query.v = query.v.substring(6);
7841
- }
7842
- return query.v ? '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//www.youtube.com/embed/' + query.v + '" frameborder="0" allowfullscreen></iframe>' : url;
7948
+ const query = parser.search ? (0,_parse_query__WEBPACK_IMPORTED_MODULE_2__.parseQuery)(parser.search) : {};
7949
+ // `youtube.com/watch` keeps the video id in the `v` query
7950
+ // parameter, while the short `youtu.be/<id>` links and the
7951
+ // `/embed/`, `/shorts/`, `/live/` paths keep it in the pathname.
7952
+ // Modern share urls add tracking params (e.g. `?si=`, `?t=`), so
7953
+ // the pathname must still be used as a fallback when there is no
7954
+ // `v`. See #1209
7955
+ let v = query.v || parser.pathname.substring(1);
7956
+ v = v.replace(/^(watch|embed|shorts|live|v)\//, '').replace(/\/$/, '');
7957
+ return v ? '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//www.youtube.com/embed/' + v + '" frameborder="0" allowfullscreen></iframe>' : url;
7843
7958
  }
7844
7959
  }
7845
7960
  return url;
@@ -17752,6 +17867,23 @@ class Jodit extends jodit_modules__WEBPACK_IMPORTED_MODULE_10__.ViewWithToolbar
17752
17867
  }
17753
17868
  this.synchronizeValues();
17754
17869
  }
17870
+ }).on(this.ow, 'mouseup', (event)=>{
17871
+ if (this.o.readonly || this.__isSilentChange) {
17872
+ return;
17873
+ }
17874
+ // When a selection is started inside the editor and the
17875
+ // mouse button is released outside of it, the editable
17876
+ // area never receives the `mouseup` event, so the toolbar
17877
+ // state (active buttons) is not recalculated. Re-fire the
17878
+ // event manually for that case while the selection still
17879
+ // belongs to the editor. See #1251
17880
+ const target = event.target;
17881
+ const insideEditor = Boolean(target && (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.isNumber)(target.nodeType) && editor.contains(target));
17882
+ if (insideEditor || !this.s.isInsideArea) {
17883
+ return;
17884
+ }
17885
+ this.e.fire('changeSelection');
17886
+ this.synchronizeValues();
17755
17887
  });
17756
17888
  }
17757
17889
  fetch(url, options) {
@@ -24221,9 +24353,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.uploader = {
24221
24353
  insertImageAsBase64URI: false,
24222
24354
  imagesExtensions: [
24223
24355
  'jpg',
24224
- 'png',
24225
24356
  'jpeg',
24226
- 'gif'
24357
+ 'png',
24358
+ 'gif',
24359
+ 'webp',
24360
+ 'bmp',
24361
+ 'svg',
24362
+ 'tiff',
24363
+ 'avif'
24227
24364
  ],
24228
24365
  headers: null,
24229
24366
  data: null,
@@ -28194,7 +28331,11 @@ function filterStyleProperties(style, allowed) {
28194
28331
  if (!jodit.o.cleanHTML.removeEmptyElements) {
28195
28332
  return false;
28196
28333
  }
28197
- 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));
28334
+ // Never drop an empty inline element that currently holds the caret it is
28335
+ // a pending-format marker the user is about to type into (#1291). `current`
28336
+ // is captured before a click moves the caret, so also check the live caret.
28337
+ const liveCaret = jodit.s.isCollapsed() ? jodit.s.range.startContainer : null;
28338
+ 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));
28198
28339
  }
28199
28340
 
28200
28341
 
@@ -28503,8 +28644,9 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
28503
28644
  const update = (key, value)=>{
28504
28645
  if (value && value !== (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(editor.editor, key).toString()) {
28505
28646
  button.state.icon.fill = value;
28506
- return;
28647
+ return true;
28507
28648
  }
28649
+ return false;
28508
28650
  };
28509
28651
  if (color) {
28510
28652
  const mode = (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.dataBind)(button, 'color');
@@ -28514,8 +28656,16 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
28514
28656
  const current = editor.s.current();
28515
28657
  if (current && !button.state.disabled) {
28516
28658
  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;
28517
- update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
28518
- update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
28659
+ // The icon's fill mirrors the current text/background color so the
28660
+ // button reflects the formatting under the caret. Both calls run so
28661
+ // that a background color (the second call) wins over the text color
28662
+ // when both are set. Keep the computed fill instead of resetting it
28663
+ // below. See #195, #182
28664
+ const hasColor = update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
28665
+ const hasBackground = update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
28666
+ if (hasColor || hasBackground) {
28667
+ return;
28668
+ }
28519
28669
  }
28520
28670
  button.state.icon.fill = '';
28521
28671
  button.state.activated = false;
@@ -29324,11 +29474,33 @@ var DragState = /*#__PURE__*/ function(DragState) {
29324
29474
  */ class dragAndDropElement extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
29325
29475
  /** @override */ afterInit() {
29326
29476
  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()) : [];
29477
+ // Allow another plugin (e.g. a drag handle/anchor) to start dragging
29478
+ // an element programmatically, regardless of the `draggableTags` list.
29479
+ this.j.e.on('startDragElement', this.onStartDragElement);
29327
29480
  if (!this.dragList.length) {
29328
29481
  return;
29329
29482
  }
29330
29483
  this.j.e.on('mousedown dragstart', this.onDragStart);
29331
29484
  }
29485
+ /**
29486
+ * Start dragging a specific element programmatically.
29487
+ *
29488
+ * Allows a separate UI element (for example a drag handle/anchor shown next
29489
+ * to a block) to initiate the drag without the user pressing directly on the
29490
+ * draggable element itself.
29491
+ *
29492
+ * @example
29493
+ * ```js
29494
+ * handle.addEventListener('mousedown', e => {
29495
+ * editor.e.fire('startDragElement', preBlock, e);
29496
+ * });
29497
+ * ```
29498
+ */ onStartDragElement(element, event) {
29499
+ if (this.isInDestruct || this.state > 0 || !element) {
29500
+ return;
29501
+ }
29502
+ this.startDragging(element, event);
29503
+ }
29332
29504
  /**
29333
29505
  * Drag start handler
29334
29506
  */ onDragStart(event) {
@@ -29350,11 +29522,18 @@ var DragState = /*#__PURE__*/ function(DragState) {
29350
29522
  if (jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isTag(lastTarget.parentElement, 'a') && lastTarget.parentElement.firstChild === lastTarget && lastTarget.parentElement.lastChild === lastTarget) {
29351
29523
  lastTarget = lastTarget.parentElement;
29352
29524
  }
29525
+ this.startDragging(lastTarget, event);
29526
+ }
29527
+ /**
29528
+ * Prepare the ghost element and switch to the waiting state.
29529
+ * Shared by the native mousedown handler and the programmatic
29530
+ * `startDragElement` event handler.
29531
+ */ startDragging(target, event) {
29353
29532
  this.startX = event.clientX;
29354
29533
  this.startY = event.clientY;
29355
29534
  this.isCopyMode = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.ctrlKey)(event); // we can move only element from editor
29356
- this.draggable = lastTarget.cloneNode(true);
29357
- (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.dataBind)(this.draggable, 'target', lastTarget);
29535
+ this.draggable = target.cloneNode(true);
29536
+ (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.dataBind)(this.draggable, 'target', target);
29358
29537
  this.state = 1;
29359
29538
  this.addDragListeners();
29360
29539
  }
@@ -29424,6 +29603,18 @@ var DragState = /*#__PURE__*/ function(DragState) {
29424
29603
  }
29425
29604
  const { parentElement } = fragment;
29426
29605
  this.j.s.insertNode(fragment, true, false);
29606
+ // Dropping a non-editable block (e.g. a `<pre>` code sample) can leave an
29607
+ // invisible filler text node beside it. Remove it so the drop does not
29608
+ // introduce a stray empty line (which clean-html would otherwise strip
29609
+ // later, causing a flash).
29610
+ [
29611
+ fragment.previousSibling,
29612
+ fragment.nextSibling
29613
+ ].forEach((node)=>{
29614
+ if (jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isEmptyTextNode(node)) {
29615
+ jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.safeRemove(node);
29616
+ }
29617
+ });
29427
29618
  if (parentElement && jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isEmpty(parentElement) && !jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isCell(parentElement)) {
29428
29619
  jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.safeRemove(parentElement);
29429
29620
  }
@@ -29450,7 +29641,7 @@ var DragState = /*#__PURE__*/ function(DragState) {
29450
29641
  }
29451
29642
  /** @override */ beforeDestruct() {
29452
29643
  this.onDragEnd();
29453
- this.j.e.off('mousedown dragstart', this.onDragStart);
29644
+ this.j.e.off('mousedown dragstart', this.onDragStart).off('startDragElement', this.onStartDragElement);
29454
29645
  this.removeDragListeners();
29455
29646
  }
29456
29647
  constructor(...args){
@@ -29459,6 +29650,9 @@ var DragState = /*#__PURE__*/ function(DragState) {
29459
29650
  */ (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);
29460
29651
  }
29461
29652
  }
29653
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
29654
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
29655
+ ], dragAndDropElement.prototype, "onStartDragElement", null);
29462
29656
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
29463
29657
  jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
29464
29658
  ], dragAndDropElement.prototype, "onDragStart", null);
@@ -29960,12 +30154,17 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_2__.pluginSystem.add('dtd', dtd);
29960
30154
  if (beforeEnter !== undefined) {
29961
30155
  return beforeEnter;
29962
30156
  }
29963
- if (!editor.s.isCollapsed()) {
29964
- editor.execCommand('Delete');
29965
- }
29966
- editor.s.focus();
29967
- this.onEnter(event);
29968
- editor.e.fire('afterEnter', event);
30157
+ // Delete-of-selection + new block must be a single history step,
30158
+ // otherwise pressing Enter over a selection needs two Ctrl+Z to undo
30159
+ // (the first only reverts to the intermediate empty state). #1292
30160
+ editor.history.snapshot.transaction(()=>{
30161
+ if (!editor.s.isCollapsed()) {
30162
+ editor.execCommand('Delete');
30163
+ }
30164
+ editor.s.focus();
30165
+ this.onEnter(event);
30166
+ editor.e.fire('afterEnter', event);
30167
+ });
29969
30168
  editor.synchronizeValues(); // fire change
29970
30169
  return false;
29971
30170
  }
@@ -31084,7 +31283,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.commandToHotkeys = {
31084
31283
  'cmd+shift+7'
31085
31284
  ],
31086
31285
  insertUnorderedList: [
31087
- 'ctrl+shift+8, cmd+shift+8'
31286
+ 'ctrl+shift+8',
31287
+ 'cmd+shift+8'
31088
31288
  ],
31089
31289
  selectall: [
31090
31290
  'ctrl+a',
@@ -33333,14 +33533,31 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.indent = {
33333
33533
  };
33334
33534
  jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.outdent = {
33335
33535
  isDisabled: (editor)=>{
33536
+ var _editor_o_tab;
33336
33537
  const current = editor.s.current();
33337
- if (current) {
33338
- const currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
33339
- if (currentBox) {
33340
- const arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
33341
- return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
33538
+ if (!current) {
33539
+ return true;
33540
+ }
33541
+ // A list item whose list is nested inside another list item can be
33542
+ // outdented (un-nested) by the `tab` plugin, even without an inline
33543
+ // indent margin. Keep the button enabled in that case. See #1247
33544
+ if ((_editor_o_tab = editor.o.tab) === null || _editor_o_tab === void 0 ? void 0 : _editor_o_tab.tabInsideLiInsertNewList) {
33545
+ const li = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, 'li', editor.editor);
33546
+ if (li) {
33547
+ const list = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(li, [
33548
+ 'ul',
33549
+ 'ol'
33550
+ ], editor.editor);
33551
+ if (list && jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(list, 'li', editor.editor)) {
33552
+ return false;
33553
+ }
33342
33554
  }
33343
33555
  }
33556
+ const currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
33557
+ if (currentBox) {
33558
+ const arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
33559
+ return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
33560
+ }
33344
33561
  return true;
33345
33562
  },
33346
33563
  tooltip: 'Decrease Indent'
@@ -36217,7 +36434,7 @@ class pasteFromWord extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugi
36217
36434
  }
36218
36435
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_ONLY_TEXT:
36219
36436
  {
36220
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.stripTags)((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.cleanFromWord)(html));
36437
+ 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);
36221
36438
  break;
36222
36439
  }
36223
36440
  }
@@ -36776,10 +36993,15 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.paste = {
36776
36993
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.cleanFromWord)(html);
36777
36994
  break;
36778
36995
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_ONLY_TEXT:
36779
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags));
36996
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
36780
36997
  break;
36781
36998
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.INSERT_AS_TEXT:
36782
36999
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.htmlspecialchars)(html);
37000
+ // Keep the source line breaks instead of letting the raw
37001
+ // newlines collapse into spaces when rendered. See #1093
37002
+ if (this.j.o.nl2brInPlainText) {
37003
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.nl2br)(html);
37004
+ }
36783
37005
  break;
36784
37006
  default:
36785
37007
  {
@@ -39523,13 +39745,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39523
39745
  /* unused harmony export select */
39524
39746
  /* harmony import */ var _swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25045);
39525
39747
  /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31635);
39526
- /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(84839);
39527
- /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(23211);
39528
- /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28077);
39529
- /* harmony import */ var jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(57821);
39530
- /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91206);
39531
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(4099);
39532
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(47670);
39748
+ /* harmony import */ var jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(81937);
39749
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(84839);
39750
+ /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(23211);
39751
+ /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28077);
39752
+ /* harmony import */ var jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(57821);
39753
+ /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(91206);
39754
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(4099);
39755
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(47670);
39533
39756
  /*!
39534
39757
  * Jodit Editor (https://xdsoft.net/jodit/)
39535
39758
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -39547,6 +39770,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39547
39770
 
39548
39771
 
39549
39772
 
39773
+
39550
39774
  /**
39551
39775
  * A utility plugin that allows you to subscribe to a click/mousedown/touchstart/mouseup on an element in DOM order
39552
39776
  *
@@ -39557,7 +39781,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39557
39781
  * console.log(img.src);
39558
39782
  * })
39559
39783
  * ```
39560
- */ class select extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
39784
+ */ class select extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__.Plugin {
39561
39785
  afterInit(jodit) {
39562
39786
  this.proxyEventsList.forEach((eventName)=>{
39563
39787
  jodit.e.on(eventName + '.select', this.onStartSelection);
@@ -39572,7 +39796,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39572
39796
  const { j } = this;
39573
39797
  let result, target = e.target;
39574
39798
  while(result === undefined && target && target !== j.editor){
39575
- result = j.e.fire((0,jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_5__.camelCase)(e.type + '_' + target.nodeName.toLowerCase()), target, e);
39799
+ result = j.e.fire((0,jodit_core_helpers_string_camel_case__WEBPACK_IMPORTED_MODULE_6__.camelCase)(e.type + '_' + target.nodeName.toLowerCase()), target, e);
39576
39800
  target = target.parentElement;
39577
39801
  }
39578
39802
  if (e.type === 'click' && result === undefined && target === j.editor) {
@@ -39583,10 +39807,10 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39583
39807
  * @event outsideClick(e) - when user clicked on the outside of editor
39584
39808
  */ onOutsideClick(e) {
39585
39809
  const node = e.target;
39586
- if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.up(node, (elm)=>elm === this.j.editor)) {
39810
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.up(node, (elm)=>elm === this.j.editor)) {
39587
39811
  return;
39588
39812
  }
39589
- const box = jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.UIElement.closestElement(node, jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.Popup);
39813
+ const box = jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__.UIElement.closestElement(node, jodit_core_ui__WEBPACK_IMPORTED_MODULE_8__.Popup);
39590
39814
  if (!box) {
39591
39815
  this.j.e.fire('outsideClick', e);
39592
39816
  }
@@ -39595,7 +39819,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39595
39819
  const { s } = this.j;
39596
39820
  if (!s.isCollapsed()) {
39597
39821
  const current = s.current();
39598
- if (current && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isOrContains(this.j.editor, current)) {
39822
+ if (current && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isOrContains(this.j.editor, current)) {
39599
39823
  this.onCopyNormalizeSelectionBound();
39600
39824
  }
39601
39825
  }
@@ -39614,14 +39838,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39614
39838
  */ onClickRightOfNestedListItem(e) {
39615
39839
  const { s } = this.j;
39616
39840
  const range = s.range;
39617
- if (!range.collapsed || range.startOffset !== 0 || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isText(range.startContainer)) {
39841
+ if (!range.collapsed || range.startOffset !== 0 || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(range.startContainer)) {
39618
39842
  return;
39619
39843
  }
39620
39844
  const text = range.startContainer;
39621
39845
  const li = text.parentNode;
39622
39846
  // The text must be the direct content of a list item that has a nested
39623
39847
  // list (the last level has no nested list and behaves correctly).
39624
- if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isTag(li, 'li') || !(li.querySelector('ul') || li.querySelector('ol'))) {
39848
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isTag(li, 'li') || !(li.querySelector('ul') || li.querySelector('ol'))) {
39625
39849
  return;
39626
39850
  }
39627
39851
  const measure = this.j.ed.createRange();
@@ -39632,6 +39856,36 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39632
39856
  s.setCursorAfter(text);
39633
39857
  }
39634
39858
  }
39859
+ /**
39860
+ * Keep pending inline formatting after a click. Toggling Bold/Italic/etc. on
39861
+ * a collapsed cursor leaves empty marker elements with the caret inside; a
39862
+ * click puts the caret right before them (outside), so they get cleaned up
39863
+ * and the formatting is lost. Move the caret back into the innermost marker
39864
+ * so the next typed character keeps every pending format (#1291).
39865
+ */ onClickKeepPendingFormat() {
39866
+ var _ref;
39867
+ var _text_nodeValue;
39868
+ const { s } = this.j;
39869
+ const range = s.range;
39870
+ if (!range.collapsed || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(range.startContainer)) {
39871
+ return;
39872
+ }
39873
+ const text = range.startContainer;
39874
+ // Caret must sit at the very end of the text, right before the markers.
39875
+ if (range.startOffset !== ((_ref = (_text_nodeValue = text.nodeValue) === null || _text_nodeValue === void 0 ? void 0 : _text_nodeValue.length) !== null && _ref !== void 0 ? _ref : 0)) {
39876
+ return;
39877
+ }
39878
+ const marker = text.nextSibling;
39879
+ 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)) {
39880
+ return;
39881
+ }
39882
+ let inner = marker;
39883
+ // Descend into the innermost empty formatting marker.
39884
+ 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)){
39885
+ inner = inner.firstElementChild;
39886
+ }
39887
+ s.setCursorIn(inner);
39888
+ }
39635
39889
  /**
39636
39890
  * Normalize selection after triple click
39637
39891
  */ onTripleClickNormalizeSelection(e) {
@@ -39640,8 +39894,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39640
39894
  }
39641
39895
  const { s } = this.j;
39642
39896
  const { startContainer, startOffset } = s.range;
39643
- if (startOffset === 0 && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isText(startContainer)) {
39644
- 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);
39897
+ if (startOffset === 0 && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isText(startContainer)) {
39898
+ 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);
39645
39899
  }
39646
39900
  }
39647
39901
  onCopyNormalizeSelectionBound(e) {
@@ -39649,7 +39903,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39649
39903
  if (!o.select.normalizeSelectionBeforeCutAndCopy || s.isCollapsed()) {
39650
39904
  return;
39651
39905
  }
39652
- 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))) {
39906
+ 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))) {
39653
39907
  return;
39654
39908
  }
39655
39909
  this.jodit.s.expandSelection();
@@ -39665,38 +39919,43 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.select = {
39665
39919
  }
39666
39920
  }
39667
39921
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39668
- jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
39922
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.autobind
39669
39923
  ], select.prototype, "onStartSelection", null);
39670
39924
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39671
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)('ow:click')
39925
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)('ow:click')
39672
39926
  ], select.prototype, "onOutsideClick", null);
39673
39927
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39674
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39928
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39675
39929
  ':beforeCommandCut'
39676
39930
  ])
39677
39931
  ], select.prototype, "beforeCommandCut", null);
39678
39932
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39679
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39933
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39680
39934
  ':beforeCommandSelectall'
39681
39935
  ])
39682
39936
  ], select.prototype, "beforeCommandSelectAll", null);
39683
39937
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39684
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39938
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39685
39939
  ':click'
39686
39940
  ])
39687
39941
  ], select.prototype, "onClickRightOfNestedListItem", null);
39688
39942
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39689
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39943
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39944
+ ':click'
39945
+ ])
39946
+ ], select.prototype, "onClickKeepPendingFormat", null);
39947
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39948
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39690
39949
  ':click'
39691
39950
  ])
39692
39951
  ], select.prototype, "onTripleClickNormalizeSelection", null);
39693
39952
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
39694
- (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)([
39953
+ (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.watch)([
39695
39954
  ':copy',
39696
39955
  ':cut'
39697
39956
  ])
39698
39957
  ], select.prototype, "onCopyNormalizeSelectionBound", null);
39699
- jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('select', select);
39958
+ jodit_core_global__WEBPACK_IMPORTED_MODULE_5__.pluginSystem.add('select', select);
39700
39959
 
39701
39960
 
39702
39961
  /***/ }),