suneditor 2.43.7 → 2.43.10

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suneditor",
3
- "version": "2.43.7",
3
+ "version": "2.43.10",
4
4
  "description": "Pure JavaScript based WYSIWYG web editor",
5
5
  "author": "JiHong.Lee",
6
6
  "license": "MIT",
@@ -460,6 +460,7 @@ export default {
460
460
  options.toolbarWidth = options.toolbarWidth ? (util.isNumber(options.toolbarWidth) ? options.toolbarWidth + 'px' : options.toolbarWidth) : 'auto';
461
461
  options.toolbarContainer = typeof options.toolbarContainer === 'string' ? document.querySelector(options.toolbarContainer) : options.toolbarContainer;
462
462
  options.stickyToolbar = (/balloon/i.test(options.mode) || !!options.toolbarContainer) ? -1 : options.stickyToolbar === undefined ? 0 : (/^\d+/.test(options.stickyToolbar) ? util.getNumber(options.stickyToolbar, 0) : -1);
463
+ options.hideToolbar = !!options.hideToolbar;
463
464
  options.fullScreenOffset = options.fullScreenOffset === undefined ? 0 : (/^\d+/.test(options.fullScreenOffset) ? util.getNumber(options.fullScreenOffset, 0) : 0);
464
465
  options.fullPage = !!options.fullPage;
465
466
  options.iframe = options.fullPage || !!options.iframe;
@@ -928,6 +929,8 @@ export default {
928
929
  tool_cover.className = 'se-toolbar-cover';
929
930
  tool_bar.appendChild(tool_cover);
930
931
 
932
+ if (options.hideToolbar) tool_bar.style.display = 'none';
933
+
931
934
  return {
932
935
  'element': tool_bar,
933
936
  'plugins': plugins,
package/src/lib/core.js CHANGED
@@ -283,6 +283,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
283
283
  * @private
284
284
  */
285
285
  _attributesWhitelistRegExp: null,
286
+ _attributesWhitelistRegExp_all_data: null,
286
287
 
287
288
  /**
288
289
  * @description Attributes blacklist used by the cleanHTML method
@@ -469,6 +470,14 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
469
470
  */
470
471
  _styleCommandMap: null,
471
472
 
473
+ /**
474
+ * @private
475
+ */
476
+ _cleanStyleRegExp: {
477
+ span: new _w.RegExp('\s*(font-family|font-size|color|background-color)\s*:[^;]+(?!;)*', 'ig'),
478
+ format: new _w.RegExp('\s*(text-align|margin-left|margin-right)\s*:[^;]+(?!;)*', 'ig')
479
+ },
480
+
472
481
  /**
473
482
  * @description Variables used internally in editor operation
474
483
  * @property {Boolean} isCodeView State of code view
@@ -5093,6 +5102,46 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5093
5102
  .replace(this.editorTagsBlacklistRegExp, '');
5094
5103
  },
5095
5104
 
5105
+ _cleanStyle: function (m, v, tagName) {
5106
+ const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
5107
+ if (sv) {
5108
+ if (!v) v = [];
5109
+ const style = sv[0].replace(/"/g, '').match(this._cleanStyleRegExp[tagName]);
5110
+ if (style) {
5111
+ const allowedStyle = [];
5112
+ for (let i = 0, len = style.length, r; i < len; i++) {
5113
+ r = style[i].match(/(.+)(:)([^:]+$)/);
5114
+ if (r && !/inherit|initial/i.test(r[3])) {
5115
+ const k = util.kebabToCamelCase(r[1].trim());
5116
+ const v = this.wwComputedStyle[k].replace(/"/g, '');
5117
+ const c = r[3].trim();
5118
+ switch (k) {
5119
+ case 'fontFamily':
5120
+ if (!options.plugins.font || options.font.indexOf(c) === -1) continue;
5121
+ break;
5122
+ case 'fontSize':
5123
+ if (!options.plugins.fontSize) continue;
5124
+ break;
5125
+ case 'color':
5126
+ if (!options.plugins.fontColor) continue;
5127
+ break;
5128
+ case 'backgroundColor':
5129
+ if (!options.plugins.hiliteColor) continue;
5130
+ break;
5131
+ }
5132
+
5133
+ if (v !== c) {
5134
+ allowedStyle.push(r[0]);
5135
+ }
5136
+ }
5137
+ }
5138
+ if (allowedStyle.length > 0) v.push('style="' + allowedStyle.join(';') + '"');
5139
+ }
5140
+ }
5141
+
5142
+ return v;
5143
+ },
5144
+
5096
5145
  /**
5097
5146
  * @description Tag and tag attribute check RegExp function. (used by "cleanHTML" and "convertContentsForEditor")
5098
5147
  * @param {Boolean} lowLevelCheck Row level check
@@ -5109,64 +5158,38 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5109
5158
 
5110
5159
  // blacklist
5111
5160
  const bAttr = this._attributesTagsBlacklist[tagName];
5161
+ m = m.replace(/\s(?:on[a-z]+)\s*=\s*(")[^"]*\1/ig, '');
5112
5162
  if (bAttr) m = m.replace(bAttr, '');
5113
5163
  else m = m.replace(this._attributesBlacklistRegExp, '');
5114
5164
 
5115
5165
  // whitelist
5116
5166
  const wAttr = this._attributesTagsWhitelist[tagName];
5117
5167
  if (wAttr) v = m.match(wAttr);
5118
- else v = m.match(this._attributesWhitelistRegExp);
5119
-
5120
- // anchor
5121
- if (!lowLevelCheck || /<a\b/i.test(t)) {
5122
- const sv = m.match(/(?:(?:id|name)\s*=\s*(?:"|')[^"']*(?:"|'))/g);
5123
- if (sv) {
5124
- if (!v) v = [];
5125
- v.push(sv[0]);
5126
- }
5127
- }
5168
+ else v = m.match(lowLevelCheck ? this._attributesWhitelistRegExp : this._attributesWhitelistRegExp_all_data);
5128
5169
 
5129
- // span
5130
- if ((!lowLevelCheck || /<span/i.test(t)) && (!v || !/style=/i.test(v.toString()))) {
5131
- const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
5132
- if (sv) {
5133
- if (!v) v = [];
5134
- const style = sv[0].replace(/&quot;/g, '').match(/\s*(font-family|font-size|color|background-color)\s*:[^;]+(?!;)*/ig);
5135
- if (style) {
5136
- const allowedStyle = [];
5137
- for (let i = 0, len = style.length, r; i < len; i++) {
5138
- r = style[i].match(/(.+)(:)([^:]+$)/);
5139
- if (r && !/inherit|initial/i.test(r[3])) {
5140
- const k = util.kebabToCamelCase(r[1].trim());
5141
- const v = this.wwComputedStyle[k].replace(/"/g, '');
5142
- const c = r[3].trim();
5143
- switch (k) {
5144
- case 'fontFamily':
5145
- if (options.plugins.font ? options.font.indexOf(c) === -1 : true) continue;
5146
- break;
5147
- case 'fontSize':
5148
- if (!options.plugins.fontSize) continue;
5149
- break;
5150
- case 'color':
5151
- if (!options.plugins.fontColor) continue;
5152
- break;
5153
- case 'backgroundColor':
5154
- if (!options.plugins.hiliteColor) continue;
5155
- break;
5156
- }
5157
-
5158
- if (v !== c) {
5159
- allowedStyle.push(r[0]);
5160
- }
5161
- }
5162
- }
5163
- if (allowedStyle.length > 0) v.push('style="' + allowedStyle.join(';') + '"');
5170
+ // attribute
5171
+ if (lowLevelCheck) {
5172
+ if (tagName === 'a') {
5173
+ const sv = m.match(/(?:(?:id|name)\s*=\s*(?:"|')[^"']*(?:"|'))/g);
5174
+ if (sv) {
5175
+ if (!v) v = [];
5176
+ v.push(sv[0]);
5177
+ }
5178
+ } else if (!v || !/style=/i.test(v.toString())) {
5179
+ if (tagName === 'span') {
5180
+ v = this._cleanStyle(m, v, 'span');
5181
+ } else if (/^(P|DIV|H[1-6]|PRE)$/i.test(tagName)) {
5182
+ v = this._cleanStyle(m, v, 'format');
5164
5183
  }
5165
5184
  }
5185
+ } else {
5186
+ const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
5187
+ if (sv && !v) v = [sv[0]];
5188
+ else if (sv && !v.some(function (v) { return /^style/.test(v.trim()); })) v.push(sv[0]);
5166
5189
  }
5167
5190
 
5168
5191
  // img
5169
- if (/<img/i.test(t)) {
5192
+ if (tagName === 'img') {
5170
5193
  let w = '', h = '';
5171
5194
  const sv = m.match(/style\s*=\s*(?:"|')[^"']*(?:"|')/);
5172
5195
  if (!v) v = [];
@@ -5240,7 +5263,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5240
5263
  } else if (util.isFormatElement(node)) {
5241
5264
  html += '<li>' +(node.innerHTML.trim() || '<br>') + '</li>';
5242
5265
  } else if (util.isRangeFormatElement(node) && !util.isTable(node)) {
5243
- html += event._convertListCell(node);
5266
+ html += this._convertListCell(node);
5244
5267
  } else {
5245
5268
  html += '<li>' + node.outerHTML + '</li>';
5246
5269
  }
@@ -5276,7 +5299,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5276
5299
  * @returns {String}
5277
5300
  */
5278
5301
  cleanHTML: function (html, whitelist, blacklist) {
5279
- html = this._deleteDisallowedTags(this._parser.parseFromString(html, 'text/html').body.innerHTML).replace(/(<[a-zA-Z0-9\-]+)[^>]*(?=>)/g, this._cleanTags.bind(this, true));
5302
+ html = this._deleteDisallowedTags(this._parser.parseFromString(html, 'text/html').body.innerHTML).replace(/(<[a-zA-Z0-9\-]+)[^>]*(?=>)/g, this._cleanTags.bind(this, true)).replace(/^.+\x3C!--StartFragment--\>|\x3C!--EndFragment-->.+$/g, '');
5280
5303
 
5281
5304
  const dom = _d.createRange().createContextualFragment(html);
5282
5305
  try {
@@ -5356,7 +5379,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5356
5379
  for (let i = 0, t; i < domTree.length; i++) {
5357
5380
  t = domTree[i];
5358
5381
 
5359
- if (!util.isFormatElement(t) && !util.isRangeFormatElement(t) && !util.isComponent(t) && !util.isMedia(t)) {
5382
+ if (!util.isFormatElement(t) && !util.isRangeFormatElement(t) && !util.isComponent(t) && !util.isMedia(t) && t.nodeType !== 8) {
5360
5383
  if (!p) p = util.createElement(options.defaultTag);
5361
5384
  p.appendChild(t);
5362
5385
  i--;
@@ -5695,7 +5718,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5695
5718
  // set whitelist
5696
5719
  const getRegList = function (str, str2) { return !str ? '^' : (str === '*' ? '[a-z-]+' : (!str2 ? str : (str + '|' + str2))); };
5697
5720
  // tags
5698
- const defaultAttr = 'contenteditable|colspan|rowspan|target|href|download|rel|src|alt|class|type|controls|data-format|data-size|data-file-size|data-file-name|data-origin|data-align|data-image-link|data-rotate|data-proportion|data-percentage|origin-size|data-exp|data-font-size';
5721
+ const defaultAttr = 'contenteditable|colspan|rowspan|target|href|download|rel|src|alt|class|type|controls|origin-size';
5722
+ const dataAttr = 'data-format|data-size|data-file-size|data-file-name|data-origin|data-align|data-image-link|data-rotate|data-proportion|data-percentage|data-exp|data-font-size';
5699
5723
  this._allowHTMLComments = options._editorTagsWhitelist.indexOf('//') > -1 || options._editorTagsWhitelist === '*';
5700
5724
  // html check
5701
5725
  this._htmlCheckWhitelistRegExp = new wRegExp('^(' + getRegList(options._editorTagsWhitelist.replace('|//', ''), '') + ')$', 'i');
@@ -5722,7 +5746,8 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
5722
5746
  }
5723
5747
  }
5724
5748
 
5725
- this._attributesWhitelistRegExp = new wRegExp('\\s(?:' + (allAttr || defaultAttr) + ')' + regEndStr, 'ig');
5749
+ this._attributesWhitelistRegExp = new wRegExp('\\s(?:' + (allAttr || defaultAttr + '|' + dataAttr) + ')' + regEndStr, 'ig');
5750
+ this._attributesWhitelistRegExp_all_data = new wRegExp('\\s(?:' + ((allAttr || defaultAttr) + '|data-[a-z0-9\\-]+') + ')' + regEndStr, 'ig');
5726
5751
  this._attributesTagsWhitelist = tagsAttr;
5727
5752
 
5728
5753
  // blacklist
@@ -6308,7 +6333,6 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
6308
6333
 
6309
6334
  onMouseDown_wysiwyg: function (e) {
6310
6335
  if (core.isReadOnly || util.isNonEditable(context.element.wysiwyg)) return;
6311
- core._editorRange();
6312
6336
 
6313
6337
  // user event
6314
6338
  if (typeof functions.onMouseDown === 'function' && functions.onMouseDown(e, core) === false) return;
@@ -7334,8 +7358,7 @@ export default function (context, pluginCallButtons, plugins, lang, options, _re
7334
7358
  }
7335
7359
  }
7336
7360
 
7337
- const textKey = !ctrl && !alt && !selectRange && !event._nonTextKeyCode.test(keyCode);
7338
- if (textKey && range.collapsed && range.startContainer === range.endContainer && util.isBreak(range.commonAncestorContainer)) {
7361
+ if (util.isIE && !ctrl && !alt && !selectRange && !event._nonTextKeyCode.test(keyCode) && util.isBreak(range.commonAncestorContainer)) {
7339
7362
  const zeroWidth = util.createTextNode(util.zeroWidthSpace);
7340
7363
  core.insertNode(zeroWidth, null, false);
7341
7364
  core.setRange(zeroWidth, 1, zeroWidth, 1);