|
|
|
@ -1,7 +1,17 @@ |
|
|
|
import { each, isString, isFunction, isUndefined } from 'underscore'; |
|
|
|
import { CssRuleProperties } from '../../css_composer/model/CssRule'; |
|
|
|
import BrowserParserHtml from './BrowserParserHtml'; |
|
|
|
|
|
|
|
export default config => { |
|
|
|
type AnyObject = Record<string, any>; |
|
|
|
|
|
|
|
type StringObject = Record<string, string>; |
|
|
|
|
|
|
|
type HTMLParseResult = { |
|
|
|
html: null | Record<string, any> | Record<string, any>[]; // TODO replace with components
|
|
|
|
css: null | CssRuleProperties[]; |
|
|
|
}; |
|
|
|
|
|
|
|
export default (config: AnyObject = {}) => { |
|
|
|
let c = config; |
|
|
|
const modelAttrStart = 'data-gjs-'; |
|
|
|
const event = 'parse:html'; |
|
|
|
@ -16,9 +26,9 @@ export default config => { |
|
|
|
* @param {Object} attr |
|
|
|
* @returns {Object} An object containing props and attributes without them |
|
|
|
*/ |
|
|
|
splitPropsFromAttr(attr = {}) { |
|
|
|
const props = {}; |
|
|
|
const attrs = {}; |
|
|
|
splitPropsFromAttr(attr: AnyObject = {}) { |
|
|
|
const props: StringObject = {}; |
|
|
|
const attrs: StringObject = {}; |
|
|
|
|
|
|
|
each(attr, (value, key) => { |
|
|
|
if (key.indexOf(this.modelAttrStart) === 0) { |
|
|
|
@ -61,15 +71,17 @@ export default config => { |
|
|
|
* console.log(stl); |
|
|
|
* // {color: 'black', width: '100px', test: 'value'}
|
|
|
|
*/ |
|
|
|
parseStyle(str) { |
|
|
|
var result = {}; |
|
|
|
var decls = str.split(';'); |
|
|
|
for (var i = 0, len = decls.length; i < len; i++) { |
|
|
|
var decl = decls[i].trim(); |
|
|
|
parseStyle(str: string) { |
|
|
|
const result: StringObject = {}; |
|
|
|
const decls = str.split(';'); |
|
|
|
|
|
|
|
for (let i = 0, len = decls.length; i < len; i++) { |
|
|
|
const decl = decls[i].trim(); |
|
|
|
if (!decl) continue; |
|
|
|
var prop = decl.split(':'); |
|
|
|
const prop = decl.split(':'); |
|
|
|
result[prop[0].trim()] = prop.slice(1).join(':').trim(); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
}, |
|
|
|
|
|
|
|
@ -82,14 +94,16 @@ export default config => { |
|
|
|
* console.log(res); |
|
|
|
* // ['test1', 'test2', 'test3']
|
|
|
|
*/ |
|
|
|
parseClass(str) { |
|
|
|
parseClass(str: string) { |
|
|
|
const result = []; |
|
|
|
const cls = str.split(' '); |
|
|
|
|
|
|
|
for (let i = 0, len = cls.length; i < len; i++) { |
|
|
|
const cl = cls[i].trim(); |
|
|
|
if (!cl) continue; |
|
|
|
result.push(cl); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
}, |
|
|
|
|
|
|
|
@ -98,22 +112,22 @@ export default config => { |
|
|
|
* @param {HTMLElement} el DOM element to traverse |
|
|
|
* @return {Array<Object>} |
|
|
|
*/ |
|
|
|
parseNode(el, opts = {}) { |
|
|
|
parseNode(el: HTMLElement, opts: AnyObject = {}) { |
|
|
|
const result = []; |
|
|
|
const nodes = el.childNodes; |
|
|
|
|
|
|
|
for (var i = 0, len = nodes.length; i < len; i++) { |
|
|
|
const node = nodes[i]; |
|
|
|
const node = nodes[i] as HTMLElement; |
|
|
|
const attrs = node.attributes || []; |
|
|
|
const attrsLen = attrs.length; |
|
|
|
const nodePrev = result[result.length - 1]; |
|
|
|
const nodeChild = node.childNodes.length; |
|
|
|
const ct = this.compTypes; |
|
|
|
let model = {}; |
|
|
|
let model: Record<string, any> = {}; // TODO use component properties
|
|
|
|
|
|
|
|
// Start with understanding what kind of component it is
|
|
|
|
if (ct) { |
|
|
|
let obj = ''; |
|
|
|
let obj: any = ''; |
|
|
|
let type = node.getAttribute && node.getAttribute(`${modelAttrStart}type`); |
|
|
|
|
|
|
|
// If the type is already defined, use it
|
|
|
|
@ -124,10 +138,12 @@ export default config => { |
|
|
|
// the first with a valid result will be that component
|
|
|
|
for (let it = 0; it < ct.length; it++) { |
|
|
|
const compType = ct[it]; |
|
|
|
// @ts-ignore
|
|
|
|
obj = compType.model.isComponent(node, opts); |
|
|
|
|
|
|
|
if (obj) { |
|
|
|
if (typeof obj !== 'object') { |
|
|
|
// @ts-ignore
|
|
|
|
obj = { type: compType.id }; |
|
|
|
} |
|
|
|
break; |
|
|
|
@ -152,7 +168,7 @@ export default config => { |
|
|
|
// Parse attributes
|
|
|
|
for (let j = 0; j < attrsLen; j++) { |
|
|
|
const nodeName = attrs[j].nodeName; |
|
|
|
let nodeValue = attrs[j].nodeValue; |
|
|
|
let nodeValue: string | boolean = attrs[j].nodeValue!; |
|
|
|
|
|
|
|
// Isolate attributes
|
|
|
|
if (nodeName == 'style') { |
|
|
|
@ -175,13 +191,13 @@ export default config => { |
|
|
|
try { |
|
|
|
nodeValue = |
|
|
|
(firstChar == '{' && lastChar == '}') || (firstChar == '[' && lastChar == ']') |
|
|
|
? JSON.parse(nodeValue) |
|
|
|
? JSON.parse(nodeValue as string) |
|
|
|
: nodeValue; |
|
|
|
} catch (e) {} |
|
|
|
|
|
|
|
model[modelAttr] = nodeValue; |
|
|
|
} else { |
|
|
|
// Check for attributes from props (eg. required, disabled)
|
|
|
|
// @ts-ignore Check for attributes from props (eg. required, disabled)
|
|
|
|
if (nodeValue === '' && node[nodeName] === true) { |
|
|
|
nodeValue = true; |
|
|
|
} |
|
|
|
@ -221,7 +237,7 @@ export default config => { |
|
|
|
// Throw away empty nodes (keep spaces)
|
|
|
|
if (!config.keepEmptyTextNodes) { |
|
|
|
const content = node.nodeValue; |
|
|
|
if (content != ' ' && !content.trim()) { |
|
|
|
if (content != ' ' && !content!.trim()) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -275,11 +291,11 @@ export default config => { |
|
|
|
* @param {ParserCss} parserCss In case there is style tags inside HTML |
|
|
|
* @return {Object} |
|
|
|
*/ |
|
|
|
parse(str, parserCss, opts = {}) { |
|
|
|
parse(str: string, parserCss: any, opts = {}) { |
|
|
|
const { em } = c; |
|
|
|
const conf = (em && em.get('Config')) || {}; |
|
|
|
const res = { html: null, css: null }; |
|
|
|
const cf = { ...config, ...opts }; |
|
|
|
const res: HTMLParseResult = { html: null, css: null }; |
|
|
|
const cf: AnyObject = { ...config, ...opts }; |
|
|
|
const options = { |
|
|
|
...config.optionsHtml, |
|
|
|
// Support previous `configParser.htmlType` option
|
|
|
|
@ -327,16 +343,16 @@ export default config => { |
|
|
|
return res; |
|
|
|
}, |
|
|
|
|
|
|
|
__clearUnsafeAttr(node) { |
|
|
|
__clearUnsafeAttr(node: HTMLElement) { |
|
|
|
const attrs = node.attributes || []; |
|
|
|
const nodes = node.childNodes || []; |
|
|
|
const toRemove = []; |
|
|
|
const toRemove: string[] = []; |
|
|
|
each(attrs, attr => { |
|
|
|
const name = attr.nodeName || ''; |
|
|
|
name.indexOf('on') === 0 && toRemove.push(name); |
|
|
|
}); |
|
|
|
toRemove.map(name => node.removeAttribute(name)); |
|
|
|
each(nodes, node => this.__clearUnsafeAttr(node)); |
|
|
|
each(nodes, node => this.__clearUnsafeAttr(node as HTMLElement)); |
|
|
|
}, |
|
|
|
}; |
|
|
|
}; |