mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-07-27 11:22:18 +08:00
521 lines
10 KiB
JavaScript
521 lines
10 KiB
JavaScript
|
|
setDefaults({
|
|
weekMode: 'fixed'
|
|
});
|
|
|
|
|
|
function BasicView(element, calendar, viewName) {
|
|
var t = this;
|
|
|
|
|
|
// exports
|
|
t.renderBasic = renderBasic;
|
|
t.setHeight = setHeight;
|
|
t.setWidth = setWidth;
|
|
t.renderDayOverlay = renderDayOverlay;
|
|
t.defaultSelectionEnd = defaultSelectionEnd;
|
|
t.renderSelection = renderSelection;
|
|
t.clearSelection = clearSelection;
|
|
t.reportDayClick = reportDayClick; // for selection (kinda hacky)
|
|
t.dragStart = dragStart;
|
|
t.dragStop = dragStop;
|
|
t.defaultEventEnd = defaultEventEnd;
|
|
t.getHoverListener = function() { return hoverListener };
|
|
t.colLeft = colLeft;
|
|
t.colRight = colRight;
|
|
t.colContentLeft = colContentLeft;
|
|
t.colContentRight = colContentRight;
|
|
t.getIsCellAllDay = function() { return true };
|
|
t.allDayRow = allDayRow;
|
|
t.getRowCnt = function() { return rowCnt };
|
|
t.getColCnt = function() { return colCnt };
|
|
t.getColWidth = function() { return colWidth };
|
|
t.getDaySegmentContainer = function() { return daySegmentContainer };
|
|
|
|
|
|
// imports
|
|
View.call(t, element, calendar, viewName);
|
|
OverlayManager.call(t);
|
|
SelectionManager.call(t);
|
|
BasicEventRenderer.call(t);
|
|
var opt = t.opt;
|
|
var trigger = t.trigger;
|
|
var renderOverlay = t.renderOverlay;
|
|
var clearOverlays = t.clearOverlays;
|
|
var daySelectionMousedown = t.daySelectionMousedown;
|
|
var cellToDate = t.cellToDate;
|
|
var dateToCell = t.dateToCell;
|
|
var rangeToSegments = t.rangeToSegments;
|
|
var formatDate = calendar.formatDate;
|
|
|
|
|
|
// locals
|
|
|
|
var table;
|
|
var head;
|
|
var headCells;
|
|
var body;
|
|
var bodyRows;
|
|
var bodyCells;
|
|
var bodyFirstCells;
|
|
var firstRowCellInners;
|
|
var firstRowCellContentInners;
|
|
var daySegmentContainer;
|
|
|
|
var viewWidth;
|
|
var viewHeight;
|
|
var colWidth;
|
|
var weekNumberWidth;
|
|
|
|
var rowCnt, colCnt;
|
|
var showNumbers;
|
|
var coordinateGrid;
|
|
var hoverListener;
|
|
var colPositions;
|
|
var colContentPositions;
|
|
|
|
var tm;
|
|
var colFormat;
|
|
var showWeekNumbers;
|
|
var weekNumberTitle;
|
|
var weekNumberFormat;
|
|
|
|
|
|
|
|
/* Rendering
|
|
------------------------------------------------------------*/
|
|
|
|
|
|
disableTextSelection(element.addClass('fc-grid'));
|
|
|
|
|
|
function renderBasic(_rowCnt, _colCnt, _showNumbers) {
|
|
rowCnt = _rowCnt;
|
|
colCnt = _colCnt;
|
|
showNumbers = _showNumbers;
|
|
updateOptions();
|
|
|
|
if (!body) {
|
|
buildEventContainer();
|
|
}
|
|
|
|
buildTable();
|
|
}
|
|
|
|
|
|
function updateOptions() {
|
|
tm = opt('theme') ? 'ui' : 'fc';
|
|
colFormat = opt('columnFormat');
|
|
|
|
// week # options. (TODO: bad, logic also in other views)
|
|
showWeekNumbers = opt('weekNumbers');
|
|
weekNumberTitle = opt('weekNumberTitle');
|
|
if (opt('weekNumberCalculation') != 'iso') {
|
|
weekNumberFormat = "w";
|
|
}
|
|
else {
|
|
weekNumberFormat = "W";
|
|
}
|
|
}
|
|
|
|
|
|
function buildEventContainer() {
|
|
daySegmentContainer =
|
|
$("<div class='fc-event-container' style='position:absolute;z-index:8;top:0;left:0'/>")
|
|
.appendTo(element);
|
|
}
|
|
|
|
|
|
function buildTable() {
|
|
var html = buildTableHTML();
|
|
|
|
if (table) {
|
|
table.remove();
|
|
}
|
|
table = $(html).appendTo(element);
|
|
|
|
head = table.find('thead');
|
|
headCells = head.find('.fc-day-header');
|
|
body = table.find('tbody');
|
|
bodyRows = body.find('tr');
|
|
bodyCells = body.find('.fc-day');
|
|
bodyFirstCells = bodyRows.find('td:first-child');
|
|
|
|
firstRowCellInners = bodyRows.eq(0).find('.fc-day > div');
|
|
firstRowCellContentInners = bodyRows.eq(0).find('.fc-day-content > div');
|
|
|
|
markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's
|
|
markFirstLast(bodyRows); // marks first+last td's
|
|
bodyRows.eq(0).addClass('fc-first');
|
|
bodyRows.filter(':last').addClass('fc-last');
|
|
|
|
bodyCells.each(function(i, _cell) {
|
|
var date = cellToDate(
|
|
Math.floor(i / colCnt),
|
|
i % colCnt
|
|
);
|
|
trigger('dayRender', t, date, $(_cell));
|
|
});
|
|
|
|
dayBind(bodyCells);
|
|
}
|
|
|
|
|
|
|
|
/* HTML Building
|
|
-----------------------------------------------------------*/
|
|
|
|
|
|
function buildTableHTML() {
|
|
var html =
|
|
"<table class='fc-border-separate' style='width:100%' cellspacing='0'>" +
|
|
buildHeadHTML() +
|
|
buildBodyHTML() +
|
|
"</table>";
|
|
|
|
return html;
|
|
}
|
|
|
|
|
|
function buildHeadHTML() {
|
|
var headerClass = tm + "-widget-header";
|
|
var html = '';
|
|
var col;
|
|
var date;
|
|
|
|
html += "<thead><tr>";
|
|
|
|
if (showWeekNumbers) {
|
|
html +=
|
|
"<th class='fc-week-number " + headerClass + "'>" +
|
|
htmlEscape(weekNumberTitle) +
|
|
"</th>";
|
|
}
|
|
|
|
for (col=0; col<colCnt; col++) {
|
|
date = cellToDate(0, col);
|
|
html +=
|
|
"<th class='fc-day-header fc-" + dayIDs[date.getDay()] + " " + headerClass + "'>" +
|
|
htmlEscape(formatDate(date, colFormat)) +
|
|
"</th>";
|
|
}
|
|
|
|
html += "</tr></thead>";
|
|
|
|
return html;
|
|
}
|
|
|
|
|
|
function buildBodyHTML() {
|
|
var contentClass = tm + "-widget-content";
|
|
var html = '';
|
|
var row;
|
|
var col;
|
|
var date;
|
|
|
|
html += "<tbody>";
|
|
|
|
for (row=0; row<rowCnt; row++) {
|
|
|
|
html += "<tr class='fc-week'>";
|
|
|
|
if (showWeekNumbers) {
|
|
date = cellToDate(row, 0);
|
|
html +=
|
|
"<td class='fc-week-number " + contentClass + "'>" +
|
|
"<div>" +
|
|
htmlEscape(formatDate(date, weekNumberFormat)) +
|
|
"</div>" +
|
|
"</td>";
|
|
}
|
|
|
|
for (col=0; col<colCnt; col++) {
|
|
date = cellToDate(row, col);
|
|
html += buildCellHTML(date);
|
|
}
|
|
|
|
html += "</tr>";
|
|
}
|
|
|
|
html += "</tbody>";
|
|
|
|
return html;
|
|
}
|
|
|
|
|
|
function buildCellHTML(date) {
|
|
var contentClass = tm + "-widget-content";
|
|
var month = t.start.getMonth();
|
|
var today = clearTime(new Date());
|
|
var html = '';
|
|
var classNames = [
|
|
'fc-day',
|
|
'fc-' + dayIDs[date.getDay()],
|
|
contentClass
|
|
];
|
|
|
|
if (date.getMonth() != month) {
|
|
classNames.push('fc-other-month');
|
|
}
|
|
if (+date == +today) {
|
|
classNames.push(
|
|
'fc-today',
|
|
tm + '-state-highlight'
|
|
);
|
|
}
|
|
else if (date < today) {
|
|
classNames.push('fc-past');
|
|
}
|
|
else {
|
|
classNames.push('fc-future');
|
|
}
|
|
|
|
html +=
|
|
"<td" +
|
|
" class='" + classNames.join(' ') + "'" +
|
|
" data-date='" + formatDate(date, 'yyyy-MM-dd') + "'" +
|
|
">" +
|
|
"<div>";
|
|
|
|
if (showNumbers) {
|
|
html += "<div class='fc-day-number'>" + date.getDate() + "</div>";
|
|
}
|
|
|
|
html +=
|
|
"<div class='fc-day-content'>" +
|
|
"<div style='position:relative'> </div>" +
|
|
"</div>" +
|
|
"</div>" +
|
|
"</td>";
|
|
|
|
return html;
|
|
}
|
|
|
|
|
|
|
|
/* Dimensions
|
|
-----------------------------------------------------------*/
|
|
|
|
|
|
function setHeight(height) {
|
|
viewHeight = height;
|
|
|
|
var bodyHeight = viewHeight - head.height();
|
|
var rowHeight;
|
|
var rowHeightLast;
|
|
var cell;
|
|
|
|
if (opt('weekMode') == 'variable') {
|
|
rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6));
|
|
}else{
|
|
rowHeight = Math.floor(bodyHeight / rowCnt);
|
|
rowHeightLast = bodyHeight - rowHeight * (rowCnt-1);
|
|
}
|
|
|
|
bodyFirstCells.each(function(i, _cell) {
|
|
if (i < rowCnt) {
|
|
cell = $(_cell);
|
|
cell.find('> div').css(
|
|
'min-height',
|
|
(i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell)
|
|
);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
|
|
function setWidth(width) {
|
|
viewWidth = width;
|
|
colPositions.clear();
|
|
colContentPositions.clear();
|
|
|
|
weekNumberWidth = 0;
|
|
if (showWeekNumbers) {
|
|
weekNumberWidth = head.find('th.fc-week-number').outerWidth();
|
|
}
|
|
|
|
colWidth = Math.floor((viewWidth - weekNumberWidth) / colCnt);
|
|
setOuterWidth(headCells.slice(0, -1), colWidth);
|
|
}
|
|
|
|
|
|
|
|
/* Day clicking and binding
|
|
-----------------------------------------------------------*/
|
|
|
|
|
|
function dayBind(days) {
|
|
days.click(dayClick)
|
|
.mousedown(daySelectionMousedown);
|
|
}
|
|
|
|
|
|
function dayClick(ev) {
|
|
if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick
|
|
var date = parseISO8601($(this).data('date'));
|
|
trigger('dayClick', this, date, true, ev);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Semi-transparent Overlay Helpers
|
|
------------------------------------------------------*/
|
|
// TODO: should be consolidated with AgendaView's methods
|
|
|
|
|
|
function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive
|
|
|
|
if (refreshCoordinateGrid) {
|
|
coordinateGrid.build();
|
|
}
|
|
|
|
var segments = rangeToSegments(overlayStart, overlayEnd);
|
|
|
|
for (var i=0; i<segments.length; i++) {
|
|
var segment = segments[i];
|
|
dayBind(
|
|
renderCellOverlay(
|
|
segment.row,
|
|
segment.leftCol,
|
|
segment.row,
|
|
segment.rightCol
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
function renderCellOverlay(row0, col0, row1, col1) { // row1,col1 is inclusive
|
|
var rect = coordinateGrid.rect(row0, col0, row1, col1, element);
|
|
return renderOverlay(rect, element);
|
|
}
|
|
|
|
|
|
|
|
/* Selection
|
|
-----------------------------------------------------------------------*/
|
|
|
|
|
|
function defaultSelectionEnd(startDate, allDay) {
|
|
return cloneDate(startDate);
|
|
}
|
|
|
|
|
|
function renderSelection(startDate, endDate, allDay) {
|
|
renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); // rebuild every time???
|
|
}
|
|
|
|
|
|
function clearSelection() {
|
|
clearOverlays();
|
|
}
|
|
|
|
|
|
function reportDayClick(date, allDay, ev) {
|
|
var cell = dateToCell(date);
|
|
var _element = bodyCells[cell.row*colCnt + cell.col];
|
|
trigger('dayClick', _element, date, allDay, ev);
|
|
}
|
|
|
|
|
|
|
|
/* External Dragging
|
|
-----------------------------------------------------------------------*/
|
|
|
|
|
|
function dragStart(_dragElement, ev, ui) {
|
|
hoverListener.start(function(cell) {
|
|
clearOverlays();
|
|
if (cell) {
|
|
renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
|
|
}
|
|
}, ev);
|
|
}
|
|
|
|
|
|
function dragStop(_dragElement, ev, ui) {
|
|
var cell = hoverListener.stop();
|
|
clearOverlays();
|
|
if (cell) {
|
|
var d = cellToDate(cell);
|
|
trigger('drop', _dragElement, d, true, ev, ui);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Utilities
|
|
--------------------------------------------------------*/
|
|
|
|
|
|
function defaultEventEnd(event) {
|
|
return cloneDate(event.start);
|
|
}
|
|
|
|
|
|
coordinateGrid = new CoordinateGrid(function(rows, cols) {
|
|
var e, n, p;
|
|
headCells.each(function(i, _e) {
|
|
e = $(_e);
|
|
n = e.offset().left;
|
|
if (i) {
|
|
p[1] = n;
|
|
}
|
|
p = [n];
|
|
cols[i] = p;
|
|
});
|
|
p[1] = n + e.outerWidth();
|
|
bodyRows.each(function(i, _e) {
|
|
if (i < rowCnt) {
|
|
e = $(_e);
|
|
n = e.offset().top;
|
|
if (i) {
|
|
p[1] = n;
|
|
}
|
|
p = [n];
|
|
rows[i] = p;
|
|
}
|
|
});
|
|
p[1] = n + e.outerHeight();
|
|
});
|
|
|
|
|
|
hoverListener = new HoverListener(coordinateGrid);
|
|
|
|
colPositions = new HorizontalPositionCache(function(col) {
|
|
return firstRowCellInners.eq(col);
|
|
});
|
|
|
|
colContentPositions = new HorizontalPositionCache(function(col) {
|
|
return firstRowCellContentInners.eq(col);
|
|
});
|
|
|
|
|
|
function colLeft(col) {
|
|
return colPositions.left(col);
|
|
}
|
|
|
|
|
|
function colRight(col) {
|
|
return colPositions.right(col);
|
|
}
|
|
|
|
|
|
function colContentLeft(col) {
|
|
return colContentPositions.left(col);
|
|
}
|
|
|
|
|
|
function colContentRight(col) {
|
|
return colContentPositions.right(col);
|
|
}
|
|
|
|
|
|
function allDayRow(i) {
|
|
return bodyRows.eq(i);
|
|
}
|
|
|
|
}
|