/* 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. var BasicView = View.extend({ 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 initialize: function() { this.dayGrid = new DayGrid(this); this.coordMap = this.dayGrid.coordMap; // the view's date-to-cell mapping is identical to the subcomponent's }, // Sets the display range and computes all necessary dates setRange: function(range) { View.prototype.setRange.call(this, range); // call the super-method this.dayGrid.breakOnWeeks = /year|month|week/.test(this.intervalUnit); // do before setRange this.dayGrid.setRange(range); }, // Compute the value to feed into setRange. Overrides superclass. computeRange: function(date) { var range = View.prototype.computeRange.call(this, date); // get value from the super-method // year and month views should be aligned with weeks. this is already done for week if (/year|month/.test(range.intervalUnit)) { range.start.startOf('week'); range.start = this.skipHiddenDays(range.start); // make end-of-week if not already if (range.end.weekday()) { range.end.add(1, 'week').startOf('week'); range.end = this.skipHiddenDays(range.end, -1, true); // exclusively move backwards } } return range; }, // Renders the view into `this.el`, which should already be assigned renderDates: function() { this.dayNumbersVisible = this.dayGrid.rowCnt > 1; // TODO: make grid responsible 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.setElement(this.el.find('.fc-day-grid')); this.dayGrid.renderDates(this.hasRigidRows()); }, // Unrenders the content of the view. Since we haven't separated skeleton rendering from date rendering, // always completely kill the dayGrid's rendering. unrenderDates: function() { this.dayGrid.unrenderDates(); this.dayGrid.removeElement(); }, renderBusinessHours: function() { this.dayGrid.renderBusinessHours(); }, // 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.dayGrid.getCell(row, 0).start.format('w') + '' + ''; } }, // 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(cell) { var date = cell.start; 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.removeSegPopover(); // 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); } }, // 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 }, // Retrieves all segment objects that are rendered in the view getEventSegs: function() { return this.dayGrid.getEventSegs(); }, // Unrenders all event elements and clears internal segment data unrenderEvents: function() { this.dayGrid.unrenderEvents(); // 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 }, /* Dragging (for both events and external elements) ------------------------------------------------------------------------------------------------------------------*/ // A returned value of `true` signals that a mock "helper" event has been rendered. renderDrag: function(dropLocation, seg) { return this.dayGrid.renderDrag(dropLocation, seg); }, unrenderDrag: function() { this.dayGrid.unrenderDrag(); }, /* Selection ------------------------------------------------------------------------------------------------------------------*/ // Renders a visual indication of a selection renderSelection: function(range) { this.dayGrid.renderSelection(range); }, // Unrenders a visual indications of a selection unrenderSelection: function() { this.dayGrid.unrenderSelection(); } });