From 9bd30577003960d454442b0ee426946d581ff875 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Fri, 26 Mar 2021 20:29:15 -0400 Subject: [PATCH] AngularLoader - Support multiple angularjs apps running on the page This creates a service named 'angularjs.loader' to manage multiple angular apps on the page. Because can only be used once per page, a new tag, has been created. --- CRM/Core/Region.php | 1 + Civi/Angular/AngularLoader.php | 29 +++++++++++++++++++++++++---- Civi/Core/Container.php | 5 +++++ js/crm-angularjs-loader.js | 11 +++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 js/crm-angularjs-loader.js diff --git a/CRM/Core/Region.php b/CRM/Core/Region.php index c7eab5c584..388d8d17f2 100644 --- a/CRM/Core/Region.php +++ b/CRM/Core/Region.php @@ -142,6 +142,7 @@ class CRM_Core_Region implements CRM_Core_Resources_CollectionInterface, CRM_Cor } }; + Civi::dispatcher()->dispatch('civi.region.render', \Civi\Core\Event\GenericHookEvent::create(['region' => $this])); foreach ($this->snippets as $snippet) { if (empty($snippet['disabled'])) { $renderSnippet($snippet); diff --git a/Civi/Angular/AngularLoader.php b/Civi/Angular/AngularLoader.php index 60252c83b3..d446fec947 100644 --- a/Civi/Angular/AngularLoader.php +++ b/Civi/Angular/AngularLoader.php @@ -78,8 +78,18 @@ class AngularLoader { } /** - * Register resources required by Angular. + * Calling this method from outside this class is deprecated. * + * The correct way to use this class is as a service, which will load automatically. E.g.: + * + * ``` + * Civi::service('angularjs.loader') + * ->addModules('moduleFoo') + * ->useApp(); // Optional, if Civi's routing is desired (full-page apps only) + * ``` + * + * @internal + * @deprecated * @return AngularLoader */ public function load() { @@ -88,9 +98,7 @@ class AngularLoader { if ($this->crmApp !== NULL) { $this->addModules($this->crmApp['modules']); - $region = \CRM_Core_Region::instance($this->crmApp['region']); - $region->update('default', ['disabled' => TRUE]); - $region->add(['template' => $this->crmApp['file'], 'weight' => 0]); + $this->res->addSetting([ 'crmApp' => [ 'defaultRoute' => $this->crmApp['defaultRoute'], @@ -216,6 +224,9 @@ class AngularLoader { 'file' => 'Civi/Angular/Page/Main.tpl', ]; $this->crmApp = array_merge($defaults, $settings); + $region = \CRM_Core_Region::instance($this->crmApp['region']); + $region->update('default', ['disabled' => TRUE]); + $region->add(['template' => $this->crmApp['file'], 'weight' => 0]); return $this; } @@ -335,4 +346,14 @@ class AngularLoader { return $this; } + /** + * @param \Civi\Core\Event\GenericHookEvent $e + */ + public function onRegionRender($e) { + if ($e->region->_name === $this->region && ($this->modules || $this->crmApp)) { + $this->load(); + $this->res->addScriptFile('civicrm', 'js/crm-angularjs-loader.js', 200, $this->getRegion(), FALSE); + } + } + } diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index 7a02a56b45..39749a81bb 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -123,6 +123,9 @@ class Container { )) ->setFactory([new Reference(self::SELF), 'createAngularManager'])->setPublic(TRUE); + $container->setDefinition('angularjs.loader', new Definition('Civi\Angular\AngularLoader', [])) + ->setPublic(TRUE); + $container->setDefinition('dispatcher', new Definition( 'Civi\Core\CiviEventDispatcher', [] @@ -351,6 +354,7 @@ class Container { */ public function createEventDispatcher() { // Continue building on the original dispatcher created during bootstrap. + /** @var CiviEventDispatcher $dispatcher */ $dispatcher = static::getBootService('dispatcher.boot'); $dispatcher->addListener('civi.core.install', ['\Civi\Core\InstallationCanary', 'check']); @@ -370,6 +374,7 @@ class Container { $dispatcher->addListener('hook_civicrm_eventDefs', ['\Civi\API\Events', 'hookEventDefs']); $dispatcher->addListener('hook_civicrm_eventDefs', ['\Civi\Core\Event\SystemInstallEvent', 'hookEventDefs']); $dispatcher->addListener('hook_civicrm_buildAsset', ['\Civi\Angular\Page\Modules', 'buildAngularModules']); + $dispatcher->addListenerService('civi.region.render', ['angularjs.loader', 'onRegionRender']); $dispatcher->addListener('hook_civicrm_buildAsset', ['\CRM_Utils_VisualBundle', 'buildAssetJs']); $dispatcher->addListener('hook_civicrm_buildAsset', ['\CRM_Utils_VisualBundle', 'buildAssetCss']); $dispatcher->addListener('hook_civicrm_buildAsset', ['\CRM_Core_Resources', 'renderMenubarStylesheet']); diff --git a/js/crm-angularjs-loader.js b/js/crm-angularjs-loader.js new file mode 100644 index 0000000000..5a2fe57f21 --- /dev/null +++ b/js/crm-angularjs-loader.js @@ -0,0 +1,11 @@ +// http://civicrm.org/licensing +(function($, _) { + "use strict"; + + $(document).on('crmLoad', function(e) { + $('crm-angular-js', e.target).not('.ng-scope').each(function() { + angular.bootstrap(this, $(this).attr('modules').split()); + }); + }); + +})(CRM.$, CRM._); -- 2.25.1