From: deb.monish Date: Tue, 7 Aug 2018 13:25:32 +0000 (+0530) Subject: Move datepicker widget to a separate file X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=403c52ac8ead2a4cb1171bb24559f01dc35f4860;p=civicrm-core.git Move datepicker widget to a separate file --- diff --git a/CRM/Core/Resources.php b/CRM/Core/Resources.php index 7be010ab6b..e24e36ff5c 100644 --- a/CRM/Core/Resources.php +++ b/CRM/Core/Resources.php @@ -725,6 +725,7 @@ class CRM_Core_Resources { "bower_components/datatables/media/css/jquery.dataTables.min.css", "bower_components/jquery-validation/dist/jquery.validate.min.js", "packages/jquery/plugins/jquery.ui.datepicker.validation.min.js", + "js/crm.datepicker.js", "js/Common.js", "js/crm.ajax.js", "js/wysiwyg/crm.wysiwyg.js", diff --git a/js/Common.js b/js/Common.js index 8a53067637..985e7d616c 100644 --- a/js/Common.js +++ b/js/Common.js @@ -646,153 +646,12 @@ if (!CRM.vars) CRM.vars = {}; return combined; } - function copyAttributes($source, $target, attributes) { + CRM.utils.copyAttributes = function ($source, $target, attributes) { _.each(attributes, function(name) { if ($source.attr(name) !== undefined) { $target.attr(name, $source.attr(name)); } }); - } - - /** - * @see http://wiki.civicrm.org/confluence/display/CRMDOC/crmDatepicker - */ - $.fn.crmDatepicker = function(options) { - return $(this).each(function() { - if ($(this).is('.crm-form-date-wrapper .crm-hidden-date')) { - // Already initialized - destroy - $(this) - .off('.crmDatepicker') - .css('display', '') - .removeClass('crm-hidden-date') - .siblings().remove(); - $(this).unwrap(); - } - if (options === 'destroy') { - return; - } - var - $dataField = $(this).wrap(''), - settings = _.cloneDeep(options || {}), - $dateField = $(), - $timeField = $(), - $clearLink = $(), - hasDatepicker = settings.date !== false && settings.date !== 'yy', - type = hasDatepicker ? 'text' : 'number'; - - if (settings.allowClear !== undefined ? settings.allowClear : !$dataField.is('.required, [required]')) { - $clearLink = $('') - .insertAfter($dataField); - } - if (settings.time !== false) { - $timeField = $('').insertAfter($dataField); - copyAttributes($dataField, $timeField, ['class', 'disabled']); - $timeField - .addClass('crm-form-text crm-form-time') - .attr('placeholder', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder')) - .attr('aria-label', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder')) - .change(updateDataField) - .timeEntry({ - spinnerImage: '', - show24Hours: settings.time === true || settings.time === undefined ? CRM.config.timeIs24Hr : settings.time == '24' - }); - } - if (settings.date !== false) { - // Render "number" field for year-only format, calendar popup for all other formats - $dateField = $('').insertAfter($dataField); - copyAttributes($dataField, $dateField, ['placeholder', 'style', 'class', 'disabled', 'aria-label']); - $dateField.addClass('crm-form-' + type); - if (hasDatepicker) { - settings.minDate = settings.minDate ? CRM.utils.makeDate(settings.minDate) : null; - settings.maxDate = settings.maxDate ? CRM.utils.makeDate(settings.maxDate) : null; - settings.dateFormat = typeof settings.date === 'string' ? settings.date : CRM.config.dateInputFormat; - settings.changeMonth = _.includes(settings.dateFormat, 'm'); - settings.changeYear = _.includes(settings.dateFormat, 'y'); - if (!settings.yearRange && settings.minDate !== null && settings.maxDate !== null) { - settings.yearRange = '' + CRM.utils.formatDate(settings.minDate, 'yy') + ':' + CRM.utils.formatDate(settings.maxDate, 'yy'); - } - $dateField.addClass('crm-form-date').datepicker(settings); - } else { - $dateField.attr('min', settings.minDate ? CRM.utils.formatDate(settings.minDate, 'yy') : '1000'); - $dateField.attr('max', settings.maxDate ? CRM.utils.formatDate(settings.maxDate, 'yy') : '4000'); - } - $dateField.change(updateDataField); - } - // Rudimentary validation. TODO: Roll into use of jQUery validate and ui.datepicker.validation - function isValidDate() { - // FIXME: parseDate doesn't work with incomplete date formats; skip validation if no month, day or year in format - var lowerFormat = settings.dateFormat.toLowerCase(); - if (lowerFormat.indexOf('y') < 0 || lowerFormat.indexOf('m') < 0 || !dateHasDay()) { - return true; - } - try { - $.datepicker.parseDate(settings.dateFormat, $dateField.val()); - return true; - } catch (e) { - return false; - } - } - - /** - * Does the date format contain the day. - * - * @returns {boolean} - */ - function dateHasDay() { - var lowerFormat = settings.dateFormat.toLowerCase(); - if (lowerFormat.indexOf('d') < 0) { - return false; - } - return true; - } - function updateInputFields(e, context) { - var val = $dataField.val(), - time = null; - if (context !== 'userInput' && context !== 'crmClear') { - if (hasDatepicker) { - $dateField.datepicker('setDate', _.includes(val, '-') ? $.datepicker.parseDate('yy-mm-dd', val) : null); - } else if ($dateField.length) { - $dateField.val(val.slice(0, 4)); - } - if ($timeField.length) { - if (val.length === 8) { - time = val; - } else if (val.length === 19) { - time = val.split(' ')[1]; - } - $timeField.timeEntry('setTime', time); - } - } - $clearLink.css('visibility', val ? 'visible' : 'hidden'); - } - function updateDataField(e, context) { - // The crmClear event wipes all the field values anyway, so no need to respond - if (context !== 'crmClear') { - var val = ''; - if ($dateField.val()) { - if (hasDatepicker && isValidDate() && dateHasDay()) { - val = $.datepicker.formatDate('yy-mm-dd', $dateField.datepicker('getDate')); - $dateField.removeClass('crm-error'); - } else if (!hasDatepicker) { - val = $dateField.val() + '-01-01'; - } - else if (!dateHasDay()) { - // This would be a Year-month date (yyyy-mm) - // it could be argued it should not use a datepicker.... - val = $dateField.val() + '-01'; - } else { - $dateField.addClass('crm-error'); - } - } - if ($timeField.val()) { - val += (val ? ' ' : '') + $timeField.timeEntry('getTime').toTimeString().substr(0, 8); - } - $dataField.val(val).trigger('change', ['userInput']); - } - } - $dataField.hide().addClass('crm-hidden-date').on('change.crmDatepicker', updateInputFields); - updateInputFields(); - }); }; CRM.utils.formatSelect2Result = function (row) { diff --git a/js/crm.datepicker.js b/js/crm.datepicker.js new file mode 100644 index 0000000000..cfef977c04 --- /dev/null +++ b/js/crm.datepicker.js @@ -0,0 +1,144 @@ +(function($, CRM, _) { + "use strict"; + + /** + * @see http://wiki.civicrm.org/confluence/display/CRMDOC/crmDatepicker + */ + $.fn.crmDatepicker = function(options) { + return $(this).each(function() { + if ($(this).is('.crm-form-date-wrapper .crm-hidden-date')) { + // Already initialized - destroy + $(this) + .off('.crmDatepicker') + .css('display', '') + .removeClass('crm-hidden-date') + .siblings().remove(); + $(this).unwrap(); + } + if (options === 'destroy') { + return; + } + var + $dataField = $(this).wrap(''), + settings = CRM._.cloneDeep(options || {}), + $dateField = $(), + $timeField = $(), + $clearLink = $(), + hasDatepicker = settings.date !== false && settings.date !== 'yy', + type = hasDatepicker ? 'text' : 'number'; + + if (settings.allowClear !== undefined ? settings.allowClear : !$dataField.is('.required, [required]')) { + $clearLink = $('') + .insertAfter($dataField); + } + if (settings.time !== false) { + $timeField = $('').insertAfter($dataField); + CRM.utils.copyAttributes($dataField, $timeField, ['class', 'disabled']); + $timeField + .addClass('crm-form-text crm-form-time') + .attr('placeholder', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder')) + .attr('aria-label', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder')) + .change(updateDataField) + .timeEntry({ + spinnerImage: '', + show24Hours: settings.time === true || settings.time === undefined ? CRM.config.timeIs24Hr : settings.time == '24' + }); + } + if (settings.date !== false) { + // Render "number" field for year-only format, calendar popup for all other formats + $dateField = $('').insertAfter($dataField); + CRM.utils.copyAttributes($dataField, $dateField, ['placeholder', 'style', 'class', 'disabled', 'aria-label']); + $dateField.addClass('crm-form-' + type); + if (hasDatepicker) { + settings.minDate = settings.minDate ? CRM.utils.makeDate(settings.minDate) : null; + settings.maxDate = settings.maxDate ? CRM.utils.makeDate(settings.maxDate) : null; + settings.dateFormat = typeof settings.date === 'string' ? settings.date : CRM.config.dateInputFormat; + settings.changeMonth = CRM._.includes(settings.dateFormat, 'm'); + settings.changeYear = CRM._.includes(settings.dateFormat, 'y'); + if (!settings.yearRange && settings.minDate !== null && settings.maxDate !== null) { + settings.yearRange = '' + CRM.utils.formatDate(settings.minDate, 'yy') + ':' + CRM.utils.formatDate(settings.maxDate, 'yy'); + } + $dateField.addClass('crm-form-date').datepicker(settings); + } else { + $dateField.attr('min', settings.minDate ? CRM.utils.formatDate(settings.minDate, 'yy') : '1000'); + $dateField.attr('max', settings.maxDate ? CRM.utils.formatDate(settings.maxDate, 'yy') : '4000'); + } + $dateField.change(updateDataField); + } + // Rudimentary validation. TODO: Roll into use of jQUery validate and ui.datepicker.validation + function isValidDate() { + // FIXME: parseDate doesn't work with incomplete date formats; skip validation if no month, day or year in format + var lowerFormat = settings.dateFormat.toLowerCase(); + if (lowerFormat.indexOf('y') < 0 || lowerFormat.indexOf('m') < 0 || !dateHasDay()) { + return true; + } + try { + $.datepicker.parseDate(settings.dateFormat, $dateField.val()); + return true; + } catch (e) { + return false; + } + } + + /** + * Does the date format contain the day. + * + * @returns {boolean} + */ + function dateHasDay() { + var lowerFormat = settings.dateFormat.toLowerCase(); + if (lowerFormat.indexOf('d') < 0) { + return false; + } + return true; + } + function updateInputFields(e, context) { + var val = $dataField.val(), + time = null; + if (context !== 'userInput' && context !== 'crmClear') { + if (hasDatepicker) { + $dateField.datepicker('setDate', CRM._.includes(val, '-') ? $.datepicker.parseDate('yy-mm-dd', val) : null); + } else if ($dateField.length) { + $dateField.val(val.slice(0, 4)); + } + if ($timeField.length) { + if (val.length === 8) { + time = val; + } else if (val.length === 19) { + time = val.split(' ')[1]; + } + $timeField.timeEntry('setTime', time); + } + } + $clearLink.css('visibility', val ? 'visible' : 'hidden'); + } + function updateDataField(e, context) { + // The crmClear event wipes all the field values anyway, so no need to respond + if (context !== 'crmClear') { + var val = ''; + if ($dateField.val()) { + if (hasDatepicker && isValidDate() && dateHasDay()) { + val = $.datepicker.formatDate('yy-mm-dd', $dateField.datepicker('getDate')); + $dateField.removeClass('crm-error'); + } else if (!hasDatepicker) { + val = $dateField.val() + '-01-01'; + } + else if (!dateHasDay()) { + // This would be a Year-month date (yyyy-mm) + // it could be argued it should not use a datepicker.... + val = $dateField.val() + '-01'; + } else { + $dateField.addClass('crm-error'); + } + } + if ($timeField.val()) { + val += (val ? ' ' : '') + $timeField.timeEntry('getTime').toTimeString().substr(0, 8); + } + $dataField.val(val).trigger('change', ['userInput']); + } + } + $dataField.hide().addClass('crm-hidden-date').on('change.crmDatepicker', updateInputFields); + updateInputFields(); + }); + }; +})(jQuery, CRM, CRM._); diff --git a/karma.conf.js b/karma.conf.js index d1c9cd3487..2915dc7814 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -32,6 +32,7 @@ module.exports = function(config) { 'bower_components/jquery-validation/dist/jquery.validate.min.js', 'packages/jquery/plugins/jquery.timeentry.js', 'js/Common.js', + 'js/crm.datepicker.js', 'bower_components/angular/angular.js', 'js/crm.angular.js', angularTempFile,