Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow usage of the calendar for specific periods #32

Merged
merged 12 commits into from
Aug 22, 2021

Conversation

Paul-DS
Copy link

@Paul-DS Paul-DS commented Apr 4, 2020

Following the requests for this 2 features:

This PR implement 2 options:

  • startDate: Allow to define the first month displayed in the calendar
  • numberMonthsDisplayed Allow to define the number of months displayed in the calendar

Examples

These options allow you to do the following:

Display a full year starting from a specific month

With parameters:

  • startDate: new Date(2020, 8, 1)

Result:
image

Display only X months

With parameters:

  • numberMonthsDisplayed: 3

Result:
image

With parameters:

  • startDate: new Date(2020, 3, 1)
  • numberMonthsDisplayed: 1

Result:
image

TODO

  • Update the dataSource option to pass the startDate and endDate parameters
  • Update the comments to specify the order of priority between startDate and startYear
  • Update the comments to specify the condition of usage of yearChanged event, the getYear/setYear methods, etc...
  • Test all functionalities to unsure there is no regression
  • Add specific unit tests

Breaking changes ⚠️

The first parameter of the dataSource function is now { year, startDate, endDate } instead of just year.

Example:

new Calendar('#calendar', {
    dataSource: function(period) {
        console.log(`Year: ${period.year}`);
        console.log(`Period displayed: ${period.startDate} - ${period.endDate}`);
        return ...;
    }
});

How to test

Use the @next version of the package:

  • With NPM: npm install js-year-calendar@next
  • With CDN: <script src="https://unpkg.com/js-year-calendar@next/dist/js-year-calendar.min.js"></script>

Additional informations

This is an additional feature , so it shouldn't break the current usage of the calendar (using the basic optionstartYear).

The startDate option override the startYear option.
The yearChanged event, and the getYear and setYear method are available only if the startDate and numberMonthsDisplayed options are not used.

@Paul-DS
Copy link
Author

Paul-DS commented Apr 4, 2020

This functionality will be released in the v1.1.0.
I'll provide a beta version as soon as I'll publish the v1.0.2, so you can all test this feature.

Given the lot of modifications needed for this feature, I will need a lot of testing from current users to check that there is no regression.

I'm open to any remark on the current implementation.

@codecov-io
Copy link

codecov-io commented Apr 5, 2020

Codecov Report

Merging #32 into master will not change coverage by %.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##            master       #32   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           28        28           
  Lines           28        28           
=========================================
  Hits            28        28           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update afcf34d...e392984. Read the comment docs.

@sarveshraval
Copy link

sarveshraval commented May 1, 2020

Hi @Paul-DS I tested the functionality in alpha version , is it available in the stable version 1.1 or 1.2 ?
can you please tell me when can i expect it in either of these versions ?

@PieterDJK
Copy link

PieterDJK commented May 5, 2020

Hi @Paul-DS,

First of all, great calendar! I tried to test this new functionality, but I have troubles with the dataSource.
I have tested it with your github API and that works fine, but I use a Json Object (or Array) as input source instead.
In the bootstrap version that worked fine, but in this version I'm probably doing something wrong (as I'm not a JavaScript expert).
I hope you can help me with this.

If I use your example code of the dataSource usage it works fine:


...
    dataSource: function(year) {
      // Load data from GitHub API
      return fetch(`https://api.github.com/search/issues?q=repo:Paul-DS/bootstrap-year-calendar%20created:2020-01-01..2020-12-31`)
        .then(result => result.json())
        .then(result => {
          if (result.items) {
            return result.items.map(r => ({
              startDate: new Date(r.created_at),
              endDate: new Date(r.created_at),
              name: '#' + r.number + ' - ' + r.title,
              details: r.comments + ' comments', 
            }));
          }          
          return [];
        });
      },
...

Here is my version where "CalendarData" is the Json Object (see example below).

const calendar = new Calendar(('#controlAddIn'),
 {    
   language: 'nl',
   enableRangeSelection:true,
   enableContextMenu: true, 
   numberMonthsDisplayed: 1,
   startDate: new Date(2020,1,1), 

   dataSource: function(period) {
         if (CalendarData.dataSource) {
           return CalendarData.dataSource.map(r => ({
             startDate: parseStringToDate(r.startDate), 
             endDate: parseStringToDate(r.endDate), 
             name: r.name,
             color : r.color
           }));
         }
         return [];
   }
 });
 
function parseStringToDate(dateString) {
 // get year, month and day
 var ymd = dateString.split(" ")[0].split("-");
 var mydate = new Date(parseInt(ymd[0]), parseInt(ymd[1])-1, parseInt(ymd[2]))
 return mydate;
}

example of the "CalendarData" Json Object:

{"dataSource":[
{"startDate":"2020-01-01","endDate":"2020-01-01","name":"","color":"#E89E63"},
{"startDate":"2020-01-28","endDate":"2020-01-28","name":"O000777","color":"#75D8E7"},
{"startDate":"2020-01-29","endDate":"2020-01-29","name":"O000777","color":"#75D8E7"}
]}


another option I tried is using a Json Array (CalendarData) as input like this:

[{"startDate":"2020-01-01","endDate":"2020-01-01","name":"","color":"#E89E63"},
{"startDate":"2020-01-28","endDate":"2020-01-28","name":"O000777","color":"#75D8E7"}]

.... and then first parse the strings to dates:

  for(var i = 0; i < CalendarData.length; i++) {
   var obj = CalendarData[i];
   obj["startDate"] = parseStringToDate(obj.startDate);
   obj["endDate"] = parseStringToDate(obj.endDate);
  }

.....and then use it like below:

const calendar = new Calendar(('#controlAddIn'),
  {    
    language: 'nl',
    enableRangeSelection:true,
    enableContextMenu: true, 
    numberMonthsDisplayed: 1,
    startDate: new Date(2020,1,1), 
    dataSource:CalendarData
...

does not give any result in the calendar.

@ghost
Copy link

ghost commented Jun 4, 2020

Would love to use this feature in my application for my client. Be happy to try it out at a minimum and see how things go. I think numberMonthsDisplayed makes a lot of sense and yeah just being able to control which is the first month by setting the date. Sounds great to me.

Only thought that may be nice is just being able to control this dynamically. Say the user has the 12 month calendar showing and wants to change to 3 month. If you are able to provide a method where I can call and set those parameters and cause the calendar to re-render that would be slick. But I understand if that could be a lot more work on top of what you are already doing. I'm assuming the settings are in onLoad and are more challenging as a method call. But like other calendars i.e. Google users are able to switch between views, making that seamless is just my suggestion and would be a nice to have.

Other than that as long as the dataSource works as expected, which you mentioned, I think that would be all I have. Nice though if the dataSouce re-render of the calendar worked well dynamically as said above. I'll think more. Tag me if you are curious about something I said or if you want to direct me to something to look at and I'll try to help in the code or version available.

@ghost
Copy link

ghost commented Jun 16, 2020

@Paul-DS is there a potential ETA on this by the way? I think my clients would be excited for the flexible partial month(s) view. That kind of ability to flex between either a full calendar year or partial would be ideal for their needs. I've found ways to trigger a re-draw by setting the dataSource dynamically, and if this worked with similar methods on the elements that would be great. Happy to try to help push things forward where I can.

@basilgohar
Copy link

I was about to put in a request for this kind of a feature as well and then I saw the reference to this PR. I'm calling it a night for now but I may try this out and report back here on my own success.

@Paul-DS
Copy link
Author

Paul-DS commented Jun 20, 2020

I published a new version with some minor modifications.

@sarveshraval Did you find any bug while testing this new functionality ?

@PieterDJK Your code seems to be working, but the data are displayed in January, and you're opening the calendar in February (startDate: new Date(2020,1,1)). Change the start date to startDate: new Date(2020,0,1) to make it work

@JJZolper you can now use the setStartDate and setNumberMonthsDisplayed to change the displayed period dynamically.

Concerning the ETA, I'll wait for about a week to get more feedback, and then publish a new release (2.0.0) with this functionality.

Thank you all for your feedback.

@PieterDJK
Copy link

PieterDJK commented Jun 22, 2020

@Paul-DS, thanks for your reaction. I already tried that, my example code was not correct, sorry.
I have tested it again for a whole year with the code below:
`**********************************************************
const calendar = new Calendar(('#controlAddIn'),
{
language: 'nl',
enableRangeSelection:true,
enableContextMenu: true,
numberMonthsDisplayed: 12,
startDate: new Date(2020,0,1),
dataSource: function(period) {
if (CalendarData) {
return CalendarData.map(r => ({
startDate: parseStringToDate(r.startDate),
endDate: parseStringToDate(r.endDate),
name: r.name,
color : r.color
}));
}
return [];
}
});

function parseStringToDate(dateString) {
// get year, month and day
var ymd = dateString.split(" ")[0].split("-");
var mydate = new Date(parseInt(ymd[0]), parseInt(ymd[1])-1, parseInt(ymd[2]))
return mydate;
}
` **********************************************************
where CalendarData is the below Json Array:

[{"startDate":"2020-01-01","endDate":"2020-01-01","name":"","color":"#E89E63"},{"startDate":"2020-01-28","endDate":"2020-01-28","name":"O000777","color":"#75D8E7"},{"startDate":"2020-01-29","endDate":"2020-01-29","name":"O000777","color":"#75D8E7"},{"startDate":"2020-02-04","endDate":"2020-02-04","name":"O000777","color":"#75D8E7"},{"startDate":"2020-02-20","endDate":"2020-02-20","name":"O000777","color":"#75D8E7"},{"startDate":"2020-03-03","endDate":"2020-03-03","name":"O000777","color":"#75D8E7"},{"startDate":"2020-03-09","endDate":"2020-03-09","name":"O000777","color":"#75D8E7"},{"startDate":"2020-04-01","endDate":"2020-04-01","name":"","color":"#E97768"},{"startDate":"2020-04-07","endDate":"2020-04-07","name":"O000827","color":"#75D8E7"},{"startDate":"2020-04-27","endDate":"2020-04-27","name":"","color":"#E89E63"},{"startDate":"2020-05-05","endDate":"2020-05-05","name":"","color":"#E89E63"},{"startDate":"2020-05-09","endDate":"2020-05-09","name":"","color":"#E97768"},{"startDate":"2020-05-10","endDate":"2020-05-10","name":"O000828","color":"#75D8E7"},{"startDate":"2020-05-31","endDate":"2020-05-31","name":"","color":"#E89E63"},{"startDate":"2020-06-01","endDate":"2020-06-01","name":"","color":"#E89E63"},{"startDate":"2020-06-03","endDate":"2020-06-03","name":"O000898","color":"#75D8E7"},{"startDate":"2020-06-13","endDate":"2020-06-13","name":"O000899","color":"#75D8E7"},{"startDate":"2020-07-24","endDate":"2020-07-24","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-07-31","endDate":"2020-07-31","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-08-07","endDate":"2020-08-07","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-08-28","endDate":"2020-08-28","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-09-04","endDate":"2020-09-04","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-09-25","endDate":"2020-09-25","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-10-02","endDate":"2020-10-02","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-10-30","endDate":"2020-10-30","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-11-06","endDate":"2020-11-06","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-11-27","endDate":"2020-11-27","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-12-04","endDate":"2020-12-04","name":"1x per week vrijdag","color":"#E97768"},{"startDate":"2020-12-26","endDate":"2020-12-26","name":"","color":"#E89E63"}]

The result is an empty calendar of the whole year.
Any other idea?
image

@ghost
Copy link

ghost commented Oct 2, 2020

In my case I also need to change the color of the day or box clicked while using the new methods. I was able to figure out a way to do this in a more complicated way below. The spikesData var contains the data for the entire calendar.

    clickDay: function(e) {

        clickedDay = convertDateToStrDashed(e.date);
        console.log(e);

        if((selectedDay.date != clickedDay) && (Array.isArray(e.events) && e.events.length > 0)) {
        
            // Reset previous selected day, if it had been set
            if(selectedDay.element) {
                // Reset prior selections 
                document.getElementById('calendar').querySelectorAll('.day-start').forEach(function(el) {
                    el.style.backgroundColor = 'rgb(' + [86,187,85,1].join(',') + ')';
                })

                // Data set
                spikesData.forEach(function (item, index) {
                    if(item.spike_date == selectedDay.date) {
                        item.color = 'rgb(' + [86,187,85,1].join(',') + ')';
                    }
                });
            }

            // Set new selected day
            e.element.style.backgroundColor = 'rgb(' + [0,128,128,1].join(',') + ')';
            spikesData.forEach(function (item, index) {
                if(item.spike_date == clickedDay) {
                    item.color = 'rgb(' + [0,128,128,1].join(',') + ')';
                }
            });

            selectedDay.date = clickedDay;
            selectedDay.element = e.element;
            
        }

    },


$("#periodSelector ul li").click(function(){
    var monthOption = $(this).text();

    var modDate = new Date();
    if(monthOption == '3 Months') {
        // Smaller box
        $("#calendarBox").css("width", "700px");

        modDate.setMonth(today.getMonth() - 3);

        calendar.setStartDate(modDate);
        calendar.setNumberMonthsDisplayed(3);

        calendar.setDataSource(spikesData);
    } else if(monthOption == '6 Months') {
        // Full width box
        $("#calendarBox").css("width", "100%");

        modDate.setMonth(today.getMonth() - 6);

        calendar.setStartDate(modDate);
        calendar.setNumberMonthsDisplayed(6);

        calendar.setDataSource(spikesData);
    } else if(monthOption == '12 Months') {
        // Full width box
        $("#calendarBox").css("width", "100%");

        modDate.setMonth(today.getMonth() - 12);

        calendar.setStartDate(modDate);
        calendar.setNumberMonthsDisplayed(12);

        calendar.setDataSource(spikesData);
    }

    $("#period_selected").text(monthOption);
    $("#periodSelector ul").removeClass("active");
});

For the time being I'm managing and everything is superb. I change the colors of the objects for the calendar on a per date basis as they click the day. I also set the element itself sometimes if needed. When a redraw occurs from the setNumberMonthsDisplayed() and setStartDate() it requires passing via the data. Even though I was able to workaround things is this something that would be easy to add at some point @Paul-DS? It may be a bit odd to incorporate alongside the other methods but if it is doable it probably would be a good one to do. I'm using the bleeding edge source in this application for the client and I'll update once it's in @ latest.

@Cavva79
Copy link

Cavva79 commented Nov 4, 2020

Hi @Paul-DS,
I'm approaching to js-year-calendar, this feature it is foundamental for a project I'm in.
I'm trying to show a period of time from 11 nov 2020 to 10 nov 2021. Obviusly it is an year but spans on 13 months.
I think this

numberMonthsDisplayed: !isNaN(parseInt(opt.numberMonthsDisplayed)) && opt.numberMonthsDisplayed > 0 && opt.numberMonthsDisplayed <= 12 ? parseInt(opt.numberMonthsDisplayed) : 12,

could be easy switched to

numberMonthsDisplayed: !isNaN(parseInt(opt.numberMonthsDisplayed)) 
     && opt.numberMonthsDisplayed > 0 ? parseInt(opt.numberMonthsDisplayed) : 12,

to allow more than 12 months or try to implement intermediate startDate.

@Paul-DS
Copy link
Author

Paul-DS commented Aug 22, 2021

Sorry guys for the delay.

@JJZolper I don't see your point exactly, can you provide a CodePen (or similar) example.

@Cavva79 Can you open a dedicated issue for this feature ? I'm gonna merge this PR, so I'll handle your request separately.

@Paul-DS Paul-DS merged commit 2f178e8 into master Aug 22, 2021
@Paul-DS
Copy link
Author

Paul-DS commented Aug 24, 2021

The feature is available in v2.0.0

@Cavva79
Copy link

Cavva79 commented Aug 29, 2021

Hi @Paul-DS,
I just opened the issue #73 you asked some days ago.
thank you for your help

@manuelfrancisc
Copy link

Hi, @Paul-DS

u ok?

i have a bug using de calendar with asp net core 5 and vue js

<script src="https://unpkg.com/js-year-calendar@latest/dist/js-year-calendar.min.js"></script> <script src="https://unpkg.com/js-year-calendar@latest/locales/js-year-calendar.pt.js"></script> <script> new Calendar('.calendar', { style: 'background', minDate: new Date() }) </script>

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants