jodit 4.12.18 → 4.12.21

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 (65) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +6 -6
  4. package/es2015/jodit.js +195 -44
  5. package/es2015/jodit.min.js +6 -6
  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 +6 -6
  13. package/es2018/jodit.min.js +6 -6
  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 +8 -8
  18. package/es2021/jodit.js +194 -44
  19. package/es2021/jodit.min.js +8 -8
  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 +8 -8
  28. package/es2021.en/jodit.js +194 -44
  29. package/es2021.en/jodit.min.js +8 -8
  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 +214 -50
  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/convert-media-url-to-video-embed.js +41 -19
  57. package/esm/jodit.js +20 -0
  58. package/esm/modules/uploader/config.js +11 -1
  59. package/esm/plugins/color/config.js +12 -3
  60. package/esm/plugins/hotkeys/config.js +1 -1
  61. package/esm/plugins/indent/config.js +20 -6
  62. package/esm/plugins/paste/paste.js +6 -1
  63. package/esm/plugins/paste-from-word/paste-from-word.js +1 -1
  64. package/package.json +1 -1
  65. package/types/core/helpers/html/strip-tags.d.ts +1 -1
package/es5/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.18
4
+ * Version: v4.12.21
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -2066,7 +2066,7 @@ __webpack_require__.r(__webpack_exports__);
2066
2066
  * @packageDocumentation
2067
2067
  * @module constants
2068
2068
  */
2069
- var APP_VERSION = "4.12.18";
2069
+ var APP_VERSION = "4.12.21";
2070
2070
  // prettier-ignore
2071
2071
  var ES = "es5";
2072
2072
  var IS_ES_MODERN = false;
@@ -6719,6 +6719,16 @@ function normalizeCSS(s) {
6719
6719
  iframeDoc.open();
6720
6720
  iframeDoc.write(html);
6721
6721
  iframeDoc.close();
6722
+ // Word marks its auto-generated list markers (the literal
6723
+ // bullet/number, e.g. `1.` or `·`) with `mso-list:Ignore`.
6724
+ // They are display-only and must not be imported, otherwise
6725
+ // the marker text leaks into the content. Drop them before any
6726
+ // style normalization strips the `mso-list` hint. See #948
6727
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.each(iframeDoc.body, function(node) {
6728
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isElement(node) && /mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
6729
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
6730
+ }
6731
+ });
6722
6732
  try {
6723
6733
  var _loop = function(i) {
6724
6734
  var _loop = function(idx) {
@@ -6818,6 +6828,15 @@ function normalizeCSS(s) {
6818
6828
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(node);
6819
6829
  break;
6820
6830
  default:
6831
+ // Word marks its auto-generated list markers
6832
+ // (the literal bullet/number, e.g. `1.` or `·`)
6833
+ // with `mso-list:Ignore`. They are display-only
6834
+ // and must not be imported, otherwise the marker
6835
+ // text leaks into the content. See #948
6836
+ if (/mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
6837
+ marks.push(node);
6838
+ break;
6839
+ }
6821
6840
  (0,jodit_core_helpers_array_to_array__WEBPACK_IMPORTED_MODULE_2__.toArray)(node.attributes).forEach(function(attr) {
6822
6841
  if ([
6823
6842
  'src',
@@ -6959,26 +6978,20 @@ function normalizeCSS(s) {
6959
6978
  return;
6960
6979
  }
6961
6980
  var removeEvents = (_options_removeEventAttributes = options.removeEventAttributes) !== null && _options_removeEventAttributes !== void 0 ? _options_removeEventAttributes : options.removeOnError;
6962
- if (removeEvents) {
6963
- removeAllEventAttributes(box);
6964
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('*', box).forEach(function(elm) {
6965
- return removeAllEventAttributes(elm);
6966
- });
6967
- } else if (options.removeOnError) {
6968
- sanitizeHTMLElement(box, options);
6969
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('[onerror]', box).forEach(function(elm) {
6970
- return sanitizeHTMLElement(elm, options);
6971
- });
6972
- }
6973
- if (options.safeJavaScriptLink) {
6974
- sanitizeHTMLElement(box, options);
6975
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('a[href^="javascript"]', box).forEach(function(elm) {
6976
- return sanitizeHTMLElement(elm, options);
6977
- });
6978
- }
6979
- if (options.safeLinksTarget) {
6980
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.$$)('a[target="_blank"]', box).forEach(function(elm) {
6981
- var rel = elm.getAttribute('rel') || '';
6981
+ // Single synchronous traversal of the subtree. Besides removing event
6982
+ // handlers and `javascript:` links, `sanitizeHTMLElement` neutralises
6983
+ // executable `iframe[srcdoc]`, `data:text/html` / SVG `data:` document
6984
+ // sources and dangerous schemes in every URL-bearing attribute.
6985
+ var process = function process(node) {
6986
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement(node)) {
6987
+ return;
6988
+ }
6989
+ if (removeEvents) {
6990
+ removeAllEventAttributes(node);
6991
+ }
6992
+ sanitizeHTMLElement(node, options);
6993
+ if (options.safeLinksTarget && node.nodeName === 'A' && node.getAttribute('target') === '_blank') {
6994
+ var rel = node.getAttribute('rel') || '';
6982
6995
  var parts = rel.split(/\s+/).filter(Boolean);
6983
6996
  if (!parts.includes('noopener')) {
6984
6997
  parts.push('noopener');
@@ -6986,9 +6999,11 @@ function normalizeCSS(s) {
6986
6999
  if (!parts.includes('noreferrer')) {
6987
7000
  parts.push('noreferrer');
6988
7001
  }
6989
- (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'rel', parts.join(' '));
6990
- });
6991
- }
7002
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(node, 'rel', parts.join(' '));
7003
+ }
7004
+ };
7005
+ process(box);
7006
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.each(box, process);
6992
7007
  }
6993
7008
  /**
6994
7009
  * Remove all on* event handler attributes from an element
@@ -7026,6 +7041,41 @@ function normalizeCSS(s) {
7026
7041
  }
7027
7042
  return effected;
7028
7043
  }
7044
+ /**
7045
+ * URL-bearing attributes (besides `href`) that can load or execute content.
7046
+ */ var URL_ATTRIBUTES = [
7047
+ 'src',
7048
+ 'data',
7049
+ 'action',
7050
+ 'formaction',
7051
+ 'poster',
7052
+ 'background',
7053
+ 'xlink:href'
7054
+ ];
7055
+ /**
7056
+ * Tags that load their URL as a *document* (scripts inside run). An SVG data
7057
+ * URL is only an XSS vector here — as an `<img>` source it renders inertly.
7058
+ */ var DOCUMENT_EMBED_TAGS = new Set([
7059
+ 'iframe',
7060
+ 'frame',
7061
+ 'object',
7062
+ 'embed'
7063
+ ]);
7064
+ /**
7065
+ * Detects executable / script-bearing URL schemes. The attribute value is
7066
+ * already HTML-entity-decoded by `getAttribute`, so only whitespace and
7067
+ * control characters (which browsers ignore inside a scheme) need stripping.
7068
+ */ function isDangerousUrl(value, tagName) {
7069
+ // eslint-disable-next-line no-control-regex
7070
+ var normalized = value.replace(/[\u0000-\u0020]+/g, '').toLowerCase();
7071
+ if (/^(?:javascript|vbscript|livescript|mocha):/.test(normalized)) {
7072
+ return true;
7073
+ }
7074
+ if (/^data:(?:text\/html|application\/xhtml)/.test(normalized)) {
7075
+ return true;
7076
+ }
7077
+ return /^data:image\/svg/.test(normalized) && DOCUMENT_EMBED_TAGS.has(tagName);
7078
+ }
7029
7079
  function sanitizeHTMLElement(elm) {
7030
7080
  var _ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {
7031
7081
  safeJavaScriptLink: true,
@@ -7044,6 +7094,39 @@ function sanitizeHTMLElement(elm) {
7044
7094
  (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'href', location.protocol + '//' + href);
7045
7095
  effected = true;
7046
7096
  }
7097
+ if (safeJavaScriptLink) {
7098
+ // `srcdoc` runs its content as a full HTML document — drop it entirely.
7099
+ if (elm.hasAttribute('srcdoc')) {
7100
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, 'srcdoc', null);
7101
+ effected = true;
7102
+ }
7103
+ // Strip executable schemes from any other URL-bearing attribute.
7104
+ var tagName = elm.nodeName.toLowerCase();
7105
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7106
+ try {
7107
+ for(var _iterator = URL_ATTRIBUTES[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
7108
+ var name = _step.value;
7109
+ var value = elm.getAttribute(name);
7110
+ if (value && isDangerousUrl(value, tagName)) {
7111
+ (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_1__.attr)(elm, name, null);
7112
+ effected = true;
7113
+ }
7114
+ }
7115
+ } catch (err) {
7116
+ _didIteratorError = true;
7117
+ _iteratorError = err;
7118
+ } finally{
7119
+ try {
7120
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
7121
+ _iterator.return();
7122
+ }
7123
+ } finally{
7124
+ if (_didIteratorError) {
7125
+ throw _iteratorError;
7126
+ }
7127
+ }
7128
+ }
7129
+ }
7047
7130
  return effected;
7048
7131
  }
7049
7132
 
@@ -7095,7 +7178,7 @@ var ALONE_TAGS = new Set([
7095
7178
  /**
7096
7179
  * Extract plain text from HTML text
7097
7180
  */ function stripTags(html) {
7098
- var doc = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : document, exclude = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
7181
+ var doc = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : document, exclude = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null, blockBr = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : false;
7099
7182
  var tmp = doc.createElement('div');
7100
7183
  if ((0,jodit_core_helpers_checker_is_string__WEBPACK_IMPORTED_MODULE_1__.isString)(html)) {
7101
7184
  tmp.innerHTML = html;
@@ -7109,7 +7192,7 @@ var ALONE_TAGS = new Set([
7109
7192
  }
7110
7193
  if (exclude && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, exclude)) {
7111
7194
  var tag = p.nodeName.toLowerCase();
7112
- var text = !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, ALONE_TAGS) ? "%%%jodit-".concat(tag, "%%%").concat(stripTags(p.innerHTML, doc, exclude), "%%%/jodit-").concat(tag, "%%%") : "%%%jodit-single-".concat(tag, "%%%");
7195
+ var text = !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(p, ALONE_TAGS) ? "%%%jodit-".concat(tag, "%%%").concat(stripTags(p.innerHTML, doc, exclude, blockBr), "%%%/jodit-").concat(tag, "%%%") : "%%%jodit-single-".concat(tag, "%%%");
7113
7196
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.before(p, doc.createTextNode(text));
7114
7197
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.safeRemove(p);
7115
7198
  return;
@@ -7126,7 +7209,11 @@ var ALONE_TAGS = new Set([
7126
7209
  return;
7127
7210
  }
7128
7211
  if (nx) {
7129
- pr.insertBefore(doc.createTextNode(' '), nx);
7212
+ // By default blocks are joined with a single space (single-line
7213
+ // plain text). When `blockBr` is set, separate them with a line
7214
+ // break instead, so paragraph structure survives — e.g. the
7215
+ // "Insert only Text" paste option. See #1232
7216
+ pr.insertBefore(doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '), nx);
7130
7217
  }
7131
7218
  });
7132
7219
  return restoreTags((0,jodit_core_helpers_string_trim__WEBPACK_IMPORTED_MODULE_2__.trim)(tmp.innerText));
@@ -8829,7 +8916,6 @@ function ConfigDeepFlatten(obj) {
8829
8916
  return url;
8830
8917
  }
8831
8918
  var parser = jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.globalDocument.createElement('a');
8832
- var pattern1 = /(?:http?s?:\/\/)?(?:www\.)?(?:vimeo\.com)\/?(.+)/g;
8833
8919
  parser.href = url;
8834
8920
  if (!width) {
8835
8921
  width = 400;
@@ -8841,19 +8927,43 @@ function ConfigDeepFlatten(obj) {
8841
8927
  switch(parser.hostname){
8842
8928
  case 'www.vimeo.com':
8843
8929
  case 'vimeo.com':
8844
- return pattern1.test(url) ? url.replace(pattern1, '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//player.vimeo.com/video/$1" frameborder="0" allowfullscreen></iframe>') : url;
8930
+ {
8931
+ // The numeric video id can be preceded by `channels/<name>/` or
8932
+ // `groups/<name>/videos/` and followed by tracking params (e.g.
8933
+ // `?share=copy`). Unlisted videos keep a hash right after the id
8934
+ // (`vimeo.com/<id>/<hash>`). Extract the id (+ hash) from the path
8935
+ // so all of those forms produce a valid embed. See #1209
8936
+ var segments = parser.pathname.split('/').filter(Boolean);
8937
+ var idIndex = segments.findIndex(function(s) {
8938
+ return /^\d+$/.test(s);
8939
+ });
8940
+ if (idIndex === -1) {
8941
+ return url;
8942
+ }
8943
+ var path = segments[idIndex];
8944
+ var hash = segments[idIndex + 1];
8945
+ if (hash && idIndex === 0) {
8946
+ path += '/' + hash;
8947
+ }
8948
+ return '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//player.vimeo.com/video/' + path + '" frameborder="0" allowfullscreen></iframe>';
8949
+ }
8845
8950
  case 'youtube.com':
8846
8951
  case 'www.youtube.com':
8952
+ case 'm.youtube.com':
8953
+ case 'music.youtube.com':
8847
8954
  case 'youtu.be':
8848
8955
  case 'www.youtu.be':
8849
8956
  {
8850
- var query = parser.search ? (0,_parse_query__WEBPACK_IMPORTED_MODULE_2__.parseQuery)(parser.search) : {
8851
- v: parser.pathname.substring(1)
8852
- };
8853
- if (/^embed\/.*/.test(query.v)) {
8854
- query.v = query.v.substring(6);
8855
- }
8856
- return query.v ? '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//www.youtube.com/embed/' + query.v + '" frameborder="0" allowfullscreen></iframe>' : url;
8957
+ var query = parser.search ? (0,_parse_query__WEBPACK_IMPORTED_MODULE_2__.parseQuery)(parser.search) : {};
8958
+ // `youtube.com/watch` keeps the video id in the `v` query
8959
+ // parameter, while the short `youtu.be/<id>` links and the
8960
+ // `/embed/`, `/shorts/`, `/live/` paths keep it in the pathname.
8961
+ // Modern share urls add tracking params (e.g. `?si=`, `?t=`), so
8962
+ // the pathname must still be used as a fallback when there is no
8963
+ // `v`. See #1209
8964
+ var v = query.v || parser.pathname.substring(1);
8965
+ v = v.replace(/^(watch|embed|shorts|live|v)\//, '').replace(/\/$/, '');
8966
+ return v ? '<iframe width="' + width + '" height="' + height + '" src="' + protocol + '//www.youtube.com/embed/' + v + '" frameborder="0" allowfullscreen></iframe>' : url;
8857
8967
  }
8858
8968
  }
8859
8969
  return url;
@@ -21511,6 +21621,23 @@ var Jodit = /*#__PURE__*/ function(ViewWithToolbar) {
21511
21621
  }
21512
21622
  _this.synchronizeValues();
21513
21623
  }
21624
+ }).on(this.ow, 'mouseup', function(event) {
21625
+ if (_this.o.readonly || _this.__isSilentChange) {
21626
+ return;
21627
+ }
21628
+ // When a selection is started inside the editor and the
21629
+ // mouse button is released outside of it, the editable
21630
+ // area never receives the `mouseup` event, so the toolbar
21631
+ // state (active buttons) is not recalculated. Re-fire the
21632
+ // event manually for that case while the selection still
21633
+ // belongs to the editor. See #1251
21634
+ var target = event.target;
21635
+ var insideEditor = Boolean(target && (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_15__.isNumber)(target.nodeType) && editor.contains(target));
21636
+ if (insideEditor || !_this.s.isInsideArea) {
21637
+ return;
21638
+ }
21639
+ _this.e.fire('changeSelection');
21640
+ _this.synchronizeValues();
21514
21641
  });
21515
21642
  }
21516
21643
  },
@@ -29281,9 +29408,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.uploader = {
29281
29408
  insertImageAsBase64URI: false,
29282
29409
  imagesExtensions: [
29283
29410
  'jpg',
29284
- 'png',
29285
29411
  'jpeg',
29286
- 'gif'
29412
+ 'png',
29413
+ 'gif',
29414
+ 'webp',
29415
+ 'bmp',
29416
+ 'svg',
29417
+ 'tiff',
29418
+ 'avif'
29287
29419
  ],
29288
29420
  headers: null,
29289
29421
  data: null,
@@ -33992,8 +34124,9 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
33992
34124
  var update = function update(key, value) {
33993
34125
  if (value && value !== (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(editor.editor, key).toString()) {
33994
34126
  button.state.icon.fill = value;
33995
- return;
34127
+ return true;
33996
34128
  }
34129
+ return false;
33997
34130
  };
33998
34131
  if (color) {
33999
34132
  var mode = (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.dataBind)(button, 'color');
@@ -34003,8 +34136,16 @@ jodit_config__WEBPACK_IMPORTED_MODULE_3__.Config.prototype.controls.brush = {
34003
34136
  var current = editor.s.current();
34004
34137
  if (current && !button.state.disabled) {
34005
34138
  var 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;
34006
- update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
34007
- update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
34139
+ // The icon's fill mirrors the current text/background color so the
34140
+ // button reflects the formatting under the caret. Both calls run so
34141
+ // that a background color (the second call) wins over the text color
34142
+ // when both are set. Keep the computed fill instead of resetting it
34143
+ // below. See #195, #182
34144
+ var hasColor = update('color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'color').toString());
34145
+ var hasBackground = update('background-color', (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.css)(currentBpx, 'background-color').toString());
34146
+ if (hasColor || hasBackground) {
34147
+ return;
34148
+ }
34008
34149
  }
34009
34150
  button.state.icon.fill = '';
34010
34151
  button.state.activated = false;
@@ -36869,7 +37010,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.commandToHotkeys = {
36869
37010
  'cmd+shift+7'
36870
37011
  ],
36871
37012
  insertUnorderedList: [
36872
- 'ctrl+shift+8, cmd+shift+8'
37013
+ 'ctrl+shift+8',
37014
+ 'cmd+shift+8'
36873
37015
  ],
36874
37016
  selectall: [
36875
37017
  'ctrl+a',
@@ -39570,14 +39712,31 @@ jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.indent = {
39570
39712
  };
39571
39713
  jodit_config__WEBPACK_IMPORTED_MODULE_2__.Config.prototype.controls.outdent = {
39572
39714
  isDisabled: function isDisabled(editor) {
39715
+ var _editor_o_tab;
39573
39716
  var current = editor.s.current();
39574
- if (current) {
39575
- var currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
39576
- if (currentBox) {
39577
- var arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
39578
- return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
39717
+ if (!current) {
39718
+ return true;
39719
+ }
39720
+ // A list item whose list is nested inside another list item can be
39721
+ // outdented (un-nested) by the `tab` plugin, even without an inline
39722
+ // indent margin. Keep the button enabled in that case. See #1247
39723
+ if ((_editor_o_tab = editor.o.tab) === null || _editor_o_tab === void 0 ? void 0 : _editor_o_tab.tabInsideLiInsertNewList) {
39724
+ var li = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, 'li', editor.editor);
39725
+ if (li) {
39726
+ var list = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(li, [
39727
+ 'ul',
39728
+ 'ol'
39729
+ ], editor.editor);
39730
+ if (list && jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(list, 'li', editor.editor)) {
39731
+ return false;
39732
+ }
39579
39733
  }
39580
39734
  }
39735
+ var currentBox = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(current, jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock, editor.editor);
39736
+ if (currentBox) {
39737
+ var arrow = (0,_helpers__WEBPACK_IMPORTED_MODULE_5__.getKey)(editor.o.direction, currentBox);
39738
+ return !currentBox.style[arrow] || parseInt(currentBox.style[arrow], 10) <= 0;
39739
+ }
39581
39740
  return true;
39582
39741
  },
39583
39742
  tooltip: 'Decrease Indent'
@@ -42775,7 +42934,7 @@ var pasteFromWord = /*#__PURE__*/ function(Plugin) {
42775
42934
  }
42776
42935
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_7__.INSERT_ONLY_TEXT:
42777
42936
  {
42778
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_10__.stripTags)((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_10__.cleanFromWord)(html));
42937
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_10__.stripTags)((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_10__.cleanFromWord)(html), this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
42779
42938
  break;
42780
42939
  }
42781
42940
  }
@@ -43512,10 +43671,15 @@ jodit_config__WEBPACK_IMPORTED_MODULE_4__.Config.prototype.controls.paste = {
43512
43671
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_11__.cleanFromWord)(html);
43513
43672
  break;
43514
43673
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_7__.INSERT_ONLY_TEXT:
43515
- html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_11__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags));
43674
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_11__.stripTags)(html, this.j.ed, new Set(this.j.o.pasteExcludeStripTags), this.j.o.nl2brInPlainText);
43516
43675
  break;
43517
43676
  case jodit_core_constants__WEBPACK_IMPORTED_MODULE_7__.INSERT_AS_TEXT:
43518
43677
  html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_11__.htmlspecialchars)(html);
43678
+ // Keep the source line breaks instead of letting the raw
43679
+ // newlines collapse into spaces when rendered. See #1093
43680
+ if (this.j.o.nl2brInPlainText) {
43681
+ html = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_11__.nl2br)(html);
43682
+ }
43519
43683
  break;
43520
43684
  default:
43521
43685
  {
package/es5/jodit.min.css CHANGED
@@ -1,14 +1,14 @@
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.18
4
+ * Version: v4.12.21
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
8
8
  /*!
9
9
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
10
10
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
11
- * Version: v4.12.18
11
+ * Version: v4.12.21
12
12
  * Url: https://xdsoft.net/jodit/
13
13
  * License(s): MIT
14
14
  */