/**
* JTSage-DateBox
* @fileOverview Short Utility Functions
*
* Contains often used short utility functions that don't
* easily fit elsewhere
*
* @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
*/
/* JTSage-DateBox
*
* Short Utility Functions
*
* Contains often used short utility functions that don't
* easily fit elsewhere
*/
/**
* Break the duration into component parts
*
* @param {number} ms Duration, in milliseconds
* @return {array} [ days, hours, minutes, seconds ]
*/
JTSageDateBox._dur = function(ms) {
/* Break the duration value down into days/hrs/mins/secs */
return [
Math.max( 0, Math.floor( ms / ( 60*60*1000*24 ) ) ),
Math.max( 0, Math.floor( ms / ( 60*60*1000 ) % 24 ) ),
Math.max( 0, Math.floor( ms / ( 60*1000 ) % 60 ) ),
Math.max( 0, Math.floor( ms / ( 1000 ) % 60 ) ),
];
};
/**
* Find a i18n string (gettext of a sort)
*
* This also handles the option overrideKeyName system, and falls back to
* defaults before finally admitting defeat.
*
* @param {string} Index to find
* @return {*} Value of i18n entry
*/
JTSageDateBox.__ = function(val) {
/* Grab a localized version of a string (by index) */
var o = this.options,
lang = o.lang[o.useLang],
mode = o[ o.mode + "lang"],
oride = "override" + val.charAt(0).toUpperCase() + val.slice(1);
if ( typeof o[ oride ] !== "undefined" ) {
return o[ oride ];
}
if ( typeof lang !== "undefined" && typeof lang[ val ] !== "undefined" ) {
return lang[ val ];
}
if ( ( typeof mode !== "undefined" ) && ( typeof mode[ val ] !== "undefined" ) ) {
return mode[ val ];
}
if ( typeof o.lang[ "default" ][ val ] !== "undefined" ) {
return o.lang[ "default" ][ val ];
}
return "Err:NotFound";
};
/**
* Get the most apporopriate formatting string depending on mode.
*
* Includes an override setting for parseDate utility function.
*
* @return {string} Format string
*/
JTSageDateBox.__fmt = function() {
var w = this,
o = this.options;
if ( typeof w.fmtOver !== "undefined" && w.fmtOver !== false ) {
return w.fmtOver;
}
switch ( o.mode ) {
case "timebox" :
case "timeflipbox" :
return w.__( "timeOutput" );
case "durationbox" :
case "durationflipbox" :
return w.__( "durationFormat" );
case "datetimebox" :
case "datetimeflipbox" :
return w.__( "datetimeFormat" );
default:
return w.__( "dateFormat" );
}
};
/**
* Zero pad a number
*
* @param {number} number Number to alter
* @param {string} pad If pad is "-", do nothing
* @return {string} Formatted number
*/
JTSageDateBox._zPad = function(number, pad) {
// Zero pad a number.
if ( typeof pad !== "undefined" && pad === "-" ) { return String(number); }
return ( number < 10 ? "0" : "" ) + String( number );
};
/**
* Convert a digit to Indic or Arabic numerals.
*
* @param {string} Text to alter
* @param {number} -1 to go back to western arabic, to eastern arabic otherwise
* @return {string} Altered text
*/
JTSageDateBox._dRep = function( oper, direction ) {
// Digit replacement Indic/Arabic
var ch, i,
start = 48,
end = 57,
adder = 1584,
newString = "";
if ( direction === -1 ) {
start += adder;
end += adder;
adder = -1584;
}
for ( i = 0; i < oper.length; i++ ) {
ch = oper.charCodeAt( i );
if ( ch >= start && ch <= end ) {
newString = newString + String.fromCharCode( ch + adder );
} else {
newString = newString + String.fromCharCode( ch );
}
}
return newString;
};
/**
* Find all numbers in control and replace with eastern arabic
*/
JTSageDateBox._doIndic = function() {
/* Mass replace of all latin digits in the control */
var w = this;
w.d.intHTML.find( "*" ).each( function() {
if ( $( this ).children().length < 1 ) {
$( this ).html( w._dRep( $( this ).html() ) );
}
});
w.d.intHTML.find( "input" ).each(function() {
$( this ).val( w._dRep( $( this ).val() ) );
});
};
/**
* Instead of a negative val, return a defautl def
*
* @param {number} val Value to check
* @param {number} def Default if value is negative
* @return {number} OK or changed value
*/
JTSageDateBox._n = function ( val, def ) {
return ( val < 0 ) ? def : val;
};
/**
* This cleans un-needed information from a date.
*
* Returns a new date, does not alter reference.
*
* Always sets milliseconds to 0.
*
* When 2nd argument is a boolean, returns a date of Y-M-DT00:00:00 using arr
*
* When 2nd argument is a date, returns [date]T(arg[0][0]):(arg[0][1]):(arg[0][2])
*
* @param {array} arr h,m,s or y,m,d depending on arg[1]
* @param {object|boolean} date Date object, or boolean false
* @return {object} JavaScript date object
*/
JTSageDateBox._pa = function (arr,date) {
// "Clean" a date for use.
if ( typeof date === "boolean" ) {
return new this._date( arr[0], arr[1], arr[2], 0, 0, 0, 0 );
}
return new this._date(
date.get(0),
date.get(1),
date.get(2),
arr[0],
arr[1],
arr[2],
0
);
};
/**
* Checks if a number is between 2 other (non-inclusive)
*
* i.e. Valid hours are 0...23, so _btwn(#, -1, 24)
*
* @param {number} value Number to check
* @param {number} low Lower bound
* @param {number} high Upper bound
* @return {boolean} True if number is between low and high
*/
JTSageDateBox._btwn = function(value, low, high) {
return ( value > low && value < high );
};
/**
* Finds the most appropriate label for the DateBox.
*
* 0, overrideDialogLabel, if set
* 1. Placeholder text, if set
* 2. Title attribute, if set
* 3. Label attached to input, if found
* 4. boolean false
*
* @return {string} Label for DateBox
*/
JTSageDateBox._grabLabel = function( deflt, isPlaceholder ) {
// Get the most reasonable label for this datebox.
// In order of preference - placeholder, title, label for=
var inputPlaceholder, inputTitle,
w = this,
o = this.options,
tmp = false;
if ( typeof isPlaceholder === "undefined" ) {
isPlaceholder = false;
}
if ( typeof o.overrideDialogLabel === "undefined" ) {
inputPlaceholder = w.d.input.attr( "placeholder" );
inputTitle = w.d.input.attr( "title" );
if ( typeof inputPlaceholder !== "undefined" ) {
if ( isPlaceholder || o.headerFollowsPlaceholder ) {
return inputPlaceholder;
}
}
if ( typeof inputTitle !== "undefined" ) {
if ( isPlaceholder || o.headerFollowsTitle ) {
return inputTitle;
}
}
tmp = $(document).find( "label[for='" + w.d.input.attr( "id" ) + "']" ).text();
if ( isPlaceholder || o.headerFollowsLabel ) {
return ( tmp === "" ) ? deflt : tmp;
} else {
return deflt;
}
}
return o.overrideDialogLabel;
};
/**
* Get the appropriate filed order for the mode
*
* @param {string} mode Mode of operation
* @return {array} Field order
*/
JTSageDateBox._getFldOrder = function( mode ) {
switch ( mode ) {
case "durationbox" :
case "durationflipbox" :
return this.__( "durationOrder" );
case "timebox" :
case "timeflipbox" :
return this.__( "timeFieldOrder" );
case "datetimebox" :
case "datetimeflipbox" :
return this.__( "datetimeFieldOrder" );
default :
return this.__( "dateFieldOrder" );
}
};
/**
* Shortcut method to run a trigger. Used to cut quite a few characters from minified output
*
* @param {object} Object to pass to trigger
*/
JTSageDateBox._t = function ( obj ) {
this.d.input.trigger( "datebox", obj );
};
/**
* Prep function, pull from global if needed
*
* @param {mixed} Value of function option
* @return {mixe} Function, or false
*
*/
JTSageDateBox._prepFunc = function ( func ) {
if ( func === false || typeof func === "function" ) { return func; }
if ( typeof window[ func ] === "function" ) {
return window[ func ];
}
return false;
};
/**
* @typedef {Object} _pickRanges_Return
* @property {array} month Arrays of [ value, label, slected (boolean) ]
* @property {array} year Arrays of [ value, label, selected(boolean) ]
*/
/**
* Generate the ranges (data contents) of the month and year pickers
*
* @param {number} dispMonth Current month displayed
* @param {number} dispYear Current year displayed
* @param {number} realYear Today's year
* @param {boolean} relative Year is realtive to real current year, not selected year
* @return {_pickRanges_Return}
*/
JTSageDateBox._pickRanges = function ( dispMonth, dispYear, realYear, relative ) {
var w = this, i,
o = this.options,
calcYear = ( relative === false ) ? realYear : dispYear,
startYear = 0,
endYear = 0,
returnVal = {
month : [],
year : []
};
for ( i = 0; i <= 11; i++ ) {
if ( i === dispMonth ) {
returnVal.month.push( [ i, w.__( "monthsOfYear" )[i], true ] );
} else {
returnVal.month.push( [ i, w.__( "monthsOfYear" )[i], false ] );
}
}
if ( o.calYearPickMin < 1 ) {
startYear = calcYear + o.calYearPickMin;
} else if ( o.calYearPickMin < 1800 ) {
startYear = calcYear - o.calYearPickMin;
} else if ( o.calYearPickMin === "NOW" ) {
startYear = realYear;
} else {
startYear = o.calYearPickMin;
}
if ( o.calYearPickMax < 1800 ) {
endYear = calcYear + o.calYearPickMax;
} else if ( o.calYearPickMax === "NOW" ) {
endYear = realYear;
} else {
endYear = o.calYearPickMax;
}
for ( i = startYear; i <= endYear; i++ ) {
if ( i === dispYear ) {
returnVal.year.push( [ i, i, true ] );
} else {
returnVal.year.push( [ i, i, false ] );
}
}
return returnVal;
};