Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

The purpose of the application is to show dates. The inputs are weekdays and weeks. Or alternative days as an integer.

Example:

Present me the Friday in 5 weeks!

Or

Present me the date of the day in 100 days!

// Global object on which everything else 
// becomes attached.
var oo = {};

Object.defineProperty(oo, 'MILLI_SECONDS_DAY', {
  value: 24 * 60 * 60 * 1000
});

Object.defineProperty(oo, 'DURATION_ANIMATION', {
  value: 580
});

oo.elements = [];

oo.resultDate = document.getElementById('result-date');
oo.setDays = document.getElementById('set-days');
oo.elements[0] = document.getElementById('set-day');
oo.elements[1] = document.getElementById('set-weeks');
oo.radioControls = document.querySelectorAll('.radio-control');
oo.dateSelects = document.querySelectorAll('.date-select');

// Triggered by change of a radio-button.
// Disable all input- and select-elements except the 
// elements in the chosen fieldset.

oo.toggleDisable = function() {
  // The main parent node of the choosen fieldset.
  var fieldset = this.parentNode.parentNode;
  // The all input elements within it.
  var selects = fieldset.querySelectorAll('.date-select');
  // Disable all input elements.
  Array.prototype.forEach.call(oo.dateSelects, function(dateSelect) {
    if (!dateSelect.disabled) {
      dateSelect.setAttribute('disabled', 'disabled');
      dateSelect.parentNode.classList.remove('active-select');
    }
  });
  // Re-Enable all inputs in the current chosen fieldset.
  Array.prototype.forEach.call(selects, function(select) {
    if (select.disabled && select !== this) {
      select.removeAttribute('disabled');
      select.parentNode.classList.add('active-select');
    }
  });
}

// Attach the function to the radio-buttons.
Array.prototype.forEach.call(oo.radioControls, function(radioControl) {
  radioControl.addEventListener('change', oo.toggleDisable);
});

// Delete the value of the result text-input when 
// a mouse-click occurs.

// -- Paremeter -----------------------------------------
// (Element) Object - The clicked control.

oo.deleteLastResult = function(control) {
  control.addEventListener('mousedown', function() {
    oo.resultDate.value = '';
  });
}

// ---- Start - Attach the date-calculation method to the 
// select-elements. -------------------------------------
for (var i = 0; i < oo.elements.length; i++) {

  oo.deleteLastResult(oo.elements[i]);

  oo.elements[i].addEventListener('change', function() {
    oo.resultDate.value =
      oo.getDayMonthYearDate(
        oo.getDateBeforeIn(oo.elements[0].value,
          oo.elements[1].value));

    oo.playAnimation();
  });
}

oo.setDays.addEventListener('change', function() {

  oo.deleteLastResult(oo.setDays);

  oo.resultDate.value =
    oo.getDayMonthYearDate(
      oo.getDateBeforeInDays(oo.setDays.value));

  oo.playAnimation();
});

// Triggers the animation on the text input 
// with the result.

oo.playAnimation = function() {
    oo.resultDate.classList.add('result-present');

    setTimeout(function() {
      oo.resultDate.classList.remove('result-present');
    }, oo.DURATION_ANIMATION);
  }
  // ---- End - Attach the date-calculation method -----------

// Fills a select-element with options.

// -- Parameter --------------------------------------------
// 1. (Element) Object - Select on which the options are
//    appended.
// 2. Number - Number to start with.
// 3. Number - Upper limit (simultaneously last number to include).

oo.setOptions = function(selectElement, countOptionsStart, countOptionsEnd) {
  for (var i = countOptionsStart; i <= countOptionsEnd; i++) {
    var option = document.createElement('option');
    var optionInner = document.createTextNode(i);

    option.setAttribute('value', i);

    if (i === 0) option.setAttribute('selected', 'selected');

    option.appendChild(optionInner);
    selectElement.appendChild(option);
  }
}

oo.setOptions(oo.elements[1], -52, 52);
oo.setOptions(oo.setDays, -365, 365);

// Returns a Date Object which contains
// the date before/in n-days and 
// before/in n-weeks.

// -- Parameter ----------------------------
// 1. String - The desired weekday as an 
//   abbreviation.
//   Assign for ...
//     Monday    : 'mo'
//     Tuesday   : 'tu'
//     Wednesday : 'we'
//     Thursday  : 'th'
//     Friday    : 'fr'
//     Saturday  : 'sa'
//     Sunday    : 'su'

// 2. Number - Positive number => n-weeks in
//   the future.
//   Negative number => n-weeks before.

// -- Return -------------------------------
// (Date) Object 

oo.getDateBeforeIn = function(day, weeks) {
  var currentDate = new Date();
  var currentStamp = Date.now();
  var weekdays = {
    'mo': 1,
    'tu': 2,
    'we': 3,
    'th': 4,
    'fr': 5,
    'sa': 6,
    'su': 0
  }

  currentStamp += weeks * 7 * oo.MILLI_SECONDS_DAY;
  currentStamp +=
    (weekdays[day] - currentDate.getDay()) *
    oo.MILLI_SECONDS_DAY;

  return new Date(currentStamp);
}

oo.getDateBeforeInDays = function(days) {
  var currentDate = new Date();
  var currentStamp = Date.now();

  currentStamp += days * oo.MILLI_SECONDS_DAY;

  return new Date(currentStamp);
}

// Returns the Day, Month, Year of an 
// JavaScript Date Object as as String
// in the Date format DMY.

// -- Parameter ----------------------------
// 1. Date-Object
// 2. String - Is used for separating 
// Day-Year and Month-Year.

// -- Return -------------------------------
// String

oo.getDayMonthYearDate = function(dateObject, separator) {
  separator = separator || '.';

  return oo.getZeroPaddedNumber(dateObject.getDate(), 2) +
    separator +
    oo.getZeroPaddedNumber((dateObject.getMonth() + 1), 2) +
    separator + dateObject.getFullYear();
}

oo.getZeroPaddedNumber = function(someNumber, desiredLength) {
  someNumber = '00' + someNumber;

  return someNumber.slice(desiredLength * -1);
}
body {
  font-family: tahoma, helvetica, sans-serif;
  background-color: rgba(245, 245, 245, 1.0);
}
#wrap {
  max-width: 1000px;
  width: 100%;
  margin: 0 auto;
}
input,
select,
label {
  margin: 10px;
}
input,
select {
  font-family: tahoma;
  padding: 0 4px 2px;
  border-radius: 4px;
}
#form-set-date {
  padding: 10px 20px;
  background: linear-gradient(135deg, rgba(250, 250, 250, 1.0), rgba(220, 220, 220, 1.0));
  border: 1px solid rgba(100, 100, 100, 0.6);
  border-radius: 12px;
  box-shadow: 1px 1px 3px rgba(200, 200, 200, 1.0);
}
.control-element {
  margin: 10px 0;
  height: 40px;
  width: 300px;
  background-color: rgba(250, 250, 250, 1.0);
  border: 1px solid rgba(100, 100, 100, 0.5);
  border-radius: 9px;
  display: inline-block;
  box-shadow: 1px 1px 1px rgba(100, 100, 100, 1.0);
  text-shadow: 1px 1px 3px rgba(210, 210, 210, 1.0);
}
.active-select:hover {
  border: 1px solid rgba(0, 180, 180, 1.0);
  box-shadow: 0 0 4px rgba(0, 220, 220, 1.0);
}
.control-element label {
  display: inline-block;
  width: 100px;
}
.control-element .long-label {
  width: 180px;
}
.read-only[disabled=disabled] {
  background-color: rgba(255, 255, 255, 1.0);
  color: rgba(0, 0, 0, 1.0);
  text-align: center;
}
input[type=radio] {
  width: 10px;
}
input[type=text],
select {
  width: 110px;
}
fieldset:nth-of-type(n + 2) {
  margin-top: 20px;
}
fieldset {
  border: 1px solid rgba(100, 100, 100, 0.6);
  background-color: rgba(240, 240, 240, 1.0);
  box-shadow: 1px 1px 3px rgba(200, 200, 200, 1.0);
  border-radius: 15px;
}
p {
  font-family: georgia, serif;
}
p {
  font-size: 1.2em;
  padding-left: 5%;
  text-shadow: 1px 1px 3px rgba(210, 210, 210, 1.0);
}
.result-present {
  animation: expandShadow 0.6s 1;
}
@keyframes expandShadow {
  0% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0);
  }
  10% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.2);
  }
  20% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.4);
  }
  30% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.6);
  }
  40% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.8);
  }
  50% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 1.0);
  }
  60% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.8);
  }
  70% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.6);
  }
  80% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.4);
  }
  90% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.2);
  }
  100% {
    box-shadow: inset 0 0 20px rgba(0, 180, 180, 0.0);
  }
}
<div id="wrap">
  <p>Calculate date back or forward by defining weekday and weeks or days</p>

  <form method="" action="" id="form-set-date">
    <fieldset>
      <div class="control-element active-select">
        <input type="radio" id="by-days-weeks" value="daysWeeks" class="radio-control" checked="checked" name="radio-control" />
        <label for="by-days-weeks" class="radio-label long-label">By weekday and week(s)</label>
      </div>

      <div class="control-element active-select">
        <label>Weekday:</label>
        <select id="set-day" class="date-select">
          <option value="mo">Monday</option>
          <option value="tu">Tuesday</option>
          <option value="we">Wednesday</option>
          <option value="th">Thursday</option>
          <option value="fr">Friday</option>
          <option value="sa">Saturday</option>
          <option value="su">Sunday</option>
        </select>
      </div>

      <div class="control-element active-select">
        <label>Week(s):</label>
        <select id="set-weeks" class="date-select"></select>
      </div>
    </fieldset>

    <fieldset>
      <div class="control-element active-select">
        <input type="radio" id="by-days" value="days" class="radio-control" name="radio-control" />

        <label for="by-days" class="radio-label">By days</label>
      </div>

      <div class="control-element">
        <label>Days:</label>
        <select id="set-days" class="date-select" disabled="disabled"></select>
      </div>
    </fieldset>

    <fieldset>
      <div class="control-element">
        <label>Result:</label>
        <input type="text" class="read-only" id="result-date" disabled="disabled" />
      </div>
    </fieldset>
  </form>
</div>

Feedback & hints (concerning weaknesses) welcome.

share|improve this question

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.