From a45465497a5dc0d55495b0c616f4c53a882de0b5 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 30 Jun 2022 21:53:54 -0400 Subject: [PATCH] Angular - Support popping up an afform or other ang module via ajax modal Fixes the AngularLoader to work with modal dialogs via ajax. Dedupes the already-loaded modules to only load what's needed. --- Civi/Angular/AngularLoader.php | 46 ++++++++++++++++++++++++++-------- js/angular-crmResource/all.js | 16 ++++++------ js/crm.ajax.js | 3 +++ 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/Civi/Angular/AngularLoader.php b/Civi/Angular/AngularLoader.php index a6b5f80a42..ecfb4797fb 100644 --- a/Civi/Angular/AngularLoader.php +++ b/Civi/Angular/AngularLoader.php @@ -47,6 +47,13 @@ class AngularLoader { */ protected $region; + /** + * @var array + * When adding supplimental modules via snippet, + * these modules are already loaded. + */ + protected $modulesAlreadyLoaded = []; + /** * @var string * Ex: 'civicrm/a'. @@ -73,6 +80,11 @@ class AngularLoader { $this->region = \CRM_Utils_Request::retrieve('snippet', 'String') ? 'ajax-snippet' : 'html-header'; $this->pageName = \CRM_Utils_System::currentPath(); $this->modules = []; + if ($this->region === 'ajax-snippet' && !empty($_GET['crmAngularModules'])) { + $this->modulesAlreadyLoaded = explode(',', $_GET['crmAngularModules']); + } + // Ensure region exists + \CRM_Core_Region::instance($this->region); } /** @@ -115,7 +127,13 @@ class AngularLoader { ]); } - $moduleNames = $this->findActiveModules(); + $allModules = $this->findActiveModules(); + $moduleNames = array_values(array_diff($allModules, $this->modulesAlreadyLoaded)); + + if (!$moduleNames && $this->modulesAlreadyLoaded) { + // No modules to load + return $this; + } if (!$this->isAllModules($moduleNames)) { $assetParams = ['modules' => implode(',', $moduleNames)]; } @@ -124,7 +142,7 @@ class AngularLoader { $assetParams = ['nonce' => md5(implode(',', $moduleNames))]; } - $res->addSettingsFactory(function () use (&$moduleNames, $angular, $res, $assetParams) { + $res->addSettingsFactory(function () use (&$moduleNames, $angular, $res, $assetParams, $allModules) { // Merge static settings with the results of settingsFactory functions $settingsByModule = $angular->getResources($moduleNames, 'settings', 'settings'); foreach ($angular->getResources($moduleNames, 'settingsFactory', 'settingsFactory') as $moduleName => $factory) { @@ -144,7 +162,7 @@ class AngularLoader { return array_merge($settingsByModule, ['permissions' => $permissions], [ 'resourceUrls' => \CRM_Extension_System::singleton()->getMapper()->getActiveModuleUrls(), 'angular' => [ - 'modules' => $moduleNames, + 'modules' => $allModules, 'requires' => $angular->getResources($moduleNames, 'requires', 'requires'), 'cacheCode' => $res->getCacheCode(), 'bundleUrl' => \Civi::service('asset_builder')->getUrl('angular-modules.json', $assetParams), @@ -152,13 +170,17 @@ class AngularLoader { ]); }); - $res->addScriptFile('civicrm', 'bower_components/angular/angular.min.js', 100, $this->getRegion(), FALSE); + if (!$this->modulesAlreadyLoaded) { + $res->addScriptFile('civicrm', 'bower_components/angular/angular.min.js', 100, $this->getRegion(), FALSE); + } $headOffset = 0; $config = \CRM_Core_Config::singleton(); - if ($config->debug) { - // FIXME: The `resetLocationProviderHashPrefix.js` has to stay in sync with `\Civi\Angular\Page\Modules::buildAngularModules()`. - $res->addScriptFile('civicrm', 'ang/resetLocationProviderHashPrefix.js', 101, $this->getRegion(), FALSE); + if ($config->debug || $this->modulesAlreadyLoaded) { + if (!$this->modulesAlreadyLoaded) { + // FIXME: The `resetLocationProviderHashPrefix.js` has to stay in sync with `\Civi\Angular\Page\Modules::buildAngularModules()`. + $res->addScriptFile('civicrm', 'ang/resetLocationProviderHashPrefix.js', 101, $this->getRegion(), FALSE); + } foreach ($moduleNames as $moduleName) { foreach ($this->angular->getResources($moduleName, 'css', 'cacheUrl') as $url) { $res->addStyleUrl($url, self::DEFAULT_MODULE_WEIGHT + (++$headOffset), $this->getRegion()); @@ -187,8 +209,10 @@ class AngularLoader { } } // Add bundles - foreach ($this->angular->getResources($moduleNames, 'bundles', 'bundles') as $bundles) { - $res->addBundle($bundles); + if (!$this->modulesAlreadyLoaded) { + foreach ($this->angular->getResources($moduleNames, 'bundles', 'bundles') as $bundles) { + $res->addBundle($bundles); + } } return $this; @@ -366,7 +390,9 @@ class AngularLoader { public function onRegionRender($e) { if ($e->region->_name === $this->region && ($this->modules || $this->crmApp)) { $this->loadAngularResources(); - $this->res->addScriptFile('civicrm', 'js/crm-angularjs-loader.js', 200, $this->getRegion(), FALSE); + if (!$this->modulesAlreadyLoaded) { + $this->res->addScriptFile('civicrm', 'js/crm-angularjs-loader.js', 200, $this->getRegion(), FALSE); + } } } diff --git a/js/angular-crmResource/all.js b/js/angular-crmResource/all.js index 356a582407..bad03ba486 100644 --- a/js/angular-crmResource/all.js +++ b/js/angular-crmResource/all.js @@ -5,14 +5,13 @@ angular.module('crmResource').factory('crmResource', function($q, $http) { var deferreds = {}; // null|object; deferreds[url][idx] = Deferred; - var templates = null; // null|object; templates[url] = HTML; var notify = function notify() { var oldDfrds = deferreds; deferreds = null; angular.forEach(oldDfrds, function(dfrs, url) { - if (templates[url]) { + if (CRM.angular.templates[url]) { angular.forEach(dfrs, function(dfr) { dfr.resolve({ status: 200, @@ -20,7 +19,7 @@ var headers = {'Content-type': 'text/html'}; return name ? headers[name] : headers; }, - data: templates[url] + data: CRM.angular.templates[url] }); }); } @@ -35,10 +34,10 @@ var moduleUrl = CRM.angular.bundleUrl; $http.get(moduleUrl) .then(function httpSuccess(response) { - templates = []; - angular.forEach(response.data, function(module) { + CRM.angular.templates = CRM.angular.templates || {}; + angular.forEach(response.data, function (module) { if (module.partials) { - angular.extend(templates, module.partials); + angular.extend(CRM.angular.templates, module.partials); } if (module.strings) { CRM.addStrings(module.domain, module.strings); @@ -46,15 +45,14 @@ }); notify(); }, function httpError() { - templates = []; notify(); }); return { // @return string|Promise getUrl: function getUrl(url) { - if (templates !== null) { - return templates[url]; + if (CRM.angular.templates && CRM.angular.templates[url]) { + return CRM.angular.templates[url]; } else { var deferred = $q.defer(); diff --git a/js/crm.ajax.js b/js/crm.ajax.js index 57ed34f993..2c892bfcea 100644 --- a/js/crm.ajax.js +++ b/js/crm.ajax.js @@ -273,6 +273,9 @@ } else { url = url.replace(/snippet=[^&]*/, 'snippet=' + snippetType); } + if (snippetType === 'json' && CRM.angular) { + url += '&crmAngularModules=' + CRM.angular.modules.join(); + } } return url; }, -- 2.25.1