From a27870638ea50bd3aaf011c78b5a505cb02dd206 Mon Sep 17 00:00:00 2001 From: rajaron Date: Thu, 17 Dec 2015 18:00:46 +0530 Subject: [PATCH] Create jquery-ui.multidatespicker Few methods are added to increase the functioanlity 1. setDisabled 2. setEnabled 3. editMonthYearInCalendar 4. disableEditMonthYearInCalendar 5. removeAllDates --- jquery-ui.multidatespicker | 520 +++++++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 jquery-ui.multidatespicker diff --git a/jquery-ui.multidatespicker b/jquery-ui.multidatespicker new file mode 100644 index 0000000..9d1cfe2 --- /dev/null +++ b/jquery-ui.multidatespicker @@ -0,0 +1,520 @@ +/* + * MultiDatesPicker v1.6.5 + * http://multidatespickr.sourceforge.net/ + * + * Copyright 2014, Luca Lauretta + * Dual licensed under the MIT or GPL version 2 licenses. + */ +(function( $ ){ + $.extend($.ui, { multiDatesPicker: { version: "1.6.4" } }); + + $.fn.multiDatesPicker = function(method) { + var mdp_arguments = arguments; + var ret = this; + var today_date = new Date(); + var day_zero = new Date(0); + var mdp_events = {}; + + function removeDate(date, type) { + if(!type) type = 'picked'; + date = dateConvert.call(this, date); + for(var i = 0; i < this.multiDatesPicker.dates[type].length; i++) + if(!methods.compareDates(this.multiDatesPicker.dates[type][i], date)) + return this.multiDatesPicker.dates[type].splice(i, 1).pop(); + } + function removeIndex(index, type) { + if(!type) type = 'picked'; + return this.multiDatesPicker.dates[type].splice(index, 1).pop(); + } + function addDate(date, type, no_sort) { + if(!type) type = 'picked'; + date = dateConvert.call(this, date); + + // @todo: use jQuery UI datepicker method instead + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + + if (methods.gotDate.call(this, date, type) === false) { + this.multiDatesPicker.dates[type].push(date); + if(!no_sort) this.multiDatesPicker.dates[type].sort(methods.compareDates); + } + } + function sortDates(type) { + if(!type) type = 'picked'; + this.multiDatesPicker.dates[type].sort(methods.compareDates); + } + function dateConvert(date, desired_type, date_format) { + if(!desired_type) desired_type = 'object';/* + if(!date_format && (typeof date == 'string')) { + date_format = $(this).datepicker('option', 'dateFormat'); + if(!date_format) date_format = $.datepicker._defaults.dateFormat; + } + */ + return methods.dateConvert.call(this, date, desired_type, date_format); + } + + var methods = { + init : function( options ) { + var $this = $(this); + this.multiDatesPicker.changed = false; + + var mdp_events = { + beforeShow: function(input, inst) { + this.multiDatesPicker.changed = false; + if(this.multiDatesPicker.originalBeforeShow) + this.multiDatesPicker.originalBeforeShow.call(this, input, inst); + }, + onSelect : function(dateText, inst) { + var $this = $(this); + this.multiDatesPicker.changed = true; + + if (dateText) { + $this.multiDatesPicker('toggleDate', dateText); + this.multiDatesPicker.changed = true; + // @todo: this will be optimized when I'll move methods to the singleton. + } + + if (this.multiDatesPicker.mode == 'normal' && this.multiDatesPicker.pickableRange) { + if(this.multiDatesPicker.dates.picked.length > 0) { + var min_date = this.multiDatesPicker.dates.picked[0], + max_date = new Date(min_date.getTime()); + + methods.sumDays(max_date, this.multiDatesPicker.pickableRange-1); + + // counts the number of disabled dates in the range + if(this.multiDatesPicker.adjustRangeToDisabled) { + var c_disabled, + disabled = this.multiDatesPicker.dates.disabled.slice(0); + do { + c_disabled = 0; + for(var i = 0; i < disabled.length; i++) { + if(disabled[i].getTime() <= max_date.getTime()) { + if((min_date.getTime() <= disabled[i].getTime()) && (disabled[i].getTime() <= max_date.getTime()) ) { + c_disabled++; + } + disabled.splice(i, 1); + i--; + } + } + max_date.setDate(max_date.getDate() + c_disabled); + } while(c_disabled != 0); + } + + if(this.multiDatesPicker.maxDate && (max_date > this.multiDatesPicker.maxDate)) + max_date = this.multiDatesPicker.maxDate; + + $this + .datepicker("option", "minDate", min_date) + .datepicker("option", "maxDate", max_date); + } else { + $this + .datepicker("option", "minDate", this.multiDatesPicker.minDate) + .datepicker("option", "maxDate", this.multiDatesPicker.maxDate); + } + } + + if(this.multiDatesPicker.originalOnSelect && dateText) + this.multiDatesPicker.originalOnSelect.call(this, dateText, inst); + + }, + beforeShowDay : function(date) { + var $this = $(this), + gotThisDate = $this.multiDatesPicker('gotDate', date) !== false, + isDisabledCalendar = $this.datepicker('option', 'disabled'), + isDisabledDate = $this.multiDatesPicker('gotDate', date, 'disabled') !== false, + areAllSelected = this.multiDatesPicker.maxPicks <= this.multiDatesPicker.dates.picked.length; + + var bsdReturn = [true, '', null]; + if(this.multiDatesPicker.originalBeforeShowDay) + bsdReturn = this.multiDatesPicker.originalBeforeShowDay.call(this, date); + + bsdReturn[1] = gotThisDate ? 'ui-state-highlight '+bsdReturn[1] : bsdReturn[1]; + bsdReturn[0] = bsdReturn[0] && !(isDisabledCalendar || isDisabledDate || (areAllSelected && !bsdReturn[1])); + return bsdReturn; + } + }; + + // value have to be extracted before datepicker is initiated + if($this.val()) var inputDates = $this.val() + + if(options) { + // value have to be extracted before datepicker is initiated + //if(options.altField) var inputDates = $(options.altField).val(); + if(options.separator) this.multiDatesPicker.separator = options.separator; + if(!this.multiDatesPicker.separator) this.multiDatesPicker.separator = ', '; + + this.multiDatesPicker.originalBeforeShow = options.beforeShow; + this.multiDatesPicker.originalOnSelect = options.onSelect; + this.multiDatesPicker.originalBeforeShowDay = options.beforeShowDay; + this.multiDatesPicker.originalOnClose = options.onClose; + + // datepicker init + $this.datepicker(options); + + this.multiDatesPicker.minDate = $.datepicker._determineDate(this, options.minDate, null); + this.multiDatesPicker.maxDate = $.datepicker._determineDate(this, options.maxDate, null); + if(options.addDates) methods.addDates.call(this, options.addDates); + + if(options.addDisabledDates) + methods.addDates.call(this, options.addDisabledDates, 'disabled'); + + methods.setMode.call(this, options); + } else { + $this.datepicker(); + } + $this.datepicker('option', mdp_events); + + // adds any dates found in the input or alt field + if(inputDates) $this.multiDatesPicker('value', inputDates); + + // generates the new string of added dates + var inputs_values = $this.multiDatesPicker('value'); + + // fills the input field back with all the dates in the calendar + $this.val(inputs_values); + + // Fixes the altField filled with defaultDate by default + var altFieldOption = $this.datepicker('option', 'altField'); + if (altFieldOption) $(altFieldOption).val(inputs_values); + + // Updates the calendar view + $this.datepicker('refresh'); + }, + compareDates : function(date1, date2) { + date1 = dateConvert.call(this, date1); + date2 = dateConvert.call(this, date2); + // return > 0 means date1 is later than date2 + // return == 0 means date1 is the same day as date2 + // return < 0 means date1 is earlier than date2 + var diff = date1.getFullYear() - date2.getFullYear(); + if(!diff) { + diff = date1.getMonth() - date2.getMonth(); + if(!diff) + diff = date1.getDate() - date2.getDate(); + } + return diff; + }, + sumDays : function( date, n_days ) { + var origDateType = typeof date; + obj_date = dateConvert.call(this, date); + obj_date.setDate(obj_date.getDate() + n_days); + return dateConvert.call(this, obj_date, origDateType); + }, + dateConvert : function( date, desired_format, dateFormat ) { + var from_format = typeof date; + var $this = $(this); + + if(from_format == desired_format) { + if(from_format == 'object') { + try { + date.getTime(); + } catch (e) { + $.error('Received date is in a non supported format!'); + return false; + } + } + return date; + } + + if(typeof date == 'undefined') date = new Date(0); + + if(desired_format != 'string' && desired_format != 'object' && desired_format != 'number') + $.error('Date format "'+ desired_format +'" not supported!'); + + if(!dateFormat) { + // thanks to bibendus83 -> http://sourceforge.net/tracker/index.php?func=detail&aid=3213174&group_id=358205&atid=1495382 + var dp_dateFormat = $this.datepicker('option', 'dateFormat'); + if (dp_dateFormat) { + dateFormat = dp_dateFormat; + } else { + dateFormat = $.datepicker._defaults.dateFormat; + } + } + + // converts to object as a neutral format + switch(from_format) { + case 'object': break; + case 'string': date = $.datepicker.parseDate(dateFormat, date); break; + case 'number': date = new Date(date); break; + default: $.error('Conversion from "'+ desired_format +'" format not allowed on jQuery.multiDatesPicker'); + } + // then converts to the desired format + switch(desired_format) { + case 'object': return date; + case 'string': return $.datepicker.formatDate(dateFormat, date); + case 'number': return date.getTime(); + default: $.error('Conversion to "'+ desired_format +'" format not allowed on jQuery.multiDatesPicker'); + } + return false; + }, + gotDate : function( date, type ) { + if(!type) type = 'picked'; + for(var i = 0; i < this.multiDatesPicker.dates[type].length; i++) { + if(methods.compareDates.call(this, this.multiDatesPicker.dates[type][i], date) === 0) { + return i; + } + } + return false; + }, + value : function( value ) { + if(value && typeof value == 'string') { + methods.addDates.call(this, value.split(this.multiDatesPicker.separator)); + } else { + var dates = methods.getDates.call(this, 'string'); + return dates.length + ? dates.join(this.multiDatesPicker.separator) + : ""; + } + }, + getDates : function( format, type ) { + if(!format) format = 'string'; + if(!type) type = 'picked'; + switch (format) { + case 'object': + return this.multiDatesPicker.dates[type]; + case 'string': + case 'number': + var o_dates = new Array(); + for(var i in this.multiDatesPicker.dates[type]) + o_dates.push( + dateConvert.call( + this, + this.multiDatesPicker.dates[type][i], + format + ) + ); + return o_dates; + + default: $.error('Format "'+format+'" not supported!'); + } + }, + addDates : function( dates, type ) { + if(dates.length > 0) { + if(!type) type = 'picked'; + switch(typeof dates) { + case 'object': + case 'array': + if(dates.length) { + for(var i = 0; i < dates.length; i++) + addDate.call(this, dates[i], type, true); + sortDates.call(this, type); + break; + } // else does the same as 'string' + case 'string': + case 'number': + addDate.call(this, dates, type); + break; + default: + $.error('Date format "'+ typeof dates +'" not allowed on jQuery.multiDatesPicker'); + } + //$(this).datepicker('refresh'); + } else { + $.error('Empty array of dates received.'); + } + }, + removeDates : function( dates, type ) { + if(!type) type = 'picked'; + var removed = []; + if (Object.prototype.toString.call(dates) === '[object Array]') { + for(var i in dates.sort(function(a,b){return b-a})) { + removed.push(removeDate.call(this, dates[i], type)); + } + } else { + removed.push(removeDate.call(this, dates, type)); + } + return removed; + }, + removeIndexes : function( indexes, type ) { + if(!type) type = 'picked'; + var removed = []; + if (Object.prototype.toString.call(indexes) === '[object Array]') { + for(var i in indexes.sort(function(a,b){return b-a})) { + removed.push(removeIndex.call(this, indexes[i], type)); + } + } else { + removed.push(removeIndex.call(this, indexes, type)); + } + return removed; + }, + isDisabled : function(){ + return $(this).datepicker("isDisabled"); + }, + setDisabled: function () { + $(this).datepicker("option","disabled",true); + }, + setEnabled: function () { + $(this).datepicker("option", "disabled", false); + }, + editMonthYearInCalendar: function () { + $(this).datepicker("option", "changeMonth", true); + $(this).datepicker("option", "changeYear", true); + }, + disableEditMonthYearInCalendar: function () { + $(this).datepicker("option", "changeMonth", false); + $(this).datepicker("option", "changeYear", false); + }, + resetDates : function ( type ) { + if(!type) type = 'picked'; + this.multiDatesPicker.dates[type] = []; + }, + removeAllDates: function (type) { + if (!type) type = 'picked'; + this.multiDatesPicker.dates[type] = []; + $(this).val(""); + }, + toggleDate : function( date, type ) { + if(!type) type = 'picked'; + + switch(this.multiDatesPicker.mode) { + case 'daysRange': + this.multiDatesPicker.dates[type] = []; // deletes all picked/disabled dates + var end = this.multiDatesPicker.autoselectRange[1]; + var begin = this.multiDatesPicker.autoselectRange[0]; + if(end < begin) { // switch + end = this.multiDatesPicker.autoselectRange[0]; + begin = this.multiDatesPicker.autoselectRange[1]; + } + for(var i = begin; i < end; i++) + methods.addDates.call(this, methods.sumDays.call(this,date, i), type); + break; + default: + if(methods.gotDate.call(this, date) === false) // adds dates + methods.addDates.call(this, date, type); + else // removes dates + methods.removeDates.call(this, date, type); + break; + } + }, + setMode : function( options ) { + var $this = $(this); + if(options.mode) this.multiDatesPicker.mode = options.mode; + + switch(this.multiDatesPicker.mode) { + case 'normal': + for(option in options) + switch(option) { + case 'maxPicks': + case 'minPicks': + case 'pickableRange': + case 'adjustRangeToDisabled': + this.multiDatesPicker[option] = options[option]; + break; + //default: $.error('Option ' + option + ' ignored for mode "'.options.mode.'".'); + } + break; + case 'daysRange': + case 'weeksRange': + var mandatory = 1; + for(option in options) + switch(option) { + case 'autoselectRange': + mandatory--; + case 'pickableRange': + case 'adjustRangeToDisabled': + this.multiDatesPicker[option] = options[option]; + break; + //default: $.error('Option ' + option + ' does not exist for setMode on jQuery.multiDatesPicker'); + } + if(mandatory > 0) $.error('Some mandatory options not specified!'); + break; + } + + /* + if(options.pickableRange) { + $this.datepicker("option", "maxDate", options.pickableRange); + $this.datepicker("option", "minDate", this.multiDatesPicker.minDate); + } + */ + + if(mdp_events.onSelect) + mdp_events.onSelect(); + }, + destroy: function(){ + this.multiDatesPicker = null; + $(this).datepicker('destroy'); + } + }; + + this.each(function() { + var $this = $(this); + if (!this.multiDatesPicker) { + this.multiDatesPicker = { + dates: { + picked: [], + disabled: [] + }, + mode: 'normal', + adjustRangeToDisabled: true + }; + } + + if(methods[method]) { + var exec_result = methods[method].apply(this, Array.prototype.slice.call(mdp_arguments, 1)); + switch(method) { + case 'removeDates': + case 'removeIndexes': + case 'resetDates': + case 'toggleDate': + case 'addDates': + var altField = $this.datepicker('option', 'altField'); + // @todo: should use altFormat for altField + var dates_string = methods.value.call(this); + if (altField !== undefined && altField != "") { + $(altField).val(dates_string); + } + $this.val(dates_string); + + $.datepicker._refreshDatepicker(this); + } + switch(method) { + case 'removeDates': + case 'getDates': + case 'gotDate': + case 'sumDays': + case 'compareDates': + case 'dateConvert': + case 'value': + ret = exec_result; + } + return exec_result; + } else if( typeof method === 'object' || ! method ) { + return methods.init.apply(this, mdp_arguments); + } else { + $.error('Method ' + method + ' does not exist on jQuery.multiDatesPicker'); + } + return false; + }); + + return ret; + }; + + var PROP_NAME = 'multiDatesPicker'; + var dpuuid = new Date().getTime(); + var instActive; + + $.multiDatesPicker = {version: false}; + //$.multiDatesPicker = new MultiDatesPicker(); // singleton instance + $.multiDatesPicker.initialized = false; + $.multiDatesPicker.uuid = new Date().getTime(); + $.multiDatesPicker.version = $.ui.multiDatesPicker.version; + + // allows MDP not to hide everytime a date is picked + $.multiDatesPicker._hideDatepicker = $.datepicker._hideDatepicker; + $.datepicker._hideDatepicker = function(){ + var target = this._curInst.input[0]; + var mdp = target.multiDatesPicker; + if(!mdp || (this._curInst.inline === false && !mdp.changed)) { + return $.multiDatesPicker._hideDatepicker.apply(this, arguments); + } else { + mdp.changed = false; + $.datepicker._refreshDatepicker(target); + return; + } + }; + + // Workaround for #4055 + // Add another global to avoid noConflict issues with inline event handlers + window['DP_jQuery_' + dpuuid] = $; +})( jQuery );