Like the title says, I would like to disable past dates in a date-picker script.
Here what I do to create it:
new datepickr('datepick', {
fullCurrentMonth: true,
dateFormat: 'j-m-Y',
minDate: 0 ,
weekdays: [
'Lunedì', 'Martedì',
'Mercoledì', 'Giovedì',
'Venerdì', 'Sabato',
'Domenica'
],
months: [
'Gennaio', 'Febbraio',
'Marzo', 'Aprile',
'Maggio', 'Giugno',
'Luglio', 'Agosto',
'Settembre', 'Ottobre',
'Novembre', 'Dicembre'
],
});
And here is the entire script (from the internet, I don't remember where I found it).
/*
datepickr - pick your date not your nose
Copyright (c) 2012
*/
var datepickr = (function() {
var datepickrs = [],
currentDate = new Date(),
date = {
current: {
year: function() {
return currentDate.getFullYear();
},
month: {
integer: function() {
return currentDate.getMonth();
},
string: function(full) {
var date = currentDate.getMonth();
return monthToStr(date, full);
}
},
day: function() {
return currentDate.getDate();
}
},
month: {
string: function(full, currentMonthView) {
var date = currentMonthView;
return monthToStr(date, full);
},
numDays: function(currentMonthView, currentYearView) {
// checks to see if february is a leap year otherwise return the respective # of days
return (currentMonthView == 1 && !(currentYearView & 3) && (currentYearView % 1e2 || !(currentYearView % 4e2))) ? 29 : daysInMonth[currentMonthView];
}
}
},
weekdays = ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
months= ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
suffix = { 1: 'st', 2: 'nd', 3: 'rd', 21: 'st', 22: 'nd', 23: 'rd', 31: 'st' },
buildCache = [],
handlers = {
calendarClick: function(e) {
if(e.target.className) {
switch(e.target.className) {
case 'prev-month':
case 'prevMonth':
this.currentMonthView--;
if(this.currentMonthView < 0) {
this.currentYearView--;
this.currentMonthView = 11;
}
rebuildCalendar.call(this);
break;
case 'next-month':
case 'nextMonth':
this.currentMonthView++;
if(this.currentMonthView > 11) {
this.currentYearView++;
this.currentMonthView = 0;
}
rebuildCalendar.call(this);
break;
case 'day':
this.element.value = formatDate(new Date(this.currentYearView, this.currentMonthView, e.target.innerHTML).getTime(), this.config.dateFormat);
this.close();
break;
}
}
},
documentClick: function(e) {
if(e.target != this.element && e.target != this.calendar) {
var parentNode = e.target.parentNode;
if(parentNode != this.calender) {
while(parentNode != this.calendar) {
parentNode = parentNode.parentNode;
if(parentNode == null) {
this.close();
break;
}
}
}
}
}
};
function formatDate(milliseconds, dateFormat) {
var formattedDate = '',
dateObj = new Date(milliseconds),
format = {
d: function() {
var day = format.j();
return (day < 10) ? '0' + day : day;
},
D: function() {
return weekdays[format.w()].substring(0, 3);
},
j: function() {
return dateObj.getDate();
},
l: function() {
return weekdays[format.w()] + 'day';
},
S: function() {
return suffix[format.j()] || 'th';
},
w: function() {
return dateObj.getDay();
},
F: function() {
return monthToStr(format.n(), true);
},
m: function() {
var month = format.n() + 1;
return (month < 10) ? '0' + month : month;
},
M: function() {
return monthToStr(format.n(), false);
},
n: function() {
return dateObj.getMonth();
},
Y: function() {
return dateObj.getFullYear();
},
y: function() {
return format.Y().toString().substring(2, 4);
}
},
formatPieces = dateFormat.split('');
foreach(formatPieces, function(formatPiece) {
formattedDate += format[formatPiece] ? format[formatPiece]() : formatPiece;
});
return formattedDate;
}
function foreach(items, callback) {
var i = 0, x = items.length;
for(i; i < x; i++) {
if(callback(items[i], i) === false) {
break;
}
}
}
function addEvent(element, eventType, callback) {
if(element.addEventListener) {
element.addEventListener(eventType, callback, false);
} else if(element.attachEvent) {
var fixedCallback = function(e) {
e = e || window.event;
e.preventDefault = (function(e) {
return function() { e.returnValue = false; }
})(e);
e.stopPropagation = (function(e) {
return function() { e.cancelBubble = true; }
})(e);
e.target = e.srcElement;
callback.call(element, e);
};
element.attachEvent('on' + eventType, fixedCallback);
}
}
function removeEvent(element, eventType, callback) {
if(element.removeEventListener) {
element.removeEventListener(eventType, callback, false);
} else if(element.detachEvent) {
element.detachEvent('on' + eventType, callback);
}
}
function buildNode(nodeName, attributes, content) {
var element;
if(!(nodeName in buildCache)) {
buildCache[nodeName] = document.createElement(nodeName);
}
element = buildCache[nodeName].cloneNode(false);
if(attributes != null) {
for(var attribute in attributes) {
element[attribute] = attributes[attribute];
}
}
if(content != null) {
if(typeof(content) == 'object') {
element.appendChild(content);
} else {
element.innerHTML = content;
}
}
return element;
}
function monthToStr(date, full) {
return ((full == true) ? months[date] : ((months[date].length > 3) ? months[date].substring(0, 3) : months[date]));
}
function isToday(day, currentMonthView, currentYearView) {
return day == date.current.day() && currentMonthView == date.current.month.integer() && currentYearView == date.current.year();
}
function buildWeekdays() {
var weekdayHtml = document.createDocumentFragment();
foreach(weekdays, function(weekday) {
weekdayHtml.appendChild(buildNode('th', {}, weekday.substring(0, 2)));
});
return weekdayHtml;
}
function rebuildCalendar() {
while(this.calendarBody.hasChildNodes()){
this.calendarBody.removeChild(this.calendarBody.lastChild);
}
var firstOfMonth = new Date(this.currentYearView, this.currentMonthView, 1).getDay(),
numDays = date.month.numDays(this.currentMonthView, this.currentYearView);
this.currentMonth.innerHTML = date.month.string(this.config.fullCurrentMonth, this.currentMonthView) + ' ' + this.currentYearView;
this.calendarBody.appendChild(buildDays(firstOfMonth, numDays, this.currentMonthView, this.currentYearView));
}
function buildCurrentMonth(config, currentMonthView, currentYearView) {
return buildNode('span', { className: 'current-month' }, date.month.string(config.fullCurrentMonth, currentMonthView) + ' ' + currentYearView);
}
function buildMonths(config, currentMonthView, currentYearView) {
var months = buildNode('div', { className: 'months' }),
prevMonth = buildNode('span', { className: 'prev-month' }, buildNode('span', { className: 'prevMonth' }, '<')),
nextMonth = buildNode('span', { className: 'next-month' }, buildNode('span', { className: 'nextMonth' }, '>'));
months.appendChild(prevMonth);
months.appendChild(nextMonth);
return months;
}
function buildDays(firstOfMonth, numDays, currentMonthView, currentYearView) {
var calendarBody = document.createDocumentFragment(),
row = buildNode('tr'),
dayCount = 0, i;
// print out previous month's "days"
for(i = 1; i <= firstOfMonth; i++) {
row.appendChild(buildNode('td', null, ' '));
dayCount++;
}
for(i = 1; i <= numDays; i++) {
// if we have reached the end of a week, wrap to the next line
if(dayCount == 7) {
calendarBody.appendChild(row);
row = buildNode('tr');
dayCount = 0;
}
var todayClassName = isToday(i, currentMonthView, currentYearView) ? { className: 'today' } : null;
row.appendChild(buildNode('td', todayClassName, buildNode('span', { className: 'day' }, i)));
dayCount++;
}
// if we haven't finished at the end of the week, start writing out the "days" for the next month
for(i = 1; i <= (7 - dayCount); i++) {
row.appendChild(buildNode('td', null, ' '));
}
calendarBody.appendChild(row);
return calendarBody;
}
function buildCalendar() {
var firstOfMonth = new Date(this.currentYearView, this.currentMonthView, 1).getDay(),
numDays = date.month.numDays(this.currentMonthView, this.currentYearView),
self = this;
var inputLeft = inputTop = 0,
obj = this.element;
if(obj.offsetParent) {
do {
inputLeft += obj.offsetLeft;
inputTop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
var calendarContainer = buildNode('div', { className: 'calendar' });
calendarContainer.style.cssText = 'display: none; position: absolute; top: ' + (inputTop + this.element.offsetHeight) + 'px; left: ' + inputLeft + 'px; z-index: 100;';
this.currentMonth = buildCurrentMonth(this.config, this.currentMonthView, this.currentYearView)
var months = buildMonths(this.config, this.currentMonthView, this.currentYearView);
months.appendChild(this.currentMonth);
var calendar = buildNode('table', null, buildNode('thead', null, buildNode('tr', { className: 'weekdays' }, buildWeekdays())));
this.calendarBody = buildNode('tbody');
this.calendarBody.appendChild(buildDays(firstOfMonth, numDays, this.currentMonthView, this.currentYearView));
calendar.appendChild(this.calendarBody);
calendarContainer.appendChild(months);
calendarContainer.appendChild(calendar);
document.body.appendChild(calendarContainer);
addEvent(calendarContainer, 'click', function(e) { handlers.calendarClick.call(self, e); });
return calendarContainer;
}
return function(elementId, userConfig) {
var self = this;
this.element = document.getElementById(elementId);
this.config = {
fullCurrentMonth: true,
dateFormat: 'F jS, Y'
};
this.currentYearView = date.current.year();
this.currentMonthView = date.current.month.integer();
if(userConfig) {
for(var key in userConfig) {
if(this.config.hasOwnProperty(key)) {
this.config[key] = userConfig[key];
}
}
}
this.documentClick = function(e) { handlers.documentClick.call(self, e); }
this.open = function(e) {
addEvent(document, 'click', self.documentClick);
foreach(datepickrs, function(datepickr) {
if(datepickr != self) {
datepickr.close();
}
});
self.calendar.style.display = 'block';
}
this.close = function() {
removeEvent(document, 'click', self.documentClick);
self.calendar.style.display = 'none';
document.getElementById("abb").focus();
}
this.calendar = buildCalendar.call(this);
datepickrs.push(this);
if(this.element.nodeName == 'INPUT') {
addEvent(this.element, 'focus', this.open);
} else {
addEvent(this.element, 'click', this.open);
}
}
})();
I've already tried with minDate: 0 but it didn't work.
Some ideas? Thanks.
try like this:
minDate:'0d'
$("#id").datepicker({ changeYear: true, dateFormat: 'dd/mm/yy', showOn: 'none', showButtonPanel: true, minDate:'0d' });
And check it after
alert( $("#id").datepicker( "option", "minDate" ));
Checkout the documentation of datepicker http://api.jqueryui.com/datepicker/ how to use minDate.
When you are using datepicker.js you have to use minDate property already provided in the library.
jsFiddle link i found googling.
You can pass the minDate param to the new Datepicker obj like this:
new datepickr('datepick',
{
fullCurrentMonth : true,
dateFormat : 'j-m-Y',
minDate: new Date(2007, 0, 1), //The format to pass in is: Year, Month (starting at 0), day
weekdays : [ 'Lunedì', 'Martedì',
'Mercoledì', 'Giovedì',
'Venerdì', 'Sabato',
'Domenica' ],
months : [ 'Gennaio', 'Febbraio',
'Marzo', 'Aprile',
'Maggio', 'Giugno',
'Luglio', 'Agosto',
'Settembre', 'Ottobre',
'Novembre', 'Dicembre' ],
});
Related
I am using script jquery-timeago but when i call function timeago i get this error.
......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
This is code:
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowPast: true,
allowFuture: false,
localeTitle: false,
cutoff: 0,
autoDispose: true,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: window.AGO,
suffixFromNow: window.NOW,
inPast: 'any moment now',
seconds: window.LESS_THEN_MINUITE,
minute: window.MINUTE,
minutes: "%d "+window.MINUTES,
hour: window.HOUR,
hours: "%d "+window.HOURS,
day: window.DAY,
days: "%d "+window.DAYS,
month: window.MONTH,
months: "%d "+window.MONTHS,
year: window.YEAR,
years: "%d "+window.YEARS,
wordSeparator: " ",
numbers: []
}
},
inWords: function(distanceMillis) {
if (!this.settings.allowPast && ! this.settings.allowFuture) {
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
}
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
if (!this.settings.allowPast && distanceMillis >= 0) {
return this.settings.strings.inPast;
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));
var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) { separator = " "; }
return $.trim([prefix, words, suffix].join(separator));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});
// functions that can be called via $(el).timeago('action')
// init is default when no action is given
// functions are called with context of a single element
var functions = {
init: function() {
functions.dispose.call(this);
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
}
},
update: function(timestamp) {
var date = (timestamp instanceof Date) ? timestamp : $t.parse(timestamp);
$(this).data('timeago', { datetime: date });
if ($t.settings.localeTitle) {
$(this).attr("title", date.toLocaleString());
}
refresh.apply(this);
},
updateFromDOM: function() {
$(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
refresh.apply(this);
},
dispose: function () {
if (this._timeagoInterval) {
window.clearInterval(this._timeagoInterval);
this._timeagoInterval = null;
}
}
};
$.fn.timeago = function(action, options) {
var fn = action ? functions[action] : functions.init;
if (!fn) {
throw new Error("Unknown function name '"+ action +"' for timeago");
}
// each over objects here and call the requested function
this.each(function() {
fn.call(this, options);
});
return this;
};
function refresh() {
var $s = $t.settings;
//check if it's still visible
if ($s.autoDispose && !$.contains(document.documentElement,this)) {
//stop if it has been removed
$(this).timeago("dispose");
return this;
}
var data = prepareData(this);
if (!isNaN(data.datetime)) {
if ( $s.cutoff === 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
$(this).text(inWords(data.datetime));
} else {
if ($(this).attr('title').length > 0) {
$(this).text($(this).attr('title'));
}
}
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if ($t.settings.localeTitle) {
element.attr("title", element.data('timeago').datetime.toLocaleString());
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}));
//call function timeago
$(document).ready(function() {
$("time.timeago").timeago();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<time dir="auto" class="timeago" datetime="2018-07-28 21:08:57"></time>
The strings can't find value of window.* , you should try another way to translate strings.
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowPast: true,
allowFuture: false,
localeTitle: false,
cutoff: 0,
autoDispose: true,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
inPast: 'any moment now',
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
wordSeparator: " ",
numbers: []
}
},
inWords: function(distanceMillis) {
if (!this.settings.allowPast && ! this.settings.allowFuture) {
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
}
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
if (!this.settings.allowPast && distanceMillis >= 0) {
return this.settings.strings.inPast;
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));
var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) { separator = " "; }
return $.trim([prefix, words, suffix].join(separator));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});
// functions that can be called via $(el).timeago('action')
// init is default when no action is given
// functions are called with context of a single element
var functions = {
init: function() {
functions.dispose.call(this);
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
}
},
update: function(timestamp) {
var date = (timestamp instanceof Date) ? timestamp : $t.parse(timestamp);
$(this).data('timeago', { datetime: date });
if ($t.settings.localeTitle) {
$(this).attr("title", date.toLocaleString());
}
refresh.apply(this);
},
updateFromDOM: function() {
$(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
refresh.apply(this);
},
dispose: function () {
if (this._timeagoInterval) {
window.clearInterval(this._timeagoInterval);
this._timeagoInterval = null;
}
}
};
$.fn.timeago = function(action, options) {
var fn = action ? functions[action] : functions.init;
if (!fn) {
throw new Error("Unknown function name '"+ action +"' for timeago");
}
// each over objects here and call the requested function
this.each(function() {
fn.call(this, options);
});
return this;
};
function refresh() {
var $s = $t.settings;
//check if it's still visible
if ($s.autoDispose && !$.contains(document.documentElement,this)) {
//stop if it has been removed
$(this).timeago("dispose");
return this;
}
var data = prepareData(this);
if (!isNaN(data.datetime)) {
if ( $s.cutoff === 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
$(this).text(inWords(data.datetime));
} else {
if ($(this).attr('title').length > 0) {
$(this).text($(this).attr('title'));
}
}
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if ($t.settings.localeTitle) {
element.attr("title", element.data('timeago').datetime.toLocaleString());
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}));
//call function timeago
$(document).ready(function() {
$("time.timeago").timeago();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<time dir="auto" class="timeago" datetime="2018-07-28 21:08:57"></time>
Please be aware that I am a total noob at JS, sorry if I don't understand basic coding language. Solutions are very welcome. Thanks!
I have created my own form and have two input fields which consist of 'date of incident' and 'time of incident'. The user will need to select a date either the current date or previous dates only. Then the user will select a time and if the user selected the current date it can only be before the current time. Otherwise anytime is ok.
I have already developed the datepicker for 'date of incident' but I need all the dates after the current date to be grayed out, im not sure if I will need to use 'minDate' or 'maxDate' for this and if I will need to implement it to a existing function or create a new one.
For the 'time of incident' I am using 'type="time".
I have got a little bit of an idea for the date of incident:
futureDates = dates after current date
currentDate = today
futureDates = greyed out
But I am starting out with JavaScript and don't really know how to implement it properly into the code.
HTML:
<input id="datepick" placeholder="Enter the date of incident" type="text"/>
<input id="timepick" placeholder="Enter the time of incident" type="time"/>
Javascript for Datepicker:
var datepickr = (function() {
var datepickrs = [],
currentDate = new Date(),
date = {
current: {
year: function() {
return currentDate.getFullYear();
},
month: {
integer: function() {
return currentDate.getMonth();
},
string: function(full, months) {
var date = currentDate.getMonth();
return monthToStr(date, full, months);
minDate: currentDate;
}
},
day: function() {
return currentDate.getDate();
}
},
month: {
string: function(full, currentMonthView, months) {
var date = currentMonthView;
return monthToStr(date, full, months);
},
numDays: function(currentMonthView, currentYearView) {
/* checks to see if february is a leap year otherwise return the respective # of days */
return (currentMonthView == 1 && !(currentYearView & 3) && (currentYearView % 1e2 || !(currentYearView % 4e2))) ? 29 : daysInMonth[currentMonthView];
}
}
},
daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
buildCache = [],
handlers = {
calendarClick: function(e) {
if(e.target.className) {
switch(e.target.className) {
case 'prev-month':
case 'prevMonth':
this.currentMonthView--;
if(this.currentMonthView < 0) {
this.currentYearView--;
this.currentMonthView = 11;
}
rebuildCalendar.call(this);
break;
case 'next-month':
case 'nextMonth':
this.currentMonthView++;
if(this.currentMonthView > 11) {
this.currentYearView++;
this.currentMonthView = 0;
}
rebuildCalendar.call(this);
break;
case 'day':
this.element.value = formatDate(new Date(this.currentYearView, this.currentMonthView, e.target.innerHTML).getTime(), this.config);
this.close();
break;
}
}
},
documentClick: function(e) {
if(e.target != this.element && e.target != this.calendar) {
var parentNode = e.target.parentNode;
if(parentNode != this.calender) {
while(parentNode != this.calendar) {
parentNode = parentNode.parentNode;
if(parentNode == null) {
this.close();
break;
}
}
}
}
}
};
function formatDate(milliseconds, config) {
var formattedDate = '',
dateObj = new Date(milliseconds),
format = {
d: function() {
var day = format.j();
return (day < 10) ? '0' + day : day;
},
D: function() {
return config.weekdays[format.w()].substring(0, 3);
},
j: function() {
return dateObj.getDate();
},
l: function() {
return config.weekdays[format.w()];
},
S: function() {
return config.suffix[format.j()] || config.defaultSuffix;
},
w: function() {
return dateObj.getDay();
},
F: function() {
return monthToStr(format.n(), true, config.months);
},
m: function() {
var month = format.n() + 1;
return (month < 10) ? '0' + month : month;
},
M: function() {
return monthToStr(format.n(), false, config.months);
},
n: function() {
return dateObj.getMonth();
},
Y: function() {
return dateObj.getFullYear();
},
y: function() {
return format.Y().toString().substring(2, 4);
}
},
formatPieces = config.dateFormat.split('');
foreach(formatPieces, function(formatPiece, index) {
if(format[formatPiece] && formatPieces[index - 1] != '\\') {
formattedDate += format[formatPiece]();
} else {
if(formatPiece != '\\') {
formattedDate += formatPiece;
}
}
});
return formattedDate;
}
function foreach(items, callback) {
var i = 0, x = items.length;
for(i; i < x; i++) {
if(callback(items[i], i) === false) {
break;
}
}
}
function addEvent(element, eventType, callback) {
if(element.addEventListener) {
element.addEventListener(eventType, callback, false);
} else if(element.attachEvent) {
var fixedCallback = function(e) {
e = e || window.event;
e.preventDefault = (function(e) {
return function() { e.returnValue = false; }
})(e);
e.stopPropagation = (function(e) {
return function() { e.cancelBubble = true; }
})(e);
e.target = e.srcElement;
callback.call(element, e);
};
element.attachEvent('on' + eventType, fixedCallback);
}
}
function removeEvent(element, eventType, callback) {
if(element.removeEventListener) {
element.removeEventListener(eventType, callback, false);
} else if(element.detachEvent) {
element.detachEvent('on' + eventType, callback);
}
}
function buildNode(nodeName, attributes, content) {
var element;
if(!(nodeName in buildCache)) {
buildCache[nodeName] = document.createElement(nodeName);
}
element = buildCache[nodeName].cloneNode(false);
if(attributes != null) {
for(var attribute in attributes) {
element[attribute] = attributes[attribute];
}
}
if(content != null) {
if(typeof(content) == 'object') {
element.appendChild(content);
} else {
element.innerHTML = content;
}
}
return element;
}
function monthToStr(date, full, months) {
return ((full == true) ? months[date] : ((months[date].length > 3) ? months[date].substring(0, 3) : months[date]));
}
function isToday(day, currentMonthView, currentYearView) {
return day == date.current.day() && currentMonthView == date.current.month.integer() && currentYearView == date.current.year();
}
function buildWeekdays(weekdays) {
var weekdayHtml = document.createDocumentFragment();
foreach(weekdays, function(weekday) {
weekdayHtml.appendChild(buildNode('th', {}, weekday.substring(0, 2)));
});
return weekdayHtml;
}
function rebuildCalendar() {
while(this.calendarBody.hasChildNodes()){
this.calendarBody.removeChild(this.calendarBody.lastChild);
}
var firstOfMonth = new Date(this.currentYearView, this.currentMonthView, 1).getDay(),
numDays = date.month.numDays(this.currentMonthView, this.currentYearView);
this.currentMonth.innerHTML = date.month.string(this.config.fullCurrentMonth, this.currentMonthView, this.config.months) + ' ' + this.currentYearView;
this.calendarBody.appendChild(buildDays(firstOfMonth, numDays, this.currentMonthView, this.currentYearView));
}
function buildCurrentMonth(config, currentMonthView, currentYearView, months) {
return buildNode('span', { className: 'current-month' }, date.month.string(config.fullCurrentMonth, currentMonthView, months) + ' ' + currentYearView);
}
function buildMonths(config, currentMonthView, currentYearView) {
var months = buildNode('div', { className: 'months' }),
prevMonth = buildNode('span', { className: 'prev-month' }, buildNode('span', { className: 'prevMonth' }, '<')),
nextMonth = buildNode('span', { className: 'next-month' }, buildNode('span', { className: 'nextMonth' }, '>'));
months.appendChild(prevMonth);
months.appendChild(nextMonth);
return months;
}
function buildDays(firstOfMonth, numDays, currentMonthView, currentYearView) {
var calendarBody = document.createDocumentFragment(),
row = buildNode('tr'),
dayCount = 0, i;
/* print out previous month's "days" */
for(i = 1; i <= firstOfMonth; i++) {
row.appendChild(buildNode('td', null, ' '));
dayCount++;
}
for(i = 1; i <= numDays; i++) {
/* if we have reached the end of a week, wrap to the next line */
if(dayCount == 7) {
calendarBody.appendChild(row);
row = buildNode('tr');
dayCount = 0;
}
var todayClassName = isToday(i, currentMonthView, currentYearView) ? { className: 'today' } : null;
row.appendChild(buildNode('td', todayClassName, buildNode('span', { className: 'day' }, i)));
dayCount++;
}
/* if we haven't finished at the end of the week, start writing out the "days" for the next month */
for(i = 1; i <= (7 - dayCount); i++) {
row.appendChild(buildNode('td', null, ' '));
}
calendarBody.appendChild(row);
return calendarBody;
}
function buildCalendar() {
var firstOfMonth = new Date(this.currentYearView, this.currentMonthView, 1).getDay(),
numDays = date.month.numDays(this.currentMonthView, this.currentYearView),
self = this;
var inputLeft = inputTop = 0,
obj = this.element;
if(obj.offsetParent) {
do {
inputLeft += obj.offsetLeft;
inputTop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
var calendarContainer = buildNode('div', { className: 'calendar' });
calendarContainer.style.cssText = 'display: none; position: absolute; top: ' + (inputTop + this.element.offsetHeight) + 'px; left: ' + inputLeft + 'px; z-index: 100;';
this.currentMonth = buildCurrentMonth(this.config, this.currentMonthView, this.currentYearView, this.config.months)
var months = buildMonths(this.config, this.currentMonthView, this.currentYearView);
months.appendChild(this.currentMonth);
var calendar = buildNode('table', null, buildNode('thead', null, buildNode('tr', { className: 'weekdays' }, buildWeekdays(this.config.weekdays))));
this.calendarBody = buildNode('tbody');
this.calendarBody.appendChild(buildDays(firstOfMonth, numDays, this.currentMonthView, this.currentYearView));
calendar.appendChild(this.calendarBody);
calendarContainer.appendChild(months);
calendarContainer.appendChild(calendar);
document.body.appendChild(calendarContainer);
addEvent(calendarContainer, 'click', function(e) { handlers.calendarClick.call(self, e); });
return calendarContainer;
}
return function(elementId, userConfig) {
var self = this;
this.element = document.getElementById(elementId);
this.config = {
fullCurrentMonth: true,
dateFormat: 'F jS, Y',
weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
suffix: { 1: 'st', 2: 'nd', 3: 'rd', 21: 'st', 22: 'nd', 23: 'rd', 31: 'st' },
defaultSuffix: 'th'
};
this.currentYearView = date.current.year();
this.currentMonthView = date.current.month.integer();
if(userConfig) {
for(var key in userConfig) {
if(this.config.hasOwnProperty(key)) {
this.config[key] = userConfig[key];
}
}
}
this.documentClick = function(e) { handlers.documentClick.call(self, e); }
this.open = function(e) {
addEvent(document, 'click', self.documentClick);
foreach(datepickrs, function(datepickr) {
if(datepickr != self) {
datepickr.close();
}
});
self.calendar.style.display = 'block';
}
this.close = function() {
removeEvent(document, 'click', self.documentClick);
self.calendar.style.display = 'none';
}
this.calendar = buildCalendar.call(this);
datepickrs.push(this);
if(this.element.nodeName == 'INPUT') {
addEvent(this.element, 'focus', this.open);
} else {
addEvent(this.element, 'click', this.open);
}
}
})();
Sorry I don't have any code for my 'Time of Incident' field but I have a small psuedocode that I would like to turn into JavaScript and implement it into my code:
currentDate = new Date()
currentTime = new Date(time)
function timeSelect{
if{
datepicker = currentDate
{
time = currentTime (Can't select time past now, greyed out)
else
{
any time can be selected
}
Thank you for your time, it really helps me out.
-MrMaestro
I need a datepicker for our project and whilst looking online.. I found one. However, it disables to allow future dates. I tried looking into the code but I cannot fully understand it. I'm kind of new to JQuery.
This is the code (it's very long, sorry):
<script>
$.datepicker._defaults.isDateSelector = false;
$.datepicker._defaults.onAfterUpdate = null;
$.datepicker._defaults.base_update = $.datepicker._updateDatepicker;
$.datepicker._defaults.base_generate = $.datepicker._generateHTML;
function DateRange(options) {
if (!options.startField) throw "Missing Required Start Field!";
if (!options.endField) throw "Missing Required End Field!";
var isDateSelector = true;
var cur = -1,prv = -1, cnt = 0;
var df = options.dateFormat ? options.dateFormat:'mm/dd/yy';
var RangeType = {ID:'rangetype',BOTH:0,START:1,END:2};
var sData = {input:$(options.startField),div:$(document.createElement("DIV"))};
var eData = {input:null,div:null};
/*
* Overloading JQuery DatePicker to add functionality - This should use WidgetFactory!
*/
$.datepicker._updateDatepicker = function (inst) {
var base = this._get(inst, 'base_update');
base.call(this, inst);
if (isDateSelector) {
var onAfterUpdate = this._get(inst, 'onAfterUpdate');
if (onAfterUpdate) onAfterUpdate.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ''), inst]);
}
};
$.datepicker._generateHTML = function (inst) {
var base = this._get(inst, 'base_generate');
var thishtml = base.call(this, inst);
var ds = this._get(inst, 'isDateSelector');
if (isDateSelector) {
thishtml = $('<div />').append(thishtml);
thishtml = thishtml.children();
}
return thishtml;
};
function _hideSDataCalendar() {
sData.div.hide();
}
function _hideEDataCalendar() {
eData.div.hide();
}
function _handleOnSelect(dateText, inst, type) {
var localeDateText = $.datepicker.formatDate(df, new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay));
// 0 = sData, 1 = eData
switch(cnt) {
case 0:
sData.input.val(localeDateText);
eData.input.val('');
cnt=1;
break;
case 1:
if (sData.input.val()) {
var s = $.datepicker.parseDate(df,sData.input.val()).getTime();
var e = $.datepicker.parseDate(df,localeDateText).getTime();
if (e >= s) {
eData.input.val(localeDateText);
cnt=0;
}
}
}
}
function _handleBeforeShowDay(date, type) {
// Allow future dates?
var f = (options.allowFuture || date < new Date());
switch(type)
{
case RangeType.BOTH:
return [true, ((date.getTime() >= Math.min(prv, cur) && date.getTime() <= Math.max(prv, cur)) ?
'ui-daterange-selected' : '')];
case RangeType.END:
var s2 = null;
if (sData.input && sData.input.val()) {
try{
s2 = $.datepicker.parseDate(df,sData.input.val()).getTime();
}catch(e){}
}
var e2 = null;
if (eData.input && eData.input.val()) {
try {
e2 = $.datepicker.parseDate(df,eData.input.val()).getTime();
}catch(e){}
}
var drs = 'ui-daterange-selected';
var t = date.getTime();
if (s2 && !e2) {
return [(t >= s2 || cnt === 0) && f, (t===s2) ? drs:''];
}
if (s2 && e2) {
return [f, (t >= s2 && t <= e2) ? drs:''];
}
if (e2 && !s2) {
return [t < e2 && f,(t < e2) ? drs:''];
}
return [f,''];
}
}
function _attachCloseOnClickOutsideHandlers() {
$('html').click(function(e) {
var t = $(e.target);
if (sData.div.css('display') !== 'none') {
if (sData.input.is(t) || sData.div.has(t).length || /(ui-icon|ui-corner-all)/.test(e.target.className)) {
e.stopPropagation();
}else{
_hideSDataCalendar();
}
}
if (eData && eData.div.css('display') !== 'none') {
if (eData.input.is(t) || eData.div.has(t).length || /(ui-icon|ui-corner-all)/.test(e.target.className)) {
e.stopPropagation();
}else{
_hideEDataCalendar();
}
}
});
}
function _alignContainer(data, alignment) {
var dir = {right:'left',left:'right'};
var css = {
position: 'absolute',
top: data.input.position().top + data.input.outerHeight(true)
};
css[alignment ? dir[alignment]:'right'] = '0em';
data.div.css(css);
}
function _handleChangeMonthYear(year, month, inst) {
// What do we want to do here to sync?
}
function _focusStartDate(e) {
cnt = 0;
sData.div.datepicker('refresh');
_alignContainer(sData,options.opensTo);
sData.div.show();
_hideEDataCalendar();
}
function _focusEndDate(e) {
cnt = 1;
_alignContainer(eData,options.opensTo);
eData.div.datepicker('refresh');
eData.div.show();
sData.div.datepicker('refresh');
sData.div.hide();
}
// Build the start input element
sData.input.attr(RangeType.ID, options.endField ? RangeType.START : RangeType.BOTH);
sData.div.attr('id',sData.input.attr('id')+'_cDiv');
sData.div.addClass('ui-daterange-calendar');
sData.div.hide();
var pDiv = $(document.createElement("DIV"));
pDiv.addClass('ui-daterange-container');
// Move the dom around
sData.input.before(pDiv);
pDiv.append(sData.input.detach());
pDiv.append(sData.div);
sData.input.on('focus', _focusStartDate);
sData.input.keydown(function(e){if(e.keyCode==9){return false;}});
sData.input.keyup(function(e){
_handleKeyUp(e, options.endField ? RangeType.START : RangeType.BOTH);
});
_attachCloseOnClickOutsideHandlers();
var sDataOptions = {
showButtonPanel: true,
changeMonth: true,
changeYear: true,
isDateSelector: true,
beforeShow:function(){sData.input.datepicker('refresh');},
beforeShowDay: function(date){
return _handleBeforeShowDay(date, options.endField ? RangeType.END : RangeType.BOTH);
},
onChangeMonthYear: _handleChangeMonthYear,
onSelect: function(dateText, inst) {
return _handleOnSelect(dateText,inst,options.endField ? RangeType.END : RangeType.BOTH);
},
onAfterUpdate: function(){
$('<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">Done</button>')
.appendTo($('#'+sData.div.attr('id') + ' .ui-datepicker-buttonpane'))
.on('click', function () {
sData.div.hide();
});
}
};
sData.div.datepicker($.extend({}, options, sDataOptions));
// Attach the end input element
if (options.endField) {
eData.input = $(options.endField);
if (eData.input.length > 1 || !eData.input.is("input")) {
throw "Illegal element provided for end range input!";
}
if (!eData.input.attr('id')) {eData.input.attr('id','dp_'+new Date().getTime());}
eData.input.attr(RangeType.ID, RangeType.END);
eData.div = $(document.createElement("DIV"));
eData.div.addClass('ui-daterange-calendar');
eData.div.attr('id',eData.input.attr('id')+'_cDiv');
eData.div.hide();
pDiv = $(document.createElement("DIV"));
pDiv.addClass('ui-daterange-container');
// Move the dom around
eData.input.before(pDiv);
pDiv.append(eData.input.detach());
pDiv.append(eData.div);
eData.input.on('focus', _focusEndDate);
// Add Keyup handler
eData.input.keyup(function(e){
_handleKeyUp(e, RangeType.END);
});
var eDataOptions = {
showButtonPanel: true,
changeMonth: true,
changeYear: true,
isDateSelector: true,
beforeShow:function(){sData.input.datepicker('refresh');},
beforeShowDay: function(date){
return _handleBeforeShowDay(date, RangeType.END);
},
onSelect: function(dateText, inst) {
return _handleOnSelect(dateText,inst,RangeType.END);
},
onAfterUpdate: function(){
$('<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">Done</button>')
.appendTo($('#'+eData.div.attr('id') + ' .ui-datepicker-buttonpane'))
.on('click', function () {
eData.div.hide();
});
}
};
eData.div.datepicker($.extend({}, options, eDataOptions));
}
return {
// Returns an array of dates[start,end]
getDates: function getDates() {
var dates = [];
var sDate = sData.input.val();
if (sDate) {
try {
dates.push($.datepicker.parseDate(df,sDate));
}catch(e){}
}
var eDate = (eData.input) ? eData.input.val():null;
if (eDate) {
try {
dates.push($.datepicker.parseDate(df,eDate));
}catch(e){}
}
return dates;
},
// Returns the end date as a js date
getStartDate: function getStartDate() {
try {
return $.datepicker.parseDate(df,sData.input.val());
}catch(e){}
},
// Returns the start date as a js date
getEndDate: function getEndDate() {
try {
return $.datepicker.parseDate(df,eData.input.val());
}catch(e){}
}
};
}
var cfg = {startField: '#fromDate', endField: '#toDate',opensTo: 'Left', numberOfMonths: 3, defaultDate: -50};
var dr = new DateRange(cfg);
</script>
There is a comment along the code that says, "Allow Future Dates?" That's where I tried looking but I had no luck for hours now. Please help me.
This is how the date range picker looks like in my page:
Thank you so much for your help.
UPDATE: JSFIDDLE http://jsfiddle.net/dacrazycoder/4Fppd/
In cfg, add a property with key allowFuture with the value of true
http://jsfiddle.net/4Fppd/85/
I have a javascript datepicker which works perfectly, with one exception. If the user tabs out of the form field without selecting a date, the datepicker remains on the screen. I need to destroy onBlur but not sure where.
The function calling the date picker in the body is:
<script type="text/javascript" src="../Datepicker/datepickr.js"></script>
<script type="text/javascript">
new datepickr('effectiveDate', {
'dateFormat': 'n/j/Y'
});
</script>
The content of the js file is:
var datepickr = (function() {
var datepickrs = [],
currentDate = new Date(setAllDates(3)),
date = {
current: {
year: function() {
return currentDate.getFullYear();
},
month: {
integer: function() {
return currentDate.getMonth();
},
string: function(full) {
var date = currentDate.getMonth();
return monthToStr(date, full);
}
},
day: function() {
return currentDate.getDate();
}
},
month: {
string: function(full, currentMonthView) {
var date = currentMonthView;
return monthToStr(date, full);
},
numDays: function(currentMonthView, currentYearView) {
// checks to see if february is a leap year otherwise return the respective # of days
return (currentMonthView == 1 && !(currentYearView & 3) && (currentYearView % 1e2 || !(currentYearView % 4e2))) ? 29 : daysInMonth[currentMonthView];
}
}
},
weekdays = ['Sun', 'Mon', 'Tues', 'Wednes', 'Thurs', 'Fri', 'Satur'],
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
suffix = { 1: 'st', 2: 'nd', 3: 'rd', 21: 'st', 22: 'nd', 23: 'rd', 31: 'st' },
buildCache = [],
handlers = {
calendarClick: function(e) {
if(e.target.className) {
switch(e.target.className) {
case 'prev-month':
case 'prevMonth':
this.currentMonthView--;
if(this.currentMonthView < 0) {
this.currentYearView--;
this.currentMonthView = 11;
}
rebuildCalendar.call(this);
break;
case 'next-month':
case 'nextMonth':
this.currentMonthView++;
if(this.currentMonthView > 11) {
this.currentYearView++;
this.currentMonthView = 0;
}
rebuildCalendar.call(this);
break;
case 'day':
this.element.value = formatDate(new Date(this.currentYearView, this.currentMonthView, e.target.innerHTML).getTime(), this.config.dateFormat);
this.close();
break;
}
}
},
documentClick: function(e) {
if(e.target != this.element && e.target != this.calendar) {
var parentNode = e.target.parentNode;
if(parentNode != this.calender) {
while(parentNode != this.calendar) {
parentNode = parentNode.parentNode;
if(parentNode == null) {
this.close();
break;
}
}
}
}
}
};
function formatDate(milliseconds, dateFormat) {
var formattedDate = '',
dateObj = new Date(milliseconds),
format = {
d: function() {
var day = format.j();
return (day < 10) ? '0' + day : day;
},
D: function() {
return weekdays[format.w()].substring(0, 3);
},
j: function() {
return dateObj.getDate();
},
l: function() {
return weekdays[format.w()] + 'day';
},
S: function() {
return suffix[format.j()] || 'th';
},
w: function() {
return dateObj.getDay();
},
F: function() {
return monthToStr(format.n(), true);
},
m: function() {
var month = format.n() + 1;
return (month < 10) ? '0' + month : month;
},
M: function() {
return monthToStr(format.n(), false);
},
n: function() {
return dateObj.getMonth() + 1;
},
Y: function() {
return dateObj.getFullYear();
},
y: function() {
return format.Y().toString().substring(2, 4);
}
},
formatPieces = dateFormat.split('');
foreach(formatPieces, function(formatPiece) {
formattedDate += format[formatPiece] ? format[formatPiece]() : formatPiece;
});
return formattedDate;
}
function foreach(items, callback) {
var i = 0, x = items.length;
for(i; i < x; i++) {
if(callback(items[i], i) === false) {
break;
}
}
}
function addEvent(element, eventType, callback) {
if(element.addEventListener) {
element.addEventListener(eventType, callback, false);
} else if(element.attachEvent) {
var fixedCallback = function(e) {
e = e || window.event;
e.preventDefault = (function(e) {
return function() { e.returnValue = false; }
})(e);
e.stopPropagation = (function(e) {
return function() { e.cancelBubble = true; }
})(e);
e.target = e.srcElement;
callback.call(element, e);
};
element.attachEvent('on' + eventType, fixedCallback);
}
}
function removeEvent(element, eventType, callback) {
if(element.removeEventListener) {
element.removeEventListener(eventType, callback, false);
} else if(element.detachEvent) {
element.detachEvent('on' + eventType, callback);
}
}
function buildNode(nodeName, attributes, content) {
var element;
if(!(nodeName in buildCache)) {
buildCache[nodeName] = document.createElement(nodeName);
}
element = buildCache[nodeName].cloneNode(false);
if(attributes != null) {
for(var attribute in attributes) {
element[attribute] = attributes[attribute];
}
}
if(content != null) {
if(typeof(content) == 'object') {
element.appendChild(content);
} else {
element.innerHTML = content;
}
}
return element;
}
function monthToStr(date, full) {
return ((full == true) ? months[date] : ((months[date].length > 3) ? months[date].substring(0, 3) : months[date]));
}
function isToday(day, currentMonthView, currentYearView) {
return day == date.current.day() && currentMonthView == date.current.month.integer() && currentYearView == date.current.year();
}
function buildWeekdays() {
var weekdayHtml = document.createDocumentFragment();
foreach(weekdays, function(weekday) {
weekdayHtml.appendChild(buildNode('th', {}, weekday.substring(0, 2)));
});
return weekdayHtml;
}
function rebuildCalendar() {
while(this.calendarBody.hasChildNodes()){
this.calendarBody.removeChild(this.calendarBody.lastChild);
}
var firstOfMonth = new Date(this.currentYearView, this.currentMonthView, 1).getDay(),
numDays = date.month.numDays(this.currentMonthView, this.currentYearView);
this.currentMonth.innerHTML = date.month.string(this.config.fullCurrentMonth, this.currentMonthView) + ' ' + this.currentYearView;
this.calendarBody.appendChild(buildDays(firstOfMonth, numDays, this.currentMonthView, this.currentYearView));
}
function buildCurrentMonth(config, currentMonthView, currentYearView) {
return buildNode('span', { className: 'current-month' }, date.month.string(config.fullCurrentMonth, currentMonthView) + ' ' + currentYearView);
}
function buildMonths(config, currentMonthView, currentYearView) {
var months = buildNode('div', { className: 'months' }),
prevMonth = buildNode('span', { className: 'prev-month' }, buildNode('span', { className: 'prevMonth' }, '<')),
nextMonth = buildNode('span', { className: 'next-month' }, buildNode('span', { className: 'nextMonth' }, '>'));
months.appendChild(prevMonth);
months.appendChild(nextMonth);
return months;
}
function buildDays(firstOfMonth, numDays, currentMonthView, currentYearView) {
var calendarBody = document.createDocumentFragment(),
row = buildNode('tr'),
dayCount = 0, i;
// print out previous month's "days"
for(i = 1; i <= firstOfMonth; i++) {
row.appendChild(buildNode('td', null, ' '));
dayCount++;
}
for(i = 1; i <= numDays; i++) {
// if we have reached the end of a week, wrap to the next line
if(dayCount == 7) {
calendarBody.appendChild(row);
row = buildNode('tr');
dayCount = 0;
}
var todayClassName = isToday(i, currentMonthView, currentYearView) ? { className: 'today' } : null;
row.appendChild(buildNode('td', todayClassName, buildNode('span', { className: 'day' }, i)));
dayCount++;
}
// if we haven't finished at the end of the week, start writing out the "days" for the next month
for(i = 1; i <= (7 - dayCount); i++) {
row.appendChild(buildNode('td', null, ' '));
}
calendarBody.appendChild(row);
return calendarBody;
}
function buildCalendar() {
var firstOfMonth = new Date(this.currentYearView, this.currentMonthView, 1).getDay(),
numDays = date.month.numDays(this.currentMonthView, this.currentYearView),
self = this;
var inputLeft = inputTop = 0,
obj = this.element;
if(obj.offsetParent) {
do {
inputLeft += obj.offsetLeft;
inputTop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
var calendarContainer = buildNode('div', { className: 'calendar' });
calendarContainer.style.cssText = 'display: none; position: absolute; top: ' + (inputTop + this.element.offsetHeight) + 'px; left: ' + inputLeft + 'px; z-index: 100;';
this.currentMonth = buildCurrentMonth(this.config, this.currentMonthView, this.currentYearView)
var months = buildMonths(this.config, this.currentMonthView, this.currentYearView);
months.appendChild(this.currentMonth);
var calendar = buildNode('table', null, buildNode('thead', null, buildNode ('tr', { className: 'weekdays' }, buildWeekdays())));
this.calendarBody = buildNode('tbody');
this.calendarBody.appendChild(buildDays(firstOfMonth, numDays, this.currentMonthView, this.currentYearView));
calendar.appendChild(this.calendarBody);
calendarContainer.appendChild(months);
calendarContainer.appendChild(calendar);
document.body.appendChild(calendarContainer);
addEvent(calendarContainer, 'click', function(e) { handlers.calendarClick.call(self, e); });
return calendarContainer;
}
return function(elementId, userConfig) {
var self = this;
this.element = document.getElementById(elementId);
this.config = {
fullCurrentMonth: true,
dateFormat: 'F jS, Y'
};
this.currentYearView = date.current.year();
this.currentMonthView = date.current.month.integer();
if(userConfig) {
for(var key in userConfig) {
if(this.config.hasOwnProperty(key)) {
this.config[key] = userConfig[key];
}
}
}
this.documentClick = function(e) { handlers.documentClick.call(self, e); }
this.open = function(e) {
addEvent(document, 'click', self.documentClick);
foreach(datepickrs, function(datepickr) {
if(datepickr != self) {
datepickr.close();
}
});
self.calendar.style.display = 'block';
}
this.close = function() {
removeEvent(document, 'click', self.documentClick);
self.calendar.style.display = 'none';
}
this.calendar = buildCalendar.call(this);
datepickrs.push(this);
if(this.element.nodeName == 'INPUT') {
addEvent(this.element, 'focus', this.open);
} else {
addEvent(this.element, 'click', this.open);
}
}
})();
Try to add this (look at the end of datepickr.js):
if(this.element.nodeName == 'INPUT') {
addEvent(this.element, 'focus', this.open);
addEvent(this.element, 'blur', this.close); // <--- Add this line
} else {
addEvent(this.element, 'click', this.open);
}
var d = new datepickr('effectiveDate', {
'dateFormat': 'n/j/Y'
});
document.getElementById('effectiveDate').addEventListener('blur', function (e) {
d.close();
});
I really like this calendar plugin for my mobile site: https://github.com/michaelkamphausen/jsCalendar
Seen working here: http://jsfiddle.net/dQxVV/1/
I am pretty new at JS and am having trouble figuring out
How to collect the selected start and end dates (place them into an input value)
How to show more than one month.
I really appreciate any help on this or if you have a suggestion for a better mobile friendly calendar.
JS building date range calendar:
$(".jsCalendar").bind("startDateChanged", function () {
$(this).data("startdate");
}).bind("endDateChanged", function () {
$(this).data("enddate");
});
calendar.js
(function() {
$(document).ready(function() {
var $calendars = $(".jsCalendar");
for (var i = 0, maxI = $calendars.length; i < maxI; i++) {
var calendar = new Calendar();
calendar.ready($calendars.eq(i));
}
});
function Calendar() {
var self = this,
$calendar,
$previous,
$next,
$month,
$weekdays,
$days,
$rows,
startDate,
endDate,
currentMonth,
today,
minDate,
dateInfo,
singleDate,
firstDayOfWeek = 0,
tap = 'click',
noAnimEnd = "noAnimationEnd",
startDateString = "startDate",
endDateString = "endDate",
setDate = function (type, value) {
value && value.clearTime && value.clearTime();
if (type == startDateString) {
startDate = value;
} else {
endDate = value;
}
drawSelection();
$calendar.data(type.toLowerCase(), !value ? "" : value.toString());
$calendar.trigger(type + "Changed");
},
dateSelected = function (evt) {
evt.preventDefault();
var $this = $(this);
if ($this.hasClass("inactive") || ($this.text().length == 0)) {
return;
}
var selectedDate = new Date(currentMonth.getFullYear(), currentMonth.getMonth(), parseInt($this.text()));
if (singleDate) {
setDate(startDateString, !startDate || (selectedDate.getTime() != startDate.getTime()) ? selectedDate : null);
return;
}
if (!startDate) {
if (!endDate) {
setDate(startDateString, selectedDate);
} else {
if (selectedDate < endDate) {
setDate(startDateString, selectedDate);
} else if (endDate < selectedDate) {
setDate(startDateString, endDate);
setDate(endDateString, selectedDate);
} else {
setDate(endDateString, null);
}
}
} else if (!endDate) {
if (startDate < selectedDate) {
setDate(endDateString, selectedDate);
} else if (selectedDate < startDate) {
setDate(endDateString, startDate);
setDate(startDateString, selectedDate);
} else {
setDate(startDateString, null);
}
} else {
if ($this.hasClass(startDateString)) {
setDate(startDateString, null);
} else if ($this.hasClass(endDateString)) {
setDate(endDateString, null);
} else {
setDate(startDateString, null);
setDate(endDateString, null);
}
}
},
extendDate = function () {
/* subset from date.js, http://www.datejs.com/ */
Date.prototype.clone=function(){return new Date(this.getTime());}
Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));}
Date.prototype.getDaysInMonth=function(){return [31,(this.isLeapYear(this.getFullYear())?29:28),31,30,31,30,31,31,30,31,30,31][this.getMonth()];}
Date.prototype.moveToFirstDayOfMonth=function(){this.setDate(1);return this;}
Date.prototype.moveToLastDayOfMonth=function(){this.setDate(this.getDaysInMonth());return this;}
Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;}
Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);}
Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;}
Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;}
},
getDay = function (day) {
return (day + firstDayOfWeek) % 7; // changing first day of week
},
drawSelection = function () {
$days.removeClass(startDateString).removeClass(endDateString).removeClass("betweenDates");
var firstDay = currentMonth.clone().moveToFirstDayOfMonth();
var lastDay = currentMonth.clone().moveToLastDayOfMonth();
var dayOffset = getDay(firstDay.getDay()) - 1;
if (!!startDate && !!endDate && (startDate < lastDay) && (endDate > firstDay)) {
var firstBetweenDay = new Date(Math.max(firstDay, startDate.clone().addDays(1)));
var lastBetweenDay = new Date(Math.min(lastDay, endDate.clone().addDays(-1)));
if (firstBetweenDay <= lastBetweenDay) {
$days.slice(dayOffset + firstBetweenDay.getDate(), dayOffset + lastBetweenDay.getDate() + 1).addClass("betweenDates");
}
}
if (!!startDate && (firstDay <= startDate) && (startDate <= lastDay)) {
$days.eq(dayOffset + startDate.getDate()).addClass(startDateString);
}
if (!!endDate && (firstDay <= endDate) && (endDate <= lastDay)) {
$days.eq(dayOffset + endDate.getDate()).addClass(endDateString);
}
};
self.ready = function ($element) {
$calendar = $element;
$previous = $('<');
$next = $('>');
$month = $('<li class="calMonth"></li>');
$calendar.append($('<ul class="calButtonBar"></ul>')
.append($('<li class="calPrevious"></li>').append($previous))
.append($month)
.append($('<li class="calNext"></li>').append($next))
);
for (var i = 0, th = "", td = ""; i < 7; i++) {
th += '<th></th>';
td += '<td></td>';
}
for (var i = 0, tr = ""; i < 6; i++) {
tr += '<tr>' + td + '</tr>';
}
$calendar.append('<div class="calGrid"><table><tr>' + th + '</tr>' + tr + '</table></div>');
$weekdays = $calendar.find("th");
$days = $calendar.find("td a");
$rows = $calendar.find("tr");
$rows.eq(1).addClass("first");
singleDate = $calendar.hasClass("jsSingleDate");
firstDayOfWeek = $calendar.data("firstdayofweek") || firstDayOfWeek;
$calendar.get(0).calendar = self;
if ($.fn) {
$.fn.slice = $.fn.slice || function (start, end) {
return $([].slice.call(this, start, end));
}
$.fn.calendar = function() {
return this.get(0).calendar;
}
}
extendDate();
today = (new Date()).clearTime();
minDate = today;
startDate = $calendar.data("startdate");
startDate = startDate ? new Date(startDate).clearTime() : null;
endDate = $calendar.data("enddate");
endDate = endDate ? new Date(endDate).clearTime() : null;
currentMonth = (startDate || today).clone();
dateInfo = $calendar.data("localized_date");
if (typeof dateInfo == "string") {
dateInfo = JSON.parse(dateInfo);
}
var $monthGrid = $calendar.find(".calGrid");
var animationQueue = [];
var isAnimating = function(node) {
if ($monthGrid.children().length > 1) {
animationQueue.push(node);
return true;
}
return false;
}
var nextAnimation = function() {
if (animationQueue.length > 0) {
setTimeout(function() {
animationQueue.shift().trigger(tap);
}, 0);
}
}
$previous.bind(tap, function (evt) {
evt.preventDefault();
if (isAnimating($previous)) return;
currentMonth = currentMonth.addMonths(-1);
var $page = $('<table>' + $calendar.find("table").html() + '</table>');
$monthGrid.append($page);
$days.closest("table").addClass("turndown").bind(animEnd, function (evt) {
$(this).removeClass("turndown").unbind(animEnd);
$page.remove();
nextAnimation();
}).trigger(noAnimEnd);
self.showMonth(currentMonth);
});
$next.bind(tap, function (evt) {
evt.preventDefault();
if (isAnimating($next)) return;
currentMonth = currentMonth.addMonths(+1);
var $page = $('<table class="turnup">' + $calendar.find("table").html() + '</table>');
$monthGrid.append($page);
$page.bind(animEnd, function (evt) {
$page.remove();
nextAnimation();
}).trigger(noAnimEnd);
self.showMonth(currentMonth);
});
$calendar.bind("resetDates", function (evt) {
setDate(startDateString, null);
setDate(endDateString, null);
});
$days.bind(tap, dateSelected);
self.showMonth(currentMonth);
}
self.setDates = function(start, end) {
setDate(startDateString, start && end ? new Date(Math.min(start, end)) : start);
!singleDate && setDate(endDateString, start && end ?
(start.getTime() != end.getTime() ? new Date(Math.max(start, end)) : null) : end);
}
self.showMonth = function (date) {
minDate = new Date(Math.max(minDate, today));
if (!!dateInfo) {
$month.text(dateInfo.months.names["long"][date.getMonth()] + " " + date.getFullYear());
for (var i = 0, maxI = $weekdays.length; i < maxI; i++) {
$weekdays.eq(getDay(i)).text(dateInfo.days.names.min[i]);
}
}
var beforeMinDate = minDate > date.clone().moveToLastDayOfMonth();
var includesToday = !beforeMinDate && (minDate >= date.clone().moveToFirstDayOfMonth());
var minDay = minDate.getDate();
$days.addClass("noTransition").removeClass("inactive");
$rows.removeClass("last").removeClass("hidden");
for (var firstDay = getDay(date.clone().moveToFirstDayOfMonth().getDay()) - 1, lastDay = firstDay + date.clone().moveToLastDayOfMonth().getDate(), i = 0, maxI = $days.length; i < maxI; i++) {
var isDay = (i > firstDay) && (i <= lastDay);
var $day = $days.eq(i).text(isDay ? ("" + (i - firstDay)) : "");
if (isDay && (beforeMinDate || (includesToday && (i - firstDay < minDay)))) {
$day.addClass("inactive");
}
if (includesToday && today.getDate() == (i - firstDay)) {
$day.addClass("today");
}
if (i == lastDay) {
$day.closest("tr").addClass("last").next().addClass("hidden").next().addClass("hidden");
}
}
setTimeout(function() {
$days.removeClass("noTransition");
}, 0);
drawSelection();
}
}
})()
The code you posted turns any div with a class of jsCalendar into a jsCalendar.
You're going to want to assign an individual id to any jsCalendar object you want to access the dates of.
You should be able to see what 2 dates the user has selected by calling the data function on the jsCalendar object. For instance, if you had a jsCalendar with an id of jsCalendar1:
var startDate = $("#jsCalendar1").data("startdate");
var endDate = $("#jsCalendar1").data("enddate");
alert("Calendar 1 has a start date of " + startDate + " and an end date of " + endDate + ".");
Make sure you put this code somewhere appropriate, such as in a function that isn't called until after a user has selected a start and end date.
Here's a working jsFiddle.