Add CRM_Utils_JS::encode function
authorColeman Watts <coleman@civicrm.org>
Wed, 11 Sep 2019 21:51:47 +0000 (17:51 -0400)
committerColeman Watts <coleman@civicrm.org>
Wed, 11 Sep 2019 21:51:47 +0000 (17:51 -0400)
CRM/Utils/JS.php
tests/phpunit/CRM/Utils/JSTest.php

index 718afc457654066932b05e1db3ccfcefa52700bb..5f3764dc8ddd1d7c8a5c8954951a619fcf02c3e0 100644 (file)
@@ -159,6 +159,26 @@ class CRM_Utils_JS {
     return json_decode($js);
   }
 
+  /**
+   * Encodes a variable to js notation (not strict json).
+   *
+   * Like json_encode but the output is more suitable for an html attribute.
+   *
+   * @param $value
+   * @return string
+   */
+  public static function encode($value) {
+    if (is_array($value)) {
+      return self::writeObject($value, TRUE);
+    }
+    $result = json_encode($value, JSON_UNESCAPED_SLASHES);
+    // Prefer single quotes
+    if (is_string($value) && strpos($result, "'") === FALSE) {
+      return "'" . substr($result, 1, -1) . "'";
+    }
+    return $result;
+  }
+
   /**
    * Gets the properties of a javascript object/array WITHOUT decoding them.
    *
@@ -258,7 +278,7 @@ class CRM_Utils_JS {
     $brackets = isset($obj[0]) && array_keys($obj) === range(0, count($obj) - 1) ? ['[', ']'] : ['{', '}'];
     foreach ($obj as $key => $val) {
       if ($encodeValues) {
-        $val = json_encode($val, JSON_UNESCAPED_SLASHES);
+        $val = self::encode($val);
       }
       if ($brackets[0] == '{') {
         // Enclose the key in quotes unless it is purely alphanumeric
index 8517f568b914fbc7e7d809ccc9810f301210ab21..57c011b5846297d098f6981c0d65594696f49660 100644 (file)
@@ -237,6 +237,36 @@ class CRM_Utils_JSTest extends CiviUnitTestCase {
     $this->assertEquals($expectedOutput, CRM_Utils_JS::decode($input));
   }
 
+  public static function encodeExamples() {
+    return [
+      [
+        ['a' => 'Apple', 'b' => 'Banana', 'c' => [1, 2, 3]],
+        "{a: 'Apple', b: 'Banana', c: [1, 2, 3]}",
+      ],
+      [
+        ['a' => ['foo', 'bar'], 'b' => ["'a'" => ['foo/bar', 'bar(foo)'], 'b' => ['a' => ["fo'oo", 'bar'], 'b' => []]]],
+        "{a: ['foo', 'bar'], b: {\"'a'\": ['foo/bar', 'bar(foo)'], b: {a: [\"fo'oo\", 'bar'], b: {}}}}",
+      ],
+      [TRUE, 'true'],
+      [' ', "' '"],
+      [FALSE, 'false'],
+      [NULL, 'null'],
+      ['true', "'true'"],
+      ['0.5', "'0.5'"],
+      [0.5, '0.5'],
+      [[], "{}"],
+    ];
+  }
+
+  /**
+   * @param string $input
+   * @param string $expectedOutput
+   * @dataProvider encodeExamples
+   */
+  public function testEncode($input, $expectedOutput) {
+    $this->assertEquals($expectedOutput, CRM_Utils_JS::encode($input));
+  }
+
   /**
    * @return array
    */