Просмотр исходного кода

better handling of year and month custom views

Adam Shaw 11 лет назад
Родитель
Сommit
f90476a957

+ 0 - 1
src/agenda/AgendaView.js

@@ -35,7 +35,6 @@ fcViews.agenda = View.extend({ // AgendaView
 
 		if (this.opt('allDaySlot')) { // should we display the "all-day" area?
 			this.dayGrid = new DayGrid(this); // the all-day subcomponent of this view
-			this.dayGrid.breakOnWeeks = false;
 
 			// the coordinate grid will be a combination of both subcomponents' grids
 			this.coordMap = new ComboCoordMap([

+ 22 - 0
src/basic/BasicView.js

@@ -25,10 +25,32 @@ var BasicView = fcViews.basic = View.extend({
 	// Sets the display range and computes all necessary dates
 	setRange: function(range) {
 		View.prototype.setRange.call(this, range); // call the super-method
+
+		this.dayGrid.breakOnWeeks = /year|month|week/.test(this.intervalUnit); // do before setRange
 		this.dayGrid.setRange(range);
 	},
 
 
+	// Compute the value to feed into setRange. Overrides superclass.
+	computeRange: function(date) {
+		var range = View.prototype.computeRange.call(this, date); // get value from the super-method
+
+		// year and month views should be aligned with weeks. this is already done for week
+		if (/year|month/.test(range.intervalUnit)) {
+			range.start.startOf('week');
+			range.start = this.skipHiddenDays(range.start);
+
+			// make end-of-week if not already
+			if (range.end.weekday()) {
+				range.end.add(1, 'week').startOf('week');
+				range.end = this.skipHiddenDays(range.end, -1, true); // exclusively move backwards
+			}
+		}
+
+		return range;
+	},
+
+
 	// Renders the view into `this.el`, which should already be assigned
 	render: function() {
 

+ 12 - 29
src/basic/MonthView.js

@@ -6,40 +6,21 @@ setDefaults({
 	fixedWeekCount: true
 });
 
-fcViews.month = BasicView.extend({ // MonthView
+var MonthView = fcViews.month = BasicView.extend({
 
+	// Produces information about what range to display
 	computeRange: function(date) {
-		var rowCnt;
-		var intervalStart, intervalEnd;
-		var start, end;
-
-		intervalStart = date.clone().stripTime().startOf('month');
-		intervalEnd = intervalStart.clone().add(1, 'months');
-
-		start = intervalStart.clone();
-		start = this.skipHiddenDays(start); // move past the first week if no visible days
-		start.startOf('week');
-		start = this.skipHiddenDays(start); // move past the first invisible days of the week
-
-		end = intervalEnd.clone();
-		end = this.skipHiddenDays(end, -1, true); // move in from the last week if no visible days
-		end.add((7 - end.weekday()) % 7, 'days'); // move to end of week if not already
-		end = this.skipHiddenDays(end, -1, true); // move in from the last invisible days of the week
-
-		rowCnt = Math.ceil( // need to ceil in case there are hidden days
-			end.diff(start, 'weeks', true) // returnfloat=true
-		);
+		var range = BasicView.prototype.computeRange.call(this, date); // get value from super-method
+
 		if (this.isFixedWeeks()) {
-			end.add(6 - rowCnt, 'weeks');
-			rowCnt = 6;
+			// ensure 6 weeks
+			range.end.add(
+				6 - range.end.diff(range.start, 'weeks'),
+				'weeks'
+			);
 		}
 
-		return {
-			start: start,
-			end: end,
-			intervalStart: intervalStart,
-			intervalEnd: intervalEnd
-		};
+		return range;
 	},
 
 
@@ -67,3 +48,5 @@ fcViews.month = BasicView.extend({ // MonthView
 	}
 
 });
+
+MonthView.duration = { months: 1 };

+ 2 - 7
src/common/DayGrid.js

@@ -6,7 +6,7 @@ var DayGrid = Grid.extend({
 
 	numbersVisible: false, // should render a row for day/week numbers? set by outside view. TODO: make internal
 	bottomCoordPadding: 0, // hack for extending the hit area for the last row of the coordinate grid
-	breakOnWeeks: null, // allows the outside view to override this rendering setting
+	breakOnWeeks: null, // should create a new row for each week? set by outside view
 
 	cellDates: null, // flat chronological array of each cell's dates
 	dayToCellOffsets: null, // maps days offsets from grid's start date, to cell offsets
@@ -126,20 +126,15 @@ var DayGrid = Grid.extend({
 
 	// Initializes row/col information
 	updateCells: function() {
-		var breakOnWeeks = this.breakOnWeeks; // look at the override first
 		var cellDates;
 		var firstDay;
 		var rowCnt;
 		var colCnt;
 
-		if (breakOnWeeks == null) { // not overridden. compute it
-			breakOnWeeks = /year|month|week/.test(this.view.intervalUnit);
-		}
-
 		this.updateCellDates(); // populates cellDates and dayToCellOffsets
 		cellDates = this.cellDates;
 
-		if (breakOnWeeks) {
+		if (this.breakOnWeeks) {
 			// count columns until the day-of-week repeats
 			firstDay = cellDates[0].day();
 			for (colCnt = 1; colCnt < cellDates.length; colCnt++) {

+ 20 - 23
src/common/View.js

@@ -109,48 +109,45 @@ var View = fc.View = Class.extend({
 	// Updates all internal dates for displaying the given range.
 	// Expects all values to be normalized (like what computeRange does).
 	setRange: function(range) {
-		this.start = range.start;
-		this.end = range.end;
-
-		// all interval-related is computed if not explicitly provided by computeRange
-		this.intervalStart = range.intervalStart || range.start.clone();
-		this.intervalEnd = range.intervalEnd || range.end.clone();
-		this.intervalDuration = range.intervalDuration || computeIntervalDuration(this.intervalStart, this.intervalEnd);
-		this.intervalUnit = range.intervalUnit || computeIntervalUnit(this.intervalDuration);
+		$.extend(this, range);
 	},
 
 
-	// Given a single current, produce information about what range to display.
-	// Subclasses can override. Must return {start,end} at the very least.
+	// Given a single current date, produce information about what range to display.
+	// Subclasses can override. Must return all properties.
 	computeRange: function(date) {
-		var intervalDuration = moment.duration(this.opt('duration') || { days: 1 });
+		var intervalDuration = moment.duration(this.opt('duration') || this.constructor.duration || { days: 1 });
 		var intervalUnit = computeIntervalUnit(intervalDuration);
-		var start = date.clone().startOf(intervalUnit);
-		var end = start.clone().add(intervalDuration);
+		var intervalStart = date.clone().startOf(intervalUnit);
+		var intervalEnd = intervalStart.clone().add(intervalDuration);
+		var start, end;
 
 		// normalize the range's time-ambiguity
 		if (computeIntervalAs('days', intervalDuration)) { // whole-days?
-			start.stripTime();
-			end.stripTime();
+			intervalStart.stripTime();
+			intervalEnd.stripTime();
 		}
 		else { // needs to have a time?
-			if (!start.hasTime()) {
-				start = this.calendar.rezoneDate(start); // convert to current timezone, with a 00:00 time
+			if (!intervalStart.hasTime()) {
+				intervalStart = this.calendar.rezoneDate(intervalStart); // convert to current timezone, with 00:00
 			}
-			if (!end.hasTime()) {
-				end = this.calendar.rezoneDate(end); // convert to current timezone, with a 00:00 time
+			if (!intervalEnd.hasTime()) {
+				intervalEnd = this.calendar.rezoneDate(intervalEnd); // convert to current timezone, with 00:00
 			}
 		}
 
-		// trim the range's edges for hidden days
+		start = intervalStart.clone();
 		start = this.skipHiddenDays(start);
+		end = intervalEnd.clone();
 		end = this.skipHiddenDays(end, -1, true); // exclusively move backwards
 
 		return {
-			start: start,
-			end: end,
 			intervalDuration: intervalDuration,
-			intervalUnit: intervalUnit
+			intervalUnit: intervalUnit,
+			intervalStart: intervalStart,
+			intervalEnd: intervalEnd,
+			start: start,
+			end: end
 		};
 	},
 

+ 2 - 0
src/util.js

@@ -286,6 +286,7 @@ function diffDay(a, b) {
 // Computes the larges whole-unit period of time, as a duration object.
 // For example, 48 hours will be {days:2} whereas 49 hours will be {hours:49}.
 // Accepts start/end, a range object, or an original duration object.
+/* (never used)
 function computeIntervalDuration(start, end) {
 	var durationInput = {};
 	var i, unit;
@@ -302,6 +303,7 @@ function computeIntervalDuration(start, end) {
 	durationInput[unit] = val;
 	return moment.duration(durationInput);
 }
+*/
 
 
 // Computes the unit name of the largest whole-unit period of time.

+ 41 - 0
tests/automated/custom-view-duration.js

@@ -145,4 +145,45 @@ describe('custom view duration', function() {
 		expect($('.fc-time-grid .fc-day').length).toBe(14);
 		expect($('.fc-time-grid .fc-day:first')).toBeMatchedBy('[data-date="2014-12-21"]'); // week start
 	});
+
+	it('renders a two month agenda view', function() {
+		options.views.agendaTwoMonth = {
+			type: 'agenda',
+			duration: { months: 2 }
+		};
+		options.defaultView = 'agendaTwoMonth';
+		options.defaultDate = '2014-11-27';
+		$('#cal').fullCalendar(options);
+		expect($('.fc-day-grid .fc-row').length).toBe(1);
+		expect($('.fc-day-grid .fc-row .fc-day').length).toBe(61); // one long row
+		expect($('.fc-time-grid .fc-day').length).toBe(61);
+		expect($('.fc-time-grid .fc-day:first')).toBeMatchedBy('[data-date="2014-11-01"]');
+		expect($('.fc-time-grid .fc-day:last')).toBeMatchedBy('[data-date="2014-12-31"]');
+	});
+
+	it('renders a two month basic view', function() {
+		options.views.basicTwoWeek = {
+			type: 'basic',
+			duration: { months: 2 }
+		};
+		options.defaultView = 'basicTwoWeek';
+		options.defaultDate = '2014-11-27';
+		$('#cal').fullCalendar(options);
+		expect($('.fc-day-grid .fc-row').length).toBe(10);
+		expect($('.fc-day-grid .fc-row:first .fc-day').length).toBe(7);
+		expect($('.fc-day-grid .fc-day:first')).toBeMatchedBy('[data-date="2014-10-26"]');
+		expect($('.fc-day-grid .fc-day:last')).toBeMatchedBy('[data-date="2015-01-03"]');
+	});
+
+	it('renders a one year basic view', function() {
+		options.views.basicYear = {
+			type: 'basic',
+			duration: { years: 1 }
+		};
+		options.defaultView = 'basicYear';
+		options.defaultDate = '2014-11-27';
+		$('#cal').fullCalendar(options);
+		expect($('.fc-day-grid .fc-day:first')).toBeMatchedBy('[data-date="2013-12-29"]');
+		expect($('.fc-day-grid .fc-day:last')).toBeMatchedBy('[data-date="2015-01-03"]');
+	});
 });