CRM-20600 - Angular deps - Allow declaration in PHP code
authorTim Otten <totten@civicrm.org>
Fri, 19 May 2017 04:20:28 +0000 (21:20 -0700)
committerTim Otten <totten@civicrm.org>
Sat, 17 Jun 2017 02:03:47 +0000 (19:03 -0700)
If third-parties are allowed to alter the HTML content, then they may
introduce new dependencies.  This means that they'll need to delcare those
dependencies.

Tangentially, this will also make it easier to construct more optimized
base-pages (e.g.  "make a base-page with module X plus all its
dependencies").

CRM/Utils/Hook.php
Civi/Angular/Manager.php
Civi/Angular/Page/Main.php
js/Common.js
js/crm.angular.js [new file with mode: 0644]
karma.conf.js
package.json
tests/karma/modules.js [deleted file]

index d44d2dacddabd4d2e516795a75b2a60e09c34719..23e29ef595ca63d76697b9c01406dba8dcb1e183 100644 (file)
@@ -2075,7 +2075,12 @@ abstract class CRM_Utils_Hook {
    * EXPERIMENTAL: This hook allows one to register additional Angular modules
    *
    * @param array $angularModules
-   *   List of modules.
+   *   List of modules. Each module defines:
+   *    - ext: string, the CiviCRM extension which hosts the files.
+   *    - js: array, list of JS files or globs.
+   *    - css: array, list of CSS files or globs.
+   *    - partials: array, list of base-dirs containing HTML.
+   *    - requires: array, list of required Angular modules.
    * @return null
    *   the return value is ignored
    *
@@ -2090,6 +2095,7 @@ abstract class CRM_Utils_Hook {
    *     'js' => array('js/part1.js', 'js/part2.js'),
    *     'css' => array('css/myAngularModule.css'),
    *     'partials' => array('partials/myBigAngularModule'),
+   *     'requires' => array('otherModuleA', 'otherModuleB'),
    *   );
    * }
    * @endcode
index 7d46947ef53395790c6491ca53169db9fd0abcc7..0f19e1dff7d065c6ef89f3a1f754ee252bfd86e7 100644 (file)
@@ -262,6 +262,7 @@ class Manager {
               break;
 
             case 'settings':
+            case 'requires':
               if (!empty($module[$resType])) {
                 $result[$moduleName] = $module[$resType];
               }
index c650ff1d385dafbb63018762bd6a65d9e48141ba..b09e5bfadbf7aee9f8a40a1ccfc9373de7ba7fed 100644 (file)
@@ -89,6 +89,7 @@ class Main extends \CRM_Core_Page {
         'resourceUrls' => \CRM_Extension_System::singleton()->getMapper()->getActiveModuleUrls(),
         'angular' => array(
           'modules' => array_merge(array('ngRoute'), $moduleNames),
+          'requires' => $page->angular->getResources($moduleNames, 'requires', 'requires'),
           'cacheCode' => $page->res->getCacheCode(),
           'bundleUrl' => \Civi::service('asset_builder')->getUrl('angular-modules.json', $assetParams),
         ),
@@ -96,6 +97,7 @@ class Main extends \CRM_Core_Page {
     });
 
     $this->res->addScriptFile('civicrm', 'bower_components/angular/angular.min.js', 100, $this->region, FALSE);
+    $this->res->addScriptFile('civicrm', 'js/crm.angular.js', 101, $this->region, FALSE);
 
     $headOffset = 0;
     $config = \CRM_Core_Config::singleton();
index 691df6c15e222b651ce25c73fe6e1aa073c3e41e..15f3528b2d6ebe0a41911306dfe0b52890c946f7 100644 (file)
@@ -1592,6 +1592,10 @@ if (!CRM.vars) CRM.vars = {};
     return format.replace(/1.*234.*56/, result);
   };
 
+  CRM.angRequires = function(name) {
+    return CRM.angular.requires[name] || [];
+  };
+
   CRM.console = function(method, title, msg) {
     if (window.console) {
       method = $.isFunction(console[method]) ? method : 'log';
diff --git a/js/crm.angular.js b/js/crm.angular.js
new file mode 100644 (file)
index 0000000..f1038e3
--- /dev/null
@@ -0,0 +1,7 @@
+(function (angular, $, _) {
+  // DEPRECATED: A variant of angular.module() which uses a dependency list provided by the server.
+  // REMOVE circa v4.7.22.
+  angular.crmDepends = function crmDepends(name) {
+    return angular.module(name, CRM.angRequires(name));
+  };
+})(angular, CRM.$, CRM._);
index 8a7ba6eaa212504007b6ed219a41ca23db66d303..76a758c2cebc181dee324345fcf15b5e2beaf07e 100644 (file)
@@ -1,3 +1,21 @@
+var cv = require('civicrm-cv')({mode: 'sync'});
+var _CV = cv('vars:show');
+var cmd =
+  'CRM_Core_BAO_ConfigSetting::enableComponent("CiviCase");' +
+  'global $civicrm_root;' +
+  '$f = CRM_Utils_File::addTrailingSlash($civicrm_root)."tmp/karma.cv.js";' +
+  'mkdir(dirname($f), 0777, TRUE);' +
+  '$a=Civi::service("angular");' +
+  '$data = "var CRM = CRM || {}; CRM.angular =";' +
+  '$data .= json_encode(array(' +
+  '   "modules" => array_keys($a->getModules()),' +
+  '   "requires" => $a->getResources(array_keys($a->getModules()), "requires","requires"),' +
+  '));' +
+  '$data .= ";";' +
+  'file_put_contents($f, $data);' +
+  'return $f;';
+var angularTempFile = cv(['php:eval', '-U', _CV.ADMIN_USER, cmd]);
+
 module.exports = function(config) {
   config.set({
     autoWatch: true,
@@ -15,6 +33,8 @@ module.exports = function(config) {
       'packages/jquery/plugins/jquery.timeentry.js',
       'js/Common.js',
       'bower_components/angular/angular.js',
+      'js/crm.angular.js',
+      angularTempFile,
       'bower_components/angular-file-upload/angular-file-upload.js',
       'bower_components/angular-jquery-dialog-service/dialog-service.js',
       'bower_components/angular-route/angular-route.js',
@@ -22,7 +42,6 @@ module.exports = function(config) {
       'bower_components/angular-ui-sortable/sortable.js',
       'bower_components/angular-ui-utils/ui-utils.js',
       'bower_components/angular-unsavedChanges/dist/unsavedChanges.js',
-      'tests/karma/modules.js',
       'js/crm.ajax.js',
       'ang/*.js',
       'ang/**/*.js',
index c1a781fa0c09d152622ea7969bdc110136bc17ec..b08cd2272ef9e612a90eed14abfc6347360ec58d 100644 (file)
@@ -10,6 +10,7 @@
   },
   "devDependencies": {
     "bower": "^1.3.1",
+    "civicrm-cv": "^0.1.2",
     "karma": "^0.12.16",
     "karma-ng-html2js-preprocessor": "^0.1.2",
     "karma-phantomjs-launcher": "^0.1.4",
diff --git a/tests/karma/modules.js b/tests/karma/modules.js
deleted file mode 100644 (file)
index 1b918e9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-CRM.angular = {
-  modules: [
-    'ngRoute',
-    'ui.utils',
-    'ui.sortable',
-    'unsavedChanges',
-    'angularFileUpload',
-    'dialogService',
-    'crmAttachment',
-    'crmUi',
-    'crmUtil',
-  ]
-};