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/
Related
I am building a AJAX live search page.So far everything is working as intended, but I have noticed that I am doing TONS of AJAX calls.
I know where and why this is happening, but I cannot find a way to stop these AJAX calls from happening.
I will try to give a quick explanation and paste the code below afterwards.
On the left side of the page I have a bunch of filters (e.g. location, radius, interests, engagements, daterange, ...). Each and every one of them has an event listener on them (eg changed). When one of those listeners is triggered, I update my query parameters and request the results via AJAX.
Now the problem occurs when for example someone has selected 10 interests (there are 36 of them), and then he shares the URL, it would look like this:
http://localhost/codeigniter/nl-be/sociale-teambuildings/zoeken?locations=&distance=0&minemployees=0&maxemployees=1000&minprice=0&maxprice=50000&interests=1%3B2%3B3%3B4%3B5%3B6%3B7%3B8%3B9%3B10&sdgs=&startdate=2018-12-03&enddate=2019-12-03&engagements=
Now first off, I will say that I am using iCheck.js for my checkboxes. This means that there's a check on the 'ifChecked' event.
Since the list contains 10 interest entries, the 'ifChecked' event will be fired 10 times, and thus resulting in 10 AJAX request. Now consider this in combination with 5 SDG's, 2 engagaments, 3 locations, ... and I end up with a ton of AJAX requests.
As well while removing all of my interests at the same time (there's a 'remove' link), it will fire the 'ifUnchecked' event 10 times, and thus again perform 10 AJAX requests.
This is my full JS code, i've tried creating a jsfiddle with the HTML and all, but the code is a bit intermingled with CodeIgniter framework and hard to place in there. But the JS code is enough to get the picture across.
//Set vars available to entire scope for filtering
var searchLocation = null;
var searchRadius = 0;
var searchMin = 0;
var searchMax = 1000;
var searchMinPrice = 0;
var searchMaxPrice = 50000;
var searchSelectedInterests = [];
var searchSelectedSdgs = [];
var searchStartDate = moment().format('YYYY-MM-DD');
var searchEndDate = moment().add(1, 'years').format('YYYY-MM-DD');
var searchSelectedEngagements = [];
var getUrl = window.location;
var baseUrl = getUrl .protocol + "//" + getUrl.host + "/" + getUrl.pathname.split('/')[1];
$(document).ready(function(){
'use strict';
// Square Checkbox & Radio
$('.skin-square input').iCheck({
checkboxClass: 'icheckbox_square-blue'
});
$('.searchinterests input').on('ifChecked', function(event) {
var interestid = event.target.value;
searchSelectedInterests.push(interestid);
updateURLParameters();
performSearch();
});
$('.searchinterests input').on('ifUnchecked', function(event) {
var interestid = event.target.value;
var arrayPos = $.inArray(interestid, searchSelectedInterests);
if (arrayPos > -1) {
searchSelectedInterests.splice(arrayPos, 1);
}
performSearch();
});
$('.searchsdgs input').on('ifChecked', function(event) {
var sdgid = event.target.value;
searchSelectedSdgs.push(sdgid);
updateURLParameters();
performSearch();
});
$('.searchsdgs input').on('ifUnchecked', function(event) {
var sdgid = event.target.value;
var arrayPos = $.inArray(sdgid, searchSelectedSdgs);
if (arrayPos > -1) {
searchSelectedSdgs.splice(arrayPos, 1);
}
performSearch();
});
$('.searchengagements input').on('ifChecked', function(event) {
var social_engagement_id = event.target.value;
searchSelectedEngagements.push(social_engagement_id);
updateURLParameters();
performSearch();
});
$('.searchengagements input').on('ifUnchecked', function(event) {
var social_engagement_id = event.target.value;
var arrayPos = $.inArray(social_engagement_id, searchSelectedEngagements);
if (arrayPos > -1) {
searchSelectedEngagements.splice(arrayPos, 1);
}
performSearch();
});
var searchLocationSelect = $('.stb-search-location');
var radiusSlider = document.getElementById('radius-slider');
var minMaxSlider = document.getElementById('min-max-slider');
var priceSlider = document.getElementById('price-slider');
var daterangepicker = $('#searchdaterange');
var curr_lang = $('#curr_lang').val();
switch(curr_lang) {
case 'nl':
moment.locale('nl');
daterangepicker.daterangepicker({
minDate: moment(),
startDate: moment(),
endDate: moment().add(1, 'years'),
ranges: {
'Volgende week': [moment(), moment().add(1, 'weeks')],
'Volgende maand': [moment(), moment().add(1, 'months')],
'Volgende 3 maanden': [moment(), moment().add(3, 'months')],
'Volgende 6 maanden': [moment(), moment().add(6, 'months')],
'Volgend jaar': [moment(), moment().add(1, 'years')]
},
alwaysShowCalendars: true,
locale: {
"customRangeLabel": "Vrije keuze",
"format": "DD-MM-YYYY"
}
});
break;
case 'en':
moment.locale('en');
daterangepicker.daterangepicker({
minDate: moment(),
startDate: moment(),
endDate: moment().add(1, 'years'),
ranges: {
'Next week': [moment(), moment().add(1, 'weeks')],
'Next month': [moment(), moment().add(1, 'months')],
'Next 3 months': [moment(), moment().add(3, 'months')],
'Next 6 months': [moment(), moment().add(6, 'months')],
'Next year': [moment(), moment().add(1, 'years')]
},
alwaysShowCalendars: true,
locale: {
"customRangeLabel": "Free choice",
"format": "DD-MM-YYYY"
}
});
break;
case 'fr':
moment.locale('fr');
daterangepicker.daterangepicker({
minDate: moment(),
startDate: moment(),
endDate: moment().add(1, 'years'),
ranges: {
'Semaine prochaine': [moment(), moment().add(1, 'weeks')],
'Mois prochain': [moment(), moment().add(1, 'months')],
'3 mois prochains': [moment(), moment().add(3, 'months')],
'6 mois prochains': [moment(), moment().add(6, 'months')],
'L\'année prochaine': [moment(), moment().add(1, 'years')]
},
alwaysShowCalendars: true,
locale: {
"customRangeLabel": "Libre choix",
"format": "DD-MM-YYYY"
}
});
break;
}
daterangepicker.on('hide.daterangepicker', function (ev, picker) {
var startdate = picker.startDate.format('YYYY-MM-DD');
var enddate = picker.endDate.format('YYYY-MM-DD');
setStartDate(startdate);
setEndDate(enddate);
updateURLParameters();
performSearch();
});
if (searchLocationSelect.length) {
searchLocationSelect.selectize({
create: false,
sortField: {
field: 'text',
direction: 'asc'
},
dropdownParent: 'body',
plugins: ['remove_button'],
onChange: function(value) {
setLocation(value);
var size = value.length;
if (size == 1) {
enableRadius(radiusSlider);
} else {
disableAndResetRadius(radiusSlider);
}
updateURLParameters();
performSearch();
}
});
}
noUiSlider.create(radiusSlider, {
start: [0],
step: 5,
range: {
'min': 0,
'max': 100
}
});
var radiusNodes = [
document.getElementById('radius-value')
];
// Display the slider value and how far the handle moved
// from the left edge of the slider.
radiusSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
var value = values[handle];
radiusNodes[handle].innerHTML = Math.round(value);
});
radiusSlider.noUiSlider.on('set', function (value) {
setRadius(value);
updateURLParameters();
performSearch();
});
var minmax_slider_options = {
start: [0,1000],
behaviour: 'drag',
connect: true,
tooltips: [wNumb({
decimals: 0
}), wNumb({
decimals: 0
})],
range: {
'min': 0,
'max': 1000
},
step: 5
};
noUiSlider.create(minMaxSlider, minmax_slider_options);
var minMaxNodes = [
document.getElementById('minmax-lower-value'),
document.getElementById('minmax-upper-value')
];
// Display the slider value and how far the handle moved
// from the left edge of the slider.
minMaxSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
var value = values[handle];
minMaxNodes[handle].innerHTML = Math.round(value);
});
minMaxSlider.noUiSlider.on('set', function (values) {
setMin(values[0]);
setMax(values[1]);
updateURLParameters();
performSearch();
});
var price_slider_options = {
start: [0,50000],
behaviour: 'drag',
connect: true,
tooltips: [wNumb({
decimals: 0
}), wNumb({
decimals: 0
})],
range: {
'min': 0,
'max': 50000
},
step: 250
};
noUiSlider.create(priceSlider, price_slider_options);
var priceNodes = [
document.getElementById('price-lower-value'), // 1000
document.getElementById('price-upper-value') // 3500
];
// Display the slider value and how far the handle moved
// from the left edge of the slider.
priceSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
var value = values[handle];
priceNodes[handle].innerHTML = '€'+Math.round(value);
});
priceSlider.noUiSlider.on('set', function (values) {
setMinPrice(values[0]);
setMaxPrice(values[1]);
updateURLParameters();
performSearch();
});
/** Reset methods **/
$('#resetLocations').on('click', function(e) {
e.preventDefault();
var locationInputField = $('.stb-search-location');
var control = locationInputField[0].selectize;
control.clear();
});
$('#resetRadius').on('click', function(e) {
e.preventDefault();
document.getElementById('radius-slider').noUiSlider.set(0);
});
$('#resetMinMax').on('click', function(e) {
e.preventDefault();
document.getElementById('min-max-slider').noUiSlider.set([0,1000]);
});
$('#resetPrice').on('click', function(e) {
e.preventDefault();
document.getElementById('price-slider').noUiSlider.set([0,50000]);
});
$('#resetInterests').on('click', function(e) {
e.preventDefault();
searchSelectedInterests = [];
$("input[name='interests[]']").iCheck('uncheck');
});
$('#resetSdgs').on('click', function(e) {
e.preventDefault();
searchSelectedSdgs = [];
$("input[name='sdgs[]']").iCheck('uncheck');
});
$('#resetDate').on('click', function(e) {
e.preventDefault();
$('#searchdaterange').data('daterangepicker').setStartDate(moment());
$('#searchdaterange').data('daterangepicker').setEndDate(moment().add(1, 'years'));
var startdate = $('#searchdaterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
var enddate = $('#searchdaterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
setStartDate(startdate);
setEndDate(enddate);
performSearch();
});
$('#resetEngagement').on('click', function(e) {
e.preventDefault();
searchSelectedEngagements = [];
$("input[name='engagement[]']").iCheck('uncheck');
});
// Set initial parameters (and pre-fill the filters based on query params)
setupConfig(radiusSlider);
});
function getQueryStringValue(){
var currentURL = new URI();
var queryParams = currentURL.query(true);
if ($.isEmptyObject(queryParams) === false) {
return queryParams;
} else {
return undefined;
}
}
//In here we read the query parameters from the URL and set the filters to the query parameters (+ do initial filtering)
function setupConfig(radiusSlider) {
var queryParams = getQueryStringValue();
if (queryParams !== undefined) {
var locations = queryParams.locations;
if (locations !== undefined) {
var locationsArray = locations.split(";");
fillLocations(locationsArray);
if (locationsArray.length != 1) {
disableAndResetRadius(radiusSlider);
}
} else {
disableAndResetRadius(radiusSlider);
}
var distance = queryParams.distance;
if (distance !== undefined) {
if (locationsArray.length != 1) {
disableAndResetRadius(radiusSlider);
} else {
document.getElementById('radius-slider').noUiSlider.set(distance);
}
}
var minEmployees = queryParams.minemployees;
var maxEmployees = queryParams.maxemployees;
if ((minEmployees !== undefined) && (maxEmployees !== undefined)) {
document.getElementById('min-max-slider').noUiSlider.set([minEmployees,maxEmployees]);
}
var minPrice = queryParams.minprice;
var maxPrice = queryParams.maxprice;
if ((minPrice !== undefined) && (maxPrice !== undefined)) {
document.getElementById('price-slider').noUiSlider.set([minPrice,maxPrice]);
}
var interests = queryParams.interests;
if (interests !== undefined) {
var interestsArray = interests.split(";");
fillInterests(interestsArray);
}
var sdgs = queryParams.sdgs;
if (sdgs !== undefined) {
var sdgsArray = sdgs.split(";");
fillSdgs(sdgsArray);
}
var startdate = queryParams.startdate;
var enddate = queryParams.enddate;
if ((startdate !== undefined) && (enddate !== undefined)) {
$('#searchdaterange').data('daterangepicker').setStartDate(moment(startdate));
$('#searchdaterange').data('daterangepicker').setEndDate(moment(enddate));
var startdate = $('#searchdaterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
var enddate = $('#searchdaterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
setStartDate(startdate);
setEndDate(enddate);
}
var engagements = queryParams.engagements;
if (engagements !== undefined) {
var engagementsArray = engagements.split(";");
fillEngagements(engagementsArray);
}
} else {
disableAndResetRadius(radiusSlider);
performSearch();
}
}
function fillLocations(locations) {
var selectize = $('.stb-search-location');
selectize[0].selectize.setValue(locations);
}
function fillInterests(interests) {
for (var i = 0; i < interests.length; i++) {
var checkboxId = "interest-"+interests[i];
var checkbox = $('#'+checkboxId);
checkbox.iCheck('check');
}
}
function fillSdgs(sdgs) {
for (var i = 0; i < sdgs.length; i++) {
var checkboxId = "sdg-"+sdgs[i];
var checkbox = $('#'+checkboxId);
checkbox.iCheck('check');
}
}
function fillEngagements(engagements) {
for (var i = 0; i < engagements.length; i++) {
var checkboxId = "eng-"+engagements[i];
var checkbox = $('#'+checkboxId);
checkbox.iCheck('check');
}
}
function getCurrLang() {
return $('#curr_lang').val();
}
function getCurrLangSegment() {
return $('#curr_abbr').val();
}
function getLocation() {
return $('#location').val();
}
function setLocation(value) {
searchLocation = value;
}
function setRadius(value) {
searchRadius = value;
}
function disableAndResetRadius(radiusSlider) {
radiusSlider.noUiSlider.set(0);
radiusSlider.setAttribute('disabled', true);
}
function enableRadius(radiusSlider) {
radiusSlider.removeAttribute('disabled');
}
function setMin(value) {
searchMin = value;
}
function setMax(value) {
searchMax = value;
}
function setMinPrice(value) {
searchMinPrice = value;
}
function setMaxPrice(value) {
searchMaxPrice = value;
}
function setStartDate(value) {
searchStartDate = value;
}
function setEndDate(value) {
searchEndDate = value;
}
function performSearch() {
$('#stb-items-placeholder').html('<div id="loading"><span>'+res.StbSearchPlaceholder+'</span></div>');
var searchOptions = {
type: 'POST',
url: baseUrl + '/dashboard/socialteambuildings/search/getFilteredStbs',
dataType: 'json'
};
var filterdata = {
"curr_lang" : getCurrLang(),
"curr_abbr" : getCurrLangSegment(),
"location" : getLocation(),
"interests": searchSelectedInterests,
"sdgs": searchSelectedSdgs
};
var options = $.extend({}, searchOptions, {
data: filterdata
});
// ajax done & fail
$.ajax(options).done(function (data) {
var mustacheJsonData = data.result;
var html = Mustache.render( $('#stbItemGen').html(), mustacheJsonData );
$('#stb-items-placeholder').html( html );
});
}
function updateURLParameters() {
if (searchLocation != null) {
var locationsUrlString = searchLocation.join(";");
}
var distanceUrlString = Math.round(searchRadius[0]);
var minEmployeesUrlString = Math.round(searchMin);
var maxEmployeesUrlString = Math.round(searchMax);
var minPriceUrlString = Math.round(searchMinPrice);
var maxPriceUrlString = Math.round(searchMaxPrice);
var interestUrlString = searchSelectedInterests.join(";");
var sdgUrlString = searchSelectedSdgs.join(";");
var startDateUrlString = searchStartDate;
var endDateUrlString = searchEndDate;
var engagementUrlString = searchSelectedEngagements.join(";");
var params = {locations: locationsUrlString, distance: distanceUrlString, minemployees: minEmployeesUrlString, maxemployees: maxEmployeesUrlString, minprice: minPriceUrlString, maxprice: maxPriceUrlString, interests: interestUrlString, sdgs: sdgUrlString, startdate: startDateUrlString, enddate: endDateUrlString, engagements: engagementUrlString};
var query = $.param(params);
addURLParameter(query);
}
//This function removes all the query parameters and adds the completely newly built query param string again
function addURLParameter(queryString){
var currentUrl = window.location.href;
var urlNoQueryParams = currentUrl.split("?");
var baseUrl = urlNoQueryParams[0];
var result = baseUrl + "?" + queryString;
window.history.replaceState('', '', result);
}
I tried using e.stopPropagation() and e.stopImmediatePropagation() on the remove option for example. This does not stop the events going back to the iCheck library.
Debounce will not work here as the problem is NOT in just one event listener having too many requests in a short amount of time, but with many independent event listeners firing one after the other.
Possible solutions:
Add a button eg SEARCH which will actually perform the search, instead of this being triggered by individual updates. This is a nice and simple solution to the many independent listeners problem.
If you dont want to add a new button do sth like the following. Add a timeinterval with setInterval to perform a search with AJAX. And have a flag whether a search should be performed. Then when either listener on checkbox changes simply set the flag to true. Also if a request is already in progress do NOT make another AJAX request untill the current one finishes.
pseudocode follows:
var do_search = false, timer = null, doing_ajax = false, TROTTLE = 500;
timer = setTimeout(performSearch, TROTTLE);
function performSearch()
{
if ( !do_search || doing_ajax )
{
timer = setTimeout(performSearch, TROTTLE);
return;
}
doing_ajax = true;
do_search = false;
// do the ajax request here
// ...
// NOTE: on ajax complete reset the timer, eg timer = setTimeout(performSearch, TROTTLE);
// and set doing_ajax = false;
}
// then your checkboxes listeners will simply update the do-search flag eg:
$('.searchsdgs input').on('ifChecked', function(event) {
var sdgid = event.target.value;
searchSelectedSdgs.push(sdgid);
updateURLParameters();
//performSearch();
do_search = true;
});
$('.searchsdgs input').on('ifUnchecked', function(event) {
var sdgid = event.target.value;
var arrayPos = $.inArray(sdgid, searchSelectedSdgs);
if (arrayPos > -1) {
searchSelectedSdgs.splice(arrayPos, 1);
}
//performSearch();
do_search = true;
});
$('.searchengagements input').on('ifChecked', function(event) {
var social_engagement_id = event.target.value;
searchSelectedEngagements.push(social_engagement_id);
updateURLParameters();
//performSearch();
do_search = true;
});
$('.searchengagements input').on('ifUnchecked', function(event) {
var social_engagement_id = event.target.value;
var arrayPos = $.inArray(social_engagement_id, searchSelectedEngagements);
if (arrayPos > -1) {
searchSelectedEngagements.splice(arrayPos, 1);
}
//performSearch();
do_search = true;
});
NOTE you can adjust the TROTTLE interval to balance between more immediate interactivity and less AJAX requests. Experiment with different values to get a feeling for it for your app.
NOTE2 You can build on this example and make it like a multi-debounce function for example by clearing the timeout and resetting it in each individual listener (instead of simply setting do_search=true you can set do_search=true and clear the previous interval and reset it again). This will make sure only the last update will be performed.
I got a calendar range on a page, consisting of two inputs, #from-date and #to-date. If I select from date, I want the to date to be shown automatically.
HTML markup:
<div class="calendar-range">
<div class="filter-first date-from">
<input type="text" id="from-date" class="form-control form-control-main calendar-from datepicker">
<i class="fa fa-calendar"></i>
</div>
<div class="filter date-to">
<input type="text" id="to-date" class="form-control form-control-main calendar-to datepicker">
<i class="fa fa-calendar"></i>
</div>
</div>
This is the jQuery code:
body.find(".calendar-range").each(function (index, callback) {
var selectedToElement = $(this).find('.calendar-to');
var selectedToDay = selectedToElement.datepicker('getDate');
var selectedFromElement = $(this).find('.calendar-from');
var selectedFromDay = selectedFromElement.datepicker('getDate');
var numberOfMonths = 2;
if (body.width() < 768) {
numberOfMonths = 1;
}
var settings = {
changeMonth: false,
numberOfMonths: numberOfMonths,
dateFormat: dateFormat,
minDate: new Date(Date.now()),
maxDate: new Date(new Date().setFullYear(new Date().getFullYear() + 1)),
onSelect: function (dateText, object) {
selectedToDay = selectedToElement.datepicker('getDate');
selectedFromDay = selectedFromElement.datepicker('getDate');
selectedToElement.change();
selectedFromElement.change();
if ($(this).hasClass('calendar-from')) {
to.datepicker("option", "minDate", getDate(this.value));
} else if ($(this).hasClass('calendar-to')) {
from.datepicker("option", "maxDate", getDate(this.value));
}
},
beforeShow: function (input, inst) {
selectedToDay = selectedToElement.datepicker('getDate');
selectedFromDay = selectedFromElement.datepicker('getDate');
},
beforeShowDay: function (date) {
var d = date.getTime();
var cssClass = 'selected-date-range';
var defaultClass = '';
if (selectedToDay != null && d == selectedToDay.getTime()) {
cssClass = cssClass + ' selected-date-range-last';
defaultClass = defaultClass + ' selected-date-range-last';
} else if (selectedFromDay != null && d == selectedFromDay.getTime()) {
cssClass = cssClass + ' selected-date-range-first';
defaultClass = defaultClass + ' selected-date-range-first';
}
if (selectedFromDay != null && selectedToDay != null && d <= selectedToDay.getTime() && d >= selectedFromDay.getTime()) {
return [true, cssClass, ''];
}
return [true, defaultClass, ''];
},
onClose: function (input, object) {
if (object.id === "from-date") {
to.datepicker("show");
}
}
};
var from = selectedFromElement.datepicker(settings);
var to = selectedToElement.datepicker(settings);
});
I tried solving it with onClose, but this seems to iterate twice, and close the opened #to-date too. Is it possible to implement it without separating the two datepickers? (also something really weird happens with hiding/showing the datepickers)
Help appreciated, thx.
There are a number of improvements you can make. Here is a working example:
https://jsfiddle.net/Twisty/mcqra47o/
JavaScript
$(function() {
var body = $("body");
var dateFormat = "mm/dd/yy";
$(".calendar-range").each(function(index, callback) {
var selectedToElement = $(this).find('.calendar-to');
var selectedToDay = selectedToElement.val().length ? selectedToElement.datepicker('getDate') : new Date;
var selectedFromElement = $(this).find('.calendar-from');
var selectedFromDay = selectedFromElement.val().length ? selectedFromElement.datepicker('getDate') : new Date;
var numberOfMonths = 2;
if (body.width() < 768) {
numberOfMonths = 1;
}
var settings = {
changeMonth: false,
numberOfMonths: numberOfMonths,
dateFormat: dateFormat,
minDate: 0,
maxDate: "+1y",
onSelect: function(dateText, object) {
selectedToDay = selectedToElement.datepicker('getDate');
selectedFromDay = selectedFromElement.datepicker('getDate');
/*
selectedToElement.change();
selectedFromElement.change();
*/
if ($(this).hasClass('calendar-from')) {
selectedToElement.datepicker("option", "minDate", dateText);
} else if ($(this).hasClass('calendar-to')) {
selectedFromElement.datepicker("option", "maxDate", dateText);
}
},
beforeShow: function(input, inst) {
selectedToDay = selectedToElement.datepicker('getDate');
selectedFromDay = selectedFromElement.datepicker('getDate');
},
beforeShowDay: function(date) {
var d = date.getTime();
var cssClass = 'selected-date-range';
var defaultClass = '';
if (selectedToDay != null && d == selectedToDay.getTime()) {
cssClass = cssClass + ' selected-date-range-last';
defaultClass = defaultClass + ' selected-date-range-last';
} else if (selectedFromDay != null && d == selectedFromDay.getTime()) {
cssClass = cssClass + ' selected-date-range-first';
defaultClass = defaultClass + ' selected-date-range-first';
}
if (selectedFromDay != null && selectedToDay != null && d <= selectedToDay.getTime() && d >= selectedFromDay.getTime()) {
return [true, cssClass, ''];
}
return [true, defaultClass, ''];
},
/*
onClose: function(input, object) {
if (object.id === "from-date") {
to.datepicker("show");
}
}
*/
};
var from = selectedFromElement.datepicker(settings);
var to = selectedToElement.datepicker(settings);
});
});
First, we should not call .datepicker() to getDate before it's been initialized. So to set the following variables early, we can do this:
var selectedToDay = selectedToElement.val().length ? selectedToElement.datepicker('getDate') : new Date;
var selectedFromDay = selectedFromElement.val().length ? selectedFromElement.datepicker('getDate') : new Date;
For minDate and maxDate, we can check the API and see:
Multiple types supported:
Date: A date object containing the minimum date.
Number: A number of days from today. For example 2 represents two days from today and -1 represents yesterday.
String: A string in the format defined by the dateFormat option, or a relative date. Relative dates must contain value and period pairs; valid periods are "y" for years, "m" for months, "w" for weeks, and "d" for days. For example, "+1m +7d" represents one month and seven days from today.
I suggest using relative date formats if possible. For today, I used 0, and for 1 year, I used "+1y".
When a selection is made change is fired anyway, so I commented this out. If it is needed for something else, I would suggest looking at .tragger("change").
The onSelect option passes dateText in, so we can use that to set the new minDate and maxDate as needed.
Hopefully that addresses everything and works as you'd desired.
I'm using Datepicker to toggle between date selection for oneway and round bus trips.
Function datecalendar is for round and initiated from round div, while datecalendar1 is for oneway and is initiated from "from" div.
Both functions execute properly on first instance.
However if I first select any function say datecalendar1 for oneway it works fine but then after selection if i click on return div (to which onclick datecalendar for range selection is attached) then still Datepicker is initiated with single date selection and not range as in datecalendar function appended to onclick.
<script type="text/javascript">
function datecalendar () {
$.datepicker._clearDate('#datesearchdiv');
$.datepicker._defaults.onAfterUpdate = null;
var datepicker__updateDatepicker = $.datepicker._updateDatepicker;
$.datepicker._updateDatepicker = function(inst) {
datepicker__updateDatepicker.call(this, inst);
var onAfterUpdate = this._get(inst, 'onAfterUpdate');
if (onAfterUpdate) onAfterUpdate.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ''), inst]);
}
$(function() {
var cur = -1,
prv = -1;
$('#datesearchdiv')
.datepicker({
numberOfMonths: [12, 1],
changeMonth: true,
changeYear: true,
minDate: 0,
beforeShowDay: function(date) {
return [true, ((date.getTime() >= Math.min(prv, cur) && date.getTime() <= Math.max(prv, cur)) ? 'date-range-selected' : '')];
},
onSelect: function(dateText, inst) {
var d1, d2;
prv = cur;
cur = (new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)).getTime();
if (prv == -1 || prv == cur) {
prv = cur;
$('#departdate').val(dateText);
} else {
d1 = $.datepicker.formatDate('dd/mm/yy', new Date(Math.min(prv, cur)), {});
d2 = $.datepicker.formatDate('dd/mm/yy', new Date(Math.max(prv, cur)), {});
var d11 = $.datepicker.formatDate('mm/dd/yy', new Date(Math.min(prv, cur)), {});
var d22 = $.datepicker.formatDate('mm/dd/yy', new Date(Math.max(prv, cur)), {});
$('#departdate').val(d1);
$('#returndate').val(d2);
spandateupdate(d11, d22);
}
},
onChangeMonthYear: function(year, month, inst) {
//prv = cur = -1;
},
})
.position({
my: 'left top',
at: 'left bottom',
of: $('#departdate')
})
.hide();
$('#departdate').on('focus', function(e) {
var v = this.value,
d;
try {
if (v.indexOf(' - ') > -1) {
d = v.split(' - ');
prv = $.datepicker.parseDate('mm/dd/yy', d[0]).getTime();
cur = $.datepicker.parseDate('mm/dd/yy', d[1]).getTime();
} else if (v.length > 0) {
prv = cur = $.datepicker.parseDate('mm/dd/yy', v).getTime();
}
} catch (e) {
cur = prv = -1;
}
if (cur > -1) $('#datesearchdiv').datepicker('setDate', new Date(cur));
$('#datesearchdiv').datepicker('refresh').show();
showdatespan();
});
});
document.getElementById("departdate").focus();
document.getElementById("departdate").select();
}
</script>
<script type="text/javascript">
function datecalendar1 () {
$.datepicker._defaults.onAfterUpdate = null;
var datepicker__updateDatepicker = $.datepicker._updateDatepicker;
$.datepicker._updateDatepicker = function(inst) {
datepicker__updateDatepicker.call(this, inst);
var onAfterUpdate = this._get(inst, 'onAfterUpdate');
if (onAfterUpdate) onAfterUpdate.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ''), inst]);
}
$(function() {
var cur = -1,
prv = -1;
$('#datesearchdiv')
.datepicker({
numberOfMonths: [12, 1],
changeMonth: true,
changeYear: true,
minDate: 0,
beforeShowDay: function(date) {
return [true, ((date.getTime() === Math.min(cur)) ? 'date-range-selected' : '')];
},
onSelect: function(dateText, inst) {
var d1;
prv = cur;
cur = (new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)).getTime();
if (prv == -1 || prv == cur) {
prv = cur;
$('#departdate').val(dateText);
} else {
d1 = $.datepicker.formatDate('dd/mm/yy', new Date(Math.min( cur)), {});
var d11 = $.datepicker.formatDate('mm/dd/yy', new Date(Math.min( cur)), {});
$('#departdate').val(d1);
spandateupdate1(d11);
}
},
onChangeMonthYear: function(year, month, inst) {
//prv = cur = -1;
},
})
.position({
my: 'left top',
at: 'left bottom',
of: $('#departdate')
})
.hide();
$('#departdate').on('focus', function(e) {
var v = this.value,
d;
try {
if (v.indexOf(' - ') > -1) {
d = v.split(' - ');
prv = $.datepicker.parseDate('mm/dd/yy', d[0]).getTime();
cur = $.datepicker.parseDate('mm/dd/yy', d[1]).getTime();
} else if (v.length > 0) {
prv = cur = $.datepicker.parseDate('mm/dd/yy', v).getTime();
}
} catch (e) {
cur = prv = -1;
}
if (cur > -1) $('#datesearchdiv').datepicker('setDate', new Date(cur));
$('#datesearchdiv').datepicker('refresh').show();
showdatespan();
});
});
document.getElementById("departdate").focus();
document.getElementById("departdate").select();
}
</script>
I'm using a jquery plugin called quicksearch within Sharepoint 2010 and it works perfectly. Unfortunately were being forced to migrate onto sharepoint 2013 and it's stopped working. An error is shown saying that the function is undefined. I believe I've narrowed this down to the quicksearch function itself.
Here is the preliminary code:
_spBodyOnLoadFunctionNames.push("Load");
$('[name=search]').on('keyup', function(){
Load();
});
function Load() {
var searchArea = "#cbqwpctl00_ctl22_g_ca6bb172_1ab4_430d_ae38_a32cfa03b56b ul li";
var qs = $('input#id_search_list').val();
qs.quicksearch(searchArea);
$('.filter input').on('change', function(){
checkAndHide()
//$(searchArea).unhighlight();
});
function checkAndHide(){
var inputs = $('.filter input');
var i =0;
for (var i = 0; i < inputs.length; i++){
if (!inputs[i].checked){
$('.' + inputs[i].name).addClass('filter-hide');
} else {
$('.' + inputs[i].name).removeClass('filter-hide');
};
};
};
}
Here is an example of the quicksearch library I'm using:
(function($, window, document, undefined) {
$.fn.quicksearch = function (target, opt) {
var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
delay: 300,
selector: null,
stripeRows: null,
loader: null,
noResults: 'div#noresults',
bind: 'keyup keydown',
onBefore: function () {
var ar = $('input#id_search_list').val()
if (ar.length > 2) {
var i=0;
var ar2 = $('input#id_search_list').val().split(" ");
for (i = 0; i < ar2.length; i++) {
$(searchArea + ':visible');
}
return true;
}
return false;
checkAndHide()
},
onAfter: function () {
return;
},
show: function () {
this.style.display = "block";
},
hide: function () {
this.style.display = "none";
},
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
testQuery: function (query, txt, _row) {
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
}, opt);
this.go = function () {
var i = 0,
noresults = true,
query = options.prepareQuery(val),
val_empty = (val.replace(' ', '').length === 0);
for (var i = 0, len = rowcache.length; i < len; i++) {
if (val_empty) {
options.hide.apply(rowcache[i]);
noresults = false;
} else if (options.testQuery(query, cache[i], rowcache[i])){
options.show.apply(rowcache[i]);
noresults = false;
} else {
options.hide.apply(rowcache[i]);
}
}
if (noresults) {
this.results(false);
} else {
this.results(true);
this.stripe();
}
this.loader(false);
options.onAfter();
return this;
};
this.stripe = function () {
if (typeof options.stripeRows === "object" && options.stripeRows !== null)
{
var joined = options.stripeRows.join(' ');
var stripeRows_length = options.stripeRows.length;
jq_results.not(':hidden').each(function (i) {
$(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
});
}
return this;
};
this.strip_html = function (input) {
var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
output = $.trim(output.toLowerCase());
return output;
};
this.results = function (bool) {
if (typeof options.noResults === "string" && options.noResults !== "") {
if (bool) {
$(options.noResults).hide();
} else {
$(options.noResults).show();
}
}
return this;
};
this.loader = function (bool) {
if (typeof options.loader === "string" && options.loader !== "") {
(bool) ? $(options.loader).show() : $(options.loader).hide();
}
return this;
};
this.cache = function () {
jq_results = $(target);
if (typeof options.noResults === "string" && options.noResults !== "") {
jq_results = jq_results.not(options.noResults);
}
var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
cache = t.map(function () {
return e.strip_html(this.innerHTML);
});
rowcache = jq_results.map(function () {
return this;
});
return this.go();
};
this.trigger = function () {
this.loader(true);
if (options.onBefore()) {
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
e.go();
}, options.delay);
}
return this;
};
this.cache();
this.results(true);
this.stripe();
this.loader(false);
return this.each(function () {
$(this).bind(options.bind, function () {
val = $(this).val();
e.trigger();
});
});
};
}(jQuery, this, document));
`
This is where the error comes up:
var qs = $('input#id_search_list').val();
qs.quicksearch(searchArea);
Any help would be appreciated
Turns out was a small issue in the code and major css as sharepoint plays differently in 2013
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.