Quellcode durchsuchen

break out ChronoComponent

Adam Shaw vor 8 Jahren
Ursprung
Commit
753e540eaa
3 geänderte Dateien mit 375 neuen und 306 gelöschten Zeilen
  1. 1 0
      src.json
  2. 357 0
      src/common/ChronoComponent.js
  3. 17 306
      src/common/View.js

+ 1 - 0
src.json

@@ -27,6 +27,7 @@
     "common/DayGrid.limit.js",
     "common/DayGrid.limit.js",
     "common/TimeGrid.js",
     "common/TimeGrid.js",
     "common/TimeGrid.events.js",
     "common/TimeGrid.events.js",
+    "common/ChronoComponent.js",
     "common/View.js",
     "common/View.js",
     "common/View.date-range.js",
     "common/View.date-range.js",
     "common/Scroller.js",
     "common/Scroller.js",

+ 357 - 0
src/common/ChronoComponent.js

@@ -0,0 +1,357 @@
+
+var ChronoComponent = Model.extend({
+
+	el: null, // the view's containing element. set by Calendar(?)
+
+	// TODO: move below props to Options object
+	//
+	isRTL: false, // why not use this.opt('isRTL') ?
+	nextDayThreshold: null,
+	//
+	// classNames styled by jqui themes
+	widgetHeaderClass: null,
+	widgetContentClass: null,
+	highlightStateClass: null,
+
+
+	// Options
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	opt: function(name) {
+		// subclasses must implement
+	},
+
+
+	processOptions: function() {
+		this.nextDayThreshold = moment.duration(this.opt('nextDayThreshold'));
+		this.isRTL = this.opt('isRTL');
+		this.initThemingProps();
+	},
+
+
+	// Initializes internal variables related to theming
+	initThemingProps: function() {
+		var tm = this.opt('theme') ? 'ui' : 'fc';
+
+		this.widgetHeaderClass = tm + '-widget-header';
+		this.widgetContentClass = tm + '-widget-content';
+		this.highlightStateClass = tm + '-state-highlight';
+	},
+
+
+	// Element
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	// Sets the container element that the view should render inside of, does global DOM-related initializations,
+	// and renders all the non-date-related content inside.
+	setElement: function(el) {
+		this.el = el;
+		this.renderSkeleton();
+	},
+
+
+	// Removes the view's container element from the DOM, clearing any content beforehand.
+	// Undoes any other DOM-related attachments.
+	removeElement: function() {
+		this.unsetDate();
+		this.unrenderSkeleton();
+
+		this.el.remove();
+		// NOTE: don't null-out this.el in case the View was destroyed within an API callback.
+		// We don't null-out the View's other jQuery element references upon destroy,
+		//  so we shouldn't kill this.el either.
+	},
+
+
+	// Skeleton
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	// Renders the basic structure of the view before any content is rendered
+	renderSkeleton: function() {
+		// subclasses should implement
+	},
+
+
+	// Unrenders the basic structure of the view
+	unrenderSkeleton: function() {
+		// subclasses should implement
+	},
+
+
+	// Date Low-level Rendering
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	// date-cell content only
+	renderDates: function() {
+		// subclasses should implement
+	},
+
+
+	// date-cell content only
+	unrenderDates: function() {
+		// subclasses should override
+	},
+
+
+	// Now-Indicator
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	// Renders a current time indicator at the given datetime
+	renderNowIndicator: function(date) {
+		// subclasses should implement
+	},
+
+
+	// Undoes the rendering actions from renderNowIndicator
+	unrenderNowIndicator: function() {
+		// subclasses should implement
+	},
+
+
+	// Business Hours
+	// ---------------------------------------------------------------------------------------------------------------*/
+
+
+	// Renders business-hours onto the view. Assumes updateSize has already been called.
+	renderBusinessHours: function() {
+		// subclasses should implement
+	},
+
+
+	// Unrenders previously-rendered business-hours
+	unrenderBusinessHours: function() {
+		// subclasses should implement
+	},
+
+
+	// Event Low-level Rendering
+	// -----------------------------------------------------------------------------------------------------------------
+
+
+	// Renders the events onto the view.
+	renderEvents: function(events) {
+		// subclasses should implement
+	},
+
+
+	// Removes event elements from the view.
+	unrenderEvents: function() {
+		// subclasses should implement
+	},
+
+
+	// Drag-n-Drop Rendering (for both events and external elements)
+	// ---------------------------------------------------------------------------------------------------------------*/
+
+
+	// Renders a visual indication of a event or external-element drag over the given drop zone.
+	// If an external-element, seg will be `null`.
+	// Must return elements used for any mock events.
+	renderDrag: function(dropLocation, seg) {
+		// subclasses must implement
+	},
+
+
+	// Unrenders a visual indication of an event or external-element being dragged.
+	unrenderDrag: function() {
+		// subclasses must implement
+	},
+
+
+	// Selection
+	// ---------------------------------------------------------------------------------------------------------------*/
+
+
+	// Renders a visual indication of the selection
+	renderSelection: function(span) {
+		// subclasses should implement
+	},
+
+
+	// Unrenders a visual indication of selection
+	unrenderSelection: function() {
+		// subclasses should implement
+	},
+
+
+	/* Event Drag-n-Drop
+	------------------------------------------------------------------------------------------------------------------*/
+
+
+	// Computes if the given event is allowed to be dragged by the user
+	isEventDraggable: function(event) {
+		return this.isEventStartEditable(event);
+	},
+
+
+	isEventStartEditable: function(event) {
+		return firstDefined(
+			event.startEditable,
+			(event.source || {}).startEditable,
+			this.opt('eventStartEditable'),
+			this.isEventGenerallyEditable(event)
+		);
+	},
+
+
+	isEventGenerallyEditable: function(event) {
+		return firstDefined(
+			event.editable,
+			(event.source || {}).editable,
+			this.opt('editable')
+		);
+	},
+
+
+	/* Event Resizing
+	------------------------------------------------------------------------------------------------------------------*/
+
+
+	// Computes if the given event is allowed to be resized from its starting edge
+	isEventResizableFromStart: function(event) {
+		return this.opt('eventResizableFromStart') && this.isEventResizable(event);
+	},
+
+
+	// Computes if the given event is allowed to be resized from its ending edge
+	isEventResizableFromEnd: function(event) {
+		return this.isEventResizable(event);
+	},
+
+
+	// Computes if the given event is allowed to be resized by the user at all
+	isEventResizable: function(event) {
+		var source = event.source || {};
+
+		return firstDefined(
+			event.durationEditable,
+			source.durationEditable,
+			this.opt('eventDurationEditable'),
+			event.editable,
+			source.editable,
+			this.opt('editable')
+		);
+	},
+
+
+	// Navigation
+	// ----------------------------------------------------------------------------------------------------------------*/
+
+
+	// Generates HTML for an anchor to another view into the calendar.
+	// Will either generate an <a> tag or a non-clickable <span> tag, depending on enabled settings.
+	// `gotoOptions` can either be a moment input, or an object with the form:
+	// { date, type, forceOff }
+	// `type` is a view-type like "day" or "week". default value is "day".
+	// `attrs` and `innerHtml` are use to generate the rest of the HTML tag.
+	buildGotoAnchorHtml: function(gotoOptions, attrs, innerHtml) {
+		var date, type, forceOff;
+		var finalOptions;
+
+		if ($.isPlainObject(gotoOptions)) {
+			date = gotoOptions.date;
+			type = gotoOptions.type;
+			forceOff = gotoOptions.forceOff;
+		}
+		else {
+			date = gotoOptions; // a single moment input
+		}
+		date = FC.moment(date); // if a string, parse it
+
+		finalOptions = { // for serialization into the link
+			date: date.format('YYYY-MM-DD'),
+			type: type || 'day'
+		};
+
+		if (typeof attrs === 'string') {
+			innerHtml = attrs;
+			attrs = null;
+		}
+
+		attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space
+		innerHtml = innerHtml || '';
+
+		if (!forceOff && this.opt('navLinks')) {
+			return '<a' + attrs +
+				' data-goto="' + htmlEscape(JSON.stringify(finalOptions)) + '">' +
+				innerHtml +
+				'</a>';
+		}
+		else {
+			return '<span' + attrs + '>' +
+				innerHtml +
+				'</span>';
+		}
+	},
+
+
+	// Date Formatting Utils
+	// ---------------------------------------------------------------------------------------------------------------*/
+
+
+	// Utility for formatting a range. Accepts a range object, formatting string, and optional separator.
+	// Displays all-day ranges naturally, with an inclusive end. Takes the current isRTL into account.
+	// The timezones of the dates within `range` will be respected.
+	formatRange: function(range, formatStr, separator) {
+		var end = range.end;
+
+		if (!end.hasTime()) { // all-day?
+			end = end.clone().subtract(1); // convert to inclusive. last ms of previous day
+		}
+
+		return formatRange(range.start, end, formatStr, separator, this.opt('isRTL'));
+	},
+
+
+	getAllDayHtml: function() {
+		return this.opt('allDayHtml') || htmlEscape(this.opt('allDayText'));
+	},
+
+
+	// Date Utils
+	// ---------------------------------------------------------------------------------------------------------------*/
+
+
+	// Returns the date range of the full days the given range visually appears to occupy.
+	// Returns a new range object.
+	computeDayRange: function(range) {
+		var startDay = range.start.clone().stripTime(); // the beginning of the day the range starts
+		var end = range.end;
+		var endDay = null;
+		var endTimeMS;
+
+		if (end) {
+			endDay = end.clone().stripTime(); // the beginning of the day the range exclusively ends
+			endTimeMS = +end.time(); // # of milliseconds into `endDay`
+
+			// If the end time is actually inclusively part of the next day and is equal to or
+			// beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
+			// Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
+			if (endTimeMS && endTimeMS >= this.nextDayThreshold) {
+				endDay.add(1, 'days');
+			}
+		}
+
+		// If no end was specified, or if it is within `startDay` but not past nextDayThreshold,
+		// assign the default duration of one day.
+		if (!end || endDay <= startDay) {
+			endDay = startDay.clone().add(1, 'days');
+		}
+
+		return { start: startDay, end: endDay };
+	},
+
+
+	// Does the given event visually appear to occupy more than one day?
+	isMultiDayEvent: function(event) {
+		var range = this.computeDayRange(event); // event is range-ish
+
+		return range.end.diff(range.start, 'days') > 1;
+	}
+
+});

+ 17 - 306
src/common/View.js

@@ -2,7 +2,7 @@
 /* An abstract class from which other views inherit from
 /* An abstract class from which other views inherit from
 ----------------------------------------------------------------------------------------------------------------------*/
 ----------------------------------------------------------------------------------------------------------------------*/
 
 
-var View = FC.View = Model.extend({
+var View = FC.View = ChronoComponent.extend({
 
 
 	type: null, // subclass' view name (string)
 	type: null, // subclass' view name (string)
 	name: null, // deprecated. use `type` instead
 	name: null, // deprecated. use `type` instead
@@ -11,7 +11,6 @@ var View = FC.View = Model.extend({
 	calendar: null, // owner Calendar object
 	calendar: null, // owner Calendar object
 	viewSpec: null,
 	viewSpec: null,
 	options: null, // hash containing all options. already merged with view-specific-options
 	options: null, // hash containing all options. already merged with view-specific-options
-	el: null, // the view's containing element. set by Calendar
 
 
 	renderQueue: null,
 	renderQueue: null,
 	batchRenderDepth: 0,
 	batchRenderDepth: 0,
@@ -21,19 +20,12 @@ var View = FC.View = Model.extend({
 
 
 	queuedScroll: null,
 	queuedScroll: null,
 
 
-	isRTL: false,
 	isSelected: false, // boolean whether a range of time is user-selected or not
 	isSelected: false, // boolean whether a range of time is user-selected or not
 	selectedEvent: null,
 	selectedEvent: null,
 
 
 	eventOrderSpecs: null, // criteria for ordering events when they have same date/time
 	eventOrderSpecs: null, // criteria for ordering events when they have same date/time
 
 
-	// classNames styled by jqui themes
-	widgetHeaderClass: null,
-	widgetContentClass: null,
-	highlightStateClass: null,
-
 	// for date utils, computed from options
 	// for date utils, computed from options
-	nextDayThreshold: null,
 	isHiddenDayHash: null,
 	isHiddenDayHash: null,
 
 
 	// now indicator
 	// now indicator
@@ -45,7 +37,7 @@ var View = FC.View = Model.extend({
 
 
 
 
 	constructor: function(calendar, viewSpec) {
 	constructor: function(calendar, viewSpec) {
-		Model.prototype.constructor.call(this);
+		ChronoComponent.call(this);
 
 
 		this.calendar = calendar;
 		this.calendar = calendar;
 		this.viewSpec = viewSpec;
 		this.viewSpec = viewSpec;
@@ -57,12 +49,7 @@ var View = FC.View = Model.extend({
 		// .name is deprecated
 		// .name is deprecated
 		this.name = this.type;
 		this.name = this.type;
 
 
-		this.nextDayThreshold = moment.duration(this.opt('nextDayThreshold'));
-		this.initThemingProps();
-		this.initHiddenDays();
-		this.isRTL = this.opt('isRTL');
-
-		this.eventOrderSpecs = parseFieldSpecs(this.opt('eventOrder'));
+		this.processOptions();
 
 
 		this.renderQueue = this.buildRenderQueue();
 		this.renderQueue = this.buildRenderQueue();
 		this.initAutoBatchRender();
 		this.initAutoBatchRender();
@@ -71,6 +58,14 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
+	processOptions: function() {
+		ChronoComponent.prototype.processOptions.apply(this, arguments);
+
+		this.initHiddenDays();
+		this.eventOrderSpecs = parseFieldSpecs(this.opt('eventOrder'));
+	},
+
+
 	buildRenderQueue: function() {
 	buildRenderQueue: function() {
 		var _this = this;
 		var _this = this;
 		var renderQueue = new RenderQueue({
 		var renderQueue = new RenderQueue({
@@ -197,115 +192,23 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Utility for formatting a range. Accepts a range object, formatting string, and optional separator.
-	// Displays all-day ranges naturally, with an inclusive end. Takes the current isRTL into account.
-	// The timezones of the dates within `range` will be respected.
-	formatRange: function(range, formatStr, separator) {
-		var end = range.end;
-
-		if (!end.hasTime()) { // all-day?
-			end = end.clone().subtract(1); // convert to inclusive. last ms of previous day
-		}
-
-		return formatRange(range.start, end, formatStr, separator, this.opt('isRTL'));
-	},
-
-
-	getAllDayHtml: function() {
-		return this.opt('allDayHtml') || htmlEscape(this.opt('allDayText'));
-	},
-
-
-	/* Navigation
-	------------------------------------------------------------------------------------------------------------------*/
-
-
-	// Generates HTML for an anchor to another view into the calendar.
-	// Will either generate an <a> tag or a non-clickable <span> tag, depending on enabled settings.
-	// `gotoOptions` can either be a moment input, or an object with the form:
-	// { date, type, forceOff }
-	// `type` is a view-type like "day" or "week". default value is "day".
-	// `attrs` and `innerHtml` are use to generate the rest of the HTML tag.
-	buildGotoAnchorHtml: function(gotoOptions, attrs, innerHtml) {
-		var date, type, forceOff;
-		var finalOptions;
-
-		if ($.isPlainObject(gotoOptions)) {
-			date = gotoOptions.date;
-			type = gotoOptions.type;
-			forceOff = gotoOptions.forceOff;
-		}
-		else {
-			date = gotoOptions; // a single moment input
-		}
-		date = FC.moment(date); // if a string, parse it
-
-		finalOptions = { // for serialization into the link
-			date: date.format('YYYY-MM-DD'),
-			type: type || 'day'
-		};
-
-		if (typeof attrs === 'string') {
-			innerHtml = attrs;
-			attrs = null;
-		}
-
-		attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space
-		innerHtml = innerHtml || '';
-
-		if (!forceOff && this.opt('navLinks')) {
-			return '<a' + attrs +
-				' data-goto="' + htmlEscape(JSON.stringify(finalOptions)) + '">' +
-				innerHtml +
-				'</a>';
-		}
-		else {
-			return '<span' + attrs + '>' +
-				innerHtml +
-				'</span>';
-		}
-	},
-
-
-	// Rendering Non-date-related Content
+	// Element
 	// -----------------------------------------------------------------------------------------------------------------
 	// -----------------------------------------------------------------------------------------------------------------
 
 
 
 
-	// Sets the container element that the view should render inside of, does global DOM-related initializations,
-	// and renders all the non-date-related content inside.
 	setElement: function(el) {
 	setElement: function(el) {
-		this.el = el;
+		ChronoComponent.prototype.setElement.apply(this, arguments);
+
 		this.bindGlobalHandlers();
 		this.bindGlobalHandlers();
 		this.bindBaseRenderHandlers();
 		this.bindBaseRenderHandlers();
-		this.renderSkeleton();
 	},
 	},
 
 
 
 
-	// Removes the view's container element from the DOM, clearing any content beforehand.
-	// Undoes any other DOM-related attachments.
 	removeElement: function() {
 	removeElement: function() {
-		this.unsetDate();
-		this.unrenderSkeleton();
-
 		this.unbindGlobalHandlers();
 		this.unbindGlobalHandlers();
 		this.unbindBaseRenderHandlers();
 		this.unbindBaseRenderHandlers();
 
 
-		this.el.remove();
-		// NOTE: don't null-out this.el in case the View was destroyed within an API callback.
-		// We don't null-out the View's other jQuery element references upon destroy,
-		//  so we shouldn't kill this.el either.
-	},
-
-
-	// Renders the basic structure of the view before any content is rendered
-	renderSkeleton: function() {
-		// subclasses should implement
-	},
-
-
-	// Unrenders the basic structure of the view
-	unrenderSkeleton: function() {
-		// subclasses should implement
+		ChronoComponent.prototype.removeElement.apply(this, arguments);
 	},
 	},
 
 
 
 
@@ -466,22 +369,6 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Date Low-level Rendering
-	// -----------------------------------------------------------------------------------------------------------------
-
-
-	// date-cell content only
-	renderDates: function() {
-		// subclasses should implement
-	},
-
-
-	// date-cell content only
-	unrenderDates: function() {
-		// subclasses should override
-	},
-
-
 	// Determing when the "meat" of the view is rendered (aka the base)
 	// Determing when the "meat" of the view is rendered (aka the base)
 	// -----------------------------------------------------------------------------------------------------------------
 	// -----------------------------------------------------------------------------------------------------------------
 
 
@@ -535,32 +422,6 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Initializes internal variables related to theming
-	initThemingProps: function() {
-		var tm = this.opt('theme') ? 'ui' : 'fc';
-
-		this.widgetHeaderClass = tm + '-widget-header';
-		this.widgetContentClass = tm + '-widget-content';
-		this.highlightStateClass = tm + '-state-highlight';
-	},
-
-
-	/* Business Hours
-	------------------------------------------------------------------------------------------------------------------*/
-
-
-	// Renders business-hours onto the view. Assumes updateSize has already been called.
-	renderBusinessHours: function() {
-		// subclasses should implement
-	},
-
-
-	// Unrenders previously-rendered business-hours
-	unrenderBusinessHours: function() {
-		// subclasses should implement
-	},
-
-
 	/* Now Indicator
 	/* Now Indicator
 	------------------------------------------------------------------------------------------------------------------*/
 	------------------------------------------------------------------------------------------------------------------*/
 
 
@@ -637,20 +498,9 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Renders a current time indicator at the given datetime
-	renderNowIndicator: function(date) {
-		// subclasses should implement
-	},
-
-
-	// Undoes the rendering actions from renderNowIndicator
-	unrenderNowIndicator: function() {
-		// subclasses should implement
-	},
-
-
 	/* Dimensions
 	/* Dimensions
 	------------------------------------------------------------------------------------------------------------------*/
 	------------------------------------------------------------------------------------------------------------------*/
+	// TODO: move some of these to ChronoComponent
 
 
 
 
 	// Refreshes anything dependant upon sizing of the container element of the grid
 	// Refreshes anything dependant upon sizing of the container element of the grid
@@ -831,24 +681,9 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Event Low-level Rendering
-	// -----------------------------------------------------------------------------------------------------------------
-
-
-	// Renders the events onto the view.
-	renderEvents: function(events) {
-		// subclasses should implement
-	},
-
-
-	// Removes event elements from the view.
-	unrenderEvents: function() {
-		// subclasses should implement
-	},
-
-
 	// Event Rendering Utils
 	// Event Rendering Utils
 	// -----------------------------------------------------------------------------------------------------------------
 	// -----------------------------------------------------------------------------------------------------------------
+	// TODO: move this to ChronoComponent
 
 
 
 
 	// Given an event and the default element used for rendering, returns the element that should actually be used.
 	// Given an event and the default element used for rendering, returns the element that should actually be used.
@@ -911,31 +746,6 @@ var View = FC.View = Model.extend({
 	------------------------------------------------------------------------------------------------------------------*/
 	------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
-	// Computes if the given event is allowed to be dragged by the user
-	isEventDraggable: function(event) {
-		return this.isEventStartEditable(event);
-	},
-
-
-	isEventStartEditable: function(event) {
-		return firstDefined(
-			event.startEditable,
-			(event.source || {}).startEditable,
-			this.opt('eventStartEditable'),
-			this.isEventGenerallyEditable(event)
-		);
-	},
-
-
-	isEventGenerallyEditable: function(event) {
-		return firstDefined(
-			event.editable,
-			(event.source || {}).editable,
-			this.opt('editable')
-		);
-	},
-
-
 	// Must be called when an event in the view is dropped onto new location.
 	// Must be called when an event in the view is dropped onto new location.
 	// `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
 	// `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
 	reportSegDrop: function(seg, dropLocation, largeUnit, el, ev) {
 	reportSegDrop: function(seg, dropLocation, largeUnit, el, ev) {
@@ -991,55 +801,10 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	/* Drag-n-Drop Rendering (for both events and external elements)
-	------------------------------------------------------------------------------------------------------------------*/
-
-
-	// Renders a visual indication of a event or external-element drag over the given drop zone.
-	// If an external-element, seg will be `null`.
-	// Must return elements used for any mock events.
-	renderDrag: function(dropLocation, seg) {
-		// subclasses must implement
-	},
-
-
-	// Unrenders a visual indication of an event or external-element being dragged.
-	unrenderDrag: function() {
-		// subclasses must implement
-	},
-
-
 	/* Event Resizing
 	/* Event Resizing
 	------------------------------------------------------------------------------------------------------------------*/
 	------------------------------------------------------------------------------------------------------------------*/
 
 
 
 
-	// Computes if the given event is allowed to be resized from its starting edge
-	isEventResizableFromStart: function(event) {
-		return this.opt('eventResizableFromStart') && this.isEventResizable(event);
-	},
-
-
-	// Computes if the given event is allowed to be resized from its ending edge
-	isEventResizableFromEnd: function(event) {
-		return this.isEventResizable(event);
-	},
-
-
-	// Computes if the given event is allowed to be resized by the user at all
-	isEventResizable: function(event) {
-		var source = event.source || {};
-
-		return firstDefined(
-			event.durationEditable,
-			source.durationEditable,
-			this.opt('eventDurationEditable'),
-			event.editable,
-			source.editable,
-			this.opt('editable')
-		);
-	},
-
-
 	// Must be called when an event in the view has been resized to a new length
 	// Must be called when an event in the view has been resized to a new length
 	reportSegResize: function(seg, resizeLocation, largeUnit, el, ev) {
 	reportSegResize: function(seg, resizeLocation, largeUnit, el, ev) {
 		var calendar = this.calendar;
 		var calendar = this.calendar;
@@ -1073,12 +838,6 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Renders a visual indication of the selection
-	renderSelection: function(span) {
-		// subclasses should implement
-	},
-
-
 	// Called when a new selection is made. Updates internal state and triggers handlers.
 	// Called when a new selection is made. Updates internal state and triggers handlers.
 	reportSelection: function(span, ev) {
 	reportSelection: function(span, ev) {
 		this.isSelected = true;
 		this.isSelected = true;
@@ -1112,12 +871,6 @@ var View = FC.View = Model.extend({
 	},
 	},
 
 
 
 
-	// Unrenders a visual indication of selection
-	unrenderSelection: function() {
-		// subclasses should implement
-	},
-
-
 	/* Event Selection
 	/* Event Selection
 	------------------------------------------------------------------------------------------------------------------*/
 	------------------------------------------------------------------------------------------------------------------*/
 
 
@@ -1205,48 +958,6 @@ var View = FC.View = Model.extend({
 			this.calendar.applyTimezone(span.start), // convert to calendar's timezone for external API
 			this.calendar.applyTimezone(span.start), // convert to calendar's timezone for external API
 			ev
 			ev
 		);
 		);
-	},
-
-
-	/* Date Utils
-	------------------------------------------------------------------------------------------------------------------*/
-
-
-	// Returns the date range of the full days the given range visually appears to occupy.
-	// Returns a new range object.
-	computeDayRange: function(range) {
-		var startDay = range.start.clone().stripTime(); // the beginning of the day the range starts
-		var end = range.end;
-		var endDay = null;
-		var endTimeMS;
-
-		if (end) {
-			endDay = end.clone().stripTime(); // the beginning of the day the range exclusively ends
-			endTimeMS = +end.time(); // # of milliseconds into `endDay`
-
-			// If the end time is actually inclusively part of the next day and is equal to or
-			// beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
-			// Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
-			if (endTimeMS && endTimeMS >= this.nextDayThreshold) {
-				endDay.add(1, 'days');
-			}
-		}
-
-		// If no end was specified, or if it is within `startDay` but not past nextDayThreshold,
-		// assign the default duration of one day.
-		if (!end || endDay <= startDay) {
-			endDay = startDay.clone().add(1, 'days');
-		}
-
-		return { start: startDay, end: endDay };
-	},
-
-
-	// Does the given event visually appear to occupy more than one day?
-	isMultiDayEvent: function(event) {
-		var range = this.computeDayRange(event); // event is range-ish
-
-		return range.end.diff(range.start, 'days') > 1;
 	}
 	}
 
 
 });
 });