From 3a9e5a624237332d69b063f2bc7c816e7ebf9394 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 3 Dec 2019 13:04:13 -0500 Subject: [PATCH] Fix handling of non-breaking spaces See https://stackoverflow.com/questions/59215211/why-does-domdocument-mess-up-unicode-nonbreaking-spaces --- ext/afform/core/CRM/Afform/ArrayHtml.php | 42 +++++++++++++++++-- .../Civi/Api4/Utils/AfformFormatTrait.php | 2 +- .../phpunit/api/v4/formatExamples/apple.php | 8 ++-- .../phpunit/api/v4/formatExamples/banana.php | 10 ++--- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/ext/afform/core/CRM/Afform/ArrayHtml.php b/ext/afform/core/CRM/Afform/ArrayHtml.php index 59c8cae0a5..1c0e9f30ee 100644 --- a/ext/afform/core/CRM/Afform/ArrayHtml.php +++ b/ext/afform/core/CRM/Afform/ArrayHtml.php @@ -150,6 +150,12 @@ class CRM_Afform_ArrayHtml { return $buf . $end; } + /** + * Converts a subset of items into html markup + * + * @param array $children + * @return string html + */ public function convertArraysToHtml($children) { $buf = ''; $this->indent++; @@ -167,6 +173,17 @@ class CRM_Afform_ArrayHtml { return $buf; } + /** + * Converts a full array of items into html markup + * + * @param array $tree + * @return string html + */ + public function convertTreeToHtml($tree) { + $this->indent = -1; + return $this->replaceUnicodeChars($this->convertArraysToHtml($tree)); + } + /** * @param string $html * Ex: '
Hello world
' @@ -180,7 +197,7 @@ class CRM_Afform_ArrayHtml { $doc = new DOMDocument(); $doc->preserveWhiteSpace = !$this->formatWhitespace; - @$doc->loadHTML("$html"); + @$doc->loadHTML("$html"); // FIXME: Validate expected number of child nodes @@ -210,7 +227,7 @@ class CRM_Afform_ArrayHtml { if (!$this->deepCoding && !$this->isNodeEditable($arr)) { $arr['#markup'] = ''; foreach ($node->childNodes as $child) { - $arr['#markup'] .= $child->ownerDocument->saveXML($child); + $arr['#markup'] .= $this->replaceUnicodeChars($child->ownerDocument->saveXML($child)); } } else { @@ -220,7 +237,7 @@ class CRM_Afform_ArrayHtml { return $arr; } elseif ($node instanceof DOMText) { - return ['#text' => $node->textContent]; + return ['#text' => $this->replaceUnicodeChars($node->textContent)]; } elseif ($node instanceof DOMComment) { return ['#comment' => $node->nodeValue]; @@ -336,6 +353,25 @@ class CRM_Afform_ArrayHtml { } } + /** + * Convert non-breaking space character to html notation. + * + * Makes html files easier to read. + * + * Note: This function does NOT convert all html entities (< to <, etc.) + * as the input string is assumed to already be valid markup. + * + * @param string $markup - some html + * @return string + */ + public function replaceUnicodeChars($markup) { + // TODO: Potentially replace other unicode characters that can be represented as html entities + $replace = [ + ["\xc2\xa0", ' '], + ]; + return str_replace(array_column($replace, 0), array_column($replace, 1), $markup); + } + /** * Determine if a node is recognized by the gui editor. * diff --git a/ext/afform/core/Civi/Api4/Utils/AfformFormatTrait.php b/ext/afform/core/Civi/Api4/Utils/AfformFormatTrait.php index 4383a11066..ea4af10d36 100644 --- a/ext/afform/core/Civi/Api4/Utils/AfformFormatTrait.php +++ b/ext/afform/core/Civi/Api4/Utils/AfformFormatTrait.php @@ -58,7 +58,7 @@ trait AfformFormatTrait { return $mixed; } $converter = new \CRM_Afform_ArrayHtml($this->layoutFormat !== 'shallow', $this->formatWhitespace); - return $converter->convertArraysToHtml($mixed); + return $converter->convertTreeToHtml($mixed); } } diff --git a/ext/afform/mock/tests/phpunit/api/v4/formatExamples/apple.php b/ext/afform/mock/tests/phpunit/api/v4/formatExamples/apple.php index 18a4bb0eab..b082ae0a5a 100644 --- a/ext/afform/mock/tests/phpunit/api/v4/formatExamples/apple.php +++ b/ext/afform/mock/tests/phpunit/api/v4/formatExamples/apple.php @@ -1,12 +1,12 @@ 'New text!', - 'pretty' => "New text!\n", + 'html' => 'New   text!', + 'pretty' => "New   text!\n", 'shallow' => [ - ['#tag' => 'strong', '#markup' => 'New text!'], + ['#tag' => 'strong', '#markup' => 'New   text!'], ], 'deep' => [ - ['#tag' => 'strong', '#children' => [['#text' => 'New text!']]], + ['#tag' => 'strong', '#children' => [['#text' => 'New   text!']]], ], ]; diff --git a/ext/afform/mock/tests/phpunit/api/v4/formatExamples/banana.php b/ext/afform/mock/tests/phpunit/api/v4/formatExamples/banana.php index da70ac501c..122d455b00 100644 --- a/ext/afform/mock/tests/phpunit/api/v4/formatExamples/banana.php +++ b/ext/afform/mock/tests/phpunit/api/v4/formatExamples/banana.php @@ -1,10 +1,10 @@ '
New text! No whitespace!
', + 'html' => '
New text!   Get a trim!
', 'pretty' => '
New text! - No whitespace! +   Get a trim!
', @@ -14,7 +14,7 @@ return [ 'class' => 'af-block', '#children' => [ ['#tag' => 'strong', '#markup' => ' New text!'], - ['#tag' => 'strong', 'class' => 'af-text', '#children' => [['#text' => 'No whitespace!']]], + ['#tag' => 'strong', 'class' => 'af-text', '#children' => [['#text' => "  Get a trim!"]]], ['#tag' => 'af-field', 'name' => 'do_not_sms', 'defn' => "{label: 'Do not do any of the emailing'}"], ], ], @@ -25,7 +25,7 @@ return [ 'class' => 'af-block', '#children' => [ ['#tag' => 'strong', '#markup' => ' New text!'], - ['#tag' => 'strong', 'class' => 'af-text', '#children' => [['#text' => ' No whitespace! ']]], + ['#tag' => 'strong', 'class' => 'af-text', '#children' => [['#text' => "   Get a trim! "]]], ['#tag' => 'af-field', 'name' => 'do_not_sms', 'defn' => "{label: 'Do not do any of the emailing'}"], ], ], @@ -36,7 +36,7 @@ return [ 'class' => 'af-block', '#children' => [ ['#tag' => 'strong', '#children' => [['#text' => ' New text!']]], - ['#tag' => 'strong', 'class' => 'af-text', '#children' => [['#text' => ' No whitespace! ']]], + ['#tag' => 'strong', 'class' => 'af-text', '#children' => [['#text' => "   Get a trim! "]]], ['#tag' => 'af-field', 'name' => 'do_not_sms', 'defn' => ['label' => 'Do not do any of the emailing']], ], ], -- 2.25.1