mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-08-19 12:10:12 +08:00
large code refactor. new HTML/CSS skeleton, no more JQUI dependency, among other things
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
|
||||
/* A component that renders a grid of whole-days that runs horizontally. There can be multiple rows, one per week.
|
||||
----------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function DayGrid(view) {
|
||||
Grid.call(this, view); // call the super-constructor
|
||||
}
|
||||
|
||||
|
||||
DayGrid.prototype = createObject(Grid.prototype); // declare the super-class
|
||||
$.extend(DayGrid.prototype, {
|
||||
|
||||
numbersVisible: false, // should render a row for day/week numbers? manually set by the view
|
||||
cellDuration: moment.duration({ days: 1 }), // required for Grid.event.js. Each cell is always a single day
|
||||
bottomCoordPadding: 0, // hack for extending the hit area for the last row of the coordinate grid
|
||||
|
||||
rowEls: null, // set of fake row elements
|
||||
dayEls: null, // set of whole-day elements comprising the row's background
|
||||
helperEls: null, // set of cell skeleton elements for rendering the mock event "helper"
|
||||
highlightEls: null, // set of cell skeleton elements for rendering the highlight
|
||||
|
||||
|
||||
// Renders the rows and columns into the component's `this.el`, which should already be assigned.
|
||||
// Relies on the view's colCnt and rowCnt. In the future, this component should probably be self-sufficient.
|
||||
render: function() {
|
||||
var view = this.view;
|
||||
var html = '';
|
||||
var row;
|
||||
|
||||
for (row = 0; row < view.rowCnt; row++) {
|
||||
html += this.dayRowHtml(row);
|
||||
}
|
||||
this.el.html(html);
|
||||
|
||||
this.rowEls = this.el.find('.fc-row');
|
||||
this.dayEls = this.el.find('.fc-day');
|
||||
|
||||
// run all the day cells through the dayRender callback
|
||||
this.dayEls.each(function(i, node) {
|
||||
var date = view.cellToDate(Math.floor(i / view.colCnt), i % view.colCnt);
|
||||
view.trigger('dayRender', null, date, $(node));
|
||||
});
|
||||
|
||||
Grid.prototype.render.call(this); // call the super-method
|
||||
},
|
||||
|
||||
|
||||
// Generates the HTML for a single row. `row` is the row number.
|
||||
dayRowHtml: function(row) {
|
||||
var view = this.view;
|
||||
var classes = [ 'fc-row', 'fc-week' ];
|
||||
|
||||
if (view.dayRowThemeClass) { // provides the view a hook to inject a theme className
|
||||
classes.push(view.dayRowThemeClass);
|
||||
}
|
||||
|
||||
return '' +
|
||||
'<div class="' + classes.join(' ') + '">' +
|
||||
'<div class="fc-bg">' +
|
||||
'<table>' +
|
||||
this.rowHtml('day', row) + // leverages RowRenderer. calls dayCellHtml()
|
||||
'</table>' +
|
||||
'</div>' +
|
||||
'<div class="fc-content-skeleton">' +
|
||||
'<table>' +
|
||||
(this.numbersVisible ?
|
||||
'<thead>' +
|
||||
this.rowHtml('number', row) + // leverages RowRenderer. View will define render method
|
||||
'</thead>' :
|
||||
''
|
||||
) +
|
||||
'</table>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
},
|
||||
|
||||
|
||||
// Renders the HTML for a whole-day cell. Will eventually end up in the day-row's background.
|
||||
// We go through a 'day' row type instead of just doing a 'bg' row type so that the View can do custom rendering
|
||||
// specifically for whole-day rows, whereas a 'bg' might also be used for other purposes (TimeGrid bg for example).
|
||||
dayCellHtml: function(row, col, date) {
|
||||
return this.bgCellHtml(row, col, date);
|
||||
},
|
||||
|
||||
|
||||
/* Coordinates & Cells
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Populates the empty `rows` and `cols` arrays with coordinates of the cells. For CoordGrid.
|
||||
buildCoords: function(rows, cols) {
|
||||
var colCnt = this.view.colCnt;
|
||||
var e, n, p;
|
||||
|
||||
this.dayEls.slice(0, colCnt).each(function(i, _e) { // iterate the first row of day elements
|
||||
e = $(_e);
|
||||
n = e.offset().left;
|
||||
if (i) {
|
||||
p[1] = n;
|
||||
}
|
||||
p = [ n ];
|
||||
cols[i] = p;
|
||||
});
|
||||
p[1] = n + e.outerWidth();
|
||||
|
||||
this.rowEls.each(function(i, _e) {
|
||||
e = $(_e);
|
||||
n = e.offset().top;
|
||||
if (i) {
|
||||
p[1] = n;
|
||||
}
|
||||
p = [ n ];
|
||||
rows[i] = p;
|
||||
});
|
||||
p[1] = n + e.outerHeight() + this.bottomCoordPadding; // hack to extend hit area of last row
|
||||
},
|
||||
|
||||
|
||||
// Converts a cell to a date
|
||||
getCellDate: function(cell) {
|
||||
return this.view.cellToDate(cell); // leverages the View's cell system
|
||||
},
|
||||
|
||||
|
||||
// Gets the whole-day element associated with the cell
|
||||
getCellDayEl: function(cell) {
|
||||
return this.dayEls.eq(cell.row * this.view.colCnt + cell.col);
|
||||
},
|
||||
|
||||
|
||||
// Converts a range with an inclusive `start` and an exclusive `end` into an array of segment objects
|
||||
rangeToSegs: function(start, end) {
|
||||
return this.view.rangeToSegments(start, end); // leverages the View's cell system
|
||||
},
|
||||
|
||||
|
||||
/* Event Drag Visualization
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a visual indication of an event hovering 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) {
|
||||
var opacity;
|
||||
|
||||
// always render a highlight underneath
|
||||
this.renderHighlight(
|
||||
start,
|
||||
end || this.view.calendar.getDefaultEventEnd(true, start)
|
||||
);
|
||||
|
||||
// if a segment from the same calendar but another component is being dragged, render a helper event
|
||||
if (seg && !seg.el.closest(this.el).length) {
|
||||
|
||||
this.renderRangeHelper(start, end, seg);
|
||||
|
||||
opacity = this.view.opt('dragOpacity');
|
||||
if (opacity !== undefined) {
|
||||
this.helperEls.css('opacity', opacity);
|
||||
}
|
||||
|
||||
return true; // a helper has been rendered
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Unrenders any visual indication of a hovering event
|
||||
destroyDrag: function() {
|
||||
this.destroyHighlight();
|
||||
this.destroyHelper();
|
||||
},
|
||||
|
||||
|
||||
/* Event Resize Visualization
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a visual indication of an event being resized
|
||||
renderResize: function(start, end, seg) {
|
||||
this.renderHighlight(start, end);
|
||||
this.renderRangeHelper(start, end, seg);
|
||||
},
|
||||
|
||||
|
||||
// Unrenders a visual indication of an event being resized
|
||||
destroyResize: function() {
|
||||
this.destroyHighlight();
|
||||
this.destroyHelper();
|
||||
},
|
||||
|
||||
|
||||
/* Event Helper
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders a mock "helper" event. `sourceSeg` is the associated internal segment object. It can be null.
|
||||
renderHelper: function(event, sourceSeg) {
|
||||
var helperNodes = [];
|
||||
var tbodyEls = this.renderEventRows([ event ]).tbodyEls; // render events as usual, receiving tbodys to inject
|
||||
|
||||
// inject each new event skeleton into each associated row
|
||||
this.rowEls.each(function(row, rowNode) {
|
||||
var rowEl = $(rowNode); // the .fc-row
|
||||
var skeletonEl = $('<div class="fc-helper-skeleton"><table/></div>'); // will be absolutely positioned
|
||||
var skeletonTop;
|
||||
|
||||
// If there is an original segment, match the top position. Otherwise, put it at the row's top level
|
||||
if (sourceSeg && sourceSeg.row === row) {
|
||||
skeletonTop = sourceSeg.el.position().top;
|
||||
}
|
||||
else {
|
||||
skeletonTop = rowEl.find('.fc-content-skeleton tbody').position().top;
|
||||
}
|
||||
|
||||
skeletonEl.css('top', skeletonTop)
|
||||
.find('table')
|
||||
.append(tbodyEls[row]);
|
||||
|
||||
rowEl.append(skeletonEl);
|
||||
helperNodes.push(skeletonEl[0]);
|
||||
});
|
||||
|
||||
this.helperEls = $(helperNodes); // array -> jQuery set
|
||||
},
|
||||
|
||||
|
||||
// Unrenders any visual indication of a mock helper event
|
||||
destroyHelper: function() {
|
||||
if (this.helperEls) {
|
||||
this.helperEls.remove();
|
||||
this.helperEls = null;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/* Highlighting
|
||||
------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Renders an emphasis on the given date range. `start` is an inclusive, `end` is exclusive.
|
||||
renderHighlight: function(start, end) {
|
||||
var segs = this.rangeToSegs(start, end);
|
||||
var highlightNodes = [];
|
||||
var i, seg;
|
||||
var el;
|
||||
|
||||
// build an event skeleton for each row that needs it
|
||||
for (i = 0; i < segs.length; i++) {
|
||||
seg = segs[i];
|
||||
el = $(
|
||||
this.highlightSkeletonHtml(seg.leftCol, seg.rightCol + 1) // make end exclusive
|
||||
);
|
||||
el.appendTo(this.rowEls[seg.row]);
|
||||
highlightNodes.push(el[0]);
|
||||
}
|
||||
|
||||
this.highlightEls = $(highlightNodes); // array -> jQuery set
|
||||
},
|
||||
|
||||
|
||||
// Unrenders any visual emphasis on a date range
|
||||
destroyHighlight: function() {
|
||||
if (this.highlightEls) {
|
||||
this.highlightEls.remove();
|
||||
this.highlightEls = null;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Generates the HTML used to build a single-row "highlight skeleton", a table that frames highlight cells
|
||||
highlightSkeletonHtml: function(startCol, endCol) {
|
||||
var colCnt = this.view.colCnt;
|
||||
var cellHtml = '';
|
||||
|
||||
if (startCol > 0) {
|
||||
cellHtml += '<td colspan="' + startCol + '"/>';
|
||||
}
|
||||
if (endCol > startCol) {
|
||||
cellHtml += '<td colspan="' + (endCol - startCol) + '" class="fc-highlight" />';
|
||||
}
|
||||
if (colCnt > endCol) {
|
||||
cellHtml += '<td colspan="' + (colCnt - endCol) + '"/>';
|
||||
}
|
||||
|
||||
cellHtml = this.bookendCells(cellHtml, 'highlight');
|
||||
|
||||
return '' +
|
||||
'<div class="fc-highlight-skeleton">' +
|
||||
'<table>' +
|
||||
'<tr>' +
|
||||
cellHtml +
|
||||
'</tr>' +
|
||||
'</table>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user