Adam Shaw 13 лет назад
Родитель
Сommit
b62383d0ad

+ 34 - 2
src/agenda/AgendaView.js

@@ -121,6 +121,9 @@ function AgendaView(element, calendar, viewName) {
 	var rtl, dis, dit;  // day index sign / translate
 	var minMinute, maxMinute;
 	var colFormat;
+	var showWeekNumbers;
+	var weekNumberTitle;
+	var weekNumberFormat;
 	
 
 	
@@ -158,6 +161,16 @@ function AgendaView(element, calendar, viewName) {
 		minMinute = parseTime(opt('minTime'));
 		maxMinute = parseTime(opt('maxTime'));
 		colFormat = opt('columnFormat');
+
+		// week # options. (TODO: bad, logic also in other views)
+		showWeekNumbers = opt('weekNumbers');
+		weekNumberTitle = opt('weekNumberTitle');
+		if (opt('weekNumberCalculation') != 'iso') {
+			weekNumberFormat = "w";
+		}
+		else {
+			weekNumberFormat = "W";
+		}
 	}
 	
 	
@@ -175,8 +188,15 @@ function AgendaView(element, calendar, viewName) {
 		s =
 			"<table style='width:100%' class='fc-agenda-days fc-border-separate' cellspacing='0'>" +
 			"<thead>" +
-			"<tr>" +
-			"<th class='fc-agenda-axis " + headerClass + "'>&nbsp;</th>";
+			"<tr>";
+
+		if (showWeekNumbers) {
+			s += "<th class='fc-agenda-axis fc-week-number " + headerClass + "'/>";
+		}
+		else {
+			s += "<th class='fc-agenda-axis " + headerClass + "'>&nbsp;</th>";
+		}
+
 		for (i=0; i<colCnt; i++) {
 			s +=
 				"<th class='fc- fc-col" + i + ' ' + headerClass + "'/>"; // fc- needed for setDayID
@@ -310,6 +330,18 @@ function AgendaView(element, calendar, viewName) {
 		var bodyCell;
 		var date;
 		var today = clearTime(new Date());
+
+		if (showWeekNumbers) {
+			var weekText = formatDate(colDate(0), weekNumberFormat);
+			if (rtl) {
+				weekText = weekText + weekNumberTitle;
+			}
+			else {
+				weekText = weekNumberTitle + weekText;
+			}
+			dayHead.find('.fc-week-number').text(weekText);
+		}
+
 		for (i=0; i<colCnt; i++) {
 			date = colDate(i);
 			headCell = dayHeadCells.eq(i);

+ 4 - 0
src/agenda/agenda.css

@@ -18,6 +18,10 @@
 	white-space: nowrap;
 	font-weight: normal;
 	}
+
+.fc-agenda .fc-week-number {
+	font-weight: bold;
+	}
 	
 .fc-agenda .fc-day-content {
 	padding: 2px 2px 1px;

+ 50 - 6
src/basic/BasicView.js

@@ -63,6 +63,7 @@ function BasicView(element, calendar, viewName) {
 	var viewWidth;
 	var viewHeight;
 	var colWidth;
+	var weekNumberWidth;
 	
 	var rowCnt, colCnt;
 	var coordinateGrid;
@@ -71,9 +72,12 @@ function BasicView(element, calendar, viewName) {
 	
 	var rtl, dis, dit;
 	var firstDay;
-	var nwe;
+	var nwe; // no weekends? a 0 or 1 for easy computations
 	var tm;
 	var colFormat;
+	var showWeekNumbers;
+	var weekNumberTitle;
+	var weekNumberFormat;
 	
 	
 	
@@ -112,6 +116,16 @@ function BasicView(element, calendar, viewName) {
 		nwe = opt('weekends') ? 0 : 1;
 		tm = opt('theme') ? 'ui' : 'fc';
 		colFormat = opt('columnFormat');
+
+		// week # options. (TODO: bad, logic also in other views)
+		showWeekNumbers = opt('weekNumbers');
+		weekNumberTitle = opt('weekNumberTitle');
+		if (opt('weekNumberCalculation') != 'iso') {
+			weekNumberFormat = "w";
+		}
+		else {
+			weekNumberFormat = "W";
+		}
 	}
 	
 	
@@ -127,6 +141,10 @@ function BasicView(element, calendar, viewName) {
 			"<table class='fc-border-separate' style='width:100%' cellspacing='0'>" +
 			"<thead>" +
 			"<tr>";
+		if (showWeekNumbers) {
+			s +=
+				"<th class='fc-week-number " + headerClass + "'/>";
+		}
 		for (i=0; i<colCnt; i++) {
 			s +=
 				"<th class='fc- " + headerClass + "'/>"; // need fc- for setDayID
@@ -138,6 +156,10 @@ function BasicView(element, calendar, viewName) {
 		for (i=0; i<maxRowCnt; i++) {
 			s +=
 				"<tr class='fc-week" + i + "'>";
+			if (showWeekNumbers) {
+				s +=
+					"<td class='fc-week-number " + contentClass + "'><div></div></td>";
+			}
 			for (j=0; j<colCnt; j++) {
 				s +=
 					"<td class='fc- " + contentClass + " fc-day" + (i*colCnt+j) + "'>" + // need fc- for setDayID
@@ -161,11 +183,11 @@ function BasicView(element, calendar, viewName) {
 		table = $(s).appendTo(element);
 		
 		head = table.find('thead');
-		headCells = head.find('th');
+		headCells = head.find('th:not(.fc-week-number)');
 		body = table.find('tbody');
 		bodyRows = body.find('tr');
-		bodyCells = body.find('td');
-		bodyFirstCells = bodyCells.filter(':first-child');
+		bodyCells = body.find('td').filter(':not(.fc-week-number)');
+		bodyFirstCells = bodyCells.filter(':first-child, td.fc-week-number + *'); // either first cell in each row, or immediately following week #
 		bodyCellTopInners = bodyRows.eq(0).find('div.fc-day-content div');
 		
 		markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's
@@ -189,6 +211,10 @@ function BasicView(element, calendar, viewName) {
 		var date;
 		var row;
 	
+		if (showWeekNumbers) {
+			head.find('.fc-week-number').text(weekNumberTitle);
+		}
+
 		if (dowDirty) {
 			headCells.each(function(i, _cell) {
 				cell = $(_cell);
@@ -220,6 +246,14 @@ function BasicView(element, calendar, viewName) {
 		bodyRows.each(function(i, _row) {
 			row = $(_row);
 			if (i < rowCnt) {
+
+				if (showWeekNumbers) {
+					var weekStartDate = indexDate(i*7);
+					row.find('.fc-week-number > div').text(
+						formatDate(weekStartDate, weekNumberFormat)
+					);
+				}
+
 				row.show();
 				if (i == rowCnt-1) {
 					row.addClass('fc-last');
@@ -265,7 +299,13 @@ function BasicView(element, calendar, viewName) {
 	function setWidth(width) {
 		viewWidth = width;
 		colContentPositions.clear();
-		colWidth = Math.floor(viewWidth / colCnt);
+
+		weekNumberWidth = 0;
+		if (showWeekNumbers) {
+			weekNumberWidth = head.find('th.fc-week-number').outerWidth();
+		}
+
+		colWidth = Math.floor((viewWidth - weekNumberWidth) / colCnt);
 		setOuterWidth(headCells.slice(0, -1), colWidth);
 	}
 	
@@ -475,8 +515,12 @@ function BasicView(element, calendar, viewName) {
 	
 	
 	function allDayBounds(i) {
+		var left = 0;
+		if (showWeekNumbers) {
+			left += weekNumberWidth;
+		}
 		return {
-			left: 0,
+			left: left,
 			right: viewWidth
 		};
 	}

+ 9 - 0
src/basic/basic.css

@@ -5,6 +5,15 @@
 .fc-grid th {
 	text-align: center;
 	}
+
+.fc .fc-week-number {
+	width: 22px;
+	text-align: center;
+	}
+
+.fc .fc-week-number div {
+	padding: 0 2px;
+	}
 	
 .fc-grid .fc-day-number {
 	float: right;

+ 1 - 1
src/common/DayEventRenderer.js

@@ -343,7 +343,7 @@ function DayEventRenderer() {
 		var rowDivs = [];
 		for (i=0; i<rowCnt; i++) {
 			rowDivs[i] = allDayRow(i)
-				.find('td:first div.fc-day-content > div'); // optimal selector?
+				.find('div.fc-day-content > div'); // optimal selector?
 		}
 		return rowDivs;
 	}

+ 25 - 0
src/date_util.js

@@ -353,7 +353,32 @@ var dateFormatters = {
 			return 'th';
 		}
 		return ['st', 'nd', 'rd'][date%10-1] || 'th';
+	},
+	w   : function(d, o) { // local
+		return o.weekNumberCalculation(d);
+	},
+	W   : function(d) { // ISO
+		return iso8601Week(d);
 	}
 };
 
 
+/* thanks jQuery UI (https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js)
+ * 
+ * Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+ * @param  date  Date - the date to get the week for
+ * @return  number - the number of the week within the year that contains this date
+ */
+function iso8601Week(date) {
+	var time;
+	var checkDate = new Date(date.getTime());
+
+	// Find Thursday of this week starting on Monday
+	checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+	time = checkDate.getTime();
+	checkDate.setMonth(0); // Compare with Jan 1
+	checkDate.setDate(1);
+	return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+}
+

+ 3 - 0
src/defaults.js

@@ -10,6 +10,9 @@ var defaults = {
 		right: 'today prev,next'
 	},
 	weekends: true,
+	weekNumbers: false,
+	weekNumberCalculation: 'iso',
+	weekNumberTitle: 'W',
 	
 	// editing
 	//editable: false,

+ 109 - 0
tests/week_numbers.html

@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel='stylesheet' href='../build/out/fullcalendar/fullcalendar.css' />
+<link rel='stylesheet' href='../build/out/fullcalendar/fullcalendar.print.css' media='print' />
+<link rel='stylesheet' href='../demos/cupertino/theme.css' />
+<script src='../lib/moment.js'></script>
+<script src='../build/deps.js'></script>
+<script src='../build/out/fullcalendar/fullcalendar.js'></script>
+<script>
+
+	$(document).ready(function() {
+	
+		var date = new Date();
+		var d = date.getDate();
+		var m = date.getMonth();
+		var y = date.getFullYear();
+		
+		$('#calendar').fullCalendar({
+
+			weekNumbers: true,
+			weekNumberTitle: 'Wk ',
+
+			//weekNumberCalculation: function(date) {
+			//	return date.getMonth(); // inappropriate. but just for testing
+			//},
+
+			firstDay: 1,
+			selectable: true,
+			//isRTL: true,
+			//theme: true,
+
+			editable: true,
+			header: {
+				left: 'prev,next today',
+				center: 'title',
+				right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
+			},
+			events: [
+				{
+					title: 'All Day Event',
+					start: new Date(y, m, 1)
+				},
+				{
+					title: 'Long Event',
+					start: new Date(y, m, d-5),
+					end: new Date(y, m, d-2)
+				},
+				{
+					id: 999,
+					title: 'Repeating Event',
+					start: new Date(y, m, d-3, 16, 0),
+					allDay: false
+				},
+				{
+					id: 999,
+					title: 'Repeating Event',
+					start: new Date(y, m, d+4, 16, 0),
+					allDay: false
+				},
+				{
+					title: 'Meeting',
+					start: new Date(y, m, d, 10, 30),
+					allDay: false
+				},
+				{
+					title: 'Lunch',
+					start: new Date(y, m, d, 12, 5),
+					end: new Date(y, m, d, 14, 43),
+					allDay: false
+				},
+				{
+					title: 'Birthday Party',
+					start: new Date(y, m, d+1, 19, 0),
+					end: new Date(y, m, d+1, 22, 30),
+					allDay: false
+				},
+				{
+					title: 'Click for Google',
+					start: new Date(y, m, 28),
+					end: new Date(y, m, 29),
+					url: 'http://google.com/'
+				}
+			]
+		});
+		
+	});
+
+</script>
+<style>
+
+	body {
+		margin-top: 40px;
+		text-align: center;
+		font-size: 13px;
+		font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
+		}
+
+	#calendar {
+		width: 900px;
+		margin: 0 auto;
+		}
+
+</style>
+</head>
+<body>
+<div id='calendar'></div>
+</body>
+</html>