CRM-15706 - Use scope.help() instead of scope.crmUiHelpFile
authorTim Otten <totten@civicrm.org>
Wed, 18 Mar 2015 00:18:08 +0000 (17:18 -0700)
committerColeman Watts <coleman@civicrm.org>
Thu, 19 Mar 2015 15:39:48 +0000 (11:39 -0400)
The old code relied explicitly passing ```help-id``` string and implicitly
passing a ```crmUiHelpFile``` string through various layers.  This broke
down when trying to implicitly pass crmUiHelpFile through isolate-scopes.

By contrast, this patch relies on explicitly passing a help object. The help
object is complete (i.e.  it has both id and file), so it's easier to pass
through various layers.

js/angular-crm-ui.js
js/angular-crmMailing/directives.js
js/angular-crmMailingAB/directives.js
partials/crmMailing/headerFooter.html
partials/crmMailing/mailing.html
partials/crmMailing/summary.html
partials/crmMailingAB/joint-mailing.html
partials/crmMailingAB/setup.html
partials/crmUi/field.html

index e59e7427c3b3f973a76c1eb1d5822cf9e11784ea..2b6b1abaae4f9e064dba9298617528ba159dbf21 100644 (file)
     // example: <div crm-ui-field="{title: ts('My Field')}"> {{mydata}} </div>
     // example: <div crm-ui-field="{name: 'subform.myfield', title: ts('My Field')}"> <input crm-ui-id="subform.myfield" name="myfield" /> </div>
     // example: <div crm-ui-field="{name: 'subform.myfield', title: ts('My Field')}"> <input crm-ui-id="subform.myfield" name="myfield" required /> </div>
-    // example: <div crm-ui-field="{name: 'subform.myfield', title: ts('My Field'), help: 'help_field_name'}"> {{mydata}} </div>
+    // example: <div crm-ui-field="{name: 'subform.myfield', title: ts('My Field'), help: help('help_field_name')}"> {{mydata}} </div>
     .directive('crmUiField', function() {
       // Note: When writing new templates, the "label" position is particular. See/patch "var label" below.
       var templateUrls = {
         transclude: true,
         link: function (scope, element, attrs, crmUiIdCtrl) {
           $(element).addClass('crm-section');
-          // Inherit helpFile from parent scope if not specified
-          scope.crmUiHelpFile = scope.crmUiField.helpFile || scope.$parent.crmUiHelpFile;
+          scope.$watch('crmUiField', function(crmUiField) {
+            if (crmUiField && crmUiField.help) {
+              scope.help = crmUiField.help.clone({}, {
+                title: crmUiField.title
+              });
+            }
+          });
         }
       };
     })
       };
     })
 
-    // Display a help icon which loads help from a *.hlp file.
+    // for example, see crmUiHelp
+    .service('crmUiHelp', function(){
+      // example: var h = new FieldHelp({id: 'foo'}); h.open();
+      function FieldHelp(options) {
+        this.options = options;
+      }
+      angular.extend(FieldHelp.prototype, {
+        get: function(n) {
+          return this.options[n];
+        },
+        open: function open() {
+          console.log('open', this.options.title, this.options.id, this.options.file);
+          CRM.help(this.options.title, {id: this.options.id, file: this.options.file});
+        },
+        clone: function clone(options, defaults) {
+          options = options || {};
+          defaults = defaults || {};
+          console.log('clone', defaults, this.options, options);
+          return new FieldHelp(angular.extend({}, defaults, this.options, options));
+        }
+      });
+
+      // example: var help = crmUiHelp({file: 'CRM/Foo/Bar'});
+      return function(defaults){
+        // example: help('myfield')
+        // example: help({id: 'myfield', title: 'Foo Bar', file: 'Whiz/Bang'})
+        return function(options) {
+          if (_.isString(options)) {
+            options = {id: options};
+          }
+          return new FieldHelp(angular.extend({}, defaults, options));
+        }
+      }
+    })
+
+    // Display a help icon
     // Example: Use a default *.hlp file
-    //   JS: scope.crmUiHelpFile='CRM/Foo/Bar';
-    //   HTML: <a crm-ui-help="{title:ts('My Field'), id:'my_field'}">
+    //   scope.help = crmUiHelp({file: 'Path/To/Help/File'});
+    //   HTML: <a crm-ui-help="help({title:ts('My Field'), id:'my_field'})">
     // Example: Use an explicit *.hlp file
-    //   HTML: <a crm-ui-help="{title:ts('My Field'), id:'my_field', file:'CRM/Foo/Bar'}">
+    //   HTML: <a crm-ui-help="help({title:ts('My Field'), id:'my_field', file:'CRM/Foo/Bar'})">
     .directive('crmUiHelp', function() {
       return {
         restrict: 'EA',
-        scope: {
-          crmUiHelp: '='
-        },
         link: function (scope, element, attrs) {
+          var crmUiHelp = null;
+
+          scope.$watch(attrs.crmUiHelp, function(newCrmUiHelp){
+            crmUiHelp = newCrmUiHelp;
+            var title = crmUiHelp && crmUiHelp.get('title') ? ts('%1 Help', {1: crmUiHelp.get('title')}) : ts('Help');
+            element.attr('title', title);
+          });
+
           element
             .addClass('helpicon')
-            .attr('title', ts('%1 Help', {1: scope.crmUiHelp.title}))
             .attr('href', '#')
             .on('click', function(e) {
               e.preventDefault();
-              CRM.help(scope.crmUiHelp.title, {id: scope.crmUiHelp.id, file: scope.crmUiHelp.file || scope.$parent.crmUiHelpFile});
+              crmUiHelp.open();
             });
         }
       };
index 80a022a32703d29ac22452b12efcce36cda4d0fa..16ddb84ee6f21494100032f967d3881e322429e1 100644 (file)
@@ -16,7 +16,7 @@
     crmMailingBodyText: '~/crmMailing/body_text.html'
   };
   _.each(simpleBlocks, function(templateUrl, directiveName){
-    angular.module('crmMailing').directive(directiveName, function ($q, crmMetadata) {
+    angular.module('crmMailing').directive(directiveName, function ($q, crmMetadata, crmUiHelp) {
       return {
         scope: {
           crmMailing: '@'
@@ -28,7 +28,7 @@
           });
           scope.crmMailingConst = CRM.crmMailing;
           scope.ts = CRM.ts(null);
-          scope.crmUiHelpFile = 'CRM/Mailing/MailingUI';
+          scope.help = crmUiHelp({file: 'CRM/Mailing/MailingUI'});
           scope[directiveName] = attr[directiveName] ? scope.$parent.$eval(attr[directiveName]) : {};
           $q.when(crmMetadata.getFields('Mailing'), function(fields) {
             scope.mailingFields = fields;
index 7cf79d731311a0dbdb8b307b3479787b983d0ece..d46c3885aa9a7caadc15b70e46bba3cb4c7474ad 100644 (file)
@@ -8,7 +8,7 @@
     crmMailingAbBlockSetup: '~/crmMailingAB/setup.html'
   };
   _.each(simpleDirectives, function (templateUrl, directiveName) {
-    angular.module('crmMailingAB').directive(directiveName, function ($parse, crmMailingABCriteria) {
+    angular.module('crmMailingAB').directive(directiveName, function ($parse, crmMailingABCriteria, crmUiHelp) {
       var scopeDesc = {crmAbtest: '@'};
       scopeDesc[directiveName] = '@';
 
@@ -21,7 +21,7 @@
           scope.crmMailingConst = CRM.crmMailing;
           scope.crmMailingABCriteria = crmMailingABCriteria;
           scope.ts = CRM.ts(null);
-          scope.crmUiHelpFile = 'CRM/Mailing/MailingUI';
+          scope.help = crmUiHelp({file: 'CRM/Mailing/MailingUI'});
 
           var fieldsModel = $parse(attr[directiveName]);
           scope.fields = fieldsModel(scope.$parent);
index 2e611c5a6c34968ee44f1ff79f81152ee908a045..c6df982a64191d44172718f50bffe8dca3748cb1 100644 (file)
@@ -4,7 +4,7 @@ Required vars: mailing, crmMailingConst
 -->
 <div class="crm-block"  ng-form="subform" crm-ui-id-scope>
   <div class="crm-group" ng-controller="EmailBodyCtrl">
-    <div crm-ui-field="{name: 'subform.header_id', title: ts('Mailing Header'), help: 'header'}">
+    <div crm-ui-field="{name: 'subform.header_id', title: ts('Mailing Header'), help: help('header')}">
       <select
         crm-ui-id="subform.header_id"
         name="header_id"
@@ -16,7 +16,7 @@ Required vars: mailing, crmMailingConst
         <option value=""></option>
       </select>
     </div>
-    <div crm-ui-field="{name: 'subform.footer_id', title: ts('Mailing Footer'), help: 'footer'}">
+    <div crm-ui-field="{name: 'subform.footer_id', title: ts('Mailing Footer'), help: help('footer')}">
       <select
         crm-ui-id="subform.footer_id"
         name="footer_id"
index f9393d9a3aa776c05b498635465cc1c3b6312fa4..10655f3eb4afc9065db6697bbdb527f94b07a399 100644 (file)
@@ -21,7 +21,7 @@ It could perhaps be thinned by 30-60% by making more directives.
         <a crm-icon="disk" ng-click="saveTemplate(mailing)" class="crm-hover-button" title="{{ts('Save As')}}"></a>
       </div>
     </div>
-    <div crm-ui-field="{name: 'subform.fromAddress', title: ts('From'), help: 'from_email'}">
+    <div crm-ui-field="{name: 'subform.fromAddress', title: ts('From'), help: help('from_email')}">
       <div ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="mailing">
         <select
           crm-ui-id="subform.fromAddress"
index ac96c69c28265adad64717d54f577d8ce9926ed6..5fcfa0eca8a4ea43a64987117facc564a78286f0 100644 (file)
@@ -5,7 +5,7 @@ FIXME: Don't hardcode table-based layout!
 -->
 <div class="crm-block" ng-form="subform" crm-ui-id-scope>
   <div class="crm-group">
-    <div crm-ui-field="{name: 'subform.mailingName', title: ts('Mailing Name'), help: 'name'}">
+    <div crm-ui-field="{name: 'subform.mailingName', title: ts('Mailing Name'), help: help('name')}">
       <div>
         <input
           crm-ui-id="subform.mailingName"
@@ -17,7 +17,7 @@ FIXME: Don't hardcode table-based layout!
           name="mailingName" />
       </div>
     </div>
-    <div crm-ui-field="{name: 'subform.campaign', title: ts('Campaign'), help: 'id-campaign_id', helpFile: 'CRM/Campaign/Form/addCampaignToComponent'}" ng-show="crmMailingConst.campNames.length > 0">
+    <div crm-ui-field="{name: 'subform.campaign', title: ts('Campaign'), help: help({id: 'id-campaign_id', file: 'CRM/Campaign/Form/addCampaignToComponent'})}" ng-show="crmMailingConst.campNames.length > 0">
       <select
         crm-ui-id="subform.campaign"
         name="campaign"
index 3786a13b8d621d6e5ffbd7310eeb846384199bc9..d328376ab9f115cb04f8093a86f4d7e780d48265 100644 (file)
@@ -62,7 +62,7 @@ processed by Angular; if false, the field will be hidden and completely ignored
     </div>
 
 
-    <div crm-ui-field="{name: 'subform.fromAddress', title: ts('From'), help: 'from_email'}" ng-if="fields.fromAddress">
+    <div crm-ui-field="{name: 'subform.fromAddress', title: ts('From'), help: help('from_email')}" ng-if="fields.fromAddress">
       <span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="abtest.mailings.a">
         <select
           crm-ui-id="subform.fromAddress"
@@ -75,7 +75,7 @@ processed by Angular; if false, the field will be hidden and completely ignored
         </select>
       </span>
     </div>
-    <div crm-ui-field="{name: 'subform.fromAddressA', title: ts('From (A)'), help: 'from_email'}" ng-if="fields.fromAddressA">
+    <div crm-ui-field="{name: 'subform.fromAddressA', title: ts('From (A)'), help: help('from_email')}" ng-if="fields.fromAddressA">
       <span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="abtest.mailings.a">
         <select
           crm-ui-id="subform.fromAddressA"
@@ -88,7 +88,7 @@ processed by Angular; if false, the field will be hidden and completely ignored
         </select>
       </span>
     </div>
-    <div crm-ui-field="{name: 'subform.fromAddressB', title: ts('From (B)'), help: 'from_email'}" ng-if="fields.fromAddressB">
+    <div crm-ui-field="{name: 'subform.fromAddressB', title: ts('From (B)'), help: help('from_email')}" ng-if="fields.fromAddressB">
       <span ng-controller="EmailAddrCtrl" crm-mailing-from-address="fromPlaceholder" crm-mailing="abtest.mailings.b">
         <select
           crm-ui-id="subform.fromAddressB"
index 80f76a2983ded700c23cbd34897379e363ab6b17..7058a2854a508f838d12c914df216fc10044b473 100644 (file)
@@ -4,7 +4,7 @@
       {{ts('A/B testing allows you to send two test mailings to a random subset of your recipients. After collecting and
       comparing metrics, the more successful mailing will be sent to the remaining recipients.')}}
     </div>
-    <div crm-ui-field="{name: 'setupForm.abName', title: ts('Name'), help: 'name'}" ng-if="fields.abName">
+    <div crm-ui-field="{name: 'setupForm.abName', title: ts('Name'), help: help('name')}" ng-if="fields.abName">
       <input
         crm-ui-id="setupForm.abName"
         name="abName"
@@ -13,7 +13,7 @@
         placeholder="A/B Test Name"
         required/>
     </div>
-    <div crm-ui-field="{name: 'setupForm.campaign', title: ts('Campaign'), help: 'id-campaign_id', helpFile: 'CRM/Campaign/Form/addCampaignToComponent'}" ng-show="crmMailingConst.campNames.length > 0"
+    <div crm-ui-field="{name: 'setupForm.campaign', title: ts('Campaign'), help: help({id: 'id-campaign_id', file: 'CRM/Campaign/Form/addCampaignToComponent'})}" ng-show="crmMailingConst.campNames.length > 0"
          ng-if="fields.campaign">
       <select
         crm-ui-id="setupForm.campaign"
index 20a5216b25ac6b54732721355738bc3808ad0dca..cf160bc60a242506c2132119b9a13d6ef56b8b46 100644 (file)
@@ -1,6 +1,6 @@
 <div class="label">
   <label crm-ui-for="{{crmUiField.name}}" crm-depth="1">{{crmUiField.title}}</label>
-  <a crm-ui-help="{title: crmUiField.title, id: crmUiField.help}" ng-if="crmUiField.help"></a>
+  <a crm-ui-help="help" ng-if="crmUiField.help"></a>
 </div>
 <div class="content" ng-transclude></div>
 <div class="clear"></div>