From e7ff70420d0eca8795ff46e4d9bb8a4589f4228a Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Tue, 15 Apr 2014 19:25:38 -0700 Subject: [PATCH] CRM-14479 - Implement "/civicrm/a" page This page is a container for Angular-based pages. To develop a new Angular-based page, one would: a) Create a JS file which defines an Angular module. (The file should start out with "var myModule = angular.module(...)".) b) Register the module-name/file-name. This can be registered either by: - If writing a CiviCRM extension, then implement hook_civicrm_angularModules. - If writing a CiviCRM component, then implement getAngularModules(). --- CRM/Core/Component/Info.php | 10 ++++++ CRM/Core/Page/Angular.php | 54 +++++++++++++++++++++++++++++ CRM/Core/xml/Menu/Misc.xml | 5 +++ CRM/Extension/Mapper.php | 18 ++++++++++ CRM/Utils/Hook.php | 21 +++++++++++ templates/CRM/Core/Page/Angular.tpl | 19 ++++++++++ 6 files changed, 127 insertions(+) create mode 100644 CRM/Core/Page/Angular.php create mode 100644 templates/CRM/Core/Page/Angular.tpl diff --git a/CRM/Core/Component/Info.php b/CRM/Core/Component/Info.php index 24bef08f9d..8278edfa38 100644 --- a/CRM/Core/Component/Info.php +++ b/CRM/Core/Component/Info.php @@ -115,6 +115,16 @@ abstract class CRM_Core_Component_Info { $this->info['url'] = $this->getKeyword(); } + /** + * EXPERIMENTAL: Get a list of AngularJS modules + * + * @return array list of modules; same format as CRM_Utils_Hook::angularModules(&$angularModules) + * @see CRM_Utils_Hook::angularModules + */ + public function getAngularModules() { + return array(); + } + /** * Provides base information about the component. * Needs to be implemented in component's information diff --git a/CRM/Core/Page/Angular.php b/CRM/Core/Page/Angular.php new file mode 100644 index 0000000000..412fc371ab --- /dev/null +++ b/CRM/Core/Page/Angular.php @@ -0,0 +1,54 @@ +addSettingsFactory(function () use (&$modules) { + // TODO optimization; client-side caching + return array( + 'resourceUrls' => CRM_Extension_System::singleton()->getMapper()->getActiveModuleUrls(), + 'angular' => array( + 'modules' => array_merge(array('ngRoute'), array_keys($modules)), + ), + ); + }); + + $res->addScriptFile('civicrm', 'packages/bower_components/angular/angular.js', 100, 'html-header', FALSE); + $res->addScriptFile('civicrm', 'packages/bower_components/angular-route/angular-route.js', 110, 'html-header', FALSE); + foreach ($modules as $module) { + if (!empty($module['file'])) { + $res->addScriptFile($module['ext'], $module['file'], self::DEFAULT_MODULE_WEIGHT, 'html-header', TRUE); + } + } + + return parent::run(); + } + + /** + * Get a list of AngularJS modules which should be autoloaded + * + * @return array (string $name => array('ext' => string $key, 'file' => string $path)) + */ + public static function getAngularModules() { + $angularModules = array(); + foreach (CRM_Core_Component::getEnabledComponents() as $component) { + $angularModules = array_merge($angularModules, $component->getAngularModules()); + } + CRM_Utils_Hook::angularModules($angularModules); + return $angularModules; + } + +} \ No newline at end of file diff --git a/CRM/Core/xml/Menu/Misc.xml b/CRM/Core/xml/Menu/Misc.xml index 274c6fc946..e1f4a1d11d 100644 --- a/CRM/Core/xml/Menu/Misc.xml +++ b/CRM/Core/xml/Menu/Misc.xml @@ -170,4 +170,9 @@ ProfileEditor access CiviCRM + + civicrm/a + CRM_Core_Page_Angular + access CiviCRM + diff --git a/CRM/Extension/Mapper.php b/CRM/Extension/Mapper.php index c70f218dad..76ee2b9777 100755 --- a/CRM/Extension/Mapper.php +++ b/CRM/Extension/Mapper.php @@ -305,6 +305,24 @@ class CRM_Extension_Mapper { return $moduleExtensions; } + /** + * Get a list of base URLs for all active modules + * + * @return array (string $extKey => string $baseUrl) + */ + public function getActiveModuleUrls() { + // TODO optimization/caching + $urls = array(); + $urls['civicrm'] = $this->keyToUrl('civicrm'); + foreach ($this->getModules() as $module) { + /** @var $module CRM_Core_Module */ + if ($module->is_active) { + $urls[$module->name] = $this->keyToUrl($module->name); + } + } + return $urls; + } + public function isActiveModule($name) { $activeModules = $this->getActiveModuleFiles(); foreach ($activeModules as $activeModule) { diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index db7c036bd9..664b21a8b1 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -1600,4 +1600,25 @@ abstract class CRM_Utils_Hook { self::$_nullObject, 'civicrm_contact_get_displayname' ); } + + /** + * EXPERIMENTAL: This hook allows one to register additional Angular modules + * + * @param array $angularModules list of modules + * @return null the return value is ignored + * @access public + * + * @code + * function mymod_civicrm_angularModules(&$angularModules) { + * $angularModules['myAngularModule'] = array('ext' => 'org.example.mymod', 'file' => 'js/myAngularModule.js'); + * } + * @endcode + */ + static function angularModules(&$angularModules) { + return self::singleton()->invoke(1, $angularModules, + self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, + 'civicrm_angularModules' + ); + } + } diff --git a/templates/CRM/Core/Page/Angular.tpl b/templates/CRM/Core/Page/Angular.tpl new file mode 100644 index 0000000000..ca531b944d --- /dev/null +++ b/templates/CRM/Core/Page/Angular.tpl @@ -0,0 +1,19 @@ +{literal} +
+
+
+ + + +{/literal} \ No newline at end of file -- 2.25.1