mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-08-12 12:00:40 +08:00
large code refactor. new HTML/CSS skeleton, no more JQUI dependency, among other things
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
|
||||
/* An abstract class comprised of a "grid" of cells that each represent a specific datetime
|
||||
----------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Grid(view) {
|
||||
RowRenderer.call(this, view); // call the super-constructor
|
||||
this.coordMap = new GridCoordMap(this);
|
||||
}
|
||||
|
||||
|
||||
Grid.prototype = createObject(RowRenderer.prototype); // declare the super-class
|
||||
$.extend(Grid.prototype, {
|
||||
|
||||
el: null, // the containing element
|
||||
coordMap: null, // a GridCoordMap that converts pixel values to datetimes
|
||||
cellDuration: null, // a cell's duration. subclasses must assign this ASAP
|
||||
|
||||
|
||||
// Renders the grid into the `el` element.
|
||||
// Subclasses should override and call this super-method when done.
|
||||
render: function() {
|
||||
this.bindHandlers();
|
||||
},
|
||||
|
||||
|
||||
/* Coordinates & Cells
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Populates the given empty arrays with the y and x coordinates of the cells
|
||||
buildCoords: function(rows, cols) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
// Given a cell object, returns the date for that cell
|
||||
getCellDate: function(cell) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
// Given a cell object, returns the element that represents the cell's whole-day
|
||||
getCellDayEl: function(cell) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
// Converts a range with an inclusive `start` and an exclusive `end` into an array of segment objects
|
||||
rangeToSegs: function(start, end) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
/* Handlers
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Attach handlers to `this.el`, using bubbling to listen to all ancestors.
|
||||
// We don't need to undo any of this in a "destroy" method, because the view will simply remove `this.el` from the
|
||||
// DOM and jQuery will be smart enough to garbage collect the handlers.
|
||||
bindHandlers: function() {
|
||||
var _this = this;
|
||||
|
||||
this.el.on('mousedown', function(ev) {
|
||||
if (!$(ev.target).is('.fc-event-container *')) { // not an event element
|
||||
_this.dayMousedown(ev);
|
||||
}
|
||||
});
|
||||
|
||||
this.bindSegHandlers(); // attach event-element-related handlers. in Grid.events.js
|
||||
},
|
||||
|
||||
|
||||
// Process a mousedown on an element that represents a day. For day clicking and selecting.
|
||||
dayMousedown: function(ev) {
|
||||
var _this = this;
|
||||
var view = this.view;
|
||||
var isSelectable = view.opt('selectable');
|
||||
var dates = null; // the inclusive dates of the selection. will be null if no selection
|
||||
var start; // the inclusive start of the selection
|
||||
var end; // the *exclusive* end of the selection
|
||||
var dayEl;
|
||||
|
||||
// this listener tracks a mousedown on a day element, and a subsequent drag.
|
||||
// if the drag ends on the same day, it is a 'dayClick'.
|
||||
// if 'selectable' is enabled, this listener also detects selections.
|
||||
var dragListener = new DragListener(this.coordMap, {
|
||||
//distance: 5, // needs more work if we want dayClick to fire correctly
|
||||
dragStart: function() {
|
||||
view.unselect(); // since we could be rendering a new selection, we want to clear any old one
|
||||
},
|
||||
cellOver: function(cell, date) {
|
||||
if (dragListener.origDate) { // click needs to have started on a cell
|
||||
|
||||
dayEl = _this.getCellDayEl(cell);
|
||||
|
||||
dates = [ date, dragListener.origDate ].sort(dateCompare);
|
||||
start = dates[0];
|
||||
end = dates[1].clone().add(_this.cellDuration);
|
||||
|
||||
if (isSelectable) {
|
||||
_this.renderSelection(start, end);
|
||||
}
|
||||
}
|
||||
},
|
||||
cellOut: function(cell, date) {
|
||||
dates = null;
|
||||
_this.destroySelection();
|
||||
},
|
||||
listenStop: function(ev) {
|
||||
if (dates) { // started and ended on a cell?
|
||||
if (dates[0].isSame(dates[1])) {
|
||||
view.trigger('dayClick', dayEl[0], start, ev);
|
||||
}
|
||||
if (isSelectable) {
|
||||
// the selection will already have been rendered. just report it
|
||||
view.reportSelection(start, end, ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dragListener.mousedown(ev); // start listening, which will eventually initiate a dragStart
|
||||
},
|
||||
|
||||
|
||||
/* Event Dragging
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a visual indication of a event being dragged over the given date(s).
|
||||
// `end` can be null, as well as `seg`. See View's documentation on renderDrag for more info.
|
||||
// A returned value of `true` signals that a mock "helper" event has been rendered.
|
||||
renderDrag: function(start, end, seg) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
// Unrenders a visual indication of an event being dragged
|
||||
destroyDrag: function() {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
/* Event Resizing
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a visual indication of an event being resized.
|
||||
// `start` and `end` are the updated dates of the event. `seg` is the original segment object involved in the drag.
|
||||
renderResize: function(start, end, seg) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
// Unrenders a visual indication of an event being resized.
|
||||
destroyResize: function() {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
/* Event Helper
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a mock event over the given date(s).
|
||||
// `end` can be null, in which case the mock event that is rendered will have a null end time.
|
||||
// `sourceSeg` is the internal segment object involved in the drag. If null, something external is dragging.
|
||||
renderRangeHelper: function(start, end, sourceSeg) {
|
||||
var view = this.view;
|
||||
var fakeEvent;
|
||||
|
||||
// compute the end time if forced to do so (this is what EventManager does)
|
||||
if (!end && view.opt('forceEventDuration')) {
|
||||
end = view.calendar.getDefaultEventEnd(!start.hasTime(), start);
|
||||
}
|
||||
|
||||
fakeEvent = sourceSeg ? createObject(sourceSeg.event) : {}; // mask the original event object if possible
|
||||
fakeEvent.start = start;
|
||||
fakeEvent.end = end;
|
||||
fakeEvent.allDay = !(start.hasTime() || (end && end.hasTime())); // freshly compute allDay
|
||||
|
||||
// this extra className will be useful for differentiating real events from mock events in CSS
|
||||
fakeEvent.className = (fakeEvent.className || []).concat('fc-helper');
|
||||
|
||||
// if something external is being dragged in, don't render a resizer
|
||||
if (!sourceSeg) {
|
||||
fakeEvent.editable = false;
|
||||
}
|
||||
|
||||
this.renderHelper(fakeEvent, sourceSeg); // do the actual rendering
|
||||
},
|
||||
|
||||
|
||||
// Renders a mock event
|
||||
renderHelper: function(event, sourceSeg) {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
// Unrenders a mock event
|
||||
destroyHelper: function() {
|
||||
// subclasses must implement
|
||||
},
|
||||
|
||||
|
||||
/* Selection
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a visual indication of a selection. Will highlight by default but can be overridden by subclasses.
|
||||
renderSelection: function(start, end) {
|
||||
this.renderHighlight(start, end);
|
||||
},
|
||||
|
||||
|
||||
// Unrenders any visual indications of a selection. Will unrender a highlight by default.
|
||||
destroySelection: function() {
|
||||
this.destroyHighlight();
|
||||
},
|
||||
|
||||
|
||||
/* Highlight
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Puts visual emphasis on a certain date range
|
||||
renderHighlight: function(start, end) {
|
||||
// subclasses should implement
|
||||
},
|
||||
|
||||
|
||||
// Removes visual emphasis on a date range
|
||||
destroyHighlight: function() {
|
||||
// subclasses should implement
|
||||
},
|
||||
|
||||
|
||||
|
||||
/* Generic rendering utilities for subclasses
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a day-of-week header row
|
||||
headHtml: function() {
|
||||
return '' +
|
||||
'<div class="fc-row ' + this.view.widgetHeaderClass + '">' +
|
||||
'<table>' +
|
||||
'<thead>' +
|
||||
this.rowHtml('head') + // leverages RowRenderer
|
||||
'</thead>' +
|
||||
'</table>' +
|
||||
'</div>';
|
||||
},
|
||||
|
||||
|
||||
// Used by the `headHtml` method, via RowRenderer, for rendering the HTML of a day-of-week header cell
|
||||
headCellHtml: function(row, col, date) {
|
||||
var view = this.view;
|
||||
var calendar = view.calendar;
|
||||
var colFormat = view.opt('columnFormat');
|
||||
|
||||
return '' +
|
||||
'<th class="fc-day-header ' + view.widgetHeaderClass + ' fc-' + dayIDs[date.day()] + '">' +
|
||||
htmlEscape(calendar.formatDate(date, colFormat)) +
|
||||
'</th>';
|
||||
},
|
||||
|
||||
|
||||
// Renders the HTML for a single-day background cell
|
||||
bgCellHtml: function(row, col, date) {
|
||||
var view = this.view;
|
||||
var classes = this.getDayClasses(date);
|
||||
|
||||
classes.unshift('fc-day', view.widgetContentClass);
|
||||
|
||||
return '<td class="' + classes.join(' ') + '" data-date="' + date.format() + '"></td>';
|
||||
},
|
||||
|
||||
|
||||
// Computes HTML classNames for a single-day cell
|
||||
getDayClasses: function(date) {
|
||||
var view = this.view;
|
||||
var today = view.calendar.getNow().stripTime();
|
||||
var classes = [ 'fc-' + dayIDs[date.day()] ];
|
||||
|
||||
if (
|
||||
view.name === 'month' &&
|
||||
date.month() != view.intervalStart.month()
|
||||
) {
|
||||
classes.push('fc-other-month');
|
||||
}
|
||||
|
||||
if (date.isSame(today, 'day')) {
|
||||
classes.push(
|
||||
'fc-today',
|
||||
view.highlightStateClass
|
||||
);
|
||||
}
|
||||
else if (date < today) {
|
||||
classes.push('fc-past');
|
||||
}
|
||||
else {
|
||||
classes.push('fc-future');
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user