setDefaults({ allDaySlot: true, allDayText: 'all-day', firstHour: 6, slotMinutes: 30, minSlotNumber: 0, maxSlotNumber: 0, defaultEventMinutes: 120, axisFormat: 'h(:mm)tt', timeFormat: { agenda: 'h:mm{ - h:mm}' }, dragOpacity: { agenda: .5 }, minTime: 0, maxTime: 24 }); // TODO: make it work in quirks mode (event corners, all-day height) // TODO: test liquid width, especially in IE6 function AgendaView(element, calendar, viewName) { var t = this; // exports t.renderAgenda = renderAgenda; t.setWidth = setWidth; t.setHeight = setHeight; t.beforeHide = beforeHide; t.afterShow = afterShow; t.defaultEventEnd = defaultEventEnd; t.timePosition = timePosition; t.dayOfWeekCol = dayOfWeekCol; t.dateCell = dateCell; t.cellDate = cellDate; t.cellIsAllDay = cellIsAllDay; t.allDayRow = getAllDayRow; t.allDayBounds = allDayBounds; t.getHoverListener = function() { return hoverListener }; 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.getRowCnt = function() { return 1 }; t.getColCnt = function() { return colCnt }; t.getColWidth = function() { return colWidth }; t.getSlotHeight = function() { return slotHeight }; t.getBorderHeight = function() { return borderHeight }; t.getSlotTableHeight = function() { return slotTable.height() }; t.defaultSelectionEnd = defaultSelectionEnd; t.renderDayOverlay = renderDayOverlay; t.renderSelection = renderSelection; t.clearSelection = clearSelection; t.reportDayClick = reportDayClick; // selection mousedown hack t.dragStart = dragStart; t.dragStop = dragStop; // imports View.call(t, element, calendar, viewName); OverlayManager.call(t); SelectionManager.call(t); AgendaEventRenderer.call(t); var opt = t.opt; var trigger = t.trigger; var clearEvents = t.clearEvents; var renderOverlay = t.renderOverlay; var clearOverlays = t.clearOverlays; var reportSelection = t.reportSelection; var unselect = t.unselect; var daySelectionMousedown = t.daySelectionMousedown; var slotSegHtml = t.slotSegHtml; var formatDate = calendar.formatDate; // locals var dayTable; var dayHead; var dayHeadCells; var dayBody; var dayBodyCells; var dayBodyCellInners; var dayBodyFirstCell; var dayBodyFirstCellStretcher; var slotLayer; var daySegmentContainer; var allDayTable; var allDayRow; var slotScroller; var slotContent; var slotSegmentContainer; var slotTable; var slotTableFirstRow; var slotTableSecondRow; var axisFirstCells; var gutterCells; var selectionHelper; var viewWidth; var viewHeight; var axisWidth; var colWidth; var gutterWidth; var slotHeight; // TODO: what if slotHeight changes? (see issue 650) var borderHeight; var savedScrollTop; var colCnt; var slotCnt; var coordinateGrid; var hoverListener; var colContentPositions; var slotTopCache = {}; var tm; var firstDay; var nwe; // no weekends (int) var rtl, dis, dit; // day index sign / translate var minMinute, maxMinute; var colFormat; /* Rendering -----------------------------------------------------------------------------*/ disableTextSelection(element.addClass('fc-agenda')); function renderAgenda(c) { colCnt = c; updateOptions(); if (!dayTable) { buildSkeleton(); }else{ 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; } minMinute = parseTime(opt('minTime')); maxMinute = parseTime(opt('maxTime')); colFormat = opt('columnFormat'); } function buildSkeleton() { var headerClass = tm + "-widget-header"; var contentClass = tm + "-widget-content"; var s; var i; var d; var maxd; var minutes; var slotNormal = opt('slotMinutes') % 15 == 0; s = "" + "" + "" + ""; for (i=0; i"; // fc- needed for setDayID } s += "" + "" + "" + "" + "" + ""; for (i=0; i" + // fc- needed for setDayID "
" + "
" + "
 
" + "
" + "
" + ""; } 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'); slotLayer = $("
") .appendTo(element); if (opt('allDaySlot')) { daySegmentContainer = $("
") .appendTo(slotLayer); s = "" + "" + "" + "" + "" + "" + "
" + opt('allDayText') + "" + "
" + "
 
"; allDayTable = $(s).appendTo(slotLayer); allDayRow = allDayTable.find('tr'); dayBind(allDayRow.find('td')); axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); slotLayer.append( "
" + "
" + "
" ); }else{ daySegmentContainer = $([]); // in jQuery 1.4, we can just do $() } slotScroller = $("
") .appendTo(slotLayer); slotContent = $("
") .appendTo(slotScroller); slotSegmentContainer = $("
") .appendTo(slotContent); s = "" + ""; d = zeroDate(); maxd = addMinutes(cloneDate(d), maxMinute); addMinutes(d, minMinute); slotCnt = 0; for (i=0; d < maxd; i++) { minutes = d.getMinutes(); s += "" + "" + "" + ""; addMinutes(d, opt('slotMinutes')); slotCnt++; } s += "" + "
" + ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') + "" + "
 
" + "
"; slotTable = $(s).appendTo(slotContent); slotTableFirstRow = slotTable.find('tr:first'); slotTableSecondRow = slotTable.find('tr:nth-child(2)'); slotBind(slotTable.find('td')); axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); } function updateCells() { var i; var headCell; var bodyCell; var date; var today = clearTime(new Date()); for (i=0; i= 0) { addMinutes(d, minMinute + slotIndex * opt('slotMinutes')); } return d; } function colDate(col) { // returns dates with 00:00:00 return addDays(cloneDate(t.visStart), col*dis+dit); } function cellIsAllDay(cell) { return opt('allDaySlot') && !cell.row; } function dayOfWeekCol(dayOfWeek) { return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt)*dis+dit; } // get the Y coordinate of the given time on the given day (both Date objects) function timePosition(day, time) { // both date objects. day holds 00:00 of current day day = cloneDate(day, true); if (time < addMinutes(cloneDate(day), minMinute)) { return 0; } if (time >= addMinutes(cloneDate(day), maxMinute)) { return slotTable.height(); } var slotMinutes = opt('slotMinutes'), minutes = time.getHours()*60 + time.getMinutes() - minMinute, slotI = Math.floor(minutes / slotMinutes), slotTop = slotTopCache[slotI]; if (slotTop === undefined) { slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization??? } return Math.max(0, Math.round( slotTop + slotHeight * ((minutes % slotMinutes) / slotMinutes) )); } function allDayBounds() { return { left: axisWidth, right: viewWidth - gutterWidth } } function getAllDayRow(index) { return allDayRow; } function defaultEventEnd(event) { var start = cloneDate(event.start); if (event.allDay) { return start; } return addMinutes(start, opt('defaultEventMinutes')); } /* Selection ---------------------------------------------------------------------------------*/ function defaultSelectionEnd(startDate, allDay) { if (allDay) { return cloneDate(startDate); } return addMinutes(cloneDate(startDate), opt('slotMinutes')); } function renderSelection(startDate, endDate, allDay) { // only for all-day if (allDay) { if (opt('allDaySlot')) { renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); } }else{ renderSlotSelection(startDate, endDate); } } function renderSlotSelection(startDate, endDate) { var helperOption = opt('selectHelper'); coordinateGrid.build(); if (helperOption) { var col = dayDiff(startDate, t.visStart) * dis + dit; if (col >= 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 top = timePosition(startDate, startDate); var bottom = timePosition(startDate, endDate); if (bottom < slotTable.height()) { bottom -= borderHeight; } if (bottom > top) { // protect against selections that are entirely before or after visible range rect.top = top; rect.height = bottom - top; rect.left += 2; rect.width -= 5; if ($.isFunction(helperOption)) { var helperRes = helperOption(startDate, endDate); if (helperRes) { rect.position = 'absolute'; rect.zIndex = 8; selectionHelper = $(helperRes) .css(rect) .appendTo(slotContent); } }else{ rect.isStart = true; // conside rect a "seg" now rect.isEnd = true; // selectionHelper = $(slotSegHtml( { title: '', start: startDate, end: endDate, className: ['fc-select-helper'], editable: false }, rect )); selectionHelper.css('opacity', opt('dragOpacity')); } if (selectionHelper) { slotBind(selectionHelper); slotContent.append(selectionHelper); setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended setOuterHeight(selectionHelper, rect.height, true); } } } }else{ renderSlotOverlay(startDate, endDate); } } function clearSelection() { clearOverlays(); if (selectionHelper) { selectionHelper.remove(); selectionHelper = null; } } function slotSelectionMousedown(ev) { if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button unselect(ev); var dates; var minSlotNumber = opt('minSlotNumber'); if (minSlotNumber <= 0) minSlotNumber = 1; var maxSlotNumber = opt('maxSlotNumber'); hoverListener.start(function(cell, origCell) { clearSelection(); if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) { var d1 = cellDate(origCell); var d2 = cellDate(cell); if (d2>d1) { var date1 = d1 var date2 = d2 } else { var date1 = d2 var date2 = d1 } if (maxSlotNumber != 0 && (date2-date1) >= maxSlotNumber*opt('slotMinutes')*60000) { dates = [ date1, addMinutes(cloneDate(date1), minSlotNumber*opt('slotMinutes')), date1, addMinutes(cloneDate(date1), maxSlotNumber*opt('slotMinutes')) ].sort(cmp); } else { dates = [ date1, addMinutes(cloneDate(date1), minSlotNumber*opt('slotMinutes')), date2, addMinutes(cloneDate(date2), opt('slotMinutes')) ].sort(cmp); } renderSlotSelection(dates[0], dates[3]); }else{ dates = null; } }, ev); $(document).one('mouseup', function(ev) { hoverListener.stop(); if (dates) { if (+dates[0] == +dates[1]) { reportDayClick(dates[0], false, ev); } reportSelection(dates[0], dates[3], false, ev); } }); } } function reportDayClick(date, allDay, ev) { trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev); } /* External Dragging --------------------------------------------------------------------------------*/ function dragStart(_dragElement, ev, ui) { hoverListener.start(function(cell) { clearOverlays(); if (cell) { if (cellIsAllDay(cell)) { renderCellOverlay(cell.row, cell.col, cell.row, cell.col); }else{ var d1 = cellDate(cell); var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes')); renderSlotOverlay(d1, d2); } } }, ev); } function dragStop(_dragElement, ev, ui) { var cell = hoverListener.stop(); clearOverlays(); if (cell) { trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui); } } }