0

I have this code that generates a calendar. I want the dates to be links. So for example, if a date is Today, the link will be https://example.com/dates/2020-09-18. This will be dynamic for any date. If date year selected is 2016-10-20, the link for the date becomes https://example.com/dates/2016-10-20 etc.

The code is

function generate_year_range(start, end) {
  var years = "";
  for (var year = start; year <= end; year++) {
    years += "<option value='" + year + "'>" + year + "</option>";
  }
  return years;
}

var today = new Date();
var currentMonth = today.getMonth();
var currentYear = today.getFullYear();
var selectYear = document.getElementById("year");
var selectMonth = document.getElementById("month");


var createYear = generate_year_range(2016, 2021);
/** or
 * createYear = generate_year_range( 1970, currentYear );
 */

document.getElementById("year").innerHTML = createYear;

var calendar = document.getElementById("calendar");
var lang = calendar.getAttribute('data-lang');

var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

var dayHeader = "<tr>";
for (day in days) {
  dayHeader += "<th data-days='" + days[day] + "'>" + days[day] + "</th>";
}
dayHeader += "</tr>";

document.getElementById("thead-month").innerHTML = dayHeader;


monthAndYear = document.getElementById("monthAndYear");
showCalendar(currentMonth, currentYear);



function next() {
  currentYear = (currentMonth === 11) ? currentYear + 1 : currentYear;
  currentMonth = (currentMonth + 1) % 12;
  showCalendar(currentMonth, currentYear);
}

function previous() {
  currentYear = (currentMonth === 0) ? currentYear - 1 : currentYear;
  currentMonth = (currentMonth === 0) ? 11 : currentMonth - 1;
  showCalendar(currentMonth, currentYear);
}

function jump() {
  currentYear = parseInt(selectYear.value);
  currentMonth = parseInt(selectMonth.value);
  showCalendar(currentMonth, currentYear);
}

function showCalendar(month, year) {

  var firstDay = (new Date(year, month)).getDay();

  tbl = document.getElementById("calendar-body");


  tbl.innerHTML = "";


  monthAndYear.innerHTML = months[month] + " " + year;
  selectYear.value = year;
  selectMonth.value = month;

  // creating all cells
  var date = 1;
  for (var i = 0; i < 6; i++) {
    var row = document.createElement("tr");

    for (var j = 0; j < 7; j++) {
      if (i === 0 && j < firstDay) {
        cell = document.createElement("td");
        cellText = document.createTextNode("");
        cell.appendChild(cellText);
        row.appendChild(cell);
      } else if (date > daysInMonth(month, year)) {
        break;
      } else {
        cell = document.createElement("td");
        cell.setAttribute("data-date", date);
        cell.setAttribute("data-month", month + 1);
        cell.setAttribute("data-year", year);
        cell.setAttribute("data-month_name", months[month]);
        cell.className = "date-picker";
        cell.innerHTML = "<span>" + date + "</span>";

        if (date === today.getDate() && year === today.getFullYear() && month === today.getMonth()) {
          cell.className = "date-picker selected";
        }
        row.appendChild(cell);
        date++;
      }


    }

    tbl.appendChild(row);
  }

}

function daysInMonth(iMonth, iYear) {
  return 32 - new Date(iYear, iMonth, 32).getDate();
}
html {
  font-family: sans-serif;
  font-size: 15px;
  line-height: 1.4;
  color: #444;
}

body {
  margin: 0;
  background: #504f4f;
  font-size: 1em;
}

.wrapper {
  margin: 15px auto;
  max-width: 1100px;
}

.container-calendar {
  background: #ffffff;
  padding: 15px;
  max-width: 475px;
  margin: 0 auto;
  overflow: auto;
}

.button-container-calendar button {
  cursor: pointer;
  display: inline-block;
  zoom: 1;
  background: #00a2b7;
  color: #fff;
  border: 1px solid #0aa2b5;
  border-radius: 4px;
  padding: 5px 10px;
}

.table-calendar {
  border-collapse: collapse;
  width: 100%;
}

.table-calendar td,
.table-calendar th {
  padding: 5px;
  border: 1px solid #e2e2e2;
  text-align: center;
  vertical-align: top;
}

.date-picker.selected {
  font-weight: bold;
  outline: 1px dashed #00BCD4;
}

.date-picker.selected span {
  border-bottom: 2px solid currentColor;
}


/* sunday */

.date-picker:nth-child(1) {
  color: red;
}


/* friday */

.date-picker:nth-child(6) {
  color: green;
}

#monthAndYear {
  text-align: center;
  margin-top: 0;
}

.button-container-calendar {
  position: relative;
  margin-bottom: 1em;
  overflow: hidden;
  clear: both;
}

#previous {
  float: left;
}

#next {
  float: right;
}

.footer-container-calendar {
  margin-top: 1em;
  border-top: 1px solid #dadada;
  padding: 10px 0;
}

.footer-container-calendar select {
  cursor: pointer;
  display: inline-block;
  zoom: 1;
  background: #ffffff;
  color: #585858;
  border: 1px solid #bfc5c5;
  border-radius: 3px;
  padding: 5px 1em;
}
<!DOCTYPE>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="calendar.css">
</head>

<body>
  <div class="wrapper">
    <div class="container-calendar">
      <h3 id="monthAndYear"></h3>
      <div class="button-container-calendar">
        <button id="previous" onclick="previous()">&#8249;</button>
        <button id="next" onclick="next()">&#8250;</button>
      </div>

      <table class="table-calendar" id="calendar" data-lang="en">
        <thead id="thead-month"></thead>
        <tbody id="calendar-body"></tbody>
      </table>

      <div class="footer-container-calendar">
        <label for="month">Jump To: </label>
        <select id="month" onchange="jump()">
          <option value=0>Jan</option>
          <option value=1>Feb</option>
          <option value=2>Mar</option>
          <option value=3>Apr</option>
          <option value=4>May</option>
          <option value=5>Jun</option>
          <option value=6>Jul</option>
          <option value=7>Aug</option>
          <option value=8>Sep</option>
          <option value=9>Oct</option>
          <option value=10>Nov</option>
          <option value=11>Dec</option>
        </select>
        <select id="year" onchange="jump()"></select>
      </div>
    </div>
  </div>
  <script src="calendar.js" type="text/javascript"></script>
</body>

</html>
ikiK
  • 6,328
  • 4
  • 20
  • 40

1 Answers1

1
function links () {
    document.querySelectorAll('td.date-picker > span').forEach(element => {
    //get all days from calendar as element
    
      var year = element.parentElement.getAttribute('data-year');
    //extract year data attribute from parent element div
    
      var month = element.parentElement.getAttribute('data-month');
    //extract month data attribute from parent element div
    
      var day =  element.textContent;
    //save day value
    
      if (month.length === 1) {
        month = "0" + month;
      }
    // if month is one digit add 0 to it
    
        if (day.length === 1) {
        day = "0" + day;
      }
    // if day is one digit add 0 to it
    
      element.innerHTML = '<a href="https://example.com/dates/' + year + '-' + month + '-' + day + '">' + element.textContent + '</a> '
    //replace element with link data
    })
}
links()

WORKING EXAMPLE:

function generate_year_range(start, end) {
  var years = "";
  for (var year = start; year <= end; year++) {
    years += "<option value='" + year + "'>" + year + "</option>";
  }
  return years;
}

var today = new Date();
var currentMonth = today.getMonth();
var currentYear = today.getFullYear();
var selectYear = document.getElementById("year");
var selectMonth = document.getElementById("month");


var createYear = generate_year_range(2016, 2021);
/** or
 * createYear = generate_year_range( 1970, currentYear );
 */

document.getElementById("year").innerHTML = createYear;

var calendar = document.getElementById("calendar");
var lang = calendar.getAttribute('data-lang');

var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

var dayHeader = "<tr>";
for (day in days) {
  dayHeader += "<th data-days='" + days[day] + "'>" + days[day] + "</th>";
}
dayHeader += "</tr>";

document.getElementById("thead-month").innerHTML = dayHeader;


monthAndYear = document.getElementById("monthAndYear");
showCalendar(currentMonth, currentYear);



function next() {
  currentYear = (currentMonth === 11) ? currentYear + 1 : currentYear;
  currentMonth = (currentMonth + 1) % 12;
  showCalendar(currentMonth, currentYear);
  links () 
}

function previous() {
  currentYear = (currentMonth === 0) ? currentYear - 1 : currentYear;
  currentMonth = (currentMonth === 0) ? 11 : currentMonth - 1;
  showCalendar(currentMonth, currentYear);
  links () 
}

function jump() {
  currentYear = parseInt(selectYear.value);
  currentMonth = parseInt(selectMonth.value);
  showCalendar(currentMonth, currentYear);
  links () 
}

function showCalendar(month, year) {

  var firstDay = (new Date(year, month)).getDay();

  tbl = document.getElementById("calendar-body");


  tbl.innerHTML = "";


  monthAndYear.innerHTML = months[month] + " " + year;
  selectYear.value = year;
  selectMonth.value = month;

  // creating all cells
  var date = 1;
  for (var i = 0; i < 6; i++) {
    var row = document.createElement("tr");

    for (var j = 0; j < 7; j++) {
      if (i === 0 && j < firstDay) {
        cell = document.createElement("td");
        cellText = document.createTextNode("");
        cell.appendChild(cellText);
        row.appendChild(cell);
      } else if (date > daysInMonth(month, year)) {
        break;
      } else {
        cell = document.createElement("td");
        cell.setAttribute("data-date", date);
        cell.setAttribute("data-month", month + 1);
        cell.setAttribute("data-year", year);
        cell.setAttribute("data-month_name", months[month]);
        cell.className = "date-picker";
        cell.innerHTML = "<span>" + date + "</span>";

        if (date === today.getDate() && year === today.getFullYear() && month === today.getMonth()) {
          cell.className = "date-picker selected";
        }
        row.appendChild(cell);
        date++;
      }


    }

    tbl.appendChild(row);
  }

}

function daysInMonth(iMonth, iYear) {
  return 32 - new Date(iYear, iMonth, 32).getDate();
}

function links () {
document.querySelectorAll('td.date-picker > span').forEach(element => {
  var year = element.parentElement.getAttribute('data-year');
  var month = element.parentElement.getAttribute('data-month');
  var day =  element.textContent;
  if (month.length === 1) {
    month = "0" + month;
  }
    if (day.length === 1) {
    day = "0" + day;
  }
  element.innerHTML = '<a href="https://example.com/dates/' + year + '-' + month + '-' + day + '">' + element.textContent + '</a> '
})
}

links ()
html {
  font-family: sans-serif;
  font-size: 15px;
  line-height: 1.4;
  color: #444;
}

body {
  margin: 0;
  background: #504f4f;
  font-size: 1em;
}

.wrapper {
  margin: 15px auto;
  max-width: 1100px;
}

.container-calendar {
  background: #ffffff;
  padding: 15px;
  max-width: 475px;
  margin: 0 auto;
  overflow: auto;
}

.button-container-calendar button {
  cursor: pointer;
  display: inline-block;
  zoom: 1;
  background: #00a2b7;
  color: #fff;
  border: 1px solid #0aa2b5;
  border-radius: 4px;
  padding: 5px 10px;
}

.table-calendar {
  border-collapse: collapse;
  width: 100%;
}

.table-calendar td,
.table-calendar th {
  padding: 5px;
  border: 1px solid #e2e2e2;
  text-align: center;
  vertical-align: top;
}

.date-picker.selected {
  font-weight: bold;
  outline: 1px dashed #00BCD4;
}

.date-picker.selected span {
  border-bottom: 2px solid currentColor;
}


/* sunday */

.date-picker:nth-child(1) {
  color: red;
}


/* friday */

.date-picker:nth-child(6) {
  color: green;
}

#monthAndYear {
  text-align: center;
  margin-top: 0;
}

.button-container-calendar {
  position: relative;
  margin-bottom: 1em;
  overflow: hidden;
  clear: both;
}

#previous {
  float: left;
}

#next {
  float: right;
}

.footer-container-calendar {
  margin-top: 1em;
  border-top: 1px solid #dadada;
  padding: 10px 0;
}

.footer-container-calendar select {
  cursor: pointer;
  display: inline-block;
  zoom: 1;
  background: #ffffff;
  color: #585858;
  border: 1px solid #bfc5c5;
  border-radius: 3px;
  padding: 5px 1em;
}
<!DOCTYPE>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="calendar.css">
</head>

<body>
  <div class="wrapper">
    <div class="container-calendar">
      <h3 id="monthAndYear"></h3>
      <div class="button-container-calendar">
        <button id="previous" onclick="previous()">&#8249;</button>
        <button id="next" onclick="next()">&#8250;</button>
      </div>

      <table class="table-calendar" id="calendar" data-lang="en">
        <thead id="thead-month"></thead>
        <tbody id="calendar-body"></tbody>
      </table>

      <div class="footer-container-calendar">
        <label for="month">Jump To: </label>
        <select id="month" onchange="jump()">
          <option value=0>Jan</option>
          <option value=1>Feb</option>
          <option value=2>Mar</option>
          <option value=3>Apr</option>
          <option value=4>May</option>
          <option value=5>Jun</option>
          <option value=6>Jul</option>
          <option value=7>Aug</option>
          <option value=8>Sep</option>
          <option value=9>Oct</option>
          <option value=10>Nov</option>
          <option value=11>Dec</option>
        </select>
        <select id="year" onchange="jump()"></select>
      </div>
    </div>
  </div>
  <script src="calendar.js" type="text/javascript"></script>
</body>

</html>

EDIT:

To apply this on calendar navigation wrap this in function

links ()

and call it on page load as well as your navigating function, i added links () at end to initiate it:

function next() {
function previous() {
function jump() {
ikiK
  • 6,328
  • 4
  • 20
  • 40
  • Your code works like I want but it's missing other months, dates. – mary ongubo Sep 18 '20 at 11:40
  • @maryongubo Please study the code for future reference, people here like to see some attempt at desired effect. But I know how is it when you get stuck and do not even know where to start, plus you are new here. Keep in mind this website is not free writing service, its bug fix mostly. So please try to learn how this code i wrote works. If you have any questions feel free to ask. Cheers and welcome to SO – ikiK Sep 18 '20 at 11:51
  • Added the code in WordPress but links disappear when I navigate. I copied the whole code here because it already works like I want. I don't know what could be different in WordPress. – mary ongubo Sep 18 '20 at 13:56
  • @maryongubo Did you check your console.log for errors? – ikiK Sep 18 '20 at 14:01
  • @maryongubo Also I hope you copied whole code from fiddle including `functions next() , previous() and jump()` , because that is where I added `links ()` at end to react to navigating calendar. – ikiK Sep 18 '20 at 14:08
  • I'm I supposed to wrap like so ```function next() { function previous() { function jump() { links ()}}}``` Sorry I didn't understand the last bit – mary ongubo Sep 18 '20 at 14:13
  • @maryongubo please see the fiddle code. It needs to be like there... When you press for example next button that starts function `next()`, so inside you also need to at end start `links()` function like so: `function next() { currentYear = (currentMonth === 11) ? currentYear + 1 : currentYear; currentMonth = (currentMonth + 1) % 12; showCalendar(currentMonth, currentYear); links () }`** take note** `links ()` at end... Same goes for all 3 navigating function I mentioned in my answer... – ikiK Sep 18 '20 at 14:17
  • Your code already contains the code, for all the three. So I copied your code as is with the links () functions inside the three function next(), function previous() and function jump() – mary ongubo Sep 18 '20 at 14:24
  • @maryongubo OK, that part is re-applying the links on calendar while navigating, it is there, so problem is somewhere else. Did you check your console log for errors in browser dev tools like I asked? – ikiK Sep 18 '20 at 14:27
  • Console log report ```Failed to load resource: the server responded with a status of 404 () (index):2429 Uncaught TypeError: links is not a function at previous ((index):2429) at HTMLButtonElement.onclick ((index):2313)``` – mary ongubo Sep 18 '20 at 14:32
  • @maryongubo That means you haven't included the whole `function links() {....}` at right place. `links is not a function` means browser is trying to initiate it but it does not see it for some reason... I don't know how to help you without seeing your source code , where, what and when you are including things in webpage... – ikiK Sep 18 '20 at 14:38
  • I added both js codes inside after the html code. Like so `````` – mary ongubo Sep 18 '20 at 14:43
  • @maryongubo Try putting `links () {...}` at very END after everything, after `function daysInMonth(iMonth, iYear)`. Order of things is very important! See where its placed in fiddle! – ikiK Sep 18 '20 at 14:47
  • I have tested on a different WordPress website and everything works perfectly. It's obviously something to do with the other site. I will figure that out. Absolutely indebted for your patience with me. – mary ongubo Sep 18 '20 at 15:01