Building a multi view calendar from scratch; weekly view algorithm - javascript

I am building a multi view calendar from scratch. I have an implementation working that sets the date to the correct date, and lets you toggle through the months.
My html for that implementation looks like this:
<div id="cal">
<div class="header">
<span class="left button" id="prev"> 〈 </span>
<span class="month-year" id="label"> June 2017 </span>
<span class="right button" id="next"> 〉 </span>
</div>
<table id="days">
<td>sun</td>
<td>mon</td>
<td>tue</td>
<td>wed</td>
<td>thu</td>
<td>fri</td>
<td>sat</td>
</table>
<div id="cal-frame">
<table class="curr">
<tbody>
<tr><td class="nil"></td><td class="nil"></td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
<tr><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td class="today">11</td><td>12</td></tr>
<tr><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td><td>18</td><td>19</td></tr>
<tr><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td><td>25</td><td>26</td></tr>
<tr><td>27</td><td>28</td><td>29</td><td>30</td><td class="nil"></td><td class="nil"></td><td class="nil"></td></tr>
</tbody>
</table>
</div>
and the javascript that accompanies it is this:
$(document).ready(function(){
var CALENDAR = function () {
var wrap, label,
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
function init(newWrap) {
wrap = $(newWrap || "#cal");
label = wrap.find("#label");
wrap.find("#prev").bind("click.calendar", function () { switchMonth(false); });
wrap.find("#next").bind("click.calendar", function () { switchMonth(true); });
label.bind("click", function () { switchMonth(null, new Date().getMonth(), new Date().getFullYear()); });
label.click();
}
function switchMonth(next, month, year) {
var curr = label.text().trim().split(" "), calendar, tempYear = parseInt(curr[1], 10);
if (!month) {
if (next) {
if (curr[0] === "December") {
month = 0;
} else {
month = months.indexOf(curr[0]) + 1;
}
} else {
if (curr[0] === "January") {
month = 11;
} else {
month = months.indexOf(curr[0]) - 1;
}
}
}
if (!year) {
if (next && month === 0) {
year = tempYear + 1;
} else if (!next && month === 11) {
year = tempYear - 1;
} else {
year = tempYear;
}
}
calendar = createCal(year, month);
$("#cal-frame", wrap)
.find(".curr")
.removeClass("curr")
.addClass("temp")
.end()
.prepend(calendar.calendar())
.find(".temp")
.fadeOut("slow", function () { $(this).remove(); });
$('#label').text(calendar.label);
}
function createCal(year, month) {
var day = 1, i, j, haveDays = true,
startDay = new Date(year, month, day).getDay(),
daysInMonths = [31, (((year%4==0)&&(year%100!=0))||(year%400==0)) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
calendar = [];
if (createCal.cache[year]) {
if (createCal.cache[year][month]) {
return createCal.cache[year][month];
}
}
else {
createCal.cache[year] = {};
}
i = 0;
while (haveDays) {
calendar[i] = [];
for (j = 0; j < 7; j++) {
if (i === 0) {
if (j === startDay) {
calendar[i][j] = day++;
startDay++;
}
} else if (day <= daysInMonths[month]) {
calendar[i][j] = day++;
} else {
calendar[i][j] = "";
haveDays = false;
}
if (day > daysInMonths[month]) {
haveDays = false;
}
}
i++;
}
if (calendar[5]) {
for (i = 0; i < calendar[5].length; i++) {
if (calendar[5][i] !== "") {
calendar[4][i] = "<span>" + calendar[4][i] + "</span><span>" + calendar[5][i] + "</span>";
}
}
calendar = calendar.slice(0, 5);
}
for (i = 0; i < calendar.length; i++) {
calendar[i] = "<tr><td>" + calendar[i].join("</td><td>") + "</td></tr>";
}
calendar = $("<table>" + calendar.join("") + "</table>").addClass("curr");
$("td:empty", calendar).addClass("nil");
if (month === new Date().getMonth()) {
$('td', calendar).filter(function () { return $(this).text() === new Date().getDate().toString(); }).addClass("today");
}
createCal.cache[year][month] = { calendar : function () { return calendar.clone() }, label : months[month] + " " + year };
return createCal.cache[year][month];
}
createCal.cache = {};
return {
init : init,
switchMonth : switchMonth,
createCal : createCal
};
};
var cal = CALENDAR();
cal.init();
});
This all works perfectly and is just provided for context. My issue is thar I am trying to implement the same feature for a weekly view (i.e. defaults to the current week, has the correct dates for that week, lists the month and year on the header, and lets you toggle through weeks. I tried using the month code as a guideline to implement the same idea for the weekly feature, but unforetunately it isn't working. I'm not sure if I need to find some new algorithm altogether, or whether the code can be modified, but I'm hoping for the latter. Let me know if you have any insight.
The html for week view looks like this:
<html>
<head>
</head>
<body>
<div id="weekCal">
<div class="header">
<span class="left button" id="prev"> 〈 </span>
<span class="month-year" id="label"> April 2017 </span>
<span class="right button" id="next"> 〉 </span>
</div>
<table id="days">
<td>sun</td>
<td>mon</td>
<td>tue</td>
<td>wed</td>
<td>thu</td>
<td>fri</td>
<td>sat</td>
</table>
<div id="cal-frame">
<table class="curr">
<tbody>
<tr><td class="nil"></td><td class="nil"></td><td>1</td><td class="today">2</td><td>3</td><td>4</td><td>5</td></tr>
</tbody>
</table>
</div>
</div>
The Javascript I tried to derive for the week view looks like this:
$(document).ready(function(){
var WEEKLY_CALENDAR = function () {
var weekWrap, weekLlabel,
weeks = ["Week1", "Week2", "Week3", "Week4", "Week 5", "Week 6", "Week 7", "Week 8", "Week 9", "Week 10", "Week 11", "Week 12"];
In the final implementation I am assuming I will need 52 weeks, but I started with 12 as an example kind of, just to see if it worked
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
Date.prototype.getWeek = function() {
var onejan = new Date(this.getFullYear(),0,1);
var today = new Date(this.getFullYear(),this.getMonth(),this.getDate());
var dayOfYear = ((today - onejan + 86400000)/86400000);
return Math.ceil(dayOfYear/7)
};
found this getWeek function at at JavaScript Date.getWeek()?
function init(newWrap) {
weekWrap = $(newWrap || "#weekCal");
label = wrap.find("#label");
wrap.find("#prev").bind("click.calendar", function () { switchWeek(false); });
wrap.find("#next").bind("click.calendar", function () { switchWeek(true); });
label.bind("click", function () { switchWeek(null, new Date().getWeek(), new Date().getMonth(), new Date().getFullYear()); });
label.click();
}
function switchWeek(next, week, month, year) {
var curr = label.text().trim().split(" "), calendar, tempYear = parseInt(curr[1], 10);
if (!week) {
if (next) {
if (curr[0] === "week 52") {
week = 0;
} else {
week = week.indexOf(curr[0]) + 1;
}
} else {
if (curr[0] === "week 1") {
week = 11;
} else {
week = weeks.indexOf(curr[0]) - 1;
}
}
}
if (!month) {
if (next) {
if (curr[0] === "December") {
month = 0;
} else {
month = months.indexOf(curr[0]) + 1;
}
} else {
if (curr[0] === "January") {
month = 11;
} else {
month = months.indexOf(curr[0]) - 1;
}
}
}
if (!year) {
if (next && month === 0) {
year = tempYear + 1;
} else if (!next && month === 11) {
year = tempYear - 1;
} else {
year = tempYear;
}
}
calendar = createCal(year, month, week);
$("#cal-frame", weekWrap)
.find(".curr")
.removeClass("curr")
.addClass("temp")
.end()
.prepend(calendar.calendar())
.find(".temp")
.fadeOut("slow", function () { $(this).remove(); });
$('#label').text(calendar.label);
}
function createCal(year, month, week) {
var day = 1, i, j, haveDays = true,
startDay = new Date(year, month, day).getDay(),
daysInMonths = [31, (((year%4==0)&&(year%100!=0))||(year%400==0)) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
calendar = [];
if (createCal.cache[year]) {
if (createCal.cache[year][week]) {
return createCal.cache[year][week];
}
}
else {
createCal.cache[year] = {};
}
i = 0;
while (haveDays) {
calendar[i] = [];
for (j = 0; j < 7; j++) {
if (i === 0) {
if (j === startDay) {
calendar[i][j] = day++;
startDay++;
}
} else if (day <= daysInMonths[month]) {
calendar[i][j] = day++;
} else {
calendar[i][j] = "";
haveDays = false;
}
if (day > daysInMonths[month]) {
haveDays = false;
}
}
i++;
}
if (calendar[5]) {
for (i = 0; i < calendar[5].length; i++) {
if (calendar[5][i] !== "") {
calendar[4][i] = "<span>" + calendar[4][i] + "</span><span>" + calendar[5][i] + "</span>";
}
}
calendar = calendar.slice(0, 5);
}
for (i = 0; i < calendar.length; i++) {
calendar[i] = "<tr><td>" + calendar[i].join("</td><td>") + "</td></tr>";
}
calendar = $("<table>" + calendar.join("") + "</table>").addClass("curr");
$("td:empty", calendar).addClass("nil");
if (month === new Date().getMonth()) {
$('td', calendar).filter(function () { return $(this).text() === new Date().getDate().toString(); }).addClass("today");
}
createCal.cache[year][week] = { calendar : function () { return calendar.clone() }, label : weeks[week] + " " + year };
return createCal.cache[year][week];
}
createCal.cache = {};
return {
init : init,
switchWeek : switchWeek,
createCal : createCal
};
};
var cal = CALENDAR();
cal.init();
});
I am fairly new to javascript and algorithms, so I'm a little lost on how to fix this. If you have any insight I'd love to hear it.

Not sure if this will work for you... Might take some major tweaks, but this should set you on the right path.. If not let me know.
function getWeek(fromDate) {
var sunday = new Date(fromDate.setDate(fromDate.getDate() - fromDate.getDay())),
result = [new Date(sunday)];
while (sunday.setDate(sunday.getDate() + 1) && sunday.getDay() !== 0) {
result.push(new Date(sunday));
}
return result;
}
// usage
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1; //January is 0!
var yyyy = today.getFullYear();
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
today = mm + '/' + dd + '/' + yyyy;
var week = getWeek(new Date(today));
var weekLayout = "";
for (i = 0; week.length > i; i++) {
var data = week[i];
weekLayout = weekLayout + "<li>" + data + "</li>";
}
$('.calendar').append("<ul>" + weekLayout + "</ul>");
var months = "";
var cal = false;
function getYear() {
var mthLayout = ""
console.log(months);
for (i = 0; months.length > i; i++) {
var data = months[i];
mthLayout = mthLayout + "<li>" + data + "</li>";
}
if($('.calendar').length > 0){
$('.calendar ul').remove(); $('.calendar').append("<ul>" + mthLayout + "</ul>");
} else {
$('.calendar').append("<ul>" + mthLayout + "</ul>");
}
}
function getDaysInMonth(month, year) {
var date = new Date(year, month, 1);
var days = [];
while (date.getMonth() === month) {
days.push(new Date(date));
date.setDate(date.getDate() + 1);
}
months = days;
}
$('a#mth').click(function(e) {
if(cal == false){
cal = true;
getDaysInMonth(4, 2017);
console.log(months);
getYear();
} else {
cal = false;
$('.calendar ul').remove(); $('.calendar').append("<ul>" + weekLayout + "</ul>");
}
e.preventDefault();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="calendar"></div>
Month

Related

Modifying JS code to remove DatePicker option

I'm trying to add a datepicker to a page I'm creating. Since I don't know much at all about Javascript I'm modifying an example I've found at https://code-boxx.com/simple-datepicker-pure-javascript-css/. I don't want any extra pages or files as I need the form I'm creating to be entirely self-contained. I've condensed it down to this:
<!DOCTYPE html>
<html>
<head>
<title>Simple Date Picker Example</title>
<style>
/* (A) POPUP */
.picker-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.5);
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
}
.picker-wrap.show {
opacity: 1;
visibility: visible;
}
.picker-wrap .picker {
margin: 50vh auto 0 auto;
transform: translateY(-50%);
}
/* (B) CONTAINER */
.picker {
max-width: 300px;
background: #444444;
padding: 10px;
}
/* (C) MONTH + YEAR */
.picker-m, .picker-y {
width: 50%;
padding: 5px;
box-sizing: border-box;
font-size: 16px;
}
/* (D) DAY */
.picker-d table {
color: #fff;
border-collapse: separate;
width: 100%;
margin-top: 10px;
}
.picker-d table td {
width: 14.28%; /* 7 EQUAL COLUMNS */
padding: 5px;
text-align: center;
}
/* HEADER CELLS */
.picker-d-h td {
font-weight: bold;
}
/* BLANK DATES */
.picker-d-b {
background: #4e4e4e;
}
/* TODAY */
.picker-d-td {
background: #d84f4f;
}
/* PICKABLE DATES */
.picker-d-d:hover {
cursor: pointer;
/* UNPICKABLE DATES */
.picker-d-dd {
color: #888;
background: #4e4e4e;
}
</style>
<!-- (A) LOAD DATE PICKER -->
<!--<link href="dp-dark.css" rel="stylesheet">-->
<link href="dp-light.css" rel="stylesheet" />
<script src="datepicker.js"></script>
</head>
<body>
<!-- (B) THE HTML -->
<!-- (B1) INLINE DATE PICKER -->
<input type="text" id="input-inline" placeholder="Inline" />
<div id="pick-inline"></div>
<!-- (B2) POPUP DATE PICKER -->
<input type="text" id="input-pop" placeholder="Popup" />
<!-- (C) ATTACH DATE PICKER ON LOAD -->
<script>
window.addEventListener("load", function () {
// (C1) INLINE DATE PICKER
picker.attach({
target: "input-inline",
container: "pick-inline",
});
// (C2) POPUP DATE PICKER
picker.attach({
target: "input-pop",
});
});
</script>
</body>
<script>
var picker = {
// (A) ATTACH DATEPICKER TO TARGET
// target : datepicker will populate this field
// container : datepicker will be generated in this container
// startmon : start on Monday (default false)
// disableday : array of days to disable, e.g. [2,7] to disable Tue and Sun
attach: function (opt) {
// (A1) CREATE NEW DATEPICKER
var dp = document.createElement("div");
dp.dataset.target = opt.target;
dp.dataset.startmon = opt.startmon ? "1" : "0";
dp.classList.add("picker");
if (opt.disableday) {
dp.dataset.disableday = JSON.stringify(opt.disableday);
}
// (A2) DEFAULT TO CURRENT MONTH + YEAR - NOTE: UTC+0!
var today = new Date(),
thisMonth = today.getUTCMonth(), // Note: Jan is 0
thisYear = today.getUTCFullYear(),
months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
// (A3) MONTH SELECT
var select = document.createElement("select"),
option = null;
select.classList.add("picker-m");
for (var mth in months) {
option = document.createElement("option");
option.value = parseInt(mth) + 1;
option.text = months[mth];
select.appendChild(option);
}
select.selectedIndex = thisMonth;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A4) YEAR SELECT
var yRange = 10; // Year range to show, I.E. from thisYear-yRange to thisYear+yRange
select = document.createElement("select");
select.classList.add("picker-y");
for (var y = thisYear - yRange; y < thisYear + yRange; y++) {
option = document.createElement("option");
option.value = y;
option.text = y;
select.appendChild(option);
}
select.selectedIndex = yRange;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A5) DAY SELECT
var days = document.createElement("div");
days.classList.add("picker-d");
dp.appendChild(days);
// (A6) ATTACH DATE PICKER TO TARGET CONTAINER + DRAW THE DATES
picker.draw(select);
// (A6-I) INLINE DATE PICKER
if (opt.container) {
document.getElementById(opt.container).appendChild(dp);
}
// (A6-P) POPUP DATE PICKER
else {
// (A6-P-1) MARK THIS AS A "POPUP"
var uniqueID = 0;
while (document.getElementById("picker-" + uniqueID) != null) {
uniqueID = Math.floor(Math.random() * (100 - 2)) + 1;
}
dp.dataset.popup = "1";
dp.dataset.dpid = uniqueID;
// (A6-P-2) CREATE WRAPPER
var wrapper = document.createElement("div");
wrapper.id = "picker-" + uniqueID;
wrapper.classList.add("picker-wrap");
wrapper.appendChild(dp);
// (A6-P-3) ATTACH ONCLICK TO SHOW/HIDE DATEPICKER
var target = document.getElementById(opt.target);
target.dataset.dp = uniqueID;
target.readOnly = true; // Prevent onscreen keyboar on mobile devices
target.onfocus = function () {
document
.getElementById("picker-" + this.dataset.dp)
.classList.add("show");
};
wrapper.addEventListener("click", function (evt) {
if (evt.target.classList.contains("picker-wrap")) {
this.classList.remove("show");
}
});
// (A6-P-4) ATTACH POPUP DATEPICKER TO BODY
document.body.appendChild(wrapper);
}
},
// (B) DRAW THE DAYS IN MONTH
// el : HTML reference to either year or month selector
draw: function (el) {
// (B1) GET DATE PICKER COMPONENTS
var parent = el.parentElement,
year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
days = parent.getElementsByClassName("picker-d")[0];
// (B2) DATE RANGE CALCULATION - NOTE: UTC+0!
var daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate(),
startDay = new Date(Date.UTC(year, month - 1, 1)).getUTCDay(), // Note: Sun = 0
endDay = new Date(Date.UTC(year, month - 1, daysInMonth)).getUTCDay(),
startDay = startDay == 0 ? 7 : startDay,
endDay = endDay == 0 ? 7 : endDay;
// (B3) GENERATE DATE SQUARES (IN ARRAY FIRST)
var squares = [],
disableday = null;
if (parent.dataset.disableday) {
disableday = JSON.parse(parent.dataset.disableday);
}
// (B4) EMPTY SQUARES BEFORE FIRST DAY OF MONTH
if (parent.dataset.startmon == "1" && startDay != 1) {
for (var i = 1; i < startDay; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && startDay != 7) {
for (var i = 0; i < startDay; i++) {
squares.push("B");
}
}
// (B5) DAYS OF MONTH
// (B5-1) ALL DAYS ENABLED, JUST ADD
if (disableday == null) {
for (var i = 1; i <= daysInMonth; i++) {
squares.push([i, false]);
}
}
// (B5-2) SOME DAYS DISABLED
else {
var thisday = startDay;
for (var i = 1; i <= daysInMonth; i++) {
// CHECK IF DAY IS DISABLED
var disabled = disableday.includes(thisday);
// DAY OF MONTH, DISABLED
squares.push([i, disabled]);
// NEXT DAY
thisday++;
if (thisday == 8) {
thisday = 1;
}
}
}
// (B6) EMPTY SQUARES AFTER LAST DAY OF MONTH
if (parent.dataset.startmon == "1" && endDay != 7) {
for (var i = endDay; i < 7; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && endDay != 6) {
for (var i = endDay; i < (endDay == 7 ? 13 : 6); i++) {
squares.push("B");
}
}
// (B7) DRAW HTML
var daynames = ["Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
if (parent.dataset.startmon == "1") {
daynames.push("Sun");
} else {
daynames.unshift("Sun");
}
// (B7-1) HTML DATE HEADER
var table = document.createElement("table"),
row = table.insertRow(),
cell = null;
row.classList.add("picker-d-h");
for (let d of daynames) {
cell = row.insertCell();
cell.innerHTML = d;
}
// (B7-2) HTML DATE CELLS
var total = squares.length,
row = table.insertRow(),
today = new Date(),
todayDate = null;
if (
today.getUTCMonth() + 1 == month &&
today.getUTCFullYear() == year
) {
todayDate = today.getUTCDate();
}
for (var i = 0; i < total; i++) {
if (i != total && i % 7 == 0) {
row = table.insertRow();
}
cell = row.insertCell();
if (squares[i] == "B") {
cell.classList.add("picker-d-b");
} else {
cell.innerHTML = squares[i][0];
// NOT ALLOWED TO CHOOSE THIS DAY
if (squares[i][1]) {
cell.classList.add("picker-d-dd");
}
// ALLOWED TO CHOOSE THIS DAY
else {
if (i == todayDate) {
cell.classList.add("picker-d-td");
}
cell.classList.add("picker-d-d");
cell.addEventListener("click", function () {
picker.pick(this);
});
}
}
}
// (B7-3) ATTACH NEW CALENDAR TO DATEPICKER
days.innerHTML = "";
days.appendChild(table);
},
// (C) CHOOSE A DATE
// el : HTML reference to selected date cell
pick: function (el) {
// (C1) GET ALL COMPONENTS
var parent = el.parentElement;
while (!parent.classList.contains("picker")) {
parent = parent.parentElement;
}
// (C2) GET FULL SELECTED YEAR MONTH DAY
var year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
day = el.innerHTML;
// YYYY-MM-DD FORMAT - CHANGE FORMAT HERE IF YOU WANT !
if (parseInt(month) < 10) {
month = "0" + month;
}
if (parseInt(day) < 10) {
day = "0" + day;
}
var fullDate = year + "-" + month + "-" + day;
// (C3) UPDATE SELECTED DATE
document.getElementById(parent.dataset.target).value = fullDate;
// (C4) POPUP ONLY - CLOSE THE POPUP
if (parent.dataset.popup == "1") {
document
.getElementById("picker-" + parent.dataset.dpid)
.classList.remove("show");
}
},
};
</script>
</html>
Since I don't want the inline date picker and only want the pop-up date picker, I thought all I would need to do is remove this section:
<!-- (B1) INLINE DATE PICKER -->
<input type="text" id="input-inline" placeholder="Inline"/>
<div id="pick-inline"></div>
but when I do that the pop-up stops working as well. What do I need to change to remove the inline but just keep the pop-up?
You commented the template code for the inline date picker, but you have not commented the script for inline date picker.
Comment out the below code to make your solution working.
// Comment this code block in script
picker.attach({
target: "input-inline",
container: "pick-inline",
});
Why this was throwing error?
The datepicker was trying to find a target from dom having id input-inline. Since you have commented it out, it will not be available. Thats why it was stoping the execution of javascript. The code got broken there and the lines below that is not executed. This is why your popup date picker was also not working.
Working Fiddle
window.addEventListener("load", function () {
// (C1) INLINE DATE PICKER
// picker.attach({
// target: "input-inline",
// container: "pick-inline",
// });
// (C2) POPUP DATE PICKER
picker.attach({
target: "input-pop",
});
});
var picker = {
// (A) ATTACH DATEPICKER TO TARGET
// target : datepicker will populate this field
// container : datepicker will be generated in this container
// startmon : start on Monday (default false)
// disableday : array of days to disable, e.g. [2,7] to disable Tue and Sun
attach: function (opt) {
// (A1) CREATE NEW DATEPICKER
var dp = document.createElement("div");
dp.dataset.target = opt.target;
dp.dataset.startmon = opt.startmon ? "1" : "0";
dp.classList.add("picker");
if (opt.disableday) {
dp.dataset.disableday = JSON.stringify(opt.disableday);
}
// (A2) DEFAULT TO CURRENT MONTH + YEAR - NOTE: UTC+0!
var today = new Date(),
thisMonth = today.getUTCMonth(), // Note: Jan is 0
thisYear = today.getUTCFullYear(),
months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
// (A3) MONTH SELECT
var select = document.createElement("select"),
option = null;
select.classList.add("picker-m");
for (var mth in months) {
option = document.createElement("option");
option.value = parseInt(mth) + 1;
option.text = months[mth];
select.appendChild(option);
}
select.selectedIndex = thisMonth;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A4) YEAR SELECT
var yRange = 10; // Year range to show, I.E. from thisYear-yRange to thisYear+yRange
select = document.createElement("select");
select.classList.add("picker-y");
for (var y = thisYear - yRange; y < thisYear + yRange; y++) {
option = document.createElement("option");
option.value = y;
option.text = y;
select.appendChild(option);
}
select.selectedIndex = yRange;
select.addEventListener("change", function () {
picker.draw(this);
});
dp.appendChild(select);
// (A5) DAY SELECT
var days = document.createElement("div");
days.classList.add("picker-d");
dp.appendChild(days);
// (A6) ATTACH DATE PICKER TO TARGET CONTAINER + DRAW THE DATES
picker.draw(select);
// (A6-I) INLINE DATE PICKER
if (opt.container) {
document.getElementById(opt.container).appendChild(dp);
}
// (A6-P) POPUP DATE PICKER
else {
// (A6-P-1) MARK THIS AS A "POPUP"
var uniqueID = 0;
while (document.getElementById("picker-" + uniqueID) != null) {
uniqueID = Math.floor(Math.random() * (100 - 2)) + 1;
}
dp.dataset.popup = "1";
dp.dataset.dpid = uniqueID;
// (A6-P-2) CREATE WRAPPER
var wrapper = document.createElement("div");
wrapper.id = "picker-" + uniqueID;
wrapper.classList.add("picker-wrap");
wrapper.appendChild(dp);
// (A6-P-3) ATTACH ONCLICK TO SHOW/HIDE DATEPICKER
var target = document.getElementById(opt.target);
target.dataset.dp = uniqueID;
target.readOnly = true; // Prevent onscreen keyboar on mobile devices
target.onfocus = function () {
document
.getElementById("picker-" + this.dataset.dp)
.classList.add("show");
};
wrapper.addEventListener("click", function (evt) {
if (evt.target.classList.contains("picker-wrap")) {
this.classList.remove("show");
}
});
// (A6-P-4) ATTACH POPUP DATEPICKER TO BODY
document.body.appendChild(wrapper);
}
},
// (B) DRAW THE DAYS IN MONTH
// el : HTML reference to either year or month selector
draw: function (el) {
// (B1) GET DATE PICKER COMPONENTS
var parent = el.parentElement,
year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
days = parent.getElementsByClassName("picker-d")[0];
// (B2) DATE RANGE CALCULATION - NOTE: UTC+0!
var daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate(),
startDay = new Date(Date.UTC(year, month - 1, 1)).getUTCDay(), // Note: Sun = 0
endDay = new Date(Date.UTC(year, month - 1, daysInMonth)).getUTCDay(),
startDay = startDay == 0 ? 7 : startDay,
endDay = endDay == 0 ? 7 : endDay;
// (B3) GENERATE DATE SQUARES (IN ARRAY FIRST)
var squares = [],
disableday = null;
if (parent.dataset.disableday) {
disableday = JSON.parse(parent.dataset.disableday);
}
// (B4) EMPTY SQUARES BEFORE FIRST DAY OF MONTH
if (parent.dataset.startmon == "1" && startDay != 1) {
for (var i = 1; i < startDay; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && startDay != 7) {
for (var i = 0; i < startDay; i++) {
squares.push("B");
}
}
// (B5) DAYS OF MONTH
// (B5-1) ALL DAYS ENABLED, JUST ADD
if (disableday == null) {
for (var i = 1; i <= daysInMonth; i++) {
squares.push([i, false]);
}
}
// (B5-2) SOME DAYS DISABLED
else {
var thisday = startDay;
for (var i = 1; i <= daysInMonth; i++) {
// CHECK IF DAY IS DISABLED
var disabled = disableday.includes(thisday);
// DAY OF MONTH, DISABLED
squares.push([i, disabled]);
// NEXT DAY
thisday++;
if (thisday == 8) {
thisday = 1;
}
}
}
// (B6) EMPTY SQUARES AFTER LAST DAY OF MONTH
if (parent.dataset.startmon == "1" && endDay != 7) {
for (var i = endDay; i < 7; i++) {
squares.push("B");
}
}
if (parent.dataset.startmon == "0" && endDay != 6) {
for (var i = endDay; i < (endDay == 7 ? 13 : 6); i++) {
squares.push("B");
}
}
// (B7) DRAW HTML
var daynames = ["Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
if (parent.dataset.startmon == "1") {
daynames.push("Sun");
} else {
daynames.unshift("Sun");
}
// (B7-1) HTML DATE HEADER
var table = document.createElement("table"),
row = table.insertRow(),
cell = null;
row.classList.add("picker-d-h");
for (let d of daynames) {
cell = row.insertCell();
cell.innerHTML = d;
}
// (B7-2) HTML DATE CELLS
var total = squares.length,
row = table.insertRow(),
today = new Date(),
todayDate = null;
if (
today.getUTCMonth() + 1 == month &&
today.getUTCFullYear() == year
) {
todayDate = today.getUTCDate();
}
for (var i = 0; i < total; i++) {
if (i != total && i % 7 == 0) {
row = table.insertRow();
}
cell = row.insertCell();
if (squares[i] == "B") {
cell.classList.add("picker-d-b");
} else {
cell.innerHTML = squares[i][0];
// NOT ALLOWED TO CHOOSE THIS DAY
if (squares[i][1]) {
cell.classList.add("picker-d-dd");
}
// ALLOWED TO CHOOSE THIS DAY
else {
if (i == todayDate) {
cell.classList.add("picker-d-td");
}
cell.classList.add("picker-d-d");
cell.addEventListener("click", function () {
picker.pick(this);
});
}
}
}
// (B7-3) ATTACH NEW CALENDAR TO DATEPICKER
days.innerHTML = "";
days.appendChild(table);
},
// (C) CHOOSE A DATE
// el : HTML reference to selected date cell
pick: function (el) {
// (C1) GET ALL COMPONENTS
var parent = el.parentElement;
while (!parent.classList.contains("picker")) {
parent = parent.parentElement;
}
// (C2) GET FULL SELECTED YEAR MONTH DAY
var year = parent.getElementsByClassName("picker-y")[0].value,
month = parent.getElementsByClassName("picker-m")[0].value,
day = el.innerHTML;
// YYYY-MM-DD FORMAT - CHANGE FORMAT HERE IF YOU WANT !
if (parseInt(month) < 10) {
month = "0" + month;
}
if (parseInt(day) < 10) {
day = "0" + day;
}
var fullDate = year + "-" + month + "-" + day;
// (C3) UPDATE SELECTED DATE
document.getElementById(parent.dataset.target).value = fullDate;
// (C4) POPUP ONLY - CLOSE THE POPUP
if (parent.dataset.popup == "1") {
document
.getElementById("picker-" + parent.dataset.dpid)
.classList.remove("show");
}
},
};
/* (A) POPUP */
.picker-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
}
.picker-wrap.show {
opacity: 1;
visibility: visible;
}
.picker-wrap .picker {
margin: 50vh auto 0 auto;
transform: translateY(-50%);
}
/* (B) CONTAINER */
.picker {
max-width: 300px;
background: #444444;
padding: 10px;
}
/* (C) MONTH + YEAR */
.picker-m,
.picker-y {
width: 50%;
padding: 5px;
box-sizing: border-box;
font-size: 16px;
}
/* (D) DAY */
.picker-d table {
color: #fff;
border-collapse: separate;
width: 100%;
margin-top: 10px;
}
.picker-d table td {
width: 14.28%;
/* 7 EQUAL COLUMNS */
padding: 5px;
text-align: center;
}
/* HEADER CELLS */
.picker-d-h td {
font-weight: bold;
}
/* BLANK DATES */
.picker-d-b {
background: #4e4e4e;
}
/* TODAY */
.picker-d-td {
background: #d84f4f;
}
/* PICKABLE DATES */
.picker-d-d:hover {
cursor: pointer;
/* UNPICKABLE DATES */
.picker-d-dd {
color: #888;
background: #4e4e4e;
}
}
<!-- (B) THE HTML -->
<!-- (B1) INLINE DATE PICKER -->
<!-- <input type="text" id="input-inline" placeholder="Inline" />
<div id="pick-inline"></div> -->
<!-- (B2) POPUP DATE PICKER -->
<input type="text" id="input-pop" placeholder="Popup" />

Javascript app freezing after approximately two hours (memory leak?)

I'm currently developing a home automation user interface, running on a wall-mounted android (version 4.2.2) tablet, which, after a couple of minutes of inactivity, displays a "screensaver" html page.
As you can see in the screenshot above, this "screensaver" basically consists of the following features :
a clock displaying the current time and date, triggered by the script date_time.js and refreshed at one second interval;
a picture on the top right-hand side which shows the current status of the alarm;
a picture "Touchez l'écran pour quitter le mode veille" which is randomly repositioned every 3500 miliseconds.
Both points 2) and 3) above are run by another script stored in a script called "screensaver_run.js". The method getAlarmDataFromDatabase is retrieving data from my mysql database.
Now, for the problem statement: after approximately two hours, the whole screen freezes (both the clock and the repositioning script) in such a way that even the tablet is no longer pingable. I suspect that a memory leak is occurring but after a couple of sleepless nights ... and a lot of coffee ... I am not able to find out the root cause of my issue.
Reading some documentation on the internet, notably https://www.lambdatest.com/blog/eradicating-memory-leaks-in-javascript, I have already implemented some changes such as changing the declaration of the variables from "var" to "let".
In Chrome, I run the script during 2 1/2 minutes and profiled the memory usage (I have the heaptimeline file available, if it can be of any help, but here I'm not quite sure how to analyse it?):
Besides, I queried the console for :
performance.memory.usedJSHeapSize and got some changing values :
3430886, 3195206, 4743246, 3402767, etc
performance.memory.jsHeapSizeLimit and got : 4294705152
Does anyone have any hint where to start investigating, knowing that debugging possibilities of this tablet are not as advanced as on a modern browser? My tablet is "already" 5 years old... Upgrading this tablet is not an option.
Many thanks for your time reading me and I do hope that my post is understandable, well documented and in the future, could help other to have restful nights :)
The code of my html page (named after 'screen_saver.html) is the following :
<!DOCTYPE html>
<html>
<head>
<title>Domoos | Screen saver screen</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<meta http-equiv="pragma" content="no-cache">
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" type="text/css" href="css/mystyle_saver.css?rnd=999" />
<script type="text/javascript" src="scripts/date_time.js"></script>
<script type="text/javascript" src="scripts/screensaver_run.js"></script>
</head>
<body onload="runScreenSaver(); setup();">
<div style="position:absolute" id="randomPlacement">
<p><img src="assets/pictures/texte_sortie_veille.png" alt ="" style="width:90px;height:90px;" border="0"></p>
</div>
<div id="svg">
<svg height="210" width="1020">
<line x1="11" y1="100" x2="1015" y2="100" style="stroke:rgb(69,69,66);stroke-width:3" />
</svg>
</div>
<div id="date"></div>
<div id="time"></div>
<div id="icon_alarm">
<img id="img_alarm" src="assets/icons/alarme_eteinte.png" alt ="" style="width:27px;height:35px;">
</div>
<div id="tag_temperature">
<p>21°C</p>
</div>
<div id="tag_free_text">
<p>151<sup>ème</sup> jour de l'année 2020.<br>Bonsoir</p>
</div>
<div id="meteo_icon">
<img src="assets/meteo_icons/eclaircies-big.png" alt="" style="width:40px;height:40px;">
</div>
<div id="tag_weather_condition">
<p>Eclaircies</p>
</div>
</body>
</html>
Code of my javasript file screensaver_run.js:
function runScreenSaver()
{
let xmin = 0;
let xmax = 890;
let ymin = 0;
let ymax = 430;
let sDate;
let sTime;
let bOverlapAuthorised;
let bDisplayPos;
let zRandomImage;
let xCoord;
let yCoord;
let xCoordStr;
let yCoordStr;
bOverlapAuthorised = true;
bDisplayPos = false;
// If overlap is forbidden, the x min and y min parameters will be redefined to be slightly below the line
if (!bOverlapAuthorised)
{
xmin = 15;
ymin = 130;
}
// Computes a random x and y, based on the min and ma
xCoord = Math.floor((Math.random()*xmax)+xmin);
yCoord = Math.floor((Math.random()*ymax)+ymin);
xCoordStr = xCoord.toString() + "px";
yCoordStr = yCoord.toString() + "px";
zRandomImage = document.getElementById("randomPlacement");
zRandomImage.style.left = xCoordStr;
zRandomImage.style.top = yCoordStr;
// Instead of displaying a message in the 'tag_free_text',
// shows the randomly defined coordinates of the 'randomPlacement' object
if (bDisplayPos)
{
document.getElementById("tag_free_text").innerHTML = 'X:' + xCoordStr + '<br>Y:' + yCoordStr;
}
document.getElementById("date").innerhtml=getTimeDate('date');
getAlarmDataFromDatabase();
zRandomImage = null;
xCoord = null;
yCoord = null;
xCoordStr = null;
yCoordStr = null;
setTimeout('runScreenSaver()','3500');
}
function setup()
{
this.addEventListener("mousemove", exitScreenSaver, false);
this.addEventListener("mousedown", exitScreenSaver, false);
this.addEventListener("keypress", exitScreenSaver, false);
this.addEventListener("DOMMouseScroll", exitScreenSaver, false);
this.addEventListener("mousewheel", exitScreenSaver, false);
this.addEventListener("touchstart", exitScreenSaver, false);
this.addEventListener("MSPointerMove", exitScreenSaver, false);
}
function getAlarmDataFromDatabase()
{
let ajax = new XMLHttpRequest();
let id_component;
let technical_name_html;
let comp_value;
let data;
ajax.open("GET", "php/data4screensaver1.php", true);
ajax.send();
ajax.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200)
{
data = JSON.parse(this.responseText);
for(var a = 0; a < data.length; a++)
{
id_component = data[a]['id_component'];
technical_name_html = data[a]['technical_name_html'];
comp_value = parseInt(data[a]['value']);
}
data = null;
console.log("ID Component: " + id_component);
//console.log("Valeur de l'alarme : " + comp_value);
switch (comp_value)
{
case 0:
case 50:
case 100:
displayPictureAlarm(comp_value);
break;
default:
displayPictureAlarm(-1);
break;
}
}
};
ajax = null;
id_component = null;
technical_name_html = null;
comp_value = null;
}
function exitScreenSaver(e)
{
goActive(e);
}
function goActive(event)
{
// do something
console.log(".. active ..");
//event.preventDefault();
this.removeEventListener("mousemove", exitScreenSaver);
this.removeEventListener("mousedown", exitScreenSaver);
this.removeEventListener("keypress", exitScreenSaver);
this.removeEventListener("DOMMouseScroll", exitScreenSaver);
this.removeEventListener("mousewheel", exitScreenSaver);
this.removeEventListener("touchstart", exitScreenSaver);
this.removeEventListener("MSPointerMove", exitScreenSaver);
window.open("index.html","_self");
}
function displayPictureAlarm(pValue)
{
let z;
z = document.getElementById("img_alarm");
if (pValue == 0) // désarmée
{
z.src = "assets/icons/alarme_desarmee.png";
}
if (pValue == 50) // partielle
{
z.src = "assets/icons/alarme_partielle.png";
}
if (pValue == 100) // totale
{
z.src = "assets/icons/alarme_totale.png";
}
if (pValue == -1) // éteinte
{
z.src = "assets/icons/alarme_eteinte.png";
}
z = null;
}
Code of my javascript file datetime.js (as called in the the method runScreenSaver above):
function getDate(id)
{
date = new Date;
year = date.getFullYear();
month = date.getMonth();
month += 1;
d = date.getDate();
day = date.getDay();
days = new Array('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi');
if (d<10)
{
d = "0"+d;
}
if(month<10)
{
month = "0"+month;
}
result = ''+days[day]+' '+d+'.'+month+'.'+year;
result = days[day]+' '+d+'.'+month+'.'+year;
document.getElementById(id).innerHTML = result;
setTimeout('getDate("'+id+'");','1000');
return true;
}
function getTimeDateMainScreen()
{
var za;
var zb;
var zc;
var mydate;
var result1;
var result2;
var result3;
mydate = new Date;
year = mydate.getFullYear();
month = mydate.getMonth();
day = mydate.getDate();
weekday = mydate.getDay();
hrs = mydate.getHours();
mns = mydate.getMinutes();
secs = mydate.getSeconds();
days = new Array('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi');
month += 1;
if (day < 10)
{
day = "0" + day;
}
if(month < 10)
{
month = "0" + month;
}
if(hrs < 10)
{
hrs = "0" + hrs;
}
if(mns < 10)
{
mns = "0" + mns;
}
if(secs < 10)
{
secs = "0" + secs;
}
//result = ''+days[weekday]+' '+d+'.'+month+'.'+year;
//result = days[weekday]+' '+d+'.'+month+'.'+year;
result1 = day + "." + month + "." + year;
result2 = days[weekday];
result3 = hrs + ":" + mns + ":" + secs;
za = document.getElementById("curr_date");
zb = document.getElementById("curr_weekday");
zc = document.getElementById("curr_time");
za.innerHTML = result1;
zb.innerHTML = result2;
zc.innerHTML = result3;
za = null;
zb = null;
zc = null;
mydate = null;
result1 = null;
result2 = null;
result3 = null;
setTimeout('getTimeDateMainScreen();','500');
}
function getTime(id)
{
date = new Date;
h = date.getHours();
if(h<10)
{
h = "0"+h;
}
m = date.getMinutes();
if(m<10)
{
m = "0"+m;
}
s = date.getSeconds();
if(s<10)
{
s = "0"+s;
}
result = ''+h+':'+m+':'+s;
document.getElementById(id).innerHTML = result;
setTimeout('getTime("'+id+'");','1000');
return true;
}
function getTime2()
{
date = new Date;
h = date.getHours();
if(h<10)
{
h = "0"+h;
}
m = date.getMinutes();
if(m<10)
{
m = "0"+m;
}
s = date.getSeconds();
if(s<10)
{
s = "0"+s;
}
result = ''+h+':'+m+':'+s;
document.getElementById("time").innerHTML = result;
setTimeout('getTime2();','1000');
}
function getTimeDate(id)
{
let date;
let year;
let month;
let d;
let day;
let days;
let h;
let m;
let s;
let result;
date = new Date;
console.log("J'affiche la date3");
year = date.getFullYear();
month = date.getMonth();
month += 1;
d = date.getDate();
day = date.getDay();
days = new Array('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi');
h = date.getHours();
m = date.getMinutes();
s = date.getSeconds();
if (d<10)
{
d = "0"+d;
}
if(month<10)
{
month = "0"+month;
}
if(h<10)
{
h = "0"+h;
}
if(m<10)
{
m = "0"+m;
}
if(s<10)
{
s = "0"+s;
}
result = ''+days[day]+' '+d+'.'+month+'.'+year +' ' + h+':'+m+':'+s;
document.getElementById(id).innerHTML = result;
date = null;
year = null;
month = null;
d = null;
day = null;
days = null;
h = null;
m = null;
s = null;
result = null;
setTimeout('getTimeDate("'+id+'");','1000');
return true;
}
And, finally, here is my php (data4screensaver1.php) to retrieve the data from my mysql database :
<?php
$host = "ip_Address_db";
$db_user_encoded = "user_encoded";
$db_password_encoded = "pw_encoded";
$db_name_encoded = "db_name_encoded";
$conn = mysqli_connect($host, (encrypt_decrypt('decrypt', $db_user_encoded)), (encrypt_decrypt('decrypt', $db_password_encoded)), (encrypt_decrypt('decrypt', $db_name_encoded )));
$result = mysqli_query($conn, "CALL sp_tbl_domotique_components_get_lab61()");
$data = array();
while ($row = mysqli_fetch_object($result))
{
array_push($data, $row);
}
echo json_encode($data);
exit();
function encrypt_decrypt($action, $string)
{
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = '$SecretKey$';
$secret_iv = '$SecretIV$';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if ( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
} else if( $action == 'decrypt' ) {
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
?>

Ajax Request Not Always Consistent

I have been developing a site that will provide schedules created by people. I'm using Alienware to develop it and the ajax code works perfectly on the laptop all of the time. I am using IE. However, if I access my site on my Samsung Smart TV or my HTC U11 phone, Ajax isn't consistent. It displays the data I am requesting, however, when I sum up a total of hours for the week, it sometimes displays the correct hours, or sometimes shows 0 hours, when the user is scheduled for the week. Why is it inconsistent between devices? I know that Ajax is recommended for IE. As I said, though, it sometimes will display the correct total weekly hours, and other times it will just show zero. This issue isn't occurring on my Alienware.
I've already tried using onload instead of onreadystatechange. I've set the request to asynchronous and synchronous. Whether it's set to true or false, on my other devices, it fails to be consistent. I've tried it as a post and get method, and both also are inconsistent. What is wrong with my code?
function getThisWeek(str5) {
lastDate = new Date(str5);
// getting dates for this week to be displayed...
this.math = dayInput.length - 1;
this.math0 = 0 - new Date(str5).getDay();
// getting week total hour length, to determine how many times this code executes...
weekSum = 0;
totals = [];
for (this.i = 0; this.i < weekTotalHours.length; this.i++) {
str3 = this.i;
this.date = new Date(str5);
for (this.ii = (this.i * (7)) - new Date().getDay(); this.ii < (7 * (this.i + 1)) - new Date().getDay(); this.ii++) {
totalHours = 0;
this.date = new Date(str5);
this.date = new Date(this.date.setDate(this.date.getDate() + (this.ii)));
// which element position the total daily hours belongs to when displaying them...
this.pos = this.ii + new Date().getDay();
thisDayChart[this.pos].innerHTML = "";
// displaying the date
dayInput[this.pos].innerHTML = this.date.getDate();
// highlighting today's date...
if (this.date.getDate() == new Date(str5).getDate() && this.date.getMonth() == new Date().getMonth()) {
dayInput[this.pos].style.color = "white";
dayInput[this.pos].style.backgroundColor = "silver";
dayInput[this.pos].style.borderRadius = "0px";
thisDay[this.pos].style.border = "2px double lightblue";
} else {
dayInput[this.pos].style.color = "";
dayInput[this.pos].style.backgroundColor = "";
dayInput[this.pos].style.borderRadius = "";
thisDay[this.pos].style.border = "";
}
// getting schedule from database...
this.xmlhttp = new XMLHttpRequest();
this.xmlhttp.pos = this.pos;
this.xmlhttp.ipos = this.i;
this.xmlhttp.d = months[this.date.getMonth()] + " " + this.date.getDate() + ", " + this.date.getFullYear();
this.xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//alert(this.responseText);
dayInput[this.pos].m = months[new Date(this.d).getMonth()];
dayInput[this.pos].weekDay = days[new Date(this.d).getDay()];
// how many weeks in the year is user...
this.islpyr = new Date(this.d);
this.islpyr = this.islpyr.setMonth(1);
this.islpyr = new Date(new Date(this.islpyr).setDate(29));
if (this.islpyr.getMonth() == 2) {
mlens[1] = 28;
} else {
mlens[1] = 29;
}
// getting total amount of days for the year...
this.yrlen = 0;
for (this.iii = 0; this.iii < mlens.length; this.iii++) {
this.yrlen += mlens[this.iii];
}
// getting total weeks
this.wklen = this.yrlen / 7;
this.wklen = Math.round(this.wklen);
this.week = 0;
for (this.iii = 0; this.iii < new Date(this.d).getMonth(); this.iii++) {
this.week += mlens[this.iii];
}
this.week += new Date(this.d).getDate();
this.week /= 7;
this.week = Math.round(this.week) + 1;
// rounding and displaying current week number...
if (new Date(this.d).getDay() == 0) {
myDayWrapper[this.ipos].weekLabel = "Week " + this.week + " of " + this.wklen;
}
if (this.pos == 0) {
weekDisplay[0].innerHTML = myDayWrapper[0].weekLabel;
}
// which day of the year it is... how many days in the year is the user...
this.yrpos = 0;
for (this.iv = 0; this.iv < new Date(this.d).getMonth(); this.iv++) {
this.yrpos += mlens[this.iv];
}
this.yrpos += new Date(this.d).getDate();
thisDayTitle[this.pos].innerHTML = "Day " + this.yrpos + " of " + this.yrlen;
totalHours = 0;
this.schedule = "" + this.responseText;
// if user is unscheduled, do this first... 'undefined' literally means there isn't a schedule for that specific day.
if (this.schedule.search("Undefined") >= 0) {
this.elem = document.createElement("div");
this.elem.setAttribute("class","not_scheduled");
this.elem.innerHTML = "Unscheduled";
thisDayChart[this.pos].appendChild(this.elem);
this.elem = document.createElement("div");
this.elem.setAttribute("class","pick_up_shift_btn");
this.elem.innerHTML = "Claim Shifts";
this.elem.i = this.pos;
this.elem.ipos = this.ipos;
this.elem.onclick = function() {
popUpWrap[1].style.display = "block";
this.datesd = [];
for (this.i = this.ipos * 7; this.i < 7 * (this.ipos + 1); this.i++) {
this.datesd.push(dayInput[this.i].innerHTML);
}
for (this.i = 0; this.i < 7; this.i++) {
shiftClaimDate[this.i].innerHTML = this.datesd[this.i];
popUpShiftDay[this.i].innerHTML = dayInput[this.i].weekDay;
this.strrr = "" + dayInput[this.i].m;
this.strrr = this.strrr.substring(0,3);
shiftClaimMonth[this.i].innerHTML = this.strrr;
}
}
thisDayChart[this.pos].appendChild(this.elem);
if (totals.length - 1 == this.pos) {
} else {
totals.push(0);
}
} else {
// getting daily total...
this.schedule = this.schedule.split(",");
for (this.iii = 0; this.iii < this.schedule.length; this.iii++) {
this.str = "" + this.schedule[this.iii];
this.str = this.str.split("=");
this.dateString = "December 22, 1991";
switch (this.str[0]) {
case "shift_start":
this.start = new Date(this.dateString + " " + this.str[1]);
this.end = this.schedule[this.schedule.length - 1] + "";
this.end = this.end.split("=");
this.end = new Date(this.dateString + " " + this.end[1]);
this.hours = (this.end.getHours() - this.start.getHours()) * 60;
this.hours = this.hours - (this.start.getMinutes() + this.end.getMinutes());
this.hours /= 60;
totalHours += this.hours;
weekSum += totalHours;
break;
case "break_start":
this.start = new Date(this.dateString + " " + this.str[1]);
this.end = this.schedule[this.iii + 1] + "";
this.end = this.end.split("=");
this.end = new Date(this.dateString + " " + this.end[1]);
this.hours = (this.end.getHours() - this.start.getHours()) * 60;
this.hours = this.hours - (this.start.getMinutes() + this.end.getMinutes());
this.hours /= 60;
weekSum -= this.hours;
totalHours -= this.hours;
this.s = "s";
if (totalHours == 1) {
this.s = "";
}
thisDayChart[this.pos].innerHTML = totalHours + " hour" + this.s;
break;
}
}
}
weekTotalHours[this.ipos].innerHTML = "Week Total: " + weekSum;
//alert(weekSum);
// displaying hour totals...
if (new Date(this.d).getDay() == 6) {
weekSum = 0;
}
totalHours = 0;
}
}
this.xmlhttp.open("GET","/js/data/schedule.html?date="+ months[this.date.getMonth()] + " " + this.date.getDate() + ", " + this.date.getFullYear(),false);
this.xmlhttp.send();
}
}
}
I expect every device to be consistent with the hour total it should be displaying, on every device that Ajax should work on.

Javascript Booking Year Calendar

I'm looking for year calendar with select range functions, but i don't found this. And I decided customize Bootstrap Year Calendar - http://www.bootstrap-year-calendar.com/
And I'm stuck, my customised version is on http://ngrdanjski.com/calendar/
and I'm looking for help!
I added:
All days are disabled by default.
You can added Price periods, in this dates period you have enabled booking.
I want to add option when first click on the day it's first day of booking range, and second click is last day of booking range. Right now when click on day you have enable start date/first day, but when you click second time on day when you want to select end date, it's again start/first date. I wan't to have function to select start and end date. First click on day is start and second is end.
Code for current behavior is:
if(this.options.enableRangeSelection) {
cells.mousedown(function (e) {
if(e.which == 1)
{
var currentDate = _this._getDate($(this));
//console.log(currentDate);
if(_this.options.allowOverlap || _this.getEvents(currentDate).length == 0)
{
_this._mouseDown = true;
_this._rangeStart = _this._rangeEnd = currentDate;
_this._refreshRange();
}
}
});
cells.mouseenter(function (e) {
//console.log(e);
if (_this._mouseDown)
{
var currentDate = _this._getDate($(this));
if(!_this.options.allowOverlap)
{
var newDate = new Date(_this._rangeStart.getTime());
if(newDate < currentDate)
{
var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() + 1);
while(newDate < currentDate)
{
if(_this.getEvents(nextDate).length > 0)
{
break;
}
newDate.setDate(newDate.getDate() + 1);
nextDate.setDate(nextDate.getDate() + 1);
}
}
else
{
var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() - 1);
while(newDate > currentDate)
{
if(_this.getEvents(nextDate).length > 0)
{
break;
}
newDate.setDate(newDate.getDate() - 1);
nextDate.setDate(nextDate.getDate() - 1);
}
}
currentDate = newDate;
}
var oldValue = _this._rangeEnd;
_this._rangeEnd = currentDate;
if (oldValue.getTime() != _this._rangeEnd.getTime())
{
_this._refreshRange();
}
}
});
/* $(window).mouseup(function (e) {
if (_this._mouseDown)
{
_this._mouseDown = false;
_this._refreshRange();
var minDate = _this._rangeStart < _this._rangeEnd ? _this._rangeStart : _this._rangeEnd;
var maxDate = _this._rangeEnd > _this._rangeStart ? _this._rangeEnd : _this._rangeStart;
_this._triggerEvent('selectRange', {
startDate: minDate,
endDate: maxDate,
events: _this.getEventsOnRange(minDate, new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate() + 1))
});
}
}); */
}
URL: https://ngrdanjski.com/calendar/js/bootstrap-year-calendar.js
Full version: https://codepen.io/NGrdanjski/pen/bQGdRb
I don't have skill for this functionality, please help.
Tnx!
I edited your code a bit. I understand that you want to set two dates, the start and the end of the range, and all that happens in two clicks. I also added a check if the second date is after the first one, if it's not they will swap places, so the earlier date is the rangeStart. The dates are stored in rangeStart and rangeEnd:
Edit: here's a pen
cells.mousedown(function (e) {
if(e.which == 1)
{
var currentDate = _this._getDate($(this));
//console.log(currentDate);
if(_this.options.allowOverlap || _this.getEvents(currentDate).length == 0)
{
if(!_this._mouseDown) {
_this._mouseDown = true;
_this._rangeStart = _this._rangeEnd = currentDate;
_this._refreshRange();
}
else {
_this._mouseDown = false;
_this._rangeEnd = currentDate;
if(_this._rangeEnd.getTime() < _this._rangeStart.getTime()) {
var tempDate = _this._rangeEnd;
_this._rangeEnd = _this._rangeStart;
_this._rangeStart = tempDate;
}
// _this._refreshRange();
}
}
if(_this._rangeStart != _this._rangeEnd) {
console.log(_this._rangeStart.getDate() + ',' + _this._rangeEnd.getDate());
}
}
});

Custom shipping countdown timer

I'm currently working on a custom jquery/javascript countdown timer to indicate how much time a customer has left to buy something before it gets shipped. It's very crude - but it works for me, i'm not a coder per se - in basic.
jQuery(function($) {
$(document).ready(function() {
setInterval(function() {
var now = new Date();
var day = now.getDay();
//var day = 6;
var day2 = (now.getDate() < 10 ? '0' : '') + now.getDate();
var month = ("0" + (now.getMonth() + 1)).slice(-2);
var offday = day2 + month;
var offdayset = false;
var end;
if (day >= 1 && day <= 4) {
end = new Date(now.getYear(), now.getMonth(), day, 15, 30, 0, 0);
} else if (day == 5) {
end = new Date(now.getYear(), now.getMonth(), day, 15, 30, 0, 0);
} else {
end = new Date(now.getYear(), now.getMonth(), day, 15, 30, 0, 0);
}
var timeleft = end.getTime() - now.getTime();
var diff = new Date(timeleft);
var weekday = new Array(7);
weekday[0] = "Zondag";
weekday[1] = "Maandag";
weekday[2] = "Dinsdag";
weekday[3] = "Woensdag";
weekday[4] = "Donderdag";
weekday[5] = "Vrijdag";
weekday[6] = "Zaterdag";
var shippingday = weekday[now.getDay()];
/* Declare an array. */
var offdays = new Array('2303', '2412', '2512', '3112');
/* Traverse each of value of an array using for loop to
check whether the value is exist in array*/
for (var i = 0; i < offdays.length; i++) {
if (offdays[i] === offday) {
//alert('Value exist');
offdayset = true;
}
}
if (shippingday == "Zaterdag" || shippingday == "Zondag")
{
shippingday = "Maandag";
} else if ("" + diff.getHours() + ('0' + diff.getMinutes()).slice(-2) <= 1630 && offdayset == false) {
shippingday = "Vandaag";
} else {
shippingday = weekday[now.getDay() + 1];
}
$("#datecountdown").html("binnen " + diff.getHours() + "u " + diff.getMinutes() + "min " + diff.getSeconds() + "sec");
$("#dateshipping").html(shippingday);
//below are just for testing purposes
$("#time1").html(offday);
$("#time2").html(offdayset);
$("#time3").html(end);
}, 1000);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="/verzending-bezorging/" class="shippingtimer" title="*wanneer product op voorraad is">
<p class="shippingtimer"> Besteld <span id="datecountdown"></span> = <span id="dateshipping"></span> verzonden*</p>
</a>
<span id="time1"></span>
<br>
<span id="time2"></span>
<br>
<span id="time3"></span>
So far i got the countdown working and the check if it's weekendl; When it's weekend (saturday or sunday) shipping will only be on Monday. However, i can't get the timer to indicate this into a bigger set of hours: i.e After 16.30 on friday Friday will be +72h, Saturday would be + 48 hours, Sunday + 24, untill 16.30 on Monday.
Can anybody lend me a hand?
I reorganized your code a bit, to make the logic a little bit clearer, I think this might be what you want.
Edit:
var shippingDate = new Date(bookingDate.getFullYear(), bookingDate.getMonth(), bookingDate.getDay(), 15, 30, 0, 0);
bookingDate.getDay() should be bookingDate.getDate()
var shippingDate = new Date(bookingDate.getFullYear(), bookingDate.getMonth(), bookingDate.getDate(), 15, 30, 0, 0);
jQuery(function($) {
$(document).ready(function() {
var weekday = new Array(7);
weekday[0] = "Zondag";
weekday[1] = "Maandag";
weekday[2] = "Dinsdag";
weekday[3] = "Woensdag";
weekday[4] = "Donderdag";
weekday[5] = "Vrijdag";
weekday[6] = "Zaterdag";
//var bookingDate - the date you book
var bookingDate = new Date();
//var bookingDay - the day you book
var bookingDay = weekday[bookingDate.getDay()];
//var shippingDay - the day you ship
var shippingDay = null;
//var shippingDate - the date you ship
var shippingDate = new Date(bookingDate.getFullYear(), bookingDate.getMonth(), bookingDate.getDate(), 15, 30, 0, 0);
//logic to get shippingDay and shippingDate
if (bookingDay == "Zaterdag") {
shippingDate = shippingDate.setDate(bookingDate.getDate() + 2)
shippingDay = weekday[bookingDate.getDay() + 2];
} else if (bookingDay == "Zondag") {
shippingDate = shippingDate.setDate(bookingDate.getDate() + 1)
shippingDay = weekday[bookingDate.getDay() + 1];
} else {
//if we book before 15:30, we still can catch today's shipping
//otherwise +1 day
if (shippingDate - bookingDate >= 0) {
shippingDay = "Vandaag";
} else {
shippingDate.setDate(bookingDate.getDate() + 1);
shippingDay = weekday[bookingDate.getDay() + 1];
}
}
//you can deal with offdays with similar logic, I don't know what does shippingday = "Vandaag"; means
/*} else if ("" + diff.getHours() + ('0' + diff.getMinutes()).slice(-2) <= 1630 && offdayset == false) {
shippingday = "Vandaag";
} */
//I didn't touch your offday logic, you can fill in the gap
var now = new Date();
var day = now.getDay();
//var day = 6;
var day2 = (now.getDate() < 10 ? '0' : '') + now.getDate();
var month = ("0" + (now.getMonth() + 1)).slice(-2);
var offday = day2 + month;
var offdayset = false;
/* Declare an array. */
var offdays = new Array('2303', '2412', '2512', '3112');
/* Traverse each of value of an array using for loop to
check whether the value is exist in array*/
for (var i = 0; i < offdays.length; i++) {
if (offdays[i] === offday) {
//alert('Value exist');
offdayset = true;
}
}
setInterval(function() {
now = new Date();
var timeleft = shippingDate - now;
var diff = new Date(timeleft);
$("#datecountdown").html("binnen " + diff.getHours() + "u " + diff.getMinutes() + "min " + diff.getSeconds() + "sec");
$("#dateshipping").html(shippingDay);
//below are just for testing purposes
$("#time1").html(offday);
$("#time2").html(offdayset);
$("#time3").html("bookingdate: " + bookingDate);
$("#time4").html("shippingdate: " + shippingDate);
}, 1000);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<a href="/verzending-bezorging/" class="shippingtimer" title="*wanneer product op voorraad is">
<p class="shippingtimer"> Besteld <span id="datecountdown"></span> = <span id="dateshipping"></span> verzonden*</p>
</a>
<span id="time1"></span>
<br>
<span id="time2"></span>
<br>
<span id="time3"></span>
<br>
<span id="time4"></span>
<br>
<span id="time5"></span>

Categories