diff --git a/src/agenda/AgendaDayView.js b/src/agenda/AgendaDayView.js index 12b6b56..a6526b5 100644 --- a/src/agenda/AgendaDayView.js +++ b/src/agenda/AgendaDayView.js @@ -1,6 +1,7 @@ fcViews.agendaDay = AgendaDayView; + function AgendaDayView(element, calendar) { var t = this; @@ -13,22 +14,25 @@ function AgendaDayView(element, calendar) { AgendaView.call(t, element, calendar, 'agendaDay'); var opt = t.opt; var renderAgenda = t.renderAgenda; + var skipHiddenDays = t.skipHiddenDays; var formatDate = calendar.formatDate; - function render(date, delta) { + if (delta) { addDays(date, delta); - if (!opt('weekends')) { - skipWeekend(date, delta < 0 ? -1 : 1); - } } + skipHiddenDays(date, delta < 0 ? -1 : 1); + var start = cloneDate(date, true); var end = addDays(cloneDate(start), 1); + t.title = formatDate(date, opt('titleFormat')); + t.start = t.visStart = start; t.end = t.visEnd = end; + renderAgenda(1); } diff --git a/src/agenda/AgendaEventRenderer.js b/src/agenda/AgendaEventRenderer.js index 98cb861..6f5d516 100644 --- a/src/agenda/AgendaEventRenderer.js +++ b/src/agenda/AgendaEventRenderer.js @@ -5,17 +5,14 @@ function AgendaEventRenderer() { // exports t.renderEvents = renderEvents; - t.compileDaySegs = compileDaySegs; // for DayEventRenderer t.clearEvents = clearEvents; t.slotSegHtml = slotSegHtml; - t.bindDaySeg = bindDaySeg; // imports DayEventRenderer.call(t); var opt = t.opt; var trigger = t.trigger; - //var setOverflowHidden = t.setOverflowHidden; var isEventDraggable = t.isEventDraggable; var isEventResizable = t.isEventResizable; var eventEnd = t.eventEnd; @@ -31,13 +28,13 @@ function AgendaEventRenderer() { var timePosition = t.timePosition; var colContentLeft = t.colContentLeft; var colContentRight = t.colContentRight; - var renderDaySegs = t.renderDaySegs; - var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecture + var cellToDate = t.cellToDate; + var segmentCompare = t.segmentCompare; var getColCnt = t.getColCnt; var getColWidth = t.getColWidth; var getSnapHeight = t.getSnapHeight; var getSnapMinutes = t.getSnapMinutes; - var getBodyContent = t.getBodyContent; + var getSlotContainer = t.getSlotContainer; var reportEventElement = t.reportEventElement; var showEvents = t.showEvents; var hideEvents = t.hideEvents; @@ -45,10 +42,15 @@ function AgendaEventRenderer() { var eventResize = t.eventResize; var renderDayOverlay = t.renderDayOverlay; var clearOverlays = t.clearOverlays; + var renderDayEvents = t.renderDayEvents; var calendar = t.calendar; var formatDate = calendar.formatDate; var formatDates = calendar.formatDates; - + + + // overrides + t.draggableDayEvent = draggableDayEvent; + /* Rendering @@ -67,11 +69,14 @@ function AgendaEventRenderer() { slotEvents.push(events[i]); } } + if (opt('allDaySlot')) { - renderDaySegs(compileDaySegs(dayEvents), modifiedEventId); + renderDayEvents(dayEvents, modifiedEventId); setHeight(); // no params means set to viewHeight } + renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId); + trigger('eventAfterAllRender'); } @@ -81,39 +86,33 @@ function AgendaEventRenderer() { getDaySegmentContainer().empty(); getSlotSegmentContainer().empty(); } - - - function compileDaySegs(events) { - var levels = stackSegs(sliceSegs(events, $.map(events, exclEndDay), t.visStart, t.visEnd)), - i, levelCnt=levels.length, level, - j, seg, - segs=[]; - for (i=0; i start && eventStart < end) { + if (eventStart < start) { + segStart = cloneDate(start); + isStart = false; + }else{ + segStart = eventStart; + isStart = true; + } + if (eventEnd > end) { + segEnd = cloneDate(end); + isEnd = false; + }else{ + segEnd = eventEnd; + isEnd = true; + } + segs.push({ + event: event, + start: segStart, + end: segEnd, + isStart: isStart, + isEnd: isEnd, + msLength: segEnd - segStart + }); + } + } + return segs.sort(segmentCompare); + } + + function slotEventEnd(event) { if (event.end) { return cloneDate(event.end); @@ -139,6 +176,8 @@ function AgendaEventRenderer() { // renders events in the 'time slots' at the bottom + // TODO: when we refactor this, when user returns `false` eventRender, don't have empty space + // TODO: refactor will include using pixels to detect collisions instead of dates (handy for seg cmp) function renderSlotSegs(segs, modifiedEventId) { @@ -155,21 +194,15 @@ function AgendaEventRenderer() { eventElements, eventElement, triggerRes, - vsideCache={}, - hsideCache={}, - key, val, titleElement, height, slotSegmentContainer = getSlotSegmentContainer(), - rtl, dis, dit, - colCnt = getColCnt(); + rtl, dis; if (rtl = opt('isRTL')) { dis = -1; - dit = colCnt - 1; }else{ dis = 1; - dit = 0; } // calculate position/dimensions, create html @@ -181,8 +214,8 @@ function AgendaEventRenderer() { colI = seg.col; levelI = seg.level; forward = seg.forward || 0; - leftmost = colContentLeft(colI*dis + dit); - availWidth = colContentRight(colI*dis + dit) - leftmost; + leftmost = colContentLeft(colI); + availWidth = colContentRight(colI) - leftmost; availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS if (levelI) { // indented and thin @@ -243,10 +276,8 @@ function AgendaEventRenderer() { for (i=0; i0; i--) { @@ -604,7 +664,7 @@ function countForwardSegs(levels) { segForward = level[j]; for (k=0; k seg2.start && seg1.start < seg2.end; +} + diff --git a/src/agenda/AgendaView.js b/src/agenda/AgendaView.js index b53d86d..6e5d88a 100644 --- a/src/agenda/AgendaView.js +++ b/src/agenda/AgendaView.js @@ -33,20 +33,18 @@ function AgendaView(element, calendar, viewName) { t.afterShow = afterShow; t.defaultEventEnd = defaultEventEnd; t.timePosition = timePosition; - t.dayOfWeekCol = dayOfWeekCol; - t.dateCell = dateCell; - t.cellDate = cellDate; - t.cellIsAllDay = cellIsAllDay; + t.getIsCellAllDay = getIsCellAllDay; t.allDayRow = getAllDayRow; - t.allDayBounds = allDayBounds; t.getHoverListener = function() { return hoverListener }; + t.colLeft = colLeft; + t.colRight = colRight; t.colContentLeft = colContentLeft; t.colContentRight = colContentRight; t.getDaySegmentContainer = function() { return daySegmentContainer }; t.getSlotSegmentContainer = function() { return slotSegmentContainer }; t.getMinMinute = function() { return minMinute }; t.getMaxMinute = function() { return maxMinute }; - t.getBodyContent = function() { return slotContent }; // !!?? + t.getSlotContainer = function() { return slotContainer }; t.getRowCnt = function() { return 1 }; t.getColCnt = function() { return colCnt }; t.getColWidth = function() { return colWidth }; @@ -75,6 +73,9 @@ function AgendaView(element, calendar, viewName) { var unselect = t.unselect; var daySelectionMousedown = t.daySelectionMousedown; var slotSegHtml = t.slotSegHtml; + var cellToDate = t.cellToDate; + var dateToCell = t.dateToCell; + var rangeToSegments = t.rangeToSegments; var formatDate = calendar.formatDate; @@ -86,6 +87,7 @@ function AgendaView(element, calendar, viewName) { var dayBody; var dayBodyCells; var dayBodyCellInners; + var dayBodyCellContentInners; var dayBodyFirstCell; var dayBodyFirstCellStretcher; var slotLayer; @@ -93,12 +95,10 @@ function AgendaView(element, calendar, viewName) { var allDayTable; var allDayRow; var slotScroller; - var slotContent; + var slotContainer; var slotSegmentContainer; var slotTable; var slotTableFirstInner; - var axisFirstCells; - var gutterCells; var selectionHelper; var viewWidth; @@ -116,14 +116,13 @@ function AgendaView(element, calendar, viewName) { var slotCnt; var coordinateGrid; var hoverListener; + var colPositions; var colContentPositions; var slotTopCache = {}; var savedScrollTop; var tm; - var firstDay; - var nwe; // no weekends (int) - var rtl, dis, dit; // day index sign / translate + var rtl; var minMinute, maxMinute; var colFormat; var showWeekNumbers; @@ -143,26 +142,18 @@ function AgendaView(element, calendar, viewName) { colCnt = c; updateOptions(); if (!dayTable) { - buildSkeleton(); + buildSkeleton(); // builds day table, slot area, events containers }else{ + buildDayTable(); // rebuilds day table clearEvents(); } - updateCells(); } - function updateOptions() { + tm = opt('theme') ? 'ui' : 'fc'; - nwe = opt('weekends') ? 0 : 1; - firstDay = opt('firstDay'); - if (rtl = opt('isRTL')) { - dis = -1; - dit = colCnt - 1; - }else{ - dis = 1; - dit = 0; - } + rtl = opt('isRTL') minMinute = parseTime(opt('minTime')); maxMinute = parseTime(opt('maxTime')); colFormat = opt('columnFormat'); @@ -179,71 +170,24 @@ function AgendaView(element, calendar, viewName) { snapMinutes = opt('snapMinutes') || opt('slotMinutes'); } - - - + + + + /* Build DOM + -----------------------------------------------------------------------*/ + + function buildSkeleton() { var headerClass = tm + "-widget-header"; var contentClass = tm + "-widget-content"; var s; - var i; var d; + var i; var maxd; var minutes; var slotNormal = opt('slotMinutes') % 15 == 0; - s = - "" + - "" + - ""; - - if (showWeekNumbers) { - s += ""; - } - - for (i=0; i"; // fc- needed for setDayID - } - s += - "" + - "" + - "" + - "" + - "" + - ""; - for (i=0; i" + // fc- needed for setDayID - "
" + - "
" + - "
 
" + - "
" + - "
" + - ""; - } - s += - "
" + - "" + - "" + - "
"; - } - else { - s += "  
  
"; - dayTable = $(s).appendTo(element); - dayHead = dayTable.find('thead'); - dayHeadCells = dayHead.find('th').slice(1, -1); - dayBody = dayTable.find('tbody'); - dayBodyCells = dayBody.find('td').slice(0, -1); - dayBodyCellInners = dayBodyCells.find('div.fc-day-content div'); - dayBodyFirstCell = dayBodyCells.eq(0); - dayBodyFirstCellStretcher = dayBodyFirstCell.find('> div'); - - markFirstLast(dayHead.add(dayHead.find('tr'))); - markFirstLast(dayBody.add(dayBody.find('tr'))); - - axisFirstCells = dayHead.find('th:first'); - gutterCells = dayTable.find('.fc-agenda-gutter'); + buildDayTable(); slotLayer = $("
") @@ -270,9 +214,6 @@ function AgendaView(element, calendar, viewName) { dayBind(allDayRow.find('td')); - axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); - gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); - slotLayer.append( "
" + "
" + @@ -289,13 +230,13 @@ function AgendaView(element, calendar, viewName) { $("
") .appendTo(slotLayer); - slotContent = + slotContainer = $("
") .appendTo(slotScroller); slotSegmentContainer = $("
") - .appendTo(slotContent); + .appendTo(slotContainer); s = "" + @@ -321,49 +262,162 @@ function AgendaView(element, calendar, viewName) { s += "" + "
"; - slotTable = $(s).appendTo(slotContent); + slotTable = $(s).appendTo(slotContainer); slotTableFirstInner = slotTable.find('div:first'); slotBind(slotTable.find('td')); - - axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); } - - - - function updateCells() { - var i; - var headCell; - var bodyCell; + + + + /* Build Day Table + -----------------------------------------------------------------------*/ + + + function buildDayTable() { + var html = buildDayTableHTML(); + + if (dayTable) { + dayTable.remove(); + } + dayTable = $(html).appendTo(element); + + dayHead = dayTable.find('thead'); + dayHeadCells = dayHead.find('th').slice(1, -1); // exclude gutter + dayBody = dayTable.find('tbody'); + dayBodyCells = dayBody.find('td').slice(0, -1); // exclude gutter + dayBodyCellInners = dayBodyCells.find('> div'); + dayBodyCellContentInners = dayBodyCells.find('.fc-day-content > div'); + + dayBodyFirstCell = dayBodyCells.eq(0); + dayBodyFirstCellStretcher = dayBodyCellInners.eq(0); + + markFirstLast(dayHead.add(dayHead.find('tr'))); + markFirstLast(dayBody.add(dayBody.find('tr'))); + + // TODO: now that we rebuild the cells every time, we should call dayRender + } + + + function buildDayTableHTML() { + var html = + "" + + buildDayTableHeadHTML() + + buildDayTableBodyHTML() + + "
"; + + return html; + } + + + function buildDayTableHeadHTML() { + var headerClass = tm + "-widget-header"; var date; - var today = clearTime(new Date()); + var html = ''; + var weekText; + var col; + + html += + "" + + ""; if (showWeekNumbers) { - var weekText = formatDate(colDate(0), weekNumberFormat); + weekText = formatDate(date, weekNumberFormat); if (rtl) { - weekText = weekText + weekNumberTitle; + weekText += weekNumberTitle; } else { weekText = weekNumberTitle + weekText; } - dayHead.find('.fc-week-number').text(weekText); + html += + "" + + htmlEscape(weekText) + + ""; + } + else { + html += " "; } - for (i=0; i" + + htmlEscape(formatDate(date, colFormat)) + + ""; } + + html += + " " + + "" + + ""; + + return html; } + + + function buildDayTableBodyHTML() { + var headerClass = tm + "-widget-header"; // TODO: make these when updateOptions() called + var contentClass = tm + "-widget-content"; + var date; + var today = clearTime(new Date()); + var col; + var cellsHTML; + var cellHTML; + var classNames; + var html = ''; + + html += + "" + + "" + + " "; + + cellsHTML = ''; + + for (col=0; col" + + "
" + + "
" + + "
 
" + + "
" + + "
" + + ""; + + cellsHTML += cellHTML; + } + + html += cellsHTML; + html += + " " + + "" + + ""; + + return html; + } + + + // TODO: data-date on the cells + + /* Dimensions + -----------------------------------------------------------------------*/ + function setHeight(height, dateChanged) { if (height === undefined) { @@ -378,7 +432,7 @@ function AgendaView(element, calendar, viewName) { height - headHeight, // when scrollbars slotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border ); - + dayBodyFirstCellStretcher .height(bodyHeight - vsides(dayBodyFirstCell)); @@ -397,10 +451,16 @@ function AgendaView(element, calendar, viewName) { } - function setWidth(width) { viewWidth = width; + colPositions.clear(); colContentPositions.clear(); + + var axisFirstCells = dayHead.find('th:first'); + if (allDayTable) { + axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); + } + axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); axisWidth = 0; setOuterWidth( @@ -412,8 +472,12 @@ function AgendaView(element, calendar, viewName) { axisWidth ); + var gutterCells = dayTable.find('.fc-agenda-gutter'); + if (allDayTable) { + gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); + } + var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7) - //slotTable.width(slotTableWidth); gutterWidth = slotScroller.width() - slotTableWidth; if (gutterWidth) { @@ -435,6 +499,10 @@ function AgendaView(element, calendar, viewName) { + /* Scrolling + -----------------------------------------------------------------------*/ + + function resetScroll() { var d0 = zeroDate(); var scrollDate = cloneDate(d0); @@ -478,7 +546,7 @@ function AgendaView(element, calendar, viewName) { function slotClick(ev) { if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick var col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth)); - var date = colDate(col); + var date = cellToDate(0, col); var rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use data if (rowMatch) { var mins = parseInt(rowMatch[1]) * opt('slotMinutes'); @@ -496,26 +564,26 @@ function AgendaView(element, calendar, viewName) { /* Semi-transparent Overlay Helpers -----------------------------------------------------*/ - + // TODO: should be consolidated with BasicView's methods + + + function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - function renderDayOverlay(startDate, endDate, refreshCoordinateGrid) { // endDate is exclusive if (refreshCoordinateGrid) { coordinateGrid.build(); } - var visStart = cloneDate(t.visStart); - var startCol, endCol; - if (rtl) { - startCol = dayDiff(endDate, visStart)*dis+dit+1; - endCol = dayDiff(startDate, visStart)*dis+dit+1; - }else{ - startCol = dayDiff(startDate, visStart); - endCol = dayDiff(endDate, visStart); - } - startCol = Math.max(0, startCol); - endCol = Math.min(colCnt, endCol); - if (startCol < endCol) { + + var segments = rangeToSegments(overlayStart, overlayEnd); + + for (var i=0; i= 0 && col < colCnt) { // only works when times are on same day - var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coords + var rect = coordinateGrid.rect(0, col, 0, col, slotContainer); // only for horizontal coords var top = timePosition(startDate, startDate); var bottom = timePosition(startDate, endDate); if (bottom > top) { // protect against selections that are entirely before or after visible range @@ -734,7 +782,7 @@ function AgendaView(element, calendar, viewName) { rect.zIndex = 8; selectionHelper = $(helperRes) .css(rect) - .appendTo(slotContent); + .appendTo(slotContainer); } }else{ rect.isStart = true; // conside rect a "seg" now @@ -753,7 +801,7 @@ function AgendaView(element, calendar, viewName) { } if (selectionHelper) { slotBind(selectionHelper); - slotContent.append(selectionHelper); + slotContainer.append(selectionHelper); setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended setOuterHeight(selectionHelper, rect.height, true); } @@ -780,15 +828,15 @@ function AgendaView(element, calendar, viewName) { var dates; hoverListener.start(function(cell, origCell) { clearSelection(); - if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) { - var d1 = cellDate(origCell); - var d2 = cellDate(cell); + if (cell && cell.col == origCell.col && !getIsCellAllDay(cell)) { + var d1 = realCellToDate(origCell); + var d2 = realCellToDate(cell); dates = [ d1, addMinutes(cloneDate(d1), snapMinutes), // calculate minutes depending on selection slot minutes d2, addMinutes(cloneDate(d2), snapMinutes) - ].sort(cmp); + ].sort(dateCompare); renderSlotSelection(dates[0], dates[3]); }else{ dates = null; @@ -805,10 +853,10 @@ function AgendaView(element, calendar, viewName) { }); } } - - + + function reportDayClick(date, allDay, ev) { - trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev); + trigger('dayClick', dayBodyCells[dateToCell(date).col], date, allDay, ev); } @@ -821,10 +869,10 @@ function AgendaView(element, calendar, viewName) { hoverListener.start(function(cell) { clearOverlays(); if (cell) { - if (cellIsAllDay(cell)) { + if (getIsCellAllDay(cell)) { renderCellOverlay(cell.row, cell.col, cell.row, cell.col); }else{ - var d1 = cellDate(cell); + var d1 = realCellToDate(cell); var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes')); renderSlotOverlay(d1, d2); } @@ -837,9 +885,9 @@ function AgendaView(element, calendar, viewName) { var cell = hoverListener.stop(); clearOverlays(); if (cell) { - trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui); + trigger('drop', _dragElement, realCellToDate(cell), getIsCellAllDay(cell), ev, ui); } } - + } diff --git a/src/agenda/AgendaWeekView.js b/src/agenda/AgendaWeekView.js index 03d0f7e..3352cc5 100644 --- a/src/agenda/AgendaWeekView.js +++ b/src/agenda/AgendaWeekView.js @@ -13,34 +13,40 @@ function AgendaWeekView(element, calendar) { AgendaView.call(t, element, calendar, 'agendaWeek'); var opt = t.opt; var renderAgenda = t.renderAgenda; + var skipHiddenDays = t.skipHiddenDays; + var getCellsPerWeek = t.getCellsPerWeek; var formatDates = calendar.formatDates; - - + function render(date, delta) { + if (delta) { addDays(date, delta * 7); } + var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7)); var end = addDays(cloneDate(start), 7); + var visStart = cloneDate(start); + skipHiddenDays(visStart); + var visEnd = cloneDate(end); - var weekends = opt('weekends'); - if (!weekends) { - skipWeekend(visStart); - skipWeekend(visEnd, -1, true); - } + skipHiddenDays(visEnd, -1, true); + + var colCnt = getCellsPerWeek(); + t.title = formatDates( visStart, addDays(cloneDate(visEnd), -1), opt('titleFormat') ); + t.start = start; t.end = end; t.visStart = visStart; t.visEnd = visEnd; - renderAgenda(weekends ? 7 : 5); + + renderAgenda(colCnt); } - } diff --git a/src/basic/BasicDayView.js b/src/basic/BasicDayView.js index 1f49c84..2c94d8c 100644 --- a/src/basic/BasicDayView.js +++ b/src/basic/BasicDayView.js @@ -1,8 +1,6 @@ fcViews.basicDay = BasicDayView; -//TODO: when calendar's date starts out on a weekend, shouldn't happen - function BasicDayView(element, calendar) { var t = this; @@ -16,20 +14,25 @@ function BasicDayView(element, calendar) { BasicView.call(t, element, calendar, 'basicDay'); var opt = t.opt; var renderBasic = t.renderBasic; + var skipHiddenDays = t.skipHiddenDays; var formatDate = calendar.formatDate; - function render(date, delta) { + if (delta) { addDays(date, delta); - if (!opt('weekends')) { - skipWeekend(date, delta < 0 ? -1 : 1); - } } + skipHiddenDays(date, delta < 0 ? -1 : 1); + + var start = cloneDate(date, true); + var end = addDays(cloneDate(start), 1); + t.title = formatDate(date, opt('titleFormat')); - t.start = t.visStart = cloneDate(date, true); - t.end = t.visEnd = addDays(cloneDate(t.start), 1); + + t.start = t.visStart = start; + t.end = t.visEnd = end; + renderBasic(1, 1, false); } diff --git a/src/basic/BasicEventRenderer.js b/src/basic/BasicEventRenderer.js index 1ad3786..342e1de 100644 --- a/src/basic/BasicEventRenderer.js +++ b/src/basic/BasicEventRenderer.js @@ -5,138 +5,26 @@ function BasicEventRenderer() { // exports t.renderEvents = renderEvents; - t.compileDaySegs = compileSegs; // for DayEventRenderer t.clearEvents = clearEvents; - t.bindDaySeg = bindDaySeg; - + // imports DayEventRenderer.call(t); - var opt = t.opt; - var trigger = t.trigger; - //var setOverflowHidden = t.setOverflowHidden; - var isEventDraggable = t.isEventDraggable; - var isEventResizable = t.isEventResizable; - var reportEvents = t.reportEvents; - var reportEventClear = t.reportEventClear; - var eventElementHandlers = t.eventElementHandlers; - var showEvents = t.showEvents; - var hideEvents = t.hideEvents; - var eventDrop = t.eventDrop; - var getDaySegmentContainer = t.getDaySegmentContainer; - var getHoverListener = t.getHoverListener; - var renderDayOverlay = t.renderDayOverlay; - var clearOverlays = t.clearOverlays; - var getRowCnt = t.getRowCnt; - var getColCnt = t.getColCnt; - var renderDaySegs = t.renderDaySegs; - var resizableDayEvent = t.resizableDayEvent; - - - - /* Rendering - --------------------------------------------------------------------*/ - + function renderEvents(events, modifiedEventId) { - reportEvents(events); - renderDaySegs(compileSegs(events), modifiedEventId); - trigger('eventAfterAllRender'); + t.reportEvents(events); + t.renderDayEvents(events, modifiedEventId); + t.trigger('eventAfterAllRender'); } function clearEvents() { - reportEventClear(); - getDaySegmentContainer().empty(); - } - - - function compileSegs(events) { - var rowCnt = getRowCnt(), - colCnt = getColCnt(), - d1 = cloneDate(t.visStart), - d2 = addDays(cloneDate(d1), colCnt), - visEventsEnds = $.map(events, exclEndDay), - i, row, - j, level, - k, seg, - segs=[]; - for (i=0; i") @@ -138,79 +128,8 @@ function BasicView(element, calendar, viewName) { } - - function buildTable(showNumbers) { - var html = ''; - var i, j; - var headerClass = tm + "-widget-header"; - var contentClass = tm + "-widget-content"; - var month = t.start.getMonth(); - var today = clearTime(new Date()); - var cellDate; // not to be confused with local function. TODO: better names - var cellClasses; - var cell; - - html += "" + - "" + - ""; - - if (showWeekNumbers) { - html += "" + - "" + - ""; - - for (i=0; i" + - "
" + - ""; - } - - for (j=0; j" + - "
"; - if (showNumbers) { - html += "
" + cellDate.getDate() + "
"; - } - html += "
" + - "
 
" + - "
" + - "
" + - ""; - } - - html += ""; - } - html += "
" + - "
"; - } - - for (i=0; i"; - } - - html += "
"; + function buildTable() { + var html = buildTableHTML(); lockHeight(); // the unlock happens later, in setHeight()... if (table) { @@ -224,37 +143,155 @@ function BasicView(element, calendar, viewName) { bodyRows = body.find('tr'); bodyCells = body.find('.fc-day'); bodyFirstCells = bodyRows.find('td:first-child'); - bodyCellTopInners = bodyRows.eq(0).find('.fc-day-content > div'); + + 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'); - - if (showWeekNumbers) { - head.find('.fc-week-number').text(weekNumberTitle); - } - headCells.each(function(i, _cell) { - var date = indexDate(i); - $(_cell).text(formatDate(date, colFormat)); - }); - - if (showWeekNumbers) { - body.find('.fc-week-number > div').each(function(i, _cell) { - var weekStart = _cellDate(i, 0); - $(_cell).text(formatDate(weekStart, weekNumberFormat)); - }); - } - bodyCells.each(function(i, _cell) { - var date = indexDate(i); + var date = cellToDate( + Math.floor(i / colCnt), + i % colCnt + ); trigger('dayRender', t, date, $(_cell)); }); dayBind(bodyCells); } - + + + + /* HTML Building + -----------------------------------------------------------*/ + + + function buildTableHTML() { + var html = + "" + + buildHeadHTML() + + buildBodyHTML() + + "
"; + + return html; + } + + + function buildHeadHTML() { + var headerClass = tm + "-widget-header"; + var html = ''; + var col; + var date; + + html += ""; + + if (showWeekNumbers) { + html += + "" + + htmlEscape(weekNumberTitle) + + ""; + } + + for (col=0; col" + + htmlEscape(formatDate(date, colFormat)) + + ""; + } + + html += ""; + + return html; + } + + + function buildBodyHTML() { + var contentClass = tm + "-widget-content"; + var html = ''; + var row; + var col; + var date; + + html += ""; + + for (row=0; row" + + "
" + + htmlEscape(formatDate(date, weekNumberFormat)) + + "
" + + ""; + } + + for (col=0; col" + + "
"; + + if (showNumbers) { + html += "
" + date.getDate() + "
"; + } + + html += + "
" + + "
 
" + + "
" + + "
" + + ""; + + return html; + } + + + + /* Dimensions + -----------------------------------------------------------*/ function setHeight(height) { @@ -288,6 +325,7 @@ function BasicView(element, calendar, viewName) { function setWidth(width) { viewWidth = width; + colPositions.clear(); colContentPositions.clear(); weekNumberWidth = 0; @@ -322,35 +360,30 @@ function BasicView(element, calendar, viewName) { /* 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 rowStart = cloneDate(t.visStart); - var rowEnd = addDays(cloneDate(rowStart), colCnt); - for (var i=0; i"); + + + // Render an event on the calendar, but don't report them anywhere, and don't attach mouse handlers. + // Append this event element to the event container, which might already be populated with events. + // If an event's segment will have row equal to `adjustRow`, then explicitly set its top coordinate to `adjustTop`. + // This hack is used to maintain continuity when user is manually resizing an event. + // Returns an array of DOM elements for the event. + function renderTempDayEvent(event, adjustRow, adjustTop) { + + // actually render the event. `true` for appending element to container. + // Recieve the intermediate "segment" data structures. + var segments = _renderDayEvents( + [ event ], + true, // append event elements + false // don't set the heights of the rows + ); + + var elements = []; + + // Adjust certain elements' top coordinates + segmentElementEach(segments, function(segment, element) { + if (segment.row === adjustRow) { + element.css('top', adjustTop); + } + elements.push(element[0]); // accumulate DOM nodes + }); + + return elements; + } + + + // Render events onto the calendar. Only responsible for the VISUAL aspect. + // Not responsible for attaching handlers or calling callbacks. + // Set `doAppend` to `true` for rendering elements without clearing the existing container. + // Set `doRowHeights` to allow setting the height of each row, to compensate for vertical event overflow. + function _renderDayEvents(events, doAppend, doRowHeights) { + + // where the DOM nodes will eventually end up + var finalContainer = getDaySegmentContainer(); + + // the container where the initial HTML will be rendered. + // If `doAppend`==true, uses a temporary container. + var renderContainer = doAppend ? $("
") : finalContainer; + + var segments = buildSegments(events); + var html; var elements; - var segmentContainer = getDaySegmentContainer(); - var i; - var segCnt = segs.length; - var element; - tempContainer[0].innerHTML = daySegHTML(segs); // faster than .html() - elements = tempContainer.children(); - segmentContainer.append(elements); - daySegElementResolve(segs, elements); - daySegCalcHSides(segs); - daySegSetWidths(segs); - daySegCalcHeights(segs); - daySegSetTops(segs, getRowTops(getRowDivs())); - elements = []; - for (i=0; i" + - "
"; - if (!event.allDay && seg.isStart) { - html += - "" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - ""; - } - html += - "" + htmlEscape(event.title) + "" + - "
"; - if (seg.isEnd && isEventResizable(event)) { - html += - "
" + - "   " + // makes hit area a lot better for IE6/7 - "
"; - } - html += - ""; - seg.left = left; - seg.outerWidth = right - left; - seg.startCol = leftCol; - seg.endCol = rightCol + 1; // needs to be exclusive + for (var i=0; i" + + "
"; + if (!event.allDay && segment.isStart) { + html += + "" + + htmlEscape( + formatDates(event.start, event.end, opt('timeFormat')) + ) + + ""; + } + html += + "" + htmlEscape(event.title) + "" + + "
"; + if (segment.isEnd && isEventResizable(event)) { + html += + "
" + + "   " + // makes hit area a lot better for IE6/7 + "
"; + } + html += ""; + + // TODO: + // When these elements are initially rendered, they will be briefly visibile on the screen, + // even though their widths/heights are not set. + // SOLUTION: initially set them as visibility:hidden ? + + return html; + } + + + // Associate each segment (an object) with an element (a jQuery object), + // by setting each `segment.element`. + // Run each element through the `eventRender` filter, which allows developers to + // modify an existing element, supply a new one, or cancel rendering. + function resolveElements(segments, elements) { + for (var i=0; i div'); // optimal selector? + .find('div.fc-day-content > div'); } return rowDivs; } - - - function getRowTops(rowDivs) { - var i; - var rowCnt = rowDivs.length; - var tops = []; - for (i=0; i= segment.leftCol + ) { + return true; + } + } + return false; +} + + +function segmentElementEach(segments, callback) { // TODO: use in AgendaView? + for (var i=0; i