Resources - Define helper methods `addModule()`, `addModuleFile()`, `addModuleUrl()`
authorTim Otten <totten@civicrm.org>
Fri, 5 May 2023 07:42:37 +0000 (00:42 -0700)
committerTim Otten <totten@civicrm.org>
Wed, 10 May 2023 21:22:49 +0000 (14:22 -0700)
CRM/Core/Resources/CollectionAdderInterface.php
CRM/Core/Resources/CollectionAdderTrait.php
tests/phpunit/CRM/Core/Resources/CollectionTestTrait.php

index e3b4f2cc92122859aed75472d35772c287aaee57..606af6798edb07741fd9155db4a9c53e736af773 100644 (file)
@@ -44,6 +44,52 @@ interface CRM_Core_Resources_CollectionAdderInterface {
    */
   public function addMarkup(string $markup, ...$options);
 
+  /**
+   * Add an ECMAScript module to the current page (<SCRIPT TYPE=MODULE>).
+   *
+   * Ex: addScript('alert("Hello world");', ['weight' => 123]);
+   *
+   * @param string $code
+   *   JavaScript source code.
+   * @param array $options
+   *   Open-ended list of key-value options. See CollectionInterface docs.
+   *   Positional equivalence: addScript(string $code, int $weight, string $region).
+   * @return static
+   * @see CRM_Core_Resources_CollectionInterface
+   */
+  public function addModule(string $code, ...$options);
+
+  /**
+   * Add an ECMAScript Module from file to the current page (<SCRIPT TYPE=MODULE SRC=...>).
+   *
+   * Ex: addScriptFile('myextension', 'myscript.js', ['weight' => 123]);
+   *
+   * @param string $ext
+   *   Extension name; use 'civicrm' for core.
+   * @param string $file
+   *   File path -- relative to the extension base dir.
+   * @param array $options
+   *   Open-ended list of key-value options. See CollectionInterface docs.
+   *   Positional equivalence: addScriptFile(string $code, int $weight, string $region, mixed $translate).
+   * @return static
+   * @see CRM_Core_Resources_CollectionInterface
+   */
+  public function addModuleFile(string $ext, string $file, ...$options);
+
+  /**
+   * Add an ECMAScript Module by URL to the current page (<SCRIPT TYPE=MODULE SRC=...>).
+   *
+   * Ex: addScriptUrl('http://example.com/foo.js', ['weight' => 123])
+   *
+   * @param string $url
+   * @param array $options
+   *   Open-ended list of key-value options. See CollectionInterface docs.
+   *   Positional equivalence: addScriptUrl(string $url, int $weight, string $region).
+   * @return static
+   * @see CRM_Core_Resources_CollectionInterface
+   */
+  public function addModuleUrl(string $url, ...$options);
+
   /**
    * Export permission data to the client to enable smarter GUIs.
    *
index da81a34a03d9935211646b66e49ace2441929fc6..2ab04b01d00f3cc09f2f01bb2b0e549a46eab60a 100644 (file)
@@ -61,6 +61,79 @@ trait CRM_Core_Resources_CollectionAdderTrait {
     return $this;
   }
 
+  /**
+   * Add an ECMAScript module to the current page (<SCRIPT TYPE=MODULE>).
+   *
+   * Ex: addModule('alert("Hello world");', ['weight' => 123]);
+   *
+   * @param string $code
+   *   JavaScript source code.
+   * @param array $options
+   *   Open-ended list of key-value options. See CollectionInterface docs.
+   *   Positional equivalence: addModule(string $code, int $weight, string $region).
+   * @return static
+   * @see CRM_Core_Resources_CollectionInterface
+   * @see CRM_Core_Resources_CollectionAdderInterface::addModule()
+   */
+  public function addModule(string $code, ...$options) {
+    $this->add(self::mergeStandardOptions($options, [
+      'esm' => TRUE,
+      'script' => $code,
+    ]));
+    return $this;
+  }
+
+  /**
+   * Add an ECMAScript Module from file to the current page (<SCRIPT TYPE=MODULE SRC=...>).
+   *
+   * Ex: addModuleFile('myextension', 'myscript.js', ['weight' => 123]);
+   *
+   * @param string $ext
+   *   Extension name; use 'civicrm' for core.
+   * @param string $file
+   *   File path -- relative to the extension base dir.
+   * @param array $options
+   *   Open-ended list of key-value options. See CollectionInterface docs.
+   *   Positional equivalence: addModuleFile(string $code, int $weight, string $region, mixed $translate).
+   * @return static
+   * @see CRM_Core_Resources_CollectionInterface
+   * @see CRM_Core_Resources_CollectionAdderInterface::addModuleFile()
+   */
+  public function addModuleFile(string $ext, string $file, ...$options) {
+    $this->add(self::mergeStandardOptions($options, [
+      'esm' => TRUE,
+      'scriptFile' => [$ext, $file],
+      'name' => "$ext:$file",
+      // Setting the name above may appear superfluous, but it preserves a historical quirk
+      // where Region::add() and Resources::addScriptFile() produce slightly different orderings.
+    ]));
+    return $this;
+  }
+
+  /**
+   * Add an ECMAScript Module by URL to the current page (<SCRIPT TYPE=MODULE SRC=...>).
+   *
+   * Ex: addModuleUrl('http://example.com/foo.js', ['weight' => 123])
+   *
+   * @param string $url
+   * @param array $options
+   *   Open-ended list of key-value options. See CollectionInterface docs.
+   *   Positional equivalence: addModuleUrl(string $url, int $weight, string $region).
+   * @return static
+   * @see CRM_Core_Resources_CollectionInterface
+   * @see CRM_Core_Resources_CollectionAdderInterface::addModuleUrl()
+   */
+  public function addModuleUrl(string $url, ...$options) {
+    $this->add(self::mergeStandardOptions($options, [
+      'esm' => TRUE,
+      'scriptUrl' => $url,
+      'name' => $url,
+      // Setting the name above may appear superfluous, but it preserves a historical quirk
+      // where Region::add() and Resources::addScriptUrl() produce slightly different orderings.
+    ]));
+    return $this;
+  }
+
   /**
    * Export permission data to the client to enable smarter GUIs.
    *
index caead5920cca93b6c10760b66883274618120844..05594c7fd81e61b6bba51103e34e16b50e53c977 100644 (file)
@@ -126,6 +126,21 @@ trait CRM_Core_Resources_CollectionTestTrait {
       ]
     );
 
+    $addCases(
+      [
+        'add(scriptUrl,esm)' => ['add', ['scriptUrl' => 'http://example.com/foo.js', 'esm' => TRUE]],
+        'addModuleUrl()' => ['addModuleUrl', 'http://example.com/foo.js'],
+      ],
+      [
+        'name' => 'http://example.com/foo.js',
+        'disabled' => FALSE,
+        'weight' => 1,
+        'type' => 'scriptUrl',
+        'scriptUrl' => 'http://example.com/foo.js',
+        'esm' => TRUE,
+      ]
+    );
+
     $addCases(
       [
         'add(styleFile)' => ['add', ['styleFile' => ['civicrm', 'css/civicrm.css']]],
@@ -153,6 +168,15 @@ trait CRM_Core_Resources_CollectionTestTrait {
       ],
     ];
 
+    $addCases(
+      [
+        'add(scriptFile): esm' => ['add', ['scriptFile' => ['civicrm', 'js/foo.js'], 'esm' => TRUE]],
+        'addScriptFile(): esm' => ['addModuleFile', 'civicrm', 'js/foo.js', ['esm' => TRUE]],
+        'addModuleFile(): dfl' => ['addModuleFile', 'civicrm', 'js/foo.js'],
+      ],
+      $basicFooJs + ['weight' => 1, 'translate' => TRUE, 'esm' => TRUE]
+    );
+
     $addCases(
       [
         'add(scriptFile): dfl' => ['add', ['scriptFile' => ['civicrm', 'js/foo.js']]],
@@ -195,6 +219,22 @@ trait CRM_Core_Resources_CollectionTestTrait {
       ]
     );
 
+    $addCases(
+      [
+        'add(script): esm' => ['add', ['script' => 'window.alert("Boo!");', 'esm' => TRUE]],
+        'addScript(): esm' => ['addScript', 'window.alert("Boo!");', ['esm' => TRUE]],
+        'addModule(): dfl' => ['addModule', 'window.alert("Boo!");'],
+      ],
+      [
+        'name' => 1 + $defaultCount,
+        'disabled' => FALSE,
+        'weight' => 1,
+        'type' => 'script',
+        'script' => 'window.alert("Boo!");',
+        'esm' => TRUE,
+      ]
+    );
+
     if ($allowsMarkup) {
       $addCases(
         [