How to detect 'current week' for render days conditionally? - javascript

I discovered the dayRender function today (in the v4.0.0beta4 of fullCalendar.io).
My goal is render the previous weeks with gray background, the current week with white background e the future weeks with a third backgroundcolor.
Is there something in fullcalendar.io objects that can help me?
Using
dayRender: function(dayRenderInfo) {
console.log( $(dayRenderInfo.el).data('date') );
return dayRenderInfo.el;
}
I know that dayRenderInfo contains el, so using jQuery I can read $(el).data('date') to retrieve the date of the rendered day 'cell'.
But then, in js, how to check it, for example '2019-03-20' is the current week or past or future ?
I posted the question using fullcalendar tag because I hope there is an helper proprerty or similar, otherwiser, anyway, a plain js solution is very appreciated.

My solution is use the dayRender function of fullCalendar.io (actually #v4.0.1)
The function receive an HTML element already rendered. But you can intercept and manipulate it.
I decided to append an attribute, data-date, to the element so I can check it at runtime.
Note: I'm using jQuery.
dayRender: function(dayRenderInfo) {
// Make a Date object from current rendered element
const day = dayRenderInfo.el;
const date_str_of_this_day = $(day).data('date');
const this_day = new Date(date_str_of_this_day);
const today_string = new Date().toISOString().slice(0, 10);
// 0 (Sunday) ... 6 (Saturday)
let number_of_weekday = this_day.getDay();
if (number_of_weekday ==0) {
// I shift to adapt to italian week
// 1 (Monday) ... 7 (Sunday)
number_of_weekday = 7;
}
// From today's date object, I can find monday
let first = this_day.getDate() - number_of_weekday + 1;
const monday_date = new Date(this_day.setDate(first));
const monday_string = monday_date.toISOString().slice(0, 10);
// From monday's date object I can find sunday
let last = monday_date.getDate() + 6;
const sunday_date = new Date(this_day.setDate(last));
const sunday_string = sunday_date.toISOString().slice(0, 10);
if (sunday_string < today ) {
// the current day being renderer is AFTER current week
dayRenderInfo.el.style.backgroundColor = '#ededed';
} else if (today < monday_string ) {
// the current day being renderer is BEFORE current week
dayRenderInfo.el.style.backgroundColor = '#f9e9d7';
} else {
// the current day being renderer is PART OF curremt week
dayRenderInfo.el.style.backgroundColor = 'white';
}
// return altered html rendered
return dayRenderInfo.el;
},

Related

Calculate new date after calendar event drop

I have a JavaScript/Math question.
I am stuck with one task for two days now and I guess I am complete idiot as I can't figure it out...Screenshot
I am creating a week calendar with shifts from 7am untill 8pm., but I can have shift which is for example 2 days long (or more).
The problem is that I can drag and drop the calendar event on the calendar and then I need to calculate new dateTo from dateFrom which I get from the div I placed it on.
The issues is that when I try to drag and drop the item to another time I need to place dateFrom to whenever I dragged it, but then I need to calculate hours so I get the same amount of time, but the problem is when the event is stretched over multiple days I need the event to finish next date after 7 am and not in the middle of the night. For example I had event from 3pm to 5pm of next day and then I moved it to 7pm of next day so I need the event to finish at 9 am of next day.
Does anyone has the same issue or solution for this?
Hope it makes sense, thank you very much.
Here is the code I am using right now, it almost works, but sometimes I get the wrong date/time (usually it removes 10 hours from date).
export function getCorrectDateAfterDrop(originalDateFrom, originalDateTo, dateFrom) {
const NIGHT_TIME = 11;
dateFrom = moment(dateFrom);
originalDateTo = moment(originalDateTo);
originalDateFrom = moment(originalDateFrom);
let hoursDiff = moment.duration(originalDateTo.diff(originalDateFrom)).asHours();
const sign = Math.sign(hoursDiff);
if (originalDateTo.isAfter(moment(originalDateFrom).hours(20))) {
hoursDiff = (hoursDiff > NIGHT_TIME) ? (hoursDiff - NIGHT_TIME) : hoursDiff;
}
let finalDateToBeChecked = moment(dateFrom).add((hoursDiff * sign), 'hours');
let isDateFromSameAsDateTo = moment(dateFrom).isSame(finalDateToBeChecked, 'day');
if (isDateFromSameAsDateTo && finalDateToBeChecked.hours() < 20) {
// I think the problem is here, but I can't figure it out :D
return finalDateToBeChecked.format();
} else {
const diffUntilShiftEnds = moment.duration(moment(dateFrom).hours(20).diff(dateFrom)).asHours();
hoursDiff -= diffUntilShiftEnds;
const finalDateFrom = moment(dateFrom).add(1, 'days').hours(7);
const finalDateTo = moment(dateFrom).add(1, 'days').hours(7).add(hoursDiff, 'hours');
return getCorrectDateAfterDrop(finalDateFrom, finalDateTo, finalDateFrom);
}
}
Maybe I do not fully understand your question, but I think something like the following should work:
function getCorrectDateAfterDrop(originalDateFrom, originalDateTo, dateFrom) {
return originalDateTo - originalDateFrom + dateFrom;
}
// verify it works:
var origFrom = Date.parse('01 Jan 2018 05:00:00');
var origTo = Date.parse('02 Jan 2018 07:00:00');
var newFrom = Date.parse('02 Jan 2018 01:00:00');
var newTo = getCorrectDateAfterDrop(origFrom, origTo, newFrom)
console.log((Date.parse('03 Jan 2018 03:00:00') === newTo)) // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>

Creating a version number based on last modified date

My function looks like this:
$(document).ready(function(){
var d = new Date(document.lastModified);
// document.getElementById("lastup").innerHTML = d;
$("#lastup").html(d);
// Create a version number based on the date
var cy = new Date();
var y = cy.getFullYear()-2015; // ex: 2018 - 2015 = 3 third year of program
var mo = d.getMonth()+1; // ex: 2 = Feb
var dy = d.getDate(); // ex: 12 = Date of month
var v = 'v'+y+'.'+mo+'.'+dy; // ex: v3 = third year of program
$("#version2").html(v); // ex: v3.2.12
});
The goal being to create a version number based on the last time the page code was changed. You can see the year part is based on years the program has been in place. But the month and day take there values from 'd' which is the value of "new Date(document.lastModified)" put it all together and you get a version number. But in this case it gives me a new version number for every day, it does not hold the last modified data, it always increments based on the date. Somewhere I'm not seeing the obvious here. Why is it doing this?

Preventing Memory Leaks when removing DOM elements

I've been developing in Javascript for a while but the issue I am having with memory leaks is a little over my head. Apologies as this my be a long question but any help will be greatly appreciated.
I have a custom made table in a calendar format #sxpSolutionTblWrap which is dynamically populated using a template with details of each day. By default I load in 2 weeks, without weekends, so I populate 10 days worth of DOM elements.
Clicking on a day calls a function populateInfoPanel, in this function I call another function loadSingleSolutionRow where I find if a previous day has been selected in table and remove it, then populate it again with the basic info as if it weren't selected.
loadSingleSolutionRow
loadSingleSolutionRow: function(dow, dateValue, click, columnId) {
var self = this;
if (click === true) {
$('.sxpTableCol[data-colid="' + dow + '"]').empty();
}
//do stuff
var columnName = click === true ? '.sxpTableCol[data-colid="' + dow + '"]' : '#solCol' + columnId;
if (click === true) {
$(columnName).replaceWith(self.solutionTableRow({
dayId: dow,
date: selectedDate,
dateValue: dateValue,
statusClass: statusClass,
statusIconClass: statusIconClass,
trainerCountEarly: trainerCountEarly,
trainerListEarly: trainerListEarly,
roomCountEarly: roomCountEarly,
roomListEarly: rooomListEarly,
trainerCountLate: trainerCountLate,
trainerListLate: trainerListLate,
roomCountLate: roomCountLate,
roomListLate: rooomListLate,
protip: protip,
statusText: statusText,
}));
} else {
$(columnName).append(self.solutionTableRow({
dayId: dow,
date: selectedDate,
dateValue: dateValue,
statusClass: statusClass,
statusIconClass: statusIconClass,
trainerCountEarly: trainerCountEarly,
trainerListEarly: trainerListEarly,
roomCountEarly: roomCountEarly,
roomListEarly: rooomListEarly,
trainerCountLate: trainerCountLate,
trainerListLate: trainerListLate,
roomCountLate: roomCountLate,
roomListLate: rooomListLate,
protip: protip,
statusText: statusText,
}));
}
//Event listener for clicking on day
$('.sxpTableCol').off().on('click', '.sxpTableHeader', function (e) {
//populateInfoPanel
});
}
I then proceed to add events of each day to load onto the calendar in a for loop, that remove DOM elements previously in day and replaces it with new DOM element in the populateInfoPanel Function
populateInfoPanel
for (var j = 0; j < duration; j++) {
var dayCount = j + 1;
if (dayId !== undefined && daySolutions.Days[dayId].Solution !== undefined) {
//Getting day of solution in calendar grid
var daySolution = daySolutions.Days[dayId].Solution[j];
var solutionDayIndex = daySolution.DayIndex;
var solutionWeekIndex = daySolution.WeekNum;
var startWeek = moment(self.dto.startDate, 'YYYY-MM-DDTHH:mm').diff(moment(this.settings.findWhere({
Key: 'StartDate'
}).get('Value'), 'YYYY-MM-DD').startOf('isoWeek'), 'weeks') + 1;
var weekIndex = solutionWeekIndex - startWeek;
//var day = parseInt(dayId) + j;
var day = solutionDayIndex + (weekIndex * self.numDays);
//DO STUFF -- GETTING ROOM & TRAINER INFORMATION TO APPEND TO DOM
//DO STUFF -- GETTING POSITION OF ELEMENT ON THAT DAY
//DO STUFF -- GETTING LABELS THAT GO ONTO HEADER OF DAY
//APPEND DAY DETAILS TO CALENDAR
$(shiftData + day + '"]').append(self.selectedItemTpl({
dayCourse: dayCourse,
trainerList: trainerLabel,
roomList: roomLabel,
dayId: dayInfoId,
solutionId: j,
shiftId: shiftIndex,
day: day,
trainerIconClass: trainerIconClass,
roomIconClass: roomIconClass,
}));
}
}
The problem I am having is that when I click on a day and then another and another, it takes a little longer each time. This is fine when a solution only have 1 - 5 days on a 2 week grid, however it is very slow when a solution is 20 days long on a 5 week grid and the time when clicking through each day is more noticable.
The populateInfoPanel is about 500 lines long, unsure if that has anything to do with it. I am unsure if my method of removing elements isn't actually removing them from memory, if this is the case, how can I do this more effectively? Any help would be greatly appreciated.
From a 10 day solution on a grid of 5 weeks (25 days worth of DOM elements on Grid), here is the timeline view of clicking between days for 30 seconds, as you can see the first click takes 8 tenths of second, whereas the final click takes 1.5 seconds and gets more noticeable the more you click.
Below are some heap snapshots during 30 seconds of clicking between days, if you need to see anything further to get a better idea of what may be causing this issue, it would be very helpful
Before
Comparison

Make a date/time value called from an API tick very second. (JavaScript)

I'm calling a date and time through an API, which looks like this:
<?php $xml = simplexml_load_file("https://api.eveonline.com/server/ServerStatus.xml.aspx/"); ?>
<div class="server-time">
<?php echo $xml->currentTime; ?>
</div>
This will show a date and time like this on the page:
2013-10-16 08:15:36
Now I want this clock to tick every second and the time and even date (in case it's just seconds before midnight when the user visits the site) values to change accordingly, just like you would expect a digital clock to work.
I know this is possible with JavaScript but since I am a total rookie at it I don't know how to do this - at all.
Help would be highly appriciated!
There are many javascript clocks out there, you don't even have to use an API to get the time and date!
function clock(id) {
//Create a new Date object.
oDate = new Date();
//Get year (4 digits)
var year = oDate.getFullYear();
//Get month (0 - 11) - NOTE this is using indexes, so 0 = January.
var month = oDate.getMonth();
//Get day (1 - 31) - not using indexes.
var day = oDate.getDate();
//Get hours
var hours = oDate.getHours();
//Get minutes
var minutes = oDate.getMinutes();
//Get seconds
var seconds = oDate.getSeconds();
//Maybe create a function that adds leading zero's here
var dateStr = '';
dateStr += year+' - '+month+' - '+day+' '+hours+':'+minutes+':'+seconds;
//Append dateStr to some element.
document.getElementById(id).innerHTML = dateStr;
//Repeat the function every 1000 miliseconds aka 1 second
setTimeout(function() {
clock(id);
}, 1000);
}
The usage would be
<div id="yourID">clock input will go here</div>
clock('yourID');
NOTE
This function has to be called after the DOM is loaded, otherwise this would result in error.
This can be achieved by placing the script tag with your JS at the bottom of the page (not using jQuery that is).
Otherwise if using jQuery, call the $(function() {}) (equivelant to $(document).ready(function() {});
The function is quite self-explanatory, but maybe you would want to read up on the functions to see exactly what they do.
a quick google search should do the trick.
Anyways hope this helps, good luck :)
I'm not sure if you want it to fetch the time from the api every second or, if you want it to just increase every second, starting from the given api time. In the latter case, you should use setInterval:
function updateTime() {
// assuming you are using jquery for DOM manipulation:
var timestamp = $('.server-time').text();
var date = new Date(timestamp);
date.setSeconds(date.getSeconds() + 1);
$('.server-time').text(date.toString());
}
setInterval(updateTime, 1000);
If you are not using jquery, just use document.getElementById or something like that:
change your element to:
<div id="server-time">
and use the following snippet:
function updateTime() {
// assuming you are using jquery for DOM manipulation:
var timestamp = document.getElementById('server-time').innerHTML;
var date = new Date(timestamp);
date.setSeconds(date.getSeconds() + 1);
document.getElementById('server-time').innerHTML = date.toString();
}

Need explanation of this Date Processing function

Could anyone please explain the below code to me?
For example, i would like to set Today's date to today (21st of November, 2012) and the end date to the 3rd of December.
The reason for this is because i want to loop through a list of items, determine whether they are in the "past", "present" or "future" and assign a class to them accordingly.
I hope this makes sense! Any help is greatly appreciated and much welcomed!
function daysTilDate(expiredate){
expiredate ="12/"+expiredate+"/2012";
var thisDay=new Date(expiredate);
var CurrentDate = new Date();
var thisYear=CurrentDate.getFullYear();
thisDay.getFullYear(thisYear);
var DayCount=(thisDay-CurrentDate)/(1000*60*60*24);
DayCount=Math.round(DayCount);
return DayCount;
}
You can simplify the method like below if you want to calculate the days to an expire date. Please note that if you don't specify a test date, it'll take the current date as the test date.
​function ​daysTilData(expireDate, testDate) {
if(typeof testDate === "undefined"){
testDate = new Date(); // now
}
var diff = expireDate - testDate;
// minus value meaning expired days
return Math.round(diff/(1000*60*60*24));
}
alert(daysTilData(new Date("12/31/2012")));
// result 40
alert(daysTilData(new Date("12/31/2012"), new Date("1/12/2013")));
// result -12
Here's a line by line explanation.
The function declaration...
function daysTilDate(expiredate){
Takes the parameter expiredate sets it equal to the same value with "12/" prepended and "/2012" appended. so if the value of expiredate was "10", the new value is now "12/10/2012"...
expiredate ="12/"+expiredate+"/2012";
Instantiates a new Date object named thisDay using the expiredate string...
var thisDay=new Date(expiredate);
Instantiates a new Date object named CurrentDate, using the default constructor which will set the value equal to today's date...
var CurrentDate = new Date();
Gets just the Year segment from CurrentDate (which was earlier set to today's date)...
var thisYear=CurrentDate.getFullYear();
Gets the Year segment from thisDay (which was earlier set to "2012")...
thisDay.getFullYear(thisYear);
Gets the difference between thisDay and CurrentDate, which is in milliseconds, and multiplies that by 1000*60*60*24 to get the difference in days...
var DayCount=(thisDay-CurrentDate)/(1000*60*60*24);
Rounds the previously calculated difference...
DayCount=Math.round(DayCount);
Returns the difference between today and the passed-in day in December 2012...
return DayCount;
}
Note that the 2 lines that get the year segments are extraneous, because those values are never used...
I am not going to review the code, but I can answer your question of "I want to loop through a list of items, determine whether they are in the past, present, or future".
First, you want to construct your target date. If it's "now", just use new Date(). If it's a specific date, use new Date(dateString).
Second, Date objects in JavaScript have various members that return the date's characteristics. You can use this to compare dates. So, let's say you have your date strings in an array:
function loopDates(targetDateString, myDates) {
var targetDate, nextDate, status, ix;
targetDate = new Date(targetDateString);
for (ix = 0; ix < myDates.length; ++ix) {
nextDate = new Date(myDates[ix]);
if (nextDate.getFullYear() < targetDate.getFullYear()) {
status = "past";
} else if (nextDate.getFullYear() > targetDate.getFullYear()) {
status = "future";
} else {
// Year matches, compare month
if (nextDate.getMonth() < targetDate.getMonth()) {
status = "past";
} else if (nextDate.getMonth() > targetDate.getMonth()) {
status = "future";
} else {
// Month matches, compare day of month
if (nextDate.getDate() < targetDate.getDate()) {
status = "past";
} else if (nextDate.getDate() > targetDate.getDate()) {
status = "future";
} else {
// Day matches, present
status = "present";
}
}
}
console.log("Date " + myDates[ix] + " is " + status + " from " + targetDateString);
}
}
loopDates("11/17/2012", ["11/16/2012", "11/17/2012", "11/18/2012"]);
This will log:
Date 11/16/2012 is past from 11/17/2012
Date 11/17/2012 is present from 11/17/2012
Date 11/18/2012 is future from 11/17/2012
Working jsFiddle here.
If you want to work with a comprehensive Date class, use DateJS, an open source JavaScript date and time processing library with some impressive features.

Categories

Resources