From 6bbb80bafac2c1b17a987449cdd28563c99fcb35 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Tue, 12 Jun 2018 17:47:06 -0700 Subject: [PATCH] Proof-of-concept - Array<=>Html mapper --- ext/afform/CRM/Afform/ArrayHtml.php | 109 ++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 ext/afform/CRM/Afform/ArrayHtml.php diff --git a/ext/afform/CRM/Afform/ArrayHtml.php b/ext/afform/CRM/Afform/ArrayHtml.php new file mode 100644 index 0000000000..c6dd28e8c5 --- /dev/null +++ b/ext/afform/CRM/Afform/ArrayHtml.php @@ -0,0 +1,109 @@ +html mapping. + */ +class CRM_Afform_ArrayHtml { + + const DEFAULT_TAG = 'div'; + + /** + * @param array $array + * Ex: ['#tag' => 'div', 'class' => 'greeting', '#children' => ['Hello world']] + * @return string + * Ex: '
Hello world
' + */ + public function convertArrayToHtml($array) { + $tag = empty($array['#tag']) ? self::DEFAULT_TAG : $array['#tag']; + unset($array['#tag']); + $children = empty($array['#children']) ? self::DEFAULT_TAG : $array['#children']; + unset($array['#children']); + + $buf = '<' . $tag; + foreach ($array as $attrName => $attrValue) { + if ($attrName{0} === '#') { + continue; + } + if (!preg_match('/^[a-zA-Z0-9\-]+$/', $attrName)) { + throw new \RuntimeException("Malformed HTML attribute"); + } + if (is_string($attrValue)) { + $buf .= sprintf(' %s="%s"', $attrName, htmlentities($attrValue)); // FIXME attribute encoding + } + elseif (is_array($attrValue) && $this->allowStructuredAttribute($tag, $attrName)) { + $buf .= sprintf(' %s="%s"', $attrName, htmlentities(json_encode($attrValue))); // FIXME attribute encoding + } + } + $buf .= '>'; + + foreach ($children as $child) { + if (is_string($child)) { + $buf .= htmlentities($child); + } + elseif (is_array($child)) { + $buf .= $this->convertArrayToHtml($child); + } + } + + $buf .= ''; + return $buf; + } + + /** + * @param string $html + * Ex: '
Hello world
' + * @return array + * Ex: ['#tag' => 'div', 'class' => 'greeting', '#children' => ['Hello world']] + */ + public function convertHtmlToArray($html) { + $doc = new DOMDocument(); + $doc->loadHTML("$html"); + + // FIXME: Valid expected number of child nodes + + foreach ($doc->childNodes as $htmlNode) { + if ($htmlNode instanceof DOMElement && $htmlNode->tagName === 'html') { + return $this->convertNodeToArray($htmlNode->firstChild->firstChild); + } + } + + return NULL; + } + + /** + * @param \DOMNode $node + * @return array|string + */ + public function convertNodeToArray($node) { + if ($node instanceof DOMElement) { + $arr = ['#tag' => $node->tagName]; + foreach ($node->attributes as $attribute) { + $txt = $attribute->textContent; + if ($txt{0} === '{' && $txt{1} !== '{' && $this->allowStructuredAttribute($node->tagName, $attribute->name)) { + $arr[$attribute->name] = sprintf('PARSE-ME(%s)', $txt); + } + else { + $arr[$attribute->name] = $txt; + } + } + foreach ($node->childNodes as $childNode) { + $arr['#children'][] = $this->convertNodeToArray($childNode); + } + return $arr; + } + elseif ($node instanceof DOMText) { + return $node->textContent; + } + else { + throw new \RuntimeException("Unrecognized DOM node"); + } + } + + public function allowStructuredAttribute($tag, $attr) { + // FIXME: use whitelist of allowed angular directives + return FALSE; + } + +} -- 2.25.1