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

move View date range methods to own file

Adam Shaw 9 лет назад
Родитель
Сommit
42e6e01e45
3 измененных файлов с 366 добавлено и 333 удалено
  1. 1 0
      src.json
  2. 364 0
      src/common/View.date-range.js
  3. 1 333
      src/common/View.js

+ 1 - 0
src.json

@@ -26,6 +26,7 @@
     "common/TimeGrid.js",
     "common/TimeGrid.events.js",
     "common/View.js",
+    "common/View.date-range.js",
     "common/Scroller.js",
     "common/Iterator.js",
     "Toolbar.js",

+ 364 - 0
src/common/View.date-range.js

@@ -0,0 +1,364 @@
+
+View.mixin({å
+
+	// range the view is formally responsible for.
+	// for example, a month view might have 1st-31st, excluding padded dates
+	currentRange: null,
+	currentRangeUnit: null, // name of largest unit being displayed, like "month" or "week"
+
+	// date range with a rendered skeleton
+	// includes not-active days that need some sort of DOM
+	renderRange: null,
+
+	// dates that display events and accept drag-n-drop
+	activeRange: null,
+
+	// constraint for where prev/next operations can go and where events can be dragged/resized to.
+	// an object with optional start and end properties.
+	validRange: null,
+
+	// how far the current date will move for a prev/next operation
+	dateIncrement: null,
+
+	// stores the *calendar's* current date after setDate
+	// TODO: entirely Calendar's responsibility
+	currentDate: null,
+
+	// DEPRECATED
+	start: null, // use activeRange.start
+	end: null, // use activeRange.end
+	intervalStart: null, // use currentRange.start
+	intervalEnd: null, // use currentRange.end
+
+
+	/* Date Range Computation
+	------------------------------------------------------------------------------------------------------------------*/
+
+
+	// Updates all internal dates/ranges for eventual rendering around the given date.
+	// Returns a boolean about whether there was some sort of change.
+	setRangeFromDate: function(date) {
+
+		var rangeInfo = this.buildRangeInfo(date);
+
+		// some sort of change? (TODO: compare other ranges too?)
+		if (!this.activeRange || !isRangesEqual(this.activeRange, rangeInfo.activeRange)) {
+
+			this.currentRange = rangeInfo.currentRange;
+			this.currentRangeUnit = rangeInfo.currentRangeUnit;
+			this.renderRange = rangeInfo.renderRange;
+			this.activeRange = rangeInfo.activeRange;
+			this.validRange = rangeInfo.validRange;
+			this.dateIncrement = rangeInfo.dateIncrement;
+			this.currentDate = rangeInfo.date;
+
+			// DEPRECATED, but we need to keep it updated
+			this.start = rangeInfo.activeRange.start;
+			this.end = rangeInfo.activeRange.end;
+			this.intervalStart = rangeInfo.currentRange.start;
+			this.intervalEnd = rangeInfo.currentRange.end;
+
+			this.updateTitle();
+			this.calendar.updateToolbarButtons();
+
+			return true;
+		}
+
+		return false;
+	},
+
+
+	// Builds a structure with info about what the dates/ranges will be for the "prev" view.
+	buildPrevRangeInfo: function(date) {
+		var prevDate = date.clone().startOf(this.currentRangeUnit).subtract(this.dateIncrement);
+
+		return this.buildRangeInfo(prevDate, -1);
+	},
+
+
+	// Builds a structure with info about what the dates/ranges will be for the "next" view.
+	buildNextRangeInfo: function(date) {
+		var nextDate = date.clone().startOf(this.currentRangeUnit).add(this.dateIncrement);
+
+		return this.buildRangeInfo(nextDate, 1);
+	},
+
+
+	// Builds a structure holding dates/ranges for rendering around the given date.
+	// Optional direction param indicates whether the date is being incremented/decremented
+	// from its previous value. decremented = -1, incremented = 1 (default).
+	buildRangeInfo: function(date, direction) {
+		var validRange = this.buildValidRange();
+		var isDateValid = isDateWithinRange(date, validRange);
+		var currentInfo;
+		var renderRange;
+		var activeRange;
+		var isVisibleRangeValid;
+
+		date = constrainDate(date, validRange);
+		currentInfo = this.buildCurrentRangeInfo(date, direction);
+		renderRange = this.buildRenderRange(currentInfo.range, currentInfo.unit);
+		activeRange = constrainRange(renderRange, validRange);
+
+		if (this.opt('disableNonCurrentDates')) {
+			activeRange = constrainRange(activeRange, currentInfo.range);
+		}
+
+		date = constrainDate(date, activeRange);
+		isVisibleRangeValid = Boolean(intersectRanges(activeRange, currentInfo.range));
+
+		return {
+			validRange: validRange,
+			currentRange: currentInfo.range,
+			currentRangeUnit: currentInfo.unit,
+			activeRange: activeRange,
+			renderRange: renderRange,
+			isValid: isDateValid && isVisibleRangeValid,
+			date: date,
+			dateIncrement: this.buildDateIncrement(currentInfo.duration)
+				// pass a fallback (might be null) ^
+		};
+	},
+
+
+	// Builds an object with optional start/end properties.
+	// Indicates the minimum/maximum dates to display.
+	buildValidRange: function() {
+		return this.getRangeOption('validRange', this.calendar.getNow()) || {};
+	},
+
+
+	// Builds a structure with info about the "current" range, the range that is
+	// highlighted as being the current month for example.
+	// See buildRangeInfo for a description of `direction`.
+	// Guaranteed to have `range` and `unit` properties. `duration` is optional.
+	buildCurrentRangeInfo: function(date, direction) {
+		var duration = null;
+		var unit = null;
+		var range = null;
+		var dayCount;
+
+		if (this.viewSpec.duration) {
+			duration = this.viewSpec.duration;
+			unit = this.viewSpec.durationUnit;
+			range = this.buildRangeFromDuration(date, direction, duration, unit);
+		}
+		else if ((dayCount = this.opt('dayCount'))) {
+			unit = 'day';
+			range = this.buildRangeFromDayCount(date, direction, dayCount);
+		}
+		else if ((range = this.buildCustomVisibleRange(date))) {
+			unit = computeIntervalUnit(range.start, range.end);
+		}
+		else {
+			unit = 'day';
+			duration = moment.duration({ days: 1 });
+			range = this.buildRangeFromDuration(date, direction, duration, unit);
+		}
+
+		this.normalizeRange(range, unit); // modifies in-place
+
+		return { duration: duration, unit: unit, range: range };
+	},
+
+
+	// If the range has day units or larger, remove times. Otherwise, ensure times.
+	normalizeRange: function(range, unit) {
+
+		if (/^(year|month|week|day)$/.test(unit)) { // whole-days?
+			range.start.stripTime();
+			range.end.stripTime();
+		}
+		else { // needs to have a time?
+			if (!range.start.hasTime()) {
+				range.start.time(0); // give 00:00 time
+			}
+			if (!range.end.hasTime()) {
+				range.end.time(0); // give 00:00 time
+			}
+		}
+	},
+
+
+	// Builds the "current" range when it is specified as an explicit duration.
+	// `unit` is the already-computed computeIntervalUnit value of duration.
+	buildRangeFromDuration: function(date, direction, duration, unit) {
+		var customAlignment = this.opt('dateAlignment');
+		var start = date.clone();
+		var end;
+
+		// if the view displays a single day or smaller
+		if (duration.as('days') <= 1) {
+			if (this.isHiddenDay(start)) {
+				start = this.skipHiddenDays(start, direction);
+				start.startOf('day');
+			}
+		}
+
+		start.startOf(customAlignment || unit);
+		end = start.clone().add(duration);
+
+		return { start: start, end: end };
+	},
+
+
+	// Builds the "current" range when a dayCount is specified.
+	buildRangeFromDayCount: function(date, direction, dayCount) {
+		var customAlignment = this.opt('dateAlignment');
+		var runningCount = 0;
+		var start = date.clone();
+		var end;
+
+		if (customAlignment) {
+			start.startOf(customAlignment);
+		}
+
+		start.startOf('day');
+		start = this.skipHiddenDays(start, direction);
+
+		end = start.clone();
+		do {
+			end.add(1, 'day');
+			if (!this.isHiddenDay(end)) {
+				runningCount++;
+			}
+		} while (runningCount < dayCount);
+
+		return { start: start, end: end };
+	},
+
+
+	// Builds a normalized range object for the "visible" range,
+	// which is a way to define the currentRange and activeRange at the same time.
+	buildCustomVisibleRange: function(date) {
+		var visibleRange = this.getRangeOption('visibleRange', date);
+
+		if (visibleRange && (!visibleRange.start || !visibleRange.end)) {
+			return null;
+		}
+
+		return visibleRange;
+	},
+
+
+	// Computes the range that will represent the element/cells for *rendering*,
+	// but which may have voided days/times.
+	buildRenderRange: function(currentRange) {
+		// cut off days in the currentRange that are hidden
+		return this.trimHiddenDays(currentRange);
+	},
+
+
+	// Compute the duration value that should be added/substracted to the current date
+	// when a prev/next operation happens.
+	buildDateIncrement: function(fallback) {
+		var dateIncrementInput = this.opt('dateIncrement');
+		var customAlignment;
+
+		if (dateIncrementInput) {
+			return moment.duration(dateIncrementInput);
+		}
+		else if ((customAlignment = this.opt('dateAlignment'))) {
+			return moment.duration(1, customAlignment);
+		}
+		else if (fallback) {
+			return fallback;
+		}
+		else {
+			return moment.duration({ days: 1 });
+		}
+	},
+
+
+	// Remove days from the beginning and end of the range that are computed as hidden.
+	trimHiddenDays: function(inputRange) {
+		return {
+			start: this.skipHiddenDays(inputRange.start),
+			end: this.skipHiddenDays(inputRange.end, -1, true) // exclusively move backwards
+		};
+	},
+
+
+	// Compute the number of the give units in the "current" range.
+	// Will return a floating-point number. Won't round.
+	currentRangeAs: function(unit) {
+		var currentRange = this.currentRange;
+		return currentRange.end.diff(currentRange.start, unit, true);
+	},
+
+
+	// arguments after name will be forwarded to a hypothetical function value
+	getRangeOption: function(name) {
+		var val = this.opt(name);
+
+		if (typeof val === 'function') {
+			val = val.apply(
+				null,
+				Array.prototype.slice.call(arguments, 1)
+			);
+		}
+
+		if (val) {
+			return this.calendar.parseRange(val);
+		}
+	},
+
+
+	/* Hidden Days
+	------------------------------------------------------------------------------------------------------------------*/
+
+
+	// Initializes internal variables related to calculating hidden days-of-week
+	initHiddenDays: function() {
+		var hiddenDays = this.opt('hiddenDays') || []; // array of day-of-week indices that are hidden
+		var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)
+		var dayCnt = 0;
+		var i;
+
+		if (this.opt('weekends') === false) {
+			hiddenDays.push(0, 6); // 0=sunday, 6=saturday
+		}
+
+		for (i = 0; i < 7; i++) {
+			if (
+				!(isHiddenDayHash[i] = $.inArray(i, hiddenDays) !== -1)
+			) {
+				dayCnt++;
+			}
+		}
+
+		if (!dayCnt) {
+			throw 'invalid hiddenDays'; // all days were hidden? bad.
+		}
+
+		this.isHiddenDayHash = isHiddenDayHash;
+	},
+
+
+	// Is the current day hidden?
+	// `day` is a day-of-week index (0-6), or a Moment
+	isHiddenDay: function(day) {
+		if (moment.isMoment(day)) {
+			day = day.day();
+		}
+		return this.isHiddenDayHash[day];
+	},
+
+
+	// Incrementing the current day until it is no longer a hidden day, returning a copy.
+	// DOES NOT CONSIDER validRange!
+	// If the initial value of `date` is not a hidden day, don't do anything.
+	// Pass `isExclusive` as `true` if you are dealing with an end date.
+	// `inc` defaults to `1` (increment one day forward each time)
+	skipHiddenDays: function(date, inc, isExclusive) {
+		var out = date.clone();
+		inc = inc || 1;
+		while (
+			this.isHiddenDayHash[(out.day() + (isExclusive ? inc : 0) + 7) % 7]
+		) {
+			out.add(inc, 'days');
+		}
+		return out;
+	}
+
+});

+ 1 - 333
src/common/View.js

@@ -9,6 +9,7 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	title: null, // the text that will be displayed in the header's title
 
 	calendar: null, // owner Calendar object
+	viewSpec: null,
 	options: null, // hash containing all options. already merged with view-specific-options
 	el: null, // the view's containing element. set by Calendar
 
@@ -21,32 +22,6 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	isEventsRendered: false,
 	eventRenderQueue: null,
 
-	viewSpec: null,
-	currentDate: null,
-
-	// range the view is formally responsible for (moments)
-	// may be different from start/end. for example, a month view might have 1st-31st, excluding padded dates
-	currentRange: null,
-	currentRangeUnit: null, // name of largest unit being displayed, like "month" or "week"
-
-	dateIncrement: null,
-
-	// date range with a rendered skeleton
-	// includes not-active days that need some sort of DOM
-	renderRange: null,
-
-	// active dates that display events and accept drag-nd-drop
-	activeRange: null,
-
-	// date constraints. defines the "valid range"
-	// TODO: enforce this in prev/next/gotoDate
-	validRange: null,
-
-	start: null, // DEPRECATED: use activeRange instead
-	end: null,   // "
-	intervalStart: null, // DEPRECATED: use currentRange instead
-	intervalEnd: null,    // "
-
 	isRTL: false,
 	isSelected: false, // boolean whether a range of time is user-selected or not
 	selectedEvent: null,
@@ -145,259 +120,6 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	},
 
 
-	/* Date Computation
-	------------------------------------------------------------------------------------------------------------------*/
-
-
-	// Updates all internal dates for displaying the given unzoned range.
-	// Will return a boolean about whether there was some sort of change.
-	setRangeFromDate: function(date) {
-
-		var ranges = this.buildRangeInfo(date);
-
-		this.validRange = ranges.validRange;
-
-		if (!this.activeRange || !isRangesEqual(this.activeRange, ranges.activeRange)) {
-			// some sort of change
-
-			this.currentRange = ranges.currentRange;
-			this.currentRangeUnit = ranges.currentRangeUnit;
-			this.renderRange = ranges.renderRange;
-			this.activeRange = ranges.activeRange;
-			this.dateIncrement = ranges.dateIncrement;
-			this.currentDate = ranges.date;
-
-			// DEPRECATED, but we need to keep it updated
-			// TODO: run automated tests with this commented out
-			this.start = ranges.activeRange.start;
-			this.end = ranges.activeRange.end;
-			this.intervalStart = ranges.currentRange.start;
-			this.intervalEnd = ranges.currentRange.end;
-
-			this.updateTitle();
-			this.calendar.updateToolbarButtons();
-
-			return true;
-		}
-
-		return false;
-	},
-
-
-	buildRangeInfo: function(date, direction) {
-		var validRange = this.buildValidRange();
-		var isDateValid = isDateWithinRange(date, validRange);
-		var currentInfo;
-		var renderRange;
-		var activeRange;
-		var isVisibleRangeValid;
-
-		date = constrainDate(date, validRange);
-		currentInfo = this.buildCurrentRangeInfo(date, direction);
-		renderRange = this.buildRenderRange(currentInfo.range, currentInfo.unit);
-		activeRange = constrainRange(renderRange, validRange);
-
-		if (this.opt('disableNonCurrentDates')) {
-			activeRange = constrainRange(activeRange, currentInfo.range);
-		}
-
-		date = constrainDate(date, activeRange);
-		isVisibleRangeValid = Boolean(intersectRanges(activeRange, currentInfo.range));
-
-		return {
-			validRange: validRange,
-			currentRange: currentInfo.range,
-			currentRangeUnit: currentInfo.unit,
-			activeRange: activeRange,
-			renderRange: renderRange,
-			isValid: isDateValid && isVisibleRangeValid,
-			date: date,
-			dateIncrement: this.buildDateIncrement(currentInfo.duration)
-		};
-	},
-
-
-	buildValidRange: function() {
-		return this.getRangeOption('validRange', this.calendar.getNow()) || {};
-	},
-
-
-	buildCurrentRangeInfo: function(date, direction) {
-		var duration = null;
-		var unit = null;
-		var range = null;
-		var dayCount;
-
-		if (this.viewSpec.duration) {
-			duration = this.viewSpec.duration;
-			unit = this.viewSpec.durationUnit;
-			range = this.buildRangeFromDuration(date, direction, duration, unit);
-		}
-		else if ((dayCount = this.opt('dayCount'))) {
-			unit = 'day';
-			range = this.buildRangeFromDayCount(date, direction, dayCount);
-		}
-		else if ((range = this.buildCustomVisibleRange(date))) {
-			unit = computeIntervalUnit(range.start, range.end);
-		}
-		else {
-			unit = 'day';
-			duration = moment.duration({ days: 1 });
-			range = this.buildRangeFromDuration(date, direction, duration, unit);
-		}
-
-		range = this.filterCurrentRange(range, unit);
-
-		return { duration: duration, unit: unit, range: range };
-	},
-
-
-	filterCurrentRange: function(currentRange, unit) {
-
-		// normalize the range's time-ambiguity
-		if (/^(year|month|week|day)$/.test(unit)) { // whole-days?
-			currentRange.start.stripTime();
-			currentRange.end.stripTime();
-		}
-		else { // needs to have a time?
-			if (!currentRange.start.hasTime()) {
-				currentRange.start.time(0); // give 00:00 time
-			}
-			if (!currentRange.end.hasTime()) {
-				currentRange.end.time(0); // give 00:00 time
-			}
-		}
-
-		return currentRange;
-	},
-
-
-	buildRangeFromDuration: function(date, direction, duration, unit) {
-		var customAlignment = this.opt('dateAlignment');
-		var start = date.clone();
-		var end;
-
-		// if the view displays a single day or smaller
-		if (duration.as('days') <= 1) {
-			if (this.isHiddenDay(start)) {
-				start = this.skipHiddenDays(start, direction);
-				start.startOf('day');
-			}
-		}
-
-		start.startOf(customAlignment || unit);
-		end = start.clone().add(duration);
-
-		return { start: start, end: end };
-	},
-
-
-	buildRangeFromDayCount: function(date, direction, dayCount) {
-		var customAlignment = this.opt('dateAlignment');
-		var runningCount = 0;
-		var start = date.clone();
-		var end;
-
-		if (customAlignment) {
-			start.startOf(customAlignment);
-		}
-
-		start.startOf('day');
-		start = this.skipHiddenDays(start, direction);
-
-		end = start.clone();
-		do {
-			end.add(1, 'day');
-			if (!this.isHiddenDay(end)) {
-				runningCount++;
-			}
-		} while (runningCount < dayCount);
-
-		return { start: start, end: end };
-	},
-
-
-	buildCustomVisibleRange: function(date) {
-		var visibleRange = this.getRangeOption('visibleRange', date);
-
-		if (visibleRange && (!visibleRange.start || !visibleRange.end)) {
-			return null;
-		}
-
-		return visibleRange;
-	},
-
-
-	// Computes the date range that will be rendered.
-	buildRenderRange: function(currentRange) {
-		return this.trimHiddenDays(currentRange);
-	},
-
-
-	buildDateIncrement: function(fallback) {
-		var dateIncrementInput = this.opt('dateIncrement');
-		var customAlignment;
-
-		if (dateIncrementInput) {
-			return moment.duration(dateIncrementInput);
-		}
-		else if ((customAlignment = this.opt('dateAlignment'))) {
-			return moment.duration(1, customAlignment);
-		}
-		else if (fallback) {
-			return fallback;
-		}
-		else {
-			return moment.duration(1, 'day');
-		}
-	},
-
-
-	buildPrevRangeInfo: function(date) {
-		var prevDate = date.clone().startOf(this.currentRangeUnit).subtract(this.dateIncrement);
-
-		return this.buildRangeInfo(prevDate, -1);
-	},
-
-
-	buildNextRangeInfo: function(date) {
-		var nextDate = date.clone().startOf(this.currentRangeUnit).add(this.dateIncrement);
-
-		return this.buildRangeInfo(nextDate, 1);
-	},
-
-
-	trimHiddenDays: function(inputRange) {
-		return {
-			start: this.skipHiddenDays(inputRange.start),
-			end: this.skipHiddenDays(inputRange.end, -1, true) // exclusively move backwards
-		};
-	},
-
-
-	currentRangeAs: function(unit) {
-		var currentRange = this.currentRange;
-		return currentRange.end.diff(currentRange.start, unit, true);
-	},
-
-
-	// arguments after name will be forwarded to a hypothetical function value
-	getRangeOption: function(name) {
-		var val = this.opt(name);
-
-		if (typeof val === 'function') {
-			val = val.apply(
-				null,
-				Array.prototype.slice.call(arguments, 1)
-			);
-		}
-
-		if (val) {
-			return this.calendar.parseRange(val);
-		}
-	},
-
-
 	/* Title and Date Formatting
 	------------------------------------------------------------------------------------------------------------------*/
 
@@ -1605,60 +1327,6 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	------------------------------------------------------------------------------------------------------------------*/
 
 
-	// Initializes internal variables related to calculating hidden days-of-week
-	initHiddenDays: function() {
-		var hiddenDays = this.opt('hiddenDays') || []; // array of day-of-week indices that are hidden
-		var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)
-		var dayCnt = 0;
-		var i;
-
-		if (this.opt('weekends') === false) {
-			hiddenDays.push(0, 6); // 0=sunday, 6=saturday
-		}
-
-		for (i = 0; i < 7; i++) {
-			if (
-				!(isHiddenDayHash[i] = $.inArray(i, hiddenDays) !== -1)
-			) {
-				dayCnt++;
-			}
-		}
-
-		if (!dayCnt) {
-			throw 'invalid hiddenDays'; // all days were hidden? bad.
-		}
-
-		this.isHiddenDayHash = isHiddenDayHash;
-	},
-
-
-	// Is the current day hidden?
-	// `day` is a day-of-week index (0-6), or a Moment
-	isHiddenDay: function(day) {
-		if (moment.isMoment(day)) {
-			day = day.day();
-		}
-		return this.isHiddenDayHash[day];
-	},
-
-
-	// Incrementing the current day until it is no longer a hidden day, returning a copy.
-	// DOES NOT CONSIDER validRange!
-	// If the initial value of `date` is not a hidden day, don't do anything.
-	// Pass `isExclusive` as `true` if you are dealing with an end date.
-	// `inc` defaults to `1` (increment one day forward each time)
-	skipHiddenDays: function(date, inc, isExclusive) {
-		var out = date.clone();
-		inc = inc || 1;
-		while (
-			this.isHiddenDayHash[(out.day() + (isExclusive ? inc : 0) + 7) % 7]
-		) {
-			out.add(inc, 'days');
-		}
-		return out;
-	},
-
-
 	// Returns the date range of the full days the given range visually appears to occupy.
 	// Returns a new range object.
 	computeDayRange: function(range) {