Open cyrus-za opened 12 years ago
I think it's ok. And I have created the "datetimepicker" directive in my project and work well. But we need concern that the model value if need the datetime type, and I use the date time string in my project.
The source code: (function (window, angular) { var module = angular.module('ui.date', []); module.constant('viUIDateTimeFormatConfig', { dateFormat: 'mm/dd/yy', //window.visionApps ? window.visionApps.cms_core.DateFormat : 'mm/dd/yy', timeFormat: 'h:mm TT' //window.visionApps ? window.visionApps.cms_core.TimeFormat : 'h:mm tt' }).factory('viUIDateTimeConverter', ['viUIDateTimeFormatConfig', function (viUIDateTimeFormatConfig) { return { stringToDate: stringToDate, dateToString: dateToString, stringToDateTime: stringToDateTime, dateTimeToString: dateTimeToString };
function timezoneToOffset(timezone, fallback) {
timezone = timezone.replace(/:/g, '');
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
}
function addDateMinutes(date, minutes) {
date = new Date(date.getTime());
date.setMinutes(date.getMinutes() + minutes);
return date;
}
function convertTimezoneToLocal(date, timezone, reverse) {
reverse = reverse ? -1 : 1;
var dateTimezoneOffset = date.getTimezoneOffset();
var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
}
function doTZ(date, timezone, reverse) {
return timezone ? convertTimezoneToLocal(date, timezone, reverse) : date;
}
function dateToString(uiDateFormat, value) {
var dateFormat = uiDateFormat || viUIDateTimeFormatConfig.dateFormat;
if (value) {
if (dateFormat) {
try {
return $.datepicker.formatDate(dateFormat, value);
} catch (formatException) {
return undefined;
}
}
if (value.toISOString) {
return value.toISOString();
}
}
return null;
}
function stringToDate(dateFormat, valueToParse, timezone) {
dateFormat = dateFormat || viUIDateTimeFormatConfig.dateFormat;
if (angular.isDate(valueToParse) && !isNaN(valueToParse)) {
return doTZ(valueToParse, timezone);
}
if (angular.isString(valueToParse)) {
if (dateFormat) {
if (valueToParse.indexOf('T') > -1) {
var date = new Date(valueToParse);
return doTZ(date, timezone);
}
return doTZ($.datepicker.parseDate(dateFormat, valueToParse), timezone);
}
var isoDate = new Date(valueToParse);
return isNaN(isoDate.getTime()) ? null : doTZ(isoDate, timezone);
}
if (angular.isNumber(valueToParse)) {
return doTZ(new Date(valueToParse), timezone);
}
return null;
}
function dateTimeToString(uiDateFormat, value) {
var dateFormat = uiDateFormat || viUIDateTimeFormatConfig.dateFormat + ' ' + viUIDateTimeFormatConfig.timeFormat;
if (value) {
if (dateFormat) {
try {
return $.datepicker.formatDateTime(dateFormat, value);
} catch (formatException) {
return undefined;
}
}
if (value.toISOString) {
return value.toISOString();
}
}
return null;
}
function stringToDateTime(dateTimeFormat, valueToParse, timezone) {
dateTimeFormat = dateTimeFormat || viUIDateTimeFormatConfig.dateFormat + ' ' + viUIDateTimeFormatConfig.timeFormat;
if (angular.isDate(valueToParse) && !isNaN(valueToParse)) {
return doTZ(valueToParse, timezone);
}
if (angular.isString(valueToParse)) {
if (valueToParse.indexOf('T') > -1) {
var isoDate = new Date(valueToParse);
return isNaN(isoDate.getTime()) ? null : doTZ(isoDate, timezone);
}
if (dateTimeFormat) {
return doTZ(new Date($.datepicker.replaceDotInTime(valueToParse)), timezone);
}
var isoDate = new Date(valueToParse);
return isNaN(isoDate.getTime()) ? null : doTZ(isoDate, timezone);
}
if (angular.isNumber(valueToParse)) {
return doTZ(new Date(valueToParse), timezone);
}
return null;
}
}]);
module.directive("viDatepicker", ['$compile', '$timeout', 'viUIDateTimeFormatConfig', 'viUIDateTimeConverter', function ($compile, $timeout, viUIDateTimeFormatConfig, viUIDateTimeConverter) {
return {
restrict: 'EA',
require: '?ngModel',
priority: 1,
link: function link(scope, element, attrs, controller) {
var $element = $(element);
var getOptions = function () {
var settings = angular.extend({}, viUIDateTimeFormatConfig, scope.$eval(attrs.viDatepicker || "{}"));
if (!angular.isDate(settings.minDate)) {
settings.minDate = new Date(settings.minDate);
}
if (!angular.isDate(settings.maxDate)) {
settings.maxDate = new Date(settings.maxDate);
}
return settings;
};
var initDateWidget = function () {
var showing = false;
var opts = getOptions();
var timezone = null;
function setVal(selectedValue) {
controller.$setViewValue(selectedValue);
}
// If we have a controller (i.e. ngModelController) then wire it up
if (controller) {
// Set the view value in a $apply block when users selects
// (calling directive user's function too if provided)
var _onSelect = opts.onSelect || angular.noop;
opts.onSelect = function (value, picker) {
scope.$apply(function () {
showing = true;
setVal(value);
$element.blur();
_onSelect(value, picker, $element);
});
};
var _beforeShow = opts.beforeShow || angular.noop;
opts.beforeShow = function (input, picker) {
showing = true;
_beforeShow(input, picker, $element);
};
var _onClose = opts.onClose || angular.noop;
opts.onClose = function (value, picker) {
showing = false;
_onClose(value, picker, $element);
};
$element.on('focus', function (focusEvent) {
if (attrs.readonly) {
focusEvent.stopImmediatePropagation();
}
});
$element.off('blur.datepicker').on('blur.datepicker', function () {
if (!showing) {
scope.$apply(function () {
$element.datepicker('setDate', $element.datepicker('getDate'));
setVal(viUIDateTimeConverter.dateToString(attrs.viDateFormat, $element.datepicker('getDate')));
});
}
});
controller.$validators.viDateValidator = function (modelValue, viewValue) {
return viewValue === null || viewValue === '' || angular.isDate(viUIDateTimeConverter.stringToDate(attrs.viDateFormat, viewValue));
};
controller.$parsers.push(function (valueToParse) {
//return viUIDateTimeConverter.stringToDate(attrs.viDateFormat, valueToParse, timezone);
if (angular.isDate(valueToParse)) {
return viUIDateTimeConverter.dateToString(attrs.viDateFormat, valueToParse, timezone);
}
return valueToParse;
});
// Update the date picker when the model changes
controller.$render = function () {
// Force a render to override whatever is in the input text box
if (angular.isDate(controller.$modelValue) === false && angular.isString(controller.$modelValue)) {
//controller.$modelValue = viUIDateTimeConverter.stringToDate(attrs.viDateFormat, controller.$modelValue, timezone);
var selectedDate = viUIDateTimeConverter.stringToDate(attrs.viUIDateFormat, controller.$modelValue, timezone);
$element.datepicker('setDate', selectedDate);
controller.$modelValue = viUIDateTimeConverter.dateToString(attrs.viUIDateTimeFormat, selectedDate);
}
//$element.datepicker('setDate', controller.$modelValue);
};
}
// Check if the $element already has a datepicker.
if ($element.data('datepicker')) {
// Updates the datepicker options
$element.datepicker('option', opts);
$element.datepicker('refresh');
} else {
// Creates the new datepicker widget
$element.datepicker(opts);
// Cleanup on destroy, prevent memory leaking
$element.on('$destroy', function () {
$element.datepicker('hide');
$element.datepicker('destroy');
});
}
if (controller) {
controller.$render();
// Update the model with the value from the datepicker after parsed
setVal(controller.$modelValue);
}
};
// Watch for changes to the directives options
scope.$watch(getOptions, initDateWidget, true);
}
};
}]);
module.directive("viDatetimepicker", ['$compile', '$timeout', 'viUIDateTimeFormatConfig', 'viUIDateTimeConverter', function ($compile, $timeout, viUIDateTimeFormatConfig, viUIDateTimeConverter) {
return {
restrict: 'EA',
require: '?ngModel',
priority: 1,
link: function link(scope, element, attrs, controller) {
var $element = $(element),
timezone = null;
var getOptions = function () {
var defaultOptions = {
hourGrid: 3,
minuteGrid: 15,
enableInput: true,
showTimepicker: true,
//filterTime: "{\"Hour\":0,\"Minute\":0}",
filterTime: null,
separator: ' ',
yearRange: 'c-50:c+20',
updateDateTimeCallback: function (datePicker, dp_inst, formattedDateTime) {
var _defaults = datePicker._defaults;
if (_defaults.filterTime) {
var filterTimeOption = _defaults.filterTime;
var filterTime = { hour: filterTimeOption.Hour, minute: filterTimeOption.Minute };
var filterTimeStr = $.datepicker.formatTime(_defaults['timeFormat'], filterTime, _defaults);
if (filterTimeStr.toLowerCase() == datePicker.formattedTime.toLowerCase()) {
return formattedDateTime;
} else {
formattedDateTime += _defaults.separator + datePicker.formattedTime + _defaults.timeSuffix;
return formattedDateTime;
}
} else {
return formattedDateTime += _defaults.separator + datePicker.formattedTime + _defaults.timeSuffix;
}
}
};
var settings = angular.extend(defaultOptions, viUIDateTimeFormatConfig, scope.$eval(attrs.viDatetimepicker || "{}"));
if (!angular.isDate(settings.minDate)) {
settings.minDate = new Date(settings.minDate);
}
if (!angular.isDate(settings.maxDate)) {
settings.maxDate = new Date(settings.maxDate);
}
return settings;
};
var initDateTimeWidget = function () {
var showing = false;
var opts = getOptions();
function setVal(selectedValue) {
controller.$setViewValue(selectedValue);
}
// If we have a controller (i.e. ngModelController) then wire it up
if (controller) {
// Set the view value in a $apply block when users selects
// (calling directive user's function too if provided)
var _onSelect = opts.onSelect || angular.noop;
opts.onSelect = function (value, picker) {
//scope.$apply(function () {
showing = true;
setVal(value);
_onSelect(value, picker, $element);
//});
};
var _beforeShow = opts.beforeShow || angular.noop;
opts.beforeShow = function (input, picker) {
showing = true;
_beforeShow(input, picker, $element);
};
var _onClose = opts.onClose || angular.noop;
opts.onClose = function (value, picker) {
showing = false;
_onClose(value, picker, $element);
};
$element.on('focus', function (focusEvent) {
if (attrs.readonly) {
focusEvent.stopImmediatePropagation();
}
});
controller.$validators.viDateTimeValidator = function (modelValue, viewValue) {
return viewValue === null || viewValue === '' || angular.isDate(viUIDateTimeConverter.stringToDateTime(attrs.viUIDateTimeFormat, viewValue));
};
controller.$parsers.push(function (valueToParse) {
if (angular.isDate(valueToParse)) {
return viUIDateTimeConverter.dateTimeToString(attrs.viUIDateTimeFormat, valueToParse, timezone);
}
return valueToParse;
//return viUIDateTimeConverter.stringToDateTime(attrs.viUIDateTimeFormat, valueToParse, timezone);
});
// Update the date picker when the model changes
controller.$render = function () {
// Force a render to override whatever is in the input text box
if (angular.isDate(controller.$modelValue) === false && angular.isString(controller.$modelValue)) {
var selectedDate = viUIDateTimeConverter.stringToDateTime(attrs.viUIDateTimeFormat, controller.$modelValue, timezone);
$element.datetimepicker('setDate', selectedDate);
controller.$modelValue = viUIDateTimeConverter.dateTimeToString(attrs.viUIDateTimeFormat, selectedDate);
}
};
}
// Check if the $element already has a datetimepicker.
if ($element.data('datetimepicker')) {
// Updates the datetimepicker options
$element.datetimepicker('option', opts);
$element.datetimepicker('refresh');
} else {
// Creates the new datetimepicker widget
$element.datetimepicker(opts);
// Cleanup on destroy, prevent memory leaking
$element.on('$destroy', function () {
$element.datetimepicker('hide');
$element.datetimepicker('destroy');
});
}
if (controller) {
controller.$render();
// Update the model with the value from the datetimepicker after parsed
setVal(controller.$modelValue);
}
};
// Watch for changes to the directives options
scope.$watch(getOptions, initDateTimeWidget, true);
}
};
}]);
})(window, angular);
FYI.
Hi,
There is a Datepicker on angular-ui (http://angular-ui.github.com/) which uses Jquery-ui datepicker.
I would like to know if it is possible to add your timepicker addon in there?