관리-도구
편집 파일: html-to-react.js
import { createElement } from '@wordpress/element'; import { camelCaseAttrMap } from "./camel-case-attribute-names"; // eslint-disable-next-line max-len // https://github.com/facebook/react/blob/15.0-stable/src/renderers/dom/shared/ReactDOMComponent.js#L457 const voidElementTags = [ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr', 'menuitem', 'textarea' ]; // Render block on editor export function pagelayerParseHtmlToReact(html, props){ var reactEle = ''; var data = []; const createElementArray = (node) => { node = jQuery(node)[0]; if(node.nodeType === 3) { return node.data; }else if(node.nodeType === 8) { // FIXME: The following doesn't work as the generated HTML results in // "<!-- This is a comment -->" // return '<!-- ' + node.data + ' -->'; return ''; } var localName = node.localName; // If we start typing like "<s" is changed to "<s< ="" div></s<>", so we replace "<" from tag name localName = localName.replace(/[^\w-]/g, ''); if(voidElementTags.indexOf(localName) > -1){ return pagelayer_createElement(node, props); } var data = ''; var children = []; if(jQuery(node).children().length > 0){ var cn = node.childNodes, i = 0; while(cn.length > i) { children.push(createElementArray(cn[i])); i += 1; } }else{ data = node.innerText; } return pagelayer_createElement(node, props, data, children); } jQuery(html).each(function(){ data.push( createElementArray(this) ); }); return data; } export function pagelayer_createElement(node, props, data, children){ let elementProps = {}; let isRichText = false; let isGroupHolder = false; var localName = node.localName; // If we start typing like "<s" is changed to "<s< ="" div></s<>", so we replace "<" from tag name localName = localName.replace(/[^\w-]/g, ''); children = children || []; if(node.attributes){ elementProps = Object.entries(node.attributes).reduce((result, [key, value]) => { var name = value.nodeName; var val = value.nodeValue; name = camelCaseAttrMap[name.replace(/[-:]/, '')] || name; if (name === 'style') { val = createStyleJsonFromString(val); } else if (name === 'class') { name = 'className'; } else if (name === 'for') { name = 'htmlFor'; } else if (name.startsWith('on')) { val = Function(val); } else if(name === 'pagelayer-editable'){ isRichText = val; } else if(name === 'pagelayer-group-holder'){ isGroupHolder = val; } if (booleanAttrs.includes(name) && (val || '') === '') { val = name; } result[name] = val; return result; }, elementProps); } // TODO: also pass el.atts if(isRichText){ var eleProps = { tagName: localName, _props: props, propsName: isRichText, value: node.innerHTML } elementProps = {...elementProps, ...eleProps}; return createElement(wp.PagelayerComponents['rich_text'], elementProps); } if(isGroupHolder){ var eleProps = { TagName: localName, plTag: isGroupHolder, _props: props, }; elementProps = {...elementProps, ...eleProps}; var RenderGroupBlock = wp.PagelayerBlocks['addGroupBlock']; return createElement(RenderGroupBlock, elementProps); } const allChildren = data != null ? [data,].concat(children) : children; return createElement.apply( null, [localName, elementProps].concat(allChildren) ); } // Boolean HTML attributes, copied from https://meiert.com/en/blog/boolean-attributes-of-html/, // on the form React expects. const booleanAttrs = [ 'allowFullScreen', 'allowpaymentrequest', 'async', 'autoFocus', 'autoPlay', 'checked', 'controls', 'default', 'disabled', 'formNoValidate', 'hidden', 'ismap', 'itemScope', 'loop', 'multiple', 'muted', 'nomodule', 'noValidate', 'open', 'playsinline', 'readOnly', 'required', 'reversed', 'selected', 'truespeed', ]; export function createStyleJsonFromString(styleString){ styleString = styleString || ''; const styles = styleString.split(/;(?!base64)/); var jsonStyles = {}; for(let i = 0; i < styles.length; ++i){ let singleStyle, key, value; singleStyle = styles[i].split(':'); if (singleStyle.length > 2) { singleStyle[1] = singleStyle.slice(1).join(':'); } key = singleStyle[0]; value = singleStyle[1]; if (typeof value === 'string'){ value = value.trim(); } if (key != null && value != null && key.length > 0 && value.length > 0) { // There are two ways to declare css keys in react first is lower case string and second is camel case // key = key.toLowerCase(); // This is first way // We use camel case way to create css // Don't camelCase CSS custom properties if(key.indexOf('--') !== 0) { key = key .trim() .split('-') .map((word, index) => { if (index === 0) { return word; } return word.charAt(0).toUpperCase() + word.slice(1); }) .join(''); } jsonStyles[key] = value; } } return jsonStyles; }