From bb56ac7825fc810d04faff70d4a23463c2f98cce Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Tue, 12 Jun 2018 19:25:58 -0700 Subject: [PATCH] Proof-of-concept - Autogenerate AngularJS modules+directives for each form --- ext/afform/README.md | 10 ++++ ext/afform/afform.php | 51 +++++++++++++++++++ .../templates/afform/FormAsDirective.tpl | 26 ++++++++++ 3 files changed, 87 insertions(+) create mode 100644 ext/afform/templates/afform/FormAsDirective.tpl diff --git a/ext/afform/README.md b/ext/afform/README.md index 4e95873a00..8ddd872dca 100644 --- a/ext/afform/README.md +++ b/ext/afform/README.md @@ -91,6 +91,16 @@ $ cv api afform.create name=foobar title="The Foo Bar Screen" (* FIXME *) +## Usage (Developers): Include a customizable subform in your own page + +Suppose you've created an AngularJS UI based on [the developer +documentation](https://docs.civicrm.org/dev/en/latest/framework/angular/quickstart/). You'd like to use the +customizable `foobar` form as part of your UI. Fortunately, `foobar` is available as an AngularJS module named +`afformFoobar`. You can use it with two steps: + +1. In your module metadata (`ang/MYMODULE.ang.php`), update the `requires` to include `afformFoobar`. +2. In your HTML template, use the directive `
`. + ## Known Issues (* FIXME *) diff --git a/ext/afform/afform.php b/ext/afform/afform.php index 59b22af5a4..5eaaa6ca13 100644 --- a/ext/afform/afform.php +++ b/ext/afform/afform.php @@ -132,6 +132,23 @@ function afform_civicrm_caseTypes(&$caseTypes) { */ function afform_civicrm_angularModules(&$angularModules) { _afform_civix_civicrm_angularModules($angularModules); + + $scanner = new CRM_Afform_AfformScanner(); + $names = array_keys($scanner->findFilePaths()); + foreach ($names as $name) { + $meta = $scanner->getMeta($name); + $angularModules[_afform_angular_module_name($name)] = [ + 'ext' => E::LONG_NAME, + 'js' => ['assetBuilder://afform.js?name=' . urlencode($name)], + 'requires' => $meta['requires'], + 'basePages' => [], + ]; + + // FIXME: The HTML layout template is embedded in the JS asset. + // This works at runtime for basic usage, but it bypasses + // the hook_alterAngular infrastructure, and I'm not sure translation works. + // We should update core so that 'partials' can be specified more dynamically. + } } /** @@ -156,6 +173,40 @@ function afform_civicrm_entityTypes(&$entityTypes) { // --- Functions below this ship commented out. Uncomment as required. --- +/** + * Implements hook_civicrm_buildAsset(). + */ +function afform_civicrm_buildAsset($asset, $params, &$mimeType, &$content) { + if ($asset !== 'afform.js') { + return; + } + + if (empty($params['name'])) { + throw new RuntimeException("Missing required parameter: afform.js?name=NAME"); + } + + $name = $params['name']; + $meta = civicrm_api3('Afform', 'getsingle', ['name' => $name]); + $scanner = new CRM_Afform_AfformScanner(); + + $smarty = CRM_Core_Smarty::singleton(); + $smarty->assign('afform', [ + 'camel' => _afform_angular_module_name($name), + 'meta' => $meta, + 'layout' => file_get_contents($scanner->findFilePath($name, 'layout.html')) + ]); + $mimeType = 'text/javascript'; + $content = $smarty->fetch('afform/FormAsDirective.tpl'); +} + +/** + * @param $name + * @return string + */ +function _afform_angular_module_name($name) { + return 'afform' . strtoupper($name{0}) . substr($name, 1); +} + /** * Implements hook_civicrm_preProcess(). * diff --git a/ext/afform/templates/afform/FormAsDirective.tpl b/ext/afform/templates/afform/FormAsDirective.tpl new file mode 100644 index 0000000000..75eb2a15ba --- /dev/null +++ b/ext/afform/templates/afform/FormAsDirective.tpl @@ -0,0 +1,26 @@ +{* This takes an $afform and generates an AngularJS directive. + + @param string $afform.camel The full camel-case name of the AngularJS module being created + @param string $afform.meta The full metadata record of the form + @param string $afform.layout The template content + *} +{literal} +(function(angular, $, _) { + angular.module('{/literal}{$afform.camel}{literal}', CRM.angRequires('{/literal}{$afform.camel}{literal}')); + angular.module('{/literal}{$afform.camel}{literal}').directive('{/literal}{$afform.camel}{literal}', function() { + return { + restrict: 'AE', + template: {/literal}{$afform.layout|json}{literal}, + scope: { + {/literal}{$afform.camel}{literal}: '=' + }, + link: function($scope, $el, $attr) { + var ts = $scope.ts = CRM.ts('{/literal}{$afform.camel}{literal}'); + $scope.$watch('{/literal}{$afform.camel}{literal}', function(newValue){ + $scope.myOptions = newValue; + }); + } + }; + }); +})(angular, CRM.$, CRM._); +{/literal} \ No newline at end of file -- 2.25.1