Cassidy Haas
Cassidy Haas

Reputation: 65

Building a multi view calendar from scratch; weekly view algorithm

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"> &lang; </span>
      <span class="month-year" id="label"> June 2017 </span>
      <span class="right button" id="next"> &rang; </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"> &lang; </span>
      <span class="month-year" id="label"> April 2017 </span>
      <span class="right button" id="next"> &rang; </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.

Upvotes: 1

Views: 1818

Answers (1)

Cam
Cam

Reputation: 1902

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>
<a href="#" id="mth">Month</a>

Upvotes: 1

Related Questions