/**
* JTSage-DateBox
* @fileOverview Offset dates
* @author J.T.Sage <jtsage+datebox@gmail.com>
* @author {@link https://github.com/jtsage/jtsage-datebox/contributors|GitHub Contributors}
* @license {@link https://github.com/jtsage/jtsage-datebox/blob/master/LICENSE.txt|MIT}
* @version 5.2.0
*/
/**
* This method offsets the current date. Do it in such a way that rollover can be prevented
*
* @param {string} mode Element to shift
* @param {number} amount Amount to shift +/-
* @param {boolean} update Set to false, will not update display
*/
JTSageDateBox._offset = function( oper, amount, update ) {
// Compute a date/time offset.
// update = false to prevent controls refresh
//
// The rollover option has no effect on year or meridiem. It makes no sense with year, and
// meridiem feels odd when allowed to rollover, so it's set to not.
var testCurrent, condHigh, condLow, condMulti,
w = this,
o = w.options,
operNum = [ "y", "m", "d", "h", "i", "s" ].indexOf( oper ),
lastDate = 32 - w.theDate.copy([0],[0,0,32,13]).getDate(),
thisYear = [ // Only used when rollover prevented.
31, 32 - w.theDate.copy([0],[0,1,32,13]).getDate(), 31,
30, 31, 30,
31, 31, 30,
31, 30, 31
],
rolloverAllowed = ( oper !== "a" && ( oper === "y" ||
typeof o.rolloverMode[oper] === "undefined" ||
o.rolloverMode[oper] === true) );
// Trap for un-set argument.
if ( typeof update === "undefined" ) { update = true; }
if ( oper === "y" && w.theDate.get( 1 ) === 1 && w.theDate.get( 2 ) === 29 ) {
// Extreme edge case of altering year when date is set to february 29th (a leap year).
// For this case, we do not check if the new year is a leap year, I'm willing to be a day
// off every 4 years or so.
// This check is not based on rollover mode, it always happens.
w.theDate.setD( 2, 28 );
}
if ( oper === "a" ) {
// Rollover independant, handle meridiem specially.
if ( amount % 2 !== 0 ) {
// we modulus divide by 2, because if we move it twice, it's the same as before.
// Otherwise, if it is PM, we move 12 hours back, if it's AM, we move 12 hours forward.
testCurrent = ( w.theDate.get( 3 ) > 11 ) ? -12 : 12;
w.theDate.adj( 3, testCurrent );
}
} else if ( rolloverAllowed ) {
// Rollover allowed, or year operator, just do the update. (year is always ok)
w.theDate.adj( operNum, amount );
} else {
// Rollover not allowed, need to do it piece by piece.
switch ( oper ) {
case "m" : // 12 months in a year, zero based
condHigh = 11;
condLow = 0;
condMulti = 12;
break;
case "d" : // "lastDate" days in a year, one based
condHigh = lastDate;
condLow = 1;
condMulti = lastDate;
break;
case "h" : // 24 hours in a day, zero based
condHigh = 23;
condLow = 0;
condMulti = 24;
break;
case "i" : // 60 minutes in an hour, zero based
case "s" : // 60 seconds in an hour, zero based
condHigh = 59;
condLow = 0;
condMulti = 60;
break;
}
// Get what the new value will be.
testCurrent = w.theDate.get( operNum ) + amount;
if ( testCurrent < condLow ) {
// If it's less than a reasonable minimum, normalize it to be in the range
testCurrent = ( testCurrent % condMulti ) + condMulti;
} else if ( testCurrent > condHigh ) {
// Same for higher than reasonable
testCurrent = testCurrent % condMulti;
}
// Trap for month offset, when the date is very near the end of the month
// and might make things move oddly.
//
// For instance, May 31 -> offset 1 month previous -> April 30
// * note the date change as well, since April does not have 31 days.
// * this is done carfully, so that May 31 -> offset 2 month prev -> March 31
if ( oper === "m" && w.theDate.get( 2 ) > thisYear[ testCurrent ] ) {
w.theDate.setD( 2, thisYear[ testCurrent ] );
}
// Finally, update the value
w.theDate.setD( operNum, testCurrent );
}
// If we wish to update the display, do so
if ( update === true ) { w.refresh(); }
// Immediate settting? do so.
if ( o.useImmediate ) { w._t( { method : "doset" } ); }
// This fires when we change the calendar display, but don't set the date.
if ( o.mode === "calbox" ) {
w._t( {
method : "displayChange",
selectedDate : w.originalDate,
shownDate : w.theDate,
thisChange : oper,
thisChangeAmount : amount,
gridStart : w.getCalStartGrid(),
gridEnd : w.getCalEndGrid(),
selectedInGrid : w.isSelectedInCalGrid(),
selectedInBounds : w.isSelectedInBounds()
});
}
// This is the listener event, to let know whatever might be listening that
// and offset just occured.
w._t( {
method : "offset",
type : oper,
amount : amount,
newDate : w.theDate
} );
};
/**
* Alter a date by the startOffset values.
*
* @param {object} date JavaScript date object
* @return {object} JavaScript date object
*/
JTSageDateBox._startOffset = function(date) {
var o = this.options;
if ( o.startOffsetYears !== false ) {
date.adj( 0, o.startOffsetYears );
}
if ( o.startOffsetMonths !== false ) {
date.adj( 1, o.startOffsetMonths );
}
if ( o.startOffsetDays !== false ) {
date.adj( 2, o.startOffsetDays );
}
return date;
};