CRM-16019 - Datepicker unit tests and fixes
authorColeman Watts <coleman@civicrm.org>
Wed, 4 Mar 2015 03:04:29 +0000 (22:04 -0500)
committerColeman Watts <coleman@civicrm.org>
Thu, 5 Mar 2015 19:36:43 +0000 (14:36 -0500)
js/Common.js
js/angular-crm-ui.js
js/angular-crmMailing/directives.js
tests/karma/unit/crmMailingRadioDateSpec.js

index b9f26de384fd400506276b8c9a1a2144ad5acb09..5a8e0cb9babaa94a16b2db247c4c57b493e5c1a6 100644 (file)
@@ -611,19 +611,22 @@ CRM.strings = CRM.strings || {};
         $dateField.datepicker(settings).change(updateDataField);
       }
       function updateInputFields(e, context) {
+        var val = $dataField.val(),
+          time = null;
         if (context !== 'userInput' && context !== 'crmClear') {
-          if ($(this).val()) {
-            if ($dateField.length) {
-              $dateField.datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', $(this).val()));
-            }
-            if ($timeField.length) {
-              $timeField.timeEntry('setTime', ($dateField.length ? $(this).val().split(' ')[1] : $(this).val()) || null);
+          if ($dateField.length) {
+            $dateField.datepicker('setDate', _.includes(val, '-') ? $.datepicker.parseDate('yy-mm-dd', val) : null);
+          }
+          if ($timeField.length) {
+            if (val.length === 8) {
+              time = val;
+            } else if (val.length === 19) {
+              time = val.split(' ')[1];
             }
-          } else {
-            $dateField.add($timeField).val('');
+            $timeField.timeEntry('setTime', time);
           }
         }
-        $clearLink.css('visibility', $(this).val() ? 'visible' : 'hidden');
+        $clearLink.css('visibility', val ? 'visible' : 'hidden');
       }
       function updateDataField(e, context) {
         if (context !== 'crmClear') {
@@ -632,7 +635,7 @@ CRM.strings = CRM.strings || {};
             val = $.datepicker.formatDate('yy-mm-dd', $dateField.datepicker('getDate'));
           }
           if ($timeField.val()) {
-            val += (val ? ' ' : '') + $timeField.timeEntry('getTime').toTimeString().substr(0, 5);
+            val += (val ? ' ' : '') + $timeField.timeEntry('getTime').toTimeString().substr(0, 8);
           }
           $dataField.val(val).trigger('change', ['userInput']);
         }
index 48c688955d025d1284055eb54b8c86f82b624adb..b810b39fce1dc43e95e63a6306b3a588f3a03f03 100644 (file)
           crmUiDatepicker: '='
         },
         link: function (scope, element, attrs, ngModel) {
+          ngModel.$render = function () {
+            element.val(ngModel.$viewValue).change();
+          };
+
           element
             .crmDatepicker(scope.crmUiDatepicker)
             .on('change', function() {
-              var requiredLength = 16;
+              var requiredLength = 19;
               if (scope.crmUiDatepicker && scope.crmUiDatepicker.time === false) {
                 requiredLength = 10;
               }
               if (scope.crmUiDatepicker && scope.crmUiDatepicker.date === false) {
-                requiredLength = 5;
+                requiredLength = 8;
               }
               ngModel.$setValidity('incompleteDateTime', !($(this).val().length && $(this).val().length !== requiredLength));
             });
index a175bf6c86f29f827f4b29f0cbbc0c1dda0870a7..a9977a6a9fd547ec8693a5d68f6a68975554d91c 100644 (file)
         };
 
         ngModel.$render = function $render() {
-          validate();
+          var sched = ngModel.$viewValue;
+          if (!_.isEmpty(sched)) {
+            schedule.mode = 'at';
+            schedule.datetime = sched;
+          }
+          else {
+            schedule.mode = 'now';
+            schedule.datetime = '';
+          }
         };
-        // Update time value based on radio selection
+
         var updateParent = (function () {
           switch (schedule.mode) {
             case 'now':
               schedule.datetime = '';
               break;
             case 'at':
+              schedule.datetime = schedule.datetime || '?';
               ngModel.$setViewValue(schedule.datetime);
               break;
             default:
               throw 'Unrecognized schedule mode: ' + schedule.mode;
           }
-          validate();
-          // Angular model changes don't seem to trigger the "change" event.
-          // Redundantly setting the value here to ensure it happens before the event and not after
-          $('.crm-hidden-date', element).val(schedule.datetime).trigger('change');
         });
 
-        function validate() {
-          switch (schedule.mode) {
-            case 'now':
-              ngModel.$setValidity('empty', true);
-              break;
-            case 'at':
-              ngModel.$setValidity('empty', !_.isEmpty(schedule.datetime));
-              break;
-            default:
-              throw 'Unrecognized schedule mode: ' + schedule.mode;
-          }
-        }
+        element.on('click', ':radio[value=at]', function() {
+          $('.crm-form-date', element).focus();
+        });
 
         $scope.$watch(attrs.crmMailingRadioDate + '.mode', updateParent);
-
-        // Watch changes in the date element, but only those initiated by the user
-        // (model-based changes to this field should not force-update other parts of the model)
-        $(element).on('change', '.crm-hidden-date', function(e, context) {
-          if (context === 'userInput' || context === 'crmClear') {
-            schedule.mode = $(this).val() ? 'at' : 'now';
-            updateParent();
+        $scope.$watch(attrs.crmMailingRadioDate + '.datetime', function (newValue, oldValue) {
+          // automatically switch mode based on datetime entry
+          if (typeof oldValue === 'undefined') oldValue = '';
+          if (typeof newValue === 'undefined') newValue = '';
+          if (oldValue !== newValue) {
+            if (_.isEmpty(newValue)) {
+              schedule.mode = 'now';
+            }
+            else {
+              schedule.mode = 'at';
+            }
           }
+          updateParent();
         });
       }
     };
index 196b1152ca3d626a6addbbedd0df9565bd6fda12..a90a820f6bb27d22780afef38aa5e9a68524511a 100644 (file)
@@ -1,5 +1,5 @@
 'use strict';
-/* global CRM:true */
+/* global $, CRM:true */
 
 describe('crmMailingRadioDate', function() {
 
@@ -61,15 +61,16 @@ describe('crmMailingRadioDate', function() {
       expect(element.find('.crm-form-date').datepicker('getDate')).toBe(null);
       expect(element.find('.crm-form-time').timeEntry('getTime')).toBe(null);
 
-      model.the_date = '2014-01-01 ';
+      model.the_date = '2014-01-01';
       $rootScope.$digest();
       expect($rootScope.myForm.$valid).toBe(false);
       expect(element.find('.radio-now').prop('checked')).toBe(false);
       expect(element.find('.radio-at').prop('checked')).toBe(true);
-      expect(element.find('.crm-form-date').datepicker('getDate').toDateString()).toEqual('Wed Jan 01 2014');
+      expect(element.find('.crm-hidden-date').val()).toEqual('2014-01-01');
+      expect(element.find('.crm-form-date').val()).toEqual('01/01/2014');
       expect(element.find('.crm-form-time').timeEntry('getTime')).toBe(null);
 
-      model.the_date = '02:03:04';
+      model.the_date = '02:03:00';
       $rootScope.$digest();
       expect($rootScope.myForm.$valid).toBe(false);
       expect(element.find('.radio-now').prop('checked')).toBe(false);
@@ -77,7 +78,7 @@ describe('crmMailingRadioDate', function() {
       expect(element.find('.crm-form-date').datepicker('getDate')).toBe(null);
       expect(element.find('.crm-form-time').timeEntry('getTime').getMinutes()).toBe(3);
 
-      model.the_date = '2014-01-02 02:03:04';
+      model.the_date = '2014-01-02 02:03:00';
       $rootScope.$digest();
       expect($rootScope.myForm.$valid).toBe(true);
       expect(element.find('.radio-now').prop('checked')).toBe(false);
@@ -88,13 +89,15 @@ describe('crmMailingRadioDate', function() {
 
     it('should update the model after changing the date and time', function() {
       element = $compile(standardMarkup)($rootScope);
+
       model.the_date = '';
       $rootScope.$digest();
       expect($rootScope.myForm.$valid).toBe(true);
       expect(element.find('.radio-now').prop('checked')).toBe(true);
       expect(element.find('.radio-at').prop('checked')).toBe(false);
 
-      element.find('.crm-form-date').datepicker('setDate', '2014-01-03').trigger('change');
+      element.find('.radio-now').click().trigger('click').trigger('change');
+      element.find('.crm-form-date').datepicker('setDate', $.datepicker.parseDate('yy-mm-dd', '2014-01-03')).trigger('change');
       $rootScope.$digest();
       expect(model.the_date).toBe('2014-01-03');
       expect($rootScope.myForm.$valid).toBe(false);
@@ -103,14 +106,14 @@ describe('crmMailingRadioDate', function() {
 
       element.find('.crm-form-time').timeEntry('setTime', '04:05').trigger('change');
       $rootScope.$digest();
-      expect(model.the_date).toBe('2014-01-03 04:05');
+      expect(model.the_date).toBe('2014-01-03 04:05:00');
       expect($rootScope.myForm.$valid).toBe(true);
       expect(element.find('.radio-now').prop('checked')).toBe(false);
       expect(element.find('.radio-at').prop('checked')).toBe(true);
 
       element.find('.crm-form-date').datepicker('setDate', '').trigger('change');
       $rootScope.$digest();
-      expect(model.the_date).toBe('04:05');
+      expect(model.the_date).toBe('04:05:00');
       expect($rootScope.myForm.$valid).toBe(false);
       expect(element.find('.radio-now').prop('checked')).toBe(false);
       expect(element.find('.radio-at').prop('checked')).toBe(true);