Skip to content

Commit

Permalink
Merge pull request #19922 from colemanw/angularLoader
Browse files Browse the repository at this point in the history
AngularJS - Allow loading multiple apps on a single page
  • Loading branch information
colemanw authored Apr 6, 2021
2 parents e050cce + ac27ff2 commit 5da2ee7
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 40 deletions.
11 changes: 4 additions & 7 deletions CRM/Api4/Page/Api4Explorer.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,10 @@ public function run() {
->addScriptFile('civicrm', 'bower_components/google-code-prettify/bin/prettify.min.js')
->addStyleFile('civicrm', 'bower_components/google-code-prettify/bin/prettify.min.css');

$loader = new Civi\Angular\AngularLoader();
$loader->setModules(['api4Explorer']);
$loader->setPageName('civicrm/api4');
$loader->useApp([
'defaultRoute' => '/explorer',
]);
$loader->load();
Civi::service('angularjs.loader')
->addModules('api4Explorer')
->useApp(['defaultRoute' => '/explorer']);

parent::run();
}

Expand Down
9 changes: 3 additions & 6 deletions CRM/Contact/Page/DashBoard.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,21 @@ public function run() {
}
}

$loader = new Civi\Angular\AngularLoader();
$loader = Civi::service('angularjs.loader');
$loader->addModules('crmDashboard');
$loader->setPageName('civicrm/dashboard');

// For each dashlet that requires an angular directive, load the angular module which provides that directive
$modules = [];
foreach (CRM_Core_BAO_Dashboard::getContactDashlets() as $dashlet) {
if (!empty($dashlet['directive'])) {
foreach ($loader->getAngular()->getModules() as $name => $module) {
if (!empty($module['exports'][$dashlet['directive']])) {
$modules[] = $name;
$loader->addModules($name);
continue;
}
}
}
}
$loader->setModules($modules);

$loader->load();

return parent::run();
}
Expand Down
2 changes: 2 additions & 0 deletions CRM/Core/Region.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public function render($default, $allowCmsOverride = TRUE) {
$this->snippets['default']['markup'] = $default;
}

Civi::dispatcher()->dispatch('civi.region.render', \Civi\Core\Event\GenericHookEvent::create(['region' => $this]));

$this->sort();

$cms = CRM_Core_Config::singleton()->userSystem;
Expand Down
7 changes: 3 additions & 4 deletions CRM/Export/Form/Map.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ public function preProcess() {
],
]);

// Bootstrap angular and load exportui app
$loader = new Civi\Angular\AngularLoader();
$loader->setModules(['exportui']);
$loader->load();
// Add exportui app
Civi::service('angularjs.loader')
->addModules('exportui');
}

public function buildQuickForm() {
Expand Down
33 changes: 29 additions & 4 deletions Civi/Angular/AngularLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,18 @@ public function __construct() {
}

/**
* 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() {
Expand All @@ -88,9 +98,7 @@ public function load() {

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'],
Expand Down Expand Up @@ -216,6 +224,9 @@ public function useApp($settings = []) {
'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;
}

Expand Down Expand Up @@ -327,6 +338,10 @@ public function getModules() {
}

/**
* Replace all previously set modules.
*
* Use with caution, as it can cause conflicts with other extensions who have added modules.
*
* @param array $modules
* @return AngularLoader
*/
Expand All @@ -335,4 +350,14 @@ public function setModules($modules) {
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);
}
}

}
5 changes: 5 additions & 0 deletions Civi/Core/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ public function createContainer() {
))
->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',
[]
Expand Down Expand Up @@ -351,6 +354,7 @@ public function createAngularManager() {
*/
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']);
Expand All @@ -370,6 +374,7 @@ public function createEventDispatcher() {
$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']);
Expand Down
2 changes: 1 addition & 1 deletion ang/crmDashboard.ang.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'css' => ['css/dashboard.css'],
'partials' => ['ang/crmDashboard'],
'partialsCallback' => ['CRM_Contact_Page_DashBoard', 'angularPartials'],
'basePages' => ['civicrm/dashboard'],
'basePages' => [],
'requires' => ['crmUi', 'crmUtil', 'ui.sortable', 'dialogService', 'api4'],
'settingsFactory' => ['CRM_Contact_Page_DashBoard', 'angularSettings'],
'permissions' => ['administer CiviCRM'],
Expand Down
5 changes: 2 additions & 3 deletions ext/afform/admin/CRM/AfformAdmin/Page/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ public function run() {
CRM_Utils_System::appendBreadCrumb([$breadCrumb]);

// Load angular module
$loader = new Civi\Angular\AngularLoader();
$loader->setPageName('civicrm/admin/afform');
$loader = Civi::service('angularjs.loader');
$loader->useApp();
$loader->load();

parent::run();
}

Expand Down
9 changes: 3 additions & 6 deletions ext/search/CRM/Search/Page/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,9 @@ public function run() {
CRM_Utils_System::appendBreadCrumb([$breadCrumb]);

// Load angular module
$loader = new Civi\Angular\AngularLoader();
$loader->setPageName('civicrm/admin/search');
$loader->useApp([
'defaultRoute' => '/list',
]);
$loader->load();
Civi::service('angularjs.loader')
->useApp(['defaultRoute' => '/list']);

parent::run();
}

Expand Down
8 changes: 1 addition & 7 deletions ext/search/CRM/Search/Page/Search.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@ class CRM_Search_Page_Search extends CRM_Core_Page {

public function run() {

Civi::resources()->addBundle('bootstrap3');

// Load angular module
$loader = new Civi\Angular\AngularLoader();
$loader->setPageName('civicrm/search');
$loader->useApp();
$loader->load();
Civi::service('angularjs.loader')->useApp();

if (CRM_Core_Permission::check('administer CiviCRM')) {
CRM_Utils_System::appendBreadCrumb([['title' => E::ts('Search Kit'), 'url' => CRM_Utils_System::url('civicrm/admin/search')]]);
Expand Down
11 changes: 11 additions & 0 deletions js/crm-angularjs-loader.js
Original file line number Diff line number Diff line change
@@ -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._);
4 changes: 2 additions & 2 deletions templates/CRM/Export/Form/Map.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
{include file="CRM/common/WizardHeader.tpl"}
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>

<div ng-app="exportui">
<crm-angular-js modules="exportui">
<div class="crm-export-field-selector-outer" ng-controller="ExportUiCtrl" ng-include="'~/exportui/export.html'"></div>
</div>
</crm-angular-js>

<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
{$initHideBoxes}
Expand Down

0 comments on commit 5da2ee7

Please sign in to comment.