/* An abstract class for the "basic" views, as well as month view. Renders one or more rows of day cells. ----------------------------------------------------------------------------------------------------------------------*/ // It is a manager for a DayGrid subcomponent, which does most of the heavy lifting. // It is responsible for managing width/height. function BasicView(calendar) { View.call(this, calendar); // call the super-constructor this.dayGrid = new DayGrid(this); this.coordMap = this.dayGrid.coordMap; // the view's date-to-cell mapping is identical to the subcomponent's } BasicView.prototype = createObject(View.prototype); // define the super-class $.extend(BasicView.prototype, { dayGrid: null, // the main subcomponent that does most of the heavy lifting dayNumbersVisible: false, // display day numbers on each day cell? weekNumbersVisible: false, // display week numbers along the side? weekNumberWidth: null, // width of all the week-number cells running down the side headRowEl: null, // the fake row element of the day-of-week header // Renders the view into `this.el`, which should already be assigned. // rowCnt, colCnt, and dayNumbersVisible have been calculated by a subclass and passed here. render: function(rowCnt, colCnt, dayNumbersVisible) { // needed for cell-to-date and date-to-cell calculations in View this.rowCnt = rowCnt; this.colCnt = colCnt; this.dayNumbersVisible = dayNumbersVisible; this.weekNumbersVisible = this.opt('weekNumbers'); this.dayGrid.numbersVisible = this.dayNumbersVisible || this.weekNumbersVisible; this.el.addClass('fc-basic-view').html(this.renderHtml()); this.headRowEl = this.el.find('thead .fc-row'); this.scrollerEl = this.el.find('.fc-day-grid-container'); this.dayGrid.coordMap.containerEl = this.scrollerEl; // constrain clicks/etc to the dimensions of the scroller this.dayGrid.el = this.el.find('.fc-day-grid'); this.dayGrid.render(this.hasRigidRows()); View.prototype.render.call(this); // call the super-method }, // Make subcomponents ready for cleanup destroy: function() { this.dayGrid.destroy(); View.prototype.destroy.call(this); // call the super-method }, // Builds the HTML skeleton for the view. // The day-grid component will render inside of a container defined by this HTML. renderHtml: function() { return '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + this.dayGrid.headHtml() + // render the day-of-week headers '
' + '
' + '
' + '
' + '
'; }, // Generates the HTML that will go before the day-of week header cells. // Queried by the DayGrid subcomponent when generating rows. Ordering depends on isRTL. headIntroHtml: function() { if (this.weekNumbersVisible) { return '' + '' + '' + // needed for matchCellWidths htmlEscape(this.opt('weekNumberTitle')) + '' + ''; } }, // Generates the HTML that will go before content-skeleton cells that display the day/week numbers. // Queried by the DayGrid subcomponent. Ordering depends on isRTL. numberIntroHtml: function(row) { if (this.weekNumbersVisible) { return '' + '' + '' + // needed for matchCellWidths this.calendar.calculateWeekNumber(this.cellToDate(row, 0)) + '' + ''; } }, // Generates the HTML that goes before the day bg cells for each day-row. // Queried by the DayGrid subcomponent. Ordering depends on isRTL. dayIntroHtml: function() { if (this.weekNumbersVisible) { return ''; } }, // Generates the HTML that goes before every other type of row generated by DayGrid. Ordering depends on isRTL. // Affects helper-skeleton and highlight-skeleton rows. introHtml: function() { if (this.weekNumbersVisible) { return ''; } }, // Generates the HTML for the s of the "number" row in the DayGrid's content skeleton. // The number row will only exist if either day numbers or week numbers are turned on. numberCellHtml: function(row, col, date) { var classes; if (!this.dayNumbersVisible) { // if there are week numbers but not day numbers return ''; // will create an empty space above events :( } classes = this.dayGrid.getDayClasses(date); classes.unshift('fc-day-number'); return '' + '' + date.date() + ''; }, // Generates an HTML attribute string for setting the width of the week number column, if it is known weekNumberStyleAttr: function() { if (this.weekNumberWidth !== null) { return 'style="width:' + this.weekNumberWidth + 'px"'; } return ''; }, // Determines whether each row should have a constant height hasRigidRows: function() { var eventLimit = this.opt('eventLimit'); return eventLimit && typeof eventLimit !== 'number'; }, /* Dimensions ------------------------------------------------------------------------------------------------------------------*/ // Refreshes the horizontal dimensions of the view updateWidth: function() { if (this.weekNumbersVisible) { // Make sure all week number cells running down the side have the same width. // Record the width for cells created later. this.weekNumberWidth = matchCellWidths( this.el.find('.fc-week-number') ); } }, // Adjusts the vertical dimensions of the view to the specified values setHeight: function(totalHeight, isAuto) { var eventLimit = this.opt('eventLimit'); var scrollerHeight; // reset all heights to be natural unsetScroller(this.scrollerEl); uncompensateScroll(this.headRowEl); this.dayGrid.destroySegPopover(); // kill the "more" popover if displayed // is the event limit a constant level number? if (eventLimit && typeof eventLimit === 'number') { this.dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after } scrollerHeight = this.computeScrollerHeight(totalHeight); this.setGridHeight(scrollerHeight, isAuto); // is the event limit dynamically calculated? if (eventLimit && typeof eventLimit !== 'number') { this.dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set } if (!isAuto && setPotentialScroller(this.scrollerEl, scrollerHeight)) { // using scrollbars? compensateScroll(this.headRowEl, getScrollbarWidths(this.scrollerEl)); // doing the scrollbar compensation might have created text overflow which created more height. redo scrollerHeight = this.computeScrollerHeight(totalHeight); this.scrollerEl.height(scrollerHeight); this.restoreScroll(); } }, // Sets the height of just the DayGrid component in this view setGridHeight: function(height, isAuto) { if (isAuto) { undistributeHeight(this.dayGrid.rowEls); // let the rows be their natural height with no expanding } else { distributeHeight(this.dayGrid.rowEls, height, true); // true = compensate for height-hogging rows } }, /* Events ------------------------------------------------------------------------------------------------------------------*/ // Renders the given events onto the view and populates the segments array renderEvents: function(events) { this.dayGrid.renderEvents(events); this.updateHeight(); // must compensate for events that overflow the row View.prototype.renderEvents.call(this, events); // call the super-method }, // Retrieves all segment objects that are rendered in the view getSegs: function() { return this.dayGrid.getSegs(); }, // Unrenders all event elements and clears internal segment data destroyEvents: function() { View.prototype.destroyEvents.call(this); // do this before dayGrid's segs have been cleared this.recordScroll(); // removing events will reduce height and mess with the scroll, so record beforehand this.dayGrid.destroyEvents(); // we DON'T need to call updateHeight() because: // A) a renderEvents() call always happens after this, which will eventually call updateHeight() // B) in IE8, this causes a flash whenever events are rerendered }, /* Event Dragging ------------------------------------------------------------------------------------------------------------------*/ // Renders a visual indication of an event being dragged over the view. // A returned value of `true` signals that a mock "helper" event has been rendered. renderDrag: function(start, end, seg) { return this.dayGrid.renderDrag(start, end, seg); }, // Unrenders the visual indication of an event being dragged over the view destroyDrag: function() { this.dayGrid.destroyDrag(); }, /* Selection ------------------------------------------------------------------------------------------------------------------*/ // Renders a visual indication of a selection renderSelection: function(start, end) { this.dayGrid.renderSelection(start, end); }, // Unrenders a visual indications of a selection destroySelection: function() { this.dayGrid.destroySelection(); } });