From a42344f478b913fe4359b64b93993dea8737dd87 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 3 Mar 2015 14:38:57 -0500 Subject: [PATCH] CRM-16019 - Migrate Angular pages to use new crmDatepicker widget --- js/angular-crm-ui.js | 127 +++----------------- js/angular-crmMailing/directives.js | 34 ++---- partials/crmExample/example.html | 5 +- partials/crmMailing/schedule.html | 2 +- partials/crmMailingAB/selectWinner.html | 2 +- partials/crmMailingAB/setup.html | 4 +- partials/crmUi/datetime.html | 19 --- tests/karma/unit/crmMailingRadioDateSpec.js | 41 ++++--- 8 files changed, 58 insertions(+), 176 deletions(-) delete mode 100644 partials/crmUi/datetime.html diff --git a/js/angular-crm-ui.js b/js/angular-crm-ui.js index 34450648bf..48c688955d 100644 --- a/js/angular-crm-ui.js +++ b/js/angular-crm-ui.js @@ -54,98 +54,29 @@ }; }) - // Display a date widget. - // example: - // example: - .directive('crmUiDate', function ($parse, $timeout) { + // Simple wrapper around $.crmDatepicker. + // example with no time input: + // example with custom date format: + .directive('crmUiDatepicker', function () { return { restrict: 'AE', require: 'ngModel', scope: { - crmUiDateFormat: '@' // expression, date format (default: "yy-mm-dd") + crmUiDatepicker: '=' }, link: function (scope, element, attrs, ngModel) { - var fmt = attrs.crmUiDateFormat ? $parse(attrs.crmUiDateFormat)() : "yy-mm-dd"; - - element.addClass('dateplugin'); - $(element).datepicker({ - dateFormat: fmt - }); - - ngModel.$render = function $render() { - $(element).datepicker('setDate', ngModel.$viewValue); - }; - var updateParent = (function() { - $timeout(function () { - ngModel.$setViewValue(element.val()); + element + .crmDatepicker(scope.crmUiDatepicker) + .on('change', function() { + var requiredLength = 16; + if (scope.crmUiDatepicker && scope.crmUiDatepicker.time === false) { + requiredLength = 10; + } + if (scope.crmUiDatepicker && scope.crmUiDatepicker.date === false) { + requiredLength = 5; + } + ngModel.$setValidity('incompleteDateTime', !($(this).val().length && $(this).val().length !== requiredLength)); }); - }); - - element.on('change', updateParent); - } - }; - }) - - // Display a date-time widget. - // example:
- .directive('crmUiDateTime', function ($parse) { - return { - restrict: 'AE', - require: 'ngModel', - scope: { - ngRequired: '@' - }, - templateUrl: '~/crmUi/datetime.html', - link: function (scope, element, attrs, ngModel) { - var ts = scope.ts = CRM.ts(null); - scope.dateLabel = ts('Date'); - scope.timeLabel = ts('Time'); - element.addClass('crm-ui-datetime'); - - ngModel.$render = function $render() { - if (!_.isEmpty(ngModel.$viewValue)) { - var dtparts = ngModel.$viewValue.split(/ /); - scope.dtparts = {date: dtparts[0], time: dtparts[1]}; - } - else { - scope.dtparts = {date: '', time: ''}; - } - validate(); - }; - - function updateParent() { - validate(); - - if (_.isEmpty(scope.dtparts.date) && _.isEmpty(scope.dtparts.time)) { - ngModel.$setViewValue(' '); - } - else { - //ngModel.$setViewValue(scope.dtparts.date + ' ' + scope.dtparts.time); - ngModel.$setViewValue((scope.dtparts.date ? scope.dtparts.date : '') + ' ' + (scope.dtparts.time ? scope.dtparts.time : '')); - } - } - - scope.$watch('dtparts.date', updateParent); - scope.$watch('dtparts.time', updateParent); - - function validate() { - var incompleteDateTime = _.isEmpty(scope.dtparts.date) ^ _.isEmpty(scope.dtparts.time); - ngModel.$setValidity('incompleteDateTime', !incompleteDateTime); - } - - function updateRequired() { - scope.required = scope.$parent.$eval(attrs.ngRequired); - } - - if (attrs.ngRequired) { - updateRequired(); - scope.$parent.$watch(attrs.ngRequired, updateRequired); - } - - scope.reset = function reset() { - scope.dtparts = {date: '', time: ''}; - ngModel.$setViewValue(''); - }; } }; }) @@ -638,32 +569,6 @@ }; }) - // Display a time-entry field. - // example: - .directive('crmUiTime', function ($parse, $timeout) { - return { - restrict: 'AE', - require: 'ngModel', - scope: { - }, - link: function (scope, element, attrs, ngModel) { - element.addClass('crm-form-text six'); - element.timeEntry({show24Hours: true}); - - ngModel.$render = function $render() { - element.timeEntry('setTime', ngModel.$viewValue); - }; - - var updateParent = (function () { - $timeout(function () { - ngModel.$setViewValue(element.val()); - }); - }); - element.on('change', updateParent); - } - }; - }) - // Generic, field-independent form validator. // example: // example: diff --git a/js/angular-crmMailing/directives.js b/js/angular-crmMailing/directives.js index 7ae1cad7e4..a175bf6c86 100644 --- a/js/angular-crmMailing/directives.js +++ b/js/angular-crmMailing/directives.js @@ -122,22 +122,14 @@ }; ngModel.$render = function $render() { - var sched = ngModel.$viewValue; - if (!_.isEmpty(sched)) { - schedule.mode = 'at'; - schedule.datetime = sched; - } - else { - schedule.mode = 'now'; - } validate(); }; - + // Update time value based on radio selection var updateParent = (function () { switch (schedule.mode) { case 'now': ngModel.$setViewValue(null); - schedule.datetime = ' '; + schedule.datetime = ''; break; case 'at': ngModel.$setViewValue(schedule.datetime); @@ -146,6 +138,9 @@ 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() { @@ -154,7 +149,7 @@ ngModel.$setValidity('empty', true); break; case 'at': - ngModel.$setValidity('empty', !_.isEmpty(schedule.datetime) && schedule.datetime !== ' '); + ngModel.$setValidity('empty', !_.isEmpty(schedule.datetime)); break; default: throw 'Unrecognized schedule mode: ' + schedule.mode; @@ -162,17 +157,14 @@ } $scope.$watch(attrs.crmMailingRadioDate + '.mode', updateParent); - $scope.$watch(attrs.crmMailingRadioDate + '.datetime', function (newValue, oldValue) { - // automatically switch mode based on datetime entry - if (oldValue != newValue) { - if (_.isEmpty(newValue) || newValue == " ") { - schedule.mode = 'now'; - } - else { - schedule.mode = 'at'; - } + + // 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(); } - updateParent(); }); } }; diff --git a/partials/crmExample/example.html b/partials/crmExample/example.html index f19fca560f..c9b6abd03f 100644 --- a/partials/crmExample/example.html +++ b/partials/crmExample/example.html @@ -15,9 +15,6 @@ {{exName}} {{example.value}} - - -
@@ -29,7 +26,7 @@
- +
diff --git a/partials/crmMailing/schedule.html b/partials/crmMailing/schedule.html index 4dcdc66457..75cf19b2cb 100644 --- a/partials/crmMailing/schedule.html +++ b/partials/crmMailing/schedule.html @@ -7,7 +7,7 @@
- +
diff --git a/partials/crmMailingAB/selectWinner.html b/partials/crmMailingAB/selectWinner.html index 67a8a316eb..3e1f31e737 100644 --- a/partials/crmMailingAB/selectWinner.html +++ b/partials/crmMailingAB/selectWinner.html @@ -12,7 +12,7 @@
- +
diff --git a/partials/crmMailingAB/setup.html b/partials/crmMailingAB/setup.html index 2b15e66ca5..7167566373 100644 --- a/partials/crmMailingAB/setup.html +++ b/partials/crmMailingAB/setup.html @@ -50,7 +50,7 @@
- +
@@ -63,7 +63,7 @@
- +
diff --git a/partials/crmUi/datetime.html b/partials/crmUi/datetime.html deleted file mode 100644 index 1533bb5bcb..0000000000 --- a/partials/crmUi/datetime.html +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/tests/karma/unit/crmMailingRadioDateSpec.js b/tests/karma/unit/crmMailingRadioDateSpec.js index e9dc448e0c..196b1152ca 100644 --- a/tests/karma/unit/crmMailingRadioDateSpec.js +++ b/tests/karma/unit/crmMailingRadioDateSpec.js @@ -1,4 +1,5 @@ 'use strict'; +/* global CRM:true */ describe('crmMailingRadioDate', function() { @@ -12,7 +13,7 @@ describe('crmMailingRadioDate', function() { '
' + ' ' + ' ' + - ' ' + + ' ' + '
' + ''; @@ -30,6 +31,12 @@ describe('crmMailingRadioDate', function() { $interval = _$interval_; $timeout = _$timeout_; + // Global settings needed for crmUiDatepicker + CRM = CRM || {}; + CRM.config = CRM.config || {}; + CRM.config.dateInputFormat = 'mm/dd/yy'; + CRM.config.timeIs24Hr = true; + $rootScope.model = model = { the_date: '' }; @@ -43,40 +50,40 @@ describe('crmMailingRadioDate', function() { expect($rootScope.myForm.$valid).toBe(true); expect(element.find('.radio-now').prop('checked')).toBe(true); expect(element.find('.radio-at').prop('checked')).toBe(false); - expect(element.find('.dateplugin').datepicker('getDate')).toBe(null); - expect(element.find('.hasTimeEntry').timeEntry('getTime')).toBe(null); + expect(element.find('.crm-form-date').datepicker('getDate')).toBe(null); + expect(element.find('.crm-form-time').timeEntry('getTime')).toBe(null); model.the_date = ' '; $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('.dateplugin').datepicker('getDate')).toBe(null); - expect(element.find('.hasTimeEntry').timeEntry('getTime')).toBe(null); + 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 '; $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('.dateplugin').datepicker('getDate').toDateString()).toEqual('Wed Jan 01 2014'); - expect(element.find('.hasTimeEntry').timeEntry('getTime')).toBe(null); + expect(element.find('.crm-form-date').datepicker('getDate').toDateString()).toEqual('Wed Jan 01 2014'); + expect(element.find('.crm-form-time').timeEntry('getTime')).toBe(null); - model.the_date = ' 02:03:04'; + model.the_date = '02:03:04'; $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('.dateplugin').datepicker('getDate')).toBe(null); - expect(element.find('.hasTimeEntry').timeEntry('getTime').getMinutes()).toBe(3); + 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'; $rootScope.$digest(); expect($rootScope.myForm.$valid).toBe(true); expect(element.find('.radio-now').prop('checked')).toBe(false); expect(element.find('.radio-at').prop('checked')).toBe(true); - expect(element.find('.dateplugin').datepicker('getDate').toDateString()).toEqual('Thu Jan 02 2014'); - expect(element.find('.hasTimeEntry').timeEntry('getTime').getMinutes()).toBe(3); + expect(element.find('.crm-form-date').datepicker('getDate').toDateString()).toEqual('Thu Jan 02 2014'); + expect(element.find('.crm-form-time').timeEntry('getTime').getMinutes()).toBe(3); }); it('should update the model after changing the date and time', function() { @@ -87,23 +94,23 @@ describe('crmMailingRadioDate', function() { expect(element.find('.radio-now').prop('checked')).toBe(true); expect(element.find('.radio-at').prop('checked')).toBe(false); - element.find('.dateplugin').datepicker('setDate', '2014-01-03').trigger('change'); + element.find('.crm-form-date').datepicker('setDate', '2014-01-03').trigger('change'); $rootScope.$digest(); - expect(model.the_date).toBe('2014-01-03 '); + expect(model.the_date).toBe('2014-01-03'); expect($rootScope.myForm.$valid).toBe(false); expect(element.find('.radio-now').prop('checked')).toBe(false); expect(element.find('.radio-at').prop('checked')).toBe(true); - element.find('.hasTimeEntry').timeEntry('setTime', '04:05').trigger('change'); + element.find('.crm-form-time').timeEntry('setTime', '04:05').trigger('change'); $rootScope.$digest(); expect(model.the_date).toBe('2014-01-03 04:05'); 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('.dateplugin').datepicker('setDate', '').trigger('change'); + 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'); expect($rootScope.myForm.$valid).toBe(false); expect(element.find('.radio-now').prop('checked')).toBe(false); expect(element.find('.radio-at').prop('checked')).toBe(true); -- 2.25.1