Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comportement calendrier en JQuery

mois précédent - mois suivant

Sujet résolu
    31 octobre 2010 à 11:45:31

    Bonjour,

    j'ai un autre problème avec mon calendrier en JQuery...

    La flèche pour aller au mois précédent ne fonctionne pas (ou rarement), et la flèche pour aller au mois suivant rajoute 2 mois au lieu d'un (sauf des fois où ça n'en rajoute qu'un, de décembre à janvier, et de juillet à août)...

    Je ne comprends pas pourquoi, sachant que j'ai déjà vu ce calendrier très bien fonctionner. Il n'est pas de moi, je l'ai pris ici : http://flowplayer.org/tools/demos/dateinput/static.html

    J'ai apporté quelques modifications au fichier JQuery de base pour pouvoir faire ce que je veux. (A priori, aucune de ces modifs ne devraient affecter le changement de mois).

    Vous pouvez voir le bug sur cette page;

    Sinon, voici le code complet (700 lignes)


    /**
     * @license                                     
     * jQuery Tools 1.2.5 Dateinput - <input type="date" /> for humans
     * 
     * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
     * 
     * http://flowplayer.org/tools/form/dateinput/
     *
     * Since: Mar 2010
     * Date:    Wed Sep 22 06:02:10 2010 +0000 
     */
    (function($) {	
    		
    	/* TODO: 
    		 preserve today highlighted
    	*/
    	
    	$.tools = $.tools || {version: '1.2.5'};
    	
    	var instances = [], 
    		 tool, 
    		 
    		 // h=72, j=74, k=75, l=76, down=40, left=37, up=38, right=39
    		 KEYS = [75, 76, 38, 39, 74, 72, 40, 37],
    		 LABELS = {};
    	
    	tool = $.tools.dateinput = {
    		
    		conf: { 
    			format: 'mm/dd/yy',
    			selectors: false,
    			yearRange: [-5, 5],
    			lang: 'en',
    			offset: [0, 0],
    			speed: 0,
    			firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
    			min: undefined,
    			max: undefined,
    			trigger: false,
    			container: 0,
    			
    			css: {
    				
    				prefix: 'cal',
    				input: 'date',
    				
    				// ids
    				root: 0,
    				head: 0,
    				title: 0, 
    				prev: 0,
    				next: 0,
    				month: 0,
    				year: 0, 
    				days: 0,
    				
    				body: 0,
    				weeks: 0,
    				today: 0,		
    				current: 0,
    				
    				// classnames
    				week: 0, 
    				off: 0,
    				sunday: 0,
    				focus: 0,
    				disabled: 0,
    				trigger: 0
    			}  
    		},
    		
    		localize: function(language, labels) {
    			$.each(labels, function(key, val) {
    				labels[key] = val.split(",");		
    			});
    			LABELS[language] = labels;	
    		}
    		
    	};
    	
    	tool.localize("en", {
    		months: 		 'January,February,March,April,May,June,July,August,September,October,November,December', 
    		shortMonths: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec',  
    		days: 		 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday', 
    		shortDays: 	 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'	  
    	});
    
    	
    //{{{ private functions
    		
    
    	// @return amount of days in certain month
    	function dayAm(year, month) {
    		return 32 - new Date(year, month, 32).getDate();		
    	}
     
    	function zeropad(val, len) {
    		val = '' + val;
    		len = len || 2;
    		while (val.length < len) { val = "0" + val; }
    		return val;
    	}  
    	
    	// thanks: http://stevenlevithan.com/assets/misc/date.format.js 
    	var Re = /d{1,4}|m{1,4}|yy(?:yy)?|"[^"]*"|'[^']*'/g, tmpTag = $("<a/>");
    	
    	function format(date, fmt, lang) {
    		
    	  var d = date.getDate(),
    			D = date.getDay(),
    			m = date.getMonth(),
    			y = date.getFullYear(),
    
    			flags = {
    				d:    d,
    				dd:   zeropad(d),
    				ddd:  LABELS[lang].shortDays[D],
    				dddd: LABELS[lang].days[D],
    				m:    m + 1,
    				mm:   zeropad(m + 1),
    				mmm:  LABELS[lang].shortMonths[m],
    				mmmm: LABELS[lang].months[m],
    				yy:   String(y).slice(2),
    				yyyy: y
    			};
    
    		var ret = fmt.replace(Re, function ($0) {
    			return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
    		});
    		
    		// a small trick to handle special characters
    		return tmpTag.html(ret).html();
    		
    	}
    	
    	function integer(val) {
    		return parseInt(val, 10);	
    	} 
    
    	function isSameDay(d1, d2)  {
    		return d1.getFullYear() === d2.getFullYear() && 
    			d1.getMonth() == d2.getMonth() &&
    			d1.getDate() == d2.getDate(); 
    	}
    
    	function parseDate(val) {
    		
    		if (!val) { return; }
    		if (val.constructor == Date) { return val; } 
    		
    		if (typeof val == 'string') {
    			
    			// rfc3339?
    			var els = val.split("-");		
    			if (els.length == 3) {
    				return new Date(integer(els[0]), integer(els[1]) -1, integer(els[2]));
    			}	
    			
    			// invalid offset
    			if (!/^-?\d+$/.test(val)) { return; }
    			
    			// convert to integer
    			val = integer(val);
    		}
    		
    		var date = new Date();
    		date.setDate(date.getDate() + val);
    		return date; 
    	}
    	
    //}}}
    		 
    	
    	function Dateinput(input, conf)  { 
    
    		// variables
    		var self = this,  
    			 now = new Date(),
    			 css = conf.css,
    			 labels = LABELS[conf.lang],
    			 root = $("#" + css.root),
    			 title = root.find("#" + css.title),
    			 trigger,
    			 pm, nm, 
    			 currYear, currMonth, currDay,
    			 value = input.attr("data-value") || conf.value || input.val(), 
    			 min = input.attr("min") || conf.min,  
    			 max = input.attr("max") || conf.max,
    			 opened;
    
    		// zero min is not undefined 	 
    		if (min === 0) { min = "0"; }
    		
    		// use sane values for value, min & max		
    		value = parseDate(value) || now;
    		min   = parseDate(min || conf.yearRange[0] * 365);
    		max   = parseDate(max || conf.yearRange[1] * 365);
    		
    		
    		// check that language exists
    		if (!labels) { throw "Dateinput: invalid language: " + conf.lang; }
    		
    		// Replace built-in date input: NOTE: input.attr("type", "text") throws exception by the browser
    		if (input.attr("type") == 'date') {
    			var tmp = $("<input/>");
    				 
    			$.each("class,disabled,id,maxlength,name,readonly,required,size,style,tabindex,title,value".split(","), function(i, attr)  {
    				tmp.attr(attr, input.attr(attr));		
    			});			
    			input.replaceWith(tmp);
    			input = tmp;
    		}
    		input.addClass(css.input);
    		
    		var fire = input.add(self);
    			 
    		// construct layout
    		if (!root.length) {
    			
    			// root
    			root = $('<div><div><a/><div/><a/></div><div><div/><div/></div></div>')
    				.hide().css({position: 'static'}).attr("id", css.root);			
    						
    			// elements
    			root.children()
    				.eq(0).attr("id", css.head).end() 
    				.eq(1).attr("id", css.body).children()
    					.eq(0).attr("id", css.days).end()
    					.eq(1).attr("id", css.weeks).end().end().end()
    				.find("a").eq(0).attr("id", css.prev).end().eq(1).attr("id", css.next);		 				  
    			
    			// title
    			title = root.find("#" + css.head).find("div").attr("id", css.title);
    			
    			// year & month selectors
    			if (conf.selectors) {				
    				var monthSelector = $("<select/>").attr("id", css.month),
    					 yearSelector = $("<select/>").attr("id", css.year);				
    				title.html(monthSelector.add(yearSelector));
    			}						
    			
    			// day titles
    			var days = root.find("#" + css.days); 
    			
    			// days of the week
    			for (var d = 0; d < 7; d++) { 
    				days.append($("<span/>").text(labels.shortDays[(d + conf.firstDay) % 7]));
    			}
    			
    			// $("body").append(root);
    			if (conf.container){
    				$(conf.container).append(root);
    			}else{
    				input.after(root);
    			}
    		}	
    		
    				
    		// trigger icon
    		if (conf.trigger) {
    			trigger = $("<a/>").attr("href", "#").addClass(css.trigger).click(function(e)  {
    				self.show();
    				return e.preventDefault();
    			}).insertAfter(input);	
    		}
    		
    		
    		// layout elements
    		var weeks = root.find("#" + css.weeks);
    		yearSelector = root.find("#" + css.year);
    		monthSelector = root.find("#" + css.month);
    			 
    		
    //{{{ pick
    			 			 
    		function select(date, conf, e) {  
    			
    			// current value
    			value 	 = date;
    			currYear  = date.getFullYear();
    			currMonth = date.getMonth();
    			currDay	 = date.getDate();				
    			
    			
    			// change
    			e = e || $.Event("api");
    			e.type = "change";
    			
    			fire.trigger(e, [date]); 
    			if (e.isDefaultPrevented()) { return; }
    			
    			// formatting			
    			input.val(format(date, conf.format, conf.lang));
    			
    			// store value into input
    			input.data("date", date);
    			
    			self.hide(e); 
    		}
    //}}}
    		
    		
    //{{{ onShow
    
    		function onShow(ev) {
    			
    			ev.type = "onShow";
    			fire.trigger(ev);
    			
    			$(document).bind("keydown.d", function(e) {
    					
    				if (e.ctrlKey) { return true; }				
    				var key = e.keyCode;			 
    				
    				// backspace clears the value
    				if (key == 8) {
    					input.val("");
    					return self.hide(e);	
    				}
    				
    				// esc key
    				if (key == 27) { return self.hide(e); }						
    					
    				if ($(KEYS).index(key) >= 0) {
    					
    					if (!opened) { 
    						self.show(e); 
    						return e.preventDefault();
    					} 
    					
    					var days = $("#" + css.weeks + " a"), 
    						 el = $("." + css.focus),
    						 index = days.index(el);
    					 
    					el.removeClass(css.focus);
    					
    					if (key == 74 || key == 40) { index += 7; }
    					else if (key == 75 || key == 38) { index -= 7; }							
    					else if (key == 76 || key == 39) { index += 1; }
    					else if (key == 72 || key == 37) { index -= 1; }
    					
    					
    					if (index > 41) {
    						 self.addMonth();
    						 el = $("#" + css.weeks + " a:eq(" + (index-42) + ")");
    					} else if (index < 0) {
    						 self.addMonth(-1);
    						 el = $("#" + css.weeks + " a:eq(" + (index+42) + ")");
    					} else {
    						 el = days.eq(index);
    					}
    					
    					el.addClass(css.focus);
    					return e.preventDefault();
    					
    				}
    			 
    				// pageUp / pageDown
    				if (key == 34) { return self.addMonth(); }						
    				if (key == 33) { return self.addMonth(-1); }
    				
    				// home
    				if (key == 36) { return self.today(); } 
    				
    				// enter
    				if (key == 13) {
    					if (!$(e.target).is("select")) {
    						$("." + css.focus).click(); 
    					} 
    				}
    				
    				return $([16, 17, 18, 9]).index(key) >= 0;  				
    			});
    			
    			
    			// click outside dateinput
    			$(document).bind("click.d", function(e) {					
    				var el = e.target;
    				
    				if (!$(el).parents("#" + css.root).length && el != input[0] && (!trigger || el != trigger[0])) {
    					self.hide(e);
    				}
    				
    			}); 
    		}
    //}}}
    		
    		
    		$.extend(self, {
    
    //{{{  show
    								
    			show: function(e) {
    				
    				if (input.attr("readonly") || input.attr("disabled") || opened) { return; }
    				
    				// onBeforeShow
    				e = e || $.Event();
    				e.type = "onBeforeShow";
    				fire.trigger(e);
    				if (e.isDefaultPrevented()) { return; }
    			
    				$.each(instances, function() {
    					this.hide();	
    				});
    				
    				opened = true;
    				
    				// month selector
    				monthSelector.unbind("change").change(function() {
    					self.setValue(yearSelector.val(), $(this).val());		
    				});
    				
    				// year selector
    				yearSelector.unbind("change").change(function() {
    					self.setValue($(this).val(), monthSelector.val());		
    				});
    				
    				// prev / next month
    				pm = root.find("#" + css.prev).unbind("click").click(function(e) {
    					if (!pm.hasClass(css.disabled)) {	
    						self.addMonth(-1);
    					}
    					return false;
    				});
    				
    				nm = root.find("#" + css.next).unbind("click").click(function(e) {
    					if (!nm.hasClass(css.disabled)) {
    						self.addMonth();
    					}
    					return false;
    				});	 
    				
    				// set date
    				self.setValue(value);				 
    				
    				// show calendar
    				// var pos = input.offset();
    			if (conf.container){
    				var pos = input.offset();
    			}else{
    				var pos = input.position();
    			}
    
    				// iPad position fix
    				if (/iPad/i.test(navigator.userAgent)) {
    					pos.top -= $(window).scrollTop();
    				}
    				
    				root.css({ 
    					top: pos.top + input.outerHeight({margins: true}) + conf.offset[0], 
    					left: pos.left + conf.offset[1] 
    				});
    				
    				if (conf.speed) {
    					root.show(conf.speed, function() {
    						onShow(e);			
    					});	
    				} else {
    					root.show();
    					onShow(e);
    				}
    				
    				return self;
    			}, 
    //}}}
    
    
    //{{{  setValue
    
    			setValue: function(year, month, day)  {
    				
    				var date = integer(month) >= -1 ?
    					new Date(integer(year), integer(month), integer(day || 1)) : year || value
    				;				
    				
    				if (date < min) { date = min; }
    				else if (date > max) { date = max; }
    				
    				year = date.getFullYear();
    				month = date.getMonth();
    				day = date.getDate(); 
    				
    				
    				// roll year & month
    				if (month == -1) {
    					month = 11;
    					year--;
    				} else if (month == 12) {
    					month = 0;
    					year++;
    				} 
    				
    				if (!opened) { 
    					select(date, conf);
    					return self; 
    				} 				
    				
    				currMonth = month;
    				currYear = year;
    
    				// variables
    				var tmp = new Date(year, month, 1 - conf.firstDay), begin = tmp.getDay(),
    					 days = dayAm(year, month),
    					 prevDays = dayAm(year, month - 1),
    					 week;	 
    				
    				// selectors
    				if (conf.selectors) { 
    					
    					// month selector
    					monthSelector.empty();
    					$.each(labels.months, function(i, m) {					
    						if (min < new Date(year, i + 1, -1) && max > new Date(year, i, 0)) {
    							monthSelector.append($("<option/>").html(m).attr("value", i));
    						}
    					});
    					
    					// year selector
    					yearSelector.empty();		
    					var yearNow = now.getFullYear();
    					
    					for (var i = yearNow + conf.yearRange[0];  i < yearNow + conf.yearRange[1]; i++) {
    						if (min <= new Date(i + 1, -1, 1) && max > new Date(i, 0, 0)) {
    							yearSelector.append($("<option/>").text(i));
    						}
    					}		
    					
    					monthSelector.val(month);
    					yearSelector.val(year);
    					
    				// title
    				} else {
    					title.html(labels.months[month] + " " + year);	
    				} 	   
    					 
    				// populate weeks
    				weeks.empty();				
    				pm.add(nm).removeClass(css.disabled); 
    				
    				// !begin === "sunday"
    				for (var j = !begin ? -7 : 0, a, num; j < (!begin ? 35 : 42); j++) { 
    					
    					a = $("<a/>");
    					
    					if (j % 7 === 0) {
    						week = $("<div/>").addClass(css.week);
    						weeks.append(week);			
    					}					
    					
    					if (j < begin)  { 
    						a.addClass(css.off); 
    						num = prevDays - begin + j + 1;
    						date = new Date(year, month-1, num);
    						a.attr("href", "#" + year + "-" + month + "-" + num).text(num).data("date", date);	
    						
    					} else if (j >= begin + days)  {
    						a.addClass(css.off);	
    						num = j - days - begin + 1;
    						date = new Date(year, month+1, num);
    						a.attr("href", "#" + year + "-" + (month+2) + "-" + num).text(num).data("date", date);	
    						
    					} else  { 
    						num = j - begin + 1;
    						date = new Date(year, month, num);  
    						
    						// current date
    						if (isSameDay(value, date)) {
    							a.attr("id", css.current).addClass(css.focus);
    							
    						// today
    						} else if (isSameDay(now, date)) {
    							a.attr("id", css.today);
    						}	
    						a.attr("href", "#" + year + "-" + (month+1) + "-" + num).text(num).data("date", date);							
    					}
    					
    					// disabled
    					if (min && date < min) {
    						a.add(pm).addClass(css.disabled);						
    					}
    					
    					if (max && date > max) {
    						a.add(nm).addClass(css.disabled);						
    					}
    					
    									
    					
    					week.append(a);
    				}
    				
    				// date picking					
    				weeks.find("a").click(function(e) {
    					var el = $(this); 
    					if (!el.hasClass(css.disabled)) {  
    						$("#" + css.current).removeAttr("id");
    						el.attr("id", css.current);	 
    						select(el.data("date"), conf, e);
    					}
    					return false;
    				});
    
    				// sunday
    				if (css.sunday) {
    					weeks.find(css.week).each(function() {
    						var beg = conf.firstDay ? 7 - conf.firstDay : 0;
    						$(this).children().slice(beg, beg + 1).addClass(css.sunday);		
    					});	
    				} 
    				
    				return self;
    			}, 
    	//}}}
    	
    			setMin: function(val, fit) {
    				min = parseDate(val);
    				if (fit && value < min) { self.setValue(min); }
    				return self;
    			},
    		
    			setMax: function(val, fit) {
    				max = parseDate(val);
    				if (fit && value > max) { self.setValue(max); }
    				return self;
    			}, 
    			
    			today: function() {
    				return self.setValue(now);	
    			},
    			
    			addDay: function(amount) {
    				return this.setValue(currYear, currMonth, currDay + (amount || 1));		
    			},
    			
    			addMonth: function(amount) {
    				return this.setValue(currYear, currMonth + (amount || 1), currDay);	
    			},
    			
    			addYear: function(amount) {
    				return this.setValue(currYear + (amount || 1), currMonth, currDay);	
    			},
    						
    			hide: function(e) {				 
    				
    				if (opened) {  
    					
    					// onHide 
    					e = $.Event();
    					e.type = "onHide";
    					fire.trigger(e);
    					
    					$(document).unbind("click.d").unbind("keydown.d");
    					
    					// cancelled ?
    					if (e.isDefaultPrevented()) { return; }
    					
    					// do the hide
    					root.hide();
    					opened = false;
    				}
    				
    				return self;
    			},
    			
    			getConf: function() {
    				return conf;	
    			},
    			
    			getInput: function() {
    				return input;	
    			},
    			
    			getCalendar: function() {
    				return root;	
    			},
    			
    			getValue: function(dateFormat) {
    				return dateFormat ? format(value, dateFormat, conf.lang) : value;	
    			},
    			
    			isOpen: function() {
    				return opened;	
    			}
    			
    		}); 
    		
    		// callbacks	
    		$.each(['onBeforeShow','onShow','change','onHide'], function(i, name) {
    				
    			// configuration
    			if ($.isFunction(conf[name]))  {
    				$(self).bind(name, conf[name]);	
    			}
    			
    			// API methods				
    			self[name] = function(fn) {
    				if (fn) { $(self).bind(name, fn); }
    				return self;
    			};
    		});
    
    		
    		// show dateinput & assign keyboard shortcuts
    		input.bind("focus click", self.show).keydown(function(e) {
    
    			var key = e.keyCode;
    	
    			// open dateinput with navigation keyw
    			if (!opened &&  $(KEYS).index(key) >= 0) {
    				self.show(e);
    				return e.preventDefault();
    			} 
    			
    			// allow tab
    			return e.shiftKey || e.ctrlKey || e.altKey || key == 9 ? true : e.preventDefault();   
    			
    		}); 
    		
    		// initial value 		
    		if (parseDate(input.val())) { 
    			select(value, conf);
    		}
    		
    	} 
    	
    	$.expr[':'].date = function(el) {
    		var type = el.getAttribute("type");
    		return type && type == 'date' || !!$(el).data("dateinput");
    	};
    	
    	
    	$.fn.dateinput = function(conf) {   
    		
    		// already instantiated
    		if (this.data("dateinput")) { return this; } 
    		
    		// configuration
    		conf = $.extend(true, {}, tool.conf, conf);		
    		
    		// CSS prefix
    		$.each(conf.css, function(key, val) {
    			if (!val && key != 'prefix') { 
    				conf.css[key] = (conf.css.prefix || '') + (val || key);
    			}
    		});		
    	
    		var els;
    		
    		this.each(function() {									
    			var el = new Dateinput($(this), conf);
    			instances.push(el);
    			var input = el.getInput().data("dateinput", el);
    			els = els ? els.add(input) : input;	
    		});		
    	
    		return els ? els : this;		
    	}; 
    	
    	
    }) (jQuery);
    




    Et si vous avez la flemme, voici les passages qui je pense, se rapportent au changement de mois :

    // prev / next month
    pm = root.find("#" + css.prev).unbind("click").click(function(e) {
    	if (!pm.hasClass(css.disabled)) {	
    		self.addMonth(-1);
    	}
    	return false;
    });
    
    nm = root.find("#" + css.next).unbind("click").click(function(e) {
    	if (!nm.hasClass(css.disabled)) {
    		self.addMonth();
    	}
    	return false;
    });
    


    addMonth: function(amount) {
    	return this.setValue(currYear, currMonth + (amount || 1), currDay);	
    },
    


    J'ai rajouté ce code (dans index.php), qui intervient au clic sur une des 2 flèches :

    $("#calprev").click(function() {
    	$(".calweek a").each(function(){
    	var that = this;
    	$.get("jour.php",{jour:$(this).attr("href")},  
    		function success(data){   
    			$(that).addClass(data);
    		}
    		); 
    	 });
    } );			
    
    $("#calnext").click(function() {
    	$(".calweek a").each(function(){
    	var that = this;
    	$.get("jour.php",{jour:$(this).attr("href")},  
    		function success(data){   
    			$(that).addClass(data);
    		}
    		); 
    	 });
    } );
    


    Mais le calendrier a déjà fonctionné correctement avec ça en +.

    Merci pour votre aide
    • Partager sur Facebook
    • Partager sur Twitter
      3 novembre 2010 à 14:41:41

      Waouh,
      rien que ça pour un simple calendrier o_O .

      ton code fonctionne bien (en tout cas sous firefox).
      • Partager sur Facebook
      • Partager sur Twitter
        3 novembre 2010 à 14:46:17

        Citation : thez_au_riz

        Waouh,
        rien que ça pour un simple calendrier o_O .

        ton code fonctionne bien (en tout cas sous firefox).



        En fait, j'ai demandé à un collègue qui s'y connaît en JQuery, et c'est un bug propre au calendrier:
        Quand on est positionné sur le jour 31 d'un mois, et qu'on veut changer de mois, le script se positionne sur le même jour du mois suivant (donc le 31 du mois suivant). Sauf que le mois suivant du mois qui a 31 jours n'a que 30 jours, d'où le bug. Du coup j'ai corrigé et ça marche mieux ;)
        • Partager sur Facebook
        • Partager sur Twitter

        Comportement calendrier en JQuery

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
        • Editeur
        • Markdown