jtsage / jtsage-datebox

A multi-mode date and time picker for Bootstrap (3&4), jQueryMobile, Foundation, Bulma, FomanticUI, and UIKit (or others)
http://datebox.jtsage.dev/
Other
474 stars 166 forks source link

Custom display information for griddate buttons. #340

Closed slavap closed 10 years ago

slavap commented 10 years ago

Additional option is needed to support date buttons custom display/formatting. The following code:

if ( genny[row][col][0]) {
    $("<div>")
        .text( String( genny[row][col][0] ) )
        .addClass( uid + "griddate ui-corner-all ui-btn")
...

should be changed to replace String( genny[row][col][0] ) by call of custom display/formatting function (if specified). Input parameter: Date; Output: display String. See attachment. calendarpricing

slavap commented 10 years ago

Ok, I've implemented a workaround for this functionality. You can load the following script after jqm-datebox and then provide your custom formatting function:

(function() {

    $.widget("mobile.datebox", $.mobile.datebox, {
        setGridDateFormatter: function( formatter ) {
            // Provide a PUBLIC function to set the date buttons formatter 
            // ACCEPTS: function with (input: array of Date; output: array of String/Html) 
            if ( typeof formatter === "function" ) {
                this.gridDateFormatter = formatter;
                this.refresh();
            }
        }
    });

    var _prev = $.mobile.datebox.prototype._build.calbox;
    $.mobile.datebox.prototype._build.calbox = function() {
        _prev.call(this);
        if (typeof this.gridDateFormatter === "undefined" || this.gridDateFormatter === null) return;

        var dateBtns = this.d.intHTML.find(".ui-datebox-griddate.ui-btn");
        if (dateBtns.length === 0) return;

        // -1 previous year's Dec
        // 12 next year's Jan
        // 0..11 current year's Jan..Dec

        var thisYY = this.theDate.getFullYear(); // this.theDate is current header's date
        var dates = [];
        dateBtns.each(function( index, elt ) { // elt == this
            var mm = $(elt).data("month");
            var dd = $(elt).data("date");
            var yy = thisYY;
            if (mm < 0) { 
                yy--;
                mm = 12 + mm;
            } else if (mm > 11) { 
                yy++;
                mm = mm - 12; 
            };
            var d = new Date(yy, mm, dd, 0, 0, 0);
            dates.push(d);
        });
        var fmtDates = this.gridDateFormatter(dates);
        if ($.isArray(fmtDates) && fmtDates.length === dates.length) {
            dateBtns.each(function( index, elt ) { // elt == this
                $(elt).html(fmtDates[index]);
            });
        }
    };
})();

And then define custom formatting function like this:

$('#myInput').datebox('setGridDateFormatter', function (dates) {
    var strs = [];
    $.each(dates, function( index, item ) { // item == this
        strs.push("|<u>" + item.getDate() + "</u>|");
    });
    return strs;
});
jtsage commented 10 years ago

I like this. I'm gonna play a bit with it of course, but this is a good idea. :)

jtsage commented 10 years ago

so, here's what is going to hit in a few minutes once I finish some docs.

calFormatter: false // or a function, or a reference to a function

default "false" ( just the date) - with the option to pass a function, either in full ( prototype.options... ) or by reference (window.myFunction, calFormatter: "myFunction")

It recieves a single object of the date -

{
    "Year" : 0,
    "Month" : 0-11,
    "Date" : 1-31,
}

Month and Year normalized and not the "one off" that are found in genny[]

I'm open to suggestions on this - for instance, I like the thought of setGridDateFormatter, but I'm not sure (apart from the shortcut) what it gains. (use case?)

I did set it up to call on each date, rather than dumping a big object of the whole month - it is certainly easier to write the formatter this way - however, if you are doing events or prices or something, it is obviously less efficient to query the server for each date - my guess is that something hooked on to the "offset" event could be leveraged to pre-load the whole month. (Not sure - in all likelyhood I'll never actually use this myself - so, if there is a good reason to do it another way, lemme know)

Overview: http://dev.jtsage.com/jQM-DateBox/doc/5-0-control/ Detail: http://dev.jtsage.com/jQM-DateBox/api/calFormatter/

slavap commented 10 years ago

Call it for each date is OK as well, because you have to use some kind of client side cache for supporting additional information (pricing, inventory, ...) anyway. I'll try to switch my code to your implementation and let you know if it's working for me.

slavap commented 10 years ago

Regarding setGridDateFormatter(). In my code it was possible to change formatting function dynamically for any datebox widget, like: $('#myInput').datebox('setGridDateFormatter', function (date) {...}); How I'm supposed to do that now, without adding my function to window? I've tried $('#myInput').datebox('option').calFormatter = function (date) {...}; but it's not working. And I don't see documentation for datebox('option'), is it supported by jQuery widget?

Also _cal_formatter is declared, but not used in your code. And its body is not correct, must be: return date.Date;

jtsage commented 10 years ago

1.) the function - yes, when I started working, I was going to do something similar to how the _build() function works - however, it would have made part 2 of this answer much harder to do.

2.) Changing dynamically is actually easier than that. It is, at it's heart, just an option - so you can change it with the usual options method:

$('#myinput').datebox( { } );

For instance:

$('#datebox_input_element').datebox({ 'calFormatter': function( date ) { return date.Month; } });

This drops it through the _setOption routine, so there is no need to throw a refresh() at it, as that is done for you.

Updated http://dev.jtsage.com/jQM-DateBox/api/calFormatter/ to show that bit of demo code too.

slavap commented 10 years ago

You mean not comma, but colon, right ? :-)

$('#datebox_input_element').datebox({ 'calFormatter': function( date ) { return date.Month; } });

Thanks for explanation! My JS skills are still really sucks. And once again, when I'm using:

var o = $('#myinput').datebox('option');

I'm getting current options, but still cannot figure out why it's actually working :-)

jtsage commented 10 years ago

Yes, I did indeed mean a colon. Fixed in the docs too. Oops.

And indeed, datebox('option') will get you a full list - it's inherited from the jquery-ui widget library (which all of the jquerymobile widgets, and datebox are built on)

https://github.com/jquery/jquery-mobile/blob/master/external/jquery-ui/jquery.ui.widget.js#L298

Fwiw, if you need to retrieve a single option, you can also do this:

var myOption = $('#myinput').datebox('getOption', 'calFormatter');  // Really a comma here :)
slavap commented 10 years ago

Thanks! All working on my side now.

jtsage commented 10 years ago

Which, after actually reading that a bit closer, you were not that far off with your original syntax of trying to set the option. This should work just fine too:

$('#myinput').datebox('option', 'calFormatter', function( date ) { return date.Month; } );

Conversely, to just get an option,

$('#myinput').datebox('option', 'calFormatter');

(a/n: What "getOption" actually does is dig through all of the i18n crap for you automatically as well - the original method is somewhat blind to that stuff - or, blind to which language is currently in use anyway)

Glad it's working though :)