Browse Source

Add new `parser.optionsHtml` config

pull/4105/head
Artur Arseniev 4 years ago
parent
commit
249511a47a
  1. 3
      src/editor/config/config.js
  2. 17
      src/parser/config/config.js
  3. 64
      src/parser/model/ParserHtml.js

3
src/editor/config/config.js

@ -83,7 +83,8 @@ export default {
showToolbar: 1,
// Allow script tag importing
allowScripts: 0,
// @deprecated in favor of `config.parser.optionsHtml.allowScripts`
// allowScripts: 0,
// If true render a select of available devices
showDevices: 1,

17
src/parser/config/config.js

@ -14,8 +14,17 @@ export default {
// Here the result will be XMLDocument, which extends Node
parserHtml: null,
// DOMParser mime type (default 'text/html')
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString
// If you use the `text/html` parser, it will fix the invalid syntax automatically
htmlType: null
// Default HTML parser options (used in `parserModule.parseHtml('<div...', options)`)
optionsHtml: {
// DOMParser mime type (default 'text/html')
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString
// If you use the `text/html` parser, it will fix the invalid syntax automatically
htmlType: null,
// Allow <script> tags
allowScripts: false,
// Allow unsafe HTML attributes (eg. `on*` inline event handlers)
allowUnsafeAttr: false,
},
};

64
src/parser/model/ParserHtml.js

@ -1,4 +1,4 @@
import { each, isString, isFunction } from 'underscore';
import { each, isString, isFunction, isUndefined, forEach } from 'underscore';
import BrowserParserHtml from './BrowserParserHtml';
export default config => {
@ -35,8 +35,7 @@ export default config => {
// so put it under try/catch and let fail silently
try {
value =
(firstChar == '{' && lastChar == '}') ||
(firstChar == '[' && lastChar == ']')
(firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']')
? JSON.parse(value)
: value;
} catch (e) {}
@ -49,7 +48,7 @@ export default config => {
return {
props,
attrs
attrs,
};
},
@ -69,10 +68,7 @@ export default config => {
var decl = decls[i].trim();
if (!decl) continue;
var prop = decl.split(':');
result[prop[0].trim()] = prop
.slice(1)
.join(':')
.trim();
result[prop[0].trim()] = prop.slice(1).join(':').trim();
}
return result;
},
@ -118,8 +114,7 @@ export default config => {
// Start with understanding what kind of component it is
if (ct) {
let obj = '';
let type =
node.getAttribute && node.getAttribute(`${modelAttrStart}type`);
let type = node.getAttribute && node.getAttribute(`${modelAttrStart}type`);
// If the type is already defined, use it
if (type) {
@ -177,8 +172,7 @@ export default config => {
// so put it under try/catch and let fail silently
try {
nodeValue =
(firstChar == '{' && lastChar == '}') ||
(firstChar == '[' && lastChar == ']')
(firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']')
? JSON.parse(nodeValue)
: nodeValue;
} catch (e) {}
@ -205,12 +199,12 @@ export default config => {
!model.type && (model.type = 'text');
model.components = {
type: 'textnode',
content: firstChild.nodeValue
content: firstChild.nodeValue,
};
} else {
model.components = this.parseNode(node, {
...opts,
inSvg: opts.inSvg || model.type === 'svg'
inSvg: opts.inSvg || model.type === 'svg',
});
}
}
@ -247,10 +241,7 @@ export default config => {
const comp = comps[ci];
const cType = comp.type;
if (
['text', 'textnode'].indexOf(cType) < 0 &&
c.textTags.indexOf(comp.tagName) < 0
) {
if (['text', 'textnode'].indexOf(cType) < 0 && c.textTags.indexOf(comp.tagName) < 0) {
allTxt = 0;
break;
}
@ -287,17 +278,29 @@ export default config => {
const conf = (em && em.get('Config')) || {};
const res = { html: null, css: null };
const cf = { ...config, ...opts };
const el = isFunction(cf.parserHtml)
? cf.parserHtml(str, cf)
: BrowserParserHtml(str, cf);
const options = {
...config.optionsHtml,
// Support previous `configParser.htmlType` option
htmlType: config.optionsHtml.htmlType || config.htmlType,
...opts,
};
const el = isFunction(cf.parserHtml) ? cf.parserHtml(str, options) : BrowserParserHtml(str, options);
const scripts = el.querySelectorAll('script');
let i = scripts.length;
// Remove all scripts
if (!conf.allowScripts) {
// Support previous `configMain.allowScripts` option
const allowScripts = !isUndefined(conf.allowScripts) ? conf.allowScripts : options.allowScripts;
// Remove script tags
if (!allowScripts) {
while (i--) scripts[i].parentNode.removeChild(scripts[i]);
}
// Remove unsafe attributes
if (!options.allowUnsafeAttr) {
this.__clearUnsafeAttr(el);
}
// Detach style tags and parse them
if (parserCss) {
const styles = el.querySelectorAll('style');
@ -315,12 +318,21 @@ export default config => {
em && em.trigger(`${event}:root`, { input: str, root: el });
const result = this.parseNode(el);
// I have to keep it otherwise it breaks the DomComponents.addComponent (returns always array)
const resHtml =
result.length === 1 && !c.returnArray ? result[0] : result;
const resHtml = result.length === 1 && !c.returnArray ? result[0] : result;
res.html = resHtml;
em && em.trigger(event, { input: str, output: res });
return res;
}
},
__clearUnsafeAttr(node) {
const attrs = node.attributes || [];
const nodes = node.childNodes || [];
forEach(attrs, attr => {
const name = attr.nodeName || '';
name.indexOf('on') === 0 && node.removeAttribute(name);
});
forEach(nodes, node => this.__clearUnsafeAttr(node));
},
};
};

Loading…
Cancel
Save