Calendar - globules-io/OGX.JS GitHub Wiki

Calendar is locale aware, infinite multi function, multi layout calendar, that can render time periods, such as (and not limited to) centuries, decades, years, months, weeks, days (...) and custom data within each period.

Time periods can also be customized via layouts to render any time period and elements of that time period that suits your needs.

Calendar relies on OGX.GridSwiper and momentjs

Stack

Extends

 Uxi, Touch

Requires

  GridSwiper, List

OML

Format

 {"selector:Calendar":{CONFIG}}

Example

  {"#selector:Calendar":{}}

Instantiate

 let config = {
      id:_*_, //Unique ID
      el:_SELECTOR_ , //Required, The selector for the target HTML element   
      date:_DATE_ ,  //Optional, the current date, either a parse-able date or JS Date object,
      selectable: _BOOL_ //Optional, defaults to true,
      no_selection: _ARRAY_, //Optional, an array of dates that cannot be selected, must match layout format
      off_dates: _ARRAY_, //Optional, an array of dates to be dislayed as "off"
      swipe:_BOOL_ //Optional, defaults to true,
      browse:_BOOL_ //Optional, defaults to true,
      mode:_STRING_, //Optional, either 'select' or 'toggle' defaults to 'select', 
      layouts:_ARRAY_ //Optional, an array of layout,
      layout:_INT_ //Optonal, the default layout, defaults to 0,
      simple:_BOOL_ //Optional, see simple section
      callbacks: _OBJ_ //optional, see callbacks
 };


 //from a Uxi
 let calendar = this.create('Calendar', config);

 //With OML from a Uxi
 OGX.Object.render(this, {"#selector:Calendar":{}});

 //from OGX.Object
 let calendar = OGX.Object.create('Calendar', config);    

 //retrieve
 let calendar = app.cfind('Calendar', 'mycalendar');

By default, OGX.Calendar uses a 3 layouts grid, DECADE_YEARS, YEARS_MONTHS and MONTH_DAYS.

Simple 1.27.0+

If you are using the default configuration but wish to only have 1 layout, like a standard calendar and also the old behavior of the Calendar object, set the flag

 simple : true 

This flag must be set to false if you are using your own layouts configuration, as it basically only keeps the MONTH_DAYS layout if set to true.

Options

The swipeable option sets the ability to swipe. The browseable option displays or hide the navigation buttons.

Methods

Retrieve selected date

  let date = calendar.val();

To set the selected date

  calendar.val('2023-04-05');    

To set the selected date without re-rendering

  calendar.val('2023-04-05', false);    

To reset the selected date

  calendar.resetSelection();

Retrieve displayed date

  let date = calendar.display();

To set the displayed date

  calendar.display('2023-04-05');

To lock the axis (if set at multiple layouts)

  calendar.axis(_x_as__bool_, _y_as_bool_);

To re-render/refresh the Calendar

  calendar.refresh();

To set the off dates

  calendar.offDates(['2023-01-04']);

To prevent the selection of certain dates

  calendar.noSelection(['2023-01-04']);      

Year selector 1.27.0+

To enable year selector, from a click on the top date, set

  config = {year_pick: true, ...}

Multiple layouts

You can also declare multiple layouts and switch from one another by swiping up/down. Then swiping left/right will increment the date based on the unit and value of the layout. The following configuration displays the days of a months. Swiping down switches the layout to rendering days of the current week.

 let config = {
      el:_SELECTOR_,
      layouts:[
           {layout:{name:'MONTH_DAYS'}, engine:{name:'DAY_NUMBER'}} ,
           {layout:{name:'WEEK_DAYS'}, engine:{name:'DAY_NUMBER'}}                 
      ]
 };

You can have as many layout/engine pairs as you want. Note that config is an extra object passed to the engine.

1.20.0+

Calendar layout and engine setup format has changed to allow custom parameters to a built-in layouts, without the need to create a custom layout. Before 1.20, only the engine could receive data via a config object

{"layout":"WEEK_DAYS", "engine":"CUSTOM_ENGINE", "config":{}}

Since 1.20, both the layout and engine can be passed a custom object. The layout and the engine must be declared by name now.

{
      "layout":{"name":"WEEK_DAYS", "config":{"format":"YYYY"}}, 
      "engine":{"name":"CUSTOM_ENGINE", "config":{}}
}

Change layouts 1.19.0+

You can change on the fly the layouts configuration

 calendar.layouts([...]);

Layouts

Out of the box, OGX.Calendar comes with a bunch of predefined layouts.

 OGX.CalendarLayout.CENTURY_DECADES  //Displays decades per century
 OGX.CalendarLayout.CENTURY_YEARS    //Displays years per century
 OGX.CalendarLayout.DECADE_YEARS     //Displays years per decade
 OGX.CalendarLayout.DECADE_MONTHS    //Displays months per decade
 OGX.CalendarLayout.YEAR_MONTHS      //Displays months per year
 OGX.CalendarLayout.YEAR_WEEKS       //Displays weeks per year
 OGX.CalendarLayout.YEAR_DAYS        //Displays days per year
 OGX.CalendarLayout.MONTH_WEEKS      //Displays weeks per month
 OGX.CalendarLayout.MONTH_DAYS       //Displays days per month
 OGX.CalendarLayout.WEEK_DAYS        //Displays days per week
 OGX.CalendarLayout.DAY_HOURS        //Displays hours per day
 OGX.CalendarLayout.DAY_WORK_HOURS   //Displays hours per day

For instance, the OGX.CalendarLayout.CENTURY_DECADES layout will display 10 zones, each representing a decade. Then on a right swipe, the century will be increased by 1. In other words, if you start with 1900, the layout will be composed of 10 zones, each representing 10 years and a swipe right would display the first decade of the 2000's.

Custom Layouts

You can also create custom layouts respecting a few rules. A layout needs a few public methods so the calendar knows what to do when a user swipes left/right.

 OGX.CalendarLayout.MY_CUSTOM_LAYOUT = function(){
      'use strict';
       OGX.CalendarLayout.BASE_LAYOUT.call(this);

      //Optional, a labels method that returns an HTML string to render as top labels
      this.labels = function(){
           return '';
      };

      //Optional, a html method that returns the layout an HTML string, defaults to empty string
      this.html = function(__date, __engine, __options){
           return '';
      };

      //Optional, a value method that return an object containing the increment value, default to the following
      this.value = function(){                
            return {value:1, unit:'months'};
      };
    
      //Optional, a format used to display the current date with this layout, defaults to YYYY-MM
      this.format = function(){
            return 'YYYY-MM';
      };

 };

Available units are

 years
 months
 days
 hours
 minutes
 seconds
 milliseconds

Engines

An engine is used to render the content of a layout element. For instance, if you use the MONTH_DAYS layout paired with the DAY_NUMBER, that engine will render in each and every layout element, the day of the given date.

Available engines out of the box are

 DAY_NUMBER
 WEEK_NUMBER
 MONTH_NUMBER
 YEAR_NUMBER
 CELL_VALUE

Note that CELL_VALUE requires a format passed in the config object. DAY_NUMBER is an actual shortcut to using CELL_VALUE with config object as

 {format:'DD'}

Custom Engines

Out of the box, only DAY_NUMBER is available but you can easily create an engine for your calendar needs. For instance, if you wish to render custom data based on the date of each and every element, simply create a custom engine as follow

 OGX.CalendarEngine.MyCustomEngine = function(__date){

       //do some calculation here based on the date
       var myresult = 'some html content based on the date';
       return '<span class="someCSS">'+myresult +'</span>';

 };

This way, you can render any type of content inside your layout elements, such as graphs, stats, images, whatever you need. The following custom engine renders a graph in every layout element using chartist.js.

 OGX.CalendarEngine.MyGraphEngine = function(__date){
   
    //must gen an id for unique selector
    let id = __date.format('YYYY-MM-DD')+Math.round(Math.random()*10000);
    let el = '<div class="my_graph_engine" data-id="'+id+'"></div>';

    //generic graph, ideally, you would get your data for your graph from another object
    function graph(){
         new Chartist.Line('.my_graph_engine[data-id="'+id+'"]', {
              series: [
                  [12, 9, 7, 8, 5]           
              ]
              }, {
              fullWidth: true                  
         });
     }
     setTimeout(graph, 0);
     return el;   
 };

Callbacks

If you'd rather have a callback instead of dealing with events (for some events), you can set callbacks in your config, or on the fly. Supported callbacks are select and unselect

Setting callbacks at config

  {..., callbacks:{select: mySelectFunction, unselect: myUnselectFunction}}

Note that you can also setup callbacks with OML and OSE using the method Node

Setting callbacks at runtime

  calendar.onSelect = mySelectFunction;
  calendar.onUnselect = myUnselectFunction;

Events

  OGX.Calendar.SELECT 
  OGX.Calendar.UNSELECT 
  OGX.Calendar.BROWSE

Inherited Events

  OGX.GridSwiper.SWIPE_LEFT
  OGX.GridSwiper.SWIPE_RIGHT
  OGX.GridSwiper.SWIPE_UP
  OGX.GridSwiper.SWIPE_DOWN
  OGX.GridSwiper.SWIPE_START
  OGX.GridSwiper.SWIPE_END
⚠️ **GitHub.com Fallback** ⚠️