Skip to content

Commit

Permalink
Move datepicker widget to a separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
monishdeb committed Aug 8, 2018
1 parent 1eaa530 commit e9b9d4d
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 142 deletions.
1 change: 1 addition & 0 deletions CRM/Core/Resources.php
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ public function coreResourceList($region) {
"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",
Expand Down
143 changes: 1 addition & 142 deletions js/Common.js
Original file line number Diff line number Diff line change
Expand Up @@ -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('<span class="crm-form-date-wrapper" />'),
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 = $('<a class="crm-hover-button crm-clear-link" title="'+ _.escape(ts('Clear')) +'"><i class="crm-i fa-times"></i></a>')
.insertAfter($dataField);
}
if (settings.time !== false) {
$timeField = $('<input>').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 = $('<input type="' + type + '">').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) {
Expand Down
144 changes: 144 additions & 0 deletions js/crm.datepicker.js
Original file line number Diff line number Diff line change
@@ -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('<span class="crm-form-date-wrapper" />'),
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 = $('<a class="crm-hover-button crm-clear-link" title="'+ CRM._.escape(ts('Clear')) +'"><i class="crm-i fa-times"></i></a>')
.insertAfter($dataField);
}
if (settings.time !== false) {
$timeField = $('<input>').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 = $('<input type="' + type + '">').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._);
1 change: 1 addition & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module.exports = function(config) {
'packages/jquery/plugins/jquery.blockUI.js',
'bower_components/jquery-validation/dist/jquery.validate.min.js',
'packages/jquery/plugins/jquery.timeentry.js',
'js/crm.datepicker.js',
'js/Common.js',
'bower_components/angular/angular.js',
'js/crm.angular.js',
Expand Down

0 comments on commit e9b9d4d

Please sign in to comment.