Отключите Прошлые даты и Выделите текущий выбор в окне выбора даты Javascript и CSS

#javascript #datepicker

Вопрос:

Я хотел бы отключить прошлые даты и выделить текущий выбор до тех пор, пока пользователь не выберет другую дату. В настоящее время текущий выбор не отображается, когда вы снова нажимаете на средство выбора даты, чтобы выбрать другую дату.

Кроме того, выбор текущей даты не соответствует моему местному часовому поясу ISD и отображается через пару часов. Есть какие-нибудь предложения о том, как это исправить?

Любая помощь будет очень признательна.

Этот индикатор даты является творением W. S. Toh (https://code-boxx.com/simple-datepicker-pure-javascript-css), и я нахожу это очень полезным для моего проекта начальной загрузки, поскольку он открывается аналогично модалам начальной загрузки (интересно, почему Bootstrap не смог предоставить такой полезный и столь необходимый ресурс на своей платформе).

Я попытался проверить решение с У. С. Тохом, но я думаю, что его ответ был простым намеком, а не чем-то, что помогло бы мне прийти к решению, которого я ожидаю. В любом случае, я его не виню.

Если какой-либо эксперт по Javascript сможет разобраться в этой проблеме и предложить подходящее решение, я был бы очень признателен за любезную помощь.

HTML:

 <input type="text" class="form-control" id="input-pop1" placeholder="Date">
 

Встроенный Javascript:

 <script type="text/javascript">
window.addEventListener("load", function () {
  picker.attach({
    target: "input-pop1",
    startmon: true,
    disablepast: true
  });
});
</script>
 

Язык JavaScript:

   var picker = {
  // (A) ATTACH DATEPICKER TO TARGET
  //  target: field to populate
  //  container: generate datepicker in here (for inline datepicker)
  //  startmon: start on mon? (optional, default false)
  //  yrange: year select range (optional, default 10)
  //  disableday: days to disable, e.g. [2,7] to disable tue and sun (optional)
  //  onpick : function to call on select date (optional)
  instances : [],
  attach : (opt) => {
    // (A1) SET DEFAULT OPTIONS amp; REGISTER INSTANCE
    opt.target = document.getElementById(opt.target);
    opt.target.readOnly = true; // PREVENT ONSCREEN KEYBOARD
    if (opt.container) { opt.container = document.getElementById(opt.container); }
    opt.startmon = opt.startmon ? true : false;
    opt.disablepast = opt.disablepast ? true : false;
    opt.yrange = opt.yrange ? opt.yrange : 10;
    const id = picker.instances.length;
    picker.instances.push(opt);
    let inst = picker.instances[id];

    // (A2) TEMP VARS   CURRENT MONTH YEAR (UTC 0)
    let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        temp, today = new Date(),
        thisMonth = today.getUTCMonth(), // JAN IS 0
        thisYear = today.getUTCFullYear();

    // (A3) GENERATE HTML
    // (A3-1) HTML DATEPICKER WRAPPER
    inst.hPick = document.createElement("div");
    inst.hPick.classList.add("picker");

    // (A3-2) HTML MONTH SELECT
    inst.hMonth = document.createElement("select");
    inst.hMonth.classList.add("picker-m");
    // for (let m in months) {
    for (let m in months) {
      temp = document.createElement("option");
      temp.value =  m   1;
      temp.text = months[m];
      inst.hMonth.appendChild(temp);
    }
    inst.hMonth.selectedIndex = thisMonth;
    inst.hMonth.onchange = () => { picker.draw(id); };
    inst.hPick.appendChild(inst.hMonth);

    // (A3-3) HTML YEAR SELECT
    inst.hYear = document.createElement("select");
    inst.hYear.classList.add("picker-y");
    for (let y = thisYear; y < thisYear inst.yrange; y  ) {
      temp = document.createElement("option");
      temp.value = y;
      temp.text = y;
      inst.hYear.appendChild(temp);
    }
    inst.hYear.selectedIndex = inst.yrange;
    inst.hYear.onchange = () => { picker.draw(id); };
    inst.hPick.appendChild(inst.hYear);

    // (A3-4) HTML DAYS
    inst.hDays = document.createElement("div");
    inst.hDays.classList.add("picker-d");
    inst.hPick.appendChild(inst.hDays);
    picker.draw(id);

    // (A4) INLINE DATEPICKER - ATTACH INTO CONTAINER
    if (inst.container) { inst.container.appendChild(inst.hPick); }

    // (A5) POPUP DATEPICKER - ATTACH INTO HTML BODY
    else {
      // (A5-1) FULL PAGE WRAPPER
      inst.hWrap = document.createElement("div");
      inst.hWrap.classList.add("picker-wrap");
      inst.hWrap.appendChild(inst.hPick);

      // (A5-2) CLICK TO TOGGLE DATEPICKER
      inst.target.onfocus = () => {
        inst.hWrap.classList.add("show");
      };
      inst.hWrap.onclick = (evt) => { if (evt.target == inst.hWrap) {
        inst.hWrap.classList.remove("show");
      }};

      // (A5-3) ATTACH POPUP DATEPICKER
      document.body.appendChild(inst.hWrap);
    }
  },

  // (B) DRAW DAYS IN MONTH
  draw : (id) => {
    // (B1) CRAZY VARS amp; CALCULATIONS
    // (B1-1) GET INSTANCE   SELECTED MONTH YEAR
    let inst = picker.instances[id],
        month = inst.hMonth.value,
        year = inst.hYear.value;

    // (B1-2) DATE RANGE CALCULATION (UTC 0)
    let daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate(),
        startDay = new Date(Date.UTC(year, month-1, 1)).getUTCDay(), // SUN IS 0
        endDay = new Date(Date.UTC(year, month-1, daysInMonth)).getUTCDay();
    startDay = startDay==0 ? 7 : startDay,
    endDay = endDay==0 ? 7 : endDay;

    // (B1-3) TODAY (FOR HIGHLIGHTING "TODAY'S DATE CELL")
    let today = new Date(), todayDate = null;
    if (today.getUTCMonth() 1 == month amp;amp; today.getUTCFullYear() == year) {
      todayDate = today.getUTCDate();
    }

    // (B1-4) DAY NAMES
    let daynames = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    if (inst.startmon) { daynames.push("Sun"); }
    else { daynames.unshift("Sun"); }

    // (B1-5) FOR GENERATING DATE SQUARES
    let table, row, cell, squares = [];

    // (B2) CALCULATE DATE SQUARES ARRAY
    // (B2-1) EMPTY SQUARES BEFORE FIRST DAY OF MONTH
    if (inst.startmon amp;amp; startDay!=1) {
      for (let i=1; i<startDay; i  ) { squares.push("B"); }
    }
    if (!inst.startmon amp;amp; startDay!=7) {
      for (let i=0; i<startDay; i  ) { squares.push("B"); }
    }

    // (B2-2) DAYS OF MONTH (SOME DAYS DISABLED)
    if (inst.disableday) {
      let thisDay = startDay;
      for (let i=1; i<=daysInMonth; i  ) {
        squares.push([i, inst.disableday.includes(thisDay)]);
        thisDay  ;
        if (thisDay==8) { thisDay = 1; }
      }
    }

    // (B2-2A) DISABLE PAST DATES
    if (inst.disablepast) {
      let thisDay = startDay;
      for (let i=1; i<=daysInMonth; i  ) {
        thisDay  ;
        if (i < todayDate) { 
          squares.push([i, true]); }
      }
    }

    // (B2-3) DAYS OF MONTH (ALL DAYS ENABLED)
    else {
      for (let i=1; i<=daysInMonth; i  ) { squares.push([i, false]); }
    }

    // (B2-4) EMPTY SQUARES AFTER LAST DAY OF MONTH
    if (inst.startmon amp;amp; endDay!=7) {
      for (let i=endDay; i<7; i  ) { squares.push("B"); }
    }
    if (!inst.startmon amp;amp; endDay!=6) {
      for (let i=endDay; i<(endDay==7?13:6); i  ) { squares.push("B"); }
    }

    // (B3) DRAW HTML
    // (B3-1) HTML DAY NAMES HEADER
    table = document.createElement("table");
    row = table.insertRow();
    row.classList.add("picker-d-h");
    for (let d of daynames) {
      cell = row.insertCell();
      cell.innerHTML = d;
    }

    // (B3-2) HTML DATE CELLS
    row = table.insertRow();
    for (let i=0; i<squares.length; i  ) {
      if (i!=squares.length amp;amp; i%7==0) { row = table.insertRow(); }
      cell = row.insertCell();
      if (squares[i] == "B") { cell.classList.add("picker-d-b"); }
      else {
        // CELL DATE
        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 (squares[i][0] == todayDate) { cell.classList.add("picker-d-td"); }
          cell.classList.add("picker-d-d");
          cell.onclick = () => { picker.pick(id, squares[i][0]); }
        }
      }
    }

    // (B4) ATTACH DAYS TO DATEPICKER
    inst.hDays.innerHTML = "";
    inst.hDays.appendChild(table);
  },

  // (C) CHOOSE A DATE
  pick : (id, day) => {
    // (C1) GET MONTH YEAR
    let inst = picker.instances[id],
        month = inst.hMonth.value,
        year = inst.hYear.value;

    // (C2) FORMAT amp; SET SELECTED DAY (YYYY-MM-DD)
    if ( month<10) { month = "0"   month; }
    if ( day<10) { day = "0"   day; }
    inst.target.value = `${year}-${month}-${day}`;

    // (C3) POPUP ONLY - CLOSE
    if (inst.container === undefined) {
      inst.hWrap.classList.remove("show");
    }

    // (C4) CALL ON PICK IF DEFINED
    if (inst.onpick) { inst.onpick(); }
  }
};
 

CSS:

  /* (A) POPUP */
.picker-wrap {
  position: fixed;
  z-index: 300;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  /* height: calc(100vh - 12vh) !important;
  margin-top: 12vh !important; */
  background-color: 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: 44.5vh auto 0 auto;
  transform: translateY(-50%);
  border-radius: 20px 20px 20px 20px;
  -webkit-box-shadow: 0px 10px 25px 5px rgba(0, 0, 0, 0.5);
  -moz-box-shadow: 0px 10px 25px 5px rgba(0, 0, 0, 0.5);
  box-shadow: 0px 10px 25px 5px rgba(0, 0, 0, 0.5);
}

/* (B) CONTAINER */
.picker {
  max-width: 300px;
  padding: 22px 20px 20px 20px !important;
  /* border: 1px solid #eee; */
  background-color: rgba(255, 255, 255, 1);
}
.picker select {
  outline: none !important;
  color: #444;
  border-color: #009b90;
  border-width: 1px !important;
  border-radius: 5px;
  -webkit-appearance: none;
  margin-bottom: 10px;
  padding-left: 10px !important;
  background-image: url(../images/chevron-down-cyan.svg);
  background-color: rgba(0, 155, 144, 0.1);
  background-repeat: no-repeat;
  background-position-x: 90%;
  background-position-y: center;
  background-size: 13px;
}

/* (C) MONTH   YEAR */
.picker-m {
  float: left;
  width: 48%;
  padding: 5px;
  box-sizing: border-box;
  font-size: 16px;
}
.picker-y {
  float: right;
  width: 48%;
  padding: 5px;
  box-sizing: border-box;
  font-size: 16px;
}

/* (D) DAY */
.picker-d table {
  font-family: 'Roboto', sans-serif;
  color: #444;
  letter-spacing: 0.25px;
  border-collapse: separate;
  width: 100%;
  margin-top: 25px;
}
.picker-d table td {
  width: 14.28%; /* 7 EQUAL COLUMNS */
  height: 35px;
  margin: 5px;
  text-align: center;
}
/* HEADER */
.picker-d-h td {
  font-weight: bold;
}
/* BLANK DATES */
.picker-d-b {
  background-color: rgba(0, 0, 0, 0.05);
  border-radius: 5px;
}
/* TODAY */
.picker-d-td {
  color: white;
  background-color: #009b90 !important;
}
/* SELECTED DAY */
.picker-d-sd {
  color: white;
  background-color: #009b90 !important;
}
/* PICKABLE DATES */
.picker-d-d {
  background-color: rgba(0,0,0,0.05);
  border-radius: 5px;
}
/* PICKABLE DATES HOVER */
.picker-d-d:hover {
  cursor: pointer;
  background-color: #009b90;
  /* background-color: #999; */
  color: #fff;
}
/* UNPICKABLE DATES */
.picker-d-dd {
  color: #aaa;
  background-color: rgba(0, 0, 0, 0.05);
  border-radius: 5px;
}