almost at 1.2
This commit is contained in:
parent
05a4a07073
commit
ff281feb33
7 changed files with 799 additions and 419 deletions
|
@ -3,6 +3,9 @@ version 1.2
|
|||
- cssClass attribute for CalEvents
|
||||
- multiple event sources (using an array for the 'events' option)
|
||||
- the 'events' option for fullCalendar() and gcalFullCalendar() is now optional
|
||||
- bugs w/ month date formatting
|
||||
- change behavior for parsing number strings (now as unix timestamp)
|
||||
- allow multiple classes in cssClass
|
||||
|
||||
version 1.1 (5/10/09)
|
||||
- Added the following options:
|
||||
|
|
|
@ -188,3 +188,6 @@ latex_documents = [
|
|||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
||||
|
||||
highlight_language = 'javascript'
|
||||
|
||||
|
|
455
docs/index.txt
455
docs/index.txt
|
@ -1,31 +1,21 @@
|
|||
|
||||
.. highlight:: javascript
|
||||
Main Usage
|
||||
==========
|
||||
|
||||
Usage
|
||||
=====
|
||||
The following code initializes a FullCalendar within an element with ID 'calendar'::
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
$('#myCalendar').fullCalendar({
|
||||
// initializes a calendar
|
||||
// see options, data provider, and triggered events below
|
||||
});
|
||||
$('#calendar').fullCalendar({
|
||||
|
||||
$('#myCalendar').fullCalendar('nextMonth'); // move ahead one month
|
||||
// put your options here
|
||||
|
||||
$('#myCalendar').fullCalendar('currentMonth'); // go to current month
|
||||
})
|
||||
|
||||
$('#myCalendar').fullCalendar('prevMonth'); // move back one month
|
||||
|
||||
$('#myCalendar').fullCalendar('gotoMonth', year, month);
|
||||
// go to an arbitrary month. 'month' is zero-based
|
||||
|
||||
$('#myCalender').fullCalendar('refresh');
|
||||
// re-fetch events for the current month
|
||||
|
||||
|
||||
Options
|
||||
=======
|
||||
.. _GeneralOptions:
|
||||
|
||||
General Options
|
||||
===============
|
||||
|
||||
**year**, **month**: integers
|
||||
The month that will be displayed when the calendar first loads.
|
||||
|
@ -35,18 +25,11 @@ Options
|
|||
Determines if all events on the calendar can be dragged & dropped. If
|
||||
``true``, requires `jQuery UI <http://jqueryui.com/>`_ core and draggables.
|
||||
Can be overridden on a per-event basis with the ``draggable`` property of
|
||||
each :ref:`CalEvent <CalEvent>` object.
|
||||
each :ref:`CalEvent <CalEvents>`.
|
||||
|
||||
**fixedWeeks**: boolean, default:``true``
|
||||
If ``true``, the calendar will always be 6 weeks tall. If ``false``, the
|
||||
calendar's height will vary per month.
|
||||
|
||||
**weekStart**: integer, default:``0``
|
||||
The day-of-week each week begins. 0 = Sunday (default),
|
||||
1 = Monday (for UK users), 2 = Tuesday, etc.
|
||||
|
||||
**rightToLeft**: boolean, default:``false``
|
||||
Displays the calendar right-to-left (for Arabic and Hebrew languages)
|
||||
|
||||
**abbrevDayHeadings**: boolean, default:``true``
|
||||
Whether to display "Sun" versus "Sunday" for days of the week.
|
||||
|
@ -55,42 +38,28 @@ Options
|
|||
Determines whether a title such as "January 2009" will be displayed at the
|
||||
top of the calendar.
|
||||
|
||||
**titleFormat**: string, default:``"Y F"``
|
||||
A string defining format of the title above the calendar. The default
|
||||
"Y F" creates strings such as "January 2009". Use the following
|
||||
codes in your format string (similar to the PHP's date function):
|
||||
|
||||
* **F** - January through December
|
||||
* **m** - 01 through 12 (leading zeros)
|
||||
* **M** - Jan through Dec
|
||||
* **n** - 1 through 12
|
||||
* **Y** - Examples: 1999 or 2003
|
||||
* **y** - Examples: 99 or 03
|
||||
**titleFormat**: string, default:``"F Y"``
|
||||
A string defining the format of the title above the calendar. The default
|
||||
"F Y" creates strings such as "January 2009". Consult the
|
||||
:ref:`$.fullCalendar.formatDate <formatDate>` documentation for a full
|
||||
list of commands.
|
||||
|
||||
**buttons**: boolean/hash, default:``true``
|
||||
Determines whether navigation buttons will be displayed at the top of the
|
||||
calendar. A hash with keys 'today', 'prev', and 'next' will determine if
|
||||
each individual button is displayed. Strings can be provided to change
|
||||
each button's text.
|
||||
calendar. A hash such as ``{today:false, prev:true, next:true}`` can be
|
||||
provided to display only certain buttons. A hash such as
|
||||
``{today:false, prev:"Last Month", next:"Next Month"}`` can be provided
|
||||
to display only certain buttons AND change a button's text.
|
||||
|
||||
**showTime**: boolean/ ``"guess"``, default:``"guess"``
|
||||
Determines if times will be displayed before each event's title.
|
||||
``"guess"`` displays times only for events with non-zero start or end times.
|
||||
|
||||
**timeFormat**: string, default: ``"gx"``
|
||||
A string defining the format of dislayed of event times. The default "gx"
|
||||
creates a string such as "9a". Use the following codes in your format
|
||||
string (similar to PHP's date function):
|
||||
|
||||
* **a** - am or pm
|
||||
* **A** - AM or PM
|
||||
* **x** - a or p
|
||||
* **X** - A or P
|
||||
* **g** - 1 through 12 (hour)
|
||||
* **G** - 0 through 23 (hour, military time)
|
||||
* **h** - 01 through 12 (hour, leading zeros)
|
||||
* **H** - 00 through 23 (hour, military time and leading zeros)
|
||||
* **i** - 00 to 59 (minute, leading zeros)
|
||||
A string defining the format of dislayed event times. The default "gx"
|
||||
creates a string such as "9a". Consult the
|
||||
:ref:`$.fullCalendar.formatDate <formatDate>`
|
||||
documentation for a full list of commands.
|
||||
|
||||
**eventDragOpacity**: float
|
||||
The opacity of an event element while it is being dragged (0.0 - 1.0)
|
||||
|
@ -99,21 +68,91 @@ Options
|
|||
Controls the duration (in milliseconds) of the animation of an event
|
||||
snapping back into place.
|
||||
|
||||
|
||||
.. _EventDataProvider:
|
||||
|
||||
|
||||
.. _TriggeredActions:
|
||||
|
||||
Event Data Provider
|
||||
===================
|
||||
Triggered Actions
|
||||
=================
|
||||
|
||||
The following options are *functions* that get executed every time something
|
||||
special happens:
|
||||
|
||||
**monthDisplay**: function(year, month, monthTitle)
|
||||
Triggered once when the calendar loads and every time the
|
||||
calendar's month is changed. ``month`` is zero-based. ``monthTitle``
|
||||
contains the new title of the month (ex: "January 2009")
|
||||
|
||||
**loading**: function(isLoading)
|
||||
Triggered with a ``true`` argument when the calendar begins fetching
|
||||
events via AJAX. Triggered with ``false`` when done.
|
||||
|
||||
**resize**: function()
|
||||
Triggered after the calendar has recovered from a resize (due to the window
|
||||
being resized).
|
||||
|
||||
``this`` is set to the main element
|
||||
|
||||
**dayClick**: function(dayDate)
|
||||
Triggered when the user clicks on a day. ``dayDate`` is a Date object with
|
||||
it's time set to 00:00:00.
|
||||
|
||||
``this`` is set to the TD element of the clicked day.
|
||||
|
||||
**eventRender**: function(calEvent, element)
|
||||
Triggered before an element is rendered for the given :ref:`CalEvent <CalEvents>`.
|
||||
``element`` is the jQuery element that will be used by default. You can modify
|
||||
this element or return a brand new element that will be used instead.
|
||||
|
||||
This function is great for attaching other jQuery plugins to each event
|
||||
element, such as a `qTip <http://craigsworks.com/projects/qtip/docs/>`_
|
||||
tooltip effect.
|
||||
|
||||
**eventClick**, **eventMouseover**, **eventMouseout**: function(calEvent, jsEvent)
|
||||
Triggered on click/mouseover/mouseout actions for an event.
|
||||
``calEvent`` holds that event's information (date, title, etc).
|
||||
``jsEvent`` holds the native javascript event (with information about click position, etc).
|
||||
|
||||
``this`` is set to the event's element
|
||||
|
||||
For ``eventClick``, return ``false`` to prevent the browser from going to
|
||||
the event's URL.
|
||||
|
||||
**eventDragStart**, **eventDragStop**: function(calEvent, jsEvent, ui)
|
||||
Triggered before/after an event is dragged (but not necessarily moved to a new day).
|
||||
``calEvent`` holds that event's information (date, title, etc).
|
||||
``jsEvent`` holds the native javascript event (with information about click position, etc).
|
||||
``ui`` holds the jQuery UI object.
|
||||
|
||||
``this`` is set to the event's element
|
||||
|
||||
**eventDrop**: function(calEvent, dayDelta, jsEvent, ui)
|
||||
Triggered when dragging stops and the event has moved to a *different* day.
|
||||
``dayDelta`` holds the number of days the event was moved forward (a positive number)
|
||||
or backwards (a negative number).
|
||||
|
||||
``dayDelta`` is elegant for dealing with multi-day and repeating events.
|
||||
If updating a remote database, just add the ``dayDelta`` to the start
|
||||
and end times of all events with the given ``calEvent.id``
|
||||
|
||||
|
||||
|
||||
.. _EventSources:
|
||||
|
||||
Event Feeds and Sources
|
||||
=======================
|
||||
|
||||
The following options determine *how* events get on the calendar:
|
||||
|
||||
**events**: array/string/function
|
||||
An array of :ref:`CalEvent` can be used to hardcode events into the
|
||||
An array of :ref:`CalEvents <CalEvents>` can be used to hardcode events into the
|
||||
calendar.
|
||||
|
||||
Or, a URL can be provided. This URL should return JSON for an array of
|
||||
:ref:`CalEvent`. GET parameters, determined by the ``startParam`` and
|
||||
``endParam`` options, will be inserted into the URL. These parameters
|
||||
indicate the UNIX timestamp of the start of the first visible day
|
||||
(inclusive) and the end of the last visible day (exclusive).
|
||||
:ref:`CalEvents <CalEvents>`. GET parameters, determined by the
|
||||
``startParam`` and ``endParam`` options, will be inserted into the URL.
|
||||
These parameters indicate the UNIX timestamp of the start of the first
|
||||
visible day (inclusive) and the end of the last visible day (exclusive).
|
||||
|
||||
Or, a function can be provided for custom fetching. The function is
|
||||
queried every time event data is needed. The function is passed a ``start``
|
||||
|
@ -140,91 +179,48 @@ Event Data Provider
|
|||
|
||||
}
|
||||
|
||||
**eventSources**: array
|
||||
Similar to the ``events`` options, except one may specify *multiple* sources.
|
||||
For example, one may specify an array of JSON URL's, an array of custom
|
||||
functions, an array of hardcoded event arrays, or any combination.
|
||||
|
||||
**startParam**: string, default:``"start"``
|
||||
A GET parameter of this name will be inserted into the URL when fetching
|
||||
events from a JSON script (when ``event`` is a URL string). The value
|
||||
of this GET parameter will be a UNIX timestamp denoting the start of the
|
||||
first visible day (inclusive).
|
||||
events from a JSON script. The value of this GET parameter will be a UNIX
|
||||
timestamp denoting the start of the first visible day (inclusive).
|
||||
|
||||
**endParam**: string, default:``"end"``
|
||||
A GET parameter of this name will be inserted into the URL when fetching
|
||||
events from a JSON script (when ``event`` is a URL string). The value
|
||||
of this GET parameter will be a UNIX timestamp denoting the end of the
|
||||
last visible day (exclusive).
|
||||
events from a JSON script. The value of this GET parameter will be a UNIX
|
||||
timestamp denoting the end of the last visible day (exclusive).
|
||||
|
||||
**cacheParam**: string, default:``"_"``
|
||||
When using a JSON url, a parameter of this name will
|
||||
automatically be inserted into the URL to prevent the browser from
|
||||
caching the response. The value will be the current millisecond time.
|
||||
|
||||
.. _TriggeredEvents:
|
||||
|
||||
Triggered Events
|
||||
================
|
||||
The following methods can be called on a FullCalendar that has already
|
||||
been initialized:
|
||||
|
||||
**monthDisplay**: function(year, month, monthTitle)
|
||||
Triggered once when the calendar loads and every time the
|
||||
calendar's month is changed. ``month`` is zero-based. ``monthTitle``
|
||||
contains the new title of the month (ex: "January 2009")
|
||||
**.fullCalendar(** ``'addEventSource'``, **source)**
|
||||
Adds an event source. ``source`` may be an array/string/function just as in
|
||||
the ``events`` option. Events will be immediately fetched from this source
|
||||
and placed on the calendar.
|
||||
|
||||
**.fullCalendar(** ``'removeEventSource'``, **source)**
|
||||
Remove an event source. ``source`` must be the original array/string/function.
|
||||
|
||||
**loading**: function(isLoading)
|
||||
Triggered with a ``true`` argument when the calendar begins fetching
|
||||
events via AJAX. Triggered with ``false`` when done.
|
||||
|
||||
**resize**: function()
|
||||
Triggered after the calendar has recovered from a resize (due to the window
|
||||
pane being resized).
|
||||
|
||||
``this`` is set to the main element
|
||||
|
||||
**dayClick**: function(dayDate)
|
||||
Triggered when the user clicks on a day. ``dayDate`` is a Date object with
|
||||
it's time set to 00:00:00.
|
||||
|
||||
``this`` is set to the TD element of the clicked day.
|
||||
|
||||
**eventRender**: function(calEvent, element)
|
||||
Triggered before an element is rendered for the given ``calEvent``.
|
||||
``element`` is the jQuery element that will be used by default. You can modify
|
||||
this element or return a brand new element that will be used instead.
|
||||
|
||||
**eventClick**, **eventMouseover**, **eventMouseout**: function(calEvent, domEvent)
|
||||
Triggered on click/mouseover/mouseout actions for an event.
|
||||
``calEvent`` holds that event's information (date, title, etc).
|
||||
``domEvent`` holds the native DOM event (with information about click position, etc).
|
||||
|
||||
``this`` is set to the event's TABLE element
|
||||
|
||||
For ``eventClick``, return ``false`` to prevent the browser from going to
|
||||
calEvent's URL.
|
||||
|
||||
**eventDragStart**, **eventDragStop**: function(calEvent, domEvent, ui)
|
||||
Triggered before/after an event is dragged (but not necessarily moved to a new day).
|
||||
``calEvent`` holds that event's information (date, title, etc).
|
||||
``domEvent`` holds the native DOM event (with information about click position, etc).
|
||||
``ui`` holds the jQuery UI object.
|
||||
|
||||
``this`` is set to the event's TABLE element
|
||||
|
||||
**eventDrop**: function(calEvent, dayDelta, domEvent, ui)
|
||||
Triggered when dragging stops and the event has moved to a *different* day.
|
||||
``dayDelta`` holds the number of days the event was moved forward (a positive number)
|
||||
or backwards (a negative number).
|
||||
|
||||
``dayDelta`` is elegant for dealing with multi-day and repeating events.
|
||||
If updating a remote database, just add the ``dayDelta`` to the start
|
||||
and end times of all events with the given ``calEvent.id``
|
||||
|
||||
|
||||
.. _CalEvent:
|
||||
|
||||
|
||||
.. _CalEvents:
|
||||
|
||||
CalEvent Objects
|
||||
================
|
||||
|
||||
A ``CalEvent`` is a data structure that frequents FullCalendar's API. It is
|
||||
used when a custom event-fetcher needs to report to the :ref:`EventDataProvider`.
|
||||
It is also used in various :ref:`TriggeredEvents`. Here are the properties of a
|
||||
``CalEvent``\:
|
||||
A CalEvent is a data structure that frequents FullCalendar's API. It is the
|
||||
standardized currency used in :ref:`EventSources`. It is also passed to various
|
||||
:ref:`Triggered Actions <TriggeredActions>`. Here are the properties of a
|
||||
CalEvent:
|
||||
|
||||
**id**: integer/string,
|
||||
Uniquely identifies the given event. Absolutely essential for multi-day
|
||||
|
@ -240,7 +236,7 @@ It is also used in various :ref:`TriggeredEvents`. Here are the properties of a
|
|||
A javascript Date object indicating the date/time an event begins.
|
||||
Events with ambiguous time-of-day should use 00:00:00.
|
||||
|
||||
When reporting to the :ref:`EventDataProvider`, for convenience,
|
||||
In an :ref:`Event Source <EventSources>`, for convenience,
|
||||
one can also use a string in IETF format (ex: "Wed, 18 Oct 2009 13:00:00 EST"),
|
||||
a string in ISO8601 format (ex: "2009-11-05T13:15:30Z") or an integer
|
||||
UNIX timestamp.
|
||||
|
@ -249,9 +245,9 @@ It is also used in various :ref:`TriggeredEvents`. Here are the properties of a
|
|||
A javascript Date object indicating the date/time an event ends
|
||||
(exclusively). If an event has an ambiguous end time, ``end`` should be
|
||||
set to midnight of the next day. This is implied if ``end`` is omitted.
|
||||
(For convenience with the :ref:`EventDataProvider`).
|
||||
(For convenience with an :ref:`Event Source <EventSources>`).
|
||||
|
||||
IETF and ISO8601 strings can be used for the :ref:`EventDataProvider`.
|
||||
IETF and ISO8601 strings can be used with an :ref:`Event Source <EventSources>`.
|
||||
|
||||
**draggable**: boolean (optional)
|
||||
Overrides the master ``draggable`` property for this single event.
|
||||
|
@ -259,20 +255,189 @@ It is also used in various :ref:`TriggeredEvents`. Here are the properties of a
|
|||
**showTime**: boolean/ ``"guess"`` (optional)
|
||||
Overrides the master ``showTime`` property for this single event.
|
||||
|
||||
When giving events to the :ref:`EventDataProvider`, one can include other
|
||||
properties beyond the ones listed. This is useful if you want to earmark your
|
||||
events with additional data to be retrieved later during a
|
||||
:ref:`Triggered Event <TriggeredEvents>`.
|
||||
**className**: string/array (optional)
|
||||
A CSS class (or array of classes) that will be attached to this event's
|
||||
element.
|
||||
|
||||
**source**: array/string/function (automatic)
|
||||
A reference to the original array, JSON URL, or function the event
|
||||
came from. Do not worry about populating this value, FullCalendar will
|
||||
do this automatically.
|
||||
|
||||
The following methods can be called on a FullCalendar that has already been
|
||||
initialized. These methods get/add/remove/update the event elements that
|
||||
currently reside on the calendar. Note that when you are using a JSON feed or custom
|
||||
event source, your event is never *permanently* deleted, because it may be
|
||||
refetched from the source at a later time. It is up to the developer to delete
|
||||
the event(s) from any database.
|
||||
|
||||
**.fullCalendar(** ``'addEvent'``, **calEvent)**
|
||||
Add an event to the current month on-the-fly. ``calEvent`` is an object
|
||||
containing at least an id, title, and start date.
|
||||
|
||||
**.fullCalendar(** ``'updateEvent'``, **calEvent)**
|
||||
Report modifications to the given :ref:`CalEvent <CalEvents>` and redraw.
|
||||
``calEvent`` must be the *actual CalEvent object*, as retrieved from a
|
||||
:ref:`Triggered Action <TriggeredActions>` or ``getEventsById`` (see below).
|
||||
A set of repeating events will all be affected.
|
||||
|
||||
**.fullCalendar(** ``'removeEvent'``, **calEventOrId)**
|
||||
Remove elements belonging to the given :ref:`CalEvent <CalEvents>`. If the
|
||||
event is repeating, all occurences of the event will be removed. The
|
||||
second argument may be a CalEvent's ID, or the CalEvent object itself.
|
||||
|
||||
**.fullCalendar(** ``'getEventsById'`` , **eventId)**
|
||||
Returns a list of :ref:`CalEvents <CalEvents>` with the given ID that are
|
||||
currently being displayed.
|
||||
|
||||
|
||||
|
||||
|
||||
Navigation Methods
|
||||
==================
|
||||
|
||||
Extras
|
||||
The following methods may be called on a FullCalendar that has already been
|
||||
initialized:
|
||||
|
||||
**.fullCalendar(** ``'prevMonth'`` **)**
|
||||
Visits the previous month.
|
||||
|
||||
**.fullCalendar(** ``'nextMonth'`` **)**
|
||||
Visits the next month.
|
||||
|
||||
**.fullCalendar(** ``'gotoMonth'``, **year, month)**
|
||||
Visits an arbitrary month. ``month`` is zero-based (0 is January, 1 is
|
||||
February, etc).
|
||||
|
||||
**.fullCalendar(** ``'today'`` **)**
|
||||
Visits the current month.
|
||||
|
||||
**.fullCalendar(** ``'refresh'`` **)**
|
||||
Refetch and redraw the events for the current month.
|
||||
|
||||
|
||||
|
||||
Locale
|
||||
======
|
||||
|
||||
FullCalendar provides some extra date utilities\:
|
||||
Use the following options to change the calendar's locale:
|
||||
|
||||
**weekStart**: integer, default:``0``
|
||||
The day-of-week each week begins. 0 = Sunday (default),
|
||||
1 = Monday (for UK users), 2 = Tuesday, etc.
|
||||
|
||||
**rightToLeft**: boolean, default:``false``
|
||||
Displays the calendar right-to-left (for Arabic and Hebrew)
|
||||
|
||||
The following *variables* may be reassigned or modified to globally change the
|
||||
text for months and days:
|
||||
|
||||
**$.fullCalendar.monthNames**
|
||||
Default: ``['January', 'February', 'March', ...]``
|
||||
|
||||
**$.fullCalendar.monthAbbrevs**
|
||||
Default: ``['Jan', 'Feb', 'Mar', ...]``
|
||||
|
||||
**$.fullCalendar.dayNames**
|
||||
Default: ``['Sunday', 'Monday', 'Tuesday', ...]``
|
||||
|
||||
**$.fullCalendar.dayAbbrevs**
|
||||
Default: ``['Sun', 'Mon', 'Tue', ...]``
|
||||
|
||||
Notice these variables are attached to the main **$** jQuery object.
|
||||
|
||||
The :ref:`GeneralOptions` ``titleFormat`` and ``timeFormat`` may also be of
|
||||
interest to those wanting to change locale.
|
||||
|
||||
|
||||
|
||||
**$.parseISO8601(string, ignoreTimezone)**
|
||||
Parses an ISO8601 string and returns a ``Date`` object
|
||||
Date Parsing and Formatting
|
||||
===========================
|
||||
|
||||
The following utilities are always available. These typically come in handy
|
||||
when creating a custom event source:
|
||||
|
||||
.. _formatDate:
|
||||
|
||||
**$.fullCalendar.formatDate(date, format)**
|
||||
Format a javascript Date object into a string. ``format`` may contain
|
||||
one or more of the following commands (similar to PHP's date function):
|
||||
|
||||
* **F** - January through December
|
||||
* **M** - Jan through Dec
|
||||
* **n** - 1 through 12 (month)
|
||||
* **m** - 01 through 12 (month, leading zeros)
|
||||
* **Y** - Examples: 1999 or 2003
|
||||
* **y** - Examples: 99 or 03
|
||||
* **a** - am or pm
|
||||
* **A** - AM or PM
|
||||
* **x** - a or p
|
||||
* **X** - A or P
|
||||
* **g** - 1 through 12 (hour)
|
||||
* **G** - 0 through 23 (hour, military time)
|
||||
* **h** - 01 through 12 (hour, leading zeros)
|
||||
* **H** - 00 through 23 (hour, military time and leading zeros)
|
||||
* **i** - 00 to 59 (minute, leading zeros)
|
||||
|
||||
**$.ISO8601String(date)**
|
||||
Takes a ``Date`` object and returns an ISO8601 string
|
||||
**$.fullCalendar.parseDate(string)**
|
||||
Parse a string and return a javascript Date object. The string may be
|
||||
in ISO8601 format, IETF format, or a UNIX timestamp.
|
||||
|
||||
**$.fullCalendar.parseISO8601(string, ignoreTimezone)**
|
||||
Parse an ISO8601 string into a javascript Date object.
|
||||
|
||||
Notice these functions are attached to the main **$** jQuery object.
|
||||
|
||||
|
||||
|
||||
Google Calendar
|
||||
===============
|
||||
|
||||
To integrate with your Google Calendar, you must first **make your calendar public**:
|
||||
|
||||
#. In the Google Calendar interface, locate the "My Calendar" box on the left.
|
||||
|
||||
#. Click the arrow next to the calendar you need.
|
||||
|
||||
#. A menu will appear. Click "Share this calendar."
|
||||
|
||||
#. Check "Make this calendar public."
|
||||
|
||||
#. Make sure "Share only my free/busy information" is *unchecked*.
|
||||
|
||||
#. Click "Save."
|
||||
|
||||
Then, you must obtain your calendar's **XML feed URL**.
|
||||
|
||||
#. In the Google Calendar interface, locate the "My Calendar" box on the left
|
||||
|
||||
#. Click the arrow next to the calendar you need.
|
||||
|
||||
#. A menu will appear. Click "Calendar settings."
|
||||
|
||||
#. In the "Calendar Address" section of the screen, click the XML badge.
|
||||
|
||||
#. Your feed's URL will appear.
|
||||
|
||||
The API for integrating a Google Calendar feed has changed since
|
||||
FullCalendar 1.1. The ``$.fullCalendar.gcalFeed`` function now produces
|
||||
an event source that can be passed to the ``events`` or ``eventSources``
|
||||
option::
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
|
||||
events: $.fullCalendar.gcalFeed(
|
||||
"http://www.google.com/calendar/feeds/...", // feed URL
|
||||
{ className: 'gcal-events' } // optional options
|
||||
)
|
||||
|
||||
});
|
||||
|
||||
Here is a list of available options:
|
||||
|
||||
* **className** - CSS class to attach to each event from this Google Calendar
|
||||
|
||||
* **draggable** - whether to allow dragging (default: ``false``)
|
||||
|
||||
See *gcal.html* in the *examples* directory for a complete example.
|
||||
|
||||
|
|
7
docs/templates/layout.html
vendored
7
docs/templates/layout.html
vendored
|
@ -3,6 +3,13 @@
|
|||
<? fullcalendar_nav() ?>
|
||||
<? begin_content() ?>
|
||||
|
||||
<div id='toc'>
|
||||
<h1>Table of Contents</h1>
|
||||
{{ toc }}
|
||||
</div>
|
||||
|
||||
<div class='clear'></div>
|
||||
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
<? end_content() ?>
|
||||
|
|
|
@ -30,9 +30,12 @@
|
|||
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#calendar').gcalFullCalendar({
|
||||
$('#calendar').fullCalendar({
|
||||
// US Holidays
|
||||
events: 'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic',
|
||||
events: $.fullCalendar.gcalFeed(
|
||||
'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic',
|
||||
{draggable: false, className: 'mygcal'}
|
||||
),
|
||||
eventClick: function(event) {
|
||||
window.open(event.url, 'gcalevent', 'width=700,height=600');
|
||||
return false;
|
||||
|
|
660
fullcalendar.js
660
fullcalendar.js
|
@ -17,19 +17,30 @@
|
|||
(function($) {
|
||||
|
||||
$.fn.fullCalendar = function(options) {
|
||||
|
||||
|
||||
//
|
||||
// Calls methods of a pre-existing instance
|
||||
//
|
||||
|
||||
if (typeof options == 'string') {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var ret; // ugly
|
||||
var res;
|
||||
this.each(function() {
|
||||
var r = $.data(this, 'fullCalendar')[options].apply(this, args);
|
||||
if (typeof ret == 'undefined') ret = r;
|
||||
if (typeof res == 'undefined') res = r;
|
||||
});
|
||||
if (typeof ret == 'undefined')
|
||||
return this;
|
||||
return ret;
|
||||
if (typeof res != 'undefined')
|
||||
return res;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Process options
|
||||
//
|
||||
|
||||
options = options || {};
|
||||
|
||||
var r2l = options.rightToLeft;
|
||||
|
@ -48,77 +59,94 @@
|
|||
var weekStart = (options.weekStart || 0) % 7;
|
||||
var timeFormat = options.timeFormat || 'gx';
|
||||
var titleFormat = options.titleFormat || (r2l ? 'Y F' : 'F Y');
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Rendering bug detection variables
|
||||
//
|
||||
|
||||
var tdTopBug, trTopBug, tbodyTopBug, sniffBugs = true;
|
||||
|
||||
|
||||
|
||||
this.each(function() {
|
||||
|
||||
var date = options.year ? new Date(options.year, options.month || 0, 1) : new Date();
|
||||
var start, end, today, numWeeks;
|
||||
|
||||
//
|
||||
// Instance variables
|
||||
//
|
||||
|
||||
var date = options.year ? // holds the year & month of current month
|
||||
new Date(options.year, options.month || 0, 1) :
|
||||
new Date();
|
||||
var start, end; // first & last VISIBLE dates
|
||||
var today;
|
||||
var numWeeks;
|
||||
var ignoreResizes = false;
|
||||
|
||||
var events = [];
|
||||
var eventSources = options.eventSources || [];
|
||||
if (options.events) eventSources.push(options.events);
|
||||
|
||||
var eventSources;
|
||||
var eo = options.events;
|
||||
if (eo) {
|
||||
if (typeof eo == 'string' || $.isFunction(eo)) {
|
||||
eventSources = [eo];
|
||||
}else{
|
||||
var item = eo[0];
|
||||
if (item) {
|
||||
if (typeof item == 'string' || $.isFunction(item))
|
||||
eventSources = eo;
|
||||
else {
|
||||
eventSources = [eo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else eventSources = [];
|
||||
|
||||
|
||||
//
|
||||
// Month navigation functions
|
||||
//
|
||||
|
||||
function updateMonth() {
|
||||
clearEvents();
|
||||
function refreshMonth() {
|
||||
clearEventElements();
|
||||
render();
|
||||
}
|
||||
|
||||
function today() {
|
||||
date = new Date();
|
||||
updateMonth();
|
||||
}
|
||||
|
||||
function prevMonth() {
|
||||
addMonths(date, -1);
|
||||
updateMonth();
|
||||
refreshMonth();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
addMonths(date, 1);
|
||||
updateMonth();
|
||||
refreshMonth();
|
||||
}
|
||||
|
||||
function gotoToday() {
|
||||
date = new Date();
|
||||
refreshMonth();
|
||||
}
|
||||
|
||||
function gotoMonth(year, month) {
|
||||
date = new Date(year, month, 1);
|
||||
updateMonth();
|
||||
refreshMonth();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Publicly accessible methods
|
||||
//
|
||||
|
||||
$.data(this, 'fullCalendar', {
|
||||
today: today,
|
||||
refresh: refreshMonth,
|
||||
prevMonth: prevMonth,
|
||||
nextMonth: nextMonth,
|
||||
today: gotoToday,
|
||||
gotoMonth: gotoMonth,
|
||||
refresh: updateMonth,
|
||||
|
||||
// event crud
|
||||
|
||||
//
|
||||
// Event CRUD
|
||||
//
|
||||
|
||||
addEvent: function(event) {
|
||||
events.push(normalizeEvent(event));
|
||||
clearEvents();
|
||||
clearEventElements();
|
||||
renderEvents();
|
||||
},
|
||||
|
||||
|
||||
updateEvent: function(event) {
|
||||
event.start = cleanDate(event.start);
|
||||
event.end = cleanDate(event.end);
|
||||
event.start = $.fullCalendar.parseDate(event.start);
|
||||
event.end = $.fullCalendar.parseDate(event.end);
|
||||
var startDelta = event.start - event._start;
|
||||
var msLength = event.end - event.start;
|
||||
event._start = cloneDate(event.start);
|
||||
|
@ -126,8 +154,8 @@
|
|||
var e = events[i];
|
||||
if (e.id === event.id && e !== event) {
|
||||
e.start = new Date(e.start.getTime() + startDelta);
|
||||
e.end = new Date(e.start.getTime() + msLength);
|
||||
e._start = cloneDate(e.start);
|
||||
e.end = new Date(e.start.getTime() + msLength);
|
||||
for (var k in event) {
|
||||
if (k && k != 'start' && k != 'end' && k.charAt(0) != '_') {
|
||||
e[k] = event[k];
|
||||
|
@ -135,14 +163,16 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
clearEvents();
|
||||
clearEventElements();
|
||||
renderEvents();
|
||||
},
|
||||
|
||||
|
||||
removeEvent: function(eventId) {
|
||||
if (typeof eventId == 'object') {
|
||||
eventId = eventId.id;
|
||||
}
|
||||
|
||||
// remove from the 'events' array
|
||||
var newEvents = [];
|
||||
for (var i=0; i<events.length; i++) {
|
||||
if (events[i].id !== eventId) {
|
||||
|
@ -150,6 +180,7 @@
|
|||
}
|
||||
}
|
||||
events = newEvents;
|
||||
|
||||
// remove from static event sources
|
||||
for (var i=0; i<eventSources.length; i++) {
|
||||
var src = eventSources[i];
|
||||
|
@ -163,10 +194,11 @@
|
|||
eventSources[i] = newSrc;
|
||||
}
|
||||
}
|
||||
clearEvents();
|
||||
|
||||
clearEventElements();
|
||||
renderEvents();
|
||||
},
|
||||
|
||||
|
||||
getEventsById: function(eventId) {
|
||||
var res = [];
|
||||
for (var i=0; i<events.length; i++) {
|
||||
|
@ -177,15 +209,23 @@
|
|||
return res;
|
||||
},
|
||||
|
||||
// event source crud
|
||||
|
||||
|
||||
//
|
||||
// Event Source CRUD
|
||||
//
|
||||
|
||||
addEventSource: function(src) {
|
||||
eventSources.push(src);
|
||||
clearEvents();
|
||||
renderEvents();
|
||||
fetchEventSource(src, function() {
|
||||
clearEventElements();
|
||||
renderEvents();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
removeEventSource: function(src) {
|
||||
|
||||
// remove from 'eventSources' array
|
||||
var newSources = [];
|
||||
for (var i=0; i<eventSources.length; i++) {
|
||||
if (src !== eventSources[i]) {
|
||||
|
@ -193,7 +233,17 @@
|
|||
}
|
||||
}
|
||||
eventSources = newSources;
|
||||
clearEvents();
|
||||
|
||||
// remove events from 'events' array
|
||||
var newEvents = [];
|
||||
for (var i=0; i<events.length; i++) {
|
||||
if (events[i].source !== src) {
|
||||
newEvents.push(events[i]);
|
||||
}
|
||||
}
|
||||
events = newEvents;
|
||||
|
||||
clearEventElements();
|
||||
renderEvents();
|
||||
}
|
||||
|
||||
|
@ -203,16 +253,26 @@
|
|||
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
//
|
||||
// Header & Table Rendering
|
||||
//
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
//
|
||||
// Build one-time DOM elements (header, month container)
|
||||
//
|
||||
|
||||
var titleElement, todayButton, monthElement, monthElementWidth;
|
||||
var header = $("<div class='full-calendar-header'/>").appendTo(this);
|
||||
|
||||
if (bo) {
|
||||
if (bo) { // "button options"
|
||||
var buttons = $("<div class='full-calendar-buttons'/>").appendTo(header);
|
||||
var prevButton, nextButton;
|
||||
if (bo == true || bo.today != false) {
|
||||
todayButton = $("<input type='button' class='full-calendar-today' value='today'/>")
|
||||
.click(today);
|
||||
.click(gotoToday);
|
||||
if (typeof bo.today == 'string') todayButton.val(bo.today);
|
||||
buttons.append(todayButton);
|
||||
}
|
||||
|
@ -237,14 +297,13 @@
|
|||
|
||||
monthElement = $("<div class='full-calendar-month' style='position:relative'/>")
|
||||
.appendTo($("<div class='full-calendar-month-wrap'/>").appendTo(this));
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Build the TABLE cells for the current month. (calls event fetch+render code)
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
var thead, tbody, glass, monthTitle;
|
||||
var thead, tbody, glass;
|
||||
|
||||
function render() {
|
||||
|
||||
|
@ -253,7 +312,7 @@
|
|||
clearTime(date);
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth();
|
||||
monthTitle = formatTitle(date);
|
||||
var monthTitle = $.fullCalendar.formatDate(date, titleFormat);
|
||||
if (titleElement) titleElement.text(monthTitle);
|
||||
|
||||
clearTime(date);
|
||||
|
@ -276,9 +335,14 @@
|
|||
todayButton.css('visibility', 'visible');
|
||||
}
|
||||
}
|
||||
|
||||
var dayNames = $.fullCalendar.dayNames;
|
||||
var dayAbbrevs = $.fullCalendar.dayAbbrevs;
|
||||
|
||||
if (!tbody) {
|
||||
|
||||
// first time, build all cells from scratch
|
||||
|
||||
var table = $("<table style='width:100%'/>").appendTo(monthElement);
|
||||
|
||||
thead = "<thead><tr>";
|
||||
|
@ -313,6 +377,8 @@
|
|||
}
|
||||
tbody = $(tbody + "</tbody>").appendTo(table);
|
||||
|
||||
// a protective coating over the TABLE
|
||||
// intercepts mouse clicks and prevents text-selection
|
||||
glass = $("<div style='position:absolute;top:0;left:0;z-index:1;width:100%' />")
|
||||
.appendTo(monthElement)
|
||||
.click(function(ev, ui) {
|
||||
|
@ -324,9 +390,12 @@
|
|||
});
|
||||
|
||||
}else{
|
||||
|
||||
// NOT first time, reuse as many cells as possible
|
||||
|
||||
var diff = numWeeks - tbody.find('tr').length;
|
||||
if (diff < 0) {
|
||||
// remove extra rows
|
||||
tbody.find('tr:gt(' + (numWeeks-1) + ')').remove();
|
||||
}
|
||||
else if (diff > 0) {
|
||||
|
@ -347,6 +416,7 @@
|
|||
if (trs) tbody.append(trs);
|
||||
}
|
||||
|
||||
// re-label and re-class existing cells
|
||||
var d = cloneDate(start);
|
||||
tbody.find('tr').each(function() {
|
||||
for (var i=0; i<7; i++) {
|
||||
|
@ -368,9 +438,11 @@
|
|||
|
||||
}
|
||||
|
||||
resizeTable();
|
||||
setCellSizes();
|
||||
|
||||
if (sniffBugs) {
|
||||
// nasty bugs in opera 9.25
|
||||
// position() returning relative to direct parent
|
||||
var tr = tbody.find('tr');
|
||||
var td = tr.find('td');
|
||||
var trTop = tr.position().top;
|
||||
|
@ -381,37 +453,7 @@
|
|||
sniffBugs = false;
|
||||
}
|
||||
|
||||
|
||||
events = [];
|
||||
var completed = eventSources.length;
|
||||
var reportEvents = function(a) {
|
||||
for (var i=0; i<a.length; i++) normalizeEvent(a[i]);
|
||||
events = events.concat(a);
|
||||
if (--completed == 0) {
|
||||
if (options.loading) options.loading(false);
|
||||
renderEvents(events);
|
||||
}
|
||||
};
|
||||
if (options.loading) options.loading(true);
|
||||
for (var i=0; i<eventSources.length; i++) {
|
||||
var src = eventSources[i];
|
||||
if (typeof src == 'string') {
|
||||
var params = {};
|
||||
params[options.startParam || 'start'] = Math.round(start.getTime() / 1000);
|
||||
params[options.endParam || 'end'] = Math.round(end.getTime() / 1000);
|
||||
params[options.cacheParam || '_'] = (new Date()).getTime();
|
||||
$.getJSON(src, params, reportEvents);
|
||||
}
|
||||
else if ($.isFunction(src)) {
|
||||
src(start, end, reportEvents);
|
||||
}
|
||||
else if (src) {
|
||||
reportEvents(src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fetchEvents(renderEvents);
|
||||
|
||||
ignoreResizes = false;
|
||||
|
||||
|
@ -421,10 +463,38 @@
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Adjust dimensions of the cells, based on container's width
|
||||
//
|
||||
|
||||
function setCellSizes() {
|
||||
var tbodyw = tbody.width();
|
||||
var cellw = Math.floor(tbodyw / 7);
|
||||
var cellh = Math.round(cellw * .85);
|
||||
thead.find('th')
|
||||
.filter(':lt(6)').width(cellw).end()
|
||||
.filter(':eq(6)').width(tbodyw - cellw*6);
|
||||
tbody.find('td').height(cellh);
|
||||
glass.height(monthElement.height());
|
||||
monthElementWidth = monthElement.width();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
//
|
||||
// Event Rendering
|
||||
//
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
//
|
||||
// Render the 'events' array. First, break up into segments
|
||||
//
|
||||
|
||||
var eventMatrix = [];
|
||||
|
||||
function renderEvents() {
|
||||
|
@ -493,7 +563,9 @@
|
|||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Do the REAL rendering of the segments
|
||||
//
|
||||
|
||||
var eventElements = []; // [[event, element], ...]
|
||||
|
||||
|
@ -535,7 +607,14 @@
|
|||
roundE = seg.isEnd;
|
||||
}
|
||||
left2 = left2.position().left + left2.width();
|
||||
var element = $("<table class='event' />")
|
||||
var cl = event.className;
|
||||
if (typeof cl == 'string') {
|
||||
cl = ' ' + cl;
|
||||
}
|
||||
else if (typeof cl == 'object') {
|
||||
cl = ' ' + cl.join(' ');
|
||||
}
|
||||
var element = $("<table class='event" + (cl || '') + "' />")
|
||||
.append("<tr>" +
|
||||
(roundW ? "<td class='nw'/>" : '') +
|
||||
"<td class='n'/>" +
|
||||
|
@ -549,7 +628,6 @@
|
|||
"<td class='s'/>" +
|
||||
(roundE ? "<td class='se'/>" : '') + "</tr>");
|
||||
buildEventText(event, element.find('td.c'));
|
||||
if (event.cssClass) element.addClass(event.cssClass);
|
||||
if (options.eventRender) {
|
||||
var res = options.eventRender(event, element);
|
||||
if (typeof res != 'undefined') {
|
||||
|
@ -576,9 +654,33 @@
|
|||
innerDiv.height(height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// create the text-contents of an event segment
|
||||
//
|
||||
|
||||
function buildEventText(event, element) {
|
||||
$("<span class='event-title' />")
|
||||
.text(event.title)
|
||||
.appendTo(element);
|
||||
var st = typeof event.showTime == 'undefined' ? showTime : event.showTime;
|
||||
if (st != false) {
|
||||
if (st == true || st == 'guess' &&
|
||||
(event.start.getHours() || event.start.getMinutes() ||
|
||||
event.end.getHours() || event.end.getMinutes())) {
|
||||
var timeStr = $.fullCalendar.formatDate(event.start, timeFormat);
|
||||
var timeElement = $("<span class='event-time' />");
|
||||
if (r2l) element.append(timeElement.text(' ' + timeStr));
|
||||
else element.prepend(timeElement.text(timeStr + ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Attach event handlers to an event segment
|
||||
//
|
||||
|
||||
function initEventElement(event, element) {
|
||||
element.click(function(ev) {
|
||||
|
@ -607,10 +709,35 @@
|
|||
}
|
||||
eventElements.push([event, element]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Remove all event segments from DOM
|
||||
//
|
||||
|
||||
function clearEventElements() {
|
||||
for (var i=0; i<eventElements.length; i++)
|
||||
eventElements[i][1].remove();
|
||||
eventElements = [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
//
|
||||
// Drag & Drop (and cell-coordinate stuff)
|
||||
//
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
//
|
||||
// Attach jQuery UI draggable
|
||||
//
|
||||
|
||||
var dragStartTD, dragTD;
|
||||
var dayOverlay;
|
||||
|
||||
|
@ -658,7 +785,7 @@
|
|||
}
|
||||
if (options.eventDrop)
|
||||
options.eventDrop.call(this, event, delta, ev, ui);
|
||||
clearEvents();
|
||||
clearEventElements();
|
||||
renderEvents();
|
||||
}
|
||||
dayOverlay.hide();
|
||||
|
@ -667,6 +794,11 @@
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Called DURING dragging, on every mouse move
|
||||
//
|
||||
|
||||
function eventDrag(node, ev, ui) {
|
||||
var oldTD = dragTD;
|
||||
|
@ -690,9 +822,9 @@
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Record positions & dimensions of each TD
|
||||
//
|
||||
|
||||
var dayX, dayY, dayX0, dayY0;
|
||||
var currTD, currR, currC;
|
||||
|
@ -717,6 +849,10 @@
|
|||
dayX.push(dayX[dayX.length-1] + td.width());
|
||||
currTD = null;
|
||||
}
|
||||
|
||||
//
|
||||
// Returns TD underneath coordinate (optimized)
|
||||
//
|
||||
|
||||
function dayTD(x, y) {
|
||||
var r=-1, c=-1;
|
||||
|
@ -737,115 +873,128 @@
|
|||
}
|
||||
return currTD;
|
||||
}
|
||||
|
||||
//
|
||||
// Get a TD's date
|
||||
//
|
||||
|
||||
function dayDate(node) {
|
||||
function dayDate(td) {
|
||||
var i, tds = tbody.get(0).getElementsByTagName('td');
|
||||
for (i=0; i<tds.length; i++) {
|
||||
if (tds[i] == node) break;
|
||||
if (tds[i] == td) break;
|
||||
}
|
||||
var d = cloneDate(start);
|
||||
return addDays(d, i);
|
||||
}
|
||||
|
||||
//
|
||||
// Return the # of days between 2 TD's
|
||||
//
|
||||
|
||||
function dayDelta(node1, node2) {
|
||||
function dayDelta(td1, td2) {
|
||||
var i1, i2, trs = tbody.get(0).getElementsByTagName('tr');
|
||||
for (var i=0; i<trs.length; i++) {
|
||||
var tr = trs[i];
|
||||
for (var j=0; j<7; j++) {
|
||||
var td = tr.childNodes[j];
|
||||
if (td == node1) i1 = i*7 + j*dis + dit;
|
||||
if (td == node2) i2 = i*7 + j*dis + dit;
|
||||
if (td == td1) i1 = i*7 + j*dis + dit;
|
||||
if (td == td2) i2 = i*7 + j*dis + dit;
|
||||
}
|
||||
}
|
||||
return i2 - i1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function resizeTable() {
|
||||
var tbodyw = tbody.width();
|
||||
var cellw = Math.floor(tbodyw / 7);
|
||||
var cellh = Math.round(cellw * .85);
|
||||
thead.find('th')
|
||||
.filter(':lt(6)').width(cellw).end()
|
||||
.filter(':eq(6)').width(tbodyw - cellw*6);
|
||||
tbody.find('td').height(cellh);
|
||||
glass.height(monthElement.height());
|
||||
monthElementWidth = monthElement.width();
|
||||
}
|
||||
|
||||
function clearEvents() {
|
||||
for (var i=0; i<eventElements.length; i++)
|
||||
eventElements[i][1].remove();
|
||||
eventElements = [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function buildEventText(event, element) {
|
||||
$("<span class='event-title' />")
|
||||
.text(event.title)
|
||||
.appendTo(element);
|
||||
var st = typeof event.showTime == 'undefined' ? showTime : event.showTime;
|
||||
if (st != false) {
|
||||
var h = event.start.getHours();
|
||||
var m = event.start.getMinutes();
|
||||
if (st == true || st == 'guess' && (h || m || event.end.getHours() || event.end.getMinutes())) {
|
||||
var s = '';
|
||||
for (var i=0; i<timeFormat.length; i++) {
|
||||
var c = timeFormat.charAt(i);
|
||||
if (c == 'a') s += h<12 ? 'am' : 'pm';
|
||||
else if (c == 'A') s += h<12 ? 'AM' : 'PM';
|
||||
else if (c == 'x') s += h<12 ? 'a' : 'p';
|
||||
else if (c == 'X') s += h<12 ? 'A' : 'P';
|
||||
else if (c == 'g') s += h%12 || 12;
|
||||
else if (c == 'G') s += h;
|
||||
else if (c == 'h') s += zeroPad(h%12 || 12);
|
||||
else if (c == 'H') s += zeroPad(h);
|
||||
else if (c == 'i') s += zeroPad(m);
|
||||
else s += c;
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
//
|
||||
// Event Sources & Fetching
|
||||
//
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
//
|
||||
// Fetch from ALL sources. Clear 'events' array and populate
|
||||
//
|
||||
|
||||
function fetchEvents(callback) {
|
||||
events = [];
|
||||
var queued = eventSources.length;
|
||||
var sourceDone = function() {
|
||||
if (--queued == 0) {
|
||||
if (options.loading) {
|
||||
options.loading(false);
|
||||
}
|
||||
if (callback) {
|
||||
callback(events);
|
||||
}
|
||||
var timeElement = $("<span class='event-time' />");
|
||||
if (r2l) element.append(timeElement.text(' ' + s));
|
||||
else element.prepend(timeElement.text(s + ' '));
|
||||
}
|
||||
};
|
||||
if (options.loading) {
|
||||
options.loading(true);
|
||||
}
|
||||
for (var i=0; i<eventSources.length; i++) {
|
||||
fetchEventSource(eventSources[i], sourceDone);
|
||||
}
|
||||
}
|
||||
|
||||
function formatTitle(d) {
|
||||
var m = d.getMonth();
|
||||
var s = '';
|
||||
for (var i=0; i<titleFormat.length; i++) {
|
||||
var c = titleFormat.charAt(i);
|
||||
if (c == 'F') s += monthNames[m];
|
||||
else if (c == 'm') s += zeroPad(m);
|
||||
else if (c == 'M') s += monthAbbrevs[m];
|
||||
else if (c == 'n') s += m;
|
||||
else if (c == 'Y') s += d.getFullYear();
|
||||
else if (c == 'y') s += (d.getFullYear()+'').substring(2);
|
||||
else s += c;
|
||||
|
||||
//
|
||||
// Fetch from a particular source. Append to the 'events' array
|
||||
//
|
||||
|
||||
function fetchEventSource(src, callback) {
|
||||
var reportEvents = function(a) {
|
||||
for (var i=0; i<a.length; i++) {
|
||||
normalizeEvent(a[i]);
|
||||
a[i].source = src;
|
||||
}
|
||||
events = events.concat(a);
|
||||
if (callback) {
|
||||
callback(a);
|
||||
}
|
||||
};
|
||||
if (typeof src == 'string') {
|
||||
var params = {};
|
||||
params[options.startParam || 'start'] = Math.round(start.getTime() / 1000);
|
||||
params[options.endParam || 'end'] = Math.round(end.getTime() / 1000);
|
||||
params[options.cacheParam || '_'] = (new Date()).getTime();
|
||||
$.getJSON(src, params, reportEvents);
|
||||
}
|
||||
else if ($.isFunction(src)) {
|
||||
src(start, end, reportEvents);
|
||||
}
|
||||
else {
|
||||
reportEvents(src);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
//
|
||||
// Begin "Main" Execution
|
||||
//
|
||||
/*******************************************************************/
|
||||
|
||||
var e = this;
|
||||
var resizeID = 0;
|
||||
$(window).resize(function() {
|
||||
$(window).resize(function() { // re-render table on window resize
|
||||
if (!ignoreResizes) {
|
||||
var rid = ++resizeID;
|
||||
var rid = ++resizeID; // add a delay
|
||||
setTimeout(function() {
|
||||
if (rid == resizeID) {
|
||||
// if the month width changed
|
||||
if (monthElement.width() != monthElementWidth) {
|
||||
clearEvents();
|
||||
resizeTable();
|
||||
clearEventElements();
|
||||
setCellSizes();
|
||||
_renderEvents();
|
||||
if (options.resize) options.resize.call(e);
|
||||
}
|
||||
|
@ -854,7 +1003,10 @@
|
|||
}
|
||||
});
|
||||
|
||||
render();
|
||||
render(); // let's begin...
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
@ -863,24 +1015,26 @@
|
|||
|
||||
|
||||
|
||||
// string utilities
|
||||
|
||||
function zeroPad(n) {
|
||||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
//
|
||||
// Utilities
|
||||
//
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
//
|
||||
// event utils
|
||||
//
|
||||
|
||||
function normalizeEvent(event) {
|
||||
if (event.date) {
|
||||
event.start = event.date;
|
||||
event.date = undefined; // can i do this?
|
||||
delete event.date;
|
||||
}
|
||||
event.start = cleanDate(event.start);
|
||||
event.start = $.fullCalendar.parseDate(event.start);
|
||||
event._start = cloneDate(event.start);
|
||||
event.end = cleanDate(event.end);
|
||||
event.end = $.fullCalendar.parseDate(event.end);
|
||||
if (!event.end) event.end = addDays(cloneDate(event.start), 1);
|
||||
return event;
|
||||
}
|
||||
|
@ -890,13 +1044,18 @@
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// string utils
|
||||
//
|
||||
|
||||
function zeroPad(n) {
|
||||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// date utils
|
||||
|
||||
var monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December'];
|
||||
var monthAbbrevs = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
var dayNames = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
|
||||
var dayAbbrevs = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
|
||||
//
|
||||
|
||||
function addMonths(d, n, keepTime) {
|
||||
d.setMonth(d.getMonth() + n);
|
||||
|
@ -922,48 +1081,99 @@
|
|||
return new Date(+d);
|
||||
}
|
||||
|
||||
function cleanDate(d) {
|
||||
if (typeof d == 'string')
|
||||
return $.parseISO8601(d, true) || Date.parse(d) || new Date(parseInt(d));
|
||||
if (typeof d == 'number')
|
||||
return new Date(d * 1000);
|
||||
return d;
|
||||
}
|
||||
|
||||
$.parseISO8601 = function(s, ignoreTimezone) {
|
||||
// derived from http://delete.me.uk/2005/03/iso8601.html
|
||||
var regexp = "([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})))?)?)?)?";
|
||||
var d = s.match(new RegExp(regexp));
|
||||
if (!d) return null;
|
||||
var offset = 0;
|
||||
var date = new Date(d[1], 0, 1);
|
||||
if (d[3]) { date.setMonth(d[3] - 1); }
|
||||
if (d[5]) { date.setDate(d[5]); }
|
||||
if (d[7]) { date.setHours(d[7]); }
|
||||
if (d[8]) { date.setMinutes(d[8]); }
|
||||
if (d[10]) { date.setSeconds(d[10]); }
|
||||
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
|
||||
if (!ignoreTimezone) {
|
||||
if (d[14]) {
|
||||
offset = (Number(d[16]) * 60) + Number(d[17]);
|
||||
offset *= ((d[15] == '-') ? 1 : -1);
|
||||
//
|
||||
// globally accessible date formatting & parsing
|
||||
//
|
||||
|
||||
$.fullCalendar = {
|
||||
|
||||
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
|
||||
monthAbbrevs: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
|
||||
dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
|
||||
dayAbbrevs: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
|
||||
|
||||
formatDate: function(d, format) {
|
||||
var f = $.fullCalendar.dateFormatters;
|
||||
var s = '';
|
||||
for (var i=0; i<format.length; i++) {
|
||||
var c = format.charAt(i);
|
||||
if (f[c]) {
|
||||
s += f[c](d);
|
||||
}else{
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
offset -= date.getTimezoneOffset();
|
||||
return s;
|
||||
},
|
||||
|
||||
dateFormatters: {
|
||||
'a': function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
|
||||
'A': function(d) { return d.getHours() < 12 ? 'AM' : 'PM' },
|
||||
'x': function(d) { return d.getHours() < 12 ? 'a' : 'p' },
|
||||
'X': function(d) { return d.getHours() < 12 ? 'A' : 'P' },
|
||||
'g': function(d) { return d.getHours() % 12 || 12 },
|
||||
'G': function(d) { return d.getHours() },
|
||||
'h': function(d) { return zeroPad(d.getHours() %12 || 12) },
|
||||
'H': function(d) { return zeroPad(d.getHours()) },
|
||||
'i': function(d) { return zeroPad(d.getMinutes()) },
|
||||
'F': function(d) { return $.fullCalendar.monthNames[d.getMonth()] },
|
||||
'm': function(d) { return zeroPad(d.getMonth() + 1) },
|
||||
'M': function(d) { return $.fullCalendar.monthAbbrevs[d.getMonth()] },
|
||||
'n': function(d) { return d.getMonth() + 1 },
|
||||
'Y': function(d) { return d.getFullYear() },
|
||||
'y': function(d) { return (d.getFullYear()+'').substring(2) },
|
||||
'c': function(d) {
|
||||
// ISO8601. derived from http://delete.me.uk/2005/03/iso8601.html
|
||||
return d.getUTCFullYear() +
|
||||
"-" + zeroPad(d.getUTCMonth() + 1) +
|
||||
"-" + zeroPad(d.getUTCDate()) +
|
||||
"T" + zeroPad(d.getUTCHours()) +
|
||||
":" + zeroPad(d.getUTCMinutes()) +
|
||||
":" + zeroPad(d.getUTCSeconds()) +
|
||||
"Z";
|
||||
}
|
||||
},
|
||||
|
||||
parseDate: function(s) {
|
||||
if (typeof s == 'object')
|
||||
return s; // already a Date object
|
||||
if (typeof s == 'undefined')
|
||||
return null;
|
||||
if (typeof s == 'number')
|
||||
return new Date(s * 1000);
|
||||
return $.fullCalendar.parseISO8601(s, true) ||
|
||||
Date.parse(s) ||
|
||||
new Date(parseInt(s) * 1000);
|
||||
},
|
||||
|
||||
parseISO8601: function(s, ignoreTimezone) {
|
||||
// derived from http://delete.me.uk/2005/03/iso8601.html
|
||||
var regexp = "([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})))?)?)?)?";
|
||||
var d = s.match(new RegExp(regexp));
|
||||
if (!d) return null;
|
||||
var offset = 0;
|
||||
var date = new Date(d[1], 0, 1);
|
||||
if (d[3]) { date.setMonth(d[3] - 1); }
|
||||
if (d[5]) { date.setDate(d[5]); }
|
||||
if (d[7]) { date.setHours(d[7]); }
|
||||
if (d[8]) { date.setMinutes(d[8]); }
|
||||
if (d[10]) { date.setSeconds(d[10]); }
|
||||
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
|
||||
if (!ignoreTimezone) {
|
||||
if (d[14]) {
|
||||
offset = (Number(d[16]) * 60) + Number(d[17]);
|
||||
offset *= ((d[15] == '-') ? 1 : -1);
|
||||
}
|
||||
offset -= date.getTimezoneOffset();
|
||||
}
|
||||
return new Date(Number(date) + (offset * 60 * 1000));
|
||||
}
|
||||
return new Date(Number(date) + (offset * 60 * 1000));
|
||||
};
|
||||
|
||||
$.ISO8601String = function(date) {
|
||||
// derived from http://delete.me.uk/2005/03/iso8601.html
|
||||
return date.getUTCFullYear() +
|
||||
"-" + zeroPad(date.getUTCMonth() + 1) +
|
||||
"-" + zeroPad(date.getUTCDate()) +
|
||||
"T" + zeroPad(date.getUTCHours()) +
|
||||
":" + zeroPad(date.getUTCMinutes()) +
|
||||
":" + zeroPad(date.getUTCSeconds()) +
|
||||
"Z";
|
||||
|
||||
};
|
||||
|
||||
// additional FullCalendar "extensions" should be attached to $.fullCalendar
|
||||
|
||||
})(jQuery);
|
||||
|
|
83
gcal.js
83
gcal.js
|
@ -21,56 +21,45 @@
|
|||
|
||||
(function($) {
|
||||
|
||||
$.fn.gcalFullCalendar = function(options) {
|
||||
$.fullCalendar.gcalFeed = function(feedUrl, options) {
|
||||
|
||||
var feedURL;
|
||||
if (options && typeof options.events == 'string') {
|
||||
feedURL = options.events;
|
||||
}
|
||||
else return this.fullCalendar(options);
|
||||
feedUrl = feedUrl.replace(/\/basic$/, '/full');
|
||||
options = options || {};
|
||||
var draggable = options.draggable || false;
|
||||
|
||||
feedURL = feedURL.replace(/\/basic$/, '/full');
|
||||
|
||||
$.extend(options, {
|
||||
|
||||
events: function(start, end, callback) {
|
||||
$.getJSON(feedURL + "?alt=json-in-script&callback=?",
|
||||
{
|
||||
'start-min': $.ISO8601String(start),
|
||||
'start-max': $.ISO8601String(end),
|
||||
'singleevents': true
|
||||
},
|
||||
function(data) {
|
||||
var events = [];
|
||||
if (data.feed.entry)
|
||||
$.each(data.feed.entry, function(i, entry) {
|
||||
var url;
|
||||
$.each(entry['link'], function(j, link) {
|
||||
if (link.type == 'text/html') url = link.href;
|
||||
});
|
||||
events.push({
|
||||
id: entry['gCal$uid']['value'],
|
||||
url: url,
|
||||
title: entry['title']['$t'],
|
||||
start: $.parseISO8601(entry['gd$when'][0]['startTime'], true),
|
||||
end: $.parseISO8601(entry['gd$when'][0]['endTime'], true),
|
||||
location: entry['gd$where'][0]['valueString'],
|
||||
description: entry['content']['$t'],
|
||||
allDay: entry['gd$when'][0]['startTime'].indexOf('T') == -1,
|
||||
draggable: false
|
||||
});
|
||||
return function(start, end, callback) {
|
||||
$.getJSON(feedUrl + "?alt=json-in-script&callback=?",
|
||||
{
|
||||
'start-min': $.fullCalendar.formatDate(start, 'c'),
|
||||
'start-max': $.fullCalendar.formatDate(end, 'c'),
|
||||
'singleevents': true
|
||||
},
|
||||
function(data) {
|
||||
var events = [];
|
||||
if (data.feed.entry)
|
||||
$.each(data.feed.entry, function(i, entry) {
|
||||
var url;
|
||||
$.each(entry['link'], function(j, link) {
|
||||
if (link.type == 'text/html') url = link.href;
|
||||
});
|
||||
callback(events);
|
||||
});
|
||||
},
|
||||
var showTime = entry['gd$when'][0]['startTime'].indexOf('T') != -1;
|
||||
events.push({
|
||||
id: entry['gCal$uid']['value'],
|
||||
url: url,
|
||||
title: entry['title']['$t'],
|
||||
start: $.fullCalendar.parseDate(entry['gd$when'][0]['startTime']),
|
||||
end: $.fullCalendar.parseDate(entry['gd$when'][0]['endTime']),
|
||||
location: entry['gd$where'][0]['valueString'],
|
||||
description: entry['content']['$t'],
|
||||
showTime: showTime,
|
||||
className: [showTime ? 'nobg' : null, options.className],
|
||||
draggable: draggable
|
||||
});
|
||||
});
|
||||
callback(events);
|
||||
});
|
||||
}
|
||||
|
||||
eventRender: function(event, element) {
|
||||
if (!event.allDay) element.addClass('nobg');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return this.fullCalendar(options);
|
||||
};
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
|
|
Loading…
Reference in a new issue