mymth / vanillajs-datepicker

A vanilla JavaScript remake of bootstrap-datepicker for Bulma and other CSS frameworks
MIT License
720 stars 147 forks source link

Allow approximate dates to be typed in: "2022-10" and "2022" #124

Open EmilStenstrom opened 1 year ago

EmilStenstrom commented 1 year ago

Hello! really appreciate all the hard work you've put into this library!

I use it for a site where you can visualise your family tree generations back. Because of this, when you go back in time, some dates will be approximate. Maybe you just know the year, or just a year and date. In the backend I support this by allowing both YYYY-MM-DD, YYYY-MM, and YYYY in the same field. I'd like to allow the user to type in those values, no need to support them in the actual picker.

Problem is, I the datepicker seems to try to parse the year to a full date.

It looks like I should be able to give a private format option, define a toValue and toDisplay value. But I can't figure out how to reuse all of your wondeful existing logic. I don't want to copy your whole parser, so I was hoping that I could call that existing parser, except for the cases where the format matches YYYY-MM or YYYY...

Is there someone that reads this that could give some pointers that can help me achieve this?

My setup is as simple as this:

var options = {
    format: "yyyy-mm-dd",
    weekStart: 1,
    format: {
        toValue(date, format, locale) {
            ...
        },
        toDisplay(date, format, locale) {
            ...
        },
    },
};
var elements = document.querySelectorAll('.date input');
elements.forEach((elem) => { new Datepicker(elem, options) });
EmilStenstrom commented 1 year ago

Ok, so you might feel a bit dirty reading this, sorry about that... I have something that works. It's using a global variable to remember the last used format for toValue, and applies that format to toDisplay.

var lastFormat = "yyyy-mm-dd";
addEventListener('load', function(event) {
    var elements = document.querySelectorAll('.date input');
    elements.forEach((elem) => { new Datepicker(elem, {
        format: {
            toValue(date, format) {
                if (date.match(/^\d{4}-?$/)) {
                    lastFormat = "yyyy";
                }
                else if (date.match(/^\d{4}-\d{2}-?$/)) {
                    lastFormat = "yyyy-mm";
                }
                else {
                    lastFormat = "yyyy-mm-dd";
                }
                return Datepicker.parseDate(date, lastFormat);
            },
            toDisplay(date, format) {
                let currentFormat = lastFormat;
                lastFormat = "yyyy-mm-dd";
                return Datepicker.formatDate(date, currentFormat);
            },
        },
    })});
});