trentrichardson / jQuery-Timepicker-Addon

Adds a timepicker to jQueryUI Datepicker
http://trentrichardson.com/examples/timepicker/
MIT License
2.66k stars 1.05k forks source link

Angular #491

Open cyrus-za opened 12 years ago

cyrus-za commented 12 years ago

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?

gaojianzhuang commented 6 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.