mithril.js calendar

by Cybolic

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tachyons/4.11.1/tachyons.min.css">
<script src="https://unpkg.com/mithril/mithril.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Calendar</title>

    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
          integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">

</head>
<body>
<div class="container col-sm-4 col-md-7 col-lg-4 mt-5">
    <div class="card">
        <h3 class="card-header" id="monthAndYear"></h3>
        <table class="table table-bordered table-responsive-sm" id="calendar">
            <thead>
            <tr>
                <th>Sun</th>
                <th>Mon</th>
                <th>Tue</th>
                <th>Wed</th>
                <th>Thu</th>
                <th>Fri</th>
                <th>Sat</th>
            </tr>
            </thead>

            <tbody id="calendar-body">

            </tbody>
        </table>

        <div class="form-inline">

            <button class="btn btn-outline-primary col-sm-6" id="previous" onclick="previous()">Previous</button>

            <button class="btn btn-outline-primary col-sm-6" id="next" onclick="next()">Next</button>
        </div>
        <br/>
        <form class="form-inline">
            <label class="lead mr-2 ml-2" for="month">Jump To: </label>
            <select class="form-control col-sm-4" name="month" 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>
        ...

JavaScript

const locale_dow = {"en":0,"ar-dz":0,"ar-kw":0,"ar-ly":6,"ar-ma":6,"ar-sa":0,"ar":6,"bn":0,"bo":0,"dv":7,"en-ca":0,"en-il":0,"es-us":0,"fa":6,"fr-ca":0,"gu":0,"he":0,"hi":0,"ja":0,"kn":0,"ko":0,"ku":6,"lo":0,"ml":0,"mn":0,"mr":0,"ne":0,"pa-in":0,"pt-br":0,"si":0,"ta":0,"te":0,"th":0,"tzm-latn":6,"tzm":6,"zh-hk":0,"zh-tw":0};

function getLocale () {
  let lang = 'en';
  const known_locales = Object.keys(locale_dow);
	const precise_matches = navigator.languages.filter(lang =>
    known_locales.includes(lang.toLowerCase())
  );
  if (precise_matches.length) {
    lang = precise_matches[0].toLowerCase();
  } else {
    const partial_matches = navigator.languages.filter(lang =
      known_locales.includes(lang.split('-')[0].toLowerCase())
    );
    if (partial_matches.length) {
      lang = partial_matches[0].split('-')[0].toLowerCase();
    }
  }
  return lang;
}

function getLocaleFirstDayOfWeek (locale) {
	locale = locale.toLowerCase();
  const locale_base = locale.split('-').shift();
  return locale_dow[locale] != null
  	? locale_dow[locale]
    : locale_dow[locale_base] != null
    	? locale_dow[locale_base]
      : 1;
}

function getMonthMatrix (locale, month, year) {
  const dow = getLocaleFirstDayOfWeek(locale);
  let first_day = (new Date(year, month)).getDay() - dow;
  if (first_day < 0) {
  	first_day = first_day + 7;
  }

  const matrix = [];

  // creating all cells
  const days_in_month = daysInMonth(month, year);
  let date = 1;
  for (let i = 0; i < 6; i++) {
    // creates a table row
    let row = [];
    //creating individual cells, filing them up with data.
    for (let j = 0; j < 7; j++) {
      if (i === 0 && j < first_day) {
        row.push({ text: "" });
      } else if (date > days_in_month) {
        break;
      } else {
        const cell = {};
        cell.text = date;
        if (date === today.getDate() && year === today.getFullYear() && month === today.getMonth()) {
          cell.today = true;
        } // color today's date
      ...