Compare commits

...

37 Commits

Author SHA1 Message Date
Adam Shaw 67ed871e67 forgot today button in docs, new docs make output directory 2009-10-15 06:13:56 +00:00
Adam Shaw 7070f2e6ba 1.3.2 2009-10-14 05:55:00 +00:00
Adam Shaw 0925364927 tagging 1.3 for real this time 2009-10-05 05:43:06 +00:00
Adam Shaw ef2bebd9ff version 1.3.1 2009-10-01 05:39:02 +00:00
Adam Shaw bed7a3df9b bugfixes and final touches for 1.3 2009-09-21 10:11:08 +00:00
Adam Shaw 44526dbe3d 2009-09-21 04:57:20 +00:00
Adam Shaw b3b84dca9a 2009-09-17 06:30:10 +00:00
Adam Shaw c35a4e89af 2009-09-16 06:17:37 +00:00
Adam Shaw beeed3af1a updated examples 2009-09-15 06:19:43 +00:00
Adam Shaw 54229b518f 2009-09-15 03:41:21 +00:00
Adam Shaw 10e7dafc72 2009-09-15 03:40:05 +00:00
Adam Shaw f45246c60c modified docs, added all new tests 2009-09-14 10:28:23 +00:00
Adam Shaw 2841a62e74 more doc changes 2009-09-14 03:36:27 +00:00
Adam Shaw 176193a18c 2009-09-13 22:25:49 +00:00
Adam Shaw 7c93ba1fe6 modified docs, legacy, works with arshaw.com 2009-09-13 22:14:09 +00:00
Adam Shaw 6bb08fb0f3 2009-09-08 07:50:23 +00:00
Adam Shaw c94cc98fa0 2009-09-08 03:37:35 +00:00
Adam Shaw cf1bc90010 getting ready for next version 2009-09-08 03:01:28 +00:00
Adam Shaw 7d8fe1f347 forgot version string 2009-06-30 06:08:08 +00:00
Adam Shaw 2acacf8ac9 1.2.1 tested patches, modified docs 2009-06-30 06:03:15 +00:00
Adam Shaw 9a06943f52 un-unit-tested bugfixes for 1.2.1 2009-06-29 05:36:29 +00:00
Adam Shaw de10f54efb at version 1.2 2009-06-01 04:51:34 +00:00
Adam Shaw e56ffb3d99 add test suit. almost at 1.2 2009-05-31 20:56:02 +00:00
Adam Shaw 103b87ff2d 2009-05-31 05:02:41 +00:00
Adam Shaw 5c9ed310f0 2009-05-31 05:01:24 +00:00
Adam Shaw 69917fa336 2009-05-31 04:57:21 +00:00
Adam Shaw f3e8cc8d59 2009-05-31 04:49:51 +00:00
Adam Shaw e92525b9e4 2009-05-31 03:25:12 +00:00
Adam Shaw ff281feb33 almost at 1.2 2009-05-30 05:54:53 +00:00
Adam Shaw 05a4a07073 fixed weekStart bug 2009-05-25 17:26:13 +00:00
Adam Shaw d9fad7a2a7 crud for events 2009-05-18 05:36:12 +00:00
Adam Shaw f35d3648fc cssClass, beefed up events option 2009-05-17 17:41:48 +00:00
Adam Shaw 55b9ad3b70 last minute css changes (ie sucks) 2009-05-11 04:31:03 +00:00
Adam Shaw b0e089170d changed makefile, updated examples 2009-05-11 02:58:02 +00:00
Adam Shaw 26212ad377 ie6/opera9.25 bugfixes, added options, more 2009-05-10 19:48:37 +00:00
Adam Shaw aea9e567ea localization: start-of-week and right-to-left 2009-05-08 19:34:50 +00:00
Adam Shaw 7763b011f9 fixed IE JSON caching issue 2009-05-05 14:42:35 +00:00
84 changed files with 10815 additions and 1479 deletions

View File

@ -1,26 +1,63 @@
FILES =\
*.js\
*.css\
jquery\
examples
VER = `cat version.txt`
DATE = `svn info . | grep Date: | sed 's/.*: //g'`
REV = `svn info . | grep Rev: | sed 's/.*: //g'`
VER = `cat version.txt`
DATE = `svn info | grep Date: | sed 's/.*: //g'`
REV = `svn info | grep Rev: | sed 's/.*: //g'`
JS_SRC_FILES =\
main.js\
grid.js\
view.js\
util.js
CSS_SRC_FILES =\
main.css\
grid.css
OTHER_FILES =\
src/gcal.js\
src/jquery\
examples\
changelog.txt
zip:
@mkdir -p fullcalendar
@cp -rt fullcalendar ${FILES}
@rm -rf `find fullcalendar -type d -name .svn`
@rm -rf build/fullcalendar
@rm -rf build/fullcalendar-*
@mkdir -p build/fullcalendar
@sed -i "s/FullCalendar/& v${VER}/" fullcalendar/fullcalendar.js
@sed -i "s/Date:/& ${DATE}/" fullcalendar/fullcalendar.js
@sed -i "s/Revision:/& ${REV}/" fullcalendar/fullcalendar.js
@echo "building js & css..."
@cd src; cat misc/head.txt ${JS_SRC_FILES} misc/foot.txt > ../build/fullcalendar/fullcalendar.js
@cd src/css; cat ${CSS_SRC_FILES} > ../../build/fullcalendar/fullcalendar.css
@for f in build/fullcalendar/*; do\
sed -i "s/* FullCalendar/& v${VER}/" $$f;\
sed -i "s/* Date:/& ${DATE}/" $$f;\
sed -i "s/* Revision:/& ${REV}/" $$f;\
done
@cp -rt build/fullcalendar ${OTHER_FILES}
@find build/fullcalendar -type d -name .svn | xargs rm -rf
@echo "compressing js..."
@java -jar build/yuicompressor-2.4.2.jar -o build/fullcalendar/fullcalendar.min.js build/fullcalendar/fullcalendar.js
@echo "building examples..."
@for f in build/fullcalendar/examples/*.html; do\
sed -i -n '1h;1!H;$${;g;s/<!--\s*<src>.*<\/src>\s*-->\s*//g;p;}' $$f;\
sed -i -n '1h;1!H;$${;g;s/<!--\s*<dist>\s*//g;p;}' $$f;\
sed -i -n '1h;1!H;$${;g;s/<\/dist>\s*-->\s*//g;p;}' $$f;\
done
@echo "zipping..."
@mv build/fullcalendar build/fullcalendar-${VER}
@cd build; for f in fullcalendar-*; do\
zip -q -r $$f.zip $$f;\
done
@mv build/fullcalendar-${VER} build/fullcalendar
@mkdir -p dist
@zip -r dist/fullcalendar-${VER}.zip fullcalendar
@rm -rf fullcalendar
@mv build/fullcalendar-${VER}.zip dist
@echo "done."
clean:
@rm -rf build/fullcalendar
@rm -rf build/fullcalendar-*
@rm -rf dist/*

Binary file not shown.

137
changelog.txt Normal file
View File

@ -0,0 +1,137 @@
version 1.3.2 (10/13/09)
- Bugfixes (please upgrade from 1.3.1!)
- squashed potential infinite loop when addMonths and addDays
is called with an invalid date
- $.fullCalendar.parseDate() now correctly parses IETF format
- when switching views, the 'today' button sticks inactive, fixed
- gotoDate now can accept a single Date argument
- documentation for changes in 1.3.1 and 1.3.2 now on website
version 1.3.1 (9/30/09)
- Important Bugfixes (please upgrade from 1.3!)
- When current date was late in the month, for long months, and prev/next buttons
were clicked in month-view, some months would be skipped/repeated
- In certain time zones, daylight savings time would cause certain days
to be misnumbered in month-view
- Subtle change in way week interval is chosen when switching from month to basicWeek/basicDay view
- Added 'allDayDefault' option
- Added 'changeView' and 'render' methods
version 1.3 (9/21/09)
- different 'views': month/basicWeek/basicDay
- more flexible 'header' system for buttons
- themable by jQuery UI themes
- resizable events (require jQuery UI resizable plugin)
- rescoped & rewritten CSS, enhanced default look
- cleaner css & rendering techniques for right-to-left
- reworked options & API to support multiple views / be consistent with jQuery UI
- refactoring of entire codebase
- broken into different JS & CSS files, assembled w/ build scripts
- new test suite for new features, uses firebug-lite
- refactored docs
- Options
+ date
+ defaultView
+ aspectRatio
+ disableResizing
+ monthNames (use instead of $.fullCalendar.monthNames)
+ monthNamesShort (use instead of $.fullCalendar.monthAbbrevs)
+ dayNames (use instead of $.fullCalendar.dayNames)
+ dayNamesShort (use instead of $.fullCalendar.dayAbbrevs)
+ theme
+ buttonText
+ buttonIcons
x draggable -> editable/disableDragging
x fixedWeeks -> weekMode
x abbrevDayHeadings -> columnFormat
x buttons/title -> header
x eventDragOpacity -> dragOpacity
x eventRevertDuration -> dragRevertDuration
x weekStart -> firstDay
x rightToLeft -> isRTL
x showTime (use 'allDay' CalEvent property instead)
- Triggered Actions
+ eventResizeStart
+ eventResizeStop
+ eventResize
x monthDisplay -> viewDisplay
x resize -> windowResize
'eventDrop' params changed, can revert if ajax cuts out
- CalEvent Properties
x showTime -> allDay
x draggable -> editable
'end' is now INCLUSIVE when allDay=true
'url' now produces a real <a> tag, more native clicking/tab behavior
- Methods:
+ renderEvent
x prevMonth -> prev
x nextMonth -> next
x prevYear/nextYear -> moveDate
x refresh -> rerenderEvents/refetchEvents
x removeEvent -> removeEvents
x getEventsByID -> clientEvents
- Utilities:
'formatDate' format string completely changed (inspired by jQuery UI datepicker + datejs)
'formatDates' added to support date-ranges
- Google Calendar Options:
x draggable -> editable
- Bugfixes
- gcal extension fetched 25 results max, now fetches all
version 1.2.1 (6/29/09)
- bugfixes
- allows and corrects invalid end dates for events
- doesn't throw an error in IE while rendering when display:none
- fixed 'loading' callback when used w/ multiple addEventSource calls
- gcal className can now be an array
version 1.2 (5/31/09)
- expanded API
- 'className' CalEvent attribute
- 'source' CalEvent attribute
- dynamically get/add/remove/update events of current month
- locale improvements: change month/day name text
- better date formatting ($.fullCalendar.formatDate)
- multiple 'event sources' allowed
- dynamically add/remove event sources
- options for prevYear and nextYear buttons
- docs have been reworked (include addition of Google Calendar docs)
- changed behavior of parseDate for number strings
(now interpets as unix timestamp, not MS times)
- bugfixes
- rightToLeft month start bug
- off-by-one errors with month formatting commands
- events from previous months sticking when clicking prev/next quickly
- Google Calendar API changed to work w/ multiple event sources
- can also provide 'className' and 'draggable' options
- date utilties moved from $ to $.fullCalendar
- more documentation in source code
- minified version of fullcalendar.js
- test suit (available from svn)
- top buttons now use <button> w/ an inner <span> for better css cusomization
- thus CSS has changed. IF UPGRADING FROM PREVIOUS VERSIONS,
UPGRADE YOUR FULLCALENDAR.CSS FILE!!!
version 1.1 (5/10/09)
- Added the following options:
- weekStart
- rightToLeft
- titleFormat
- timeFormat
- cacheParam
- resize
- Fixed rendering bugs
- Opera 9.25 (events placement & window resizing)
- IE6 (window resizing)
- Optimized window resizing for ALL browsers
- Events on same day now sorted by start time (but first by timespan)
- Correct z-index when dragging
- Dragging contained in overflow DIV for IE6
- Modified fullcalendar.css
- for right-to-left support
- for variable start-of-week
- for IE6 resizing bug
- for THEAD and TBODY (in 1.0, just used TBODY, restructured in 1.1)
- IF UPGRADING FROM FULLCALENDAR 1.0, YOU MUST UPGRADE FULLCALENDAR.CSS
!!!!!!!!!!!

View File

@ -35,7 +35,7 @@ html:
arshaw:
mkdir -p build/html build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
cp -r build/html/* /var/www/arshaw/pages/fullcalendar/docs/
cp -r build/html/* /var/www/arshaw/pages/fullcalendar/docs13/
@echo
@echo "Build finished. The HTML pages are in build/html."

View File

@ -188,3 +188,6 @@ latex_documents = [
# If false, no module index is generated.
#latex_use_modindex = True
highlight_language = 'javascript'

69
docs/date-utils.txt Executable file
View File

@ -0,0 +1,69 @@
Date Utilities
==============
**formatDate** - $.fullCalendar.formatDate(*date, formatString, [options]*)
Format a date into a string value with a specified format.
The format can be combinations of the following:
* **s** - seconds
* **ss** - seconds, 2 digits
* **m** - minutes
* **mm** - minutes, 2 digits
* **h** - hours
* **hh** - hours, 2 digits
* **H** - hours, military time
* **HH** - hours, milirary time, 2 digits
* **d** - date number
* **dd** - date number, 2 digits
* **ddd** - date name, short
* **dddd** - date name, full
* **M** - month number
* **MM** - month number, 2 digits
* **MMM** - month name, short
* **MMMM** - month name, full
* **yy** - year, 2 digits
* **yyyy** - year, 4 digits
* **t** - 'a' or 'p'
* **tt** - 'am' or 'pm'
* **T** - 'A' or 'P'
* **TT** - 'AM' or 'PM'
* **u** - ISO8601 format
* **S** - 'st', 'nd', 'rd', 'th' for the date
Special Characters:
``'...'``
literal text
``''``
single quote
``(...)``
only displays format if one of the enclosed variables is non-zero
*options* can override any of the :ref:`Locale Options<locale>`
.. _formatDates:
**formatDates** - $.fullCalendar.formatDates(*date1, date2, formatString, [options]*)
Similar to ``formatDate``, but accepts *two* dates, leveraging the following
special characters in *formatString*:
``{...}``
switches to formatting the 2nd date
``[...]``
only displays the enclosed format if the current date is different from the
alternate date in the same regards
**parseDate** - $.fullCalendar.parseDate(*string*)
Parses a string and returns a javascript Date object.
The string may be in ISO8601 format, IETF format, or a UNIX timestamp.
**parseISO8601** - $.fullCalendar.parseISO8601(*string, [ignoreTimezone]*)
Parses an ISO8601 string into a javascript Date object.

127
docs/events-and-sources.txt Executable file
View File

@ -0,0 +1,127 @@
.. _event-sources:
Event Sources
=============
The following options determine *how* events get on the calendar:
**events**: Array/String/Function
An array of :ref:`CalEvents <CalEvent>` 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:`CalEvents <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).
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``
Date object, an ``end`` Date object, and a function to be called when
fetching is complete. Here is the general form::
events: function(start, end, callback) {
// do some asynchronous ajax
$.getJSON("/myscript",
{
start: start.getTime(),
end: end.getTime()
},
function(result) {
// format the result into an array of CalEvents
// (not seen here)
// then, pass the CalEvent array to the callback
callback(calevents);
});
}
**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. 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. 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.
.. _CalEvent:
CalEvent Objects
================
A CalEvent is a data structure that frequents FullCalendar's API. It is the
standardized currency used in :ref:`event-sources`. It is also passed to various
:ref:`Triggered Actions <triggered-actions>`. Here are the properties of a
CalEvent:
**id**: Integer/String
Uniquely identifies the given event. Instances of repeating events should
all have the same id.
**title**: String
The text on an event's element
**allDay**: Boolean (optional, defaults to ``true``, see :ref:`allDayDefault <allDayDefault>` option)
Determines whether the start-date and end-date's times should be ignored.
If ``true``, times will be ignored. If ``false``, times will be considered,
displaying them on each event (like the text '3pm').
**date**: Date
Alias for ``start``
**start**: Date
A javascript Date object indicating the date/time an event begins.
In an :ref:`Event Source <event-sources>`, 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.
**end**: Date (optional)
A javascript Date object indicating the date/time an event ends.
As with ``start``, IETF and ISO8601 strings can be used.
**If an event is all-day...**
the end date is *inclusive*. This means an event with ``start`` *Nov 10* and
``end`` *Nov 12* will span *3 days* on the calendar.
**If an event is NOT all-day...**
the end date is *exclusive*. This is only a gotcha when your ``end`` has time 00:00.
It means your event ends on midnight, and it will *not* span through the next day.
**url**: String (optional)
A URL that will be visited when this event is clicked by the user.
By default, the new page will be opened in the current window, but one
may specify an ``eventClick`` :ref:`Triggered Action <triggered-actions>` for
more complex behavior (just remember to return ``false`` to prevent the default action).
**className**: String/Array (optional)
A CSS class (or array of classes) that will be attached to this event's
element.
**editable**: Boolean (optional)
Overrides the master ``editable`` option for this single event.
**source**: Array/String/Function (automatically populated)
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.

49
docs/google-calendar.txt Executable file
View File

@ -0,0 +1,49 @@
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 ``$.fullCalendar.gcalFeed`` function produces an event source that can be
passed to the ``events`` or ``eventSources`` options::
$('#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
* **editable** - whether to allow dragging/resizing (default: ``false``)
See *gcal.html* in the *examples* directory for a complete example.

View File

@ -1,235 +1,158 @@
.. highlight:: javascript
Usage
=====
.. code-block:: javascript
The following code initializes a FullCalendar within an element::
$('#myCalendar').fullCalendar({
// initializes a calendar
// see options, data provider, and triggered events below
});
$('#myCalendar').fullCalendar('nextMonth'); // move ahead one month
$('#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
=======
$('#calendar').fullCalendar({
// put your options here
})
**year**, **month**: integers
The month that will be displayed when the calendar first loads.
``month`` is zero-based (January is 0, February is 1, etc).
**draggable**: boolean, default:``false``
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.
**fixedWeeks**: boolean, default:``true``
If ``true``, the calendar will always be 6 weeks tall. If ``false``, the
calendar's height will vary per month.
**abbrevDayHeadings**: boolean, default:``true``
Whether to display "Sun" versus "Sunday" for days of the week.
**title**: boolean, default:``true``
Determines whether a title such as "January 2009" will be displayed at the
top of the calendar.
**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.
**showTime**: boolean/ ``"guess"``, default:``"guess"``
Determines if times such as "8a" or "1p" will be displayed before each
event's title. ``"guess"`` displays times only for events with non-zero
start or end times.
**eventDragOpacity**: float
The opacity of an event element while it is being dragged (0.0 - 1.0)
**eventRevertDuration**: integer
Controls the duration (in milliseconds) of the animation of an event
snapping back into place.
Basic Options
=============
.. _EventDataProvider:
Event Data Provider
===================
**events**: array/string/function
An array of :ref:`CalEvent` 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).
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``
Date object, an ``end`` Date object, and a function to be called when
fetching is complete. Here is the general form::
events: function(start, end, callback) {
// do some asynchronous ajax
$.getJSON("/myscript",
{
start: start.getTime(),
end: end.getTime()
},
function(result) {
// format the result into an array of 'CalEvent' objects
// (not seen here)
// then, pass the 'calevent' array to the callback
callback(calevents);
});
}
**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).
**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).
.. _TriggeredEvents:
Triggered Events
================
**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.
**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:
**year, month, date**: Integers
The initial year/month/date when the calendar loads.
``month`` is 0-based, meaning January=0, February=1, etc.
If ommitted, the calendar starts on the current date.
CalEvent Objects
================
**header**: Object/``false``, *Default*: ``{ left:'title', center:'', right:'today prev,next' }``
Defines the buttons/text at the top of the calendar.
``false`` will display no header.
An object can be supplied with properties ``left``, ``center``, and ``right``.
These properties contain strings with comma separated values,
containing any of the following:
``title``
text containing the current date or date-range
``prev``
button for moving the calendar back one month/week/day
``next``
button for moving the calendar forward one month/week/day
``today``
button for moving the calendar to the current month/week/day
*a blank space*
visual gap between buttons/text
*a view name*
button that will switch the calendar to any of the
:ref:`available-views`
Specifying an empty string for a property will cause it display no text/buttons.
To change the text within a button, see the :ref:`buttonText<locale>` option.
**defaultView**: String, *Default*: ``'month'``
The initial view when the calendar loads. Any of the :ref:`available-views`.
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``\:
**aspectRatio**: Float, *Default*: ``1.35``
A calendar is a block-level element that fills its entire avaiable width.
The calendar's height, however, is determined by this ratio of width-to-height.
(Hint: larger numbers make smaller heights).
**id**: integer/string,
Uniquely identifies the given event. Absolutely essential for multi-day
and repeating events to be dragged and dropped correctly.
**title**: string,
The text on an event's element
**date**: date
Alias for ``start``
**start**: date
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,
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.
**end**: date (optional)
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`).
IETF and ISO8601 strings can be used for the :ref:`EventDataProvider`.
**draggable**: boolean (optional)
Overrides the master ``draggable`` property for this single event.
**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>`.
**weekMode**: String, *Default*: ``'fixed'``
Determines the number of weeks displayed in a month view.
Also determines each week's height. Available options:
``'fixed'``
The calendar will always be 6 weeks tall.
The ``aspectRatio`` will always be maintained.
``'liquid'``
The calendar will have either 4, 5, or 6 weeks, depending on the month.
The height of the weeks will stretch to fill the available height,
as determined by ``aspectRatio``.
``'variable'``
The calendar will have either 4, 5, or 6 weeks, depending on the month.
The ``aspectRatio`` will NOT be maintained however. Each week will have
a constant height, meaning the calendar's height will change month-to-month.
.. _allDayDefault:
**allDayDefault**: Boolean, *Default*: ``true``
Determines the default value for each :ref:`CalEvent's <CalEvent>` ``allDay`` property,
when it is unspecified.
Event Editing
=============
Extras
======
**editable**: Boolean, *Default*: ``false``
Determines whether the events on the calendar can be modified, i.e,
if the events will be *draggable* and *resizable*.
This can be overridden on a per-event basis with a :ref:`CalEvent's <CalEvent>`
``editable`` property.
For dragging, the `jQuery UI draggable <http://jqueryui.com/demos/draggable/>`_ library is required.
For resizing, the `jQuery UI resizable <http://jqueryui.com/demos/resizable/>`_ library is required.
**disableDragging**: Boolean, *Default*: ``false``
Disables all event dragging, even when events are editable.
FullCalendar provides some extra date utilities\:
**disableResizing**: Boolean, *Default*: ``false``
Disables all event resizing, even when events are editable.
**dragOpacity**: Float, *Default*: ``1.0``
The opacity of an event when it is being dragged.
**$.parseISO8601(string, ignoreTimezone)**
Parses an ISO8601 string and returns a ``Date`` object
**$.ISO8601String(date)**
Takes a ``Date`` object and returns an ISO8601 string
**dragRevertDuration**: Float, *Default*: ``500``
The time in milliseconds it takes for an event to revert to its
original position after an unsuccessful drag.
Time & Date Formatting
======================
**titleFormat**: String/Object
Determines the text that will be displayed in the header's title
using :ref:`formatDates' <formatDates>`' format string. A string will set the title format
for *all* views. An object hash will set the format on a per-view basis.
Here is the default, showing example outputs for each view::
{
month: 'MMMM yyyy', // September 2009
week: "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}", // Sep 7 - 13 2009
day: 'dddd, MMM d, yyyy' // Tuesday, Sep 8, 2009
}
**columnFormat**: String/Object
Determines the text that will be displayed on a view's column headings
using :ref:`formatDates' <formatDates>` format string. A string will set the column header format
for *all* views. An object hash will set the format on a per-view basis.
Here is the default, showing example outputs for each view::
{
month: 'ddd', // Mon
week: 'ddd M/d', // Mon 9/7
day: 'dddd M/d' // Monday 9/7
}
**timeFormat**: String, *Default*: ``'h(:mm)t'``
Determines the time-text that will be displayed on an event
using :ref:`formatDates' <formatDates>` format string. The default format outputs text
such as '9a' or '5:30p'.
Time-text will only be displayed for :ref:`CalEvent` that have
``allDay`` equal to ``false``.
.. _available-views:
Available Views
===============
**month** - `see example <../../media/fullcalendar-views/month.html>`_
**basicWeek** - `see example <../../media/fullcalendar-views/basicWeek.html>`_
**basicDay** - `see example <../../media/fullcalendar-views/basicDay.html>`_

36
docs/locale.txt Executable file
View File

@ -0,0 +1,36 @@
.. _locale:
Locale Options
==============
**firstDay**: Integer, *Default*: ``0``
The day-of-week each week begins. Sunday=0,
Monday=1 (for UK users), Tuesday=2, etc.
**isRTL**: Boolean, *Default*: ``false``
Displays the calendar right-to-left (for languages such as Arabic and Hebrew)
**monthNames**: Array, *Default*: ``['January','February','March'...``
Full names of months.
**monthNamesShort**: Array, *Default*: ``['Jan','Feb','Mar'...``
Abbreviated names of months.
**dayNames**: Array, *Default*: ``['Sunday','Monday','Tuesday'...``
Full names of days-of-week.
**dayNamesShort**: Array, *Default*: ``['Sun','Mon','Tue'...``
Abbreviated names of days-of-week.
**buttonText**: Object
Text that will be displayed on buttons of the header. Default::
{
prev: '&nbsp;&#9668;&nbsp;', // left triangle
next: '&nbsp;&#9658;&nbsp;', // right triangle
today: 'today',
month: 'month',
week: 'week',
day: 'day'
}

89
docs/methods.txt Executable file
View File

@ -0,0 +1,89 @@
Methods
=======
The following are methods that can be called on a FullCalendar-initialized
jQuery object:
**prev** - .fullCalendar('prev')
Moves the calendar one step back (either by a month, week, or day).
**next** - .fullCalendar('next')
Moves the calendar one step forward (either by a month, week, or day).
**today** - .fullCalendar('today')
Moves the calendar to the current date.
**gotoDate** - .fullCalendar('gotoDate', *year, [month, [date]]*)
Moves the calendar to an arbitrary year/month/date.
``month`` is 0-based, meaning January=0, February=1, etc.
This method can also be called with a single argument, a Date object.
**incrementDate** - .fullCalendar('incrementDate', *years, [months, [days]]*)
Moves the calendar forward/backward an arbitrary amount of time.
**changeView** - .fullCalendar('changeView', *viewName*)
Immediately switches to a different view. ``viewName`` must be one of the
:ref:`available-views`.
**updateEvent** - .fullCalendar('updateEvent', *calEvent*)
Reports changes to a :ref:`CalEvent's <CalEvent>` standard properties.
This will cause the event to be rerendered on the calendar.
If there are repeating events on the calendar with the
same ID, these events will be changed as well.
``calEvent`` must be a :ref:`CalEvent <CalEvent>` retrieved from a
:ref:`Triggered Action<triggered-actions>` or from the ``clientEvents`` method.
**renderEvent** - .fullCalendar('renderEvent', *calEvent, [stick]*)
Renders a new event on the calendar. ``calEvent`` must have
at least a ``title`` and a ``start``.
By default, the event will disappear once the calendar refetches its event
sources (example: when prev/next is clicked). However, specifying ``stick`` as ``true``
will cause the event to be permanently fixed to the calendar.
**removeEvents** - .fullCalendar('removeEvents', *[idOrFilter]*)
If the second argument is omitted, all events are removed.
If the second argument is an ID, all events with
the same ID will be removed.
The second argument may also be a filter function that accepts
one :ref:`CalEvent <CalEvent>` argument and returns ``true`` if it
should be removed.
**clientEvents** - .fullCalendar('clientEvents', *[idOrFilter]*)
This method will return an array of :ref:`CalEvents <CalEvent>` that
FullCalendar has stored on the client-side (browser).
If the second argument is omitted, all events will be returned.
If the second argument is an ID, all events with the
same ID will be returned.
The second argument may also be a filter function that accepts
one :ref:`CalEvent <CalEvent>` argument and returns ``true`` if it should
be included in the result set.
**addEventSource** - .fullCalendar('addEventSource', *source*)
Adds an :ref:`Event Source <event-sources>`. ``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.
**removeEventSource** - .fullCalendar('removeEventSource', *source*)
Removes an :ref:`Event Source <event-sources>`. ``source`` must be a reference to the
original array/string/function. Events from the source will immediately be
removed from the calendar.
**rerenderEvents** - .fullCalendar(``'rerenderEvents'``)
Rerenders all events on the screen.
**refetchEvents** - .fullCalendar(``'refetchEvents'``)
Refetches events from all sources and rerenders them on the screen.
**render** - .fullCalendar(``'render'``)
Immediately renders the calendar. This method is automatically called if the $().fullCalendar
plugin is called on a visible element. However, if a hidden/invisible element is initialized
with FullCalendar, this method must be explicitly called as soon as the element becomes visible.

View File

@ -1,8 +1,9 @@
<? fullcalendar_docs_head() ?>
<? fullcalendar_title() ?>
<? fullcalendar_nav() ?>
<? fullcalendar_docs_nav() ?>
<? begin_content() ?>
{% block body %}{% endblock %}
<? end_content() ?>
<? fullcalendar_side() ?>

25
docs/theming.txt Executable file
View File

@ -0,0 +1,25 @@
Theming
=======
FullCalendar can be used with jQuery UI themes. Themes provide a more stylized
look for the calendar and can easily be created using the
`jQuery UI ThemeRoller <http://jqueryui.com/themeroller/>`_.
In order for themes to work, you must include the theme's CSS file and
*fullcalendar.css* on the current page. You must also enable the ``theme`` option.
Here is the full list of theme-related options:
**theme**: Boolean, *Default*: ``false``
Enables/disables use of jQuery UI themes
**buttonIcons**: Object
Determines which icons appear within header buttons. If a button
does not have an entry, it falls back to using ``buttonText``.
Here is the default value for ``buttonIcons``::
{
prev: 'circle-triangle-w',
next: 'circle-triangle-e'
}

132
docs/triggered-actions.txt Executable file
View File

@ -0,0 +1,132 @@
.. _triggered-actions:
Triggered Actions
=================
The following options are *functions* that get executed every time something
special happens. For every triggered action, a final ``view`` parameter is
always available (:ref:`more below <view-object>`).
**viewDisplay**: function(*view*)
Triggered once when the calendar loads and every time the
calendar's view is changed. This includes when the prev or next
button is pressed.
**loading**: function(*isLoading, view*)
Triggered with a ``true`` argument when the calendar begins fetching
events via AJAX. Triggered with ``false`` when done.
**windowResize**: function(*view*)
Triggered after the calendar's dimensions have been changed due to
the containing window being resized.
``this`` is set to the main element.
**dayClick**: function(*dayDate, view*)
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, view*)
Triggered before an element is rendered for the given :ref:`CalEvent <CalEvents>`.
``element`` is the jQuery element that will be used by default. You may modify
this element or return a brand new element that will be used instead.
Returning ``false`` will prevent the event from being rendered at all.
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, view*)
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, view*)
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, minuteDelta, revertFunc, jsEvent, ui, view*)
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).
``minuteDelta`` will always be ``0`` and is reserved for a future release
of FullCalendar where there will be an agenda view.
``dayDelta`` and ``minuteDelta`` are elegant for dealing with multi-day and
repeating events. If updating a remote database, just add these values to the
start and end times of all events with the given ``calEvent.id``
``revertFunc`` is a function that, if called, reverts the event's start/end date to
the values *before* the drag. This is useful if an ajax call should fail.
**eventResizeStart**, **eventResizeStop**: function(*calEvent, jsEvent, ui, view*)
Triggered before/after an event is resized (but not necessarily changed).
``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
**eventResize**: function(*calEvent, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view*)
Triggered when an event is resized and *changed in duration*.
``dayDelta`` holds the number of days the event's end time was moved
forward (a positive number) or backwards (a negative number).
``minuteDelta`` will always be ``0`` and is reserved for a future release
of FullCalendar where there will be an agenda view.
``revertFunc`` is a function that, if called, reverts the event's start/end date to
the values *before* the drag. This is useful if an ajax call should fail.
.. _view-object:
View Object
===========
The final parameter of every triggered action is a *view* object. It contains information about the
current view (whether month/basicWeek/basicDay) and contains the following properties:
**name**: String
Name of one of the available views (month, basicWeek, basicDay)
**title**: String
Title text that is displayed at the top of the header
(such as "September 2009" or "Sep 7 - 13 2009").
**start**: Date
The Date of the first day of the month/week.
If day-view, the Date of the single day.
**end**: Date
The Date of the day *after* the last day of the month/week.
If day-view, the Date *after* the single day.
Because this is an *exclusive* value, if the calendar has a
month-view on October 2009, ``end`` will be November 1st.
**visStart**: Date
The Date of the first *visible* day of the view. In month-view,
this value is often before the 1st day of the month, because most
months do not begin on a Monday.
In week and day views, this value will always be the same as ``start``.
**visEnd**: Date
The Date of the day *after* the last visible day
(because it is exclusive like ``end``).

View File

@ -1,10 +1,82 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!--<src>-->
<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
<script type='text/javascript' src='../src/jquery/jquery.js'></script>
<script type='text/javascript' src='../src/jquery/ui.core.js'></script>
<script type='text/javascript' src='../src/jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../src/jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../src/main.js'></script>
<script type='text/javascript' src='../src/grid.js'></script>
<script type='text/javascript' src='../src/view.js'></script>
<script type='text/javascript' src='../src/util.js'></script>
<!--</src>-->
<!--
<dist>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../fullcalendar.min.js'></script>
</dist>
-->
<script type='text/javascript'>
$(document).ready(function() {
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$('#calendar').fullCalendar({
editable: true,
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6, 14, 0),
end: new Date(y, m, 11),
allDay: false
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 2),
allDay: true
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 9),
allDay: true
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27, 16),
end: new Date(y, m, 29),
url: "http://facebook.com/",
allDay: false
}
]
});
});
</script>
<style type='text/css'>
body {
margin-top: 50px;
margin-top: 40px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
@ -16,58 +88,8 @@
}
</style>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../fullcalendar.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$('#calendar').fullCalendar({
draggable: true,
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 11)
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0)
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 29),
url: "http://facebook.com/"
}
]
});
});
</script>
</head>
<body>
<div id='calendar'></div>
</body>
</html>
</html>

View File

@ -1,10 +1,53 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!--<src>-->
<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
<script type='text/javascript' src='../src/jquery/jquery.js'></script>
<script type='text/javascript' src='../src/main.js'></script>
<script type='text/javascript' src='../src/grid.js'></script>
<script type='text/javascript' src='../src/view.js'></script>
<script type='text/javascript' src='../src/util.js'></script>
<script type='text/javascript' src='../src/gcal.js'></script>
<!--</src>-->
<!--
<dist>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../fullcalendar.min.js'></script>
<script type='text/javascript' src='../gcal.js'></script>
</dist>
-->
<script type='text/javascript'>
$(document).ready(function() {
$('#calendar').fullCalendar({
// US Holidays
events: $.fullCalendar.gcalFeed('http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic'),
eventClick: function(event) {
// opens events in a popup window
window.open(event.url, 'gcalevent', 'width=700,height=600');
return false;
},
loading: function(bool) {
if (bool) $('#loading').show();
else $('#loading').hide();
}
});
});
</script>
<style type='text/css'>
body {
margin-top: 50px;
margin-top: 40px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
@ -22,30 +65,6 @@
}
</style>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../fullcalendar.js'></script>
<script type='text/javascript' src='../gcal.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
$('#calendar').gcalFullCalendar({
// US Holidays
events: 'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic',
eventClick: function(event) {
window.open(event.url, 'gcalevent', 'width=700,height=600');
return false;
},
loading: function(bool) {
if (bool) $('#loading').show();
else $('#loading').hide();
}
});
});
</script>
</head>
<body>
<div id='loading' style='display:none'>loading...</div>

View File

@ -6,14 +6,14 @@
echo json_encode(array(
array(
'id' => 1,
'id' => 111,
'title' => "Event1",
'start' => "$year-$month-10",
'url' => "http://yahoo.com/"
),
array(
'id' => 2,
'id' => 222,
'title' => "Event2",
'start' => "$year-$month-20",
'end' => "$year-$month-22",

View File

@ -1,10 +1,57 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!--<src>-->
<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
<script type='text/javascript' src='../src/jquery/jquery.js'></script>
<script type='text/javascript' src='../src/jquery/ui.core.js'></script>
<script type='text/javascript' src='../src/jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../src/jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../src/main.js'></script>
<script type='text/javascript' src='../src/grid.js'></script>
<script type='text/javascript' src='../src/view.js'></script>
<script type='text/javascript' src='../src/util.js'></script>
<!--</src>-->
<!--
<dist>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../fullcalendar.min.js'></script>
</dist>
-->
<script type='text/javascript'>
$(document).ready(function() {
$('#calendar').fullCalendar({
editable: true,
events: "json-events.php",
eventDrop: function(event, delta) {
alert(event.title + ' was moved ' + delta + ' days\n' +
'(should probably update your database)');
},
loading: function(bool) {
if (bool) $('#loading').show();
else $('#loading').hide();
}
});
});
</script>
<style type='text/css'>
body {
margin-top: 50px;
margin-top: 40px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
@ -22,35 +69,10 @@
}
</style>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../fullcalendar.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
$('#calendar').fullCalendar({
draggable: true,
events: "json_events.php",
eventDrop: function(event, delta) {
alert(event.title + ' was moved ' + delta + ' days\n' +
'(should probably update your database)');
},
loading: function(bool) {
if (bool) $('#loading').show();
else $('#loading').hide();
}
});
});
</script>
</head>
<body>
<div id='loading' style='display:none'>loading...</div>
<div id='calendar'></div>
<p>json_events.php needs to be running in the same directory.</p>
<p>json-events.php needs to be running in the same directory.</p>
</body>
</html>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

406
examples/redmond/theme.css Executable file
View File

@ -0,0 +1,406 @@
/*
* jQuery UI CSS Framework
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; outline: none; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; outline: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; outline: none; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; outline: none; }
.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; outline: none; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; outline: none; text-decoration: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; }
.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion
----------------------------------*/
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
.ui-accordion .ui-accordion-li-fix { display: inline; }
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker
----------------------------------*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}/* Dialog
----------------------------------*/
.ui-dialog { position: relative; padding: .2em; width: 300px; }
.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/* Progressbar
----------------------------------*/
.ui-progressbar { height:2em; text-align: left; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable
----------------------------------*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider
----------------------------------*/
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
----------------------------------*/
.ui-tabs { padding: .2em; zoom: 1; }
.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }

102
examples/theme.html Executable file
View File

@ -0,0 +1,102 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<link rel='stylesheet' type='text/css' href='redmond/theme.css' />
<!--<src>-->
<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
<script type='text/javascript' src='../src/jquery/jquery.js'></script>
<script type='text/javascript' src='../src/jquery/ui.core.js'></script>
<script type='text/javascript' src='../src/jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../src/jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../src/main.js'></script>
<script type='text/javascript' src='../src/grid.js'></script>
<script type='text/javascript' src='../src/view.js'></script>
<script type='text/javascript' src='../src/util.js'></script>
<!--</src>-->
<!--
<dist>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../fullcalendar.min.js'></script>
</dist>
-->
<script type='text/javascript'>
$(document).ready(function() {
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$('#calendar').fullCalendar({
theme: true,
editable: true,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6, 14, 0),
end: new Date(y, m, 11),
allDay: false
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 2),
allDay: true
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 9),
allDay: true
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27, 16),
end: new Date(y, m, 29),
url: "http://facebook.com/",
allDay: false
}
]
});
});
</script>
<style type='text/css'>
body {
margin-top: 40px;
text-align: center;
font-size: 13px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
}
#calendar {
width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>

101
examples/views.html Executable file
View File

@ -0,0 +1,101 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!--<src>-->
<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
<script type='text/javascript' src='../src/jquery/jquery.js'></script>
<script type='text/javascript' src='../src/jquery/ui.core.js'></script>
<script type='text/javascript' src='../src/jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../src/jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../src/main.js'></script>
<script type='text/javascript' src='../src/grid.js'></script>
<script type='text/javascript' src='../src/view.js'></script>
<script type='text/javascript' src='../src/util.js'></script>
<!--</src>-->
<!--
<dist>
<link rel='stylesheet' type='text/css' href='../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../jquery/ui.resizable.js'></script>
<script type='text/javascript' src='../fullcalendar.min.js'></script>
</dist>
-->
<script type='text/javascript'>
$(document).ready(function() {
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$('#calendar').fullCalendar({
editable: true,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6, 14, 0),
end: new Date(y, m, 11),
allDay: false
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 2),
allDay: true
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 9),
allDay: true
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27, 16),
end: new Date(y, m, 29),
url: "http://facebook.com/",
allDay: false
}
]
});
});
</script>
<style type='text/css'>
body {
margin-top: 40px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
text-align: left;
}
#calendar {
width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>

View File

@ -1,135 +0,0 @@
/* top area w/ month title and buttons */
.full-calendar-header {
text-align: left;
}
.full-calendar-buttons {
float: right;
}
.full-calendar-buttons input {
vertical-align: middle;
font-size: 1.0em;
}
.full-calendar-prev,
.full-calendar-next {
width: 40px;
margin-left: 5px;
}
/* table & borders */
.full-calendar-month {
clear: both;
overflow: hidden; /*
^ prevents draggable events from leaving.
reason for our long-winded border css.
borders now look consistent across doctypes. */
border: 1px solid #ccc; /* border color & style */
}
.full-calendar-month table {
border-collapse: collapse;
border-spacing: 0;
}
.full-calendar-month th.day-heading,
.full-calendar-month td.day {
padding: 0;
vertical-align: top;
border-style: solid; /* border style */
border-color: #ccc; /* border color */
border-width: 1px 0 0 1px;
}
.full-calendar-month tr.day-headings th {
border-top: 0;
}
.full-calendar-month th.sun,
.full-calendar-month td.sun {
border-left: 0;
}
/* day styling */
.full-calendar-month td.today {
background: #FFFFCC;
}
.full-calendar-month .day-number {
text-align: right;
padding-right: 2px;
}
.full-calendar-month .other-month .day-number {
color: #bbb;
}
.full-calendar-month .day-content {
padding: 2px 2px 0; /* distance between events and day edges */
}
.full-calendar-month td.day {
/* FullCalendar automatically chooses a height, but this can be overridden: */
/* height: 100px !important; */
}
/* event styling */
.full-calendar-month .event {
margin-bottom: 2px;
font-size: .85em;
cursor: pointer;
text-align: left;
}
.full-calendar-month .ui-draggable-dragging td {
cursor: move;
}
.full-calendar-month .event td {
background: #C1D9EC;
padding: 0;
}
.full-calendar-month .event td.ne,
.full-calendar-month .event td.nw,
.full-calendar-month .event td.se,
.full-calendar-month .event td.sw {
background: none;
width: 1px; /* <-- remove if you dont want "rounded" corners */
height: 1px; /* <-- */
}
.full-calendar-month .nobg td {
background: none;
}
.full-calendar-month .event td.c {
padding: 0 2px;
}
.full-calendar-month .event-time {
font-weight: bold;
}
/* the rectangle that covers a day when dragging an event */
.full-calendar-month .over-day {
background: #ADDBFF;
opacity: .2;
filter: alpha(opacity=20);
}

View File

@ -1,728 +0,0 @@
/*
* FullCalendar
* http://arshaw.com/fullcalendar/
*
* use fullcalendar.css for basic styling
* requires jQuery UI core and draggables ONLY if you plan to do drag & drop
*
* Copyright (c) 2009 Adam Shaw
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Date:
* Revision:
*/
(function($) {
$.fn.fullCalendar = function(options) {
if (typeof options == 'string') {
var args = Array.prototype.slice.call(arguments, 1);
this.each(function() {
$.data(this, 'fullCalendar')[options].apply(this, args);
});
return this;
}
options = options || {};
var showTime = typeof options.showTime == 'undefined' ? 'guess' : options.showTime;
var bo = options.buttons;
this.each(function() {
var date = options.year ? new Date(options.year, options.month || 0, 1) : new Date();
var start, end, today, numWeeks;
var events = typeof options.events != 'string' && !$.isFunction(options.events) ?
cleanEvents(options.events) : null;
var ignoreResizes = false;
function updateMonth() {
clearEvents();
render();
}
function today() {
date = new Date();
updateMonth();
}
function prevMonth() {
addMonths(date, -1);
updateMonth();
}
function nextMonth() {
addMonths(date, 1);
updateMonth();
}
function gotoMonth(year, month) {
date = new Date(year, month, 1);
updateMonth();
}
$.data(this, 'fullCalendar', {
today: today,
prevMonth: prevMonth,
nextMonth: nextMonth,
gotoMonth: gotoMonth,
refresh: updateMonth
});
var titleElement, todayButton, monthElement;
var header = $("<div class='full-calendar-header'/>").appendTo(this);
if (bo != false) {
var buttons = $("<div class='full-calendar-buttons'/>").appendTo(header);
todayButton =
$("<input type='button' class='full-calendar-today' value='today'/>")
.click(today);
var prevButton =
$("<input type='button' class='full-calendar-prev' value='&lt;'/>")
.click(prevMonth);
var nextButton =
$("<input type='button' class='full-calendar-next' value='&gt;'/>")
.click(nextMonth);
if (typeof bo == 'object') {
if (bo.today != false) {
if (typeof bo.today == 'string') todayButton.val(bo.today);
buttons.append(todayButton);
}
if (bo.prev != false) {
if (typeof bo.prev == 'string') prevButton.val(bo.prev);
buttons.append(prevButton);
}
if (bo.next != false) {
if (typeof bo.next == 'string') nextButton.val(bo.next);
buttons.append(nextButton);
}
}else{
buttons
.append(todayButton)
.append(prevButton)
.append(nextButton);
}
}
if (options.title !== false)
titleElement = $("<h2 class='full-calendar-title'/>").appendTo(header);
monthElement = $("<div class='full-calendar-month' style='position:relative'/>").appendTo(this);
var tbody, glass, monthTitle;
function render() {
ignoreResizes = true;
date.setDate(1);
clearTime(date);
var year = date.getFullYear();
var month = date.getMonth();
monthTitle = monthNames[month] + ' ' + year;
if (titleElement) titleElement.text(monthTitle);
clearTime(date);
start = cloneDate(date);
addDays(start, -start.getDay());
end = cloneDate(date);
addMonths(end, 1);
addDays(end, (7 - end.getDay()) % 7);
numWeeks = Math.round((end.getTime() - start.getTime()) / 604800000);
if (options.fixedWeeks != false) {
addDays(end, (6 - numWeeks) * 7);
numWeeks = 6;
}
today = clearTime(new Date());
if (todayButton) {
if (today.getFullYear() == year && today.getMonth() == month) {
todayButton.css('visibility', 'hidden');
}else{
todayButton.css('visibility', 'visible');
}
}
if (!tbody) {
tbody = "<tbody><tr class='day-headings'>";
for (var i=0; i<7; i++) {
tbody +=
"<th class='day-heading " + dayAbbrevs[i].toLowerCase() + "'>" +
(options.abbrevDayHeadings!=false ? dayAbbrevs[i] : dayNames[i]) +
"</th>";
}
var d = cloneDate(start);
for (var i=0; i<numWeeks; i++) {
tbody += "<tr class='week"+(i+1)+"'>";
for (var j=0; j<7; j++) {
tbody +=
"<td class='day " + dayAbbrevs[j].toLowerCase() +
(d.getMonth() == month ? '' : ' other-month') +
(d.getTime() == today.getTime() ? ' today' : '') +
"'><div class='day-number'>" + d.getDate() + "</div>" +
"<div class='day-content'><div/></div></td>";
addDays(d, 1);
}
tbody += "</tr>";
}
tbody += "</tr></tbody>";
tbody = $(tbody)
.appendTo($("<table style='width:100%'/>")
.appendTo(monthElement));
glass = $("<div style='position:absolute;top:0;left:0;z-index:1;width:100%' />")
.appendTo(monthElement)
.click(function(ev, ui) {
if (options.dayClick) {
buildDayGrid();
var td = dayTD(ev.pageX, ev.pageY);
if (td) return options.dayClick.call(td, dayDate(td));
}
});
}else{
var diff = numWeeks - (tbody.find('tr').length - 1);
if (diff < 0) {
tbody.find('tr:gt(' + numWeeks + ')').remove();
}
else if (diff > 0) {
var trs = "";
for (var i=0; i<diff; i++) {
trs += "<tr class='week"+(numWeeks+i)+"'>";
for (var j=0; j<7; j++) {
trs +=
"<td class='day " + dayAbbrevs[j].toLowerCase() + "'>" +
"<div class='day-number'></div>" +
"<div class='day-content'><div/></div>" +
"</td>";
}
trs += "</tr>";
}
if (trs) tbody.append(trs);
}
var d = cloneDate(start);
tbody.find('td').each(function() {
if (d.getMonth() == month) {
$(this).removeClass('other-month');
}else{
$(this).addClass('other-month');
}
if (d.getTime() == today.getTime()) {
$(this).addClass('today');
}else{
$(this).removeClass('today');
}
$(this.childNodes[0]).text(d.getDate());
addDays(d, 1);
});
}
resizeTable();
if (typeof options.events == 'string') {
if (options.loading) options.loading(true);
var jsonOptions = {};
jsonOptions[options.startParam || 'start'] = Math.round(start.getTime() / 1000);
jsonOptions[options.endParam || 'end'] = Math.round(end.getTime() / 1000);
$.getJSON(options.events, jsonOptions, function(data) {
events = cleanEvents(data);
renderEvents(events);
if (options.loading) options.loading(false);
});
}
else if ($.isFunction(options.events)) {
if (options.loading) options.loading(true);
options.events(start, end,
function(data) {
events = cleanEvents(data);
renderEvents(events);
if (options.loading) options.loading(false);
});
}
else if (events) renderEvents(events);
ignoreResizes = false;
if (options.monthDisplay)
options.monthDisplay(date.getFullYear(), date.getMonth(), monthTitle);
}
var eventMatrix = [];
function renderEvents() {
eventMatrix = [];
var i = 0;
var ws = cloneDate(start);
var we = addDays(cloneDate(ws), 7);
while (ws.getTime() < end.getTime()) {
var segs = [];
$.each(events, function(j, event) {
if (event.end.getTime() > ws.getTime() && event.start.getTime() < we.getTime()) {
var ss, se, isStart, isEnd;
if (event.start.getTime() < ws.getTime()) {
ss = cloneDate(ws);
isStart = false;
}else{
ss = cloneDate(event.start);
isStart = true;
}
if (event.end.getTime() > we.getTime()) {
se = cloneDate(we);
isEnd = false;
}else{
se = cloneDate(event.end);
isEnd = true;
}
ss = clearTime(ss);
se = clearTime((se.getHours()==0 && se.getMinutes()==0) ? se : addDays(se, 1));
segs.push({
event: event, start: ss, end: se,
isStart: isStart, isEnd: isEnd, msLength: se - ss
});
}
});
segs.sort(function(a, b) { return b.msLength - a.msLength; });
var levels = [];
$.each(segs, function(j, seg) {
var l = 0; // level index
while (true) {
var collide = false;
if (levels[l]) {
for (var k=0; k<levels[l].length; k++) {
if (seg.end.getTime() > levels[l][k].start.getTime() &&
seg.start.getTime() < levels[l][k].end.getTime()) {
collide = true;
break;
}
}
}
if (collide) {
l++;
continue;
}else{
break;
}
}
if (levels[l]) levels[l].push(seg);
else levels[l] = [seg];
});
eventMatrix[i] = levels;
addDays(ws, 7);
addDays(we, 7);
i++;
}
_renderEvents();
}
var eventElements = []; // [[event, element], ...]
function _renderEvents() {
for (var i=0; i<eventMatrix.length; i++) {
var levels = eventMatrix[i];
var tr = tbody.find('tr:eq('+(i+1)+')');
var innerDiv = tr.find('td:first div.day-content div');
var top = innerDiv.position().top;
var height = 0;
for (var j=0; j<levels.length; j++) {
var segs = levels[j];
var maxh = 0;
for (var k=0; k<segs.length; k++) {
var seg = segs[k];
var event = seg.event;
var left1 = seg.isStart ?
tr.find('td:eq('+seg.start.getDay()+') div.day-content div').position().left :
tbody.position().left;
var left2 = seg.isEnd ?
tr.find('td:eq('+((seg.end.getDay()+6)%7)+') div.day-content div') :
tbody;
left2 = left2.position().left + left2.width();
var element = $("<table class='event' />")
.append("<tr>" +
(seg.isStart ? "<td class='nw'/>" : '') +
"<td class='n'/>" +
(seg.isEnd ? "<td class='ne'/>" : '') + "</tr>")
.append("<tr>" +
(seg.isStart ? "<td class='w'/>" : '') +
"<td class='c'/>" +
(seg.isEnd ? "<td class='e'/>" : '') + "</tr>")
.append("<tr>" +
(seg.isStart ? "<td class='sw'/>" : '') +
"<td class='s'/>" +
(seg.isEnd ? "<td class='se'/>" : '') + "</tr>");
buildEventText(element.find('td.c'), event,
typeof event.showTime == 'undefined' ? showTime : event.showTime);
if (options.eventRender) {
var res = options.eventRender(event, element);
if (typeof res != 'undefined') {
if (res === false) continue;
if (res !== true) element = $(res);
}
}
element
.css({
position: 'absolute',
top: top,
left: left1,
width: left2 - left1,
'z-index': 3
})
.appendTo(monthElement);
initEventElement(event, element);
var h = element.outerHeight({margin:true});
if (h > maxh) maxh = h;
}
height += maxh;
top += maxh;
}
innerDiv.height(height);
}
}
function initEventElement(event, element) {
element.click(function(ev) {
if (!element.hasClass('ui-draggable-dragging')) {
if (options.eventClick) {
var res = options.eventClick.call(this, event, ev);
if (res === false) return false;
}
if (event.url) window.location.href = event.url;
}
});
if (options.eventMouseover)
element.mouseover(function(ev) {
options.eventMouseover.call(this, event, ev);
});
if (options.eventMouseout)
element.mouseout(function(ev) {
options.eventMouseout.call(this, event, ev);
});
if (typeof event.draggable != 'undefined') {
if (event.draggable)
draggableEvent(event, element);
}
else if (options.draggable) {
draggableEvent(event, element);
}
eventElements.push([event, element]);
}
var dragStartTD, dragTD;
var dayOverlay;
function draggableEvent(event, element) {
element.draggable({
zIndex: 3,
delay: 50,
opacity: options.eventDragOpacity,
revertDuration: options.eventRevertDuration,
start: function(ev, ui) {
// hide other elements with same event
for (var i=0; i<eventElements.length; i++) {
var x = eventElements[i];
var xevent = x[0];
if (x[1].get(0) != this && (xevent == event ||
typeof xevent.id != 'undefined' && xevent.id == event.id))
x[1].hide();
}
if (!dayOverlay)
dayOverlay =
$("<div class='over-day' style='position:absolute;z-index:2' />")
.appendTo(monthElement);
buildDayGrid();
dragTD = dragStartTD = null;
eventDrag(this, ev, ui);
if (options.eventDragStart)
options.eventDragStart.call(this, event, ev, ui);
},
drag: function(ev, ui) {
eventDrag(this, ev, ui);
},
stop: function(ev, ui) {
if (!dragTD || dragTD == dragStartTD) {
// show all events
for (var i=0; i<eventElements.length; i++)
eventElements[i][1].show();
}else{
var delta = dayDelta(dragStartTD, dragTD);
for (var i=0; i<events.length; i++) {
if (event == events[i] || typeof event.id != 'undefined' && event.id == events[i].id) {
addDays(events[i].start, delta, true);
addDays(events[i].end, delta, true);
}
}
if (options.eventDrop)
options.eventDrop.call(this, event, delta, ev, ui);
clearEvents();
renderEvents();
}
dayOverlay.hide();
if (options.eventDragStop)
options.eventDragStop.call(this, event, ev, ui);
}
});
}
function eventDrag(node, ev, ui) {
var oldTD = dragTD;
dragTD = dayTD(ev.pageX, ev.pageY);
if (!dragStartTD) dragStartTD = dragTD;
if (dragTD != oldTD) {
if (dragTD) {
$(node).draggable('option', 'revert', dragTD==dragStartTD);
dayOverlay.css({
top: currTDY,
left: currTDX,
width: currTDW,
height: currTDH,
display: 'block'
});
}else{
$(node).draggable('option', 'revert', true);
dayOverlay.hide();
}
}
}
var dayX, dayY, dayX0, dayY0;
var currTD, currR, currC;
var currTDX, currTDY, currTDW, currTDH;
function buildDayGrid() {
var tr, td, o=monthElement.offset();
dayX0 = o.left;
dayY0 = o.top;
dayY = [];
tbody.find('tr:gt(0)').each(function() {
tr = $(this);
dayY.push(tr.position().top);
});
dayY.push(dayY[dayY.length-1] + tr.height());
dayX = [];
tr.find('td').each(function() {
td = $(this);
dayX.push(td.position().left);
});
dayX.push(dayX[dayX.length-1] + td.width());
currTD = null;
}
function dayTD(x, y) {
var r=-1, c=-1;
var rmax=dayY.length-1, cmax=dayX.length-1;
while (r < rmax && y > dayY0 + dayY[r+1]) r++;
while (c < cmax && x > dayX0 + dayX[c+1]) c++;
if (r < 0 || r >= rmax || c < 0 || c >= cmax)
return currTD = null;
else if (!currTD || r != currR || c != currC) {
currR = r;
currC = c;
currTD = tbody.find('tr:eq('+(r+1)+') td:eq('+c+')').get(0);
currTDX = dayX[c];
currTDY = dayY[r];
currTDW = dayX[c+1] - currTDX;
currTDH = dayY[r+1] - currTDY;
return currTD;
}
return currTD;
}
function dayDate(node) {
var i, tds = tbody.get(0).getElementsByTagName('td');
for (i=0; i<tds.length; i++) {
if (tds[i] == node) break;
}
var d = cloneDate(start);
return addDays(d, i);
}
function dayDelta(node1, node2) {
var i1, i2, tds = tbody.get(0).getElementsByTagName('td');
for (var i=0; i<tds.length; i++) {
if (tds[i] == node1) i1 = i;
if (tds[i] == node2) i2 = i;
}
return i2 - i1;
}
function resizeTable() {
var cellw = Math.floor(tbody.width() / 7);
var cellh = Math.round(cellw * .85);
tbody.find('th:lt(6)').width(cellw);
tbody.find('td').height(cellh);
glass.height(monthElement.height());
}
function clearEvents() {
for (var i=0; i<eventElements.length; i++)
eventElements[i][1].remove();
eventElements = [];
}
$(window).resize(function() {
if (!ignoreResizes) {
clearEvents();
resizeTable();
_renderEvents();
}
});
render();
});
return this;
};
// event utils
function buildEventText(element, event, showTime) {
if (showTime != false) {
var h = event.start.getHours();
var m = event.start.getMinutes();
if (showTime == true || showTime == 'guess' &&
(h || m || event.end.getHours() || event.end.getMinutes())) {
element.append($("<span class='event-time' />")
.text((h%12 || 12) + (h<12 ? 'a' : 'p') + ' '));
}
}
element.append($("<span class='event-title' />")
.text(event.title));
}
function cleanEvents(events) {
$.each(events, function(i, event) {
if (event.date) event.start = event.date;
event.start = cleanDate(event.start);
event.end = cleanDate(event.end);
if (!event.end) event.end = addDays(cloneDate(event.start), 1);
});
return events;
}
// date utils
var monthNames = ['January','February','March','April','May','June','July','August','September','October','November','December'];
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);
if (keepTime) return d;
return clearTime(d);
}
function addDays(d, n, keepTime) {
d.setDate(d.getDate() + n);
if (keepTime) return d;
return clearTime(d);
}
function clearTime(d) {
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setMilliseconds(0);
return d;
}
function cloneDate(d) {
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);
}
offset -= date.getTimezoneOffset();
}
return new Date(Number(date) + (offset * 60 * 1000));
};
$.ISO8601String = function(date) {
// derived from http://delete.me.uk/2005/03/iso8601.html
var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }
return date.getUTCFullYear() +
"-" + zeropad(date.getUTCMonth() + 1) +
"-" + zeropad(date.getUTCDate()) +
"T" + zeropad(date.getUTCHours()) +
":" + zeropad(date.getUTCMinutes()) +
":" + zeropad(date.getUTCSeconds()) +
"Z";
};
})(jQuery);

76
gcal.js
View File

@ -1,76 +0,0 @@
/*
* gcalFullCalendar extension for fullCalendar
* http://arshaw.com/fullcalendar/
*
* Same usage/options as fullCalendar.
* However, enter your Google Calendar's public feed URL in the 'events' option.
* Here is how to find it in the Google Calendar interface:
*
* -> click the arrow next to your calendar's name
* -> click "Share this calendar"
* -> check "Make this calendar public" and then Save
* -> click the arrow again, then click "Calendar settings"
* -> in the "Calendar Address" section, click the XML rectangle
* -> the URL is displayed
*
* Copyright (c) 2009 Adam Shaw
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
(function($) {
$.fn.gcalFullCalendar = function(options) {
var feedURL;
if (options && typeof options.events == 'string') {
feedURL = options.events;
}
else return this;
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
});
});
callback(events);
});
},
eventRender: function(event, element) {
if (!event.allDay) element.addClass('nobg');
}
});
return this.fullCalendar(options);
};
})(jQuery);

View File

@ -1,54 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<style type='text/css'>
body {
margin-top: 50px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
}
#loading {
position: absolute;
top: 5px;
right: 5px;
}
#calendar {
width: 900px;
margin: 0 auto;
}
</style>
<link rel='stylesheet' type='text/css' href='../../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../../fullcalendar.js'></script>
<script type='text/javascript' src='../../gcal.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
$('#calendar').gcalFullCalendar({
// US Holidays
events: 'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic',
eventClick: function(event) {
window.open(event.url, 'gcalevent', 'width=700,height=600');
return false;
},
loading: function(bool) {
if (bool) $('#loading').show();
else $('#loading').hide();
}
});
});
</script>
</head>
<body>
<div id='loading' style='display:none'>loading...</div>
<div id='calendar'></div>
</body>
</html>

View File

@ -1,56 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<style type='text/css'>
body {
margin-top: 50px;
text-align: center;
font-size: 14px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
}
#loading {
position: absolute;
top: 5px;
right: 5px;
}
#calendar {
width: 900px;
margin: 0 auto;
}
</style>
<link rel='stylesheet' type='text/css' href='../../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../../fullcalendar.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
$('#calendar').fullCalendar({
draggable: true,
events: "json_events.php",
eventDrop: function(event, delta) {
alert(event.title + ' was moved ' + delta + ' days\n' +
'(should probably update your database)');
},
loading: function(bool) {
if (bool) $('#loading').show();
else $('#loading').hide();
}
});
});
</script>
</head>
<body>
<div id='loading' style='display:none'>loading...</div>
<div id='calendar'></div>
<p>json_events.php needs to be running in the same directory.</p>
</body>
</html>

View File

@ -1,25 +0,0 @@
<?php
$year = date('Y');
$month = date('m');
echo json_encode(array(
array(
'id' => 1,
'title' => "Event1",
'start' => "$year-$month-10",
'url' => "http://yahoo.com/"
),
array(
'id' => 2,
'title' => "Event2",
'start' => "$year-$month-20",
'end' => "$year-$month-22",
'url' => "http://yahoo.com/"
)
));
?>

892
src/agenda.js Executable file
View File

@ -0,0 +1,892 @@
function segAfters(levels) { // TODO: put in agenda.js
var i, j, k, level, seg, seg2;
for (i=levels.length-1; i>0; i--) {
level = levels[i];
for (j=0; j<level.length; j++) {
seg = level[j];
for (k=0; k<segLevels[i-1].length; k++) {
seg2 = segLevels[i-1][k];
if (segsCollide(seg, seg2)) {
seg2.after = Math.max(seg2.after, seg.after+1);
}
}
}
}
}
/********************************* week view ***********************************/
$.fullCalendar.views.week = function(element, options) {
var agenda = new Agenda(element, options);
safeExtend(options, {
weekTitleFormat: 'M j Y{ - M j Y}' // TODO: shift around
});
agenda.render = function(date, delta, fetchEvents) {
if (delta) {
addDays(date, delta * 7);
}
this.start = addDays(cloneDate(date), -date.getDay());
this.end = addDays(cloneDate(this.start), 7);
this.title = formatDates(this.start, this.end, options.weekTitleFormat);
this.renderAgenda(fetchEvents);
};
return agenda;
};
/******************************* day view *************************************/
$.fullCalendar.views.day = function(element, options) {
var agenda = new Agenda(element, options);
safeExtend(options, {
dayTitleFormat: 'l F j Y' // TODO: shift around
});
agenda.render = function(date, delta, fetchEvents) {
if (delta) {
addDays(date, delta);
}
this.start = cloneDate(date, true);
this.end = addDays(cloneDate(date), 1);
this.title = formatDate(date, options.dayTitleFormat);
this.renderAgenda(fetchEvents);
};
return agenda;
};
/*********************** shared by month and day views *************************/
function Agenda(element, options) {
safeExtend(options, {
slotMinutes: 30,
defaultEventMinutes: 120,
agendaEventTimeFormat: 'g:i{ - g:i}',
agendaSideTimeFormat: 'ga',
agendaEventDragOpacity: .5
});
var view = this,
head, body, panel, bg,
dayCnt,
dayWidth, slotHeight,
timeWidth,
cachedEvents,
cachedSlotSegs, cachedDaySegs,
eventElements = [],
eventElementsByID = {},
eventsByID = {};
element.addClass('fc-agenda').css('position', 'relative');
/******************************** cell rendering ********************************/
this.renderAgenda = function(fetchEvents) { // TODO: get z-indexes sorted out
var start = view.start,
end = view.end,
today = getToday(),
todayI = -1,
tm = options.theme ? 'ui' : 'fc',
slotNormal = options.slotMinutes % 15 == 0,
dayAbbrevs = $.fullCalendar.dayAbbrevs;
if (!head) { // first time rendering, build from scratch TODO: need all the nbsp's?
// head
var i, d, dDay, dMinutes,
s = "<div class='fc-agenda-head' style='position:relative;z-index:3'>" +
"<table style='width:100%' cellpadding='0' cellspacing='0'>" +
"<tr class='fc-first'>" +
"<th class='fc-first " + tm + "-state-default'>&nbsp;</th>";
dayCnt = 0;
for (d=cloneDate(start); d<end; addDays(d, 1)) {
s += "<th class='fc-" +
dayIDs[d.getDay()] + ' ' + // needs to be first
tm + '-state-default' +
"'>" + dayAbbrevs[d.getDay()] + "</th>";
if (+d == +today) {
todayI = dayCnt;
}
dayCnt++;
}
s += "<th class='fc-last " + tm + "-state-default'>&nbsp;</th></tr>" +
"<tr class='fc-last'>" +
"<th class='fc-first " + tm + "-state-default' style='font-weight:normal;text-align:right;padding:4px 2px'>all day</th>" +
"<td colspan='" + dayCnt + "' class='" + tm + "-state-default'>" +
"<div class='fc-day-content'><div/></div></td>" +
"<th class='fc-last " + tm + "-state-default'>&nbsp;</th>" +
"</tr></table></div>";
head = $(s).appendTo(element);
// body & event panel
s = "<div style='position:relative;overflow:hidden'>" +
"<table cellpadding='0' cellspacing='0'>";
d = getToday();
dDay = d.getDay();
for (i=0; d.getDay()==dDay; i++, addMinutes(d, options.slotMinutes)) {
dMinutes = d.getMinutes();
s += "<tr class='" +
(i==0 ? 'fc-first' : (dMinutes==0 ? '' : 'fc-minor')) +
"'><th class='" + tm + "-state-default'>" +
(!slotNormal || dMinutes==0 ? formatDate(d, options.agendaSideTimeFormat) : '&nbsp;') +
"</th><td class='fc-slot " + tm + "-state-default'>&nbsp;</td></tr>";
}
s += "</table></div>";
body = $("<div class='fc-agenda-body' style='position:relative;z-index:2'/>")
.append(panel = $(s))
.appendTo(element);
// background stripes
s = "<div class='fc-agenda-bg' style='position:absolute;top:0;z-index:1'>" +
"<table style='width:100%;height:100%' cellpadding='0' cellspacing='0'><tr>";
for (i=0; i<dayCnt; i++) {
s += "<td class='fc-" +
dayIDs[i] + ' ' + // needs to be first
tm + '-state-default ' +
(i==todayI ? tm + '-state-highlight fc-today' : 'fc-not-today') +
"'><div class='fc-day-content'><div>&nbsp;</div></div></td>";
}
s += "</tr></table></div>";
bg = $(s).appendTo(element);
}else{ // skeleton already built, just modify it
clearEvents();
// change classes of background stripes
todayI = Math.round((today - start) / msInDay);
bg.find('td').each(function(i) {
if (i == todayI) {
$(this).removeClass('fc-not-today')
.addClass('fc-today')
.addClass(tm + '-state-highlight');
}else{
$(this).addClass('fc-not-today')
.removeClass('fc-today')
.removeClass(tm + '-state-highlight');
}
});
// if 1-day view, change day-of-week class and header text
if (dayCnt == 1) {
var th = head.find('th:eq(1)').html(dayAbbrevs[start.getDay()])[0],
td = bg.find('td')[0];
th.className = th.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[start.getDay()]);
td.className = td.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[start.getDay()]);
}
}
updateSize();
fetchEvents(renderEvents);
};
function updateSize() {
// align first 'time' column
timeWidth = body.find('th:first').outerWidth();
head.find('th:first').width(timeWidth);
// set table width (100% in css wasn't working in IE)
var panelWidth = body[0].clientWidth || body.width(); // first time, there are no scrollbars!? for IE6?
body.find('table').width(panelWidth);
// align spacer column to scrollbar width
setOuterWidth(head.find('th:last'), body.width() - panelWidth);
// position background stripe container
bg.css({
left: timeWidth,
width: panelWidth - timeWidth,
height: element.height()
});
// align other columns
dayWidth = Math.floor((panelWidth - timeWidth) / dayCnt);
var topCells = head.find('tr:first th:gt(0)'),
bgCells = bg.find('td');
for (var i=0, len=bgCells.length-1; i<len; i++) { // TODO: use slice
setOuterWidth(topCells.eq(i), dayWidth);
setOuterWidth(bgCells.eq(i), dayWidth);
}
slotHeight = body.find('tr:eq(1)').height(); // use second, first prob doesn't have a border
// body height
body.height(Math.round(body.width() / contentAspectRatio) - head.height());
// but this will add scrollbars...
// TODO: bug, iE6 view heights dont match up
// also, no scrollbars
}
/********************************** event rendering *********************************/
function renderEvents(events) {
var i, len=events.length, event,
fakeID=0, nextDay,
slotEvents=[], dayEvents=[];
for (i=0; i<len; i++) {
event = events[i];
event._id = typeof event.id == 'undefined' ? '_fc' + fakeID++ : event.id + '';
if (eventsByID[event._id]) {
eventsByID[event._id].push(event);
}else{
eventsByID[event._id] = [event];
}
if (event.hasTime) {
event._end = event.end || addMinutes(cloneDate(event.start), options.defaultEventMinutes);
}else{
event._end = addDays(cloneDate(event.end || event.start), 1);
}
if (event.start < view.end && event._end > view.start) {
if (event.hasTime) {
event._end = event.end || addMinutes(cloneDate(event.start), options.defaultEventMinutes);
slotEvents.push(event);
}else{
event._end = addDays(cloneDate(event.end || event.start), 1);
dayEvents.push(event);
}
}
}
cachedEvents = events;
cachedSlotSegs = compileSlotSegs(slotEvents, view.start, view.end);
cachedDaySegs = levelizeSegs(sliceSegs(dayEvents, view.start, view.end));
renderSlotSegs(cachedSlotSegs);
renderDaySegs(cachedDaySegs);
}
function rerenderEvents(skipCompile) {
clearEvents();
if (skipCompile) {
renderSlotSegs(cachedSlotSegs);
renderDaySegs(cachedDaySegs);
}else{
renderEvents(cachedEvents);
}
}
function clearEvents() {
for (var i=0; i<eventElements.length; i++) {
eventElements[i].remove();
}
eventElements = [];
eventElementsByID = {};
eventsByID = {};
}
// renders events in the 'time slots' at the bottom
function renderSlotSegs(segCols) {
var colI, colLen=segCols.length, col,
levelI, level,
segI, seg,
event, start, end,
top, bottom,
tdInner, left, width,
eventElement, anchorElement, timeElement, titleElement;
for (colI=0; colI<colLen; colI++) {
col = segCols[colI];
for (levelI=0; levelI<col.length; levelI++) {
level = col[levelI];
for (segI=0; segI<level.length; segI++) {
seg = level[segI];
event = seg.event;
top = timeCoord(seg.start, seg.start);
bottom = timeCoord(seg.start, seg.end);
tdInner = bg.find('td:eq('+colI+') div div');
availWidth = tdInner.width();
left = timeWidth + tdInner.position().left + // leftmost possible
(availWidth / (levelI + seg.right + 1) * levelI); // indentation
if (levelI == 0) {
if (seg.right == 0) {
// can be entire width, aligned left
width = availWidth * .96;
}else{
// moderately wide, aligned left still
width = ((availWidth / (seg.right + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
}
}else{
// indented and thinner
width = availWidth / (levelI + seg.right + 1);
}
eventElement = $("<div class='fc-event fc-event-vert' />")
.append(anchorElement = $("<a><span class='fc-event-bg'/></a>")
.append(titleElement = $("<span class='fc-event-title'/>")
.text(event.title)))
.css({
position: 'absolute',
zIndex: 1000,
top: top,
left: left
});
if (event.url) {
anchorElement.attr('href', event.url);
}
if (seg.isStart) {
eventElement.addClass('fc-corner-top');
// add the time header
anchorElement
.prepend(timeElement = $("<span class='fc-event-time'/>")
.text(formatDates(event.start, event.end, options.agendaEventTimeFormat)))
}else{
timeElement = null;
}
if (seg.isEnd) {
eventElement.addClass('fc-corner-bottom');
resizableSlotEvent(event, eventElement, timeElement);
}
eventElement.appendTo(panel);
setOuterWidth(eventElement, width, true);
setOuterHeight(eventElement, bottom-top, true);
if (timeElement && eventElement.height() - titleElement.position().top < 10) {
// event title doesn't have enough room, but next to the time
timeElement.text(formatDate(event.start, options.agendaEventTimeFormat) + ' - ' + event.title);
titleElement.remove();
}
draggableSlotEvent(event, eventElement, timeElement);
reportEventElement(event, eventElement);
}
}
}
}
// renders 'all-day' events at the top
function renderDaySegs(segRow) {
var td = head.find('td');
var tdInner = td.find('div div');
var top = tdInner.position().top,
rowHeight = 0,
i, len=segRow.length, level,
levelHeight,
j, seg,
event, left, right,
eventElement, anchorElement;
for (i=0; i<len; i++) {
level = segRow[i];
levelHeight = 0;
for (j=0; j<level.length; j++) {
seg = level[j];
event = seg.event;
left = seg.isStart ?
bg.find('td:eq('+((seg.start.getDay()+dayCnt)%dayCnt)+') div div') :
bg.find('td:eq('+((seg.start.getDay()+dayCnt)%dayCnt)+')');
left = left.position().left;
right = seg.isEnd ?
bg.find('td:eq('+((seg.end.getDay()-1+dayCnt)%dayCnt)+') div div') :
bg.find('td:eq('+((seg.end.getDay()-1+dayCnt)%dayCnt)+')');
right = right.position().left + right.outerWidth();
eventElement = $("<div class='fc-event fc-event-hori' />")
.append(anchorElement = $("<a/>")
.append($("<span class='fc-event-title' />")
.text(event.title)))
.css({
position: 'absolute',
top: top,
left: timeWidth + left
});
if (seg.isStart) {
eventElement.addClass('fc-corner-left');
}
if (seg.isEnd) {
eventElement.addClass('fc-corner-right');
}
if (event.url) {
anchorElement.attr('href', event.url);
}
eventElement.appendTo(head);
setOuterWidth(eventElement, right-left, true);
draggableDayEvent(event, eventElement);
//resizableDayEvent(event, eventElement);
reportEventElement(event, eventElement);
levelHeight = Math.max(levelHeight, eventElement.outerHeight(true));
}
top += levelHeight;
rowHeight += levelHeight;
}
tdInner.height(rowHeight);
//bg.height(element.height()); // tdInner might have pushed the body down, so resize
//updateSize();
}
/******************************************* draggable *****************************************/
// when event starts out IN TIMESLOTS
function draggableSlotEvent(event, eventElement, timeElement) {
var origPosition, origMarginTop,
prevSlotDelta, slotDelta,
matrix;
eventElement.draggable({
zIndex: 1001,
scroll: false,
grid: [dayWidth, slotHeight],
axis: dayCnt==1 ? 'y' : false,
cancel: '.ui-resizable-handle',
opacity: .5,
start: function(ev, ui) {
if ($.browser.msie) {
eventElement.find('span.fc-event-bg').hide();
}
origPosition = eventElement.position();
origMarginTop = parseInt(eventElement.css('margin-top')) || 0;
prevSlotDelta = 0;
matrix = new HoverMatrix(function(cell) {
if (event.hasTime) {
// event is an original slot-event
if (cell && cell.row == 0) {
// but needs to convert to temporary full-day-event
var topDiff = panel.offset().top - head.offset().top;
eventElement.css('margin-top', origMarginTop + topDiff)
.appendTo(head);
// TODO: bug in IE8 w/ above technique, draggable ends immediately
event.hasTime = false;
if (timeElement) {
timeElement.hide();
}
eventElement.draggable('option', 'grid', null);
}
}else{
// event is a temporary full-day-event
if (cell && cell.row == 1) {
// but needs to convert to original slot-event
eventElement.css('margin-top', origMarginTop)
.appendTo(panel);
event.hasTime = true;
if (timeElement) {
timeElement.css('display', ''); // show() was causing display=inline
}
eventElement.draggable('option', 'grid', [dayWidth, slotHeight]);
}
}
if (cell && cell.row == 0) {
showDayOverlay(cell);
}else{
hideDayOverlay();
}
});
matrix.row(head.find('td'));
bg.find('td').each(function() {
matrix.col(this);
});
matrix.row(body);
matrix.start();
hideSimilarEvents(event, eventElement);
},
drag: function(ev, ui) {
slotDelta = Math.round((ui.position.top - origPosition.top) / slotHeight);
if (slotDelta != prevSlotDelta) {
if (timeElement && event.hasTime) {
// update time header
var newStart = addMinutes(cloneDate(event.start), slotDelta * options.slotMinutes),
newEnd;
if (event.end) {
newEnd = addMinutes(cloneDate(event.end), slotDelta * options.slotMinutes);
}
timeElement.text(formatDates(newStart, newEnd, options.agendaEventTimeFormat));
}
prevSlotDelta = slotDelta;
}
matrix.mouse(ev.pageX, ev.pageY);
},
stop: function(ev, ui) {
if (event.hasTime) {
if (matrix.cell) {
// over slots
var dayDelta = Math.round((ui.position.left - origPosition.left) / dayWidth);
reportEventMove(event, dayDelta, true, slotDelta * options.slotMinutes);
}
}else{
// over full-days
if (!matrix.cell) {
// was being dragged over full-days, but finished over nothing, reset
event.hasTime = true;
}else{
event.end = null;
reportEventMove(event, matrix.cell.colDelta);
}
}
hideDayOverlay();
rerenderEvents();
}
});
}
// when event starts out FULL-DAY
function draggableDayEvent(event, eventElement) {
var origWidth, matrix;
eventElement.draggable({
zIndex: 1001,
start: function() {
origWidth = eventElement.width();
matrix = new HoverMatrix(function(cell) {
if (!cell) {
// mouse is outside of everything
hideDayOverlay();
}else{
if (cell.row == 0) {
// on full-days
if (event.hasTime) {
// and needs to be original full-day event
eventElement
.width(origWidth)
.height('')
.draggable('option', 'grid', null);
event.hasTime = false;
}
showDayOverlay(cell);
}else{
// mouse is over bottom slots
if (!event.hasTime) {
// convert event to temporary slot-event
//if (+cloneDate(event.start, true) == +cloneDate(event._end, true)) {
// only change styles if a 1-day event
eventElement
.width(dayWidth - 10) // don't use entire width
.height(slotHeight * Math.round(options.defaultEventMinutes/options.slotMinutes) - 2);
//}
eventElement.draggable('option', 'grid', [dayWidth, 1]);
event.hasTime = true;
}
hideDayOverlay();
}
}
});
matrix.row(head.find('td'));
bg.find('td').each(function() {
matrix.col(this);
});
matrix.row(body);
matrix.start();
hideSimilarEvents(event, eventElement);
},
drag: function(ev, ui) {
matrix.mouse(ev.pageX, ev.pageY);
},
stop: function() {
var cell = matrix.cell;
if (!cell) {
// over nothing
if (event.hasTime) {
// event was on the slots before going out, convert back
event.hasTime = false;
}
}else{
if (!event.hasTime) {
// event has been dropped on a full-day
reportEventMove(event, cell.colDelta);
}else{
// event has been dropped on the slots
var slots = Math.floor((eventElement.offset().top - panel.offset().top) / slotHeight);
event.end = null;
reportEventMove(event, cell.colDelta, false, slots * options.slotMinutes);
}
}
hideDayOverlay();
rerenderEvents();
}
});
}
// hover effect when dragging events over top days
var dayOverlay;
function showDayOverlay(props) {
if (!dayOverlay) {
dayOverlay = $("<div class='fc-day-overlay' style='position:absolute;display:none'/>")
.appendTo(element);
}
var o = element.offset();
dayOverlay
.css({
top: props.top - o.top,
left: props.left - o.left,
width: props.width,
height: props.height
})
.show();
}
function hideDayOverlay() {
if (dayOverlay) {
dayOverlay.hide();
}
}
/************************************* resizable **************************************/
function resizableSlotEvent(event, eventElement, timeElement) {
var prevSlotDelta, slotDelta, newEnd;
eventElement
.resizable({
handles: 's',
grid: [0, slotHeight],
start: function() {
prevSlotDelta = 0;
hideSimilarEvents(event, eventElement);
if ($.browser.msie && $.browser.version == '6.0') {
eventElement.css('overflow', 'hidden');
}
},
resize: function(ev, ui) {
slotDelta = Math.round((Math.max(slotHeight, ui.size.height) - ui.originalSize.height) / slotHeight);
if (slotDelta != prevSlotDelta) {
newEnd = addMinutes(cloneDate(event._end), options.slotMinutes * slotDelta);
if (timeElement) {
timeElement.text(formatDates(event.start, newEnd, options.agendaEventTimeFormat));
}
prevSlotDelta = slotDelta;
}
},
stop: function(ev, ui) {
reportEventResize(event, 0, true, options.slotMinutes * slotDelta);
rerenderEvents();
}
})
.find('div.ui-resizable-s').text('=');
}
function resizableDayEvent(event, eventElement) {
eventElement.resizable({
handles: 'e',
grid: [dayWidth, 0],
start: function() {
hideSimilarEvents(event, eventElement);
},
stop: function(ev, ui) {
var dayDelta = Math.round((Math.max(dayWidth, ui.size.width) - ui.originalSize.width) / dayWidth);
reportEventResize(event, dayDelta);
rerenderEvents();
}
});
}
/**************************************** misc **************************************/
function reportEventElement(event, eventElement) {
eventElements.push(eventElement);
if (eventElementsByID[event._id]) {
eventElementsByID[event._id].push(eventElement);
}else{
eventElementsByID[event._id] = [eventElement];
}
}
function hideSimilarEvents(event, eventElement) {
var elements = eventElementsByID[event._id];
for (var i=0; i<elements.length; i++) {
if (elements[i] != eventElement) {
elements[i].hide();
}
}
}
function reportEventMove(event, days, keepTime, minutes) {
minutes = minutes || 0;
var events = eventsByID[event._id];
for (var i=0, event2; i<events.length; i++) {
event2 = events[i];
event2.hasTime = event.hasTime;
addMinutes(addDays(event2.start, days, keepTime), minutes);
if (event.end) {
event2.end = addMinutes(addDays(event2.end || event2._end, days, keepTime), minutes);
}else{
event2.end = event2._end = null;
// hopefully renderEvents() will always be called after this
// to reset _end.... TODO?
}
}
}
function reportEventResize(event, days, keepTime, minutes) {
minutes = minutes || 0;
var events = eventsByID[event._id];
for (var i=0, event2; i<events.length; i++) {
event2 = events[i];
event2.end = addMinutes(addDays(event2.end || event2._end, days, keepTime), minutes);
}
}
// get the Y coordinate of the given time on the given day
function timeCoord(day, time) {
var nextDay = addDays(cloneDate(day), 1);
if (time < nextDay) {
var slotMinutes = options.slotMinutes;
var minutes = time.getHours()*60 + time.getMinutes();
var slotI = Math.floor(minutes / slotMinutes);
var td = body.find('tr:eq(' + slotI + ') td');
return Math.round(td.position().top + slotHeight * ((minutes % slotMinutes) / slotMinutes));
}else{
return panel.height();
}
}
}
function compileSlotSegs(events, start, end) {
// slice by day
var segCols = [],
d1 = cloneDate(start),
d2 = addDays(cloneDate(start), 1);
for (; d1<end; addDays(d1, 1), addDays(d2, 1)) {
segCols.push(sliceSegs(events, d1, d2));
}
var segLevelCols = [],
segLevels,
segs,
segI, seg,
levelI, level,
collide,
segI2, seg2;
for (var i=0; i<segCols.length; i++) {
// divide segments into levels
segLevels = segLevelCols[i] = [];
segs = segCols[i];
for (segI=0; segI<segs.length; segI++) {
seg = segs[segI];
for (levelI=0; true; levelI++) {
level = segLevels[levelI];
if (!level) {
segLevels[levelI] = [seg];
break;
}else{
collide = false;
for (segI2=0; segI2<level.length; segI2++) {
if (segsCollide(level[segI2], seg)) {
collide = true;
break;
}
}
if (!collide) {
level.push(seg);
break;
}
}
}
seg.right = 0;
}
// determine # of segments to the 'right' of each segment
for (levelI=segLevels.length-1; levelI>0; levelI--) {
level = segLevels[levelI];
for (segI=0; segI<level.length; segI++) {
seg = level[segI];
for (segI2=0; segI2<segLevels[levelI-1].length; segI2++) {
seg2 = segLevels[levelI-1][segI2];
if (segsCollide(seg, seg2)) {
seg2.right = Math.max(seg2.right, seg.right+1);
}
}
}
}
}
return segLevelCols;
}
// TODO: move to month.js
function sliceSegs(events, start, end) {
var segs = [],
i, len=events.length, event,
eventStart, eventEnd,
segStart, segEnd,
isStart, isEnd;
for (i=0; i<len; i++) {
event = events[i];
eventStart = event.start;
eventEnd = event._end;
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);
}
function segCmp(a, b) {
return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
}

177
src/css/agenda.css Executable file
View File

@ -0,0 +1,177 @@
.fc-event,
.fc-event a,
.fc-agenda .fc-event-time {
color: #fff;
border-style: solid;
border-color: blue;
background-color: blue;
}
/* header styles */
.fc .fc-agenda-head th.fc-first {
border-left: 0;
}
.fc .fc-agenda-head th,
.fc .fc-agenda-head td {
border-width: 1px 0 0 1px;
}
.fc-agenda-head tr.fc-first th {
border-width: 0 0 0 1px;
}
.fc-agenda-head tr.fc-last th,
.fc-agenda-head tr.fc-last td {
border-bottom-width: 2px;
}
.fc-agenda-head tr.fc-last th {
/*border-width: 1px 0 1px 1px;*/
background-image: none;
}
.fc-agenda-head tr.fc-last th.fc-first {
/*border-width: 0 2px 1px 0;*/
}
.fc-agenda-head tr.fc-last th.fc-last {
/*border-width: 0 0 0 3px;*/
}
.fc .fc-agenda-head td {
/*border-width: 3px 0 3px 1px;*/
background: none;
}
.fc-agenda-body {
/*width: 100%;*/
overflow: auto;
}
.fc .fc-agenda-body th {
border-width: 1px 0 0 0;
background-image: none;
text-align: right;
font-weight: normal;
vertical-align: middle;
width: 48px;
height: 22px;
padding-right: 2px;
}
.fc .fc-agenda-body td {
border-width: 1px 0 0 1px;
background: none;
}
.fc .fc-agenda-body tr.fc-minor th,
.fc .fc-agenda-body tr.fc-minor td {
border-top-style: dotted;
}
.fc .fc-agenda-body tr.fc-first th,
.fc .fc-agenda-body tr.fc-first td {
border-top: 0;
}
.fc .fc-agenda-bg td {
border-style: double;
border-width: 0 0 0 3px;
}
.fc .fc-agenda-bg td.fc-not-today {
background: none;
}
.fc-agenda .fc-day-content {
padding: 2px 1px 14px;
}
/* vertical events */
.fc-event-vert {
border-width: 0 1px;
}
.fc-event-vert a {
border-width: 0;
}
.fc-content .fc-corner-top {
margin-top: 1px;
}
.fc-content .fc-corner-top a {
margin-top: -1px;
border-top-width: 1px;
}
.fc-content .fc-corner-bottom {
margin-bottom: 1px;
}
.fc-content .fc-corner-bottom a {
margin-bottom: -1px;
border-bottom-width: 1px;
}
.fc-event-vert span {
display: block;
position: relative;
z-index: 2;
}
.fc-event-vert span.fc-event-time {
white-space: nowrap;
_white-space: normal;
overflow: hidden;
font-size: 10px;
}
.fc-event-vert span.fc-event-title {
line-height: 13px;
}
.fc-event-vert span.fc-event-bg {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
opacity: .3;
filter: alpha(opacity=30);
}
.fc-event-vert .ui-resizable-s {
font-family: monospace;
height: 8px;
font-size: 11px;
line-height: 8px;
bottom: 0;
text-align: center;
}

60
src/css/grid.css Executable file
View File

@ -0,0 +1,60 @@
/* Month View, Basic Week View, Basic Day View
------------------------------------------------------------------------*/
.fc-grid table {
width: 100%;
}
.fc .fc-grid th {
border-width: 0 0 0 1px;
text-align: center;
}
.fc .fc-grid td {
border-width: 1px 0 0 1px;
}
.fc-grid th.fc-leftmost,
.fc-grid td.fc-leftmost {
border-left: 0;
}
.fc-grid .fc-day-number {
float: right;
padding: 0 2px;
}
.fc-grid .fc-other-month .fc-day-number {
opacity: 0.3;
filter: alpha(opacity=30); /* for IE */
/* opacity with small font can sometimes look too faded
might want to set the 'color' property instead
making day-numbers bold also fixes the problem */
}
.fc-grid .fc-day-content {
clear: both;
padding: 2px 2px 0; /* distance between events and day edges */
}
/* event styles */
.fc-grid .fc-event-time {
font-weight: bold;
}
/* right-to-left */
.fc-rtl .fc-grid {
direction: rtl;
}
.fc-rtl .fc-grid .fc-day-number {
float: left;
}
.fc-rtl .fc-grid .fc-event-time {
float: right;
}

339
src/css/main.css Executable file
View File

@ -0,0 +1,339 @@
/*
* FullCalendar Stylesheet
*
* Feel free to edit this file to customize the look of FullCalendar.
* When upgrading to newer versions, please upgrade this file as well,
* porting over any customizations afterwards.
*
*/
.fc,
.fc .fc-header,
.fc .fc-content {
font-size: 1em;
}
.fc table {
border-collapse: collapse;
border-spacing: 0;
}
.fc td, .fc th {
padding: 0;
vertical-align: top;
}
/* Header
------------------------------------------------------------------------*/
table.fc-header {
width: 100%;
}
.fc-header-left {
width: 25%;
}
.fc-header-left table {
float: left;
}
.fc-header-center {
width: 50%;
}
.fc-header-center table {
margin: 0 auto;
}
.fc-header-right {
width: 25%;
}
.fc-header-right table {
float: right;
}
.fc-header-title {
margin-top: 0;
white-space: nowrap;
}
.fc-header-space {
padding-left: 10px;
}
/* right-to-left */
.fc-rtl .fc-header-title {
direction: rtl;
}
/* Buttons
------------------------------------------------------------------------*/
.fc-header .fc-state-default,
.fc-header .ui-state-default {
margin-bottom: 1em;
cursor: pointer;
}
.fc-header .fc-state-default {
border-width: 1px 0;
padding: 0 1px;
}
.fc-header .fc-state-default,
.fc-header .fc-state-default a {
border-style: solid;
}
.fc-header .fc-state-default a {
display: block;
position: relative;
border-width: 0 1px;
margin: 0 -1px;
width: 100%;
text-decoration: none;
}
.fc-header .fc-state-default span {
display: block;
border-style: solid;
border-width: 1px 0 1px 1px;
padding: 3px 5px;
}
.fc-header .ui-state-default {
padding: 4px 6px;
}
/* for adjacent buttons */
.fc-header .fc-no-right {
padding-right: 0;
border-right: 0;
}
.fc-header .ui-no-right {
border-right: 0;
}
/* for fake rounded corners */
.fc-header .fc-corner-left {
margin-left: 1px;
padding-left: 0;
}
.fc-header .fc-corner-right {
margin-right: 1px;
padding-right: 0;
}
/* DEFAULT button COLORS */
.fc-header .fc-state-default,
.fc-header .fc-state-default a {
border-color: #777; /* outer border */
color: #333;
}
.fc-header .fc-state-default span {
border-color: #fff #fff #cecece; /* inner border */
background: #e8e8e8;
}
/* PRESSED button COLORS (down and active) */
.fc-header .fc-state-active a {
color: #fff;
}
.fc-header .fc-state-down span,
.fc-header .fc-state-active span {
background: #888;
border-color: #808080 #808080 #909090; /* inner border */
}
/* DISABLED button COLORS */
.fc-header .fc-state-disabled a {
color: #999;
}
.fc-header .fc-state-disabled,
.fc-header .fc-state-disabled a {
border-color: #ccc; /* outer border */
}
.fc-header .fc-state-disabled span {
border-color: #fff #fff #f0f0f0; /* inner border */
background: #f0f0f0;
}
/* Content Area & Global Cell Styles
------------------------------------------------------------------------*/
.fc-widget-content {
border: 1px solid #ccc; /* outer border color */
}
.fc-content {
clear: both;
}
.fc-content .fc-state-default {
border-style: solid;
border-color: #ccc; /* inner border color */
}
.fc-content .fc-state-highlight { /* today */
background: #ffc;
}
.fc-content .fc-not-today {
background: none;
}
.fc-cell-overlay { /* semi-transparent rectangle while dragging */
background: #9cf;
opacity: .2;
filter: alpha(opacity=20); /* for IE */
}
.fc-view { /* prevents dragging outside of widget */
width: 100%;
overflow: hidden;
}
/* Global Event Styles
------------------------------------------------------------------------*/
.fc-event,
.fc-event a {
border-style: solid;
border-color: #36c; /* default BORDER color (probably the same as background-color) */
background-color: #36c; /* default BACKGROUND color */
color: #fff; /* default TEXT color */
}
/* Use the 'className' CalEvent property and the following
* example CSS to change event color on a per-event basis:
*
* .my-event-class,
* .my-event-class a {
* border-color: black;
* background-color: black;
* color: red;
* }
*/
.fc-event a {
overflow: hidden;
font-size: .85em;
text-decoration: none;
text-align: left;
cursor: pointer;
}
.fc-event-editable {
cursor: pointer;
}
.fc-event-time,
.fc-event-title {
padding: 0 1px;
}
/* for fake rounded corners */
.fc-event a {
display: block;
position: relative;
width: 100%;
height: 100%;
}
/* right-to-left */
.fc-rtl .fc-event a {
text-align: right;
}
/* resizable */
.fc .ui-resizable-handle {
display: block;
position: absolute;
z-index: 99999;
border: 0; /* important overrides pre jquery ui 1.7 styles */
background: url(data:image/gif;base64,AAAA) !important; /* hover fix for IE */
}
/* Horizontal Events
------------------------------------------------------------------------*/
.fc-event-hori {
border-width: 1px 0;
margin-bottom: 1px;
}
.fc-event-hori a {
border-width: 0;
}
/* for fake rounded corners */
.fc-content .fc-corner-left {
margin-left: 1px;
}
.fc-content .fc-corner-left a {
margin-left: -1px;
border-left-width: 1px;
}
.fc-content .fc-corner-right {
margin-right: 1px;
}
.fc-content .fc-corner-right a {
margin-right: -1px;
border-right-width: 1px;
}
/* resizable */
.fc-event-hori .ui-resizable-e {
top: 0 !important; /* importants override pre jquery ui 1.7 styles */
right: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: e-resize;
}
.fc-event-hori .ui-resizable-w {
top: 0 !important;
left: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: w-resize;
}
.fc-event-hori .ui-resizable-handle {
_padding-bottom: 14px; /* IE6 had 0 height */
}

64
src/gcal.js Executable file
View File

@ -0,0 +1,64 @@
/*
* FullCalendar Google Calendar Extension
*
* Copyright (c) 2009 Adam Shaw
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function($) {
$.fullCalendar.gcalFeed = function(feedUrl, options) {
feedUrl = feedUrl.replace(/\/basic$/, '/full');
options = options || {};
return function(start, end, callback) {
$.getJSON(feedUrl + "?alt=json-in-script&callback=?",
{
'start-min': $.fullCalendar.formatDate(start, 'u'),
'start-max': $.fullCalendar.formatDate(end, 'u'),
'singleevents': true,
'max-results': 9999
},
function(data) {
var events = [];
if (data.feed.entry) {
$.each(data.feed.entry, function(i, entry) {
var startStr = entry['gd$when'][0]['startTime'],
start = $.fullCalendar.parseDate(startStr),
end = $.fullCalendar.parseDate(entry['gd$when'][0]['endTime']),
allDay = startStr.indexOf('T') == -1,
classNames = [],
url;
$.each(entry.link, function() {
if (this.type == 'text/html') {
url = this.href;
}
});
if (allDay) {
end = new Date(end - 1); // make inclusive
}
events.push({
id: entry['gCal$uid']['value'],
title: entry['title']['$t'],
url: url,
start: $.fullCalendar.parseDate(entry['gd$when'][0]['startTime']),
end: end,
allDay: allDay,
location: entry['gd$where'][0]['valueString'],
description: entry['content']['$t'],
className: options.className,
editable: options.editable || false
});
});
}
callback(events);
});
}
}
})(jQuery);

580
src/grid.js Executable file
View File

@ -0,0 +1,580 @@
/* Grid-based Views: month, basicWeek, basicDay
-----------------------------------------------------------------------------*/
setDefaults({
weekMode: 'fixed'
});
views.month = function(element, options) {
return new Grid(element, options, {
render: function(date, delta, fetchEvents) {
if (delta) {
addMonths(date, delta);
date.setDate(1);
}
var start = this.start = cloneDate(date, true);
start.setDate(1);
this.title = formatDates(
start,
addDays(cloneDate(this.end = addMonths(cloneDate(start), 1)), -1),
strProp(options.titleFormat, 'month'),
options
);
addDays(this.visStart = cloneDate(start), -((start.getDay() - options.firstDay + 7) % 7));
addDays(this.visEnd = cloneDate(this.end), (7 - this.visEnd.getDay() + options.firstDay) % 7);
var rowCnt = Math.round((this.visEnd - this.visStart) / (DAY_MS * 7));
if (options.weekMode == 'fixed') {
addDays(this.visEnd, (6 - rowCnt) * 7);
rowCnt = 6;
}
this.renderGrid(rowCnt, 7, strProp(options.columnFormat, 'month'), true, fetchEvents);
}
});
}
views.basicWeek = function(element, options) {
return new Grid(element, options, {
render: function(date, delta, fetchEvents) {
if (delta) {
addDays(date, delta * 7);
}
this.title = formatDates(
this.start = this.visStart = addDays(cloneDate(date), -((date.getDay() - options.firstDay + 7) % 7)),
addDays(cloneDate(this.end = this.visEnd = addDays(cloneDate(this.start), 7)), -1),
strProp(options.titleFormat, 'week'),
options
);
this.renderGrid(1, 7, strProp(options.columnFormat, 'week'), false, fetchEvents);
}
});
};
views.basicDay = function(element, options) {
return new Grid(element, options, {
render: function(date, delta, fetchEvents) {
if (delta) {
addDays(date, delta);
}
this.title = formatDate(date, strProp(options.titleFormat, 'day'), options);
this.start = this.visStart = cloneDate(date, true);
this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderGrid(1, 1, strProp(options.columnFormat, 'day'), false, fetchEvents);
}
});
}
// rendering bugs
var tdTopBug, trTopBug, tbodyTopBug,
tdHeightBug,
rtlLeftDiff;
function Grid(element, options, methods) {
var tm, firstDay,
rtl, dis, dit, // day index sign / translate
rowCnt, colCnt,
colWidth,
thead, tbody,
cachedSegs, //...
// initialize superclass
view = $.extend(this, viewMethods, methods, {
renderGrid: renderGrid,
renderEvents: renderEvents,
rerenderEvents: rerenderEvents,
updateSize: updateSize,
defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing
return cloneDate(event.start);
},
visEventEnd: function(event) { // returns exclusive 'visible' end, for rendering
if (event.end) {
var end = cloneDate(event.end);
return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
}else{
return addDays(cloneDate(event.start), 1);
}
}
});
view.init(element, options);
/* Grid Rendering
-----------------------------------------------------------------------------*/
element.addClass('fc-grid').css('position', 'relative');
if (element.disableSelection) {
element.disableSelection();
}
function renderGrid(r, c, colFormat, showNumbers, fetchEvents) {
rowCnt = r;
colCnt = c;
var month = view.start.getMonth(),
today = clearTime(new Date()),
s, i, j, d = cloneDate(view.visStart);
// update option-derived variables
tm = options.theme ? 'ui' : 'fc';
firstDay = options.firstDay;
if (rtl = options.isRTL) {
dis = -1;
dit = colCnt - 1;
}else{
dis = 1;
dit = 0;
}
if (!tbody) { // first time, build all cells from scratch
var table = $("<table/>").appendTo(element);
s = "<thead><tr>";
for (i=0; i<colCnt; i++) {
s += "<th class='fc-" +
dayIDs[d.getDay()] + ' ' + // needs to be first
tm + '-state-default' +
(i==dit ? ' fc-leftmost' : '') +
"'>" + formatDate(d, colFormat, options) + "</th>";
addDays(d, 1);
}
thead = $(s + "</tr></thead>").appendTo(table);
s = "<tbody>";
d = cloneDate(view.visStart);
for (i=0; i<rowCnt; i++) {
s += "<tr class='fc-week" + i + "'>";
for (j=0; j<colCnt; j++) {
s += "<td class='fc-" +
dayIDs[d.getDay()] + ' ' + // needs to be first
tm + '-state-default fc-day' + (i*colCnt+j) +
(j==dit ? ' fc-leftmost' : '') +
(rowCnt>1 && d.getMonth() != month ? ' fc-other-month' : '') +
(+d == +today ?
' fc-today '+tm+'-state-highlight' :
' fc-not-today') + "'>" +
(showNumbers ? "<div class='fc-day-number'>" + d.getDate() + "</div>" : '') +
"<div class='fc-day-content'><div>&nbsp;</div></div></td>";
addDays(d, 1);
}
s += "</tr>";
}
tbody = $(s + "</tbody>").appendTo(table);
tbody.find('td').click(dayClick);
}else{ // NOT first time, reuse as many cells as possible
view.clearEvents();
var prevRowCnt = tbody.find('tr').length;
if (rowCnt < prevRowCnt) {
tbody.find('tr:gt(' + (rowCnt-1) + ')').remove(); // remove extra rows
}
else if (rowCnt > prevRowCnt) { // needs to create new rows...
s = '';
for (i=prevRowCnt; i<rowCnt; i++) {
s += "<tr class='fc-week" + i + "'>";
for (j=0; j<colCnt; j++) {
s += "<td class='fc-" +
dayIDs[d.getDay()] + ' ' + // needs to be first
tm + '-state-default fc-new fc-day' + (i*colCnt+j) +
(j==dit ? ' fc-leftmost' : '') + "'>" +
(showNumbers ? "<div class='fc-day-number'></div>" : '') +
"<div class='fc-day-content'><div>&nbsp;</div></div>" +
"</td>";
addDays(d, 1);
}
s += "</tr>";
}
tbody.append(s);
}
tbody.find('td.fc-new').removeClass('fc-new').click(dayClick);
// re-label and re-class existing cells
d = cloneDate(view.visStart);
tbody.find('td').each(function() {
var td = $(this);
if (rowCnt > 1) {
if (d.getMonth() == month) {
td.removeClass('fc-other-month');
}else{
td.addClass('fc-other-month');
}
}
if (+d == +today) {
td.removeClass('fc-not-today')
.addClass('fc-today')
.addClass(tm + '-state-highlight');
}else{
td.addClass('fc-not-today')
.removeClass('fc-today')
.removeClass(tm + '-state-highlight');
}
td.find('div.fc-day-number').text(d.getDate());
addDays(d, 1);
});
if (rowCnt == 1) { // more changes likely (week or day view)
// redo column header text and class
d = cloneDate(view.visStart);
thead.find('th').each(function() {
$(this).text(formatDate(d, colFormat, options));
this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
addDays(d, 1);
});
// redo cell day-of-weeks
d = cloneDate(view.visStart);
tbody.find('td').each(function() {
this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
addDays(d, 1);
});
}
}
updateSize();
fetchEvents(renderEvents);
};
function dayClick() {
var date = addDays(
cloneDate(view.visStart),
parseInt(this.className.match(/fc\-day(\d+)/)[1])
);
view.trigger('dayClick', this, date);
}
function updateSize() {
var height = Math.round(element.width() / options.aspectRatio),
leftTDs = tbody.find('tr td:first-child'),
tbodyHeight = height - thead.height(),
rowHeight1, rowHeight2;
if (options.weekMode == 'variable') {
rowHeight1 = rowHeight2 = Math.floor(tbodyHeight / (rowCnt==1 ? 2 : 6));
}else{
rowHeight1 = Math.floor(tbodyHeight / rowCnt);
rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1);
}
if (tdTopBug == undefined) {
// nasty bugs in opera 9.25
// position() returning relative to direct parent
var tr = tbody.find('tr:first'),
td = tr.find('td:first'),
trTop = tr.position().top,
tdTop = td.position().top;
tdTopBug = tdTop < 0;
trTopBug = trTop != tdTop;
tbodyTopBug = tbody.position().top != trTop;
}
if (tdHeightBug == undefined) {
// bug in firefox where cell height includes padding
td.height(rowHeight1);
tdHeightBug = rowHeight1 != td.height();
}
if (tdHeightBug) {
leftTDs.slice(0, -1).height(rowHeight1);
leftTDs.slice(-1).height(rowHeight2);
}else{
setOuterHeight(leftTDs.slice(0, -1), rowHeight1);
setOuterHeight(leftTDs.slice(-1), rowHeight2);
}
setOuterWidth(
thead.find('th').slice(0, -1),
colWidth = Math.floor(element.width() / colCnt)
);
}
/* Event Rendering
-----------------------------------------------------------------------------*/
function renderEvents(events) {
view.reportEvents(events);
renderSegs(cachedSegs = compileSegs(events));
}
function rerenderEvents(skipCompile) {
view.clearEvents();
if (skipCompile) {
renderSegs(cachedSegs);
}else{
renderEvents(view.cachedEvents);
}
}
function compileSegs(events) {
var d1 = cloneDate(view.visStart);
var d2 = addDays(cloneDate(d1), colCnt);
var rows = [];
for (var i=0; i<rowCnt; i++) {
rows.push(stackSegs(view.sliceSegs(events, d1, d2)));
addDays(d1, 7);
addDays(d2, 7);
}
return rows;
}
function renderSegs(segRows) {
var i, len = segRows.length, levels,
tr, td,
innerDiv,
top,
weekHeight,
j, segs,
levelHeight,
k, seg,
event,
eventClasses,
startElm, endElm,
left1, left2,
eventElement, eventAnchor,
triggerRes;
for (i=0; i<len; i++) {
levels = segRows[i];
tr = tbody.find('tr:eq('+i+')');
td = tr.find('td:first');
innerDiv = td.find('div.fc-day-content div').css('position', 'relative');
top = innerDiv.position().top;
if (tdTopBug) {
top -= td.position().top;
}
if (trTopBug) {
top += tr.position().top;
}
if (tbodyTopBug) {
top += tbody.position().top;
}
weekHeight = 0;
for (j=0; j<levels.length; j++) {
segs = levels[j];
levelHeight = 0;
for (k=0; k<segs.length; k++) {
seg = segs[k];
event = seg.event;
eventClasses = event.className;
if (typeof eventClasses == 'object') { // an array
eventClasses = eventClasses.slice(0);
}
else if (typeof eventClasses == 'string') {
eventClasses = eventClasses.split(' ');
}
else {
eventClasses = [];
}
eventClasses.push('fc-event', 'fc-event-hori');
startElm = seg.isStart ?
tr.find('td:eq('+((seg.start.getDay()-firstDay+colCnt)%colCnt)+') div.fc-day-content div') :
tbody;
endElm = seg.isEnd ?
tr.find('td:eq('+((seg.end.getDay()-firstDay+colCnt-1)%colCnt)+') div.fc-day-content div') :
tbody;
if (rtl) {
left1 = endElm.position().left;
left2 = startElm.position().left + startElm.width();
if (seg.isStart) {
eventClasses.push('fc-corner-right');
}
if (seg.isEnd) {
eventClasses.push('fc-corner-left');
}
}else{
left1 = startElm.position().left;
left2 = endElm.position().left + endElm.width();
if (seg.isStart) {
eventClasses.push('fc-corner-left');
}
if (seg.isEnd) {
eventClasses.push('fc-corner-right');
}
}
eventElement = $("<div class='" + eventClasses.join(' ') + "'/>")
.append(eventAnchor = $("<a/>")
.append(event.allDay || !seg.isStart ? null :
$("<span class='fc-event-time'/>")
.html(formatDates(event.start, event.end, options.timeFormat, options)))
.append($("<span class='fc-event-title'/>")
.text(event.title)));
if (event.url) {
eventAnchor.attr('href', event.url);
}
triggerRes = view.trigger('eventRender', event, event, eventElement);
if (triggerRes !== false) {
if (triggerRes && typeof triggerRes != 'boolean') {
eventElement = $(triggerRes);
}
eventElement
.css({
position: 'absolute',
top: top,
left: left1 + (rtlLeftDiff||0),
zIndex: 2
})
.appendTo(element);
setOuterWidth(eventElement, left2-left1, true);
if (rtl && rtlLeftDiff == undefined) {
// bug in IE6 where offsets are miscalculated with direction:rtl
rtlLeftDiff = left1 - eventElement.position().left;
if (rtlLeftDiff) {
eventElement.css('left', left1 + rtlLeftDiff);
}
}
eventElementHandlers(event, eventElement);
if (event.editable || event.editable == undefined && options.editable) {
draggableEvent(event, eventElement);
if (seg.isEnd) {
resizableEvent(event, eventElement);
}
}
view.reportEventElement(event, eventElement);
levelHeight = Math.max(levelHeight, eventElement.outerHeight(true));
}
}
weekHeight += levelHeight;
top += levelHeight;
}
innerDiv.height(weekHeight);
}
}
function eventElementHandlers(event, eventElement) {
eventElement
.click(function(ev) {
if (!eventElement.hasClass('ui-draggable-dragging')) {
return view.trigger('eventClick', this, event, ev);
}
})
.hover(
function(ev) {
view.trigger('eventMouseover', this, event, ev);
},
function(ev) {
view.trigger('eventMouseout', this, event, ev);
}
);
}
/* Draggable
-----------------------------------------------------------------------------*/
function draggableEvent(event, eventElement) {
if (!options.disableDragging && eventElement.draggable) {
var matrix;
eventElement.draggable({
zIndex: 3,
delay: 50,
opacity: options.dragOpacity,
revertDuration: options.dragRevertDuration,
start: function(ev, ui) {
matrix = new HoverMatrix(function(cell) {
eventElement.draggable('option', 'revert', !cell || !cell.rowDelta && !cell.colDelta);
if (cell) {
view.showOverlay(cell);
}else{
view.hideOverlay();
}
});
tbody.find('tr').each(function() {
matrix.row(this, tbodyTopBug);
});
var tds = tbody.find('tr:first td');
if (rtl) {
tds = $(tds.get().reverse());
}
tds.each(function() {
matrix.col(this);
});
view.hideEvents(event, eventElement);
view.trigger('eventDragStart', eventElement, event, ev, ui);
matrix.mouse(ev.pageX, ev.pageY);
},
drag: function(ev) {
matrix.mouse(ev.pageX, ev.pageY);
},
stop: function(ev, ui) {
view.hideOverlay();
view.trigger('eventDragStop', eventElement, event, ev, ui);
var cell = matrix.cell;
if (!cell || !cell.rowDelta && !cell.colDelta) {
view.showEvents(event, eventElement);
}else{
var dayDelta = cell.rowDelta*7 + cell.colDelta*dis;
view.moveEvent(event, dayDelta);
view.trigger('eventDrop', this, event, dayDelta, 0, function() {
view.moveEvent(event, -dayDelta);
rerenderEvents();
}, ev, ui);
eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
rerenderEvents();
}
}
});
}
}
/* Resizable
-----------------------------------------------------------------------------*/
function resizableEvent(event, eventElement) {
if (!options.disableResizing && eventElement.resizable) {
eventElement.resizable({
handles: rtl ? 'w' : 'e',
grid: colWidth,
minWidth: colWidth/2, // need this or else IE throws errors when too small
containment: element,
start: function(ev, ui) {
eventElement.css('z-index', 3);
view.hideEvents(event, eventElement);
view.trigger('eventResizeStart', this, event, ev, ui);
},
stop: function(ev, ui) {
view.trigger('eventResizeStop', this, event, ev, ui);
// ui.size.width wasn't working with grid correctly, use .width()
var dayDelta = Math.round((eventElement.width() - ui.originalSize.width) / colWidth);
if (dayDelta) {
view.resizeEvent(event, dayDelta);
view.trigger('eventResize', this, event, dayDelta, 0, function() {
view.resizeEvent(event, -dayDelta);
rerenderEvents();
}, ev, ui);
rerenderEvents();
}else{
view.showEvents(event, eventElement);
}
eventElement.css('z-index', 2);
}
});
}
}
};

0
jquery/jquery.js → src/jquery/jquery.js vendored Normal file → Executable file
View File

4
jquery/ui.core.js → src/jquery/ui.core.js Normal file → Executable file
View File

@ -1,5 +1,5 @@
/*
* jQuery UI 1.7
* jQuery UI 1.7.2
*
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
@ -14,7 +14,7 @@ var _remove = $.fn.remove,
//Helper functions and ui object
$.ui = {
version: "1.7",
version: "1.7.2",
// $.ui.plugin is deprecated. Use the proxy pattern instead.
plugin: {

4
jquery/ui.draggable.js → src/jquery/ui.draggable.js Normal file → Executable file
View File

@ -1,5 +1,5 @@
/*
* jQuery UI Draggable 1.7
* jQuery UI Draggable 1.7.2
*
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
@ -400,7 +400,7 @@ $.widget("ui.draggable", $.extend({}, $.ui.mouse, {
}));
$.extend($.ui.draggable, {
version: "1.7",
version: "1.7.2",
eventPrefix: "drag",
defaults: {
addClasses: true,

800
src/jquery/ui.resizable.js Executable file
View File

@ -0,0 +1,800 @@
/*
* jQuery UI Resizable 1.7.2
*
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* http://docs.jquery.com/UI/Resizables
*
* Depends:
* ui.core.js
*/
(function($) {
$.widget("ui.resizable", $.extend({}, $.ui.mouse, {
_init: function() {
var self = this, o = this.options;
this.element.addClass("ui-resizable");
$.extend(this, {
_aspectRatio: !!(o.aspectRatio),
aspectRatio: o.aspectRatio,
originalElement: this.element,
_proportionallyResizeElements: [],
_helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
});
//Wrap the element if it cannot hold child nodes
if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
//Opera fix for relative positioning
if (/relative/.test(this.element.css('position')) && $.browser.opera)
this.element.css({ position: 'relative', top: 'auto', left: 'auto' });
//Create a wrapper element and set the wrapper to the new current internal element
this.element.wrap(
$('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
position: this.element.css('position'),
width: this.element.outerWidth(),
height: this.element.outerHeight(),
top: this.element.css('top'),
left: this.element.css('left')
})
);
//Overwrite the original this.element
this.element = this.element.parent().data(
"resizable", this.element.data('resizable')
);
this.elementIsWrapper = true;
//Move margins to the wrapper
this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
//Prevent Safari textarea resize
this.originalResizeStyle = this.originalElement.css('resize');
this.originalElement.css('resize', 'none');
//Push the actual element to our proportionallyResize internal array
this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
// avoid IE jump (hard set the margin)
this.originalElement.css({ margin: this.originalElement.css('margin') });
// fix handlers offset
this._proportionallyResize();
}
this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' });
if(this.handles.constructor == String) {
if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
var n = this.handles.split(","); this.handles = {};
for(var i = 0; i < n.length; i++) {
var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
// increase zIndex of sw, se, ne, nw axis
//TODO : this modifies original option
if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });
//TODO : What's going on here?
if ('se' == handle) {
axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
};
//Insert into internal handles object and append to element
this.handles[handle] = '.ui-resizable-'+handle;
this.element.append(axis);
}
}
this._renderAxis = function(target) {
target = target || this.element;
for(var i in this.handles) {
if(this.handles[i].constructor == String)
this.handles[i] = $(this.handles[i], this.element).show();
//Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
var axis = $(this.handles[i], this.element), padWrapper = 0;
//Checking the correct pad and border
padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
//The padding type i have to apply...
var padPos = [ 'padding',
/ne|nw|n/.test(i) ? 'Top' :
/se|sw|s/.test(i) ? 'Bottom' :
/^e$/.test(i) ? 'Right' : 'Left' ].join("");
target.css(padPos, padWrapper);
this._proportionallyResize();
}
//TODO: What's that good for? There's not anything to be executed left
if(!$(this.handles[i]).length)
continue;
}
};
//TODO: make renderAxis a prototype function
this._renderAxis(this.element);
this._handles = $('.ui-resizable-handle', this.element)
.disableSelection();
//Matching axis name
this._handles.mouseover(function() {
if (!self.resizing) {
if (this.className)
var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
//Axis, default = se
self.axis = axis && axis[1] ? axis[1] : 'se';
}
});
//If we want to auto hide the elements
if (o.autoHide) {
this._handles.hide();
$(this.element)
.addClass("ui-resizable-autohide")
.hover(function() {
$(this).removeClass("ui-resizable-autohide");
self._handles.show();
},
function(){
if (!self.resizing) {
$(this).addClass("ui-resizable-autohide");
self._handles.hide();
}
});
}
//Initialize the mouse interaction
this._mouseInit();
},
destroy: function() {
this._mouseDestroy();
var _destroy = function(exp) {
$(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
.removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
};
//TODO: Unwrap at same DOM position
if (this.elementIsWrapper) {
_destroy(this.element);
var wrapper = this.element;
wrapper.parent().append(
this.originalElement.css({
position: wrapper.css('position'),
width: wrapper.outerWidth(),
height: wrapper.outerHeight(),
top: wrapper.css('top'),
left: wrapper.css('left')
})
).end().remove();
}
this.originalElement.css('resize', this.originalResizeStyle);
_destroy(this.originalElement);
},
_mouseCapture: function(event) {
var handle = false;
for(var i in this.handles) {
if($(this.handles[i])[0] == event.target) handle = true;
}
return this.options.disabled || !!handle;
},
_mouseStart: function(event) {
var o = this.options, iniPos = this.element.position(), el = this.element;
this.resizing = true;
this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
// bugfix for http://dev.jquery.com/ticket/1749
if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
}
//Opera fixing relative position
if ($.browser.opera && (/relative/).test(el.css('position')))
el.css({ position: 'relative', top: 'auto', left: 'auto' });
this._renderProxy();
var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
if (o.containment) {
curleft += $(o.containment).scrollLeft() || 0;
curtop += $(o.containment).scrollTop() || 0;
}
//Store needed variables
this.offset = this.helper.offset();
this.position = { left: curleft, top: curtop };
this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
this.originalPosition = { left: curleft, top: curtop };
this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
this.originalMousePosition = { left: event.pageX, top: event.pageY };
//Aspect Ratio
this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
var cursor = $('.ui-resizable-' + this.axis).css('cursor');
$('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
el.addClass("ui-resizable-resizing");
this._propagate("start", event);
return true;
},
_mouseDrag: function(event) {
//Increase performance, avoid regex
var el = this.helper, o = this.options, props = {},
self = this, smp = this.originalMousePosition, a = this.axis;
var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
var trigger = this._change[a];
if (!trigger) return false;
// Calculate the attrs that will be change
var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
if (this._aspectRatio || event.shiftKey)
data = this._updateRatio(data, event);
data = this._respectSize(data, event);
// plugins callbacks need to be called first
this._propagate("resize", event);
el.css({
top: this.position.top + "px", left: this.position.left + "px",
width: this.size.width + "px", height: this.size.height + "px"
});
if (!this._helper && this._proportionallyResizeElements.length)
this._proportionallyResize();
this._updateCache(data);
// calling the user callback at the end
this._trigger('resize', event, this.ui());
return false;
},
_mouseStop: function(event) {
this.resizing = false;
var o = this.options, self = this;
if(this._helper) {
var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
soffsetw = ista ? 0 : self.sizeDiff.width;
var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
if (!o.animate)
this.element.css($.extend(s, { top: top, left: left }));
self.helper.height(self.size.height);
self.helper.width(self.size.width);
if (this._helper && !o.animate) this._proportionallyResize();
}
$('body').css('cursor', 'auto');
this.element.removeClass("ui-resizable-resizing");
this._propagate("stop", event);
if (this._helper) this.helper.remove();
return false;
},
_updateCache: function(data) {
var o = this.options;
this.offset = this.helper.offset();
if (isNumber(data.left)) this.position.left = data.left;
if (isNumber(data.top)) this.position.top = data.top;
if (isNumber(data.height)) this.size.height = data.height;
if (isNumber(data.width)) this.size.width = data.width;
},
_updateRatio: function(data, event) {
var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
if (data.height) data.width = (csize.height * this.aspectRatio);
else if (data.width) data.height = (csize.width / this.aspectRatio);
if (a == 'sw') {
data.left = cpos.left + (csize.width - data.width);
data.top = null;
}
if (a == 'nw') {
data.top = cpos.top + (csize.height - data.height);
data.left = cpos.left + (csize.width - data.width);
}
return data;
},
_respectSize: function(data, event) {
var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
if (isminw) data.width = o.minWidth;
if (isminh) data.height = o.minHeight;
if (ismaxw) data.width = o.maxWidth;
if (ismaxh) data.height = o.maxHeight;
var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
if (isminw && cw) data.left = dw - o.minWidth;
if (ismaxw && cw) data.left = dw - o.maxWidth;
if (isminh && ch) data.top = dh - o.minHeight;
if (ismaxh && ch) data.top = dh - o.maxHeight;
// fixing jump error on top/left - bug #2330
var isNotwh = !data.width && !data.height;
if (isNotwh && !data.left && data.top) data.top = null;
else if (isNotwh && !data.top && data.left) data.left = null;
return data;
},
_proportionallyResize: function() {
var o = this.options;
if (!this._proportionallyResizeElements.length) return;
var element = this.helper || this.element;
for (var i=0; i < this._proportionallyResizeElements.length; i++) {
var prel = this._proportionallyResizeElements[i];
if (!this.borderDif) {
var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
this.borderDif = $.map(b, function(v, i) {
var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
return border + padding;
});
}
if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))
continue;
prel.css({
height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
});
};
},
_renderProxy: function() {
var el = this.element, o = this.options;
this.elementOffset = el.offset();
if(this._helper) {
this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
// fix ie6 offset TODO: This seems broken
var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
pxyoffset = ( ie6 ? 2 : -1 );
this.helper.addClass(this._helper).css({
width: this.element.outerWidth() + pxyoffset,
height: this.element.outerHeight() + pxyoffset,
position: 'absolute',
left: this.elementOffset.left - ie6offset +'px',
top: this.elementOffset.top - ie6offset +'px',
zIndex: ++o.zIndex //TODO: Don't modify option
});
this.helper
.appendTo("body")
.disableSelection();
} else {
this.helper = this.element;
}
},
_change: {
e: function(event, dx, dy) {
return { width: this.originalSize.width + dx };
},
w: function(event, dx, dy) {
var o = this.options, cs = this.originalSize, sp = this.originalPosition;
return { left: sp.left + dx, width: cs.width - dx };
},
n: function(event, dx, dy) {
var o = this.options, cs = this.originalSize, sp = this.originalPosition;
return { top: sp.top + dy, height: cs.height - dy };
},
s: function(event, dx, dy) {
return { height: this.originalSize.height + dy };
},
se: function(event, dx, dy) {
return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
},
sw: function(event, dx, dy) {
return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
},
ne: function(event, dx, dy) {
return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
},
nw: function(event, dx, dy) {
return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
}
},
_propagate: function(n, event) {
$.ui.plugin.call(this, n, [event, this.ui()]);
(n != "resize" && this._trigger(n, event, this.ui()));
},
plugins: {},
ui: function() {
return {
originalElement: this.originalElement,
element: this.element,
helper: this.helper,
position: this.position,
size: this.size,
originalSize: this.originalSize,
originalPosition: this.originalPosition
};
}
}));
$.extend($.ui.resizable, {
version: "1.7.2",
eventPrefix: "resize",
defaults: {
alsoResize: false,
animate: false,
animateDuration: "slow",
animateEasing: "swing",
aspectRatio: false,
autoHide: false,
cancel: ":input,option",
containment: false,
delay: 0,
distance: 1,
ghost: false,
grid: false,
handles: "e,s,se",
helper: false,
maxHeight: null,
maxWidth: null,
minHeight: 10,
minWidth: 10,
zIndex: 1000
}
});
/*
* Resizable Extensions
*/
$.ui.plugin.add("resizable", "alsoResize", {
start: function(event, ui) {
var self = $(this).data("resizable"), o = self.options;
_store = function(exp) {
$(exp).each(function() {
$(this).data("resizable-alsoresize", {
width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10)
});
});
};
if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); }
}else{
_store(o.alsoResize);
}
},
resize: function(event, ui){
var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;
var delta = {
height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
},
_alsoResize = function(exp, c) {
$(exp).each(function() {
var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left'];
$.each(css || ['width', 'height', 'top', 'left'], function(i, prop) {
var sum = (start[prop]||0) + (delta[prop]||0);
if (sum && sum >= 0)
style[prop] = sum || null;
});
//Opera fixing relative position
if (/relative/.test(el.css('position')) && $.browser.opera) {
self._revertToRelativePosition = true;
el.css({ position: 'absolute', top: 'auto', left: 'auto' });
}
el.css(style);
});
};
if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
$.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); });
}else{
_alsoResize(o.alsoResize);
}
},
stop: function(event, ui){
var self = $(this).data("resizable");
//Opera fixing relative position
if (self._revertToRelativePosition && $.browser.opera) {
self._revertToRelativePosition = false;
el.css({ position: 'relative' });
}
$(this).removeData("resizable-alsoresize-start");
}
});
$.ui.plugin.add("resizable", "animate", {
stop: function(event, ui) {
var self = $(this).data("resizable"), o = self.options;
var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
soffsetw = ista ? 0 : self.sizeDiff.width;
var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
self.element.animate(
$.extend(style, top && left ? { top: top, left: left } : {}), {
duration: o.animateDuration,
easing: o.animateEasing,
step: function() {
var data = {
width: parseInt(self.element.css('width'), 10),
height: parseInt(self.element.css('height'), 10),
top: parseInt(self.element.css('top'), 10),
left: parseInt(self.element.css('left'), 10)
};
if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
// propagating resize, and updating values for each animation step
self._updateCache(data);
self._propagate("resize", event);
}
}
);
}
});
$.ui.plugin.add("resizable", "containment", {
start: function(event, ui) {
var self = $(this).data("resizable"), o = self.options, el = self.element;
var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
if (!ce) return;
self.containerElement = $(ce);
if (/document/.test(oc) || oc == document) {
self.containerOffset = { left: 0, top: 0 };
self.containerPosition = { left: 0, top: 0 };
self.parentData = {
element: $(document), left: 0, top: 0,
width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
};
}
// i'm a node, so compute top, left, right, bottom
else {
var element = $(ce), p = [];
$([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
self.containerOffset = element.offset();
self.containerPosition = element.position();
self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
self.parentData = {
element: ce, left: co.left, top: co.top, width: width, height: height
};
}
},
resize: function(event, ui) {
var self = $(this).data("resizable"), o = self.options,
ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;
if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
if (cp.left < (self._helper ? co.left : 0)) {
self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));
if (pRatio) self.size.height = self.size.width / o.aspectRatio;
self.position.left = o.helper ? co.left : 0;
}
if (cp.top < (self._helper ? co.top : 0)) {
self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);
if (pRatio) self.size.width = self.size.height * o.aspectRatio;
self.position.top = self._helper ? co.top : 0;
}
self.offset.left = self.parentData.left+self.position.left;
self.offset.top = self.parentData.top+self.position.top;
var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );
var isParent = self.containerElement.get(0) == self.element.parent().get(0),
isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));
if(isParent && isOffsetRelative) woset -= self.parentData.left;
if (woset + self.size.width >= self.parentData.width) {
self.size.width = self.parentData.width - woset;
if (pRatio) self.size.height = self.size.width / self.aspectRatio;
}
if (hoset + self.size.height >= self.parentData.height) {
self.size.height = self.parentData.height - hoset;
if (pRatio) self.size.width = self.size.height * self.aspectRatio;
}
},
stop: function(event, ui){
var self = $(this).data("resizable"), o = self.options, cp = self.position,
co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
if (self._helper && !o.animate && (/relative/).test(ce.css('position')))
$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
if (self._helper && !o.animate && (/static/).test(ce.css('position')))
$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
}
});
$.ui.plugin.add("resizable", "ghost", {
start: function(event, ui) {
var self = $(this).data("resizable"), o = self.options, cs = self.size;
self.ghost = self.originalElement.clone();
self.ghost
.css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
.addClass('ui-resizable-ghost')
.addClass(typeof o.ghost == 'string' ? o.ghost : '');
self.ghost.appendTo(self.helper);
},
resize: function(event, ui){
var self = $(this).data("resizable"), o = self.options;
if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
},
stop: function(event, ui){
var self = $(this).data("resizable"), o = self.options;
if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
}
});
$.ui.plugin.add("resizable", "grid", {
resize: function(event, ui) {
var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;
o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
if (/^(se|s|e)$/.test(a)) {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
}
else if (/^(ne)$/.test(a)) {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
self.position.top = op.top - oy;
}
else if (/^(sw)$/.test(a)) {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
self.position.left = op.left - ox;
}
else {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
self.position.top = op.top - oy;
self.position.left = op.left - ox;
}
}
});
var num = function(v) {
return parseInt(v, 10) || 0;
};
var isNumber = function(value) {
return !isNaN(parseInt(value, 10));
};
})(jQuery);

685
src/main.js Executable file
View File

@ -0,0 +1,685 @@
var fc = $.fullCalendar = {};
var views = fc.views = {};
/* Defaults
-----------------------------------------------------------------------------*/
var defaults = {
// display
defaultView: 'month',
aspectRatio: 1.35,
header: {
left: 'title',
center: '',
right: 'today prev,next'
},
// editing
//editable: false,
//disableDragging: false,
//disableResizing: false,
allDayDefault: true,
// event ajax
startParam: 'start',
endParam: 'end',
cacheParam: '_',
// time formats
timeFormat: 'h(:mm)t', // for events
titleFormat: {
month: 'MMMM yyyy',
week: "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
day: 'dddd, MMM d, yyyy'
},
columnFormat: {
month: 'ddd',
week: 'ddd M/d',
day: 'dddd M/d'
},
// locale
isRTL: false,
firstDay: 0,
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
buttonText: {
prev: '&nbsp;&#9668;&nbsp;',
next: '&nbsp;&#9658;&nbsp;',
today: 'today',
month: 'month',
week: 'week',
day: 'day'
},
// jquery-ui theming
theme: false,
buttonIcons: {
prev: 'circle-triangle-w',
next: 'circle-triangle-e'
}
};
// right-to-left defaults
var rtlDefaults = {
header: {
left: 'next,prev today',
center: '',
right: 'title'
},
buttonText: {
prev: '&nbsp;&#9658;&nbsp;',
next: '&nbsp;&#9668;&nbsp;'
}
};
// function for adding/overriding defaults
var setDefaults = fc.setDefaults = function(d) {
$.extend(true, defaults, d);
}
/* .fullCalendar jQuery function
-----------------------------------------------------------------------------*/
$.fn.fullCalendar = function(options) {
// method calling
if (typeof options == 'string') {
var args = Array.prototype.slice.call(arguments, 1),
res;
this.each(function() {
var r = $.data(this, 'fullCalendar')[options].apply(this, args);
if (res == undefined) {
res = r;
}
});
if (res != undefined) {
return res;
}
return this;
}
// pluck the 'events' and 'eventSources' options
var eventSources = options.eventSources || [];
delete options.eventSources;
if (options.events) {
eventSources.push(options.events);
delete options.event;
}
// first event source reserved for 'sticky' events
eventSources.unshift([]);
// initialize options
options = $.extend(true, {},
defaults,
(options.isRTL || options.isRTL==undefined && defaults.isRTL) ? rtlDefaults : {},
options
);
var tm = options.theme ? 'ui' : 'fc'; // for making theme classes
this.each(function() {
/* Instance Initialization
-----------------------------------------------------------------------------*/
// element
var _element = this,
element = $(this).addClass('fc'),
content = $("<div class='fc-content " + tm + "-widget-content'/>").appendTo(this);
if (options.isRTL) {
element.addClass('fc-rtl');
}
if (options.theme) {
element.addClass('ui-widget');
}
// view managing
var date = new Date(),
viewName, view, // the current view
prevView,
viewInstances = {};
if (options.year != undefined) {
date.setYear(options.year);
}
if (options.month != undefined) {
date.setMonth(options.month);
}
if (options.date != undefined) {
date.setDate(options.date);
}
/* View Rendering
-----------------------------------------------------------------------------*/
function changeView(v) {
if (v != viewName) {
prevView = view;
if (viewInstances[v]) {
(view = viewInstances[v]).element.show();
}else{
view = viewInstances[v] = $.fullCalendar.views[v](
$("<div class='fc-view fc-view-" + v + "'/>").appendTo(content),
options);
}
if (prevView && prevView.eventsChanged) {
// if previous view's events have been changed, mark future views' events as dirty
eventsDirtyExcept(prevView);
prevView.eventsChanged = false;
}
if (header) {
// update 'active' view button
header.find('div.fc-button-' + viewName).removeClass(tm + '-state-active');
header.find('div.fc-button-' + v).addClass(tm + '-state-active');
}
view.name = viewName = v;
render();
if (prevView) {
// hide the old element AFTER the new has been rendered, preserves scrollbars
prevView.element.hide();
}
}
}
function render(inc) {
if (_element.offsetWidth !== 0) { // visible on the screen
if (inc || !view.date || +view.date != +date) { // !view.date means it hasn't been rendered yet
ignoreWindowResizes = true;
view.render(date, inc || 0, function(callback) {
// dont refetch if new view contains the same events (or a subset)
if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) {
fetchEvents(callback);
}else{
callback(events); // no refetching
}
});
ignoreWindowResizes = false;
view.date = cloneDate(date);
}
else if (view.sizeDirty) {
view.updateSize();
view.rerenderEvents();
}
else if (view.eventsDirty) {
// ensure events are rerendered if another view messed with them
// pass in 'events' b/c event might have been added/removed
view.clearEvents();
view.renderEvents(events);
}
if (header) {
// update title text
header.find('h2.fc-header-title').html(view.title);
// enable/disable 'today' button
var today = new Date();
if (today >= view.start && today < view.end) {
header.find('div.fc-button-today').addClass(tm + '-state-disabled');
}else{
header.find('div.fc-button-today').removeClass(tm + '-state-disabled');
}
}
view.sizeDirty = false;
view.eventsDirty = false;
view.trigger('viewDisplay', _element);
}
}
// marks other views' events as dirty
function eventsDirtyExcept(exceptView) {
$.each(viewInstances, function() {
if (this != exceptView) {
this.eventsDirty = true;
}
});
}
// marks other views' sizes as dirty
function sizesDirtyExcept(exceptView) {
$.each(viewInstances, function() {
if (this != exceptView) {
this.sizeDirty = true;
}
});
}
// called when any event objects have been added/removed/changed, rerenders
function eventsChanged() {
view.clearEvents();
view.renderEvents(events);
eventsDirtyExcept(view);
}
/* Event Sources and Fetching
-----------------------------------------------------------------------------*/
var events = [],
eventStart, eventEnd;
// Fetch from ALL sources. Clear 'events' array and populate
function fetchEvents(callback) {
events = [];
eventStart = cloneDate(view.visStart);
eventEnd = cloneDate(view.visEnd);
var queued = eventSources.length,
sourceDone = function() {
if (--queued == 0) {
if (callback) {
callback(events);
}
}
}, i=0;
for (; i<eventSources.length; i++) {
fetchEventSource(eventSources[i], sourceDone);
}
}
// Fetch from a particular source. Append to the 'events' array
function fetchEventSource(src, callback) {
var prevViewName = view.name,
prevDate = cloneDate(date),
reportEvents = function(a) {
if (prevViewName == view.name && +prevDate == +date) { // protects from fast switching
for (var i=0; i<a.length; i++) {
normalizeEvent(a[i], options);
a[i].source = src;
}
events = events.concat(a);
if (callback) {
callback(a);
}
}
},
reportEventsAndPop = function(a) {
reportEvents(a);
popLoading();
};
if (typeof src == 'string') {
var params = {};
params[options.startParam] = Math.round(eventStart.getTime() / 1000);
params[options.endParam] = Math.round(eventEnd.getTime() / 1000);
params[options.cacheParam] = (new Date()).getTime();
pushLoading();
$.getJSON(src, params, reportEventsAndPop);
}
else if ($.isFunction(src)) {
pushLoading();
src(cloneDate(eventStart), cloneDate(eventEnd), reportEventsAndPop);
}
else {
reportEvents(src); // src is an array
}
}
/* Loading State
-----------------------------------------------------------------------------*/
var loadingLevel = 0;
function pushLoading() {
if (!loadingLevel++) {
view.trigger('loading', _element, true);
}
}
function popLoading() {
if (!--loadingLevel) {
view.trigger('loading', _element, false);
}
}
/* Public Methods
-----------------------------------------------------------------------------*/
var publicMethods = {
render: render,
changeView: changeView,
//
// Navigation
//
prev: function() {
render(-1);
},
next: function() {
render(1);
},
today: function() {
date = new Date();
render();
},
gotoDate: function(year, month, dateNum) {
if (typeof year == 'object') {
date = cloneDate(year); // provided 1 argument, a Date
}else{
if (year != undefined) {
date.setYear(year);
}
if (month != undefined) {
date.setMonth(month);
}
if (dateNum != undefined) {
date.setDate(dateNum);
}
}
render();
},
incrementDate: function(years, months, days) {
if (years != undefined) {
addYears(date, years);
}
if (months != undefined) {
addMonths(date, months);
}
if (days != undefined) {
addDays(date, days);
}
render();
},
//
// Event Manipulation
//
updateEvent: function(event) { // update an existing event
var i, len = events.length, e,
startDelta = event.start - event._start,
endDelta = event.end ?
(event.end - (event._end || view.defaultEventEnd(event))) // event._end would be null if event.end
: 0; // was null and event was just resized
for (i=0; i<len; i++) {
e = events[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(+view.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;
normalizeEvent(e, options);
}
}
normalizeEvent(event, options);
eventsChanged();
},
renderEvent: function(event, stick) { // render a new event
normalizeEvent(event, options);
if (!event.source) {
if (stick) {
(event.source = eventSources[0]).push(event);
}
events.push(event);
}
eventsChanged();
},
removeEvents: function(filter) {
if (!filter) { // remove all
events = [];
// clear all array sources
for (var i=0; i<eventSources.length; i++) {
if (typeof eventSources[i] == 'object') {
eventSources[i] = [];
}
}
}else{
if (!$.isFunction(filter)) { // an event ID
var id = filter + '';
filter = function(e) {
return e._id == id;
};
}
events = $.grep(events, filter, true);
// remove events from array sources
for (var i=0; i<eventSources.length; i++) {
if (typeof eventSources[i] == 'object') {
eventSources[i] = $.grep(eventSources[i], filter, true);
}
}
}
eventsChanged();
},
clientEvents: function(filter) {
if ($.isFunction(filter)) {
return $.grep(events, filter);
}
else if (filter) { // an event ID
filter += '';
return $.grep(events, function(e) {
return e._id == filter;
});
}
return events; // else, return all
},
rerenderEvents: function() {
view.rerenderEvents();
},
//
// Event Source
//
addEventSource: function(source) {
eventSources.push(source);
fetchEventSource(source, function() {
eventsChanged();
});
},
removeEventSource: function(source) {
eventSources = $.grep(eventSources, function(src) {
return src != source;
});
// remove all client events from that source
events = $.grep(events, function(e) {
return e.source != source;
});
eventsChanged();
},
refetchEvents: function() {
fetchEvents(eventsChanged);
}
};
$.data(this, 'fullCalendar', publicMethods);
/* Header
-----------------------------------------------------------------------------*/
var header,
sections = options.header;
if (sections) {
header = $("<table class='fc-header'/>")
.append($("<tr/>")
.append($("<td class='fc-header-left'/>").append(buildSection(sections.left)))
.append($("<td class='fc-header-center'/>").append(buildSection(sections.center)))
.append($("<td class='fc-header-right'/>").append(buildSection(sections.right))))
.prependTo(element);
}
function buildSection(buttonStr) {
if (buttonStr) {
var tr = $("<tr/>");
$.each(buttonStr.split(' '), function(i) {
if (i > 0) {
tr.append("<td><span class='fc-header-space'/></td>");
}
var prevButton;
$.each(this.split(','), function(j) {
var buttonName = this,
buttonNameShort = this.replace(/^(basic|agenda)/, '').toLowerCase();
if (buttonName == 'title') {
tr.append("<td><h2 class='fc-header-title'/></td>");
if (prevButton) {
prevButton.addClass(tm + '-corner-right');
}
prevButton = null;
}else{
var buttonClick;
if (publicMethods[buttonNameShort]) {
buttonClick = publicMethods[buttonNameShort];
}
else if (views[buttonName]) {
buttonClick = function() { changeView(buttonName) };
}
if (buttonClick) {
if (prevButton) {
prevButton.addClass(tm + '-no-right');
}
var button,
icon = options.theme ? options.buttonIcons[buttonNameShort] : null,
text = options.buttonText[buttonNameShort];
if (icon) {
button = $("<div class='fc-button-" + buttonName + " ui-state-default'>" +
"<a><span class='ui-icon ui-icon-" + icon + "'/></a></div>");
}
else if (text) {
button = $("<div class='fc-button-" + buttonName + " " + tm + "-state-default'>" +
"<a><span>" + text + "</span></a></div>");
}
if (button) {
button
.mousedown(function() {
button.addClass(tm + '-state-down');
})
.mouseup(function() {
button.removeClass(tm + '-state-down');
})
.hover(
function() {
button.addClass(tm + '-state-hover');
},
function() {
button.removeClass(tm + '-state-hover')
.removeClass(tm + '-state-down');
}
)
.appendTo($("<td/>").appendTo(tr));
if (publicMethods[buttonNameShort]) {
button.click(publicMethods[buttonNameShort]);
}
else if (views[buttonName]) {
button.click(function() {
changeView(buttonName);
});
}
if (prevButton) {
prevButton.addClass(tm + '-no-right');
}else{
button.addClass(tm + '-corner-left');
}
prevButton = button;
}
}
}
});
if (prevButton) {
prevButton.addClass(tm + '-corner-right');
}
});
return $("<table/>").append(tr);
}
}
/* Resizing
-----------------------------------------------------------------------------*/
var elementWidth,
ignoreWindowResizes = false,
resizeCnt = 0;
$(window).resize(function() {
if (!ignoreWindowResizes && view.date) { // view.date means the view has been rendered
var rcnt = ++resizeCnt; // add a delay
setTimeout(function() {
if (rcnt == resizeCnt) {
var newWidth = element.width();
if (newWidth != elementWidth) {
elementWidth = newWidth;
view.updateSize();
view.rerenderEvents(true);
sizesDirtyExcept(view);
view.trigger('windowResize', _element);
}
}
}, 200);
}
});
// let's begin...
changeView(options.defaultView);
elementWidth = element.width();
});
return this;
};
/* Important Event Utilities
-----------------------------------------------------------------------------*/
var fakeID = 0;
function normalizeEvent(event, options) {
event._id = event._id || (event.id == undefined ? '_fc' + fakeID++ : event.id + '');
if (event.date) {
if (!event.start) {
event.start = event.date;
}
delete event.date;
}
event._start = cloneDate(event.start = parseDate(event.start));
event.end = parseDate(event.end);
if (event.end && event.end < event.start) {
event.end = null;
}
event._end = event.end ? cloneDate(event.end) : null;
if (event.allDay == undefined) {
event.allDay = options.allDayDefault;
}
}

2
src/misc/foot.txt Executable file
View File

@ -0,0 +1,2 @@
})(jQuery);

19
src/misc/head.txt Executable file
View File

@ -0,0 +1,19 @@
/*!
* FullCalendar
* http://arshaw.com/fullcalendar/
*
* Use fullcalendar.css for basic styling.
* For event drag & drop, required jQuery UI draggable.
* For event resizing, requires jQuery UI resizable.
*
* Copyright (c) 2009 Adam Shaw
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Date:
* Revision:
*/
(function($) {

345
src/util.js Executable file
View File

@ -0,0 +1,345 @@
/* Date Math
-----------------------------------------------------------------------------*/
var DAY_MS = 86400000,
HOUR_MS = 3600000;
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) { // prevent infinite looping on invalid dates
var dd = d.getDate() + n,
check = cloneDate(d);
check.setHours(12); // set to middle of day
check.setDate(dd);
d.setDate(dd);
if (!keepTime) {
clearTime(d);
}
while (d.getDate() != check.getDate()) {
d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
}
}
return d;
}
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);
}
/* Date Parsing
-----------------------------------------------------------------------------*/
var parseDate = fc.parseDate = function(s) {
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+$/)) { // a UNIX timestamp
return new Date(parseInt(s) * 1000);
}
return parseISO8601(s, true) || new Date(s) || null;
}
return null;
}
var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
// derived from http://delete.me.uk/2005/03/iso8601.html
var d = 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 (!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));
}
/* Date Formatting
-----------------------------------------------------------------------------*/
var formatDate = fc.formatDate = function(date, format, options) {
return formatDates(date, null, format, options);
}
var formatDates = fc.formatDates = function(date1, date2, format, options) {
options = options || defaults;
var date = date1,
otherDate = date2,
i, len = format.length, c,
i2, formatter,
res = '';
for (i=0; i<len; i++) {
c = format.charAt(i);
if (c == "'") {
for (i2=i+1; i2<len; 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<len; i2++) {
if (format.charAt(i2) == ')') {
var subres = formatDate(date, format.substring(i+1, i2), options);
if (parseInt(subres.replace(/\D/, ''))) {
res += subres;
}
i = i2;
break;
}
}
}
else if (c == '[') {
for (i2=i+1; i2<len; 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';
}
};
/* Element Dimensions
-----------------------------------------------------------------------------*/
function setOuterWidth(element, width, includeMargins) {
element.each(function() {
var e = $(this);
var w = width - (
(parseInt(e.css('border-left-width')) || 0) +
(parseInt(e.css('padding-left')) || 0) +
(parseInt(e.css('padding-right')) || 0) +
(parseInt(e.css('border-right-width')) || 0));
if (includeMargins) {
w -=
(parseInt(e.css('margin-left')) || 0) +
(parseInt(e.css('margin-right')) || 0);
}
e.width(w);
});
}
function setOuterHeight(element, height, includeMargins) {
element.each(function() {
var e = $(this);
var h = height - (
(parseInt(e.css('border-top-width')) || 0) +
(parseInt(e.css('padding-top')) || 0) +
(parseInt(e.css('padding-bottom')) || 0) +
(parseInt(e.css('border-bottom-width')) || 0));
if (includeMargins) {
h -=
(parseInt(e.css('margin-top')) || 0) +
(parseInt(e.css('margin-bottom')) || 0);
}
e.height(h);
});
}
/* Hover Matrix
-----------------------------------------------------------------------------*/
function HoverMatrix(changeCallback) {
var tops=[], lefts=[],
prevRowE, prevColE,
origRow, origCol,
currRow, currCol;
this.row = function(e, topBug) {
prevRowE = $(e);
tops.push(prevRowE.offset().top + (topBug ? prevRowE.parent().position().top : 0));
};
this.col = function(e) {
prevColE = $(e);
lefts.push(prevColE.offset().left);
};
this.mouse = function(x, y) {
if (origRow == undefined) {
tops.push(tops[tops.length-1] + prevRowE.outerHeight());
lefts.push(lefts[lefts.length-1] + prevColE.outerWidth());
currRow = currCol = -1;
}
var r, c;
for (r=0; r<tops.length && y>=tops[r]; r++) ;
for (c=0; c<lefts.length && x>=lefts[c]; c++) ;
r = r >= tops.length ? -1 : r - 1;
c = c >= lefts.length ? -1 : c - 1;
if (r != currRow || c != currCol) {
currRow = r;
currCol = c;
if (r == -1 || c == -1) {
this.cell = null;
}else{
if (origRow == undefined) {
origRow = r;
origCol = c;
}
this.cell = {
row: r,
col: c,
top: tops[r],
left: lefts[c],
width: lefts[c+1] - lefts[c],
height: tops[r+1] - tops[r],
isOrig: r==origRow && c==origCol,
rowDelta: r-origRow,
colDelta: c-origCol
};
}
changeCallback(this.cell);
}
};
}
/* Misc Utils
-----------------------------------------------------------------------------*/
var undefined,
dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
function zeroPad(n) {
return (n < 10 ? '0' : '') + n;
}
function strProp(s, prop) {
return typeof s == 'string' ? s : s[prop];
}

264
src/view.js Executable file
View File

@ -0,0 +1,264 @@
/* Methods & Utilities for All Views
-----------------------------------------------------------------------------*/
var viewMethods = {
/*
* Objects inheriting these methods must implement the following properties/methods:
* - title
* - start
* - end
* - visStart
* - visEnd
* - defaultEventEnd(event)
* - visEventEnd(event)
* - render(events)
* - rerenderEvents()
*
*
* z-index reservations:
* 1. day-overlay
* 2. events
* 3. dragging/resizing events
*
*/
init: function(element, options) {
this.element = element;
this.options = options;
this.cachedEvents = [];
this.eventsByID = {};
this.eventElements = [];
this.eventElementsByID = {};
},
// triggers an event handler, always append view as last arg
trigger: function(name, thisObj) {
if (this.options[name]) {
return this.options[name].apply(thisObj || this, Array.prototype.slice.call(arguments, 2).concat([this]));
}
},
// returns a Date object for an event's end
eventEnd: function(event) {
return event.end || this.defaultEventEnd(event);
},
// report when view receives new events
reportEvents: function(events) { // events are already normalized at this point
var i, len=events.length, event,
eventsByID = this.eventsByID = {},
cachedEvents = this.cachedEvents = [];
for (i=0; i<len; i++) {
event = events[i];
if (eventsByID[event._id]) {
eventsByID[event._id].push(event);
}else{
eventsByID[event._id] = [event];
}
cachedEvents.push(event);
}
},
// report when view creates an element for an event
reportEventElement: function(event, element) {
this.eventElements.push(element);
var eventElementsByID = this.eventElementsByID;
if (eventElementsByID[event._id]) {
eventElementsByID[event._id].push(element);
}else{
eventElementsByID[event._id] = [element];
}
},
// event element manipulation
clearEvents: function() { // only remove ELEMENTS
$.each(this.eventElements, function() {
this.remove();
});
this.eventElements = [];
this.eventElementsByID = {};
},
showEvents: function(event, exceptElement) {
this._eee(event, exceptElement, 'show');
},
hideEvents: function(event, exceptElement) {
this._eee(event, exceptElement, 'hide');
},
_eee: function(event, exceptElement, funcName) { // event-element-each
var elements = this.eventElementsByID[event._id],
i, len = elements.length;
for (i=0; i<len; i++) {
if (elements[i] != exceptElement) {
elements[i][funcName]();
}
}
},
// event modification reporting
moveEvent: function(event, days, minutes) { // actually DO the date changes
minutes = minutes || 0;
var events = this.eventsByID[event._id],
i, len=events.length, e;
for (i=0; i<len; i++) {
e = events[i];
e.allDay = event.allDay;
addMinutes(addDays(e.start, days, true), minutes);
if (e.end) {
e.end = addMinutes(addDays(e.end, days, true), minutes);
}
normalizeEvent(e, this.options);
}
this.eventsChanged = true;
},
resizeEvent: function(event, days, minutes) { // actually DO the date changes
minutes = minutes || 0;
var events = this.eventsByID[event._id],
i, len=events.length, e;
for (i=0; i<len; i++) {
e = events[i];
e.end = addMinutes(addDays(this.eventEnd(e), days, true), minutes);
normalizeEvent(e, this.options);
}
this.eventsChanged = true;
},
// semi-transparent overlay (while dragging)
showOverlay: function(props) {
if (!this.dayOverlay) {
this.dayOverlay = $("<div class='fc-cell-overlay' style='position:absolute;z-index:1;display:none'/>")
.appendTo(this.element);
}
var o = this.element.offset();
this.dayOverlay
.css({
top: props.top - o.top,
left: props.left - o.left,
width: props.width,
height: props.height
})
.show();
},
hideOverlay: function() {
if (this.dayOverlay) {
this.dayOverlay.hide();
}
},
// event rendering utilities
sliceSegs: function(events, start, end) {
var segs = [],
i, len=events.length, event,
eventStart, eventEnd,
segStart, segEnd,
isStart, isEnd;
for (i=0; i<len; i++) {
event = events[i];
eventStart = event.start;
eventEnd = this.visEventEnd(event);
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);
}
};
// more event rendering utilities
function stackSegs(segs) {
var levels = [],
i, len = segs.length, seg,
j, collide, k;
for (i=0; i<len; i++) {
seg = segs[i];
j = 0; // the level index where seg should belong
while (true) {
collide = false;
if (levels[j]) {
for (k=0; k<levels[j].length; 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];
}
//seg.after = 0;
}
return levels;
}
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;
}

112
legacy/examples/basic.html → tests/basic.html Normal file → Executable file
View File

@ -1,12 +1,68 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$('#calendar').fullCalendar({
editable: true,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6, 14, 0),
end: new Date(y, m, 11),
allDay: false
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 2),
allDay: true
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 9),
allDay: true
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27, 16),
end: new Date(y, m, 29),
url: "http://facebook.com/",
allDay: false
}
]
});
});
</script>
<style type='text/css'>
body {
margin-top: 50px;
margin-top: 40px;
text-align: center;
font-size: 14px;
font-size: 13px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
}
@ -16,58 +72,8 @@
}
</style>
<link rel='stylesheet' type='text/css' href='../../fullcalendar.css' />
<script type='text/javascript' src='../jquery/jquery.js'></script>
<script type='text/javascript' src='../jquery/ui.core.js'></script>
<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
<script type='text/javascript' src='../../fullcalendar.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$('#calendar').fullCalendar({
draggable: true,
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 11)
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating Event",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0)
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 29),
url: "http://facebook.com/"
}
]
});
});
</script>
</head>
<body>
<div id='calendar'></div>
</body>
</html>
</html>

115
tests/firebug-lite/ChangeLog Executable file
View File

@ -0,0 +1,115 @@
== Firebug Lite Change Log ==
2009-04-16 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1653: Removed reliability on firebug.liteFilename
Fixed a security issue in IE 7 (introduced via Microsoft Update)
2009-03-09 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1637: Script missing linebreaks in IE7, line numbers broken in all browsers
2009-03-09 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Added title to popup window
2009-03-09 Azer Koculu <azer@kodfabrik.com>
* firebug-lite.js: Removed getElementPosXY method.
Added toggle method to settings object.
2009-03-07 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed issue 1554: Text nodes could not be accessed through the inspect button.
2009-03-07 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1566: Added firebug.env.targetWindow variable to hold target window
2009-03-06 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Changed default for firebug.env.detectFirebug to false
Fixed issue 1555: Ajax calls ... we should not assume that the same domain policy is applied, use try catch instead
Fixed Issue 1541: Add XHR tab to Firebug Lite popup window
progress.gif: Corrected mime type
2009-03-03 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js, firebug-lite.css, progress.gif: Fixed Issue 1544: Lite settings menu should have a "processing" gif
2009-02-21 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed Issue 1542: FBLite F12 etc should dock the popup instead of hiding the panel
2009-02-21 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js, firebug-lite.css:
o Issue 1513 ... added:
- Settings dialog
- Settings storage cookie (stores settings, panel height, popup window positions etc.)
- firebug.env:
openInPopup
popupTop
popupLeft
popupWidth
popupHeight
o Various popup window bugfixes and performance improvements
2009-02-21 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js, firebug-lite.css, firebug_logo.png: Issue 1503: FBLite should have a visible sign it is running when starting hidden.
Added FBLite icon when hidden and firebug.env.showIconWhenHidden (default true).
2009-02-18 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed issue 1086 - FBLite can now be used locally over HTTPS if firebug.env.css is set.
2009-02-17 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Fixed problem with issue 1481 - A DIV was created instead of an IFRAME so the shield was ineffective.
2009-02-14 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1487 - Added firebug.env.liteFilename ... this allows for the renaming of the FBLite script for use in popup windows.
2009-02-12 Azer Koculu <azer@kodfabrik.com>
* minifier.py, jsmin.py, minify: Added minifier library and compressing scripts.
2009-02-12 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Corrected 2 syntax errors
2009-02-11 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1400 - firebug.env.override is now false by default ... I have also added
two methods to make it easier for the user to control the console:
firebug.overrideConsole() & firebug.restoreConsole()
2009-02-09 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1400 - Re-implemented firebug.env.override. Default is now true ... it can only be manually changed in FBLite code.
The reason this is needed is because a number of browsers have a window.console object.
2009-02-08 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Issue 1406 - Added firebug.env.hideDOMFunctions to allow hiding of DOM functions in the DOM tab.
2009-02-06 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Removed firebug.env.override to prevent problems when override is set in FF3 where window.console
is a getter and allow more control over initialization.
* firebug-lite.js: Refactored code to allow firebug.env.detectFirebug to be set from user code
* firebug-lite.js: Moved console initialization code inside of the Firebug object to remove some global variables
* firebug-lite.js & firebug-lite.css: Fixed Issue 1348 - String, Date and Boolean objects should be displayed similar
to their primitive counterparts
* firebug-lite.js & firebug-lite.css: Fixed Issue 1023 - Elements such as Flash in iframes and dropdowns in IE bleed through FBLite,
I have put an iframe 'shield' behind FBLite to prevent this
* Updated mime-types for all FBLite SVN files
2009-02-05 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Added firebug.env.detectFirebug to prevent FBLite opening when Firebug is enabled (actually the Firebug Console).
To run FBLite and Firebug at the same time it is now necessary to change the value of detectFirebug directly in firebug-lite.js
* Fixed multiple console initialization and override issues
2009-02-05 Azer Koculu <azer@kodfabrik.com>
* firebug-lite.css: mime-type property has been set to "text/css".
2009-02-04 Azer Koculu <azer@kodfabrik.com>
* firebug-lite.js: Changed default css url getfirebug.com to fbug.google.com
* firebug-lite-compressed.js: It was unnecesseary, removed.
2009-02-02 Azer Koculu <azer@kodfabrik.com>
* Copied latest source to googlecode repository.
2009-01-31 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js: Added extra hotkeys to show / hide FBLite:
F12, (CTRL|CMD)+SHIFT+L, SHIFT+ENTER
* firebug-lite.js: Added console.firebug command to show FBLite version number
* firebug-lite.js: Fixed problem with Open in New Window in Safari
* firebug-lite.js: Added debug="true/false" to show or hide FBLite on startup
2009-01-01 Mike Ratcliffe <sabine.michael.ratcliffe@gmail.com>
* firebug-lite.js & firebug-lite.css: Added Open in New Window
* firebug-lite.js: Fixed: HTML Inspect only worked in 1 very specific situation ... it now works in all situations
* firebug-lite.js: Fixed: Permission was occasionally denied to inspect CSS or scripts when it should not have been
* firebug-lite.js: Fixed: Domain check now works with domain names containing - and _

BIN
tests/firebug-lite/errorIcon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,218 @@
/* */
#Firebug div, #Firebug h3, #Firebug span, #Firebug input, #Firebug textarea, #Firebug select, #Firebug option, #Firebug a, #Firebug strong, #Firebug em, #Firebug label, #Firebug center {
position:static; float:none; width:auto; height:auto; text-align:left; border:0; overflow:visible; background:transparent none repeat left top; color:#111; font-size:1em; font-weight:normal; font-style:normal; font-family:sans-serif; margin:0; padding:0; min-height:0;
}
#Firebug input, #Firebug select, #Firebug textarea { background:#fff; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; border:1px outset #aaa; padding:2px }
#Firebug center { text-align:center; }
#Firebug strong { font-weight:bold; }
#Firebug em { font-style:italic; }
/* */
#FirebugIFrame { position:fixed !important; position:absolute; z-index:99999998; left:0; bottom:0; width:100%; height:295px; background:#fff; border-width:0px; }
#Firebug { position:fixed !important; position:absolute; z-index:99999999; left:0; bottom:0; width:100%; height:295px; background:#fff; overflow:hidden; }
#Firebug .Resizer { position:absolute; top:0; width:100%; height:5px; background:transparent; *background:url(spacer.gif); cursor:n-resize; -moz-user-select:none; }
#Firebug .Header { height:38px; background:#ccc url(firebug.gif) 0 -85px; }
#Firebug .Left, #Firebug > .Right { background:#fff; height:257px;}
#Firebug .Left { float:left; width:100%; }
#Firebug .Right { float:left; display:none; width:30%; overflow:hidden; }
#Firebug .Right .Container { height:100%; border-left:1px solid #ccc; }
/*
* buttonset
*/
#Firebug .ButtonContainer { padding:8px 0 5px 10px; *margin-top:-3px; _margin-top:0; }
#Firebug .ButtonContainer .Button { cursor:pointer; font:12px "MS Sans Serif", Geneva, sans-serif; color:#000; margin-right:5px; padding:4px 4px 4px 4px; border:1px solid transparent !important; border-color:#ccc; text-decoration:none; }
#Firebug .ButtonContainer .Button:hover { border:1px outset #aaa !important; }
#Firebug .ButtonContainer .Button:active { border-style:inset !important; background-color:#ccc; }
#Firebug .ButtonContainer .Enabled { border:1px outset #aaa !important; }
#Firebug .ButtonContainer .Logo { text-decoration:none; padding-left:24px; background:url(firebug.gif) no-repeat 5px 3px; border:0 !important; opacity:0.7; filter:Alpha(Opacity=70); }
#Firebug .ButtonContainer .Logo:hover, #Firebug .ButtonContainer .Logo:active { border:0 !important; background-color:transparent; opacity:1; filter:Alpha(Opacity=100); }
#Firebug .ButtonContainer .Maximize, #Firebug .ButtonContainer .Minimize, #Firebug .ButtonContainer .NewWindow, #Firebug .ButtonContainer .Dock, #Firebug .ButtonContainer .Close { position:absolute; right:0; top:12px; padding:6px 8px 8px 8px; background:url(firebug.gif) no-repeat -3px -48px; border:0 !important; opacity:0.7; filter:Alpha(Opacity:80); *padding:0px 7px 1px 7px; }
#Firebug .ButtonContainer .Maximize:hover, #Firebug .ButtonContainer .Maximize:active, #Firebug .ButtonContainer .NewWindow:hover, #Firebug .ButtonContainer .NewWindow:active, #Firebug .ButtonContainer .Dock:hover, #Firebug .ButtonContainer .Dock:active, #Firebug .ButtonContainer .Minimize:hover, #Firebug .ButtonContainer .Minimize:active, #Firebug .ButtonContainer .Close:hover, #Firebug .ButtonContainer .Close:active { border:0 !important; background-color:transparent; opacity:1; filter:Alpha(Opacity:100); }
#Firebug .ButtonContainer .Minimize { background-position:-3px -20px; right:40px; }
#Firebug .ButtonContainer .Maximize { display:none; background-position:-3px -34px; right:40px; }
#Firebug .ButtonContainer .NewWindow { background-position:-3px -123px; right:20px; }
#Firebug .ButtonContainer .Dock { background-position:-3px -137px; }
#Firebug .ButtonContainer .ButtonSet { border-left:1px solid #ccc; padding:0 0 0 3px; display:inline; }
/*
* navigation
*/
#Firebug .Nav { height:23px; background:url(firebug.gif) repeat-x 0 -62px; padding-left:10px; }
#Firebug .Nav .Tab { display:block; width:auto; float:left; padding:3px 6px 2px 6px; cursor:pointer; border:1px outset transparent !important; border:0; font:bold 11px Arial, Helvetica, sans-serif; color:#666; }
#Firebug .Nav .Tab:hover, #Firebug .Nav .Selected { border:1px outset #ccc !important; border-top-color:transparent !important; }
#Firebug .Nav .Selected { color:#111; cursor:default; background-color:#f2f2f2; }
#Firebug .Nav .Settings { float:right; }
#Firebug .Nav .Settings .Options { text-decoration:none; padding-left:24px; background:url(firebug.gif) no-repeat 65px -151px; border:0 !important; opacity:0.7; filter:Alpha(Opacity=70); }
#Firebug .Nav .Settings .Options:hover, #Firebug .ButtonContainer .Options:active { border:0 !important; background-color:transparent; opacity:1; filter:Alpha(Opacity=100); }
/*
* inspector
*/
#FirebugBorderInspector { display:none; z-index:99999998; position:absolute; top:0; left:0; border:2px solid #0000ff; background:transparent; *background:url(spacer.gif); opacity:0.5; filter:Alpha(Opacity=50); padding:0; margin:0; }
#FirebugBGInspector { display:none; z-index:99999998; position:absolute; top:0; left:0; background:rgb(0,150,255); opacity:0.5; filter:Alpha(Opacity=50); padding:0; margin:0; }
/*
* dom
*/
#Firebug .DOMRow { width:100% !important; width:90%; }
#Firebug .DOMRow .DOMRowLeft { float:left; width:30%; overflow:hidden; }
#Firebug .DOMRow .DOMRowLeft a { padding-left:15px; }
#Firebug .DOMRow .DOMRowRight { float:left; width:60%; *width:60%; _overflow:hidden; white-space:nowrap; }
#Firebug .DOMRow .DOMRowLeft .Object { background:url(tree_open.gif) no-repeat left center; cursor:pointer; }
#Firebug .DOMRow .DOMRowLeft .Object:hover { text-decoration:underline; color:#0000ff; }
#Firebug .DOMRow .DOMRowLeft .Opened { background-image:url(tree_close.gif) }
#Firebug .DOMRow .DOMRowSubContainer { display:none; padding-left:25px; }
/*
* console
*/
#Firebug .Left .Console { overflow:hidden; }
#Firebug .Left .Console .Monitor { height:210px; border-bottom:1px solid #ccc; overflow:scroll; overflow-x:hidden; }
#Firebug .Left .Console .Monitor .Error { background:#ffeff1; color:#ff0000; }
#Firebug .Left .Console .Monitor .Error strong { color:#ff0000; }
#Firebug .Left .Console .Monitor .Row { padding:2px 5px 2px 5px; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; overflow:hidden; border-bottom:1px solid #e5e5e5; }
#Firebug .Left .Console .Monitor .Arrow { color:rgb(0,0,255); white-space:nowrap; }
#Firebug .Left .Console .InputArrow { position:absolute; left:0px; width:20px; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; color:#0000ff; padding:2px 4px 0 4px; }
#Firebug .Left .Console .InputContainer { margin-left:35px; margin-right:5px; }
#Firebug .Left .Console .Input { width:100% !important; margin-top:2px; width:98%; overflow:hidden; border:0; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Console .MLButton { cursor:pointer; position:absolute; top:276px; right:-22px; width:20px; padding:4px 10px 10px 10px; font-size:1px; *padding:2px 10px 10px 10px; background:url(firebug.gif) no-repeat -3px -34px; opacity:0.8; filter:Alpha(Opacity:80); }
#Firebug .Console .MLButton:hover { opacity:1; filter:Alpha(Opacity:100); }
#Firebug .Console .CloseML { background-position:-3px -20px; }
#Firebug .Right .Console { background:#eee; }
#Firebug .Right .Console .Input { width:100%; _width:98%; height:228px; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; background:#fff; border:0; border-bottom:1px solid #ccc; margin-bottom:2px; *overflow:scroll; }
#Firebug .Right .Console .Button { cursor:pointer; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:1px 4px 1px 4px; margin:0 4px 0 4px; background:#eee; border:1px solid #eee; text-decoration:none; *display:block; *width:auto; *float:left; *margin-top:-1px; }
#Firebug .Right .Console .Button:hover { border:1px outset #ccc; background:#fff; }
#Firebug .Right .Console .Button:active { border:1px inset #ccc; background:#ccc; }
#Firebug .Left .Console .Monitor .Warn { background:url(warningIcon.png) #00FFFF no-repeat 2px center; padding-left:20px; }
#Firebug .Left .Console .Monitor .Info { background:url(infoIcon.png) #fff no-repeat 2px center; padding-left:20px; }
#Firebug .Left .Console .Monitor .Error { background:url(errorIcon.png) #FFFFE0 no-repeat 2px center; padding-left:20px; }
/*
* html
*/
#Firebug .Left .HTML { display:none; height:250px; overflow:scroll; padding:0 10px 2px 10px; }
#Firebug .Left .HTML .Block { padding:0 0 0 0px; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Left .HTML .Block .Spacer { cursor:default; padding:2px 2px 2px 15px; }
#Firebug .Left .HTML .Block .Link { display:block; color:#333; padding:2px 2px 2px 0; }
#Firebug .Left .HTML .Block .Link .Content { padding:2px 2px 2px 2px; }
#Firebug .Left .HTML .Block .Link .TagName { cursor:pointer; }
#Firebug .Left .HTML .Block .Parent { font-weight:bold; color:#111; text-decoration:none; }
#Firebug .Left .HTML .Block .Parent .Spacer { background:#fff center no-repeat; }
#Firebug .Left .HTML .Block .Parent .Spacer { background-image:url(tree_open.gif); }
#Firebug .Left .HTML .Block .Open .Spacer { background-image:url(tree_close.gif) }
#Firebug .Left .HTML .Block .Selected { background-color:#4473c4; }
#Firebug .Left .HTML .Block .Selected * { color:#fff; }
#Firebug .Left .HTML .Block .SubContainer { padding-left:20px; height:0; font-size:0px; }
#Firebug .Left .HTML .Block .OpenSubContainer { height:auto; }
#Firebug .Left .HTML .Unvisible { opacity:0.5; filter:Alpha(Opacity=50); }
#Firebug .Right .HTML { display:none; }
#Firebug .Right .HTML .Content { overflow:scroll; height:235px; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Right .HTML .Content .CSSItem { padding:5px; color:#333; height:6px }
#Firebug .Right .HTML .Content .CSSProperty { width:45%; float:left; overflow:hidden; }
#Firebug .Right .HTML .Content .CSSValue { width:55%; float:left; white-space:nowrap; overflow:visible !important; overflow:hidden; }
#Firebug .Right .HTML .Content .CSSValue input { font:11px ArArial, Helvetica, sans-serif; color:#333; 3px 0 0 -3px; }
#Firebug .Right .HTML .Content .CSSItem center { color:rgb(0,150,0); padding:0 0 3px 0; font:bold 12px Arial, Helvetica, sans-serif; }
#Firebug .ButtonContainer .HTML { display:none; }
/*
* CSS
*/
#Firebug .Left .CSS { display:none; padding:5px; height:225px; overflow:scroll; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Right .CSS { display:none; }
#Firebug .Left .CSS .Selector { margin-top:10px }
#Firebug .Left .CSS .CSSText { padding-left:20px; }
#Firebug .Left .CSS .CSSProperty { color:#005500; margin-top:10px; }
#Firebug .Left .CSS .CSSValue { padding-left:5px; color:#000088; }
#Firebug .ButtonContainer .CSS { display:none; }
#Firebug .Right .CSS { background:#eee; }
#Firebug .Right .CSS .Input { width:100%; _width:98%; height:205px; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; background:#fff; border:0; border-bottom:1px solid #ccc; margin-bottom:2px; *overflow:scroll; }
#Firebug .Right .CSS .Button { cursor:pointer; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:1px 4px 1px 4px; margin:0 4px 0 4px; background:#eee; border:1px solid #eee; text-decoration:none; *display:block; *width:auto; *float:left; *margin-top:-1px; }
#Firebug .Right .CSS .Button:hover { border:1px outset #ccc; background:#fff; }
#Firebug .Right .CSS .Button:active { border:1px inset #ccc; background:#ccc; }
/*
* Scripts
*/
#Firebug .Left .Scripts { display:none; height:225px; *height:235px; overflow:scroll; font:12px Verdana, Geneva, Arial, Helvetica, sans-serif; white-space:pre; }
#Firebug .Left .Scripts .LineNumber { float:left; width:30px; height:20px; padding:0 2px 0 0; background:#eee; color:#666; font-family:Courier; text-align:right; border-right:1px solid #ccc; }
#Firebug .Left .Scripts .CodeContainer { padding:5px; }
#Firebug .Left .Scripts .Code { height:20px; }
#Firebug .Left .Scripts .CodeContainer, #Firebug .Left .Scripts .Code { word-wrap:normal; white-space:pre; }
#Firebug .Right .Scripts { display:none; }
#Firebug .ButtonContainer .Scripts { display:none; }
/*
* DOM
*/
#Firebug .Left .DOM { display:none; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; overflow:scroll; height:225px; }
#Firebug .Left .DOM .Object { font-weight:bold; }
#Firebug .Right .DOM { display:none; overflow:scroll; }
#Firebug .ButtonContainer .DOM { display:none; }
#Firebug .ButtonContainer .DOM label { font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
/*
* XHR
*/
#Firebug .Left .XHR { display:none; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; overflow:scroll; height:225px; }
#Firebug .Left .XHR .Block { float:left; width:30%; }
#Firebug .Left .XHR .BlockContent { padding:3px; border-right:1px dotted #aaa; }
#Firebug .Left .XHR .Block strong { display:block; text-align:center; padding:3px; background:rgb(200,225,255); color:rgb(50,50,50); }
#Firebug .Left .XHR .Block span { display:block; text-align:center; overflow:hidden; }
#Firebug .Left .XHR .Block span a { cursor:pointer; color:rgb(0,0,200); }
#Firebug .Right .XHR { display:none; overflow:scroll; }
#Firebug .ButtonContainer .XHR { display:none; }
#Firebug .ButtonContainer .XHR label { font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Left .STR { display:none; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; padding:5px; overflow:scroll; height:225px; }
/*
* settings
*/
#Firebug .SettingsDiv {position:absolute;width:190px;top:60px;border:1px outset #000;-x-system-font:none;color:#000;font-family:"MS Sans Serif",Geneva,sans-serif;font-size:12px;font-size-adjust:none;font-stretch:normal;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;display:none;background-color:#FFF;}
#Firebug .SettingsDiv .Header {background:#CCC url(firebug.gif) repeat scroll 0 -85px;height:30px;border-bottom:1px inset #000;}
#Firebug .SettingsDiv .Header .Title {padding-top:10px;text-align:center;}
#Firebug .SettingsDiv .Content {padding:5px;}
#Firebug .SettingsDiv .Content .SettingsCBX{position:relative;top:2px;margin: 4px 5px 0 0; border:0 !important; padding:0 !important; height: 15px !important;}
#Firebug .SettingsDiv .Content .SettingsTextbox{position:relative;top:2px;margin: 4px 5px 0 0; border:0 !important; padding:0 !important; height: 15px !important; width:35px !important; border:1px solid #000000 !important;}
#Firebug .SettingsDiv .Content .ButtonsLeft {float:left;padding:10px 0px 5px 0px;}
#Firebug .SettingsDiv .Content .ButtonsRight {float:right;padding:10px 0px 5px 0px;}
#Firebug .SettingsDiv .Content .ProgressDiv {background-color:#FFF;width:100%;height:100%;position:absolute;left:0;top:0;z-index:1;opacity:.8;filter:alpha(opacity=80);display:none;}
#Firebug .SettingsDiv .Content .Progress {background-image:url(progress.gif);width:66px;height:66px;position:absolute;top:50%;left:50%;margin-left:-33px;margin-top:-33px;}
/*
* element highlighting
*/
#Firebug .Italic { font-style:italic; }
#Firebug .Strong { font-weight:bold; }
#Firebug .NormalWeight { font-weight:normal; }
#Firebug .Green { color:#008800; }
#Firebug .Gray { color:#666; }
#Firebug .Blue { color:#0000ee; }
#Firebug .DarkBlue { color:#000099; }
#Firebug .Red { color:#ee0000; }
#Firebug .Maroon { color:#800000; font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; }
#Firebug .Null { font:11px Verdana, Geneva, Arial, Helvetica, sans-serif; color:#fff; padding:0 2px 0 2px; background:#999; border:1px solid #666; }
#Firebug .ObjectLink, #Firebug .ObjectLinkHover { cursor:pointer; }
#Firebug .ObjectLinkHover { border-bottom:1px solid #008800; }
#Firebug .Clear { clear:both; height:0px; font-size:0px; }
#firebugIconDiv { width:38px;height:38px;right:15pt;bottom:5pt;border:2px solid #000;display:none;position:fixed;background-image:url(firebug_logo.png);text-decoration:underline;cursor:pointer;filter:alpha(opacity:60);opacity:.6;z-index:99999998;}

2572
tests/firebug-lite/firebug-lite.js Executable file

File diff suppressed because it is too large Load Diff

BIN
tests/firebug-lite/firebug.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

BIN
tests/firebug-lite/infoIcon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

BIN
tests/firebug-lite/progress.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
tests/firebug-lite/spacer.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

BIN
tests/firebug-lite/tree_close.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

BIN
tests/firebug-lite/tree_open.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

115
tests/gcal.html Executable file
View File

@ -0,0 +1,115 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$(document).ready(function() {
$('#calendar').fullCalendar({
editable: true,
eventSources: [
$.fullCalendar.gcalFeed(
"http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic",
{
editable: true,
className: ['holiday']
}
),
/*$.fullCalendar.gcalFeed(
"http://www.google.com/calendar/feeds/mike%40maddogsportsbar.com/private-4ad75f9427058f8fe6525c0857c59fbc/basic",
{
className: 'maddog'
}
),*/
[
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 10)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 20, 10, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://facebook.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
]
]
});
});
</script>
<style>
.holiday,
.holiday a {
background: green;
border-color: green;
}
.maddog,
.maddog a {
background: red;
border-color: red;
}
/* rescued from fullcalendar.css (not used here) */
.fc-event-nobg,
.fc-event-nobg a,
.fc-agenda .fc-event-nobg .fc-event-time {
border-style: none;
background: none;
color: inherit;
}
</style>
</head>
<body style='font-size:12px'>
<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

View File

@ -0,0 +1,819 @@
/*
* jQuery UI Resizable 1.6
*
* Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* http://docs.jquery.com/UI/Resizables
*
* Depends:
* ui.core.js
*/
(function($) {
$.widget("ui.resizable", $.extend({}, $.ui.mouse, {
_init: function() {
var self = this, o = this.options;
var elpos = this.element.css('position');
this.originalElement = this.element;
// simulate .ui-resizable { position: relative; }
this.element.addClass("ui-resizable").css({ position: /static/.test(elpos) ? 'relative' : elpos });
$.extend(o, {
_aspectRatio: !!(o.aspectRatio),
helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null,
knobHandles: o.knobHandles === true ? 'ui-resizable-knob-handle' : o.knobHandles
});
//Default Theme
var aBorder = '1px solid #DEDEDE';
o.defaultTheme = {
'ui-resizable': { display: 'block' },
'ui-resizable-handle': { position: 'absolute', background: '#F2F2F2', fontSize: '0.1px' },
'ui-resizable-n': { cursor: 'n-resize', height: '4px', left: '0px', right: '0px', borderTop: aBorder },
'ui-resizable-s': { cursor: 's-resize', height: '4px', left: '0px', right: '0px', borderBottom: aBorder },
'ui-resizable-e': { cursor: 'e-resize', width: '4px', top: '0px', bottom: '0px', borderRight: aBorder },
'ui-resizable-w': { cursor: 'w-resize', width: '4px', top: '0px', bottom: '0px', borderLeft: aBorder },
'ui-resizable-se': { cursor: 'se-resize', width: '4px', height: '4px', borderRight: aBorder, borderBottom: aBorder },
'ui-resizable-sw': { cursor: 'sw-resize', width: '4px', height: '4px', borderBottom: aBorder, borderLeft: aBorder },
'ui-resizable-ne': { cursor: 'ne-resize', width: '4px', height: '4px', borderRight: aBorder, borderTop: aBorder },
'ui-resizable-nw': { cursor: 'nw-resize', width: '4px', height: '4px', borderLeft: aBorder, borderTop: aBorder }
};
o.knobTheme = {
'ui-resizable-handle': { background: '#F2F2F2', border: '1px solid #808080', height: '8px', width: '8px' },
'ui-resizable-n': { cursor: 'n-resize', top: '0px', left: '45%' },
'ui-resizable-s': { cursor: 's-resize', bottom: '0px', left: '45%' },
'ui-resizable-e': { cursor: 'e-resize', right: '0px', top: '45%' },
'ui-resizable-w': { cursor: 'w-resize', left: '0px', top: '45%' },
'ui-resizable-se': { cursor: 'se-resize', right: '0px', bottom: '0px' },
'ui-resizable-sw': { cursor: 'sw-resize', left: '0px', bottom: '0px' },
'ui-resizable-nw': { cursor: 'nw-resize', left: '0px', top: '0px' },
'ui-resizable-ne': { cursor: 'ne-resize', right: '0px', top: '0px' }
};
o._nodeName = this.element[0].nodeName;
//Wrap the element if it cannot hold child nodes
if(o._nodeName.match(/canvas|textarea|input|select|button|img/i)) {
var el = this.element;
//Opera fixing relative position
if (/relative/.test(el.css('position')) && $.browser.opera)
el.css({ position: 'relative', top: 'auto', left: 'auto' });
//Create a wrapper element and set the wrapper to the new current internal element
el.wrap(
$('<div class="ui-wrapper" style="overflow: hidden;"></div>').css( {
position: el.css('position'),
width: el.outerWidth(),
height: el.outerHeight(),
top: el.css('top'),
left: el.css('left')
})
);
var oel = this.element; this.element = this.element.parent();
// store instance on wrapper
this.element.data('resizable', this);
//Move margins to the wrapper
this.element.css({ marginLeft: oel.css("marginLeft"), marginTop: oel.css("marginTop"),
marginRight: oel.css("marginRight"), marginBottom: oel.css("marginBottom")
});
oel.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
//Prevent Safari textarea resize
if ($.browser.safari && o.preventDefault) oel.css('resize', 'none');
o.proportionallyResize = oel.css({ position: 'static', zoom: 1, display: 'block' });
// avoid IE jump
this.element.css({ margin: oel.css('margin') });
// fix handlers offset
this._proportionallyResize();
}
if(!o.handles) o.handles = !$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' };
if(o.handles.constructor == String) {
o.zIndex = o.zIndex || 1000;
if(o.handles == 'all') o.handles = 'n,e,s,w,se,sw,ne,nw';
var n = o.handles.split(","); o.handles = {};
// insertions are applied when don't have theme loaded
var insertionsDefault = {
handle: 'position: absolute; display: none; overflow:hidden;',
n: 'top: 0pt; width:100%;',
e: 'right: 0pt; height:100%;',
s: 'bottom: 0pt; width:100%;',
w: 'left: 0pt; height:100%;',
se: 'bottom: 0pt; right: 0px;',
sw: 'bottom: 0pt; left: 0px;',
ne: 'top: 0pt; right: 0px;',
nw: 'top: 0pt; left: 0px;'
};
for(var i = 0; i < n.length; i++) {
var handle = $.trim(n[i]), dt = o.defaultTheme, hname = 'ui-resizable-'+handle, loadDefault = !$.ui.css(hname) && !o.knobHandles, userKnobClass = $.ui.css('ui-resizable-knob-handle'),
allDefTheme = $.extend(dt[hname], dt['ui-resizable-handle']), allKnobTheme = $.extend(o.knobTheme[hname], !userKnobClass ? o.knobTheme['ui-resizable-handle'] : {});
// increase zIndex of sw, se, ne, nw axis
var applyZIndex = /sw|se|ne|nw/.test(handle) ? { zIndex: ++o.zIndex } : {};
var defCss = (loadDefault ? insertionsDefault[handle] : ''),
axis = $(['<div class="ui-resizable-handle ', hname, '" style="', defCss, insertionsDefault.handle, '"></div>'].join('')).css( applyZIndex );
o.handles[handle] = '.ui-resizable-'+handle;
this.element.append(
//Theme detection, if not loaded, load o.defaultTheme
axis.css( loadDefault ? allDefTheme : {} )
// Load the knobHandle css, fix width, height, top, left...
.css( o.knobHandles ? allKnobTheme : {} ).addClass(o.knobHandles ? 'ui-resizable-knob-handle' : '').addClass(o.knobHandles)
);
}
if (o.knobHandles) this.element.addClass('ui-resizable-knob').css( !$.ui.css('ui-resizable-knob') ? { /*border: '1px #fff dashed'*/ } : {} );
}
this._renderAxis = function(target) {
target = target || this.element;
for(var i in o.handles) {
if(o.handles[i].constructor == String)
o.handles[i] = $(o.handles[i], this.element).show();
if (o.transparent)
o.handles[i].css({opacity:0});
//Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
if (this.element.is('.ui-wrapper') &&
o._nodeName.match(/textarea|input|select|button/i)) {
var axis = $(o.handles[i], this.element), padWrapper = 0;
//Checking the correct pad and border
padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
//The padding type i have to apply...
var padPos = [ 'padding',
/ne|nw|n/.test(i) ? 'Top' :
/se|sw|s/.test(i) ? 'Bottom' :
/^e$/.test(i) ? 'Right' : 'Left' ].join("");
if (!o.transparent)
target.css(padPos, padWrapper);
this._proportionallyResize();
}
if(!$(o.handles[i]).length) continue;
}
};
this._renderAxis(this.element);
o._handles = $('.ui-resizable-handle', self.element);
if (o.disableSelection)
o._handles.disableSelection();
//Matching axis name
o._handles.mouseover(function() {
if (!o.resizing) {
if (this.className)
var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
//Axis, default = se
self.axis = o.axis = axis && axis[1] ? axis[1] : 'se';
}
});
//If we want to auto hide the elements
if (o.autoHide) {
o._handles.hide();
$(self.element).addClass("ui-resizable-autohide").hover(function() {
$(this).removeClass("ui-resizable-autohide");
o._handles.show();
},
function(){
if (!o.resizing) {
$(this).addClass("ui-resizable-autohide");
o._handles.hide();
}
});
}
this._mouseInit();
},
destroy: function() {
var el = this.element, wrapped = el.children(".ui-resizable").get(0);
this._mouseDestroy();
var _destroy = function(exp) {
$(exp).removeClass("ui-resizable ui-resizable-disabled")
.removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
};
_destroy(el);
if (el.is('.ui-wrapper') && wrapped) {
el.parent().append(
$(wrapped).css({
position: el.css('position'),
width: el.outerWidth(),
height: el.outerHeight(),
top: el.css('top'),
left: el.css('left')
})
).end().remove();
_destroy(wrapped);
}
},
_mouseCapture: function(event) {
if(this.options.disabled) return false;
var handle = false;
for(var i in this.options.handles) {
if($(this.options.handles[i])[0] == event.target) handle = true;
}
if (!handle) return false;
return true;
},
_mouseStart: function(event) {
var o = this.options, iniPos = this.element.position(), el = this.element,
ie6 = $.browser.msie && $.browser.version < 7;
o.resizing = true;
o.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
// bugfix #1749
if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
// sOffset decides if document scrollOffset will be added to the top/left of the resizable element
var sOffset = $.browser.msie && !o.containment && (/absolute/).test(el.css('position')) && !(/relative/).test(el.parent().css('position'));
var dscrollt = sOffset ? this.documentScroll.top : 0, dscrolll = sOffset ? this.documentScroll.left : 0;
el.css({ position: 'absolute', top: (iniPos.top + dscrollt), left: (iniPos.left + dscrolll) });
}
//Opera fixing relative position
if ($.browser.opera && (/relative/).test(el.css('position')))
el.css({ position: 'relative', top: 'auto', left: 'auto' });
this._renderProxy();
var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
if (o.containment) {
curleft += $(o.containment).scrollLeft()||0;
curtop += $(o.containment).scrollTop()||0;
}
//Store needed variables
this.offset = this.helper.offset();
this.position = { left: curleft, top: curtop };
this.size = o.helper || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
this.originalSize = o.helper || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
this.originalPosition = { left: curleft, top: curtop };
this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
this.originalMousePosition = { left: event.pageX, top: event.pageY };
//Aspect Ratio
o.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height)||1);
if (o.preserveCursor) {
var cursor = $('.ui-resizable-' + this.axis).css('cursor');
$('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
}
this._propagate("start", event);
return true;
},
_mouseDrag: function(event) {
//Increase performance, avoid regex
var el = this.helper, o = this.options, props = {},
self = this, smp = this.originalMousePosition, a = this.axis;
var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
var trigger = this._change[a];
if (!trigger) return false;
// Calculate the attrs that will be change
var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
if (o._aspectRatio || event.shiftKey)
data = this._updateRatio(data, event);
data = this._respectSize(data, event);
// plugins callbacks need to be called first
this._propagate("resize", event);
el.css({
top: this.position.top + "px", left: this.position.left + "px",
width: this.size.width + "px", height: this.size.height + "px"
});
if (!o.helper && o.proportionallyResize)
this._proportionallyResize();
this._updateCache(data);
// calling the user callback at the end
this.element.triggerHandler("resize", [event, this.ui()], this.options["resize"]);
return false;
},
_mouseStop: function(event) {
this.options.resizing = false;
var o = this.options, self = this;
if(o.helper) {
var pr = o.proportionallyResize, ista = pr && (/textarea/i).test(pr.get(0).nodeName),
soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
soffsetw = ista ? 0 : self.sizeDiff.width;
var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
if (!o.animate)
this.element.css($.extend(s, { top: top, left: left }));
if (o.helper && !o.animate) this._proportionallyResize();
}
if (o.preserveCursor)
$('body').css('cursor', 'auto');
this._propagate("stop", event);
if (o.helper) this.helper.remove();
return false;
},
_updateCache: function(data) {
var o = this.options;
this.offset = this.helper.offset();
if (data.left) this.position.left = data.left;
if (data.top) this.position.top = data.top;
if (data.height) this.size.height = data.height;
if (data.width) this.size.width = data.width;
},
_updateRatio: function(data, event) {
var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
if (data.height) data.width = (csize.height * o.aspectRatio);
else if (data.width) data.height = (csize.width / o.aspectRatio);
if (a == 'sw') {
data.left = cpos.left + (csize.width - data.width);
data.top = null;
}
if (a == 'nw') {
data.top = cpos.top + (csize.height - data.height);
data.left = cpos.left + (csize.width - data.width);
}
return data;
},
_respectSize: function(data, event) {
var el = this.helper, o = this.options, pRatio = o._aspectRatio || event.shiftKey, a = this.axis,
ismaxw = data.width && o.maxWidth && o.maxWidth < data.width, ismaxh = data.height && o.maxHeight && o.maxHeight < data.height,
isminw = data.width && o.minWidth && o.minWidth > data.width, isminh = data.height && o.minHeight && o.minHeight > data.height;
if (isminw) data.width = o.minWidth;
if (isminh) data.height = o.minHeight;
if (ismaxw) data.width = o.maxWidth;
if (ismaxh) data.height = o.maxHeight;
var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
if (isminw && cw) data.left = dw - o.minWidth;
if (ismaxw && cw) data.left = dw - o.maxWidth;
if (isminh && ch) data.top = dh - o.minHeight;
if (ismaxh && ch) data.top = dh - o.maxHeight;
// fixing jump error on top/left - bug #2330
var isNotwh = !data.width && !data.height;
if (isNotwh && !data.left && data.top) data.top = null;
else if (isNotwh && !data.top && data.left) data.left = null;
return data;
},
_proportionallyResize: function() {
var o = this.options;
if (!o.proportionallyResize) return;
var prel = o.proportionallyResize, el = this.helper || this.element;
if (!o.borderDif) {
var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
o.borderDif = $.map(b, function(v, i) {
var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
return border + padding;
});
}
prel.css({
height: (el.height() - o.borderDif[0] - o.borderDif[2]) + "px",
width: (el.width() - o.borderDif[1] - o.borderDif[3]) + "px"
});
},
_renderProxy: function() {
var el = this.element, o = this.options;
this.elementOffset = el.offset();
if(o.helper) {
this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
// fix ie6 offset
var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
pxyoffset = ( ie6 ? 2 : -1 );
this.helper.addClass(o.helper).css({
width: el.outerWidth() + pxyoffset,
height: el.outerHeight() + pxyoffset,
position: 'absolute',
left: this.elementOffset.left - ie6offset +'px',
top: this.elementOffset.top - ie6offset +'px',
zIndex: ++o.zIndex
});
this.helper.appendTo("body");
if (o.disableSelection)
this.helper.disableSelection();
} else {
this.helper = el;
}
},
_change: {
e: function(event, dx, dy) {
return { width: this.originalSize.width + dx };
},
w: function(event, dx, dy) {
var o = this.options, cs = this.originalSize, sp = this.originalPosition;
return { left: sp.left + dx, width: cs.width - dx };
},
n: function(event, dx, dy) {
var o = this.options, cs = this.originalSize, sp = this.originalPosition;
return { top: sp.top + dy, height: cs.height - dy };
},
s: function(event, dx, dy) {
return { height: this.originalSize.height + dy };
},
se: function(event, dx, dy) {
return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
},
sw: function(event, dx, dy) {
return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
},
ne: function(event, dx, dy) {
return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
},
nw: function(event, dx, dy) {
return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
}
},
_propagate: function(n, event) {
$.ui.plugin.call(this, n, [event, this.ui()]);
if (n != "resize") this.element.triggerHandler(["resize", n].join(""), [event, this.ui()], this.options[n]);
},
plugins: {},
ui: function() {
return {
originalElement: this.originalElement,
element: this.element,
helper: this.helper,
position: this.position,
size: this.size,
options: this.options,
originalSize: this.originalSize,
originalPosition: this.originalPosition
};
}
}));
$.extend($.ui.resizable, {
version: "1.6",
defaults: {
alsoResize: false,
animate: false,
animateDuration: "slow",
animateEasing: "swing",
aspectRatio: false,
autoHide: false,
cancel: ":input",
containment: false,
disableSelection: true,
distance: 1,
delay: 0,
ghost: false,
grid: false,
knobHandles: false,
maxHeight: null,
maxWidth: null,
minHeight: 10,
minWidth: 10,
preserveCursor: true,
preventDefault: true,
proportionallyResize: false,
transparent: false
}
});
/*
* Resizable Extensions
*/
$.ui.plugin.add("resizable", "alsoResize", {
start: function(event, ui) {
var o = ui.options, self = $(this).data("resizable"),
_store = function(exp) {
$(exp).each(function() {
$(this).data("resizable-alsoresize", {
width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10)
});
});
};
if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); }
}else{
_store(o.alsoResize);
}
},
resize: function(event, ui){
var o = ui.options, self = $(this).data("resizable"), os = self.originalSize, op = self.originalPosition;
var delta = {
height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
},
_alsoResize = function(exp, c) {
$(exp).each(function() {
var start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left'];
$.each(css || ['width', 'height', 'top', 'left'], function(i, prop) {
var sum = (start[prop]||0) + (delta[prop]||0);
if (sum && sum >= 0)
style[prop] = sum || null;
});
$(this).css(style);
});
};
if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
$.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); });
}else{
_alsoResize(o.alsoResize);
}
},
stop: function(event, ui){
$(this).removeData("resizable-alsoresize-start");
}
});
$.ui.plugin.add("resizable", "animate", {
stop: function(event, ui) {
var o = ui.options, self = $(this).data("resizable");
var pr = o.proportionallyResize, ista = pr && (/textarea/i).test(pr.get(0).nodeName),
soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
soffsetw = ista ? 0 : self.sizeDiff.width;
var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
self.element.animate(
$.extend(style, top && left ? { top: top, left: left } : {}), {
duration: o.animateDuration,
easing: o.animateEasing,
step: function() {
var data = {
width: parseInt(self.element.css('width'), 10),
height: parseInt(self.element.css('height'), 10),
top: parseInt(self.element.css('top'), 10),
left: parseInt(self.element.css('left'), 10)
};
if (pr) pr.css({ width: data.width, height: data.height });
// propagating resize, and updating values for each animation step
self._updateCache(data);
self._propagate("animate", event);
}
}
);
}
});
$.ui.plugin.add("resizable", "containment", {
start: function(event, ui) {
var o = ui.options, self = $(this).data("resizable"), el = self.element;
var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
if (!ce) return;
self.containerElement = $(ce);
if (/document/.test(oc) || oc == document) {
self.containerOffset = { left: 0, top: 0 };
self.containerPosition = { left: 0, top: 0 };
self.parentData = {
element: $(document), left: 0, top: 0,
width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
};
}
// i'm a node, so compute top, left, right, bottom
else{
var element = $(ce), p = [];
$([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
self.containerOffset = element.offset();
self.containerPosition = element.position();
self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
self.parentData = {
element: ce, left: co.left, top: co.top, width: width, height: height
};
}
},
resize: function(event, ui) {
var o = ui.options, self = $(this).data("resizable"),
ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
pRatio = o._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;
if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
if (cp.left < (o.helper ? co.left : 0)) {
self.size.width = self.size.width + (o.helper ? (self.position.left - co.left) : (self.position.left - cop.left));
if (pRatio) self.size.height = self.size.width / o.aspectRatio;
self.position.left = o.helper ? co.left : 0;
}
if (cp.top < (o.helper ? co.top : 0)) {
self.size.height = self.size.height + (o.helper ? (self.position.top - co.top) : self.position.top);
if (pRatio) self.size.width = self.size.height * o.aspectRatio;
self.position.top = o.helper ? co.top : 0;
}
self.offset.left = self.parentData.left+self.position.left;
self.offset.top = self.parentData.top+self.position.top;
var woset = Math.abs( (o.helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
hoset = Math.abs( (o.helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );
var isParent = self.containerElement.get(0) == self.element.parent().get(0),
isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));
if(isParent && isOffsetRelative) woset -= self.parentData.left;
if (woset + self.size.width >= self.parentData.width) {
self.size.width = self.parentData.width - woset;
if (pRatio) self.size.height = self.size.width / o.aspectRatio;
}
if (hoset + self.size.height >= self.parentData.height) {
self.size.height = self.parentData.height - hoset;
if (pRatio) self.size.width = self.size.height * o.aspectRatio;
}
},
stop: function(event, ui){
var o = ui.options, self = $(this).data("resizable"), cp = self.position,
co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
if (o.helper && !o.animate && (/relative/).test(ce.css('position')))
$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
if (o.helper && !o.animate && (/static/).test(ce.css('position')))
$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
}
});
$.ui.plugin.add("resizable", "ghost", {
start: function(event, ui) {
var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize, cs = self.size;
if (!pr) self.ghost = self.element.clone();
else self.ghost = pr.clone();
self.ghost.css(
{ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }
)
.addClass('ui-resizable-ghost').addClass(typeof o.ghost == 'string' ? o.ghost : '');
self.ghost.appendTo(self.helper);
},
resize: function(event, ui){
var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize;
if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
},
stop: function(event, ui){
var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize;
if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
}
});
$.ui.plugin.add("resizable", "grid", {
resize: function(event, ui) {
var o = ui.options, self = $(this).data("resizable"), cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;
o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
if (/^(se|s|e)$/.test(a)) {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
}
else if (/^(ne)$/.test(a)) {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
self.position.top = op.top - oy;
}
else if (/^(sw)$/.test(a)) {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
self.position.left = op.left - ox;
}
else {
self.size.width = os.width + ox;
self.size.height = os.height + oy;
self.position.top = op.top - oy;
self.position.left = op.left - ox;
}
}
});
var num = function(v) {
return parseInt(v, 10) || 0;
};
})(jQuery);

104
tests/loader.js Executable file
View File

@ -0,0 +1,104 @@
var _origVars = [];
for (var _prop in window) {
_origVars.push(_prop);
}
function varLeaks() {
for (var prop in window) {
var found = false;
for (var i=0; i<_origVars.length; i++) {
if (prop == _origVars[i]) {
found = true;
break;
}
}
if (!found) {
console.log(prop);
}
}
}
var m = window.location.href.match(/\?(.*)$/);
var queryString = m ? m[1] : '';
function queryStringParam(name) {
m = queryString.match(new RegExp("(?:^|&)"+name+"(?:=([^&]))?"));
if (m) {
if (m[1]) return m[1];
return true;
}
}
function includeJS(src) {
document.write("<script type='text/javascript' src='" + src + "'><\/script>");
}
function includeCSS(href) {
document.write("<link rel='stylesheet' type='text/css' href='" + href + "' />");
}
var _build = queryStringParam('build');
var _minified = queryStringParam('minified');
var _legacy = queryStringParam('legacy');
if (_build) {
includeCSS('../build/fullcalendar/fullcalendar.css');
}else{
includeCSS('../src/css/main.css');
includeCSS('../src/css/grid.css');
}
if (_legacy) {
includeJS('jquery-legacy/jquery.js');
includeJS('jquery-legacy/ui.core.js');
includeJS('jquery-legacy/ui.draggable.js');
includeJS('jquery-legacy/ui.resizable.js');
}
else if (_build) {
includeJS('../build/fullcalendar/jquery/jquery.js');
includeJS('../build/fullcalendar/jquery/ui.core.js');
includeJS('../build/fullcalendar/jquery/ui.draggable.js');
includeJS('../build/fullcalendar/jquery/ui.resizable.js');
}
else {
includeJS('../src/jquery/jquery.js');
includeJS('../src/jquery/ui.core.js');
includeJS('../src/jquery/ui.draggable.js');
includeJS('../src/jquery/ui.resizable.js');
}
if (_build) {
if (_minified) {
includeJS('../build/fullcalendar/fullcalendar.min.js');
}else{
includeJS('../build/fullcalendar/fullcalendar.js');
}
includeJS('../build/fullcalendar/gcal.js');
}else{
includeJS('../src/main.js');
includeJS('../src/grid.js');
includeJS('../src/view.js');
includeJS('../src/util.js');
includeJS('../src/gcal.js');
}
includeJS('firebug-lite/firebug-lite-compressed.js');
window.onload = function() {
$('body').append(
"<form style='position:absolute;top:0;right:0;text-align:right;font-size:10px;color:#666'>" +
"<label for='build'>build</label> " +
"<input type='checkbox' id='build' name='build'" + (_build ? " checked='checked'" : '') +
" style='vertical-align:middle' onclick='$(this).parent().submit()' />" +
"<br />" +
"<label for='minified'>minified</label> " +
"<input type='checkbox' id='minified' name='minified'" + (_minified ? " checked='checked'" : '') +
" style='vertical-align:middle' onclick='$(this).parent().submit()' />" +
"<br />" +
"<label for='legacy'>legacy</label> " +
"<input type='checkbox' id='legacy' name='legacy'" + (_legacy ? " checked='checked'" : '') +
" style='vertical-align:middle' onclick='$(this).parent().submit()' />" +
"</form>"
);
};

111
tests/locale.html Normal file
View File

@ -0,0 +1,111 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
center: 'month,basicWeek,basicDay'
},
editable: true,
isRTL: true,
firstDay: 1,
monthNames: ["januari", "februari", "maart", "april", "mei", "juni","juli", "augustus", "september", "oktober", "november", "december"],
monthNamesShort: ["jan", "feb", "maa", "apr", "mei", "jun", "jul", "aug","sep", "okt", "nov", "dec"],
dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag','donderdag', 'vrijdag', 'zaterdag'],
dayNamesShort: ["zo", "ma", "di", "wo", "do", "vr", "za", "zo"],
timeFormat: 'H(:mm)t',
weekMode: 'variable',
// TODO: add drag & resize tests
dayClick: function(dayDate, view) {
console.log('dayClick - ' + dayDate + ' - ' + view.title);
},
eventDrop: function(event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view) {
console.log('DROP ' + event.title);
console.log(dayDelta + ' days');
console.log(event.start);
//console.log(minuteDelta + ' minutes');
},
eventResize: function(event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view) {
console.log('RESIZE!! ' + event.title);
console.log(dayDelta + ' days');
console.log(event.end);
//console.log(minuteDelta + ' minutes');
},
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 10)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 20, 10, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://facebook.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
]
});
});
</script>
</head>
<body style='font-size:12px'>
<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

168
tests/methods.html Normal file
View File

@ -0,0 +1,168 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var cal;
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
var staticEvents;
$(document).ready(function() {
cal = $('#calendar').fullCalendar({
editable: true,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
loading: function(bool) {
if (bool) {
$('#loading').show();
}else{
$('#loading').hide();
}
},
events: staticEvents = [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 10)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 21, 0, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://facebook.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
]
});
});
function updateEventStart() {
var event = cal.fullCalendar('clientEvents', 3)[0];
event.start = new Date(y, m, 25, 10, 30);
event.end = new Date(y, m, 26);
//event.allDay = true;
cal.fullCalendar('updateEvent', event);
}
function updateRepeatingEvent() {
var event = cal.fullCalendar('clientEvents', 2)[0];
event.start = new Date(y, m, 4, 13, 30);
event.end = new Date(y, m, 5, 2, 0);
event.allDay = false;
event.title = "repeat yo";
//event.editable = false;
event.url = "http://google.com/";
cal.fullCalendar('updateEvent', event);
//console.log(cal.fullCalendar('clientEvents', 2));
}
function renderEvent(stick) {
cal.fullCalendar('renderEvent', {
start: new Date(y, m, 16),
title: 'heyman'
}, stick);
}
var gcalFeed = $.fullCalendar.gcalFeed("http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic");
var jsonFeed = "../examples/json-events.php";
</script>
<style>
button {
font-size: 11px;
}
</style>
</head>
<body style='font-size:12px'>
<p>
<button onclick="cal.fullCalendar('prev')">prev</button>
<button onclick="cal.fullCalendar('next')">next</button>
<button onclick="cal.fullCalendar('today')">today</button>
<button onclick="cal.fullCalendar('gotoDate', 1999, 9, 31)">Oct 31 1999</button>
<button onclick="cal.fullCalendar('gotoDate', new Date(1999, 9, 30))">Oct 30 1999 (Date)</button>
<button onclick="cal.fullCalendar('incrementDate', 1, 1, 1)">+1 +1 +1</button>
<button onclick="cal.fullCalendar('incrementDate', -1, -1, -1)">-1 -1 -1</button>
<button onclick="updateEventStart()">update event start</button>
<button onclick="updateRepeatingEvent()">update repeating event</button>
<button onclick="renderEvent(false)">render new event</button>
<button onclick="renderEvent(true)">render new sticky event</button>
<br />
<button onclick="cal.fullCalendar('removeEvents')">remove all</button>
<button onclick="cal.fullCalendar('removeEvents', 2)">remove repeating events</button>
<button onclick="cal.fullCalendar('removeEvents', function(e){return !e.allDay})">remove timed events</button>
<button onclick="console.log(cal.fullCalendar('clientEvents'))">log events</button>
<button onclick="console.log(cal.fullCalendar('clientEvents', '2'))">log repeating events</button>
<button onclick="console.log(cal.fullCalendar('clientEvents', function(e){return e.allDay}))">log all-day events</button>
<br />
<button onclick="cal.fullCalendar('addEventSource', staticEvents)">+ static events</button>
<button onclick="cal.fullCalendar('removeEventSource', staticEvents)">- static events</button>
<button onclick="cal.fullCalendar('addEventSource', gcalFeed)">+ gcal</button>
<button onclick="cal.fullCalendar('removeEventSource', gcalFeed)">- gcal</button>
<button onclick="cal.fullCalendar('addEventSource', jsonFeed)">+ json</button>
<button onclick="cal.fullCalendar('removeEventSource', jsonFeed)">- json</button>
<button onclick="cal.fullCalendar('rerenderEvents')">rerender</button>
<button onclick="cal.fullCalendar('refetchEvents')">refetch</button>
<br />
<button onclick="cal.fullCalendar('changeView', 'month')">change to month</button>
<button onclick="cal.fullCalendar('changeView', 'basicWeek')">change to basicWeek</button>
<button onclick="cal.fullCalendar('changeView', 'basicDay')">change to basicDay</button>
<button onclick="cal.fullCalendar('render')">render</button>
</p>
<div id='loading' style='position:absolute;display:none'>loading...</div>
<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

112
tests/options.html Normal file
View File

@ -0,0 +1,112 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$(document).ready(function() {
$('#calendar').fullCalendar({
/*
year: 2010,
month: 0,
date: 0,
defaultView: 'basicDay',
aspectRatio: 1,
*/
header: {
left: 'title',
center: 'prev,month,basicWeek,basicDay,next',
right: 'today'
},
editable: true,
//disableDragging: true,
//disableResizing: true,
dragOpacity: .5,
dragRevertDuration: 100,
weekMode: 'variable',
//allDayDefault: false,
/*
titleFormat: {
month: "'hey!'"
},
*/
columnFormat: {
month: "dddd"
},
timeFormat: "h(:mm)[T]{ - h(:mm)T}",
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 10)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 20, 10, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://facebook.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
]
});
});
</script>
</head>
<body style='font-size:12px'>
<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

144
tests/sources.html Normal file
View File

@ -0,0 +1,144 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var cal;
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
var gcalFeed = $.fullCalendar.gcalFeed("http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic");
var jsonFeed = "../examples/json-events.php";
var staticEvents = [
{
id: 1,
title: "Long Event",
date: new Date(y, m, 6), //!
end: new Date(y, m, 10),
className: 'red-event'
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 21, 0, 0),
allDay: false,
//className: 'yellow-event black-text-event',
className: ['yellow-event', 'black-text-event'],
editable: true
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://facebook.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
];
var customSource = function(start, end, callback) {
callback([
{
title: 'FIRST',
start: start
},
{
title: 'LAST',
start: new Date(end - 1)
}
]);
};
$(document).ready(function() {
cal = $('#calendar').fullCalendar({
editable: true,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
//events: staticEvents,
eventSources: [
staticEvents,
jsonFeed,
gcalFeed,
customSource
],
loading: function(bool) {
if (bool) {
$('#loading').show();
}else{
$('#loading').hide();
}
}
/*
,
startParam: 'mystart',
endParam: 'myend',
cacheParam: 'uniq'
*/
});
});
</script>
<style>
.red-event a {
background: red;
}
.yellow-event a {
background: yellow;
}
.black-text-event a {
color: #000;
}
button {
font-size: 11px;
}
</style>
</head>
<body style='font-size:12px'>
<div id='loading' style='position:absolute;top:0;left:0;display:none'>loading...</div>
<p>
<button onclick="cal.fullCalendar('refetchEvents')">refetch</button>
</p>
<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

89
tests/theming.html Executable file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$(document).ready(function() {
$('#calendar').fullCalendar({
theme: true,
editable: true,
//isRTL: true,
header: {
center: 'month,basicWeek,basicDay'
},
buttonIcons: {
prev: 'triangle-1-w',
next: 'triangle-1-e',
today: 'home'
},
events: [
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 10)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 20, 10, 0),
allDay: false
},
{
id: 4,
title: "Click for Facebook",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://facebook.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
]
});
});
</script>
</head>
<body style='font-size:12px'>
<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

186
tests/triggers.html Executable file
View File

@ -0,0 +1,186 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
editable: true,
weekMode: 'variable',
viewDisplay: function(view) {
console.log('viewDisplay');
//console.log(view);
//console.log(this);
},
//loading: // see sources.html
windowResize: function(view) {
console.log('windowResize - ' + view.title);
//console.log(this);
},
dayClick: function(dayDate, view) {
console.log('dayClick - ' + dayDate + ' - ' + view.title);
//console.log(this);
},
eventRender: function(event, element, view) {
if (event.id == 555) {
return false;
}
else if (event.id == 666) {
return $("<div style='background:green'/>").text(event.title);
}
else if (event.id == 1) {
element.css('border-color', 'red');
//console.log('renderEvent (' + event.title + ') - ' + view.title);
}
},
eventClick: function(event, jsEvent, view) {
console.log('EVENT CLICK ' + event.title);
//console.log(jsEvent);
//console.log(view);
//console.log(this);
//return false;
},
/*
eventMouseover: function(event, jsEvent, view) {
console.log('MOUSEOVER ' + event.title);
console.log(jsEvent);
console.log(view);
console.log(this);
},
eventMouseout: function(event, jsEvent, view) {
console.log('MOUSEOUT ' + event.title);
console.log(jsEvent);
console.log(view);
console.log(this);
},
*/
eventDragStart: function(event, jsEvent, ui, view) {
console.log('DRAG START ' + event.title);
//console.log(this);
},
eventDragStop: function(event, jsEvent, ui, view) {
console.log('DRAG STOP ' + event.title);
//console.log(this);
},
eventDrop: function(event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view) {
console.log('DROP ' + event.title);
console.log(dayDelta + ' days');
console.log(minuteDelta + ' minutes');
/*setTimeout(function() {
revertFunc();
}, 2000);*/
//console.log(jsEvent);
//console.log(ui);
//console.log(view.title);
//console.log(this);
},
eventResizeStart: function(event, jsEvent, ui, view) {
console.log('RESIZE START ' + event.title);
//console.log(this);
},
eventResizeStop: function(event, jsEvent, ui, view) {
console.log('RESIZE STOP ' + event.title);
//console.log(this);
},
eventResize: function(event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view) {
console.log('RESIZE!! ' + event.title);
console.log(dayDelta + ' days');
console.log(minuteDelta + ' minutes');
/*setTimeout(function() {
revertFunc();
}, 2000);*/
//console.log(jsEvent);
//console.log(ui);
//console.log(view.title);
//console.log(this);
},
events: [
{
id: 555,
title: "Rejected Event",
start: new Date(y, m, 5)
},
{
id: 666,
title: "Homemade Elm Event",
start: new Date(y, m, 6)
},
{
id: 1,
title: "Long Event",
start: new Date(y, m, 6),
end: new Date(y, m, 10)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 2)
},
{
id: 2,
title: "Repeating",
start: new Date(y, m, 9),
end: new Date(y, m, 10)
},
{
id: 3,
title: "Meeting",
start: new Date(y, m, 20, 9, 0),
end: new Date(y, m, 20, 10, 0),
allDay: false
},
{
id: 4,
title: "Click for Google",
start: new Date(y, m, 27),
end: new Date(y, m, 28),
url: "http://google.com/"
},
{
id: 5,
title: "timed event1",
start: new Date (y, m, 31, 17, 30),
allDay: false
},
{
id: 6,
title: "timed event1",
start: new Date (y, m+1, 2, 14, 15),
allDay: false
},
{
id: 7,
title: "timed event1",
start: new Date (y, m+1, 4, 15, 00),
end: new Date(y, m+1, 4, 17, 00),
allDay: false
}
]
});
});
</script>
</head>
<body style='font-size:12px'>
<div id='calendar' style='width:75%;margin:20px auto 0;font-family:arial'></div>
</body>
</html>

View File

@ -1 +1 @@
1.0
1.3.2