美文网首页我爱编程
ace admin calendar页面日历显示为中文

ace admin calendar页面日历显示为中文

作者: 迷你小小白 | 来源:发表于2018-07-26 14:30 被阅读0次

    找到fullcalendar.js,

    找到代码为  isRTL:false,这句话

    输入以下几句

    monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],

        monthNamesShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],

        dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],

        dayNamesShort: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],

    buttonText: {

    today: '今天',

    month: '月',

    week: '周',

    day: '天'

    即可显示中文,

    如果出现乱码:请把引入fullcalendar.js的标签加上charset="GBK",就可以了。

    源网站:https://blog.csdn.net/yangxiaovip/article/details/11951971

    *!

     * FullCalendar v1.6.1

     * Docs & License: http://arshaw.com/fullcalendar/

     * (c) 2013 Adam Shaw

     */

    /*

     * Use fullcalendar.css for basic styling.

     * For event drag & drop, requires jQuery UI draggable.

     * For event resizing, requires jQuery UI resizable.

     */

    (function($, undefined) {

    ;;

    var defaults = {

    // display

    defaultView: 'month',

    // 设置宽高比例

    aspectRatio: 1.35,

    header: {

    left: 'title',

    center: '',

    right: 'today prev,next'

    },

    weekends: true,

    weekNumbers: false,

    weekNumberCalculation: 'iso',

    weekNumberTitle: 'W',

    // editing

    //editable: false,

    //disableDragging: false,

    //disableResizing: false,

    allDayDefault: true,

    ignoreTimezone: true,

    // event ajax

    lazyFetching: true,

    startParam: 'start',

    endParam: 'end',

    // time formats

    titleFormat: {

    // month: 'MMMM yyyy',月标题

    // week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}",  周标题

    // day: 'dddd, MMM d, yyyy'日标题

    month: "yyyy 年  MMMM",

       week: "yyyy 年 MMMM d[ yyyy]{ '—'[ MMM] d}",

       day: "yyyy 年 MMMM d 日 dddd"

    },

    columnFormat: {

    month: 'ddd',

    week: 'ddd M/d',

    day: 'dddd M/d'

    },

    timeFormat: { // for event elements

    // '': 'h(:mm)t' // default

    "": "HH(:mm) 点 "

    },   

    // locale

    isRTL: false,

    firstDay: 0,

    monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],

        monthNamesShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],

        dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],

        dayNamesShort: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],

    buttonText: {

    prev: "‹",

    next: "›",

    prevYear: "«",

    nextYear: "»",

    today: '今天',

    month: '月',

    week: '周',

    day: '天'

    },

    // jquery-ui theming

    theme: false,

    buttonIcons: {

    prev: 'circle-triangle-w',

    next: 'circle-triangle-e'

    },

    //selectable: false,

    unselectAuto: true,

    dropAccept: '*'

    };

    // right-to-left defaults

    var rtlDefaults = {

    header: {

    left: 'next,prev today',

    center: '',

    right: 'title'

    },

    buttonText: {

    prev: "›",

    next: "‹",

    prevYear: "»",

    nextYear: "«"

    },

    buttonIcons: {

    prev: 'circle-triangle-e',

    next: 'circle-triangle-w'

    }

    };

    ;;

    var fc = $.fullCalendar = { version: "1.6.1" };

    var fcViews = fc.views = {};

    $.fn.fullCalendar = function(options) {

    // method calling

    if (typeof options == 'string') {

    var args = Array.prototype.slice.call(arguments, 1);

    var res;

    this.each(function() {

    var calendar = $.data(this, 'fullCalendar');

    if (calendar && $.isFunction(calendar[options])) {

    var r = calendar[options].apply(calendar, args);

    if (res === undefined) {

    res = r;

    }

    if (options == 'destroy') {

    $.removeData(this, 'fullCalendar');

    }

    }

    });

    if (res !== undefined) {

    return res;

    }

    return this;

    }

    // would like to have this logic in EventManager, but needs to happen before options are recursively extended

    var eventSources = options.eventSources || [];

    delete options.eventSources;

    if (options.events) {

    eventSources.push(options.events);

    delete options.events;

    }

    options = $.extend(true, {},

    defaults,

    (options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},

    options

    );

    this.each(function(i, _element) {

    var element = $(_element);

    var calendar = new Calendar(element, options, eventSources);

    element.data('fullCalendar', calendar); // TODO: look into memory leak implications

    calendar.render();

    });

    return this;

    };

    // function for adding/overriding defaults

    function setDefaults(d) {

    $.extend(true, defaults, d);

    }

    ;;

    function Calendar(element, options, eventSources) {

    var t = this;

    // exports

    t.options = options;

    t.render = render;

    t.destroy = destroy;

    t.refetchEvents = refetchEvents;

    t.reportEvents = reportEvents;

    t.reportEventChange = reportEventChange;

    t.rerenderEvents = rerenderEvents;

    t.changeView = changeView;

    t.select = select;

    t.unselect = unselect;

    t.prev = prev;

    t.next = next;

    t.prevYear = prevYear;

    t.nextYear = nextYear;

    t.today = today;

    t.gotoDate = gotoDate;

    t.incrementDate = incrementDate;

    t.formatDate = function(format, date) { return formatDate(format, date, options) };

    t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) };

    t.getDate = getDate;

    t.getView = getView;

    t.option = option;

    t.trigger = trigger;

    // imports

    EventManager.call(t, options, eventSources);

    var isFetchNeeded = t.isFetchNeeded;

    var fetchEvents = t.fetchEvents;

    // locals

    var _element = element[0];

    var header;

    var headerElement;

    var content;

    var tm; // for making theme classes

    var currentView;

    var viewInstances = {};

    var elementOuterWidth;

    var suggestedViewHeight;

    var absoluteViewElement;

    var resizeUID = 0;

    var ignoreWindowResize = 0;

    var date = new Date();

    var events = [];

    var _dragElement;

    /* Main Rendering

    -----------------------------------------------------------------------------*/

    setYMD(date, options.year, options.month, options.date);

    function render(inc) {

    if (!content) {

    initialRender();

    }else{

    calcSize();

    markSizesDirty();

    markEventsDirty();

    renderView(inc);

    }

    }

    function initialRender() {

    tm = options.theme ? 'ui' : 'fc';

    element.addClass('fc');

    if (options.isRTL) {

    element.addClass('fc-rtl');

    }

    else {

    element.addClass('fc-ltr');

    }

    if (options.theme) {

    element.addClass('ui-widget');

    }

    content = $("

    ")

    .prependTo(element);

    header = new Header(t, options);

    headerElement = header.render();

    if (headerElement) {

    element.prepend(headerElement);

    }

    changeView(options.defaultView);

    $(window).resize(windowResize);

    // needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize

    if (!bodyVisible()) {

    lateRender();

    }

    }

    // called when we know the calendar couldn't be rendered when it was initialized,

    // but we think it's ready now

    function lateRender() {

    setTimeout(function() { // IE7 needs this so dimensions are calculated correctly

    if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once

    renderView();

    }

    },0);

    }

    function destroy() {

    $(window).unbind('resize', windowResize);

    header.destroy();

    content.remove();

    element.removeClass('fc fc-rtl ui-widget');

    }

    function elementVisible() {

    return _element.offsetWidth !== 0;

    }

    function bodyVisible() {

    return $('body')[0].offsetWidth !== 0;

    }

    /* View Rendering

    -----------------------------------------------------------------------------*/

    // TODO: improve view switching (still weird transition in IE, and FF has whiteout problem)

    function changeView(newViewName) {

    if (!currentView || newViewName != currentView.name) {

    ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached

    unselect();

    var oldView = currentView;

    var newViewElement;

    if (oldView) {

    (oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera)

    setMinHeight(content, content.height());

    oldView.element.hide();

    }else{

    setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated

    }

    content.css('overflow', 'hidden');

    currentView = viewInstances[newViewName];

    if (currentView) {

    currentView.element.show();

    }else{

    currentView = viewInstances[newViewName] = new fcViews[newViewName](

    newViewElement = absoluteViewElement =

    // 设置日历面板div样式(设置高度)

    $("

    ")

    .appendTo(content),

    t // the calendar object

    );

    }

    if (oldView) {

    header.deactivateButton(oldView.name);

    }

    header.activateButton(newViewName);

    renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to null

    content.css('overflow', '');

    if (oldView) {

    setMinHeight(content, 1);

    }

    if (!newViewElement) {

    (currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera)

    }

    ignoreWindowResize--;

    }

    }

    function renderView(inc) {

    if (elementVisible()) {

    ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached

    unselect();

    if (suggestedViewHeight === undefined) {

    calcSize();

    }

    var forceEventRender = false;

    if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {

    // view must render an entire new date range (and refetch/render events)

    currentView.render(date, inc || 0); // responsible for clearing events

    setSize(true);

    forceEventRender = true;

    }

    else if (currentView.sizeDirty) {

    // view must resize (and rerender events)

    currentView.clearEvents();

    setSize();

    forceEventRender = true;

    }

    else if (currentView.eventsDirty) {

    currentView.clearEvents();

    forceEventRender = true;

    }

    currentView.sizeDirty = false;

    currentView.eventsDirty = false;

    updateEvents(forceEventRender);

    elementOuterWidth = element.outerWidth();

    header.updateTitle(currentView.title);

    var today = new Date();

    if (today >= currentView.start && today < currentView.end) {

    header.disableButton('today');

    }else{

    header.enableButton('today');

    }

    ignoreWindowResize--;

    currentView.trigger('viewDisplay', _element);

    }

    }

    /* Resizing

    -----------------------------------------------------------------------------*/

    function updateSize() {

    markSizesDirty();

    if (elementVisible()) {

    calcSize();

    setSize();

    unselect();

    currentView.clearEvents();

    currentView.renderEvents(events);

    currentView.sizeDirty = false;

    }

    }

    function markSizesDirty() {

    $.each(viewInstances, function(i, inst) {

    inst.sizeDirty = true;

    });

    }

    function calcSize() {

    if (options.contentHeight) {

    suggestedViewHeight = options.contentHeight;

    }

    else if (options.height) {

    suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content);

    }

    else {

    suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));

    }

    }

    function setSize(dateChanged) { // todo: dateChanged?

    ignoreWindowResize++;

    currentView.setHeight(suggestedViewHeight, dateChanged);

    if (absoluteViewElement) {

    absoluteViewElement.css('position', 'relative');

    absoluteViewElement = null;

    }

    currentView.setWidth(content.width(), dateChanged);

    ignoreWindowResize--;

    }

    function windowResize() {

    if (!ignoreWindowResize) {

    if (currentView.start) { // view has already been rendered

    var uid = ++resizeUID;

    setTimeout(function() { // add a delay

    if (uid == resizeUID && !ignoreWindowResize && elementVisible()) {

    if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {

    ignoreWindowResize++; // in case the windowResize callback changes the height

    updateSize();

    currentView.trigger('windowResize', _element);

    ignoreWindowResize--;

    }

    }

    }, 200);

    }else{

    // calendar must have been initialized in a 0x0 iframe that has just been resized

    lateRender();

    }

    }

    }

    /* Event Fetching/Rendering

    -----------------------------------------------------------------------------*/

    // fetches events if necessary, rerenders events if necessary (or if forced)

    function updateEvents(forceRender) {

    if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) {

    refetchEvents();

    }

    else if (forceRender) {

    rerenderEvents();

    }

    }

    function refetchEvents() {

    fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents

    }

    // called when event data arrives

    function reportEvents(_events) {

    events = _events;

    rerenderEvents();

    }

    // called when a single event's data has been changed

    function reportEventChange(eventID) {

    rerenderEvents(eventID);

    }

    // attempts to rerenderEvents

    function rerenderEvents(modifiedEventID) {

    markEventsDirty();

    if (elementVisible()) {

    currentView.clearEvents();

    currentView.renderEvents(events, modifiedEventID);

    currentView.eventsDirty = false;

    }

    }

    function markEventsDirty() {

    $.each(viewInstances, function(i, inst) {

    inst.eventsDirty = true;

    });

    }

    /* Selection

    -----------------------------------------------------------------------------*/

    function select(start, end, allDay) {

    currentView.select(start, end, allDay===undefined ? true : allDay);

    }

    function unselect() { // safe to be called before renderView

    if (currentView) {

    currentView.unselect();

    }

    }

    /* Date

    -----------------------------------------------------------------------------*/

    function prev() {

    renderView(-1);

    }

    function next() {

    renderView(1);

    }

    function prevYear() {

    addYears(date, -1);

    renderView();

    }

    function nextYear() {

    addYears(date, 1);

    renderView();

    }

    function today() {

    date = new Date();

    renderView();

    }

    function gotoDate(year, month, dateOfMonth) {

    if (year instanceof Date) {

    date = cloneDate(year); // provided 1 argument, a Date

    }else{

    setYMD(date, year, month, dateOfMonth);

    }

    renderView();

    }

    function incrementDate(years, months, days) {

    if (years !== undefined) {

    addYears(date, years);

    }

    if (months !== undefined) {

    addMonths(date, months);

    }

    if (days !== undefined) {

    addDays(date, days);

    }

    renderView();

    }

    function getDate() {

    return cloneDate(date);

    }

    /* Misc

    -----------------------------------------------------------------------------*/

    function getView() {

    return currentView;

    }

    function option(name, value) {

    if (value === undefined) {

    return options[name];

    }

    if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {

    options[name] = value;

    updateSize();

    }

    }

    function trigger(name, thisObj) {

    if (options[name]) {

    return options[name].apply(

    thisObj || _element,

    Array.prototype.slice.call(arguments, 2)

    );

    }

    }

    /* External Dragging

    ------------------------------------------------------------------------*/

    if (options.droppable) {

    $(document)

    .bind('dragstart', function(ev, ui) {

    var _e = ev.target;

    var e = $(_e);

    if (!e.parents('.fc').length) { // not already inside a calendar

    var accept = options.dropAccept;

    if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {

    _dragElement = _e;

    currentView.dragStart(_dragElement, ev, ui);

    }

    }

    })

    .bind('dragstop', function(ev, ui) {

    if (_dragElement) {

    currentView.dragStop(_dragElement, ev, ui);

    _dragElement = null;

    }

    });

    }

    }

    ;;

    function Header(calendar, options) {

    var t = this;

    // exports

    t.render = render;

    t.destroy = destroy;

    t.updateTitle = updateTitle;

    t.activateButton = activateButton;

    t.deactivateButton = deactivateButton;

    t.disableButton = disableButton;

    t.enableButton = enableButton;

    // locals

    var element = $([]);

    var tm;

    function render() {

    tm = options.theme ? 'ui' : 'fc';

    var sections = options.header;

    if (sections) {

    element = $("")

    .append(

    $("")

    .append(renderSection('left'))

    .append(renderSection('center'))

    .append(renderSection('right'))

    );

    return element;

    }

    }

    function destroy() {

    element.remove();

    }

    function renderSection(position) {

    var e = $("");

    var buttonStr = options.header[position];

    if (buttonStr) {

    $.each(buttonStr.split(' '), function(i) {

    if (i > 0) {

    e.append("");

    }

    var prevButton;

    $.each(this.split(','), function(j, buttonName) {

    if (buttonName == 'title') {

    e.append("

    ");

    if (prevButton) {

    prevButton.addClass(tm + '-corner-right');

    }

    prevButton = null;

    }else{

    var buttonClick;

    if (calendar[buttonName]) {

    buttonClick = calendar[buttonName]; // calendar method

    }

    else if (fcViews[buttonName]) {

    buttonClick = function() {

    button.removeClass(tm + '-state-hover'); // forget why

    calendar.changeView(buttonName);

    };

    }

    if (buttonClick) {

    var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?

    var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?

    var button = $(

    "" +

    (icon ?

    "" +

    "" +

    "" :

    text

    ) +

    ""

    )

    .click(function() {

    if (!button.hasClass(tm + '-state-disabled')) {

    buttonClick();

    }

    })

    .mousedown(function() {

    button

    .not('.' + tm + '-state-active')

    .not('.' + tm + '-state-disabled')

    .addClass(tm + '-state-down');

    })

    .mouseup(function() {

    button.removeClass(tm + '-state-down');

    })

    .hover(

    function() {

    button

    .not('.' + tm + '-state-active')

    .not('.' + tm + '-state-disabled')

    .addClass(tm + '-state-hover');

    },

    function() {

    button

    .removeClass(tm + '-state-hover')

    .removeClass(tm + '-state-down');

    }

    )

    .appendTo(e);

    disableTextSelection(button);

    if (!prevButton) {

    button.addClass(tm + '-corner-left');

    }

    prevButton = button;

    }

    }

    });

    if (prevButton) {

    prevButton.addClass(tm + '-corner-right');

    }

    });

    }

    return e;

    }

    function updateTitle(html) {

    element.find('h2')

    .html(html);

    }

    function activateButton(buttonName) {

    element.find('span.fc-button-' + buttonName)

    .addClass(tm + '-state-active');

    }

    function deactivateButton(buttonName) {

    element.find('span.fc-button-' + buttonName)

    .removeClass(tm + '-state-active');

    }

    function disableButton(buttonName) {

    element.find('span.fc-button-' + buttonName)

    .addClass(tm + '-state-disabled');

    }

    function enableButton(buttonName) {

    element.find('span.fc-button-' + buttonName)

    .removeClass(tm + '-state-disabled');

    }

    }

    ;;

    fc.sourceNormalizers = [];

    fc.sourceFetchers = [];

    var ajaxDefaults = {

    dataType: 'json',

    cache: false

    };

    var eventGUID = 1;

    function EventManager(options, _sources) {

    var t = this;

    // exports

    t.isFetchNeeded = isFetchNeeded;

    t.fetchEvents = fetchEvents;

    t.addEventSource = addEventSource;

    t.removeEventSource = removeEventSource;

    t.updateEvent = updateEvent;

    t.renderEvent = renderEvent;

    t.removeEvents = removeEvents;

    t.clientEvents = clientEvents;

    t.normalizeEvent = normalizeEvent;

    // imports

    var trigger = t.trigger;

    var getView = t.getView;

    var reportEvents = t.reportEvents;

    // locals

    var stickySource = { events: [] };

    var sources = [ stickySource ];

    var rangeStart, rangeEnd;

    var currentFetchID = 0;

    var pendingSourceCnt = 0;

    var loadingLevel = 0;

    var cache = [];

    for (var i=0; i<_sources.length; i++) {

    _addEventSource(_sources[i]);

    }

    /* Fetching

    -----------------------------------------------------------------------------*/

    function isFetchNeeded(start, end) {

    return !rangeStart || start < rangeStart || end > rangeEnd;

    }

    function fetchEvents(start, end) {

    rangeStart = start;

    rangeEnd = end;

    cache = [];

    var fetchID = ++currentFetchID;

    var len = sources.length;

    pendingSourceCnt = len;

    for (var i=0; i

    fetchEventSource(sources[i], fetchID);

    }

    }

    function fetchEventSource(source, fetchID) {

    _fetchEventSource(source, function(events) {

    if (fetchID == currentFetchID) {

    if (events) {

    if (options.eventDataTransform) {

    events = $.map(events, options.eventDataTransform);

    }

    if (source.eventDataTransform) {

    events = $.map(events, source.eventDataTransform);

    }

    // TODO: this technique is not ideal for static array event sources.

    //  For arrays, we'll want to process all events right in the beginning, then never again.

    for (var i=0; i

    events[i].source = source;

    normalizeEvent(events[i]);

    }

    cache = cache.concat(events);

    }

    pendingSourceCnt--;

    if (!pendingSourceCnt) {

    reportEvents(cache);

    }

    }

    });

    }

    function _fetchEventSource(source, callback) {

    var i;

    var fetchers = fc.sourceFetchers;

    var res;

    for (i=0; i

    res = fetchers[i](source, rangeStart, rangeEnd, callback);

    if (res === true) {

    // the fetcher is in charge. made its own async request

    return;

    }

    else if (typeof res == 'object') {

    // the fetcher returned a new source. process it

    _fetchEventSource(res, callback);

    return;

    }

    }

    var events = source.events;

    if (events) {

    if ($.isFunction(events)) {

    pushLoading();

    events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {

    callback(events);

    popLoading();

    });

    }

    else if ($.isArray(events)) {

    callback(events);

    }

    else {

    callback();

    }

    }else{

    var url = source.url;

    if (url) {

    var success = source.success;

    var error = source.error;

    var complete = source.complete;

    var data = $.extend({}, source.data || {});

    var startParam = firstDefined(source.startParam, options.startParam);

    var endParam = firstDefined(source.endParam, options.endParam);

    if (startParam) {

    data[startParam] = Math.round(+rangeStart / 1000);

    }

    if (endParam) {

    data[endParam] = Math.round(+rangeEnd / 1000);

    }

    pushLoading();

    $.ajax($.extend({}, ajaxDefaults, source, {

    data: data,

    success: function(events) {

    events = events || [];

    var res = applyAll(success, this, arguments);

    if ($.isArray(res)) {

    events = res;

    }

    callback(events);

    },

    error: function() {

    applyAll(error, this, arguments);

    callback();

    },

    complete: function() {

    applyAll(complete, this, arguments);

    popLoading();

    }

    }));

    }else{

    callback();

    }

    }

    }

    /* Sources

    -----------------------------------------------------------------------------*/

    function addEventSource(source) {

    source = _addEventSource(source);

    if (source) {

    pendingSourceCnt++;

    fetchEventSource(source, currentFetchID); // will eventually call reportEvents

    }

    }

    function _addEventSource(source) {

    if ($.isFunction(source) || $.isArray(source)) {

    source = { events: source };

    }

    else if (typeof source == 'string') {

    source = { url: source };

    }

    if (typeof source == 'object') {

    normalizeSource(source);

    sources.push(source);

    return source;

    }

    }

    function removeEventSource(source) {

    sources = $.grep(sources, function(src) {

    return !isSourcesEqual(src, source);

    });

    // remove all client events from that source

    cache = $.grep(cache, function(e) {

    return !isSourcesEqual(e.source, source);

    });

    reportEvents(cache);

    }

    /* Manipulation

    -----------------------------------------------------------------------------*/

    function updateEvent(event) { // update an existing event

    var i, len = cache.length, e,

    defaultEventEnd = getView().defaultEventEnd, // getView???

    startDelta = event.start - event._start,

    endDelta = event.end ?

    (event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end

    : 0;                                                      // was null and event was just resized

    for (i=0; i

    e = cache[i];

    if (e._id == event._id && e != event) {

    e.start = new Date(+e.start + startDelta);

    if (event.end) {

    if (e.end) {

    e.end = new Date(+e.end + endDelta);

    }else{

    e.end = new Date(+defaultEventEnd(e) + endDelta);

    }

    }else{

    e.end = null;

    }

    e.title = event.title;

    e.url = event.url;

    e.allDay = event.allDay;

    e.className = event.className;

    e.editable = event.editable;

    e.color = event.color;

    e.backgroudColor = event.backgroudColor;

    e.borderColor = event.borderColor;

    e.textColor = event.textColor;

    normalizeEvent(e);

    }

    }

    normalizeEvent(event);

    reportEvents(cache);

    }

    function renderEvent(event, stick) {

    normalizeEvent(event);

    if (!event.source) {

    if (stick) {

    stickySource.events.push(event);

    event.source = stickySource;

    }

    cache.push(event);

    }

    reportEvents(cache);

    }

    function removeEvents(filter) {

    if (!filter) { // remove all

    cache = [];

    // clear all array sources

    for (var i=0; i

    if ($.isArray(sources[i].events)) {

    sources[i].events = [];

    }

    }

    }else{

    if (!$.isFunction(filter)) { // an event ID

    var id = filter + '';

    filter = function(e) {

    return e._id == id;

    };

    }

    cache = $.grep(cache, filter, true);

    // remove events from array sources

    for (var i=0; i

    if ($.isArray(sources[i].events)) {

    sources[i].events = $.grep(sources[i].events, filter, true);

    }

    }

    }

    reportEvents(cache);

    }

    function clientEvents(filter) {

    if ($.isFunction(filter)) {

    return $.grep(cache, filter);

    }

    else if (filter) { // an event ID

    filter += '';

    return $.grep(cache, function(e) {

    return e._id == filter;

    });

    }

    return cache; // else, return all

    }

    /* Loading State

    -----------------------------------------------------------------------------*/

    function pushLoading() {

    if (!loadingLevel++) {

    trigger('loading', null, true);

    }

    }

    function popLoading() {

    if (!--loadingLevel) {

    trigger('loading', null, false);

    }

    }

    /* Event Normalization

    -----------------------------------------------------------------------------*/

    function normalizeEvent(event) {

    var source = event.source || {};

    var ignoreTimezone = firstDefined(source.ignoreTimezone, options.ignoreTimezone);

    event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');

    if (event.date) {

    if (!event.start) {

    event.start = event.date;

    }

    delete event.date;

    }

    event._start = cloneDate(event.start = parseDate(event.start, ignoreTimezone));

    event.end = parseDate(event.end, ignoreTimezone);

    if (event.end && event.end <= event.start) {

    event.end = null;

    }

    event._end = event.end ? cloneDate(event.end) : null;

    if (event.allDay === undefined) {

    event.allDay = firstDefined(source.allDayDefault, options.allDayDefault);

    }

    if (event.className) {

    if (typeof event.className == 'string') {

    event.className = event.className.split(/\s+/);

    }

    }else{

    event.className = [];

    }

    // TODO: if there is no start date, return false to indicate an invalid event

    }

    /* Utils

    ------------------------------------------------------------------------------*/

    function normalizeSource(source) {

    if (source.className) {

    // TODO: repeat code, same code for event classNames

    if (typeof source.className == 'string') {

    source.className = source.className.split(/\s+/);

    }

    }else{

    source.className = [];

    }

    var normalizers = fc.sourceNormalizers;

    for (var i=0; i

    normalizers[i](source);

    }

    }

    function isSourcesEqual(source1, source2) {

    return source1 && source2 && getSourcePrimitive(source1) == getSourcePrimitive(source2);

    }

    function getSourcePrimitive(source) {

    return ((typeof source == 'object') ? (source.events || source.url) : '') || source;

    }

    }

    ;;

    fc.addDays = addDays;

    fc.cloneDate = cloneDate;

    fc.parseDate = parseDate;

    fc.parseISO8601 = parseISO8601;

    fc.parseTime = parseTime;

    fc.formatDate = formatDate;

    fc.formatDates = formatDates;

    /* Date Math

    -----------------------------------------------------------------------------*/

    var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],

    DAY_MS = 86400000,

    HOUR_MS = 3600000,

    MINUTE_MS = 60000;

    function addYears(d, n, keepTime) {

    d.setFullYear(d.getFullYear() + n);

    if (!keepTime) {

    clearTime(d);

    }

    return d;

    }

    function addMonths(d, n, keepTime) { // prevents day overflow/underflow

    if (+d) { // prevent infinite looping on invalid dates

    var m = d.getMonth() + n,

    check = cloneDate(d);

    check.setDate(1);

    check.setMonth(m);

    d.setMonth(m);

    if (!keepTime) {

    clearTime(d);

    }

    while (d.getMonth() != check.getMonth()) {

    d.setDate(d.getDate() + (d < check ? 1 : -1));

    }

    }

    return d;

    }

    function addDays(d, n, keepTime) { // deals with daylight savings

    if (+d) {

    var dd = d.getDate() + n,

    check = cloneDate(d);

    check.setHours(9); // set to middle of day

    check.setDate(dd);

    d.setDate(dd);

    if (!keepTime) {

    clearTime(d);

    }

    fixDate(d, check);

    }

    return d;

    }

    function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes

    if (+d) { // prevent infinite looping on invalid dates

    while (d.getDate() != check.getDate()) {

    d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);

    }

    }

    }

    function addMinutes(d, n) {

    d.setMinutes(d.getMinutes() + n);

    return d;

    }

    function clearTime(d) {

    d.setHours(0);

    d.setMinutes(0);

    d.setSeconds(0); 

    d.setMilliseconds(0);

    return d;

    }

    function cloneDate(d, dontKeepTime) {

    if (dontKeepTime) {

    return clearTime(new Date(+d));

    }

    return new Date(+d);

    }

    function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1

    var i=0, d;

    do {

    d = new Date(1970, i++, 1);

    } while (d.getHours()); // != 0

    return d;

    }

    function skipWeekend(date, inc, excl) {

    inc = inc || 1;

    while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {

    addDays(date, inc);

    }

    return date;

    }

    function dayDiff(d1, d2) { // d1 - d2

    return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);

    }

    function setYMD(date, y, m, d) {

    if (y !== undefined && y != date.getFullYear()) {

    date.setDate(1);

    date.setMonth(0);

    date.setFullYear(y);

    }

    if (m !== undefined && m != date.getMonth()) {

    date.setDate(1);

    date.setMonth(m);

    }

    if (d !== undefined) {

    date.setDate(d);

    }

    }

    /* Date Parsing

    -----------------------------------------------------------------------------*/

    function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true

    if (typeof s == 'object') { // already a Date object

    return s;

    }

    if (typeof s == 'number') { // a UNIX timestamp

    return new Date(s * 1000);

    }

    if (typeof s == 'string') {

    if (s.match(/^\d+(\.\d+)?$/)) { // a UNIX timestamp

    return new Date(parseFloat(s) * 1000);

    }

    if (ignoreTimezone === undefined) {

    ignoreTimezone = true;

    }

    return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);

    }

    // TODO: never return invalid dates (like from new Date()), return null instead

    return null;

    }

    function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false

    // derived from http://delete.me.uk/2005/03/iso8601.html

    // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html

    var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);

    if (!m) {

    return null;

    }

    var date = new Date(m[1], 0, 1);

    if (ignoreTimezone || !m[13]) {

    var check = new Date(m[1], 0, 1, 9, 0);

    if (m[3]) {

    date.setMonth(m[3] - 1);

    check.setMonth(m[3] - 1);

    }

    if (m[5]) {

    date.setDate(m[5]);

    check.setDate(m[5]);

    }

    fixDate(date, check);

    if (m[7]) {

    date.setHours(m[7]);

    }

    if (m[8]) {

    date.setMinutes(m[8]);

    }

    if (m[10]) {

    date.setSeconds(m[10]);

    }

    if (m[12]) {

    date.setMilliseconds(Number("0." + m[12]) * 1000);

    }

    fixDate(date, check);

    }else{

    date.setUTCFullYear(

    m[1],

    m[3] ? m[3] - 1 : 0,

    m[5] || 1

    );

    date.setUTCHours(

    m[7] || 0,

    m[8] || 0,

    m[10] || 0,

    m[12] ? Number("0." + m[12]) * 1000 : 0

    );

    if (m[14]) {

    var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);

    offset *= m[15] == '-' ? 1 : -1;

    date = new Date(+date + (offset * 60 * 1000));

    }

    }

    return date;

    }

    function parseTime(s) { // returns minutes since start of day

    if (typeof s == 'number') { // an hour

    return s * 60;

    }

    if (typeof s == 'object') { // a Date object

    return s.getHours() * 60 + s.getMinutes();

    }

    var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);

    if (m) {

    var h = parseInt(m[1], 10);

    if (m[3]) {

    h %= 12;

    if (m[3].toLowerCase().charAt(0) == 'p') {

    h += 12;

    }

    }

    return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);

    }

    }

    /* Date Formatting

    -----------------------------------------------------------------------------*/

    // TODO: use same function formatDate(date, [date2], format, [options])

    function formatDate(date, format, options) {

    return formatDates(date, null, format, options);

    }

    function formatDates(date1, date2, format, options) {

    options = options || defaults;

    var date = date1,

    otherDate = date2,

    i, len = format.length, c,

    i2, formatter,

    res = '';

    for (i=0; i

    c = format.charAt(i);

    if (c == "'") {

    for (i2=i+1; i2

    if (format.charAt(i2) == "'") {

    if (date) {

    if (i2 == i+1) {

    res += "'";

    }else{

    res += format.substring(i+1, i2);

    }

    i = i2;

    }

    break;

    }

    }

    }

    else if (c == '(') {

    for (i2=i+1; i2

    if (format.charAt(i2) == ')') {

    var subres = formatDate(date, format.substring(i+1, i2), options);

    if (parseInt(subres.replace(/\D/, ''), 10)) {

    res += subres;

    }

    i = i2;

    break;

    }

    }

    }

    else if (c == '[') {

    for (i2=i+1; i2

    if (format.charAt(i2) == ']') {

    var subformat = format.substring(i+1, i2);

    var subres = formatDate(date, subformat, options);

    if (subres != formatDate(otherDate, subformat, options)) {

    res += subres;

    }

    i = i2;

    break;

    }

    }

    }

    else if (c == '{') {

    date = date2;

    otherDate = date1;

    }

    else if (c == '}') {

    date = date1;

    otherDate = date2;

    }

    else {

    for (i2=len; i2>i; i2--) {

    if (formatter = dateFormatters[format.substring(i, i2)]) {

    if (date) {

    res += formatter(date, options);

    }

    i = i2 - 1;

    break;

    }

    }

    if (i2 == i) {

    if (date) {

    res += c;

    }

    }

    }

    }

    return res;

    };

    var dateFormatters = {

    s : function(d){ return d.getSeconds() },

    ss : function(d){ return zeroPad(d.getSeconds()) },

    m : function(d){ return d.getMinutes() },

    mm : function(d){ return zeroPad(d.getMinutes()) },

    h : function(d){ return d.getHours() % 12 || 12 },

    hh : function(d){ return zeroPad(d.getHours() % 12 || 12) },

    H : function(d){ return d.getHours() },

    HH : function(d){ return zeroPad(d.getHours()) },

    d : function(d){ return d.getDate() },

    dd : function(d){ return zeroPad(d.getDate()) },

    ddd : function(d,o){ return o.dayNamesShort[d.getDay()] },

    dddd: function(d,o){ return o.dayNames[d.getDay()] },

    M : function(d){ return d.getMonth() + 1 },

    MM : function(d){ return zeroPad(d.getMonth() + 1) },

    MMM : function(d,o){ return o.monthNamesShort[d.getMonth()] },

    MMMM: function(d,o){ return o.monthNames[d.getMonth()] },

    yy : function(d){ return (d.getFullYear()+'').substring(2) },

    yyyy: function(d){ return d.getFullYear() },

    t : function(d){ return d.getHours() < 12 ? 'a' : 'p' },

    tt : function(d){ return d.getHours() < 12 ? 'am' : 'pm' },

    T : function(d){ return d.getHours() < 12 ? 'A' : 'P' },

    TT : function(d){ return d.getHours() < 12 ? 'AM' : 'PM' },

    u : function(d){ return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") },

    S : function(d){

    var date = d.getDate();

    if (date > 10 && date < 20) {

    return 'th';

    }

    return ['st', 'nd', 'rd'][date%10-1] || 'th';

    },

    w   : function(d, o) { // local

    return o.weekNumberCalculation(d);

    },

    W   : function(d) { // ISO

    return iso8601Week(d);

    }

    };

    fc.dateFormatters = dateFormatters;

    /* thanks jQuery UI (https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js)

     * 

     * Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.

     * @param  date  Date - the date to get the week for

     * @return  number - the number of the week within the year that contains this date

     */

    function iso8601Week(date) {

    var time;

    var checkDate = new Date(date.getTime());

    // Find Thursday of this week starting on Monday

    checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));

    time = checkDate.getTime();

    checkDate.setMonth(0); // Compare with Jan 1

    checkDate.setDate(1);

    return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;

    }

    ;;

    fc.applyAll = applyAll;

    /* Event Date Math

    -----------------------------------------------------------------------------*/

    function exclEndDay(event) {

    if (event.end) {

    return _exclEndDay(event.end, event.allDay);

    }else{

    return addDays(cloneDate(event.start), 1);

    }

    }

    function _exclEndDay(end, allDay) {

    end = cloneDate(end);

    return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);

    }

    function segCmp(a, b) {

    return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);

    }

    function segsCollide(seg1, seg2) {

    return seg1.end > seg2.start && seg1.start < seg2.end;

    }

    /* Event Sorting

    -----------------------------------------------------------------------------*/

    // event rendering utilities

    function sliceSegs(events, visEventEnds, start, end) {

    var segs = [],

    i, len=events.length, event,

    eventStart, eventEnd,

    segStart, segEnd,

    isStart, isEnd;

    for (i=0; i

    event = events[i];

    eventStart = event.start;

    eventEnd = visEventEnds[i];

    if (eventEnd > 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(segCmp);

    }

    // event rendering calculation utilities

    function stackSegs(segs) {

    var levels = [],

    i, len = segs.length, seg,

    j, collide, k;

    for (i=0; i

    seg = segs[i];

    j = 0; // the level index where seg should belong

    while (true) {

    collide = false;

    if (levels[j]) {

    for (k=0; k

    if (segsCollide(levels[j][k], seg)) {

    collide = true;

    break;

    }

    }

    }

    if (collide) {

    j++;

    }else{

    break;

    }

    }

    if (levels[j]) {

    levels[j].push(seg);

    }else{

    levels[j] = [seg];

    }

    }

    return levels;

    }

    /* Event Element Binding

    -----------------------------------------------------------------------------*/

    function lazySegBind(container, segs, bindHandlers) {

    container.unbind('mouseover').mouseover(function(ev) {

    var parent=ev.target, e,

    i, seg;

    while (parent != this) {

    e = parent;

    parent = parent.parentNode;

    }

    if ((i = e._fci) !== undefined) {

    e._fci = undefined;

    seg = segs[i];

    bindHandlers(seg.event, seg.element, seg);

    $(ev.target).trigger(ev);

    }

    ev.stopPropagation();

    });

    }

    /* Element Dimensions

    -----------------------------------------------------------------------------*/

    function setOuterWidth(element, width, includeMargins) {

    for (var i=0, e; i

    e = $(element[i]);

    e.width(Math.max(0, width - hsides(e, includeMargins)));

    }

    }

    function setOuterHeight(element, height, includeMargins) {

    for (var i=0, e; i

    e = $(element[i]);

    e.height(Math.max(0, height - vsides(e, includeMargins)));

    }

    }

    function hsides(element, includeMargins) {

    return hpadding(element) + hborders(element) + (includeMargins ? hmargins(element) : 0);

    }

    function hpadding(element) {

    return (parseFloat($.css(element[0], 'paddingLeft', true)) || 0) +

          (parseFloat($.css(element[0], 'paddingRight', true)) || 0);

    }

    function hmargins(element) {

    return (parseFloat($.css(element[0], 'marginLeft', true)) || 0) +

          (parseFloat($.css(element[0], 'marginRight', true)) || 0);

    }

    function hborders(element) {

    return (parseFloat($.css(element[0], 'borderLeftWidth', true)) || 0) +

          (parseFloat($.css(element[0], 'borderRightWidth', true)) || 0);

    }

    function vsides(element, includeMargins) {

    return vpadding(element) +  vborders(element) + (includeMargins ? vmargins(element) : 0);

    }

    function vpadding(element) {

    return (parseFloat($.css(element[0], 'paddingTop', true)) || 0) +

          (parseFloat($.css(element[0], 'paddingBottom', true)) || 0);

    }

    function vmargins(element) {

    return (parseFloat($.css(element[0], 'marginTop', true)) || 0) +

          (parseFloat($.css(element[0], 'marginBottom', true)) || 0);

    }

    function vborders(element) {

    return (parseFloat($.css(element[0], 'borderTopWidth', true)) || 0) +

          (parseFloat($.css(element[0], 'borderBottomWidth', true)) || 0);

    }

    // 设置日历块大小

    function setMinHeight(element, height) {

    height = (typeof height == 'number' ? height + 'px' : height);

    element.each(function(i, _element) {

    // _element.style.cssText += ';min-height:' + height + ';_height:' + height;

    // why can't we just use .css() ? i forget

    });

    }

    /* Misc Utils

    -----------------------------------------------------------------------------*/

    //TODO: arraySlice

    //TODO: isFunction, grep ?

    function noop() { }

    function cmp(a, b) {

    return a - b;

    }

    function arrayMax(a) {

    return Math.max.apply(Math, a);

    }

    function zeroPad(n) {

    return (n < 10 ? '0' : '') + n;

    }

    function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object

    if (obj[name] !== undefined) {

    return obj[name];

    }

    var parts = name.split(/(?=[A-Z])/),

    i=parts.length-1, res;

    for (; i>=0; i--) {

    res = obj[parts[i].toLowerCase()];

    if (res !== undefined) {

    return res;

    }

    }

    return obj[''];

    }

    function htmlEscape(s) {

    return s.replace(/&/g, '&')

    .replace(/

    .replace(/>/g, '>')

    .replace(/'/g, ''')

    .replace(/"/g, '"')

    .replace(/\n/g, '
    ');

    }

    function cssKey(_element) {

    return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');

    }

    function disableTextSelection(element) {

    element

    .attr('unselectable', 'on')

    .css('MozUserSelect', 'none')

    .bind('selectstart.ui', function() { return false; });

    }

    /*

    function enableTextSelection(element) {

    element

    .attr('unselectable', 'off')

    .css('MozUserSelect', '')

    .unbind('selectstart.ui');

    }

    */

    function markFirstLast(e) {

    e.children()

    .removeClass('fc-first fc-last')

    .filter(':first-child')

    .addClass('fc-first')

    .end()

    .filter(':last-child')

    .addClass('fc-last');

    }

    function setDayID(cell, date) {

    cell.each(function(i, _cell) {

    _cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]);

    // TODO: make a way that doesn't rely on order of classes

    });

    }

    function getSkinCss(event, opt) {

    var source = event.source || {};

    var eventColor = event.color;

    var sourceColor = source.color;

    var optionColor = opt('eventColor');

    var backgroundColor =

    event.backgroundColor ||

    eventColor ||

    source.backgroundColor ||

    sourceColor ||

    opt('eventBackgroundColor') ||

    optionColor;

    var borderColor =

    event.borderColor ||

    eventColor ||

    source.borderColor ||

    sourceColor ||

    opt('eventBorderColor') ||

    optionColor;

    var textColor =

    event.textColor ||

    source.textColor ||

    opt('eventTextColor');

    var statements = [];

    if (backgroundColor) {

    statements.push('background-color:' + backgroundColor);

    }

    if (borderColor) {

    statements.push('border-color:' + borderColor);

    }

    if (textColor) {

    statements.push('color:' + textColor);

    }

    return statements.join(';');

    }

    function applyAll(functions, thisObj, args) {

    if ($.isFunction(functions)) {

    functions = [ functions ];

    }

    if (functions) {

    var i;

    var ret;

    for (i=0; i

    ret = functions[i].apply(thisObj, args) || ret;

    }

    return ret;

    }

    }

    function firstDefined() {

    for (var i=0; i

    if (arguments[i] !== undefined) {

    return arguments[i];

    }

    }

    }

    ;;

    fcViews.month = MonthView;

    function MonthView(element, calendar) {

    var t = this;

    // exports

    t.render = render;

    // imports

    BasicView.call(t, element, calendar, 'month');

    var opt = t.opt;

    var renderBasic = t.renderBasic;

    var formatDate = calendar.formatDate;

    function render(date, delta) {

    if (delta) {

    addMonths(date, delta);

    date.setDate(1);

    }

    var start = cloneDate(date, true);

    start.setDate(1);

    var end = addMonths(cloneDate(start), 1);

    var visStart = cloneDate(start);

    var visEnd = cloneDate(end);

    var firstDay = opt('firstDay');

    var nwe = opt('weekends') ? 0 : 1;

    if (nwe) {

    skipWeekend(visStart);

    skipWeekend(visEnd, -1, true);

    }

    addDays(visStart, -((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));

    addDays(visEnd, (7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);

    var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));

    if (opt('weekMode') == 'fixed') {

    addDays(visEnd, (6 - rowCnt) * 7);

    rowCnt = 6;

    }

    t.title = formatDate(start, opt('titleFormat'));

    t.start = start;

    t.end = end;

    t.visStart = visStart;

    t.visEnd = visEnd;

    renderBasic(rowCnt, nwe ? 5 : 7, true);

    }

    }

    ;;

    fcViews.basicWeek = BasicWeekView;

    function BasicWeekView(element, calendar) {

    var t = this;

    // exports

    t.render = render;

    // imports

    BasicView.call(t, element, calendar, 'basicWeek');

    var opt = t.opt;

    var renderBasic = t.renderBasic;

    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);

    var visEnd = cloneDate(end);

    var weekends = opt('weekends');

    if (!weekends) {

    skipWeekend(visStart);

    skipWeekend(visEnd, -1, true);

    }

    t.title = formatDates(

    visStart,

    addDays(cloneDate(visEnd), -1),

    opt('titleFormat')

    );

    t.start = start;

    t.end = end;

    t.visStart = visStart;

    t.visEnd = visEnd;

    renderBasic(1, weekends ? 7 : 5, false);

    }

    }

    ;;

    fcViews.basicDay = BasicDayView;

    //TODO: when calendar's date starts out on a weekend, shouldn't happen

    function BasicDayView(element, calendar) {

    var t = this;

    // exports

    t.render = render;

    // imports

    BasicView.call(t, element, calendar, 'basicDay');

    var opt = t.opt;

    var renderBasic = t.renderBasic;

    var formatDate = calendar.formatDate;

    function render(date, delta) {

    if (delta) {

    addDays(date, delta);

    if (!opt('weekends')) {

    skipWeekend(date, delta < 0 ? -1 : 1);

    }

    }

    t.title = formatDate(date, opt('titleFormat'));

    t.start = t.visStart = cloneDate(date, true);

    t.end = t.visEnd = addDays(cloneDate(t.start), 1);

    renderBasic(1, 1, false);

    }

    }

    ;;

    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.colContentLeft = colContentLeft;

    t.colContentRight = colContentRight;

    t.dayOfWeekCol = dayOfWeekCol;

    t.dateCell = dateCell;

    t.cellDate = cellDate;

    t.cellIsAllDay = function() { return true };

    t.allDayRow = allDayRow;

    t.allDayBounds = allDayBounds;

    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 clearEvents = t.clearEvents;

    var renderOverlay = t.renderOverlay;

    var clearOverlays = t.clearOverlays;

    var daySelectionMousedown = t.daySelectionMousedown;

    var formatDate = calendar.formatDate;

    // locals

    var table;

    var head;

    var headCells;

    var body;

    var bodyRows;

    var bodyCells;

    var bodyFirstCells;

    var bodyCellTopInners;

    var daySegmentContainer;

    var viewWidth;

    var viewHeight;

    var colWidth;

    var weekNumberWidth;

    var rowCnt, colCnt;

    var coordinateGrid;

    var hoverListener;

    var colContentPositions;

    var rtl, dis, dit;

    var firstDay;

    var nwe; // no weekends? a 0 or 1 for easy computations

    var tm;

    var colFormat;

    var showWeekNumbers;

    var weekNumberTitle;

    var weekNumberFormat;

    /* Rendering

    ------------------------------------------------------------*/

    disableTextSelection(element.addClass('fc-grid'));

    function renderBasic(r, c, showNumbers) {

    rowCnt = r;

    colCnt = c;

    updateOptions();

    var firstTime = !body;

    if (firstTime) {

    buildEventContainer();

    }else{

    clearEvents();

    }

    buildTable(showNumbers);

    }

    function updateOptions() {

    rtl = opt('isRTL');

    if (rtl) {

    dis = -1;

    dit = colCnt - 1;

    }else{

    dis = 1;

    dit = 0;

    }

    firstDay = opt('firstDay');

    nwe = opt('weekends') ? 0 : 1;

    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 =

    $("

    ")

    .appendTo(element);

    }

    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

    cellDate = _cellDate(0, i); // a little confusing. cellDate is local variable. _cellDate is private function

    html += "";

    }

    html += "" +

           "" +

           "";

    // 设置日历块高度

    for (i=0; i

    html += "";

    if (showWeekNumbers) {

    html += "" +

           "

    " +

           "";

    }

    for (j=0; j

    cellDate = _cellDate(i, j); // a little confusing. cellDate is local variable. _cellDate is private function

    cellClasses = [

    'fc-day',

    'fc-' + dayIDs[cellDate.getDay()],

    contentClass

    ];

    if (cellDate.getMonth() != month) {

    cellClasses.push('fc-other-month');

    }

    if (+cellDate == +today) {

    cellClasses.push('fc-today');

    cellClasses.push(tm + '-state-highlight');

    }

    html += "

           " class='" + cellClasses.join(' ') + "'" +

           " data-date='" + formatDate(cellDate, 'yyyy-MM-dd') + "'" +

           ">" + 

           "

    ";

    if (showNumbers) {

    html += "

    " + cellDate.getDate() + "";

    }

    html += "

    " +

           "

    " +

           "" +

           "" +

           "";

    }

    html += "";

    }

    html += "" +

           "";

    lockHeight(); // the unlock happens later, in setHeight()...

    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');

    bodyCellTopInners = 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);

    trigger('dayRender', t, date, $(_cell));

    });

    dayBind(bodyCells);

    }

    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);

    setMinHeight(

    cell.find('> div'),

    (i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell)

    );

    }

    });

    unlockHeight();

    }

    function setWidth(width) {

    viewWidth = width;

    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

    ------------------------------------------------------*/

    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

    var stretchStart = new Date(Math.max(rowStart, overlayStart));

    var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));

    if (stretchStart < stretchEnd) {

    var colStart, colEnd;

    if (rtl) {

    colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;

    colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;

    }else{

    colStart = dayDiff(stretchStart, rowStart);

    colEnd = dayDiff(stretchEnd, rowStart);

    }

    dayBind(

    renderCellOverlay(i, colStart, i, colEnd-1)

    );

    }

    addDays(rowStart, 7);

    addDays(rowEnd, 7);

    }

    }

    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 = dateCell(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 = cellDate(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);

    colContentPositions = new HorizontalPositionCache(function(col) {

    return bodyCellTopInners.eq(col);

    });

    function colContentLeft(col) {

    return colContentPositions.left(col);

    }

    function colContentRight(col) {

    return colContentPositions.right(col);

    }

    function dateCell(date) {

    return {

    row: Math.floor(dayDiff(date, t.visStart) / 7),

    col: dayOfWeekCol(date.getDay())

    };

    }

    function cellDate(cell) {

    return _cellDate(cell.row, cell.col);

    }

    function _cellDate(row, col) {

    return addDays(cloneDate(t.visStart), row*7 + col*dis+dit);

    // what about weekends in middle of week?

    }

    function indexDate(index) {

    return _cellDate(Math.floor(index/colCnt), index%colCnt);

    }

    function dayOfWeekCol(dayOfWeek) {

    return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt) * dis + dit;

    }

    function allDayRow(i) {

    return bodyRows.eq(i);

    }

    function allDayBounds(i) {

    var left = 0;

    if (showWeekNumbers) {

    left += weekNumberWidth;

    }

    return {

    left: left,

    right: viewWidth

    };

    }

    // makes sure height doesn't collapse while we destroy/render new cells

    // (this causes a bad end-user scrollbar jump)

    // TODO: generalize this for all view rendering. (also in Calendar.js)

    function lockHeight() {

    setMinHeight(element, element.height());

    }

    function unlockHeight() {

    setMinHeight(element, 1);

    }

    }

    ;;

    function BasicEventRenderer() {

    var t = this;

    // 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');

    }

    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

    row = stackSegs(sliceSegs(events, visEventsEnds, d1, d2));

    for (j=0; j

    level = row[j];

    for (k=0; k

    seg = level[k];

    seg.row = i;

    seg.level = j; // not needed anymore

    segs.push(seg);

    }

    }

    addDays(d1, 7);

    addDays(d2, 7);

    }

    return segs;

    }

    function bindDaySeg(event, eventElement, seg) {

    if (isEventDraggable(event)) {

    draggableDayEvent(event, eventElement);

    }

    if (seg.isEnd && isEventResizable(event)) {

    resizableDayEvent(event, eventElement, seg);

    }

    eventElementHandlers(event, eventElement);

    // needs to be after, because resizableDayEvent might stopImmediatePropagation on click

    }

    /* Dragging

    ----------------------------------------------------------------------------*/

    function draggableDayEvent(event, eventElement) {

    var hoverListener = getHoverListener();

    var dayDelta;

    eventElement.draggable({

    zIndex: 9,

    delay: 50,

    opacity: opt('dragOpacity'),

    revertDuration: opt('dragRevertDuration'),

    start: function(ev, ui) {

    trigger('eventDragStart', eventElement, event, ev, ui);

    hideEvents(event, eventElement);

    hoverListener.start(function(cell, origCell, rowDelta, colDelta) {

    eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);

    clearOverlays();

    if (cell) {

    //setOverflowHidden(true);

    dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);

    renderDayOverlay(

    addDays(cloneDate(event.start), dayDelta),

    addDays(exclEndDay(event), dayDelta)

    );

    }else{

    //setOverflowHidden(false);

    dayDelta = 0;

    }

    }, ev, 'drag');

    },

    stop: function(ev, ui) {

    hoverListener.stop();

    clearOverlays();

    trigger('eventDragStop', eventElement, event, ev, ui);

    if (dayDelta) {

    eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);

    }else{

    eventElement.css('filter', ''); // clear IE opacity side-effects

    showEvents(event, eventElement);

    }

    //setOverflowHidden(false);

    }

    });

    }

    }

    ;;

    fcViews.agendaWeek = AgendaWeekView;

    function AgendaWeekView(element, calendar) {

    var t = this;

    // exports

    t.render = render;

    // imports

    AgendaView.call(t, element, calendar, 'agendaWeek');

    var opt = t.opt;

    var renderAgenda = t.renderAgenda;

    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);

    var visEnd = cloneDate(end);

    var weekends = opt('weekends');

    if (!weekends) {

    skipWeekend(visStart);

    skipWeekend(visEnd, -1, true);

    }

    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);

    }

    }

    ;;

    fcViews.agendaDay = AgendaDayView;

    function AgendaDayView(element, calendar) {

    var t = this;

    // exports

    t.render = render;

    // imports

    AgendaView.call(t, element, calendar, 'agendaDay');

    var opt = t.opt;

    var renderAgenda = t.renderAgenda;

    var formatDate = calendar.formatDate;

    function render(date, delta) {

    if (delta) {

    addDays(date, delta);

    if (!opt('weekends')) {

    skipWeekend(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);

    }

    }

    ;;

    // 设置周,天面板样式

    setDefaults({

    allDaySlot: false,// 不显示整天区域

    allDayText: '整天',

    firstHour: 6,

    slotMinutes: 30,

    defaultEventMinutes: 50,// 点击后多少毫秒弹出Dialog

    axisFormat: 'HH(:mm)点',

    timeFormat: {

    agenda: "HH:mm{ - HH: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.getSnapHeight = function() { return snapHeight };

    t.getSnapMinutes = function() { return snapMinutes };

    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 slotTableFirstInner;

    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 snapMinutes;

    var snapRatio; // ratio of number of "selection" slots to normal slots. (ex: 1, 2, 4)

    var snapHeight; // holds the pixel hight of a "selection" slot

    var colCnt;

    var slotCnt;

    var coordinateGrid;

    var hoverListener;

    var colContentPositions;

    var slotTopCache = {};

    var savedScrollTop;

    var tm;

    var firstDay;

    var nwe;            // no weekends (int)

    var rtl, dis, dit;  // day index sign / translate

    var minMinute, maxMinute;

    var colFormat;

    var showWeekNumbers;

    var weekNumberTitle;

    var weekNumberFormat;

    /* 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');

    // week # options. (TODO: bad, logic also in other views)

    showWeekNumbers = opt('weekNumbers');

    weekNumberTitle = opt('weekNumberTitle');

    if (opt('weekNumberCalculation') != 'iso') {

    weekNumberFormat = "w";

    }

    else {

    weekNumberFormat = "W";

    }

    snapMinutes = opt('snapMinutes') || opt('slotMinutes');

    }

    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 =

    "" +

    "" +

    "";

    if (showWeekNumbers) {

    s += "";

    }

    else {

    s += " ";

    }

    for (i=0; i

    s +=

    ""; // fc- needed for setDayID

    }

    s +=

    " " +

    "" +

    "" +

    "" +

    "" +

    " ";

    for (i=0; i

    s +=

    "" + // 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 +=

    "" +

    "" +

    ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') +

    "" +

    "" +

    "

    " +

    "" +

    "";

    addMinutes(d, opt('slotMinutes'));

    slotCnt++;

    }

    s +=

    "" +

    "";

    slotTable = $(s).appendTo(slotContent);

    slotTableFirstInner = slotTable.find('div:first');

    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());

    if (showWeekNumbers) {

    var weekText = formatDate(colDate(0), weekNumberFormat);

    if (rtl) {

    weekText = weekText + weekNumberTitle;

    }

    else {

    weekText = weekNumberTitle + weekText;

    }

    dayHead.find('.fc-week-number').text(weekText);

    }

    for (i=0; i

    date = colDate(i);

    headCell = dayHeadCells.eq(i);

    headCell.html(formatDate(date, colFormat));

    bodyCell = dayBodyCells.eq(i);

    if (+date == +today) {

    bodyCell.addClass(tm + '-state-highlight fc-today');

    }else{

    bodyCell.removeClass(tm + '-state-highlight fc-today');

    }

    setDayID(headCell.add(bodyCell), date);

    }

    }

    function setHeight(height, dateChanged) {

    if (height === undefined) {

    height = viewHeight;

    }

    viewHeight = height;

    slotTopCache = {};

    var headHeight = dayBody.position().top;

    var allDayHeight = slotScroller.position().top; // including divider

    var bodyHeight = Math.min( // total body height, including borders

    height - headHeight,   // when scrollbars

    slotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border

    );

    dayBodyFirstCellStretcher

    .height(bodyHeight - vsides(dayBodyFirstCell));

    slotLayer.css('top', headHeight);

    // 设置周和天页面显示背景的高度

    // slotScroller.height(bodyHeight - allDayHeight - 1);

    slotHeight = slotTableFirstInner.height() + 1; // +1 for border

    snapRatio = opt('slotMinutes') / snapMinutes;

    snapHeight = slotHeight / snapRatio;

    if (dateChanged) {

    resetScroll();

    }

    }

    function setWidth(width) {

    viewWidth = width;

    colContentPositions.clear();

    axisWidth = 0;

    setOuterWidth(

    axisFirstCells

    .width('')

    .each(function(i, _cell) {

    axisWidth = Math.max(axisWidth, $(_cell).outerWidth());

    }),

    axisWidth

    );

    var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7)

    //slotTable.width(slotTableWidth);

    gutterWidth = slotScroller.width() - slotTableWidth;

    if (gutterWidth) {

    setOuterWidth(gutterCells, gutterWidth);

    gutterCells

    .show()

    .prev()

    .removeClass('fc-last');

    }else{

    gutterCells

    .hide()

    .prev()

    .addClass('fc-last');

    }

    colWidth = Math.floor((slotTableWidth - axisWidth) / colCnt);

    setOuterWidth(dayHeadCells.slice(0, -1), colWidth);

    }

    function resetScroll() {

    var d0 = zeroDate();

    var scrollDate = cloneDate(d0);

    scrollDate.setHours(opt('firstHour'));

    var top = timePosition(d0, scrollDate) + 1; // +1 for the border

    function scroll() {

    slotScroller.scrollTop(top);

    }

    scroll();

    setTimeout(scroll, 0); // overrides any previous scroll state made by the browser

    }

    function beforeHide() {

    savedScrollTop = slotScroller.scrollTop();

    }

    function afterShow() {

    slotScroller.scrollTop(savedScrollTop);

    }

    /* Slot/Day clicking and binding

    -----------------------------------------------------------------------*/

    function dayBind(cells) {

    cells.click(slotClick)

    .mousedown(daySelectionMousedown);

    }

    function slotBind(cells) {

    cells.click(slotClick)

    .mousedown(slotSelectionMousedown);

    }

    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 rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use data

    if (rowMatch) {

    var mins = parseInt(rowMatch[1]) * opt('slotMinutes');

    var hours = Math.floor(mins/60);

    date.setHours(hours);

    date.setMinutes(mins%60 + minMinute);

    trigger('dayClick', dayBodyCells[col], date, false, ev);

    }else{

    trigger('dayClick', dayBodyCells[col], date, true, ev);

    }

    }

    }

    /* Semi-transparent Overlay Helpers

    -----------------------------------------------------*/

    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) {

    dayBind(

    renderCellOverlay(0, startCol, 0, endCol-1)

    );

    }

    }

    function renderCellOverlay(row0, col0, row1, col1) { // only for all-day?

    var rect = coordinateGrid.rect(row0, col0, row1, col1, slotLayer);

    return renderOverlay(rect, slotLayer);

    }

    function renderSlotOverlay(overlayStart, overlayEnd) {

    var dayStart = cloneDate(t.visStart);

    var dayEnd = addDays(cloneDate(dayStart), 1);

    for (var i=0; i

    var stretchStart = new Date(Math.max(dayStart, overlayStart));

    var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));

    if (stretchStart < stretchEnd) {

    var col = i*dis+dit;

    var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only use it for horizontal coords

    var top = timePosition(dayStart, stretchStart);

    var bottom = timePosition(dayStart, stretchEnd);

    rect.top = top;

    rect.height = bottom - top;

    slotBind(

    renderOverlay(rect, slotContent)

    );

    }

    addDays(dayStart, 1);

    addDays(dayEnd, 1);

    }

    }

    /* Coordinate Utilities

    -----------------------------------------------------------------------------*/

    coordinateGrid = new CoordinateGrid(function(rows, cols) {

    var e, n, p;

    dayHeadCells.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();

    if (opt('allDaySlot')) {

    e = allDayRow;

    n = e.offset().top;

    rows[0] = [n, n+e.outerHeight()];

    }

    var slotTableTop = slotContent.offset().top;

    var slotScrollerTop = slotScroller.offset().top;

    var slotScrollerBottom = slotScrollerTop + slotScroller.outerHeight();

    function constrain(n) {

    return Math.max(slotScrollerTop, Math.min(slotScrollerBottom, n));

    }

    for (var i=0; i

    rows.push([

    constrain(slotTableTop + snapHeight*i),

    constrain(slotTableTop + snapHeight*(i+1))

    ]);

    }

    });

    hoverListener = new HoverListener(coordinateGrid);

    colContentPositions = new HorizontalPositionCache(function(col) {

    return dayBodyCellInners.eq(col);

    });

    function colContentLeft(col) {

    return colContentPositions.left(col);

    }

    function colContentRight(col) {

    return colContentPositions.right(col);

    }

    function dateCell(date) { // "cell" terminology is now confusing

    return {

    row: Math.floor(dayDiff(date, t.visStart) / 7),

    col: dayOfWeekCol(date.getDay())

    };

    }

    function cellDate(cell) {

    var d = colDate(cell.col);

    var slotIndex = cell.row;

    if (opt('allDaySlot')) {

    slotIndex--;

    }

    if (slotIndex >= 0) {

    addMinutes(d, minMinute + slotIndex * snapMinutes);

    }

    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 - 1 + 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 > 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;

    hoverListener.start(function(cell, origCell) {

    clearSelection();

    if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) {

    var d1 = cellDate(origCell);

    var d2 = cellDate(cell);

    dates = [

    d1,

    addMinutes(cloneDate(d1), snapMinutes), // calculate minutes depending on selection slot minutes 

    d2,

    addMinutes(cloneDate(d2), snapMinutes)

    ].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);

    }

    }

    }

    ;;

    function AgendaEventRenderer() {

    var t = this;

    // 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;

    var reportEvents = t.reportEvents;

    var reportEventClear = t.reportEventClear;

    var eventElementHandlers = t.eventElementHandlers;

    var setHeight = t.setHeight;

    var getDaySegmentContainer = t.getDaySegmentContainer;

    var getSlotSegmentContainer = t.getSlotSegmentContainer;

    var getHoverListener = t.getHoverListener;

    var getMaxMinute = t.getMaxMinute;

    var getMinMinute = t.getMinMinute;

    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 getColCnt = t.getColCnt;

    var getColWidth = t.getColWidth;

    var getSnapHeight = t.getSnapHeight;

    var getSnapMinutes = t.getSnapMinutes;

    var getBodyContent = t.getBodyContent;

    var reportEventElement = t.reportEventElement;

    var showEvents = t.showEvents;

    var hideEvents = t.hideEvents;

    var eventDrop = t.eventDrop;

    var eventResize = t.eventResize;

    var renderDayOverlay = t.renderDayOverlay;

    var clearOverlays = t.clearOverlays;

    var calendar = t.calendar;

    var formatDate = calendar.formatDate;

    var formatDates = calendar.formatDates;

    /* Rendering

    ----------------------------------------------------------------------------*/

    function renderEvents(events, modifiedEventId) {

    reportEvents(events);

    var i, len=events.length,

    dayEvents=[],

    slotEvents=[];

    for (i=0; i

    if (events[i].allDay) {

    dayEvents.push(events[i]);

    }else{

    slotEvents.push(events[i]);

    }

    }

    if (opt('allDaySlot')) {

    renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);

    setHeight(); // no params means set to viewHeight

    }

    renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);

    trigger('eventAfterAllRender');

    }

    function clearEvents() {

    reportEventClear();

    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

    level = levels[i];

    for (j=0; j

    seg = level[j];

    seg.row = 0;

    seg.level = i; // not needed anymore

    segs.push(seg);

    }

    }

    return segs;

    }

    function compileSlotSegs(events) {

    var colCnt = getColCnt(),

    minMinute = getMinMinute(),

    maxMinute = getMaxMinute(),

    d = addMinutes(cloneDate(t.visStart), minMinute),

    visEventEnds = $.map(events, slotEventEnd),

    i, col,

    j, level,

    k, seg,

    segs=[];

    for (i=0; i

    col = stackSegs(sliceSegs(events, visEventEnds, d, addMinutes(cloneDate(d), maxMinute-minMinute)));

    countForwardSegs(col);

    for (j=0; j

    level = col[j];

    for (k=0; k

    seg = level[k];

    seg.col = i;

    seg.level = j;

    segs.push(seg);

    }

    }

    addDays(d, 1, true);

    }

    return segs;

    }

    function slotEventEnd(event) {

    if (event.end) {

    return cloneDate(event.end);

    }else{

    return addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));

    }

    }

    // renders events in the 'time slots' at the bottom

    function renderSlotSegs(segs, modifiedEventId) {

    var i, segCnt=segs.length, seg,

    event,

    classes,

    top, bottom,

    colI, levelI, forward,

    leftmost,

    availWidth,

    outerWidth,

    left,

    html='',

    eventElements,

    eventElement,

    triggerRes,

    vsideCache={},

    hsideCache={},

    key, val,

    titleElement,

    height,

    slotSegmentContainer = getSlotSegmentContainer(),

    rtl, dis, dit,

    colCnt = getColCnt();

    if (rtl = opt('isRTL')) {

    dis = -1;

    dit = colCnt - 1;

    }else{

    dis = 1;

    dit = 0;

    }

    // calculate position/dimensions, create html

    for (i=0; i

    seg = segs[i];

    event = seg.event;

    top = timePosition(seg.start, seg.start);

    bottom = timePosition(seg.start, seg.end);

    colI = seg.col;

    levelI = seg.level;

    forward = seg.forward || 0;

    leftmost = colContentLeft(colI*dis + dit);

    availWidth = colContentRight(colI*dis + dit) - leftmost;

    availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS

    if (levelI) {

    // indented and thin

    outerWidth = availWidth / (levelI + forward + 1);

    }else{

    if (forward) {

    // moderately wide, aligned left still

    outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =

    }else{

    // can be entire width, aligned left

    outerWidth = availWidth;

    }

    }

    left = leftmost +                                  // leftmost possible

    (availWidth / (levelI + forward + 1) * levelI) // indentation

    * dis + (rtl ? availWidth - outerWidth : 0);   // rtl

    seg.top = top;

    seg.left = left;

    seg.outerWidth = outerWidth;

    seg.outerHeight = bottom - top;

    html += slotSegHtml(event, seg);

    }

    slotSegmentContainer[0].innerHTML = html; // faster than html()

    eventElements = slotSegmentContainer.children();

    // retrieve elements, run through eventRender callback, bind event handlers

    for (i=0; i

    seg = segs[i];

    event = seg.event;

    eventElement = $(eventElements[i]); // faster than eq()

    triggerRes = trigger('eventRender', event, event, eventElement);

    if (triggerRes === false) {

    eventElement.remove();

    }else{

    if (triggerRes && triggerRes !== true) {

    eventElement.remove();

    eventElement = $(triggerRes)

    .css({

    position: 'absolute',

    top: seg.top,

    left: seg.left

    })

    .appendTo(slotSegmentContainer);

    }

    seg.element = eventElement;

    if (event._id === modifiedEventId) {

    bindSlotSeg(event, eventElement, seg);

    }else{

    eventElement[0]._fci = i; // for lazySegBind

    }

    reportEventElement(event, eventElement);

    }

    }

    lazySegBind(slotSegmentContainer, segs, bindSlotSeg);

    // record event sides and title positions

    for (i=0; i

    seg = segs[i];

    if (eventElement = seg.element) {

    val = vsideCache[key = seg.key = cssKey(eventElement[0])];

    seg.vsides = val === undefined ? (vsideCache[key] = vsides(eventElement, true)) : val;

    val = hsideCache[key];

    seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement, true)) : val;

    titleElement = eventElement.find('.fc-event-title');

    if (titleElement.length) {

    seg.contentTop = titleElement[0].offsetTop;

    }

    }

    }

    // set all positions/dimensions at once

    for (i=0; i

    seg = segs[i];

    if (eventElement = seg.element) {

    eventElement[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';

    height = Math.max(0, seg.outerHeight - seg.vsides);

    eventElement[0].style.height = height + 'px';

    event = seg.event;

    if (seg.contentTop !== undefined && height - seg.contentTop < 10) {

    // not enough room for title, put it in the time (TODO: maybe make both display:inline instead)

    eventElement.find('div.fc-event-time')

    .text(formatDate(event.start, opt('timeFormat')) + ' - ' + event.title);

    eventElement.find('div.fc-event-title')

    .remove();

    }

    trigger('eventAfterRender', event, event, eventElement);

    }

    }

    }

    function slotSegHtml(event, seg) {

    var html = "<";

    var url = event.url;

    var skinCss = getSkinCss(event, opt);

    var classes = ['fc-event', 'fc-event-vert'];

    if (isEventDraggable(event)) {

    classes.push('fc-event-draggable');

    }

    if (seg.isStart) {

    classes.push('fc-event-start');

    }

    if (seg.isEnd) {

    classes.push('fc-event-end');

    }

    classes = classes.concat(event.className);

    if (event.source) {

    classes = classes.concat(event.source.className || []);

    }

    if (url) {

    html += "a href='" + htmlEscape(event.url) + "'";

    }else{

    html += "div";

    }

    html +=

    " class='" + classes.join(' ') + "'" +

    " style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'" +

    ">" +

    "

    " +

    "

    " +

    htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +

    "" +

    "

    " +

    htmlEscape(event.title) +

    "" +

    "" +

    "

    ";

    if (seg.isEnd && isEventResizable(event)) {

    html +=

    "

    =";

    }

    html +=

    "";

    return html;

    }

    function bindDaySeg(event, eventElement, seg) {

    if (isEventDraggable(event)) {

    draggableDayEvent(event, eventElement, seg.isStart);

    }

    if (seg.isEnd && isEventResizable(event)) {

    resizableDayEvent(event, eventElement, seg);

    }

    eventElementHandlers(event, eventElement);

    // needs to be after, because resizableDayEvent might stopImmediatePropagation on click

    }

    function bindSlotSeg(event, eventElement, seg) {

    var timeElement = eventElement.find('div.fc-event-time');

    if (isEventDraggable(event)) {

    draggableSlotEvent(event, eventElement, timeElement);

    }

    if (seg.isEnd && isEventResizable(event)) {

    resizableSlotEvent(event, eventElement, timeElement);

    }

    eventElementHandlers(event, eventElement);

    }

    /* Dragging

    -----------------------------------------------------------------------------------*/

    // when event starts out FULL-DAY

    function draggableDayEvent(event, eventElement, isStart) {

    var origWidth;

    var revert;

    var allDay=true;

    var dayDelta;

    var dis = opt('isRTL') ? -1 : 1;

    var hoverListener = getHoverListener();

    var colWidth = getColWidth();

    var snapHeight = getSnapHeight();

    var snapMinutes = getSnapMinutes();

    var minMinute = getMinMinute();

    eventElement.draggable({

    zIndex: 9,

    opacity: opt('dragOpacity', 'month'), // use whatever the month view was using

    revertDuration: opt('dragRevertDuration'),

    start: function(ev, ui) {

    trigger('eventDragStart', eventElement, event, ev, ui);

    hideEvents(event, eventElement);

    origWidth = eventElement.width();

    hoverListener.start(function(cell, origCell, rowDelta, colDelta) {

    clearOverlays();

    if (cell) {

    //setOverflowHidden(true);

    revert = false;

    dayDelta = colDelta * dis;

    if (!cell.row) {

    // on full-days

    renderDayOverlay(

    addDays(cloneDate(event.start), dayDelta),

    addDays(exclEndDay(event), dayDelta)

    );

    resetElement();

    }else{

    // mouse is over bottom slots

    if (isStart) {

    if (allDay) {

    // convert event to temporary slot-event

    eventElement.width(colWidth - 10); // don't use entire width

    setOuterHeight(

    eventElement,

    snapHeight * Math.round(

    (event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes')) /

    snapMinutes

    )

    );

    eventElement.draggable('option', 'grid', [colWidth, 1]);

    allDay = false;

    }

    }else{

    revert = true;

    }

    }

    revert = revert || (allDay && !dayDelta);

    }else{

    resetElement();

    //setOverflowHidden(false);

    revert = true;

    }

    eventElement.draggable('option', 'revert', revert);

    }, ev, 'drag');

    },

    stop: function(ev, ui) {

    hoverListener.stop();

    clearOverlays();

    trigger('eventDragStop', eventElement, event, ev, ui);

    if (revert) {

    // hasn't moved or is out of bounds (draggable has already reverted)

    resetElement();

    eventElement.css('filter', ''); // clear IE opacity side-effects

    showEvents(event, eventElement);

    }else{

    // changed!

    var minuteDelta = 0;

    if (!allDay) {

    minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / snapHeight)

    * snapMinutes

    + minMinute

    - (event.start.getHours() * 60 + event.start.getMinutes());

    }

    eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);

    }

    //setOverflowHidden(false);

    }

    });

    function resetElement() {

    if (!allDay) {

    eventElement

    .width(origWidth)

    .height('')

    .draggable('option', 'grid', null);

    allDay = true;

    }

    }

    }

    // when event starts out IN TIMESLOTS

    function draggableSlotEvent(event, eventElement, timeElement) {

    var origPosition;

    var allDay=false;

    var dayDelta;

    var minuteDelta;

    var prevMinuteDelta;

    var dis = opt('isRTL') ? -1 : 1;

    var hoverListener = getHoverListener();

    var colCnt = getColCnt();

    var colWidth = getColWidth();

    var snapHeight = getSnapHeight();

    var snapMinutes = getSnapMinutes();

    eventElement.draggable({

    zIndex: 9,

    scroll: false,

    grid: [colWidth, snapHeight],

    axis: colCnt==1 ? 'y' : false,

    opacity: opt('dragOpacity'),

    revertDuration: opt('dragRevertDuration'),

    start: function(ev, ui) {

    trigger('eventDragStart', eventElement, event, ev, ui);

    hideEvents(event, eventElement);

    origPosition = eventElement.position();

    minuteDelta = prevMinuteDelta = 0;

    hoverListener.start(function(cell, origCell, rowDelta, colDelta) {

    eventElement.draggable('option', 'revert', !cell);

    clearOverlays();

    if (cell) {

    dayDelta = colDelta * dis;

    if (opt('allDaySlot') && !cell.row) {

    // over full days

    if (!allDay) {

    // convert to temporary all-day event

    allDay = true;

    timeElement.hide();

    eventElement.draggable('option', 'grid', null);

    }

    renderDayOverlay(

    addDays(cloneDate(event.start), dayDelta),

    addDays(exclEndDay(event), dayDelta)

    );

    }else{

    // on slots

    resetElement();

    }

    }

    }, ev, 'drag');

    },

    drag: function(ev, ui) {

    minuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes;

    if (minuteDelta != prevMinuteDelta) {

    if (!allDay) {

    updateTimeText(minuteDelta);

    }

    prevMinuteDelta = minuteDelta;

    }

    },

    stop: function(ev, ui) {

    var cell = hoverListener.stop();

    clearOverlays();

    trigger('eventDragStop', eventElement, event, ev, ui);

    if (cell && (dayDelta || minuteDelta || allDay)) {

    // changed!

    eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);

    }else{

    // either no change or out-of-bounds (draggable has already reverted)

    resetElement();

    eventElement.css('filter', ''); // clear IE opacity side-effects

    eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position

    updateTimeText(0);

    showEvents(event, eventElement);

    }

    }

    });

    function updateTimeText(minuteDelta) {

    var newStart = addMinutes(cloneDate(event.start), minuteDelta);

    var newEnd;

    if (event.end) {

    newEnd = addMinutes(cloneDate(event.end), minuteDelta);

    }

    timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));

    }

    function resetElement() {

    // convert back to original slot-event

    if (allDay) {

    timeElement.css('display', ''); // show() was causing display=inline

    eventElement.draggable('option', 'grid', [colWidth, snapHeight]);

    allDay = false;

    }

    }

    }

    /* Resizing

    --------------------------------------------------------------------------------------*/

    function resizableSlotEvent(event, eventElement, timeElement) {

    var snapDelta, prevSnapDelta;

    var snapHeight = getSnapHeight();

    var snapMinutes = getSnapMinutes();

    eventElement.resizable({

    handles: {

    s: '.ui-resizable-handle'

    },

    grid: snapHeight,

    start: function(ev, ui) {

    snapDelta = prevSnapDelta = 0;

    hideEvents(event, eventElement);

    eventElement.css('z-index', 9);

    trigger('eventResizeStart', this, event, ev, ui);

    },

    resize: function(ev, ui) {

    // don't rely on ui.size.height, doesn't take grid into account

    snapDelta = Math.round((Math.max(snapHeight, eventElement.height()) - ui.originalSize.height) / snapHeight);

    if (snapDelta != prevSnapDelta) {

    timeElement.text(

    formatDates(

    event.start,

    (!snapDelta && !event.end) ? null : // no change, so don't display time range

    addMinutes(eventEnd(event), snapMinutes*snapDelta),

    opt('timeFormat')

    )

    );

    prevSnapDelta = snapDelta;

    }

    },

    stop: function(ev, ui) {

    trigger('eventResizeStop', this, event, ev, ui);

    if (snapDelta) {

    eventResize(this, event, 0, snapMinutes*snapDelta, ev, ui);

    }else{

    eventElement.css('z-index', 8);

    showEvents(event, eventElement);

    // BUG: if event was really short, need to put title back in span

    }

    }

    });

    }

    }

    function countForwardSegs(levels) {

    var i, j, k, level, segForward, segBack;

    for (i=levels.length-1; i>0; i--) {

    level = levels[i];

    for (j=0; j

    segForward = level[j];

    for (k=0; k

    segBack = levels[i-1][k];

    if (segsCollide(segForward, segBack)) {

    segBack.forward = Math.max(segBack.forward||0, (segForward.forward||0)+1);

    }

    }

    }

    }

    }

    ;;

    function View(element, calendar, viewName) {

    var t = this;

    // exports

    t.element = element;

    t.calendar = calendar;

    t.name = viewName;

    t.opt = opt;

    t.trigger = trigger;

    //t.setOverflowHidden = setOverflowHidden;

    t.isEventDraggable = isEventDraggable;

    t.isEventResizable = isEventResizable;

    t.reportEvents = reportEvents;

    t.eventEnd = eventEnd;

    t.reportEventElement = reportEventElement;

    t.reportEventClear = reportEventClear;

    t.eventElementHandlers = eventElementHandlers;

    t.showEvents = showEvents;

    t.hideEvents = hideEvents;

    t.eventDrop = eventDrop;

    t.eventResize = eventResize;

    // t.title

    // t.start, t.end

    // t.visStart, t.visEnd

    // imports

    var defaultEventEnd = t.defaultEventEnd;

    var normalizeEvent = calendar.normalizeEvent; // in EventManager

    var reportEventChange = calendar.reportEventChange;

    // locals

    var eventsByID = {};

    var eventElements = [];

    var eventElementsByID = {};

    var options = calendar.options;

    function opt(name, viewNameOverride) {

    var v = options[name];

    if (typeof v == 'object') {

    return smartProperty(v, viewNameOverride || viewName);

    }

    return v;

    }

    function trigger(name, thisObj) {

    return calendar.trigger.apply(

    calendar,

    [name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t])

    );

    }

    /*

    function setOverflowHidden(bool) {

    element.css('overflow', bool ? 'hidden' : '');

    }

    */

    function isEventDraggable(event) {

    return isEventEditable(event) && !opt('disableDragging');

    }

    function isEventResizable(event) { // but also need to make sure the seg.isEnd == true

    return isEventEditable(event) && !opt('disableResizing');

    }

    function isEventEditable(event) {

    return firstDefined(event.editable, (event.source || {}).editable, opt('editable'));

    }

    /* Event Data

    ------------------------------------------------------------------------------*/

    // report when view receives new events

    function reportEvents(events) { // events are already normalized at this point

    eventsByID = {};

    var i, len=events.length, event;

    for (i=0; i

    event = events[i];

    if (eventsByID[event._id]) {

    eventsByID[event._id].push(event);

    }else{

    eventsByID[event._id] = [event];

    }

    }

    }

    // returns a Date object for an event's end

    function eventEnd(event) {

    return event.end ? cloneDate(event.end) : defaultEventEnd(event);

    }

    /* Event Elements

    ------------------------------------------------------------------------------*/

    // report when view creates an element for an event

    function reportEventElement(event, element) {

    eventElements.push(element);

    if (eventElementsByID[event._id]) {

    eventElementsByID[event._id].push(element);

    }else{

    eventElementsByID[event._id] = [element];

    }

    }

    function reportEventClear() {

    eventElements = [];

    eventElementsByID = {};

    }

    // attaches eventClick, eventMouseover, eventMouseout

    function eventElementHandlers(event, eventElement) {

    eventElement

    .click(function(ev) {

    if (!eventElement.hasClass('ui-draggable-dragging') &&

    !eventElement.hasClass('ui-resizable-resizing')) {

    return trigger('eventClick', this, event, ev);

    }

    })

    .hover(

    function(ev) {

    trigger('eventMouseover', this, event, ev);

    },

    function(ev) {

    trigger('eventMouseout', this, event, ev);

    }

    );

    // TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)

    // TODO: same for resizing

    }

    function showEvents(event, exceptElement) {

    eachEventElement(event, exceptElement, 'show');

    }

    function hideEvents(event, exceptElement) {

    eachEventElement(event, exceptElement, 'hide');

    }

    function eachEventElement(event, exceptElement, funcName) {

    var elements = eventElementsByID[event._id],

    i, len = elements.length;

    for (i=0; i

    if (!exceptElement || elements[i][0] != exceptElement[0]) {

    elements[i][funcName]();

    }

    }

    }

    /* Event Modification Reporting

    ---------------------------------------------------------------------------------*/

    function eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {

    var oldAllDay = event.allDay;

    var eventId = event._id;

    moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);

    trigger(

    'eventDrop',

    e,

    event,

    dayDelta,

    minuteDelta,

    allDay,

    function() {

    // TODO: investigate cases where this inverse technique might not work

    moveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);

    reportEventChange(eventId);

    },

    ev,

    ui

    );

    reportEventChange(eventId);

    }

    function eventResize(e, event, dayDelta, minuteDelta, ev, ui) {

    var eventId = event._id;

    elongateEvents(eventsByID[eventId], dayDelta, minuteDelta);

    trigger(

    'eventResize',

    e,

    event,

    dayDelta,

    minuteDelta,

    function() {

    // TODO: investigate cases where this inverse technique might not work

    elongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);

    reportEventChange(eventId);

    },

    ev,

    ui

    );

    reportEventChange(eventId);

    }

    /* Event Modification Math

    ---------------------------------------------------------------------------------*/

    function moveEvents(events, dayDelta, minuteDelta, allDay) {

    minuteDelta = minuteDelta || 0;

    for (var e, len=events.length, i=0; i

    e = events[i];

    if (allDay !== undefined) {

    e.allDay = allDay;

    }

    addMinutes(addDays(e.start, dayDelta, true), minuteDelta);

    if (e.end) {

    e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);

    }

    normalizeEvent(e, options);

    }

    }

    function elongateEvents(events, dayDelta, minuteDelta) {

    minuteDelta = minuteDelta || 0;

    for (var e, len=events.length, i=0; i

    e = events[i];

    e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);

    normalizeEvent(e, options);

    }

    }

    }

    ;;

    function DayEventRenderer() {

    var t = this;

    // exports

    t.renderDaySegs = renderDaySegs;

    t.resizableDayEvent = resizableDayEvent;

    // imports

    var opt = t.opt;

    var trigger = t.trigger;

    var isEventDraggable = t.isEventDraggable;

    var isEventResizable = t.isEventResizable;

    var eventEnd = t.eventEnd;

    var reportEventElement = t.reportEventElement;

    var showEvents = t.showEvents;

    var hideEvents = t.hideEvents;

    var eventResize = t.eventResize;

    var getRowCnt = t.getRowCnt;

    var getColCnt = t.getColCnt;

    var getColWidth = t.getColWidth;

    var allDayRow = t.allDayRow;

    var allDayBounds = t.allDayBounds;

    var colContentLeft = t.colContentLeft;

    var colContentRight = t.colContentRight;

    var dayOfWeekCol = t.dayOfWeekCol;

    var dateCell = t.dateCell;

    var compileDaySegs = t.compileDaySegs;

    var getDaySegmentContainer = t.getDaySegmentContainer;

    var bindDaySeg = t.bindDaySeg; //TODO: streamline this

    var formatDates = t.calendar.formatDates;

    var renderDayOverlay = t.renderDayOverlay;

    var clearOverlays = t.clearOverlays;

    var clearSelection = t.clearSelection;

    /* Rendering

    -----------------------------------------------------------------------------*/

    function renderDaySegs(segs, modifiedEventId) {

    var segmentContainer = getDaySegmentContainer();

    var rowDivs;

    var rowCnt = getRowCnt();

    var colCnt = getColCnt();

    var i = 0;

    var rowI;

    var levelI;

    var colHeights;

    var j;

    var segCnt = segs.length;

    var seg;

    var top;

    var k;

    segmentContainer[0].innerHTML = daySegHTML(segs); // faster than .html()

    daySegElementResolve(segs, segmentContainer.children());

    daySegElementReport(segs);

    daySegHandlers(segs, segmentContainer, modifiedEventId);

    daySegCalcHSides(segs);

    daySegSetWidths(segs);

    daySegCalcHeights(segs);

    rowDivs = getRowDivs();

    // set row heights, calculate event tops (in relation to row top)

    for (rowI=0; rowI

    levelI = 0;

    colHeights = [];

    for (j=0; j

    colHeights[j] = 0;

    }

    while (i

    // loop through segs in a row

    top = arrayMax(colHeights.slice(seg.startCol, seg.endCol));

    seg.top = top;

    top += seg.outerHeight;

    for (k=seg.startCol; k

    colHeights[k] = top;

    }

    i++;

    }

    rowDivs[rowI].height(arrayMax(colHeights));

    }

    daySegSetTops(segs, getRowTops(rowDivs));

    }

    function renderTempDaySegs(segs, adjustRow, adjustTop) {

    var tempContainer = $("

    ");

    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

    element = segs[i].element;

    if (element) {

    if (segs[i].row === adjustRow) {

    element.css('top', adjustTop);

    }

    elements.push(element[0]);

    }

    }

    return $(elements);

    }

    function daySegHTML(segs) { // also sets seg.left and seg.outerWidth

    var rtl = opt('isRTL');

    var i;

    var segCnt=segs.length;

    var seg;

    var event;

    var url;

    var classes;

    var bounds = allDayBounds();

    var minLeft = bounds.left;

    var maxLeft = bounds.right;

    var leftCol;

    var rightCol;

    var left;

    var right;

    var skinCss;

    var html = '';

    // calculate desired position/dimensions, create html

    for (i=0; i

    seg = segs[i];

    event = seg.event;

    classes = ['fc-event', 'fc-event-hori'];

    if (isEventDraggable(event)) {

    classes.push('fc-event-draggable');

    }

    if (seg.isStart) {

    classes.push('fc-event-start');

    }

    if (seg.isEnd) {

    classes.push('fc-event-end');

    }

    if (rtl) {

    leftCol = dayOfWeekCol(seg.end.getDay()-1);

    rightCol = dayOfWeekCol(seg.start.getDay());

    left = seg.isEnd ? colContentLeft(leftCol) : minLeft;

    right = seg.isStart ? colContentRight(rightCol) : maxLeft;

    }else{

    leftCol = dayOfWeekCol(seg.start.getDay());

    rightCol = dayOfWeekCol(seg.end.getDay()-1);

    left = seg.isStart ? colContentLeft(leftCol) : minLeft;

    right = seg.isEnd ? colContentRight(rightCol) : maxLeft;

    }

    classes = classes.concat(event.className);

    if (event.source) {

    classes = classes.concat(event.source.className || []);

    }

    url = event.url;

    skinCss = getSkinCss(event, opt);

    if (url) {

    html += "

    }else{

    html += "

    }

    html +=

    " class='" + classes.join(' ') + "'" +

    " style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" +

    ">" +

    "

    ";

    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

    }

    return html;

    }

    function daySegElementResolve(segs, elements) { // sets seg.element

    var i;

    var segCnt = segs.length;

    var seg;

    var event;

    var element;

    var triggerRes;

    for (i=0; i

    seg = segs[i];

    event = seg.event;

    element = $(elements[i]); // faster than .eq()

    triggerRes = trigger('eventRender', event, event, element);

    if (triggerRes === false) {

    element.remove();

    }else{

    if (triggerRes && triggerRes !== true) {

    triggerRes = $(triggerRes)

    .css({

    position: 'absolute',

    left: seg.left

    });

    element.replaceWith(triggerRes);

    element = triggerRes;

    }

    seg.element = element;

    }

    }

    }

    function daySegElementReport(segs) {

    var i;

    var segCnt = segs.length;

    var seg;

    var element;

    for (i=0; i

    seg = segs[i];

    element = seg.element;

    if (element) {

    reportEventElement(seg.event, element);

    }

    }

    }

    function daySegHandlers(segs, segmentContainer, modifiedEventId) {

    var i;

    var segCnt = segs.length;

    var seg;

    var element;

    var event;

    // retrieve elements, run through eventRender callback, bind handlers

    for (i=0; i

    seg = segs[i];

    element = seg.element;

    if (element) {

    event = seg.event;

    if (event._id === modifiedEventId) {

    bindDaySeg(event, element, seg);

    }else{

    element[0]._fci = i; // for lazySegBind

    }

    }

    }

    lazySegBind(segmentContainer, segs, bindDaySeg);

    }

    function daySegCalcHSides(segs) { // also sets seg.key

    var i;

    var segCnt = segs.length;

    var seg;

    var element;

    var key, val;

    var hsideCache = {};

    // record event horizontal sides

    for (i=0; i

    seg = segs[i];

    element = seg.element;

    if (element) {

    key = seg.key = cssKey(element[0]);

    val = hsideCache[key];

    if (val === undefined) {

    val = hsideCache[key] = hsides(element, true);

    }

    seg.hsides = val;

    }

    }

    }

    function daySegSetWidths(segs) {

    var i;

    var segCnt = segs.length;

    var seg;

    var element;

    for (i=0; i

    seg = segs[i];

    element = seg.element;

    if (element) {

    element[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';

    }

    }

    }

    function daySegCalcHeights(segs) {

    var i;

    var segCnt = segs.length;

    var seg;

    var element;

    var key, val;

    var vmarginCache = {};

    // record event heights

    for (i=0; i

    seg = segs[i];

    element = seg.element;

    if (element) {

    key = seg.key; // created in daySegCalcHSides

    val = vmarginCache[key];

    if (val === undefined) {

    val = vmarginCache[key] = vmargins(element);

    }

    seg.outerHeight = element[0].offsetHeight + val;

    }

    }

    }

    function getRowDivs() {

    var i;

    var rowCnt = getRowCnt();

    var rowDivs = [];

    for (i=0; i

    rowDivs[i] = allDayRow(i)

    .find('div.fc-day-content > div'); // optimal selector?

    }

    return rowDivs;

    }

    function getRowTops(rowDivs) {

    var i;

    var rowCnt = rowDivs.length;

    var tops = [];

    for (i=0; i

    tops[i] = rowDivs[i][0].offsetTop; // !!?? but this means the element needs position:relative if in a table cell!!!!

    }

    return tops;

    }

    function daySegSetTops(segs, rowTops) { // also triggers eventAfterRender

    var i;

    var segCnt = segs.length;

    var seg;

    var element;

    var event;

    for (i=0; i

    seg = segs[i];

    element = seg.element;

    if (element) {

    element[0].style.top = rowTops[seg.row] + (seg.top||0) + 'px';

    event = seg.event;

    trigger('eventAfterRender', event, event, element);

    }

    }

    }

    /* Resizing

    -----------------------------------------------------------------------------------*/

    function resizableDayEvent(event, element, seg) {

    var rtl = opt('isRTL');

    var direction = rtl ? 'w' : 'e';

    var handle = element.find('.ui-resizable-' + direction); // TODO: stop using this class because we aren't using jqui for this

    var isResizing = false;

    // TODO: look into using jquery-ui mouse widget for this stuff

    disableTextSelection(element); // prevent native selection for IE

    element

    .mousedown(function(ev) { // prevent native selection for others

    ev.preventDefault();

    })

    .click(function(ev) {

    if (isResizing) {

    ev.preventDefault(); // prevent link from being visited (only method that worked in IE6)

    ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called

                                  // (eventElementHandlers needs to be bound after resizableDayEvent)

    }

    });

    handle.mousedown(function(ev) {

    if (ev.which != 1) {

    return; // needs to be left mouse button

    }

    isResizing = true;

    var hoverListener = t.getHoverListener();

    var rowCnt = getRowCnt();

    var colCnt = getColCnt();

    var dis = rtl ? -1 : 1;

    var dit = rtl ? colCnt-1 : 0;

    var elementTop = element.css('top');

    var dayDelta;

    var helpers;

    var eventCopy = $.extend({}, event);

    var minCell = dateCell(event.start);

    clearSelection();

    $('body')

    .css('cursor', direction + '-resize')

    .one('mouseup', mouseup);

    trigger('eventResizeStart', this, event, ev);

    hoverListener.start(function(cell, origCell) {

    if (cell) {

    var r = Math.max(minCell.row, cell.row);

    var c = cell.col;

    if (rowCnt == 1) {

    r = 0; // hack for all-day area in agenda views

    }

    if (r == minCell.row) {

    if (rtl) {

    c = Math.min(minCell.col, c);

    }else{

    c = Math.max(minCell.col, c);

    }

    }

    dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);

    var newEnd = addDays(eventEnd(event), dayDelta, true);

    if (dayDelta) {

    eventCopy.end = newEnd;

    var oldHelpers = helpers;

    helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);

    helpers.find('*').css('cursor', direction + '-resize');

    if (oldHelpers) {

    oldHelpers.remove();

    }

    hideEvents(event);

    }else{

    if (helpers) {

    showEvents(event);

    helpers.remove();

    helpers = null;

    }

    }

    clearOverlays();

    renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start

    }

    }, ev);

    function mouseup(ev) {

    trigger('eventResizeStop', this, event, ev);

    $('body').css('cursor', '');

    hoverListener.stop();

    clearOverlays();

    if (dayDelta) {

    eventResize(this, event, dayDelta, 0, ev);

    // event redraw will clear helpers

    }

    // otherwise, the drag handler already restored the old events

    setTimeout(function() { // make this happen after the element's click event

    isResizing = false;

    },0);

    }

    });

    }

    }

    ;;

    //BUG: unselect needs to be triggered when events are dragged+dropped

    function SelectionManager() {

    var t = this;

    // exports

    t.select = select;

    t.unselect = unselect;

    t.reportSelection = reportSelection;

    t.daySelectionMousedown = daySelectionMousedown;

    // imports

    var opt = t.opt;

    var trigger = t.trigger;

    var defaultSelectionEnd = t.defaultSelectionEnd;

    var renderSelection = t.renderSelection;

    var clearSelection = t.clearSelection;

    // locals

    var selected = false;

    // unselectAuto

    if (opt('selectable') && opt('unselectAuto')) {

    $(document).mousedown(function(ev) {

    var ignore = opt('unselectCancel');

    if (ignore) {

    if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match

    return;

    }

    }

    unselect(ev);

    });

    }

    function select(startDate, endDate, allDay) {

    unselect();

    if (!endDate) {

    endDate = defaultSelectionEnd(startDate, allDay);

    }

    renderSelection(startDate, endDate, allDay);

    reportSelection(startDate, endDate, allDay);

    }

    function unselect(ev) {

    if (selected) {

    selected = false;

    clearSelection();

    trigger('unselect', null, ev);

    }

    }

    function reportSelection(startDate, endDate, allDay, ev) {

    selected = true;

    trigger('select', null, startDate, endDate, allDay, ev);

    }

    function daySelectionMousedown(ev) { // not really a generic manager method, oh well

    var cellDate = t.cellDate;

    var cellIsAllDay = t.cellIsAllDay;

    var hoverListener = t.getHoverListener();

    var reportDayClick = t.reportDayClick; // this is hacky and sort of weird

    if (ev.which == 1 && opt('selectable')) { // which==1 means left mouse button

    unselect(ev);

    var _mousedownElement = this;

    var dates;

    hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell

    clearSelection();

    if (cell && cellIsAllDay(cell)) {

    dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);

    renderSelection(dates[0], dates[1], true);

    }else{

    dates = null;

    }

    }, ev);

    $(document).one('mouseup', function(ev) {

    hoverListener.stop();

    if (dates) {

    if (+dates[0] == +dates[1]) {

    reportDayClick(dates[0], true, ev);

    }

    reportSelection(dates[0], dates[1], true, ev);

    }

    });

    }

    }

    }

    ;;

    function OverlayManager() {

    var t = this;

    // exports

    t.renderOverlay = renderOverlay;

    t.clearOverlays = clearOverlays;

    // locals

    var usedOverlays = [];

    var unusedOverlays = [];

    function renderOverlay(rect, parent) {

    var e = unusedOverlays.shift();

    if (!e) {

    e = $("

    ");

    }

    if (e[0].parentNode != parent[0]) {

    e.appendTo(parent);

    }

    usedOverlays.push(e.css(rect).show());

    return e;

    }

    function clearOverlays() {

    var e;

    while (e = usedOverlays.shift()) {

    unusedOverlays.push(e.hide().unbind());

    }

    }

    }

    ;;

    function CoordinateGrid(buildFunc) {

    var t = this;

    var rows;

    var cols;

    t.build = function() {

    rows = [];

    cols = [];

    buildFunc(rows, cols);

    };

    t.cell = function(x, y) {

    var rowCnt = rows.length;

    var colCnt = cols.length;

    var i, r=-1, c=-1;

    for (i=0; i

    if (y >= rows[i][0] && y < rows[i][1]) {

    r = i;

    break;

    }

    }

    for (i=0; i

    if (x >= cols[i][0] && x < cols[i][1]) {

    c = i;

    break;

    }

    }

    return (r>=0 && c>=0) ? { row:r, col:c } : null;

    };

    t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive

    var origin = originElement.offset();

    return {

    top: rows[row0][0] - origin.top,

    left: cols[col0][0] - origin.left,

    width: cols[col1][1] - cols[col0][0],

    height: rows[row1][1] - rows[row0][0]

    };

    };

    }

    ;;

    function HoverListener(coordinateGrid) {

    var t = this;

    var bindType;

    var change;

    var firstCell;

    var cell;

    t.start = function(_change, ev, _bindType) {

    change = _change;

    firstCell = cell = null;

    coordinateGrid.build();

    mouse(ev);

    bindType = _bindType || 'mousemove';

    $(document).bind(bindType, mouse);

    };

    function mouse(ev) {

    _fixUIEvent(ev); // see below

    var newCell = coordinateGrid.cell(ev.pageX, ev.pageY);

    if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {

    if (newCell) {

    if (!firstCell) {

    firstCell = newCell;

    }

    change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);

    }else{

    change(newCell, firstCell);

    }

    cell = newCell;

    }

    }

    t.stop = function() {

    $(document).unbind(bindType, mouse);

    return cell;

    };

    }

    // this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1)

    // upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem

    // but keep this in here for 1.8.16 users

    // and maybe remove it down the line

    function _fixUIEvent(event) { // for issue 1168

    if (event.pageX === undefined) {

    event.pageX = event.originalEvent.pageX;

    event.pageY = event.originalEvent.pageY;

    }

    }

    ;;

    function HorizontalPositionCache(getElement) {

    var t = this,

    elements = {},

    lefts = {},

    rights = {};

    function e(i) {

    return elements[i] = elements[i] || getElement(i);

    }

    t.left = function(i) {

    return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];

    };

    t.right = function(i) {

    return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];

    };

    t.clear = function() {

    elements = {};

    lefts = {};

    rights = {};

    };

    }

    ;;

    })(jQuery);

    相关文章

      网友评论

        本文标题:ace admin calendar页面日历显示为中文

        本文链接:https://www.haomeiwen.com/subject/puszvxtx.html