);
$angularModules['crmUi'] = array(
'ext' => 'civicrm',
- 'js' => array('js/angular-crm-ui.js', 'packages/ckeditor/ckeditor.js'),
+ 'js' => array('js/angular-crm-ui.js'),
'partials' => array('partials/crmUi'),
);
$angularModules['crmUtil'] = array(
}
/**
- * @param string $name
- * Module name.
+ * Get resources for one or more modules.
+ *
+ * @param string|array $moduleNames
+ * List of module names.
+ * @param string $resType
+ * Type of resource ('js', 'css').
+ * @param string $refType
+ * Type of reference to the resource ('cacheUrl', 'rawUrl', 'path').
* @return array
- * List of URLs.
- * @throws \Exception
+ * List of URLs or paths.
+ * @throws \CRM_Core_Exception
*/
- public function getScriptUrls($name) {
- $module = $this->getModule($name);
+ public function getResources($moduleNames, $resType, $refType) {
$result = array();
- if (isset($module['js'])) {
- foreach ($module['js'] as $file) {
- $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
- }
- }
- return $result;
- }
+ $moduleNames = (array) $moduleNames;
+ foreach ($moduleNames as $moduleName) {
+ $module = $this->getModule($moduleName);
+ if (isset($module[$resType])) {
+ foreach ($module[$resType] as $file) {
+ switch ($refType) {
+ case 'path':
+ $result[] = $this->res->getPath($module['ext'], $file);
+ break;
- /**
- * @param string $name
- * Module name.
- * @return array
- * List of URLs.
- * @throws \Exception
- */
- public function getStyleUrls($name) {
- $module = $this->getModule($name);
- $result = array();
- if (isset($module['css'])) {
- foreach ($module['css'] as $file) {
- $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
+ case 'rawUrl':
+ $result[] = $this->res->getUrl($module['ext'], $file);
+ break;
+
+ case 'cacheUrl':
+ $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
+ break;
+
+ default:
+ throw new \CRM_Core_Exception("Unrecognized resource format");
+ }
+ }
}
}
return $result;
$this->res->addScriptFile('civicrm', 'bower_components/angular/angular.min.js', 100, 'html-header', FALSE);
$this->res->addScriptFile('civicrm', 'bower_components/angular-route/angular-route.min.js', 110, 'html-header', FALSE);
- $headOffset = 0;
- foreach ($modules as $moduleName => $module) {
- foreach ($this->angular->getStyleUrls($moduleName) as $url) {
- $this->res->addStyleUrl($url, self::DEFAULT_MODULE_WEIGHT + (++$headOffset), 'html-header');
- }
- foreach ($this->angular->getScriptUrls($moduleName) as $url) {
- $this->res->addScriptUrl($url, self::DEFAULT_MODULE_WEIGHT + (++$headOffset), 'html-header');
- // addScriptUrl() bypasses the normal string-localization of addScriptFile(),
- // but that's OK because all Angular strings (JS+HTML) will load via crmResource.
+
+ // FIXME: crmUi depends on loading ckeditor, but ckeditor doesn't work with this aggregation.
+ $this->res->addScriptFile('civicrm', 'packages/ckeditor/ckeditor.js', 100, 'html-header', FALSE);
+
+ $config = \CRM_Core_Config::singleton();
+ if ($config->debug) {
+ $headOffset = 0;
+ foreach ($modules as $moduleName => $module) {
+ foreach ($this->angular->getResources($moduleName, 'css', 'cacheUrl') as $url) {
+ $this->res->addStyleUrl($url, self::DEFAULT_MODULE_WEIGHT + (++$headOffset), 'html-header');
+ }
+ foreach ($this->angular->getResources($moduleName, 'js', 'cacheUrl') as $url) {
+ $this->res->addScriptUrl($url, self::DEFAULT_MODULE_WEIGHT + (++$headOffset), 'html-header');
+ // addScriptUrl() bypasses the normal string-localization of addScriptFile(),
+ // but that's OK because all Angular strings (JS+HTML) will load via crmResource.
+ }
}
}
+ else {
+ // Note: addScriptUrl() bypasses the normal string-localization of addScriptFile(),
+ // but that's OK because all Angular strings (JS+HTML) will load via crmResource.
+ $aggScriptUrl = \CRM_Utils_System::url('civicrm/ajax/angular-modules', 'format=js&r=' . $page->res->getCacheCode(), FALSE, NULL, FALSE);
+ $this->res->addScriptUrl($aggScriptUrl, 120, 'html-header');
+
+ $aggStyleUrl = \CRM_Utils_System::url('civicrm/ajax/angular-modules', 'format=css&r=' . $page->res->getCacheCode(), FALSE, NULL, FALSE);
+ $this->res->addStyleUrl($aggStyleUrl, 120, 'html-header');
+ }
}
}
namespace Civi\Angular\Page;
/**
- * This page returns HTML partials used by Angular.
+ * This page aggregates data from Angular modules.
+ *
+ * Example: Aggregate metadata about all modules in JSON format.
+ * civicrm/ajax/angular-modules?format=json
+ *
+ * Example: Aggregate metadata for crmUi and crmUtil modules.
+ * civicrm/ajax/angular-modules?format=json&modules=crmUi,crmUtil
+ *
+ * Example: Aggregate *.js files for all modules.
+ * civicrm/ajax/angular-modules?format=js
+ *
+ * Example: Aggregate *.css files for all modules.
+ * civicrm/ajax/angular-modules?format=css
*/
class Modules extends \CRM_Core_Page {
/**
- * This page aggregates HTML partials used by Angular.
+ * See class description.
*/
public function run() {
- //$config = \CRM_Core_Config::singleton();
- //\CRM_Core_Page_AJAX::setJsHeaders($config->debug ? 30 : NULL);
- \CRM_Core_Page_AJAX::setJsHeaders();
-
/**
* @var \Civi\Angular\Manager $angular
*/
$angular = \Civi\Core\Container::singleton()->get('angular');
- $modules = $angular->getModules();
+ $moduleNames = $this->parseModuleNames(\CRM_Utils_Request::retrieve('modules', 'String'), $angular);
+
+ switch (\CRM_Utils_Request::retrieve('format', 'String')) {
+ case 'json':
+ case '':
+ $this->send(
+ 'application/javascript',
+ json_encode($this->getMetadata($moduleNames, $angular))
+ );
+ break;
+
+ case 'js':
+ $this->send(
+ 'application/javascript',
+ \CRM_Utils_File::concat($angular->getResources($moduleNames, 'js', 'path'), "\n")
+ );
+ break;
+
+ case 'css':
+ $this->send(
+ 'text/css',
+ \CRM_Utils_File::concat($angular->getResources($moduleNames, 'css', 'path'), "\n")
+ );
+ break;
+
+ default:
+ \CRM_Core_Error::fatal("Unrecognized format");
+ }
+
+ \CRM_Utils_System::civiExit();
+ }
- $modulesExpr = \CRM_Utils_Request::retrieve('modules', 'String');
+ /**
+ * @param string $modulesExpr
+ * Comma-separated list of module names.
+ * @param \Civi\Angular\Manager $angular
+ * @return array
+ * Any well-formed module names. All if moduleExpr is blank.
+ */
+ public function parseModuleNames($modulesExpr, $angular) {
if ($modulesExpr) {
$moduleNames = preg_grep(
'/^[a-zA-Z0-9\-_\.]+$/',
explode(',', $modulesExpr)
);
+ return $moduleNames;
}
else {
- $moduleNames = array_keys($modules);
+ $moduleNames = array_keys($angular->getModules());
+ return $moduleNames;
}
+ }
+ /**
+ * @param array $moduleNames
+ * List of module names.
+ * @param \Civi\Angular\Manager $angular
+ * @return array
+ */
+ public function getMetadata($moduleNames, $angular) {
+ $modules = $angular->getModules();
$result = array();
foreach ($moduleNames as $moduleName) {
if (isset($modules[$moduleName])) {
$result[$moduleName] = array();
$result[$moduleName]['domain'] = $modules[$moduleName]['ext'];
- $result[$moduleName]['js'] = $angular->getScriptUrls($moduleName);
- $result[$moduleName]['css'] = $angular->getStyleUrls($moduleName);
+ $result[$moduleName]['js'] = $angular->getResources($moduleName, 'js', 'rawUrl');
+ $result[$moduleName]['css'] = $angular->getResources($moduleName, 'css', 'rawUrl');
$result[$moduleName]['partials'] = $angular->getPartials($moduleName);
$result[$moduleName]['strings'] = $angular->getTranslatedStrings($moduleName);
}
}
+ return $result;
+ }
- echo json_encode($result);
- \CRM_Utils_System::civiExit();
+ /**
+ * Send a response.
+ *
+ * @param string $type
+ * Content type.
+ * @param string $data
+ * Content.
+ */
+ public function send($type, $data) {
+ // Encourage browsers to cache for a long time - 1 year
+ $ttl = 60 * 60 * 24 * 364;
+ header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
+ header("Content-Type: $type");
+ header("Cache-Control: max-age=$ttl, public");
+ echo $data;
}
}