Ver código fonte

merged refactor148, resolved conflicts

Adam Shaw 15 anos atrás
pai
commit
1d93c56700
100 arquivos alterados com 4990 adições e 5120 exclusões
  1. 76 50
      Makefile
  2. 1 0
      build/externs.js
  3. 7 21
      demos/agenda-views.html
  4. 7 21
      demos/basic-views.html
  5. 7 21
      demos/default.html
  6. 7 21
      demos/external-dragging.html
  7. 67 0
      demos/gcal.html
  8. 0 0
      demos/json-events.php
  9. 63 0
      demos/json.html
  10. 0 0
      demos/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png
  11. BIN
      demos/redmond/images/ui-bg_flat_55_fbec88_40x100.png
  12. 0 0
      demos/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png
  13. 0 0
      demos/redmond/images/ui-bg_glass_85_dfeffc_1x400.png
  14. 0 0
      demos/redmond/images/ui-bg_glass_95_fef1ec_1x400.png
  15. 0 0
      demos/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png
  16. 0 0
      demos/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png
  17. 0 0
      demos/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png
  18. BIN
      demos/redmond/images/ui-icons_217bc0_256x240.png
  19. BIN
      demos/redmond/images/ui-icons_2e83ff_256x240.png
  20. BIN
      demos/redmond/images/ui-icons_469bdd_256x240.png
  21. BIN
      demos/redmond/images/ui-icons_6da8d5_256x240.png
  22. BIN
      demos/redmond/images/ui-icons_cd0a0a_256x240.png
  23. BIN
      demos/redmond/images/ui-icons_d8e7f3_256x240.png
  24. BIN
      demos/redmond/images/ui-icons_f9bd01_256x240.png
  25. 73 148
      demos/redmond/theme.css
  26. 7 21
      demos/selectable.html
  27. 7 21
      demos/theme.html
  28. 0 79
      examples/gcal.html
  29. 0 77
      examples/json.html
  30. BIN
      examples/redmond/images/ui-bg_flat_55_fbec88_40x100.png
  31. BIN
      examples/redmond/images/ui-icons_f9bd01_256x240.png
  32. 0 0
      lib/jquery-1.3.2.min.js
  33. 0 0
      lib/jquery-1.4.2.min.js
  34. 0 0
      lib/jquery-ui-1.7.3.custom.min.js
  35. 65 63
      lib/jquery-ui-1.8.4.custom.min.js
  36. 480 0
      src/Calendar.js
  37. 288 0
      src/EventManager.js
  38. 164 0
      src/Header.js
  39. 132 0
      src/_loader.js
  40. 0 1262
      src/agenda.js
  41. 36 0
      src/agenda/AgendaDayView.js
  42. 595 0
      src/agenda/AgendaEventRenderer.js
  43. 716 0
      src/agenda/AgendaView.js
  44. 46 0
      src/agenda/AgendaWeekView.js
  45. 0 0
      src/agenda/agenda.css
  46. 37 0
      src/basic/BasicDayView.js
  47. 149 0
      src/basic/BasicEventRenderer.js
  48. 453 0
      src/basic/BasicView.js
  49. 46 0
      src/basic/BasicWeekView.js
  50. 52 0
      src/basic/MonthView.js
  51. 0 0
      src/basic/basic.css
  52. 43 0
      src/common/CoordinateGrid.js
  53. 232 0
      src/common/DayEventRenderer.js
  54. 27 0
      src/common/HorizontalPositionCache.js
  55. 44 0
      src/common/HoverListener.js
  56. 37 0
      src/common/OverlayManager.js
  57. 98 0
      src/common/SelectionManager.js
  58. 213 0
      src/common/View.js
  59. 129 0
      src/common/common.css
  60. 41 294
      src/common/date.js
  61. 285 0
      src/common/util.js
  62. 93 0
      src/defaults.js
  63. 6 0
      src/gcal/_loader.js
  64. 3 4
      src/gcal/gcal.js
  65. 0 792
      src/grid.js
  66. 19 0
      src/intro.js
  67. 3 126
      src/main.css
  68. 26 877
      src/main.js
  69. 0 20
      src/misc/head.txt
  70. 0 0
      src/outro.js
  71. 0 45
      src/selection_util.js
  72. 0 375
      src/view.js
  73. 2 3
      tests/dbclick.html
  74. 2 3
      tests/droppable.html
  75. 2 3
      tests/fullheight.html
  76. 3 2
      tests/gcal.html
  77. 20 22
      tests/iframe.html
  78. 2 3
      tests/issue_206_parseDate_dst.html
  79. 2 3
      tests/issue_220_buttons_ie6.html
  80. 2 1
      tests/issue_221_quick_remove_source.html
  81. 6 7
      tests/issue_230_height_json_events.html
  82. 2 3
      tests/issue_244_aspectRatio_0.html
  83. 2 3
      tests/issue_251_empty_end_date.html
  84. 2 2
      tests/issue_333_blinking.html
  85. 59 0
      tests/issue_417_refetchEvents.html
  86. 2 3
      tests/issue_429_gotoDate.html
  87. 2 3
      tests/issue_477_event_width.html
  88. 0 721
      tests/jquery-ui/jquery.ui.tabs.js
  89. 0 0
      tests/lib/fancybox/fancy_closebox.png
  90. 0 0
      tests/lib/fancybox/fancy_left.png
  91. 0 0
      tests/lib/fancybox/fancy_progress.png
  92. 0 0
      tests/lib/fancybox/fancy_right.png
  93. 0 0
      tests/lib/fancybox/fancy_shadow_e.png
  94. 0 0
      tests/lib/fancybox/fancy_shadow_n.png
  95. 0 0
      tests/lib/fancybox/fancy_shadow_ne.png
  96. 0 0
      tests/lib/fancybox/fancy_shadow_nw.png
  97. 0 0
      tests/lib/fancybox/fancy_shadow_s.png
  98. 0 0
      tests/lib/fancybox/fancy_shadow_se.png
  99. 0 0
      tests/lib/fancybox/fancy_shadow_sw.png
  100. 0 0
      tests/lib/fancybox/fancy_shadow_w.png

+ 76 - 50
Makefile

@@ -1,69 +1,95 @@
 
 
 SRC_DIR = src
 SRC_DIR = src
-EXAMPLES_DIR = examples
 BUILD_DIR = build
 BUILD_DIR = build
 DIST_DIR = dist
 DIST_DIR = dist
-
-JS_SRC_FILES = \
-	${SRC_DIR}/main.js \
-	${SRC_DIR}/grid.js \
-	${SRC_DIR}/agenda.js \
-	${SRC_DIR}/view.js \
-	${SRC_DIR}/selection_util.js \
-	${SRC_DIR}/util.js
-	
-CSS_SRC_FILES = \
-	${SRC_DIR}/css/main.css \
-	${SRC_DIR}/css/grid.css \
-	${SRC_DIR}/css/agenda.css
-
+DEMOS_DIR = demos
 OTHER_FILES = \
 OTHER_FILES = \
-	${SRC_DIR}/jquery \
-	changelog.txt
-	
-VER = `cat version.txt`
+	changelog.txt \
+	MIT-LICENSE.txt \
+	GPL-LICENSE.txt
+
+VER = $$(cat version.txt)
 VER_SED = sed s/@VERSION/"${VER}"/
 VER_SED = sed s/@VERSION/"${VER}"/
-DATE = `git log -1 | grep Date: | sed 's/[^:]*: *//'`
+DATE = $$(git log -1 --pretty=format:%ad)
 DATE_SED = sed s/@DATE/"${DATE}"/
 DATE_SED = sed s/@DATE/"${DATE}"/
 
 
+JQ = $$(sed -n "s/.*JQUERY\s*=\s*[\"']\(.*\)[\"'].*/\1/p" "${SRC_DIR}/_loader.js")
+JQUI = $$(sed -n "s/.*JQUERY_UI\s*=\s*[\"']\(.*\)[\"'].*/\1/p" "${SRC_DIR}/_loader.js")
+
+DEMO_FILES = $$(cd ${DEMOS_DIR}; find . -mindepth 1 -maxdepth 1 -type f)
+DEMO_SUBDIRS = $$(cd ${DEMOS_DIR}; find . -mindepth 1 -maxdepth 1 -type d)
+DEMO_RE = \(<script[^>]*_loader\.js[^>]*><\/script>\|<!--\[\[\|\]\]-->\)\s*
+DEMO_SED = sed -n "1h;1!H;\$${;g;s/${DEMO_RE}//g;p;}"
+
+JS_SED = sed -n "s/\s*js([\"']\(.*\)[\"']).*/\1/p"
+CSS_SED = sed -n "s/\s*css([\"']\(.*\)[\"']).*/\1/p"
+
+concat_js = \
+	files=$$(cat "$(1)/_loader.js" | ${JS_SED}); \
+	if [ -f "$(1)/intro.js" ]; then \
+		files="intro.js $$files"; \
+	fi; \
+	if [ -f "$(1)/outro.js" ]; then \
+		files="$$files outro.js"; \
+	fi; \
+	old=$$PWD; \
+	(cd "$(1)"; cat $$files; cd "$$old") \
+		| ${VER_SED} \
+		| ${DATE_SED} \
+		> "$(2)"
+	
+concat_css = \
+	files=$$(cat "$(1)/_loader.js" | ${CSS_SED}); \
+	if [ "$$files" ]; then \
+		old=$$PWD; \
+		(cd "$(1)"; cat $$files; cd "$$old") \
+			| ${VER_SED} \
+			| ${DATE_SED} \
+			> "$(2)"; \
+	fi
+	
 zip:
 zip:
 	@rm -rf ${BUILD_DIR}/fullcalendar
 	@rm -rf ${BUILD_DIR}/fullcalendar
 	@rm -rf ${BUILD_DIR}/fullcalendar-*
 	@rm -rf ${BUILD_DIR}/fullcalendar-*
-	@mkdir -p ${BUILD_DIR}/fullcalendar
+	@mkdir -p ${BUILD_DIR}/fullcalendar/fullcalendar/
 	
 	
-	@echo "building js..."
-	@cat ${SRC_DIR}/misc/head.txt ${JS_SRC_FILES} ${SRC_DIR}/misc/foot.txt \
-		| ${VER_SED} | ${DATE_SED} \
-		> ${BUILD_DIR}/fullcalendar/fullcalendar.js
-	@cat ${SRC_DIR}/gcal.js \
-		| ${VER_SED} | ${DATE_SED} \
-		> ${BUILD_DIR}/fullcalendar/gcal.js
-		
-	@echo "compressing js..."
-	@java -jar ${BUILD_DIR}/compiler.jar --js ${BUILD_DIR}/fullcalendar/fullcalendar.js \
-		> ${BUILD_DIR}/fullcalendar/fullcalendar.min.js
-		
-	@echo "building css..."
-	@cat ${CSS_SRC_FILES} \
-		| ${VER_SED} | ${DATE_SED} \
-		> ${BUILD_DIR}/fullcalendar/fullcalendar.css
+	@echo "building core..."
+	@$(call concat_js,${SRC_DIR},"${BUILD_DIR}/fullcalendar/fullcalendar/fullcalendar.js")
+	@$(call concat_css,${SRC_DIR},"${BUILD_DIR}/fullcalendar/fullcalendar/fullcalendar.css")
+	
+	@echo "compressing core js..."
+	@java -jar ${BUILD_DIR}/compiler.jar --warning_level VERBOSE --jscomp_off checkTypes --externs build/externs.js \
+		--js ${BUILD_DIR}/fullcalendar/fullcalendar/fullcalendar.js \
+		> ${BUILD_DIR}/fullcalendar/fullcalendar/fullcalendar.min.js; \
 		
 		
-	@echo "building examples..."
-	@mkdir -p ${BUILD_DIR}/fullcalendar/examples
-	@for f in `cd ${EXAMPLES_DIR}; find . -mindepth 1 -maxdepth 1 -type f`; do \
-		cat ${EXAMPLES_DIR}/$$f \
-			| sed -n '1h;1!H;$${;g;s/<!--\s*<src>.*<\/src>\s*-->\s*//g;p;}' \
-			| sed -n '1h;1!H;$${;g;s/<!--\s*<dist>\s*//g;p;}' \
-			| sed -n '1h;1!H;$${;g;s/<\/dist>\s*-->\s*//g;p;}' \
-			> ${BUILD_DIR}/fullcalendar/examples/$$f; \
+	@echo "building plugins..."
+	@for loader in ${SRC_DIR}/*/_loader.js; do \
+		dir=`dirname $$loader`; \
+		name=`basename $$dir`; \
+		$(call concat_js,$$dir,"${BUILD_DIR}/fullcalendar/fullcalendar/$$name.js"); \
+	done
+	
+	@echo "copying jquery..."
+	@mkdir -p ${BUILD_DIR}/fullcalendar/jquery
+	@cp lib/${JQ} ${BUILD_DIR}/fullcalendar/jquery
+	@cp lib/${JQUI} ${BUILD_DIR}/fullcalendar/jquery
+	
+	@echo "building demos..."
+	@mkdir -p ${BUILD_DIR}/fullcalendar/demos
+	@for f in ${DEMO_FILES}; do \
+		cat ${DEMOS_DIR}/$$f \
+			| ${DEMO_SED} \
+			| sed "s/jquery\.js/${JQ}/" \
+			| sed "s/jquery-ui\.js/${JQUI}/" \
+			> ${BUILD_DIR}/fullcalendar/demos/$$f; \
 	done
 	done
-	@for d in `cd ${EXAMPLES_DIR}; find . -mindepth 1 -maxdepth 1 -type d`; do \
-		cp -r ${EXAMPLES_DIR}/$$d ${BUILD_DIR}/fullcalendar/examples/$$d; \
+	@for d in ${DEMO_SUBDIRS}; do \
+		cp -r ${DEMOS_DIR}/$$d ${BUILD_DIR}/fullcalendar/demos/$$d; \
 	done
 	done
-		
+	
 	@echo "copying other files..."
 	@echo "copying other files..."
 	@cp -r ${OTHER_FILES} ${BUILD_DIR}/fullcalendar
 	@cp -r ${OTHER_FILES} ${BUILD_DIR}/fullcalendar
-		
+	
 	@echo "zipping..."
 	@echo "zipping..."
 	@mv ${BUILD_DIR}/fullcalendar ${BUILD_DIR}/fullcalendar-${VER}
 	@mv ${BUILD_DIR}/fullcalendar ${BUILD_DIR}/fullcalendar-${VER}
 	@cd ${BUILD_DIR}; for f in fullcalendar-*; do \
 	@cd ${BUILD_DIR}; for f in fullcalendar-*; do \
@@ -74,7 +100,7 @@ zip:
 	@mkdir -p ${DIST_DIR}
 	@mkdir -p ${DIST_DIR}
 	@mv ${BUILD_DIR}/fullcalendar-${VER}.zip ${DIST_DIR}
 	@mv ${BUILD_DIR}/fullcalendar-${VER}.zip ${DIST_DIR}
 	@echo "done."
 	@echo "done."
-	
+
 clean:
 clean:
 	@rm -rf ${BUILD_DIR}/fullcalendar
 	@rm -rf ${BUILD_DIR}/fullcalendar
 	@rm -rf ${BUILD_DIR}/fullcalendar-*
 	@rm -rf ${BUILD_DIR}/fullcalendar-*

+ 1 - 0
build/externs.js

@@ -0,0 +1 @@
+var jQuery;

+ 7 - 21
examples/agenda-views.html → demos/agenda-views.html

@@ -1,27 +1,13 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<!--<src>-->
-<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
 <script type='text/javascript' src='../jquery/jquery.js'></script>
 <script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/jquery-ui-custom.js'></script>
-<script type='text/javascript' src='../fullcalendar.min.js'></script>
-</dist>
--->
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 7 - 21
examples/basic-views.html → demos/basic-views.html

@@ -1,27 +1,13 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<!--<src>-->
-<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
 <script type='text/javascript' src='../jquery/jquery.js'></script>
 <script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/jquery-ui-custom.js'></script>
-<script type='text/javascript' src='../fullcalendar.min.js'></script>
-</dist>
--->
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 7 - 21
examples/default.html → demos/default.html

@@ -1,27 +1,13 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<!--<src>-->
-<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
 <script type='text/javascript' src='../jquery/jquery.js'></script>
 <script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/jquery-ui-custom.js'></script>
-<script type='text/javascript' src='../fullcalendar.min.js'></script>
-</dist>
--->
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 7 - 21
examples/external-dragging.html → demos/external-dragging.html

@@ -1,27 +1,13 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<!--<src>-->
-<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
 <script type='text/javascript' src='../jquery/jquery.js'></script>
 <script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/jquery-ui-custom.js'></script>
-<script type='text/javascript' src='../fullcalendar.min.js'></script>
-</dist>
--->
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 67 - 0
demos/gcal.html

@@ -0,0 +1,67 @@
+<!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='../src/_loader.js'></script>
+<script type='text/javascript' src='../src/gcal/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
+<script type='text/javascript' src='../jquery/jquery.js'></script>
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+<script type='text/javascript' src='../fullcalendar/gcal.js'></script>
+]]-->
+<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: 40px;
+		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>
+</head>
+<body>
+<div id='loading' style='display:none'>loading...</div>
+<div id='calendar'></div>
+</body>
+</html>

+ 0 - 0
examples/json-events.php → demos/json-events.php


+ 63 - 0
demos/json.html

@@ -0,0 +1,63 @@
+<!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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
+<script type='text/javascript' src='../jquery/jquery.js'></script>
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
+<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: 40px;
+		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>
+</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>

+ 0 - 0
examples/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png → demos/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png


BIN
demos/redmond/images/ui-bg_flat_55_fbec88_40x100.png


+ 0 - 0
examples/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png → demos/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png


+ 0 - 0
examples/redmond/images/ui-bg_glass_85_dfeffc_1x400.png → demos/redmond/images/ui-bg_glass_85_dfeffc_1x400.png


+ 0 - 0
examples/redmond/images/ui-bg_glass_95_fef1ec_1x400.png → demos/redmond/images/ui-bg_glass_95_fef1ec_1x400.png


+ 0 - 0
examples/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png → demos/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png


+ 0 - 0
examples/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png → demos/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png


+ 0 - 0
examples/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png → demos/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png


BIN
examples/redmond/images/ui-icons_217bc0_256x240.png → demos/redmond/images/ui-icons_217bc0_256x240.png


BIN
examples/redmond/images/ui-icons_2e83ff_256x240.png → demos/redmond/images/ui-icons_2e83ff_256x240.png


BIN
examples/redmond/images/ui-icons_469bdd_256x240.png → demos/redmond/images/ui-icons_469bdd_256x240.png


BIN
examples/redmond/images/ui-icons_6da8d5_256x240.png → demos/redmond/images/ui-icons_6da8d5_256x240.png


BIN
examples/redmond/images/ui-icons_cd0a0a_256x240.png → demos/redmond/images/ui-icons_cd0a0a_256x240.png


BIN
examples/redmond/images/ui-icons_d8e7f3_256x240.png → demos/redmond/images/ui-icons_d8e7f3_256x240.png


BIN
demos/redmond/images/ui-icons_f9bd01_256x240.png


+ 73 - 148
examples/redmond/theme.css → demos/redmond/theme.css

@@ -1,8 +1,12 @@
 /*
 /*
-* 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.
-*/
+ * jQuery UI CSS Framework @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
 
 
 /* Layout helpers
 /* Layout helpers
 ----------------------------------*/
 ----------------------------------*/
@@ -37,18 +41,23 @@
 .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
 .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
-*/
+ * jQuery UI CSS Framework @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * 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
 /* Component containers
 ----------------------------------*/
 ----------------------------------*/
 .ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
 .ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 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 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 { 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-content a { color: #222222; }
@@ -57,23 +66,24 @@
 
 
 /* Interaction states
 /* 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; }
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .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; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .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; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .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; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
+.ui-widget :active { outline: none; }
 
 
 /* Interaction Cues
 /* 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; }
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .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,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .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, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
 
 
 /* Icons
 /* Icons
 ----------------------------------*/
 ----------------------------------*/
@@ -224,6 +234,8 @@
 .ui-icon-seek-next { background-position: -32px -160px; }
 .ui-icon-seek-next { background-position: -32px -160px; }
 .ui-icon-seek-prev { background-position: -48px -160px; }
 .ui-icon-seek-prev { background-position: -48px -160px; }
 .ui-icon-seek-end { background-position: -64px -160px; }
 .ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
 .ui-icon-seek-first { background-position: -80px -160px; }
 .ui-icon-seek-first { background-position: -80px -160px; }
 .ui-icon-stop { background-position: -96px -160px; }
 .ui-icon-stop { background-position: -96px -160px; }
 .ui-icon-eject { background-position: -112px -160px; }
 .ui-icon-eject { background-position: -112px -160px; }
@@ -268,139 +280,52 @@
 ----------------------------------*/
 ----------------------------------*/
 
 
 /* Corner radius */
 /* 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; }
+.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; }
+.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
+.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
+.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
+.ui-corner-right {  -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
+.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
+.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }
 
 
 /* Overlays */
 /* 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-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-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; border-radius: 8px; }/*
+ * jQuery UI Resizable @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
 .ui-resizable { position: relative;}
 .ui-resizable { position: relative;}
 .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
 .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-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-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
 .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
 .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-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-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-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
+ * jQuery UI Tabs @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
 .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.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-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-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
 .ui-tabs .ui-tabs-hide { display: none !important; }
 .ui-tabs .ui-tabs-hide { display: none !important; }

+ 7 - 21
examples/selectable.html → demos/selectable.html

@@ -1,27 +1,13 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<!--<src>-->
-<link rel='stylesheet' type='text/css' href='../src/css/main.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/grid.css' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
 <script type='text/javascript' src='../jquery/jquery.js'></script>
 <script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/jquery-ui-custom.js'></script>
-<script type='text/javascript' src='../fullcalendar.min.js'></script>
-</dist>
--->
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 7 - 21
examples/theme.html → demos/theme.html

@@ -1,28 +1,14 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
 <link rel='stylesheet' type='text/css' href='redmond/theme.css' />
 <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' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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='../src/_loader.js'></script>
+<!--[[
+<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
 <script type='text/javascript' src='../jquery/jquery.js'></script>
 <script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/jquery-ui-custom.js'></script>
-<script type='text/javascript' src='../fullcalendar.min.js'></script>
-</dist>
--->
+<script type='text/javascript' src='../jquery/jquery-ui.js'></script>
+<script type='text/javascript' src='../fullcalendar/fullcalendar.min.js'></script>
+]]-->
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 0 - 79
examples/gcal.html

@@ -1,79 +0,0 @@
-<!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' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.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/agenda.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/selection_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: 40px;
-		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>
-</head>
-<body>
-<div id='loading' style='display:none'>loading...</div>
-<div id='calendar'></div>
-</body>
-</html>

+ 0 - 77
examples/json.html

@@ -1,77 +0,0 @@
-<!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' />
-<link rel='stylesheet' type='text/css' href='../src/css/agenda.css' />
-<script type='text/javascript' src='../src/jquery/jquery.js'></script>
-<script type='text/javascript' src='../src/jquery/jquery-ui-custom.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/agenda.js'></script>
-<script type='text/javascript' src='../src/view.js'></script>
-<script type='text/javascript' src='../src/selection_util.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/jquery-ui-custom.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: 40px;
-		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>
-</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>

BIN
examples/redmond/images/ui-bg_flat_55_fbec88_40x100.png


BIN
examples/redmond/images/ui-icons_f9bd01_256x240.png


+ 0 - 0
tests/jquery-legacy/jquery-1.3.2.min.js → lib/jquery-1.3.2.min.js


+ 0 - 0
src/jquery/jquery.js → lib/jquery-1.4.2.min.js


+ 0 - 0
tests/jquery-legacy/jquery-ui-1.7.3.custom.min.js → lib/jquery-ui-1.7.3.custom.min.js


+ 65 - 63
src/jquery/jquery-ui-custom.js → lib/jquery-ui-1.8.4.custom.min.js

@@ -1,39 +1,41 @@
 /*!
 /*!
- * jQuery UI 1.8.1
+ * jQuery UI 1.8.4
  *
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  *
  * http://docs.jquery.com/UI
  * http://docs.jquery.com/UI
  */
  */
-jQuery.ui||function(c){c.ui={version:"1.8.1",plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")=="hidden")return false;
-b=b&&b=="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,f,g){return c.ui.isOverAxis(a,d,f)&&c.ui.isOverAxis(b,e,g)},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,
-PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none")},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||
-/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==
-undefined)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b=="absolute"||b=="relative"||b=="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b||"area"==b?a.href||!isNaN(d):!isNaN(d))&&
-!c(a)["area"==b?"parents":"closest"](":hidden").length},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}})}(jQuery);
+(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.4",plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,
+b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,
+CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable",
+"off").css("MozUserSelect","")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none")},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,
+"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=
+parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c.style(this,h,d(this,f)+"px")})};c.fn["outer"+
+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c.style(this,h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==
+b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}})}})(jQuery);
 ;/*!
 ;/*!
- * jQuery UI Widget 1.8.1
+ * jQuery UI Widget 1.8.4
  *
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  *
  * http://docs.jquery.com/UI/Widget
  * http://docs.jquery.com/UI/Widget
  */
  */
-(function(b){var j=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add(this).each(function(){b(this).triggerHandler("remove")});return j.call(b(this),a,c)})};b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend({},c.options);b[e][a].prototype=
-b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==undefined){h=i;return false}}):this.each(function(){var g=
-b.data(this,a);if(g){d&&g.option(d);g._init()}else b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){this.element=b(c).data(this.widgetName,this);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();
-this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===undefined)return this.options[a];d={};d[a]=c}b.each(d,function(f,
+(function(b,j){var k=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return k.call(b(this),a,c)})};b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);
+b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):
+this.each(function(){var g=b.data(this,a);if(g){d&&g.option(d);g._init()}else b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});
+this._create();this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}b.each(d,function(f,
 h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=
 h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=
 b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
 b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
 ;/*!
 ;/*!
- * jQuery UI Mouse 1.8.1
+ * jQuery UI Mouse 1.8.4
  *
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  *
  * http://docs.jquery.com/UI/Mouse
  * http://docs.jquery.com/UI/Mouse
  *
  *
@@ -46,11 +48,11 @@ return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._m
 this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
 this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
 a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
 a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
 ;/*
 ;/*
- * jQuery UI Draggable 1.8.1
+ * jQuery UI Draggable 1.8.4
  *
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  *
  * http://docs.jquery.com/UI/Draggables
  * http://docs.jquery.com/UI/Draggables
  *
  *
@@ -78,7 +80,7 @@ f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this
 this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+
 this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+
 Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-
 Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-
 this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=
 this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=
-this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.1"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");
+this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.4"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");
 if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;
 if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;
 c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=
 c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=
 1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;
 1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;
@@ -95,11 +97,11 @@ p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.
 (p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
 (p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
 10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
 10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
 ;/*
 ;/*
- * jQuery UI Resizable 1.8.1
+ * jQuery UI Resizable 1.8.4
  *
  *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
  *
  *
  * http://docs.jquery.com/UI/Resizables
  * http://docs.jquery.com/UI/Resizables
  *
  *
@@ -108,37 +110,37 @@ p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.
  *	jquery.ui.mouse.js
  *	jquery.ui.mouse.js
  *	jquery.ui.widget.js
  *	jquery.ui.widget.js
  */
  */
-(function(d){d.widget("ui.resizable",d.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");d.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
-_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&d.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(d('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
+(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
+_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<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")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;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});this.originalResizeStyle=
 top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;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});this.originalResizeStyle=
-this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!d(".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 c=this.handles.split(",");this.handles={};for(var e=0;e<c.length;e++){var g=d.trim(c[e]),f=d('<div class="ui-resizable-handle '+("ui-resizable-"+g)+'"></div>');/sw|se|ne|nw/.test(g)&&f.css({zIndex:++a.zIndex});"se"==g&&f.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[g]=".ui-resizable-"+g;this.element.append(f)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
-String)this.handles[i]=d(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=d(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}d(this.handles[i])}};this._renderAxis(this.element);this._handles=d(".ui-resizable-handle",this.element).disableSelection();
-this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();d(this.element).addClass("ui-resizable-autohide").hover(function(){d(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){d(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){d(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
-if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(d(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
-e=this.element;this.resizing=true;this.documentScroll={top:d(document).scrollTop(),left:d(document).scrollLeft()};if(e.is(".ui-draggable")||/absolute/.test(e.css("position")))e.css({position:"absolute",top:c.top,left:c.left});d.browser.opera&&/relative/.test(e.css("position"))&&e.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var g=m(this.helper.css("top"));if(a.containment){c+=d(a.containment).scrollLeft()||0;g+=d(a.containment).scrollTop()||0}this.offset=
-this.helper.offset();this.position={left:c,top:g};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:c,top:g};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
-this.originalSize.width/this.originalSize.height||1;a=d(".ui-resizable-"+this.axis).css("cursor");d("body").css("cursor",a=="auto"?this.axis+"-resize":a);e.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,e=this._change[this.axis];if(!e)return false;c=e.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
-b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var e=this._proportionallyResizeElements,g=e.length&&/textarea/i.test(e[0].nodeName);e=g&&d.ui.hasScroll(e[0],"left")?0:c.sizeDiff.height;
-g={width:c.size.width-(g?0:c.sizeDiff.width),height:c.size.height-e};e=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var f=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(d.extend(g,{top:f,left:e}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}d("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
-b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(k(b.left))this.position.left=b.left;if(k(b.top))this.position.top=b.top;if(k(b.height))this.size.height=b.height;if(k(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,e=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(e=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(e=="nw"){b.top=
-a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,e=k(b.width)&&a.maxWidth&&a.maxWidth<b.width,g=k(b.height)&&a.maxHeight&&a.maxHeight<b.height,f=k(b.width)&&a.minWidth&&a.minWidth>b.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(f)b.width=a.minWidth;if(h)b.height=a.minHeight;if(e)b.width=a.maxWidth;if(g)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
-l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(f&&l)b.left=i-a.minWidth;if(e&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(g&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var e=[c.css("borderTopWidth"),
-c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],g=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=d.map(e,function(f,h){f=parseInt(f,10)||0;h=parseInt(g[h],10)||0;return f+h})}d.browser.msie&&(d(b).is(":hidden")||d(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
-this.element.offset();if(this._helper){this.helper=this.helper||d('<div style="overflow:hidden;"></div>');var a=d.browser.msie&&d.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
-a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return d.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return d.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return d.extend(this._change.n.apply(this,
-arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return d.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){d.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,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}}});d.extend(d.ui.resizable,
-{version:"1.8.1"});d.ui.plugin.add("resizable","alsoResize",{start:function(){var b=d(this).data("resizable").options,a=function(c){d(c).each(function(){d(this).data("resizable-alsoresize",{width:parseInt(d(this).width(),10),height:parseInt(d(this).height(),10),left:parseInt(d(this).css("left"),10),top:parseInt(d(this).css("top"),10)})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else d.each(b.alsoResize,function(c){a(c)});
-else a(b.alsoResize)},resize:function(){var b=d(this).data("resizable"),a=b.options,c=b.originalSize,e=b.originalPosition,g={height:b.size.height-c.height||0,width:b.size.width-c.width||0,top:b.position.top-e.top||0,left:b.position.left-e.left||0},f=function(h,i){d(h).each(function(){var j=d(this),l=d(this).data("resizable-alsoresize"),p={};d.each((i&&i.length?i:["width","height","top","left"])||["width","height","top","left"],function(n,o){if((n=(l[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(/relative/.test(j.css("position"))&&
-d.browser.opera){b._revertToRelativePosition=true;j.css({position:"absolute",top:"auto",left:"auto"})}j.css(p)})};typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?d.each(a.alsoResize,function(h,i){f(h,i)}):f(a.alsoResize)},stop:function(){var b=d(this).data("resizable");if(b._revertToRelativePosition&&d.browser.opera){b._revertToRelativePosition=false;el.css({position:"relative"})}d(this).removeData("resizable-alsoresize-start")}});d.ui.plugin.add("resizable","animate",{stop:function(b){var a=
-d(this).data("resizable"),c=a.options,e=a._proportionallyResizeElements,g=e.length&&/textarea/i.test(e[0].nodeName),f=g&&d.ui.hasScroll(e[0],"left")?0:a.sizeDiff.height;g={width:a.size.width-(g?0:a.sizeDiff.width),height:a.size.height-f};f=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(d.extend(g,h&&f?{top:h,left:f}:{}),{duration:c.animateDuration,easing:c.animateEasing,
-step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};e&&e.length&&d(e[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});d.ui.plugin.add("resizable","containment",{start:function(){var b=d(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof d?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=
-d(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:d(document),left:0,top:0,width:d(document).width(),height:d(document).height()||document.body.parentNode.scrollHeight}}else{var e=d(a),g=[];d(["Top","Right","Left","Bottom"]).each(function(i,j){g[i]=m(e.css("padding"+j))});b.containerOffset=e.offset();b.containerPosition=e.position();b.containerSize={height:e.innerHeight()-g[3],width:e.innerWidth()-g[1]};c=b.containerOffset;
-var f=b.containerSize.height,h=b.containerSize.width;h=d.ui.hasScroll(a,"left")?a.scrollWidth:h;f=d.ui.hasScroll(a)?a.scrollHeight:f;b.parentData={element:a,left:c.left,top:c.top,width:h,height:f}}}},resize:function(b){var a=d(this).data("resizable"),c=a.options,e=a.containerOffset,g=a.position;b=a._aspectRatio||b.shiftKey;var f={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))f=e;if(g.left<(a._helper?e.left:0)){a.size.width+=a._helper?a.position.left-e.left:
-a.position.left-f.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?e.left:0}if(g.top<(a._helper?e.top:0)){a.size.height+=a._helper?a.position.top-e.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?e.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-f.left:a.offset.left-f.left)+a.sizeDiff.width);e=Math.abs((a._helper?a.offset.top-f.top:a.offset.top-
-e.top)+a.sizeDiff.height);g=a.containerElement.get(0)==a.element.parent().get(0);f=/relative|absolute/.test(a.containerElement.css("position"));if(g&&f)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(e+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-e;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=d(this).data("resizable"),a=b.options,c=b.containerOffset,e=b.containerPosition,
-g=b.containerElement,f=d(b.helper),h=f.offset(),i=f.outerWidth()-b.sizeDiff.width;f=f.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(g.css("position"))&&d(this).css({left:h.left-e.left-c.left,width:i,height:f});b._helper&&!a.animate&&/static/.test(g.css("position"))&&d(this).css({left:h.left-e.left-c.left,width:i,height:f})}});d.ui.plugin.add("resizable","ghost",{start:function(){var b=d(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,
-display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=d(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=d(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});d.ui.plugin.add("resizable","grid",{resize:function(){var b=
-d(this).data("resizable"),a=b.options,c=b.size,e=b.originalSize,g=b.originalPosition,f=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-e.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-e.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(f)){b.size.width=e.width+h;b.size.height=e.height+a}else if(/^(ne)$/.test(f)){b.size.width=e.width+h;b.size.height=e.height+a;b.position.top=g.top-a}else{if(/^(sw)$/.test(f)){b.size.width=e.width+h;b.size.height=
-e.height+a}else{b.size.width=e.width+h;b.size.height=e.height+a;b.position.top=g.top-a}b.position.left=g.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
+this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".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 c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
+String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
+this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
+if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
+d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
+this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
+this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
+b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
+f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
+b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
+a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
+k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
+c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
+this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
+arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,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}}});e.extend(e.ui.resizable,
+{version:"1.8.4"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
+function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
+(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
+false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
+a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
+b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
+"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
+f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
+a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
+e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
+height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
+d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
 ;
 ;

+ 480 - 0
src/Calendar.js

@@ -0,0 +1,480 @@
+
+ 
+function Calendar(element, options, eventSources) {
+	var t = this;
+	
+	
+	// exports
+	t.options = options;
+	t.render = render;
+	t.destroy = destroy;
+	t.changeView = changeView;
+	t.select = select;
+	t.unselect = unselect;
+	t.rerenderEvents = rerenderEvents; // todo: seems liks an EventManager thing
+	t.prev = prev;
+	t.next = next;
+	t.prevYear = prevYear;
+	t.nextYear = nextYear;
+	t.today = today;
+	t.gotoDate = gotoDate;
+	t.incrementDate = incrementDate;
+	t.formatDate = function(format, date) { return formatDate(format, date, options) };
+	t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) };
+	t.getDate = getDate;
+	t.getView = getView;
+	t.option = option;
+	t.trigger = trigger;
+	
+	
+	// imports
+	EventManager.call(t, options, eventSources);
+	var fetchEvents = t.fetchEvents;
+	var isFetchNeeded = t.isFetchNeeded;
+	var clientEvents = t.clientEvents;
+	
+	
+	// locals
+	var _element = element[0];
+	var header;
+	var headerElement;
+	var content;
+	var tm; // for making theme classes
+	var currentView;
+	var viewInstances = {};
+	var elementOuterWidth;
+	var suggestedViewHeight;
+	var absoluteViewElement;
+	var resizeUID = 0;
+	var ignoreWindowResize = 0;
+	var date = new Date();
+	
+	
+	
+	/* Main Rendering
+	-----------------------------------------------------------------------------*/
+	
+	
+	setYMD(date, options.year, options.month, options.date);
+	
+	
+	function render(inc) {
+		if (!content) {
+			initialRender();
+		}else{
+			calcSize();
+			sizesDirty();
+			eventsDirty();
+			renderView(inc);
+		}
+	}
+	
+	
+	function initialRender() {
+		tm = options.theme ? 'ui' : 'fc';
+		element.addClass('fc');
+		if (options.isRTL) {
+			element.addClass('fc-rtl');
+		}
+		if (options.theme) {
+			element.addClass('ui-widget');
+		}
+		content = $("<div class='fc-content " + tm + "-widget-content' style='position:relative'/>")
+			.prependTo(element);
+		header = new Header(t, options);
+		headerElement = header.render();
+		if (headerElement) {
+			element.prepend(headerElement);
+		}
+		changeView(options.defaultView);
+		$(window).resize(windowResize);
+		// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize
+		if (!bodyVisible()) {
+			lateRender();
+		}
+	}
+	
+	
+	// called when we know the calendar couldn't be rendered when it was initialized,
+	// but we think it's ready now
+	function lateRender() {
+		setTimeout(function() { // IE7 needs this so dimensions are calculated correctly
+			if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once
+				renderView();
+			}
+		},0);
+	}
+	
+	
+	function destroy() {
+		$(window).unbind('resize', windowResize);
+		header.destroy();
+		content.remove();
+		element.removeClass('fc fc-rtl fc-ui-widget');
+	}
+	
+	
+	
+	function elementVisible() {
+		return _element.offsetWidth !== 0;
+	}
+	
+	
+	function bodyVisible() {
+		return $('body')[0].offsetWidth !== 0;
+	}
+	
+	
+	
+	/* View Rendering
+	-----------------------------------------------------------------------------*/
+	
+	
+	function changeView(newViewName) {
+		if (!currentView || newViewName != currentView.name) {
+			ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached
+
+			unselect();
+			
+			var oldView = currentView;
+			var newViewElement;
+				
+			if (oldView) {
+				if (oldView.eventsChanged) {
+					eventsDirty();
+					oldView.eventDirty = oldView.eventsChanged = false;
+				}
+				(oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera)
+				setMinHeight(content, content.height());
+				oldView.element.hide();
+			}else{
+				setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated
+			}
+			content.css('overflow', 'hidden');
+			
+			currentView = viewInstances[newViewName];
+			if (currentView) {
+				currentView.element.show();
+			}else{
+				currentView = viewInstances[newViewName] = new fcViews[newViewName](
+					newViewElement = absoluteViewElement =
+						$("<div class='fc-view fc-view-" + newViewName + "' style='position:absolute'/>")
+							.appendTo(content),
+					t // the calendar object
+				);
+			}
+			
+			if (oldView) {
+				header.deactivateButton(oldView.name);
+			}
+			header.activateButton(newViewName);
+			
+			renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to null
+			
+			content.css('overflow', '');
+			if (oldView) {
+				setMinHeight(content, 1);
+			}
+			
+			if (!newViewElement) {
+				(currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera)
+			}
+			
+			ignoreWindowResize--;
+		}
+	}
+	
+	
+	
+	function renderView(inc) {
+		if (elementVisible()) {
+			ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached
+
+			unselect();
+			
+			if (suggestedViewHeight === undefined) {
+				calcSize();
+			}
+			
+			if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {
+				currentView.render(date, inc || 0); // responsible for clearing events
+				setSize(true);
+				if (!options.lazyFetching || isFetchNeeded()) {
+					fetchAndRenderEvents();
+				}else{
+					currentView.renderEvents(clientEvents()); // don't refetch
+				}
+			}
+			else if (currentView.sizeDirty || currentView.eventsDirty || !options.lazyFetching) {
+				currentView.clearEvents();
+				if (currentView.sizeDirty) {
+					setSize();
+				}
+				if (!options.lazyFetching || isFetchNeeded()) {
+					fetchAndRenderEvents();
+				}else{
+					currentView.renderEvents(clientEvents()); // don't refetch
+				}
+			}
+			elementOuterWidth = element.outerWidth();
+			currentView.sizeDirty = false;
+			currentView.eventsDirty = false;
+			
+			header.updateTitle(currentView.title);
+			var today = new Date();
+			if (today >= currentView.start && today < currentView.end) {
+				header.disableButton('today');
+			}else{
+				header.enableButton('today');
+			}
+			
+			ignoreWindowResize--;
+			currentView.trigger('viewDisplay', _element);
+		}
+	}
+	
+	
+	
+	/* Resizing
+	-----------------------------------------------------------------------------*/
+	
+	
+	function calcSize() {
+		if (options.contentHeight) {
+			suggestedViewHeight = options.contentHeight;
+		}
+		else if (options.height) {
+			suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content[0]);
+		}
+		else {
+			suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));
+		}
+	}
+	
+	
+	function setSize(dateChanged) { // todo: dateChanged?
+		ignoreWindowResize++;
+		currentView.setHeight(suggestedViewHeight, dateChanged);
+		if (absoluteViewElement) {
+			absoluteViewElement.css('position', 'relative');
+			absoluteViewElement = null;
+		}
+		currentView.setWidth(content.width(), dateChanged);
+		ignoreWindowResize--;
+	}
+	
+	
+	function windowResize() {
+		if (!ignoreWindowResize) {
+			if (currentView.start) { // view has already been rendered
+				var uid = ++resizeUID;
+				setTimeout(function() { // add a delay
+					if (uid == resizeUID && !ignoreWindowResize && elementVisible()) {
+						if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {
+							ignoreWindowResize++; // in case the windowResize callback changes the height
+							sizeChanged();
+							currentView.trigger('windowResize', _element);
+							ignoreWindowResize--;
+						}
+					}
+				}, 200);
+			}else{
+				// calendar must have been initialized in a 0x0 iframe that has just been resized
+				lateRender();
+			}
+		}
+	}
+	
+	
+	// called when we know the element size has changed
+	function sizeChanged() {
+		sizesDirty();
+		if (elementVisible()) {
+			calcSize();
+			setSize();
+			unselect();
+			currentView.rerenderEvents();
+			currentView.sizeDirty = false;
+		}
+	}
+	
+	
+	// marks other views' sizes as dirty
+	function sizesDirty() {
+		$.each(viewInstances, function(i, inst) {
+			inst.sizeDirty = true;
+		});
+	}
+	
+	
+	
+	/* Event Rendering
+	-----------------------------------------------------------------------------*/
+	
+	
+	// called when any event objects have been added/removed/changed, rerenders
+	function rerenderEvents() {
+		eventsDirty();
+		if (elementVisible()) {
+			currentView.clearEvents();
+			currentView.renderEvents(clientEvents());
+			currentView.eventsDirty = false;
+		}
+	}
+	
+	
+	// marks every views' events as dirty
+	function eventsDirty() {
+		$.each(viewInstances, function(i, inst) {
+			inst.eventsDirty = true;
+		});
+	}
+	
+	
+	// for convenience
+	function fetchAndRenderEvents() {
+		fetchEvents(function(events) {
+			currentView.renderEvents(events); // maintain `this` in view
+		});
+	}
+	
+
+
+	/* Selection
+	-----------------------------------------------------------------------------*/
+	
+
+	function select(start, end, allDay) {
+		currentView.select(start, end, allDay===undefined ? true : allDay);
+	}
+	
+
+	function unselect() { // safe to be called before renderView
+		if (currentView) {
+			currentView.unselect();
+		}
+	}
+	
+	
+	
+	/* Date
+	-----------------------------------------------------------------------------*/
+	
+	
+	function prev() {
+		renderView(-1);
+	}
+	
+	
+	function next() {
+		renderView(1);
+	}
+	
+	
+	function prevYear() {
+		addYears(date, -1);
+		renderView();
+	}
+	
+	
+	function nextYear() {
+		addYears(date, 1);
+		renderView();
+	}
+	
+	
+	function today() {
+		date = new Date();
+		renderView();
+	}
+	
+	
+	function gotoDate(year, month, dateOfMonth) {
+		if (year instanceof Date) {
+			date = cloneDate(year); // provided 1 argument, a Date
+		}else{
+			setYMD(date, year, month, dateOfMonth);
+		}
+		renderView();
+	}
+	
+	
+	function incrementDate(years, months, days) {
+		if (years !== undefined) {
+			addYears(date, years);
+		}
+		if (months !== undefined) {
+			addMonths(date, months);
+		}
+		if (days !== undefined) {
+			addDays(date, days);
+		}
+		renderView();
+	}
+	
+	
+	function getDate() {
+		return cloneDate(date);
+	}
+	
+	
+	
+	/* Misc
+	-----------------------------------------------------------------------------*/
+	
+	
+	function getView() {
+		return currentView;
+	}
+	
+	
+	function option(name, value) {
+		if (value === undefined) {
+			return options[name];
+		}
+		if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
+			options[name] = value;
+			sizeChanged();
+		}
+	}
+	
+	
+	function trigger(name, thisObj) {
+		if (options[name]) {
+			return options[name].apply(
+				thisObj || _element,
+				Array.prototype.slice.call(arguments, 2)
+			);
+		}
+	}
+	
+	
+	
+	/* External Dragging
+	------------------------------------------------------------------------*/
+	
+	var _dragElement;
+	
+	if (options.droppable) {
+		$(document)
+			.bind('dragstart', function(ev, ui) {
+				var _e = ev.target;
+				var e = $(_e);
+				if (!e.parents('.fc').length) { // not already inside a calendar
+					var accept = options.dropAccept;
+					if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {
+						_dragElement = _e;
+						currentView.dragStart(_dragElement, ev, ui);
+					}
+				}
+			})
+			.bind('dragstop', function(ev, ui) {
+				if (_dragElement) {
+					currentView.dragStop(_dragElement, ev, ui);
+					_dragElement = null;
+				}
+			});
+	}
+	
+
+}

+ 288 - 0
src/EventManager.js

@@ -0,0 +1,288 @@
+
+var eventGUID = 1;
+
+function EventManager(options, eventSources) {
+	var t = this;
+	
+	
+	// exports
+	t.fetchEvents = fetchEvents;
+	t.refetchEvents = refetchEvents;
+	t.isFetchNeeded = isFetchNeeded;
+	t.addEventSource = addEventSource;
+	t.removeEventSource = removeEventSource;
+	t.updateEvent = updateEvent;
+	t.renderEvent = renderEvent;
+	t.removeEvents = removeEvents;
+	t.clientEvents = clientEvents;
+	t.normalizeEvent = normalizeEvent;
+	
+	
+	// imports
+	var getDate = t.getDate;
+	var getView = t.getView;
+	var trigger = t.trigger;
+	var rerenderEvents = t.rerenderEvents;
+
+	
+	// locals
+	var eventStart, eventEnd;
+	var events = [];
+	var loadingLevel = 0;
+	
+	
+	
+	/* Sources
+	-----------------------------------------------------------------------------*/
+	
+	
+	eventSources.unshift([]); // first event source reserved for 'sticky' events
+	
+
+	function addEventSource(source) {
+		eventSources.push(source);
+		fetchEventSource(source, rerenderEvents);
+	}
+	
+
+	function removeEventSource(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;
+		});
+		rerenderEvents();
+	}
+
+
+
+	/* Fetching
+	-----------------------------------------------------------------------------*/
+	
+	
+	// Fetch from ALL sources. Clear 'events' array and populate
+	function fetchEvents(callback) {
+		var view = getView();
+		events = [];
+		eventStart = cloneDate(view.visStart);
+		eventEnd = cloneDate(view.visEnd);
+		var queued = eventSources.length,
+			sourceDone = function() {
+				if (!--queued) {
+					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 prevView = getView(),
+			prevDate = getDate(),
+			reportEvents = function(a) {
+				if (prevView == getView() && +prevDate == +getDate() && // protects from fast switching
+					$.inArray(src, eventSources) != -1) {               // makes sure source hasn't been removed
+						for (var i=0; i<a.length; i++) {
+							normalizeEvent(a[i]);
+							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);
+			if (options.cacheParam) {
+				params[options.cacheParam] = (new Date()).getTime(); // TODO: deprecate cacheParam
+			}
+			pushLoading();
+			// TODO: respect cache param in ajaxSetup
+			$.ajax({
+				url: src,
+				dataType: 'json',
+				data: params,
+				cache: options.cacheParam || false, // don't let jquery prevent caching if cacheParam is being used
+				success: reportEventsAndPop
+			});
+		}
+		else if ($.isFunction(src)) {
+			pushLoading();
+			src(cloneDate(eventStart), cloneDate(eventEnd), reportEventsAndPop);
+		}
+		else {
+			reportEvents(src); // src is an array
+		}
+	}
+	
+	
+	function refetchEvents() {
+		fetchEvents(rerenderEvents);
+	}
+	
+	
+	function isFetchNeeded() {
+		var view = getView();
+		return !eventStart || view.visStart < eventStart || view.visEnd > eventEnd;
+	}
+	
+	
+	
+	/* Manipulation
+	-----------------------------------------------------------------------------*/
+	
+	
+	function updateEvent(event) { // update an existing event
+		var i, len = events.length, e,
+			defaultEventEnd = getView().defaultEventEnd,
+			startDelta = event.start - event._start,
+			endDelta = event.end ?
+				(event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end
+				: 0;                                                      // was null and event was just resized
+		for (i=0; i<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(+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);
+			}
+		}
+		normalizeEvent(event);
+		rerenderEvents();
+	}
+	
+	
+	function renderEvent(event, stick) { // render a new event
+		normalizeEvent(event);
+		if (!event.source) {
+			if (stick) {
+				(event.source = eventSources[0]).push(event);
+			}
+			events.push(event);
+		}
+		rerenderEvents();
+	}
+	
+	
+	function removeEvents(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);
+				}
+			}
+		}
+		rerenderEvents();
+	}
+	
+	
+	function clientEvents(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
+	}
+	
+	
+	
+	/* Loading State
+	-----------------------------------------------------------------------------*/
+	
+	
+	function pushLoading() {
+		if (!loadingLevel++) {
+			trigger('loading', null, true);
+		}
+	}
+	
+	
+	function popLoading() {
+		if (!--loadingLevel) {
+			trigger('loading', null, false);
+		}
+	}
+	
+	
+	
+	/* Event Normalization
+	-----------------------------------------------------------------------------*/
+	
+	
+	function normalizeEvent(event) {
+		event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');
+		if (event.date) {
+			if (!event.start) {
+				event.start = event.date;
+			}
+			delete event.date;
+		}
+		event._start = cloneDate(event.start = parseDate(event.start, options.ignoreTimezone));
+		event.end = parseDate(event.end, options.ignoreTimezone);
+		if (event.end && event.end <= event.start) {
+			event.end = null;
+		}
+		event._end = event.end ? cloneDate(event.end) : null;
+		if (event.allDay === undefined) {
+			event.allDay = options.allDayDefault;
+		}
+		if (event.className) {
+			if (typeof event.className == 'string') {
+				event.className = event.className.split(/\s+/);
+			}
+		}else{
+			event.className = [];
+		}
+		// TODO: if there is no start date, return false to indicate an invalid event
+	}
+
+
+}

+ 164 - 0
src/Header.js

@@ -0,0 +1,164 @@
+
+function Header(calendar, options) {
+	var t = this;
+	
+	
+	// exports
+	t.render = render;
+	t.destroy = destroy;
+	t.updateTitle = updateTitle;
+	t.activateButton = activateButton;
+	t.deactivateButton = deactivateButton;
+	t.disableButton = disableButton;
+	t.enableButton = enableButton;
+	
+	
+	// locals
+	var element = $([]);
+	var tm;
+	
+
+
+	function render() {
+		tm = options.theme ? 'ui' : 'fc';
+		var sections = options.header;
+		if (sections) {
+			element = $("<table class='fc-header'/>")
+				.append($("<tr/>")
+					.append($("<td class='fc-header-left'/>")
+						.append(renderSection(sections.left)))
+					.append($("<td class='fc-header-center'/>")
+						.append(renderSection(sections.center)))
+					.append($("<td class='fc-header-right'/>")
+						.append(renderSection(sections.right))));
+			return element;
+		}
+	}
+	
+	
+	function destroy() {
+		element.remove();
+	}
+	
+	
+	function renderSection(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, buttonName) {
+					if (buttonName == 'title') {
+						tr.append("<td><h2 class='fc-header-title'>&nbsp;</h2></td>");
+						if (prevButton) {
+							prevButton.addClass(tm + '-corner-right');
+						}
+						prevButton = null;
+					}else{
+						var buttonClick;
+						if (calendar[buttonName]) {
+							buttonClick = calendar[buttonName]; // calendar method
+						}
+						else if (fcViews[buttonName]) {
+							buttonClick = function() {
+								button.removeClass(tm + '-state-hover'); // forget why
+								calendar.changeView(buttonName);
+							};
+						}
+						if (buttonClick) {
+							if (prevButton) {
+								prevButton.addClass(tm + '-no-right');
+							}
+							var button;
+							var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null;
+							var text = smartProperty(options.buttonText, buttonName);
+							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
+									.click(function() {
+										if (!button.hasClass(tm + '-state-disabled')) {
+											buttonClick();
+										}
+									})
+									.mousedown(function() {
+										button
+											.not('.' + tm + '-state-active')
+											.not('.' + tm + '-state-disabled')
+											.addClass(tm + '-state-down');
+									})
+									.mouseup(function() {
+										button.removeClass(tm + '-state-down');
+									})
+									.hover(
+										function() {
+											button
+												.not('.' + tm + '-state-active')
+												.not('.' + tm + '-state-disabled')
+												.addClass(tm + '-state-hover');
+										},
+										function() {
+											button
+												.removeClass(tm + '-state-hover')
+												.removeClass(tm + '-state-down');
+										}
+									)
+									.appendTo($("<td/>").appendTo(tr));
+								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);
+		}
+	}
+	
+	
+	function updateTitle(html) {
+		element.find('h2.fc-header-title')
+			.html(html);
+	}
+	
+	
+	function activateButton(buttonName) {
+		element.find('div.fc-button-' + buttonName)
+			.addClass(tm + '-state-active');
+	}
+	
+	
+	function deactivateButton(buttonName) {
+		element.find('div.fc-button-' + buttonName)
+			.removeClass(tm + '-state-active');
+	}
+	
+	
+	function disableButton(buttonName) {
+		element.find('div.fc-button-' + buttonName)
+			.addClass(tm + '-state-disabled');
+	}
+	
+	
+	function enableButton(buttonName) {
+		element.find('div.fc-button-' + buttonName)
+			.removeClass(tm + '-state-disabled');
+	}
+
+
+}

+ 132 - 0
src/_loader.js

@@ -0,0 +1,132 @@
+(function() {
+
+var JQUERY = 'jquery-1.4.2.min.js';
+var JQUERY_UI = 'jquery-ui-1.8.4.custom.min.js';
+var JQUERY_LEGACY = 'jquery-1.3.2.min.js';
+var JQUERY_UI_LEGACY = 'jquery-ui-1.7.3.custom.min.js';
+
+var qs = window.location.href.match(/(\?.*)?$/)[0];
+var legacy = qs.indexOf('legacy') != -1;
+var noui = qs.indexOf('noui') != -1;
+var debug;
+var prefix;
+var tags;
+
+
+startload();
+
+css('main.css');
+css('common/common.css');
+css('basic/basic.css');
+css('agenda/agenda.css');
+
+if (!legacy) {
+	jslib('../lib/' + JQUERY);
+	if (!noui) {
+		jslib('../lib/' + JQUERY_UI);
+	}
+}else{
+	jslib('../lib/' + JQUERY_LEGACY);
+	if (!noui) {
+		jslib('../lib/' + JQUERY_UI_LEGACY);
+	}
+}
+
+if (debug && (!window.console || !window.console.log)) {
+	jslib('../tests/lib/firebug-lite/firebug-lite-compressed.js');
+}
+
+js('defaults.js');
+js('main.js');
+js('Calendar.js');
+js('Header.js');
+js('EventManager.js');
+
+js('basic/MonthView.js');
+js('basic/BasicWeekView.js');
+js('basic/BasicDayView.js');
+js('basic/BasicView.js');
+js('basic/BasicEventRenderer.js');
+
+js('agenda/AgendaWeekView.js');
+js('agenda/AgendaDayView.js');
+js('agenda/AgendaView.js');
+js('agenda/AgendaEventRenderer.js');
+
+js('common/View.js');
+js('common/DayEventRenderer.js');
+js('common/SelectionManager.js');
+js('common/OverlayManager.js');
+js('common/CoordinateGrid.js');
+js('common/HoverListener.js');
+js('common/HorizontalPositionCache.js');
+js('common/date.js');
+js('common/util.js');
+
+endload();
+
+
+if (debug) {
+	window.onload = function() {
+		$('body').append(
+			"<form style='position:absolute;top:0;right:0;text-align:right;font-size:10px;color:#666'>" +
+				"<label for='legacy'>legacy</label> " +
+				"<input type='checkbox' id='legacy' name='legacy'" + (legacy ? " checked='checked'" : '') +
+					" style='vertical-align:middle' onclick='$(this).parent().submit()' />" +
+				"<br />" +
+				"<label for='ui'>no jquery ui</label> " +
+				"<input type='checkbox' id='ui' name='noui'" + (noui ? " checked='checked'" : '') +
+					" style='vertical-align:middle' onclick='$(this).parent().submit()' />" +
+			"</form>"
+		);
+	};
+}
+
+
+window.startload = startload;
+window.endload = endload;
+window.css = css;
+window.js = js;
+window.jslib = jslib;
+
+
+function startload() {
+	debug = false;
+	prefix = '';
+	tags = [];
+	var scripts = document.getElementsByTagName('script');
+	for (var i=0, script; script=scripts[i++];) {
+		if (!script._checked) {
+			script._checked = true;
+			var m = (script.getAttribute('src') || '').match(/^(.*)_loader\.js(\?.*)?$/);
+			if (m) {
+				prefix = m[1];
+				debug = (m[2] || '').indexOf('debug') != -1;
+				break;
+			}
+		}
+	}
+}
+
+
+function endload() {
+	document.write(tags.join("\n"));
+}
+
+
+function css(file) {
+	tags.push("<link rel='stylesheet' type='text/css' href='" + prefix + file + "' />");
+}
+
+
+function js(file) {
+	tags.push("<script type='text/javascript' src='" + prefix + file + "'></script>");
+}
+
+
+function jslib(file) {
+	js(file);
+}
+
+
+})();

+ 0 - 1262
src/agenda.js

@@ -1,1262 +0,0 @@
-
-/* Agenda Views: agendaWeek/agendaDay
------------------------------------------------------------------------------*/
-
-setDefaults({
-	allDaySlot: true,
-	allDayText: 'all-day',
-	firstHour: 6,
-	slotMinutes: 30,
-	defaultEventMinutes: 120,
-	axisFormat: 'h(:mm)tt',
-	timeFormat: {
-		agenda: 'h:mm{ - h:mm}'
-	},
-	dragOpacity: {
-		agenda: .5
-	},
-	minTime: 0,
-	maxTime: 24
-});
-
-views.agendaWeek = function(element, options, viewName) {
-	return new Agenda(element, options, {
-		render: function(date, delta) {
-			if (delta) {
-				addDays(date, delta * 7);
-			}
-			var visStart = this.visStart = cloneDate(
-					this.start = addDays(cloneDate(date), -((date.getDay() - options.firstDay + 7) % 7))
-				),
-				visEnd = this.visEnd = cloneDate(
-					this.end = addDays(cloneDate(visStart), 7)
-				);
-			if (!options.weekends) {
-				skipWeekend(visStart);
-				skipWeekend(visEnd, -1, true);
-			}
-			this.title = formatDates(
-				visStart,
-				addDays(cloneDate(visEnd), -1),
-				this.option('titleFormat'),
-				options
-			);
-			this.renderAgenda(
-				options.weekends ? 7 : 5,
-				this.option('columnFormat')
-			);
-		}
-	}, viewName);
-};
-
-views.agendaDay = function(element, options, viewName) {
-	return new Agenda(element, options, {
-		render: function(date, delta) {
-			if (delta) {
-				addDays(date, delta);
-				if (!options.weekends) {
-					skipWeekend(date, delta < 0 ? -1 : 1);
-				}
-			}
-			this.title = formatDate(date, this.option('titleFormat'), options);
-			this.start = this.visStart = cloneDate(date, true);
-			this.end = this.visEnd = addDays(cloneDate(this.start), 1);
-			this.renderAgenda(
-				1,
-				this.option('columnFormat')
-			);
-		}
-	}, viewName);
-};
-
-function Agenda(element, options, methods, viewName) {
-
-	var head, body, bodyContent, bodyTable, bg,
-		colCnt,
-		slotCnt=0, // spanning all the way across
-		axisWidth, colWidth, slotHeight,
-		viewWidth, viewHeight,
-		savedScrollTop,
-		cachedEvents=[],
-		daySegmentContainer,
-		slotSegmentContainer,
-		tm, firstDay,
-		nwe,            // no weekends (int)
-		rtl, dis, dit,  // day index sign / translate
-		minMinute, maxMinute,
-		colContentPositions = new HorizontalPositionCache(function(col) {
-			return bg.find('td:eq(' + col + ') div div');
-		}),
-		slotTopCache = {},
-		// ...
-		
-	view = $.extend(this, viewMethods, methods, {
-		renderAgenda: renderAgenda,
-		renderEvents: renderEvents,
-		rerenderEvents: rerenderEvents,
-		clearEvents: clearEvents,
-		setHeight: setHeight,
-		setWidth: setWidth,
-		beforeHide: function() {
-			savedScrollTop = body.scrollTop();
-		},
-		afterShow: function() {
-			body.scrollTop(savedScrollTop);
-		},
-		defaultEventEnd: function(event) {
-			var start = cloneDate(event.start);
-			if (event.allDay) {
-				return start;
-			}
-			return addMinutes(start, options.defaultEventMinutes);
-		}
-	});
-	view.name = viewName;
-	view.init(element, options);
-	
-	
-	
-	/* Time-slot rendering
-	-----------------------------------------------------------------------------*/
-	
-	
-	disableTextSelection(element.addClass('fc-agenda'));
-	
-	
-	function renderAgenda(c, colFormat) {
-	
-		colCnt = c;
-		
-		// update option-derived variables
-		tm = options.theme ? 'ui' : 'fc';
-		nwe = options.weekends ? 0 : 1;
-		firstDay = options.firstDay;
-		if (rtl = options.isRTL) {
-			dis = -1;
-			dit = colCnt - 1;
-		}else{
-			dis = 1;
-			dit = 0;
-		}
-		minMinute = parseTime(options.minTime);
-		maxMinute = parseTime(options.maxTime);
-		
-		var d0 = rtl ? addDays(cloneDate(view.visEnd), -1) : cloneDate(view.visStart),
-			d = cloneDate(d0),
-			today = clearTime(new Date());
-		
-		if (!head) { // first time rendering, build from scratch
-		
-			var i,
-				minutes,
-				slotNormal = options.slotMinutes % 15 == 0, //...
-			
-			// head
-			s = "<div class='fc-agenda-head' style='position:relative;z-index:4'>" +
-				"<table style='width:100%'>" +
-				"<tr class='fc-first" + (options.allDaySlot ? '' : ' fc-last') + "'>" +
-				"<th class='fc-leftmost " +
-					tm + "-state-default'>&nbsp;</th>";
-			for (i=0; i<colCnt; i++) {
-				s += "<th class='fc-" +
-					dayIDs[d.getDay()] + ' ' + // needs to be first
-					tm + '-state-default' +
-					"'>" + formatDate(d, colFormat, options) + "</th>";
-				addDays(d, dis);
-				if (nwe) {
-					skipWeekend(d, dis);
-				}
-			}
-			s += "<th class='" + tm + "-state-default'>&nbsp;</th></tr>";
-			if (options.allDaySlot) {
-				s += "<tr class='fc-all-day'>" +
-						"<th class='fc-axis fc-leftmost " + tm + "-state-default'>" + options.allDayText + "</th>" +
-						"<td colspan='" + colCnt + "' class='" + tm + "-state-default'>" +
-							"<div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div></td>" +
-						"<th class='" + tm + "-state-default'>&nbsp;</th>" +
-					"</tr><tr class='fc-divider fc-last'><th colspan='" + (colCnt+2) + "' class='" +
-						tm + "-state-default fc-leftmost'><div/></th></tr>";
-			}
-			s+= "</table></div>";
-			head = $(s).appendTo(element);
-			dayBind(head.find('td'));
-			
-			// all-day event container
-			daySegmentContainer = $("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(head);
-			
-			// body
-			d = zeroDate();
-			var maxd = addMinutes(cloneDate(d), maxMinute);
-			addMinutes(d, minMinute);
-			s = "<table>";
-			for (i=0; d < maxd; i++) {
-				minutes = d.getMinutes();
-				s += "<tr class='" +
-					(!i ? 'fc-first' : (!minutes ? '' : 'fc-minor')) +
-					"'><th class='fc-axis fc-leftmost " + tm + "-state-default'>" +
-					((!slotNormal || !minutes) ? formatDate(d, options.axisFormat) : '&nbsp;') + 
-					"</th><td class='fc-slot" + i + ' ' +
-						tm + "-state-default'><div style='position:relative'>&nbsp;</div></td></tr>";
-				addMinutes(d, options.slotMinutes);
-				slotCnt++;
-			}
-			s += "</table>";
-			body = $("<div class='fc-agenda-body' style='position:relative;z-index:2;overflow:auto'/>")
-				.append(bodyContent = $("<div style='position:relative;overflow:hidden'>")
-					.append(bodyTable = $(s)))
-				.appendTo(element);
-			slotBind(body.find('td'));
-			
-			// slot event container
-			slotSegmentContainer = $("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(bodyContent);
-			
-			// background stripes
-			d = cloneDate(d0);
-			s = "<div class='fc-agenda-bg' style='position:absolute;z-index:1'>" +
-				"<table style='width:100%;height:100%'><tr class='fc-first'>";
-			for (i=0; i<colCnt; i++) {
-				s += "<td class='fc-" +
-					dayIDs[d.getDay()] + ' ' + // needs to be first
-					tm + '-state-default ' +
-					(!i ? 'fc-leftmost ' : '') +
-					(+d == +today ? tm + '-state-highlight fc-today' : 'fc-not-today') +
-					"'><div class='fc-day-content'><div>&nbsp;</div></div></td>";
-				addDays(d, dis);
-				if (nwe) {
-					skipWeekend(d, dis);
-				}
-			}
-			s += "</tr></table></div>";
-			bg = $(s).appendTo(element);
-			
-		}else{ // skeleton already built, just modify it
-		
-			clearEvents();
-			
-			// redo column header text and class
-			head.find('tr:first th').slice(1, -1).each(function() {
-				$(this).text(formatDate(d, colFormat, options));
-				this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
-				addDays(d, dis);
-				if (nwe) {
-					skipWeekend(d, dis);
-				}
-			});
-			
-			// change classes of background stripes
-			d = cloneDate(d0);
-			bg.find('td').each(function() {
-				this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
-				if (+d == +today) {
-					$(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');
-				}
-				addDays(d, dis);
-				if (nwe) {
-					skipWeekend(d, dis);
-				}
-			});
-		
-		}
-		
-	}
-	
-	
-	function resetScroll() {
-		var d0 = zeroDate(),
-			scrollDate = cloneDate(d0);
-		scrollDate.setHours(options.firstHour);
-		var top = timePosition(d0, scrollDate) + 1, // +1 for the border
-			scroll = function() {
-				body.scrollTop(top);
-			};
-		scroll();
-		setTimeout(scroll, 0); // overrides any previous scroll state made by the browser
-	}
-	
-	
-	function setHeight(height, dateChanged) {
-		viewHeight = height;
-		slotTopCache = {};
-		
-		body.height(height - head.height());
-		
-		slotHeight = body.find('tr:first div').height() + 1;
-		
-		bg.css({
-			top: head.find('tr').height(),
-			height: height
-		});
-		
-		// if the table ends up shorter than the allotted view, shrink the view to fit the table
-		var tableHeight=body.find('table:first').height();
-		if (tableHeight<body.height()) {
-			body.height(tableHeight);
-		}
-		
-		if (dateChanged) {
-			resetScroll();
-		}
-	}
-	
-	
-	function setWidth(width) {
-		viewWidth = width;
-		colContentPositions.clear();
-		
-		body.width(width);
-		bodyTable.width('');
-		
-		var topTDs = head.find('tr:first th'),
-			stripeTDs = bg.find('td'),
-			clientWidth = body[0].clientWidth;
-			
-		bodyTable.width(clientWidth);
-		
-		// time-axis width
-		axisWidth = 0;
-		setOuterWidth(
-			head.find('tr:lt(2) th:first').add(body.find('tr:first th'))
-				.width('')
-				.each(function() {
-					axisWidth = Math.max(axisWidth, $(this).outerWidth());
-				}),
-			axisWidth
-		);
-		
-		// column width
-		colWidth = Math.floor((clientWidth - axisWidth) / colCnt);
-		setOuterWidth(stripeTDs.slice(0, -1), colWidth);
-		setOuterWidth(topTDs.slice(1, -2), colWidth);
-		
-		var scrollbar=body[0].scrollHeight!=body[0].clientHeight;
-
-		if (scrollbar) {
-			setOuterWidth(topTDs.slice(-2, -1), clientWidth - axisWidth - colWidth*(colCnt-1));
-		} else {
-			topTDs.slice(-1).hide();
-			$('tr.fc-all-day th').slice(-1).hide();
-		}
-		bg.css({
-			left: axisWidth,
-			width: clientWidth - axisWidth
-		});
-	}
-	
-	
-	
-	/* Slot/Day clicking and binding
-	-----------------------------------------------------------------------*/
-	
-
-	function dayBind(tds) {
-		tds.click(slotClick)
-			.mousedown(daySelectionMousedown);
-	}
-
-
-	function slotBind(tds) {
-		tds.click(slotClick)
-			.mousedown(slotSelectionMousedown);
-	}
-	
-	
-	function slotClick(ev) {
-		if (!view.option('selectable')) { // SelectionManager will worry about dayClick
-			var col = Math.min(colCnt-1, Math.floor((ev.pageX - bg.offset().left) / colWidth)),
-				date = addDays(cloneDate(view.visStart), col*dis+dit),
-				rowMatch = this.className.match(/fc-slot(\d+)/);
-			if (rowMatch) {
-				var mins = parseInt(rowMatch[1]) * options.slotMinutes,
-					hours = Math.floor(mins/60);
-				date.setHours(hours);
-				date.setMinutes(mins%60 + minMinute);
-				view.trigger('dayClick', this, date, false, ev);
-			}else{
-				view.trigger('dayClick', this, date, true, ev);
-			}
-		}
-	}
-	
-	
-	
-	/* Event Rendering
-	-----------------------------------------------------------------------------*/
-	
-	function renderEvents(events, modifiedEventId) {
-		view.reportEvents(cachedEvents = events);
-		var i, len=events.length,
-			dayEvents=[],
-			slotEvents=[];
-		for (i=0; i<len; i++) {
-			if (events[i].allDay) {
-				dayEvents.push(events[i]);
-			}else{
-				slotEvents.push(events[i]);
-			}
-		}
-		renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);
-		renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);
-	}
-	
-	
-	function rerenderEvents(modifiedEventId) {
-		clearEvents();
-		renderEvents(cachedEvents, modifiedEventId);
-	}
-	
-	
-	function clearEvents() {
-		view._clearEvents(); // only clears the hashes
-		daySegmentContainer.empty();
-		slotSegmentContainer.empty();
-	}
-	
-	
-	
-	
-	
-	function compileDaySegs(events) {
-		var levels = stackSegs(view.sliceSegs(events, $.map(events, exclEndDay), view.visStart, view.visEnd)),
-			i, levelCnt=levels.length, level,
-			j, seg,
-			segs=[];
-		for (i=0; i<levelCnt; i++) {
-			level = levels[i];
-			for (j=0; j<level.length; j++) {
-				seg = level[j];
-				seg.row = 0;
-				seg.level = i;
-				segs.push(seg);
-			}
-		}
-		return segs;
-	}
-	
-	
-	function compileSlotSegs(events) {
-		var d = addMinutes(cloneDate(view.visStart), minMinute),
-			visEventEnds = $.map(events, slotEventEnd),
-			i, col,
-			j, level,
-			k, seg,
-			segs=[];
-		for (i=0; i<colCnt; i++) {
-			col = stackSegs(view.sliceSegs(events, visEventEnds, d, addMinutes(cloneDate(d), maxMinute-minMinute)));
-			countForwardSegs(col);
-			for (j=0; j<col.length; j++) {
-				level = col[j];
-				for (k=0; k<level.length; k++) {
-					seg = level[k];
-					seg.col = i;
-					seg.level = j;
-					segs.push(seg);
-				}
-			}
-			addDays(d, 1, true);
-		}
-		return segs;
-	}
-	
-	
-	
-	
-	// renders 'all-day' events at the top
-	
-	function renderDaySegs(segs, modifiedEventId) {
-		if (options.allDaySlot) {
-			_renderDaySegs(
-				segs,
-				1,
-				view,
-				axisWidth,
-				viewWidth,
-				function() {
-					return head.find('tr.fc-all-day');
-				},
-				function(dayOfWeek) {
-					return axisWidth + colContentPositions.left(dayOfWeekCol(dayOfWeek));
-				},
-				function(dayOfWeek) {
-					return axisWidth + colContentPositions.right(dayOfWeekCol(dayOfWeek));
-				},
-				daySegmentContainer,
-				daySegBind,
-				modifiedEventId
-			);
-			setHeight(viewHeight); // might have pushed the body down, so resize
-		}
-	}
-	
-	
-	
-	// renders events in the 'time slots' at the bottom
-	
-	function renderSlotSegs(segs, modifiedEventId) {
-	
-		var i, segCnt=segs.length, seg,
-			event,
-			className,
-			top, bottom,
-			colI, levelI, forward,
-			leftmost,
-			availWidth,
-			outerWidth,
-			left,
-			html='',
-			eventElements,
-			eventElement,
-			triggerRes,
-			vsideCache={},
-			hsideCache={},
-			key, val,
-			titleSpan,
-			height;
-			
-		// calculate position/dimensions, create html
-		for (i=0; i<segCnt; i++) {
-			seg = segs[i];
-			event = seg.event;
-			className = 'fc-event fc-event-vert ';
-			if (seg.isStart) {
-				className += 'fc-corner-top ';
-			}
-			if (seg.isEnd) {
-				className += 'fc-corner-bottom ';
-			}
-			top = timePosition(seg.start, seg.start);
-			bottom = timePosition(seg.start, seg.end);
-			colI = seg.col;
-			levelI = seg.level;
-			forward = seg.forward || 0;
-			leftmost = axisWidth + colContentPositions.left(colI*dis + dit);
-			availWidth = axisWidth + colContentPositions.right(colI*dis + dit) - leftmost;
-			availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS
-			if (levelI) {
-				// indented and thin
-				outerWidth = availWidth / (levelI + forward + 1);
-			}else{
-				if (forward) {
-					// moderately wide, aligned left still
-					outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
-				}else{
-					// can be entire width, aligned left
-					outerWidth = availWidth;
-				}
-			}
-			left = leftmost +                                  // leftmost possible
-				(availWidth / (levelI + forward + 1) * levelI) // indentation
-				* dis + (rtl ? availWidth - outerWidth : 0);   // rtl
-			seg.top = top;
-			seg.left = left;
-			seg.outerWidth = outerWidth;
-			seg.outerHeight = bottom - top;
-			html += slotSegHtml(event, seg, className);
-		}
-		slotSegmentContainer[0].innerHTML = html; // faster than html()
-		eventElements = slotSegmentContainer.children();
-		
-		// retrieve elements, run through eventRender callback, bind event handlers
-		for (i=0; i<segCnt; i++) {
-			seg = segs[i];
-			event = seg.event;
-			eventElement = $(eventElements[i]); // faster than eq()
-			triggerRes = view.trigger('eventRender', event, event, eventElement);
-			if (triggerRes === false) {
-				eventElement.remove();
-			}else{
-				if (triggerRes && triggerRes !== true) {
-					eventElement.remove();
-					eventElement = $(triggerRes)
-						.css({
-							position: 'absolute',
-							top: seg.top,
-							left: seg.left
-						})
-						.appendTo(slotSegmentContainer);
-				}
-				seg.element = eventElement;
-				if (event._id === modifiedEventId) {
-					slotSegBind(event, eventElement, seg);
-				}else{
-					eventElement[0]._fci = i; // for lazySegBind
-				}
-				view.reportEventElement(event, eventElement);
-			}
-		}
-		
-		lazySegBind(slotSegmentContainer, segs, slotSegBind);
-		
-		// record event sides and title positions
-		for (i=0; i<segCnt; i++) {
-			seg = segs[i];
-			if (eventElement = seg.element) {
-				val = vsideCache[key = seg.key = cssKey(eventElement[0])];
-				seg.vsides = val === undefined ? (vsideCache[key] = vsides(eventElement[0], true)) : val;
-				val = hsideCache[key];
-				seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
-				titleSpan = eventElement.find('span.fc-event-title');
-				if (titleSpan.length) {
-					seg.titleTop = titleSpan[0].offsetTop;
-				}
-			}
-		}
-		
-		// set all positions/dimensions at once
-		for (i=0; i<segCnt; i++) {
-			seg = segs[i];
-			if (eventElement = seg.element) {
-				eventElement[0].style.width = seg.outerWidth - seg.hsides + 'px';
-				eventElement[0].style.height = (height = seg.outerHeight - seg.vsides) + 'px';
-				event = seg.event;
-				if (seg.titleTop !== undefined && height - seg.titleTop < 10) {
-					// not enough room for title, put it in the time header
-					eventElement.find('span.fc-event-time')
-						.text(formatDate(event.start, view.option('timeFormat')) + ' - ' + event.title);
-					eventElement.find('span.fc-event-title')
-						.remove();
-				}
-				view.trigger('eventAfterRender', event, event, eventElement);
-			}
-		}
-					
-	}
-	
-	function slotSegHtml(event, seg, className) {
-		return "<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px'>" +
-			"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
-				"<span class='fc-event-bg'></span>" +
-				"<span class='fc-event-time'>" + htmlEscape(formatDates(event.start, event.end, view.option('timeFormat'))) + "</span>" +
-				"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
-			"</a>" +
-			((event.editable || event.editable === undefined && options.editable) && !options.disableResizing && $.fn.resizable ?
-				"<div class='ui-resizable-handle ui-resizable-s'>=</div>"
-				: '') +
-		"</div>";
-	}
-	
-	
-	
-	function daySegBind(event, eventElement, seg) {
-		view.eventElementHandlers(event, eventElement);
-		if (event.editable || event.editable === undefined && options.editable) {
-			draggableDayEvent(event, eventElement, seg.isStart);
-			if (seg.isEnd) {
-				view.resizableDayEvent(event, eventElement, colWidth);
-			}
-		}
-	}
-	
-	
-	
-	function slotSegBind(event, eventElement, seg) {
-		view.eventElementHandlers(event, eventElement);
-		if (event.editable || event.editable === undefined && options.editable) {
-			var timeElement = eventElement.find('span.fc-event-time');
-			draggableSlotEvent(event, eventElement, timeElement);
-			if (seg.isEnd) {
-				resizableSlotEvent(event, eventElement, timeElement);
-			}
-		}
-	}
-
-	
-	
-	
-	/* Event Dragging
-	-----------------------------------------------------------------------------*/
-	
-	
-	
-	// when event starts out FULL-DAY
-	
-	function draggableDayEvent(event, eventElement, isStart) {
-		if (!options.disableDragging && eventElement.draggable) {
-			var origWidth;
-			var allDay=true;
-			var dayDelta;
-			eventElement.draggable({
-				zIndex: 9,
-				opacity: view.option('dragOpacity', 'month'), // use whatever the month view was using
-				revertDuration: options.dragRevertDuration,
-				start: function(ev, ui) {
-					view.trigger('eventDragStart', eventElement, event, ev, ui);
-					view.hideEvents(event, eventElement);
-					origWidth = eventElement.width();
-					hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
-						eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
-						clearOverlay();
-						if (cell) {
-							dayDelta = colDelta * dis;
-							if (!cell.row) {
-								// on full-days
-								renderDayOverlay(
-									addDays(cloneDate(event.start), dayDelta),
-									addDays(exclEndDay(event), dayDelta)
-								);
-								resetElement();
-							}else{
-								// mouse is over bottom slots
-								if (isStart && allDay) {
-									// convert event to temporary slot-event
-									setOuterHeight(
-										eventElement.width(colWidth - 10), // don't use entire width
-										slotHeight * Math.round(
-											(event.end ? ((event.end - event.start) / MINUTE_MS) : options.defaultEventMinutes)
-											/ options.slotMinutes
-										)
-									);
-									eventElement.draggable('option', 'grid', [colWidth, 1]);
-									allDay = false;
-								}
-							}
-						}
-					}, ev, 'drag');
-				},
-				stop: function(ev, ui) {
-					var cell = hoverListener.stop();
-					clearOverlay();
-					view.trigger('eventDragStop', eventElement, event, ev, ui);
-					if (cell && (!allDay || dayDelta)) {
-						// changed!
-						eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
-						var minuteDelta = 0;
-						if (!allDay) {
-							minuteDelta = Math.round((eventElement.offset().top - bodyContent.offset().top) / slotHeight)
-								* options.slotMinutes
-								+ minMinute
-								- (event.start.getHours() * 60 + event.start.getMinutes());
-						}
-						view.eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);
-					}else{
-						// hasn't moved or is out of bounds (draggable has already reverted)
-						resetElement();
-						if ($.browser.msie) {
-							eventElement.css('filter', ''); // clear IE opacity side-effects
-						}
-						view.showEvents(event, eventElement);
-					}
-				}
-			});
-			function resetElement() {
-				if (!allDay) {
-					eventElement
-						.width(origWidth)
-						.height('')
-						.draggable('option', 'grid', null);
-					allDay = true;
-				}
-			}
-		}
-	}
-	
-	
-	
-	// when event starts out IN TIMESLOTS
-	
-	function draggableSlotEvent(event, eventElement, timeElement) {
-		if (!options.disableDragging && eventElement.draggable) {
-			var origPosition;
-			var allDay=false;
-			var dayDelta;
-			var minuteDelta;
-			var prevMinuteDelta;
-			eventElement.draggable({
-				zIndex: 9,
-				scroll: false,
-				grid: [colWidth, slotHeight],
-				axis: colCnt==1 ? 'y' : false,
-				opacity: view.option('dragOpacity'),
-				revertDuration: options.dragRevertDuration,
-				start: function(ev, ui) {
-					view.trigger('eventDragStart', eventElement, event, ev, ui);
-					view.hideEvents(event, eventElement);
-					if ($.browser.msie) {
-						eventElement.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
-					}
-					origPosition = eventElement.position();
-					minuteDelta = prevMinuteDelta = 0;
-					hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
-						eventElement.draggable('option', 'revert', !cell);
-						clearOverlay();
-						if (cell) {
-							dayDelta = colDelta * dis;
-							if (options.allDaySlot && !cell.row) {
-								// over full days
-								if (!allDay) {
-									// convert to temporary all-day event
-									allDay = true;
-									timeElement.hide();
-									eventElement.draggable('option', 'grid', null);
-								}
-								renderDayOverlay(
-									addDays(cloneDate(event.start), dayDelta),
-									addDays(exclEndDay(event), dayDelta)
-								);
-							}else{
-								// on slots
-								resetElement();
-							}
-						}
-					}, ev, 'drag');
-				},
-				drag: function(ev, ui) {
-					minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * options.slotMinutes;
-					if (minuteDelta != prevMinuteDelta) {
-						if (!allDay) {
-							updateTimeText(minuteDelta);
-						}
-						prevMinuteDelta = minuteDelta;
-					}
-				},
-				stop: function(ev, ui) {
-					var cell = hoverListener.stop();
-					clearOverlay();
-					view.trigger('eventDragStop', eventElement, event, ev, ui);
-					if (cell && (dayDelta || minuteDelta || allDay)) {
-						// changed!
-						view.eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);
-					}else{
-						// either no change or out-of-bounds (draggable has already reverted)
-						resetElement();
-						eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
-						updateTimeText(0);
-						if ($.browser.msie) {
-							eventElement
-								.css('filter', '') // clear IE opacity side-effects
-								.find('span.fc-event-bg')
-									.css('display', ''); // .show() made display=inline
-						}
-						view.showEvents(event, eventElement);
-					}
-				}
-			});
-			function updateTimeText(minuteDelta) {
-				var newStart = addMinutes(cloneDate(event.start), minuteDelta);
-				var newEnd;
-				if (event.end) {
-					newEnd = addMinutes(cloneDate(event.end), minuteDelta);
-				}
-				timeElement.text(formatDates(newStart, newEnd, view.option('timeFormat')));
-			}
-			function resetElement() {
-				// convert back to original slot-event
-				if (allDay) {
-					timeElement.css('display', ''); // show() was causing display=inline
-					eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
-					allDay = false;
-				}
-			}
-		}
-	}
-	
-	
-	
-	
-	/* Event Resizing
-	-----------------------------------------------------------------------------*/
-	
-	// for TIMESLOT events
-
-	function resizableSlotEvent(event, eventElement, timeElement) {
-		if (!options.disableResizing && eventElement.resizable) {
-			var slotDelta, prevSlotDelta;
-			eventElement.resizable({
-				handles: {
-					s: 'div.ui-resizable-s'
-				},
-				grid: slotHeight,
-				start: function(ev, ui) {
-					slotDelta = prevSlotDelta = 0;
-					view.hideEvents(event, eventElement);
-					if ($.browser.msie && $.browser.version == '6.0') {
-						eventElement.css('overflow', 'hidden');
-					}
-					eventElement.css('z-index', 9);
-					view.trigger('eventResizeStart', this, event, ev, ui);
-				},
-				resize: function(ev, ui) {
-					// don't rely on ui.size.height, doesn't take grid into account
-					slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
-					if (slotDelta != prevSlotDelta) {
-						timeElement.text(
-							formatDates(
-								event.start,
-								(!slotDelta && !event.end) ? null : // no change, so don't display time range
-									addMinutes(view.eventEnd(event), options.slotMinutes*slotDelta),
-								view.option('timeFormat')
-							)
-						);
-						prevSlotDelta = slotDelta;
-					}
-				},
-				stop: function(ev, ui) {
-					view.trigger('eventResizeStop', this, event, ev, ui);
-					if (slotDelta) {
-						view.eventResize(this, event, 0, options.slotMinutes*slotDelta, ev, ui);
-					}else{
-						eventElement.css('z-index', 8);
-						view.showEvents(event, eventElement);
-						// BUG: if event was really short, need to put title back in span
-					}
-				}
-			});
-		}
-	}
-	
-	
-	
-	
-	/* Coordinate Utilities
-	-----------------------------------------------------------------------------*/
-	
-	var coordinateGrid = new CoordinateGrid(function(rows, cols) {
-		var e, n, p;
-		bg.find('td').each(function(i, _e) {
-			e = $(_e);
-			n = e.offset().left;
-			if (i) {
-				p[1] = n;
-			}
-			p = [n];
-			cols[i] = p;
-		});
-		p[1] = n + e.outerWidth();
-		if (options.allDaySlot) {
-			e = head.find('td');
-			n = e.offset().top;
-			rows[0] = [n, n+e.outerHeight()];
-		}
-		var bodyContentTop = bodyContent.offset().top;
-		var bodyTop = body.offset().top;
-		var bodyBottom = bodyTop + body.outerHeight();
-		function constrain(n) {
-			return Math.max(bodyTop, Math.min(bodyBottom, n));
-		}
-		for (var i=0; i<slotCnt; i++) {
-			rows.push([
-				constrain(bodyContentTop + slotHeight*i),
-				constrain(bodyContentTop + slotHeight*(i+1))
-			]);
-		}
-	});
-	
-	var hoverListener = new HoverListener(coordinateGrid);
-	
-	// get the Y coordinate of the given time on the given day (both Date objects)
-	function timePosition(day, time) { // both date objects. day holds 00:00 of current day
-		day = cloneDate(day, true);
-		if (time < addMinutes(cloneDate(day), minMinute)) {
-			return 0;
-		}
-		if (time >= addMinutes(cloneDate(day), maxMinute)) {
-			return bodyContent.height();
-		}
-		var slotMinutes = options.slotMinutes,
-			minutes = time.getHours()*60 + time.getMinutes() - minMinute,
-			slotI = Math.floor(minutes / slotMinutes),
-			slotTop = slotTopCache[slotI];
-		if (slotTop === undefined) {
-			slotTop = slotTopCache[slotI] = body.find('tr:eq(' + slotI + ') td div')[0].offsetTop;
-		}
-		return Math.max(0, Math.round(
-			slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
-		));
-	}
-	
-	
-	
-	
-	/* Selecting
-	-----------------------------------------------------------------------------*/
-	
-	var selected = false;
-	var daySelectionMousedown = selection_dayMousedown(
-		view, hoverListener, cellDate, cellIsAllDay, renderDayOverlay, clearOverlay, reportSelection, unselect
-	);
-	
-	function slotSelectionMousedown(ev) {
-		if (view.option('selectable')) {
-			unselect(ev);
-			var _mousedownElement = this;
-			var dates;
-			hoverListener.start(function(cell, origCell) {
-				clearSelection();
-				if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) {
-					var d1 = cellDate(origCell);
-					var d2 = cellDate(cell);
-					dates = [
-						d1,
-						addMinutes(cloneDate(d1), options.slotMinutes),
-						d2,
-						addMinutes(cloneDate(d2), options.slotMinutes)
-					].sort(cmp);
-					renderSlotSelection(dates[0], dates[3]);
-				}else{
-					dates = null;
-				}
-			}, ev);
-			$(document).one('mouseup', function(ev) {
-				hoverListener.stop();
-				if (dates) {
-					if (+dates[0] == +dates[1]) {
-						view.trigger('dayClick', _mousedownElement, dates[0], false, ev);
-						// BUG: _mousedownElement will sometimes be the overlay
-					}
-					reportSelection(dates[0], dates[3], false, ev);
-				}
-			});
-		}
-	}
-	
-	view.select = function(startDate, endDate, allDay) {
-		coordinateGrid.build();
-		unselect();
-		if (allDay) {
-			if (options.allDaySlot) {
-				if (!endDate) {
-					endDate = cloneDate(startDate);
-				}
-				renderDayOverlay(startDate, addDays(cloneDate(endDate), 1));
-			}
-		}else{
-			if (!endDate) {
-				endDate = addMinutes(cloneDate(startDate), options.slotMinutes);
-			}
-			renderSlotSelection(startDate, endDate);
-		}
-		reportSelection(startDate, endDate, allDay);
-	};
-	
-	function reportSelection(startDate, endDate, allDay, ev) {
-		selected = true;
-		view.trigger('select', view, startDate, endDate, allDay, ev);
-	}
-	
-	function unselect(ev) {
-		if (selected) {
-			clearSelection();
-			selected = false;
-			view.trigger('unselect', view, ev);
-		}
-	}
-	view.unselect = unselect;
-	
-	selection_unselectAuto(view, unselect);
-	
-	
-	
-	
-	/* Selecting drawing utils
-	-----------------------------------------------------------------------------*/
-	
-	var selectionHelper;
-	
-	function renderSlotSelection(startDate, endDate) {
-		var helperOption = view.option('selectHelper');
-		if (helperOption) {
-			var col = dayDiff(startDate, view.visStart) * dis + dit;
-			if (col >= 0 && col < colCnt) { // only works when times are on same day
-				var rect = coordinateGrid.rect(0, col, 0, col, bodyContent); // only for horizontal coords
-				var top = timePosition(startDate, startDate);
-				var bottom = timePosition(startDate, endDate);
-				if (bottom > top) { // protect against selections that are entirely before or after visible range
-					rect.top = top;
-					rect.height = bottom - top;
-					rect.left += 2;
-					rect.width -= 5;
-					if ($.isFunction(helperOption)) {
-						var helperRes = helperOption(startDate, endDate);
-						if (helperRes) {
-							rect.position = 'absolute';
-							rect.zIndex = 8;
-							selectionHelper = $(helperRes)
-								.css(rect)
-								.appendTo(bodyContent);
-						}
-					}else{
-						selectionHelper = $(slotSegHtml(
-							{
-								title: '',
-								start: startDate,
-								end: endDate,
-								className: [],
-								editable: false
-							},
-							rect,
-							'fc-event fc-event-vert fc-corner-top fc-corner-bottom '
-						));
-						if ($.browser.msie) {
-							selectionHelper.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
-						}
-						selectionHelper.css('opacity', view.option('dragOpacity'));
-					}
-					if (selectionHelper) {
-						slotBind(selectionHelper);
-						bodyContent.append(selectionHelper);
-						setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended
-						setOuterHeight(selectionHelper, rect.height, true);
-					}
-				}
-			}
-		}else{
-			renderSlotOverlay(startDate, endDate);
-		}
-	}
-	
-	function clearSelection() {
-		clearOverlay();
-		if (selectionHelper) {
-			selectionHelper.remove();
-			selectionHelper = null;
-		}
-	}
-	
-	
-	
-	
-	/* Semi-transparent Overlay Helpers
-	-----------------------------------------------------*/
-
-	function renderDayOverlay(startDate, endDate) {
-		var startCol, endCol;
-		if (rtl) {
-			startCol = dayDiff(endDate, view.visStart)*dis+dit+1;
-			endCol = dayDiff(startDate, view.visStart)*dis+dit+1;
-		}else{
-			startCol = dayDiff(startDate, view.visStart);
-			endCol = dayDiff(endDate, view.visStart);
-		}
-		startCol = Math.max(0, startCol);
-		endCol = Math.min(colCnt, endCol);
-		if (startCol < endCol) {
-			dayBind(
-				_renderDayOverlay(0, startCol, 0, endCol-1)
-			);
-		}
-	}
-	
-	function _renderDayOverlay(col0, row0, col1, row1) {
-		var rect = coordinateGrid.rect(col0, row0, col1, row1, head);
-		return view.renderOverlay(rect, head);
-	}
-
-	function renderSlotOverlay(overlayStart, overlayEnd) {
-		var dayStart = cloneDate(view.visStart);
-		var dayEnd = addDays(cloneDate(dayStart), 1);
-		for (var i=0; i<colCnt; i++) {
-			var stretchStart = new Date(Math.max(dayStart, overlayStart));
-			var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));
-			if (stretchStart < stretchEnd) {
-				var col = i*dis+dit;
-				var rect = coordinateGrid.rect(0, col, 0, col, bodyContent); // only use it for horizontal coords
-				var top = timePosition(dayStart, stretchStart);
-				var bottom = timePosition(dayStart, stretchEnd);
-				rect.top = top;
-				rect.height = bottom - top;
-				slotBind(
-					view.renderOverlay(rect, bodyContent)
-				);
-			}
-			addDays(dayStart, 1);
-			addDays(dayEnd, 1);
-		}
-	}
-	
-	function clearOverlay() {
-		view.clearOverlays();
-	}
-	
-	
-	
-	
-	/* External dragging
-	-----------------------------------------------------*/
-	
-	view.dragStart = function(_dragElement, ev, ui) {
-		hoverListener.start(function(cell) {
-			clearOverlay();
-			if (cell) {
-				if (cellIsAllDay(cell)) {
-					_renderDayOverlay(cell.row, cell.col, cell.row, cell.col);
-				}else{
-					var d1 = cellDate(cell);
-					var d2 = addMinutes(cloneDate(d1), options.defaultEventMinutes);
-					renderSlotOverlay(d1, d2);
-				}
-			}
-		}, ev);
-	};
-	
-	view.dragStop = function(_dragElement, ev, ui) {
-		var cell = hoverListener.stop();
-		clearOverlay();
-		if (cell) {
-			view.trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui);
-		}
-	};
-	
-	
-	
-	
-	/* Date Utilities
-	----------------------------------------------------*/
-	
-	function slotEventEnd(event) {
-		if (event.end) {
-			return cloneDate(event.end);
-		}else{
-			return addMinutes(cloneDate(event.start), options.defaultEventMinutes);
-		}
-	}
-	
-	function dayOfWeekCol(dayOfWeek) {
-		return ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt)*dis+dit;
-	}
-	
-	function cellDate(cell) {
-		var d = addDays(cloneDate(view.visStart), cell.col*dis+dit);
-		var slotIndex = cell.row;
-		if (options.allDaySlot) {
-			slotIndex--;
-		}
-		if (slotIndex >= 0) {
-			addMinutes(d, minMinute + slotIndex*options.slotMinutes);
-		}
-		return d;
-	}
-	
-	function cellIsAllDay(cell) {
-		return options.allDaySlot && !cell.row;
-	}
-	
-	
-
-}
-
-
-// count the number of colliding, higher-level segments (for event squishing)
-
-function countForwardSegs(levels) {
-	var i, j, k, level, segForward, segBack;
-	for (i=levels.length-1; i>0; i--) {
-		level = levels[i];
-		for (j=0; j<level.length; j++) {
-			segForward = level[j];
-			for (k=0; k<levels[i-1].length; k++) {
-				segBack = levels[i-1][k];
-				if (segsCollide(segForward, segBack)) {
-					segBack.forward = Math.max(segBack.forward||0, (segForward.forward||0)+1);
-				}
-			}
-		}
-	}
-}
-

+ 36 - 0
src/agenda/AgendaDayView.js

@@ -0,0 +1,36 @@
+
+fcViews.agendaDay = AgendaDayView;
+
+function AgendaDayView(element, calendar) {
+	var t = this;
+	
+	
+	// exports
+	t.render = render;
+	
+	
+	// imports
+	AgendaView.call(t, element, calendar, 'agendaDay');
+	var opt = t.opt;
+	var renderAgenda = t.renderAgenda;
+	var formatDate = calendar.formatDate;
+	
+	
+	
+	function render(date, delta) {
+		if (delta) {
+			addDays(date, delta);
+			if (!opt('weekends')) {
+				skipWeekend(date, delta < 0 ? -1 : 1);
+			}
+		}
+		var start = cloneDate(date, true);
+		var end = addDays(cloneDate(start), 1);
+		t.title = formatDate(date, opt('titleFormat'));
+		t.start = t.visStart = start;
+		t.end = t.visEnd = end;
+		renderAgenda(1);
+	}
+	
+
+}

+ 595 - 0
src/agenda/AgendaEventRenderer.js

@@ -0,0 +1,595 @@
+
+function AgendaEventRenderer() {
+	var t = this;
+	
+	
+	// exports
+	t.renderEvents = renderEvents;
+	t.rerenderEvents = rerenderEvents;
+	t.clearEvents = clearEvents;
+	t.slotSegHtml = slotSegHtml;
+	t.bindDaySeg = bindDaySeg;
+	
+	
+	// imports
+	DayEventRenderer.call(t);
+	var opt = t.opt;
+	var trigger = t.trigger;
+	var eventEnd = t.eventEnd;
+	var reportEvents = t.reportEvents;
+	var clearEventData = t.clearEventData;
+	var eventElementHandlers = t.eventElementHandlers;
+	var setHeight = t.setHeight;
+	var getDaySegmentContainer = t.getDaySegmentContainer;
+	var getSlotSegmentContainer = t.getSlotSegmentContainer;
+	var getHoverListener = t.getHoverListener;
+	var getMaxMinute = t.getMaxMinute;
+	var getMinMinute = t.getMinMinute;
+	var timePosition = t.timePosition;
+	var colContentLeft = t.colContentLeft;
+	var colContentRight = t.colContentRight;
+	var renderDaySegs = t.renderDaySegs;
+	var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecture
+	var getColCnt = t.getColCnt;
+	var getColWidth = t.getColWidth;
+	var getSlotHeight = t.getSlotHeight;
+	var getBodyContent = t.getBodyContent;
+	var reportEventElement = t.reportEventElement;
+	var showEvents = t.showEvents;
+	var hideEvents = t.hideEvents;
+	var eventDrop = t.eventDrop;
+	var eventResize = t.eventResize;
+	var renderDayOverlay = t.renderDayOverlay;
+	var clearOverlays = t.clearOverlays;
+	var calendar = t.calendar;
+	var formatDate = calendar.formatDate;
+	var formatDates = calendar.formatDates;
+	
+	
+	
+	/* Rendering
+	----------------------------------------------------------------------------*/
+	
+	
+	var cachedEvents = [];
+	
+
+	function renderEvents(events, modifiedEventId) {
+		reportEvents(cachedEvents = events);
+		var i, len=events.length,
+			dayEvents=[],
+			slotEvents=[];
+		for (i=0; i<len; i++) {
+			if (events[i].allDay) {
+				dayEvents.push(events[i]);
+			}else{
+				slotEvents.push(events[i]);
+			}
+		}
+		if (opt('allDaySlot')) {
+			renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);
+			setHeight(); // no params means set to viewHeight
+		}
+		renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);
+	}
+	
+	
+	function rerenderEvents(modifiedEventId) {
+		clearEvents();
+		renderEvents(cachedEvents, modifiedEventId);
+	}
+	
+	
+	function clearEvents() {
+		clearEventData();
+		getDaySegmentContainer().empty();
+		getSlotSegmentContainer().empty();
+	}
+	
+	
+	function compileDaySegs(events) {
+		var levels = stackSegs(sliceSegs(events, $.map(events, exclEndDay), t.visStart, t.visEnd)),
+			i, levelCnt=levels.length, level,
+			j, seg,
+			segs=[];
+		for (i=0; i<levelCnt; i++) {
+			level = levels[i];
+			for (j=0; j<level.length; j++) {
+				seg = level[j];
+				seg.row = 0;
+				seg.level = i;
+				segs.push(seg);
+			}
+		}
+		return segs;
+	}
+	
+	
+	function compileSlotSegs(events) {
+		var colCnt = getColCnt(),
+			minMinute = getMinMinute(),
+			maxMinute = getMaxMinute(),
+			d = addMinutes(cloneDate(t.visStart), minMinute),
+			visEventEnds = $.map(events, slotEventEnd),
+			i, col,
+			j, level,
+			k, seg,
+			segs=[];
+		for (i=0; i<colCnt; i++) {
+			col = stackSegs(sliceSegs(events, visEventEnds, d, addMinutes(cloneDate(d), maxMinute-minMinute)));
+			countForwardSegs(col);
+			for (j=0; j<col.length; j++) {
+				level = col[j];
+				for (k=0; k<level.length; k++) {
+					seg = level[k];
+					seg.col = i;
+					seg.level = j;
+					segs.push(seg);
+				}
+			}
+			addDays(d, 1, true);
+		}
+		return segs;
+	}
+	
+	
+	function slotEventEnd(event) {
+		if (event.end) {
+			return cloneDate(event.end);
+		}else{
+			return addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));
+		}
+	}
+	
+	
+	// renders events in the 'time slots' at the bottom
+	
+	function renderSlotSegs(segs, modifiedEventId) {
+	
+		var i, segCnt=segs.length, seg,
+			event,
+			className,
+			top, bottom,
+			colI, levelI, forward,
+			leftmost,
+			availWidth,
+			outerWidth,
+			left,
+			html='',
+			eventElements,
+			eventElement,
+			triggerRes,
+			vsideCache={},
+			hsideCache={},
+			key, val,
+			titleSpan,
+			height,
+			slotSegmentContainer = getSlotSegmentContainer(),
+			rtl, dis, dit,
+			colCnt = getColCnt();
+			
+		if (rtl = opt('isRTL')) {
+			dis = -1;
+			dit = colCnt - 1;
+		}else{
+			dis = 1;
+			dit = 0;
+		}
+			
+		// calculate position/dimensions, create html
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			event = seg.event;
+			className = 'fc-event fc-event-vert ';
+			if (seg.isStart) {
+				className += 'fc-corner-top ';
+			}
+			if (seg.isEnd) {
+				className += 'fc-corner-bottom ';
+			}
+			top = timePosition(seg.start, seg.start);
+			bottom = timePosition(seg.start, seg.end);
+			colI = seg.col;
+			levelI = seg.level;
+			forward = seg.forward || 0;
+			leftmost = colContentLeft(colI*dis + dit);
+			availWidth = colContentRight(colI*dis + dit) - leftmost;
+			availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS
+			if (levelI) {
+				// indented and thin
+				outerWidth = availWidth / (levelI + forward + 1);
+			}else{
+				if (forward) {
+					// moderately wide, aligned left still
+					outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
+				}else{
+					// can be entire width, aligned left
+					outerWidth = availWidth;
+				}
+			}
+			left = leftmost +                                  // leftmost possible
+				(availWidth / (levelI + forward + 1) * levelI) // indentation
+				* dis + (rtl ? availWidth - outerWidth : 0);   // rtl
+			seg.top = top;
+			seg.left = left;
+			seg.outerWidth = outerWidth;
+			seg.outerHeight = bottom - top;
+			html += slotSegHtml(event, seg, className);
+		}
+		slotSegmentContainer[0].innerHTML = html; // faster than html()
+		eventElements = slotSegmentContainer.children();
+		
+		// retrieve elements, run through eventRender callback, bind event handlers
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			event = seg.event;
+			eventElement = $(eventElements[i]); // faster than eq()
+			triggerRes = trigger('eventRender', event, event, eventElement);
+			if (triggerRes === false) {
+				eventElement.remove();
+			}else{
+				if (triggerRes && triggerRes !== true) {
+					eventElement.remove();
+					eventElement = $(triggerRes)
+						.css({
+							position: 'absolute',
+							top: seg.top,
+							left: seg.left
+						})
+						.appendTo(slotSegmentContainer);
+				}
+				seg.element = eventElement;
+				if (event._id === modifiedEventId) {
+					bindSlotSeg(event, eventElement, seg);
+				}else{
+					eventElement[0]._fci = i; // for lazySegBind
+				}
+				reportEventElement(event, eventElement);
+			}
+		}
+		
+		lazySegBind(slotSegmentContainer, segs, bindSlotSeg);
+		
+		// record event sides and title positions
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			if (eventElement = seg.element) {
+				val = vsideCache[key = seg.key = cssKey(eventElement[0])];
+				seg.vsides = val === undefined ? (vsideCache[key] = vsides(eventElement[0], true)) : val;
+				val = hsideCache[key];
+				seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
+				titleSpan = eventElement.find('span.fc-event-title');
+				if (titleSpan.length) {
+					seg.titleTop = titleSpan[0].offsetTop;
+				}
+			}
+		}
+		
+		// set all positions/dimensions at once
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			if (eventElement = seg.element) {
+				eventElement[0].style.width = seg.outerWidth - seg.hsides + 'px';
+				eventElement[0].style.height = (height = seg.outerHeight - seg.vsides) + 'px';
+				event = seg.event;
+				if (seg.titleTop !== undefined && height - seg.titleTop < 10) {
+					// not enough room for title, put it in the time header
+					eventElement.find('span.fc-event-time')
+						.text(formatDate(event.start, opt('timeFormat')) + ' - ' + event.title);
+					eventElement.find('span.fc-event-title')
+						.remove();
+				}
+				trigger('eventAfterRender', event, event, eventElement);
+			}
+		}
+					
+	}
+	
+	
+	function slotSegHtml(event, seg, className) {
+		return "<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px'>" +
+			"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
+				"<span class='fc-event-bg'></span>" +
+				"<span class='fc-event-time'>" + htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + "</span>" +
+				"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
+			"</a>" +
+			((event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
+				"<div class='ui-resizable-handle ui-resizable-s'>=</div>"
+				: '') +
+		"</div>";
+	}
+	
+	
+	function bindDaySeg(event, eventElement, seg) {
+		eventElementHandlers(event, eventElement);
+		if (event.editable || event.editable === undefined && opt('editable')) {
+			draggableDayEvent(event, eventElement, seg.isStart);
+			if (seg.isEnd) {
+				resizableDayEvent(event, eventElement, getColWidth());
+			}
+		}
+	}
+	
+	
+	function bindSlotSeg(event, eventElement, seg) {
+		eventElementHandlers(event, eventElement);
+		if (event.editable || event.editable === undefined && opt('editable')) {
+			var timeElement = eventElement.find('span.fc-event-time');
+			draggableSlotEvent(event, eventElement, timeElement);
+			if (seg.isEnd) {
+				resizableSlotEvent(event, eventElement, timeElement);
+			}
+		}
+	}
+	
+	
+	
+	/* Dragging
+	-----------------------------------------------------------------------------------*/
+	
+	
+	// when event starts out FULL-DAY
+	
+	function draggableDayEvent(event, eventElement, isStart) {
+		if (!opt('disableDragging') && eventElement.draggable) {
+			var origWidth;
+			var allDay=true;
+			var dayDelta;
+			var dis = opt('isRTL') ? -1 : 1;
+			var hoverListener = getHoverListener();
+			var colWidth = getColWidth();
+			var slotHeight = getSlotHeight();
+			var minMinute = getMinMinute();
+			eventElement.draggable({
+				zIndex: 9,
+				opacity: opt('dragOpacity', 'month'), // use whatever the month view was using
+				revertDuration: opt('dragRevertDuration'),
+				start: function(ev, ui) {
+					trigger('eventDragStart', eventElement, event, ev, ui);
+					hideEvents(event, eventElement);
+					origWidth = eventElement.width();
+					hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
+						eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
+						clearOverlays();
+						if (cell) {
+							dayDelta = colDelta * dis;
+							if (!cell.row) {
+								// on full-days
+								renderDayOverlay(
+									addDays(cloneDate(event.start), dayDelta),
+									addDays(exclEndDay(event), dayDelta)
+								);
+								resetElement();
+							}else{
+								// mouse is over bottom slots
+								if (isStart && allDay) {
+									// convert event to temporary slot-event
+									setOuterHeight(
+										eventElement.width(colWidth - 10), // don't use entire width
+										slotHeight * Math.round(
+											(event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))
+											/ opt('slotMinutes')
+										)
+									);
+									eventElement.draggable('option', 'grid', [colWidth, 1]);
+									allDay = false;
+								}
+							}
+						}
+					}, ev, 'drag');
+				},
+				stop: function(ev, ui) {
+					var cell = hoverListener.stop();
+					clearOverlays();
+					trigger('eventDragStop', eventElement, event, ev, ui);
+					if (cell && (!allDay || dayDelta)) {
+						// changed!
+						eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
+						var minuteDelta = 0;
+						if (!allDay) {
+							minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight)
+								* opt('slotMinutes')
+								+ minMinute
+								- (event.start.getHours() * 60 + event.start.getMinutes());
+						}
+						eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);
+					}else{
+						// hasn't moved or is out of bounds (draggable has already reverted)
+						resetElement();
+						if ($.browser.msie) {
+							eventElement.css('filter', ''); // clear IE opacity side-effects
+						}
+						showEvents(event, eventElement);
+					}
+				}
+			});
+			function resetElement() {
+				if (!allDay) {
+					eventElement
+						.width(origWidth)
+						.height('')
+						.draggable('option', 'grid', null);
+					allDay = true;
+				}
+			}
+		}
+	}
+	
+	
+	// when event starts out IN TIMESLOTS
+	
+	function draggableSlotEvent(event, eventElement, timeElement) {
+		if (!opt('disableDragging') && eventElement.draggable) {
+			var origPosition;
+			var allDay=false;
+			var dayDelta;
+			var minuteDelta;
+			var prevMinuteDelta;
+			var dis = opt('isRTL') ? -1 : 1;
+			var hoverListener = getHoverListener();
+			var colCnt = getColCnt();
+			var colWidth = getColWidth();
+			var slotHeight = getSlotHeight();
+			eventElement.draggable({
+				zIndex: 9,
+				scroll: false,
+				grid: [colWidth, slotHeight],
+				axis: colCnt==1 ? 'y' : false,
+				opacity: opt('dragOpacity'),
+				revertDuration: opt('dragRevertDuration'),
+				start: function(ev, ui) {
+					trigger('eventDragStart', eventElement, event, ev, ui);
+					hideEvents(event, eventElement);
+					if ($.browser.msie) {
+						eventElement.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
+					}
+					origPosition = eventElement.position();
+					minuteDelta = prevMinuteDelta = 0;
+					hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
+						eventElement.draggable('option', 'revert', !cell);
+						clearOverlays();
+						if (cell) {
+							dayDelta = colDelta * dis;
+							if (opt('allDaySlot') && !cell.row) {
+								// over full days
+								if (!allDay) {
+									// convert to temporary all-day event
+									allDay = true;
+									timeElement.hide();
+									eventElement.draggable('option', 'grid', null);
+								}
+								renderDayOverlay(
+									addDays(cloneDate(event.start), dayDelta),
+									addDays(exclEndDay(event), dayDelta)
+								);
+							}else{
+								// on slots
+								resetElement();
+							}
+						}
+					}, ev, 'drag');
+				},
+				drag: function(ev, ui) {
+					minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes');
+					if (minuteDelta != prevMinuteDelta) {
+						if (!allDay) {
+							updateTimeText(minuteDelta);
+						}
+						prevMinuteDelta = minuteDelta;
+					}
+				},
+				stop: function(ev, ui) {
+					var cell = hoverListener.stop();
+					clearOverlays();
+					trigger('eventDragStop', eventElement, event, ev, ui);
+					if (cell && (dayDelta || minuteDelta || allDay)) {
+						// changed!
+						eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);
+					}else{
+						// either no change or out-of-bounds (draggable has already reverted)
+						resetElement();
+						eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
+						updateTimeText(0);
+						if ($.browser.msie) {
+							eventElement
+								.css('filter', '') // clear IE opacity side-effects
+								.find('span.fc-event-bg')
+									.css('display', ''); // .show() made display=inline
+						}
+						showEvents(event, eventElement);
+					}
+				}
+			});
+			function updateTimeText(minuteDelta) {
+				var newStart = addMinutes(cloneDate(event.start), minuteDelta);
+				var newEnd;
+				if (event.end) {
+					newEnd = addMinutes(cloneDate(event.end), minuteDelta);
+				}
+				timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));
+			}
+			function resetElement() {
+				// convert back to original slot-event
+				if (allDay) {
+					timeElement.css('display', ''); // show() was causing display=inline
+					eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
+					allDay = false;
+				}
+			}
+		}
+	}
+	
+	
+	
+	/* Resizing
+	--------------------------------------------------------------------------------------*/
+	
+	
+	function resizableSlotEvent(event, eventElement, timeElement) {
+		if (!opt('disableResizing') && eventElement.resizable) {
+			var slotDelta, prevSlotDelta;
+			var slotHeight = getSlotHeight();
+			eventElement.resizable({
+				handles: {
+					s: 'div.ui-resizable-s'
+				},
+				grid: slotHeight,
+				start: function(ev, ui) {
+					slotDelta = prevSlotDelta = 0;
+					hideEvents(event, eventElement);
+					if ($.browser.msie && $.browser.version == '6.0') {
+						eventElement.css('overflow', 'hidden');
+					}
+					eventElement.css('z-index', 9);
+					trigger('eventResizeStart', this, event, ev, ui);
+				},
+				resize: function(ev, ui) {
+					// don't rely on ui.size.height, doesn't take grid into account
+					slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
+					if (slotDelta != prevSlotDelta) {
+						timeElement.text(
+							formatDates(
+								event.start,
+								(!slotDelta && !event.end) ? null : // no change, so don't display time range
+									addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),
+								opt('timeFormat')
+							)
+						);
+						prevSlotDelta = slotDelta;
+					}
+				},
+				stop: function(ev, ui) {
+					trigger('eventResizeStop', this, event, ev, ui);
+					if (slotDelta) {
+						eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui);
+					}else{
+						eventElement.css('z-index', 8);
+						showEvents(event, eventElement);
+						// BUG: if event was really short, need to put title back in span
+					}
+				}
+			});
+		}
+	}
+	
+
+}
+
+
+function countForwardSegs(levels) {
+	var i, j, k, level, segForward, segBack;
+	for (i=levels.length-1; i>0; i--) {
+		level = levels[i];
+		for (j=0; j<level.length; j++) {
+			segForward = level[j];
+			for (k=0; k<levels[i-1].length; k++) {
+				segBack = levels[i-1][k];
+				if (segsCollide(segForward, segBack)) {
+					segBack.forward = Math.max(segBack.forward||0, (segForward.forward||0)+1);
+				}
+			}
+		}
+	}
+}
+
+

+ 716 - 0
src/agenda/AgendaView.js

@@ -0,0 +1,716 @@
+
+setDefaults({
+	allDaySlot: true,
+	allDayText: 'all-day',
+	firstHour: 6,
+	slotMinutes: 30,
+	defaultEventMinutes: 120,
+	axisFormat: 'h(:mm)tt',
+	timeFormat: {
+		agenda: 'h:mm{ - h:mm}'
+	},
+	dragOpacity: {
+		agenda: .5
+	},
+	minTime: 0,
+	maxTime: 24
+});
+
+
+function AgendaView(element, calendar, viewName) {
+	var t = this;
+	
+	
+	// exports
+	t.renderAgenda = renderAgenda;
+	t.setWidth = setWidth;
+	t.setHeight = setHeight;
+	t.beforeHide = beforeHide;
+	t.afterShow = afterShow;
+	t.defaultEventEnd = defaultEventEnd;
+	t.timePosition = timePosition;
+	t.dayOfWeekCol = dayOfWeekCol;
+	t.cellDate = cellDate;
+	t.cellIsAllDay = cellIsAllDay;
+	t.allDayTR = allDayTR;
+	t.allDayBounds = allDayBounds;
+	t.getHoverListener = function() { return hoverListener };
+	t.colContentLeft = colContentLeft;
+	t.colContentRight = colContentRight;
+	t.getDaySegmentContainer = function() { return daySegmentContainer };
+	t.getSlotSegmentContainer = function() { return slotSegmentContainer };
+	t.getMinMinute = function() { return minMinute };
+	t.getMaxMinute = function() { return maxMinute };
+	t.getBodyContent = function() { return bodyContent };
+	t.getRowCnt = function() { return 1 };
+	t.getColCnt = function() { return colCnt };
+	t.getColWidth = function() { return colWidth };
+	t.getSlotHeight = function() { return slotHeight };
+	t.defaultSelectionEnd = defaultSelectionEnd;
+	t.renderDayOverlay = renderDayOverlay;
+	t.renderSelection = renderSelection;
+	t.clearSelection = clearSelection;
+	t.dragStart = dragStart;
+	t.dragStop = dragStop;
+	
+	
+	// imports
+	View.call(t, element, calendar, viewName);
+	OverlayManager.call(t);
+	SelectionManager.call(t);
+	AgendaEventRenderer.call(t);
+	var opt = t.opt;
+	var trigger = t.trigger;
+	var clearEvents = t.clearEvents;
+	var renderOverlay = t.renderOverlay;
+	var clearOverlays = t.clearOverlays;
+	var reportSelection = t.reportSelection;
+	var unselect = t.unselect;
+	var daySelectionMousedown = t.daySelectionMousedown;
+	var slotSegHtml = t.slotSegHtml;
+	var formatDate = calendar.formatDate;
+	
+	
+	// locals
+	var head, body, bodyContent, bodyTable, bg;
+	var colCnt;
+	var slotCnt=0; // spanning all the way across
+	var axisWidth, colWidth, slotHeight;
+	var viewWidth, viewHeight;
+	var savedScrollTop;
+	var tm, firstDay;
+	var nwe;            // no weekends (int)
+	var rtl, dis, dit;  // day index sign / translate
+	var minMinute, maxMinute;
+	var coordinateGrid;
+	var hoverListener;
+	var colContentPositions;
+	var slotTopCache = {};
+	var selectionHelper;
+	var daySegmentContainer;
+	var slotSegmentContainer;
+	
+
+	
+	/* Rendering
+	-----------------------------------------------------------------------------*/
+	
+	
+	disableTextSelection(element.addClass('fc-agenda'));
+	
+	
+	function renderAgenda(c) {
+	
+		colCnt = c;
+		
+		// update option-derived variables
+		tm = opt('theme') ? 'ui' : 'fc';
+		nwe = opt('weekends') ? 0 : 1;
+		firstDay = opt('firstDay');
+		if (rtl = opt('isRTL')) {
+			dis = -1;
+			dit = colCnt - 1;
+		}else{
+			dis = 1;
+			dit = 0;
+		}
+		minMinute = parseTime(opt('minTime'));
+		maxMinute = parseTime(opt('maxTime'));
+		
+		var d0 = rtl ? addDays(cloneDate(t.visEnd), -1) : cloneDate(t.visStart),
+			d = cloneDate(d0),
+			today = clearTime(new Date()),
+			colFormat = opt('columnFormat');
+		
+		if (!head) { // first time rendering, build from scratch
+		
+			var i,
+				minutes,
+				slotNormal = opt('slotMinutes') % 15 == 0, //...
+			
+			// head
+			s = "<div class='fc-agenda-head' style='position:relative;z-index:4'>" +
+				"<table style='width:100%'>" +
+				"<tr class='fc-first" + (opt('allDaySlot') ? '' : ' fc-last') + "'>" +
+				"<th class='fc-leftmost " +
+					tm + "-state-default'>&nbsp;</th>";
+			for (i=0; i<colCnt; i++) {
+				s += "<th class='fc-" +
+					dayIDs[d.getDay()] + ' ' + // needs to be first
+					tm + '-state-default' +
+					"'>" + formatDate(d, colFormat) + "</th>";
+				addDays(d, dis);
+				if (nwe) {
+					skipWeekend(d, dis);
+				}
+			}
+			s += "<th class='" + tm + "-state-default'>&nbsp;</th></tr>";
+			if (opt('allDaySlot')) {
+				s += "<tr class='fc-all-day'>" +
+						"<th class='fc-axis fc-leftmost " + tm + "-state-default'>" + opt('allDayText') + "</th>" +
+						"<td colspan='" + colCnt + "' class='" + tm + "-state-default'>" +
+							"<div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div></td>" +
+						"<th class='" + tm + "-state-default'>&nbsp;</th>" +
+					"</tr><tr class='fc-divider fc-last'><th colspan='" + (colCnt+2) + "' class='" +
+						tm + "-state-default fc-leftmost'><div/></th></tr>";
+			}
+			s+= "</table></div>";
+			head = $(s).appendTo(element);
+			dayBind(head.find('td'));
+			
+			// all-day event container
+			daySegmentContainer = $("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(head);
+			
+			// body
+			d = zeroDate();
+			var maxd = addMinutes(cloneDate(d), maxMinute);
+			addMinutes(d, minMinute);
+			s = "<table>";
+			for (i=0; d < maxd; i++) {
+				minutes = d.getMinutes();
+				s += "<tr class='" +
+					(!i ? 'fc-first' : (!minutes ? '' : 'fc-minor')) +
+					"'><th class='fc-axis fc-leftmost " + tm + "-state-default'>" +
+					((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : '&nbsp;') + 
+					"</th><td class='fc-slot" + i + ' ' +
+						tm + "-state-default'><div style='position:relative'>&nbsp;</div></td></tr>";
+				addMinutes(d, opt('slotMinutes'));
+				slotCnt++;
+			}
+			s += "</table>";
+			body = $("<div class='fc-agenda-body' style='position:relative;z-index:2;overflow:auto'/>")
+				.append(bodyContent = $("<div style='position:relative;overflow:hidden'>")
+					.append(bodyTable = $(s)))
+				.appendTo(element);
+			slotBind(body.find('td'));
+			
+			// slot event container
+			slotSegmentContainer = $("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(bodyContent);
+			
+			// background stripes
+			d = cloneDate(d0);
+			s = "<div class='fc-agenda-bg' style='position:absolute;z-index:1'>" +
+				"<table style='width:100%;height:100%'><tr class='fc-first'>";
+			for (i=0; i<colCnt; i++) {
+				s += "<td class='fc-" +
+					dayIDs[d.getDay()] + ' ' + // needs to be first
+					tm + '-state-default ' +
+					(!i ? 'fc-leftmost ' : '') +
+					(+d == +today ? tm + '-state-highlight fc-today' : 'fc-not-today') +
+					"'><div class='fc-day-content'><div>&nbsp;</div></div></td>";
+				addDays(d, dis);
+				if (nwe) {
+					skipWeekend(d, dis);
+				}
+			}
+			s += "</tr></table></div>";
+			bg = $(s).appendTo(element);
+			
+		}else{ // skeleton already built, just modify it
+		
+			clearEvents();
+			
+			// redo column header text and class
+			head.find('tr:first th').slice(1, -1).each(function(i, th) {
+				$(th).text(formatDate(d, colFormat));
+				th.className = th.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
+				addDays(d, dis);
+				if (nwe) {
+					skipWeekend(d, dis);
+				}
+			});
+			
+			// change classes of background stripes
+			d = cloneDate(d0);
+			bg.find('td').each(function(i, td) {
+				td.className = td.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
+				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');
+				}
+				addDays(d, dis);
+				if (nwe) {
+					skipWeekend(d, dis);
+				}
+			});
+		
+		}
+		
+	}
+	
+	
+	
+	function setHeight(height, dateChanged) {
+	
+		if (height === undefined) {
+			height = viewHeight;
+		}
+		
+		viewHeight = height;
+		slotTopCache = {};
+		
+		body.height(height - head.height());
+		
+		slotHeight = body.find('tr:first div').height() + 1;
+		
+		bg.css({
+			top: head.find('tr').height(),
+			height: height
+		});
+		
+		// if the table ends up shorter than the allotted view, shrink the view to fit the table
+		var tableHeight = body.find('table:first').height();
+		if (tableHeight < body.height()) {
+			body.height(tableHeight);
+		}
+		
+		if (dateChanged) {
+			resetScroll();
+		}
+	}
+	
+	
+	
+	function setWidth(width) {
+		viewWidth = width;
+		colContentPositions.clear();
+		
+		body.width(width);
+		bodyTable.width('');
+		
+		var topTDs = head.find('tr:first th'),
+			stripeTDs = bg.find('td'),
+			clientWidth = body[0].clientWidth;
+			
+		bodyTable.width(clientWidth);
+		
+		// time-axis width
+		axisWidth = 0;
+		setOuterWidth(
+			head.find('tr:lt(2) th:first').add(body.find('tr:first th'))
+				.width('')
+				.each(function() {
+					axisWidth = Math.max(axisWidth, $(this).outerWidth());
+				}),
+			axisWidth
+		);
+		axisWidth = axisWidth;
+		
+		// column width, except for last column
+		colWidth = Math.floor((clientWidth - axisWidth) / colCnt);
+		setOuterWidth(stripeTDs.slice(0, -1), colWidth);
+		setOuterWidth(topTDs.slice(1, -2), colWidth);
+		
+		// column width for last column
+		var hasScrollbar = body[0].scrollHeight != body[0].clientHeight;
+		if (hasScrollbar) {
+			setOuterWidth(topTDs.slice(-2, -1), clientWidth - axisWidth - colWidth*(colCnt-1));
+		}else{
+			topTDs.slice(-1).hide();
+			$('tr.fc-all-day th').slice(-1).hide();
+		}
+		
+		bg.css({
+			left: axisWidth,
+			width: clientWidth - axisWidth
+		});
+	}
+	
+	
+	function resetScroll() {
+		var d0 = zeroDate(),
+			scrollDate = cloneDate(d0);
+		scrollDate.setHours(opt('firstHour'));
+		var top = timePosition(d0, scrollDate) + 1, // +1 for the border
+			scroll = function() {
+				body.scrollTop(top);
+			};
+		scroll();
+		setTimeout(scroll, 0); // overrides any previous scroll state made by the browser
+	}
+	
+	
+	function beforeHide() {
+		savedScrollTop = body.scrollTop();
+	}
+	
+	
+	function afterShow() {
+		body.scrollTop(savedScrollTop);
+	}
+	
+	
+	
+	/* Slot/Day clicking and binding
+	-----------------------------------------------------------------------*/
+	
+
+	function dayBind(tds) {
+		tds.click(slotClick)
+			.mousedown(daySelectionMousedown);
+	}
+
+
+	function slotBind(tds) {
+		tds.click(slotClick)
+			.mousedown(slotSelectionMousedown);
+	}
+	
+	
+	function slotClick(ev) {
+		if (!opt('selectable')) { // SelectionManager will worry about dayClick
+			var col = Math.min(colCnt-1, Math.floor((ev.pageX - bg.offset().left) / colWidth)),
+				date = addDays(cloneDate(t.visStart), col*dis+dit),
+				rowMatch = this.className.match(/fc-slot(\d+)/);
+			if (rowMatch) {
+				var mins = parseInt(rowMatch[1]) * opt('slotMinutes'),
+					hours = Math.floor(mins/60);
+				date.setHours(hours);
+				date.setMinutes(mins%60 + minMinute);
+				trigger('dayClick', this, date, false, ev);
+			}else{
+				trigger('dayClick', this, date, true, ev);
+			}
+		}
+	}
+	
+	
+	
+	/* Semi-transparent Overlay Helpers
+	-----------------------------------------------------*/
+	
+
+	function renderDayOverlay(startDate, endDate, refreshCoordinateGrid) { // endDate is exclusive
+		if (refreshCoordinateGrid) {
+			coordinateGrid.build();
+		}
+		var visStart = cloneDate(t.visStart);
+		var startCol, endCol;
+		if (rtl) {
+			startCol = dayDiff(endDate, visStart)*dis+dit+1;
+			endCol = dayDiff(startDate, visStart)*dis+dit+1;
+		}else{
+			startCol = dayDiff(startDate, visStart);
+			endCol = dayDiff(endDate, visStart);
+		}
+		startCol = Math.max(0, startCol);
+		endCol = Math.min(colCnt, endCol);
+		if (startCol < endCol) {
+			dayBind(
+				renderCellOverlay(0, startCol, 0, endCol-1)
+			);
+		}
+	}
+	
+	
+	function renderCellOverlay(col0, row0, col1, row1) {
+		var rect = coordinateGrid.rect(col0, row0, col1, row1, head);
+		return renderOverlay(rect, head);
+	}
+	
+
+	function renderSlotOverlay(overlayStart, overlayEnd) {
+		var dayStart = cloneDate(t.visStart);
+		var dayEnd = addDays(cloneDate(dayStart), 1);
+		for (var i=0; i<colCnt; i++) {
+			var stretchStart = new Date(Math.max(dayStart, overlayStart));
+			var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));
+			if (stretchStart < stretchEnd) {
+				var col = i*dis+dit;
+				var rect = coordinateGrid.rect(0, col, 0, col, bodyContent); // only use it for horizontal coords
+				var top = timePosition(dayStart, stretchStart);
+				var bottom = timePosition(dayStart, stretchEnd);
+				rect.top = top;
+				rect.height = bottom - top;
+				slotBind(
+					renderOverlay(rect, bodyContent)
+				);
+			}
+			addDays(dayStart, 1);
+			addDays(dayEnd, 1);
+		}
+	}
+	
+	
+	
+	/* Coordinate Utilities
+	-----------------------------------------------------------------------------*/
+	
+	
+	coordinateGrid = new CoordinateGrid(function(rows, cols) {
+		var e, n, p;
+		bg.find('td').each(function(i, _e) {
+			e = $(_e);
+			n = e.offset().left;
+			if (i) {
+				p[1] = n;
+			}
+			p = [n];
+			cols[i] = p;
+		});
+		p[1] = n + e.outerWidth();
+		if (opt('allDaySlot')) {
+			e = head.find('td');
+			n = e.offset().top;
+			rows[0] = [n, n+e.outerHeight()];
+		}
+		var bodyContentTop = bodyContent.offset().top;
+		var bodyTop = body.offset().top;
+		var bodyBottom = bodyTop + body.outerHeight();
+		function constrain(n) {
+			return Math.max(bodyTop, Math.min(bodyBottom, n));
+		}
+		for (var i=0; i<slotCnt; i++) {
+			rows.push([
+				constrain(bodyContentTop + slotHeight*i),
+				constrain(bodyContentTop + slotHeight*(i+1))
+			]);
+		}
+	});
+	
+	
+	hoverListener = new HoverListener(coordinateGrid);
+	
+	
+	colContentPositions = new HorizontalPositionCache(function(col) {
+		return bg.find('td:eq(' + col + ') div div');
+	});
+	
+	
+	function colContentLeft(col) {
+		return axisWidth + colContentPositions.left(col);
+	}
+	
+	
+	function colContentRight(col) {
+		return axisWidth + colContentPositions.right(col);
+	}
+	
+	
+	function dayOfWeekCol(dayOfWeek) {
+		return ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt)*dis+dit;
+	}
+	
+	
+	// get the Y coordinate of the given time on the given day (both Date objects)
+	function timePosition(day, time) { // both date objects. day holds 00:00 of current day
+		day = cloneDate(day, true);
+		if (time < addMinutes(cloneDate(day), minMinute)) {
+			return 0;
+		}
+		if (time >= addMinutes(cloneDate(day), maxMinute)) {
+			return bodyContent.height();
+		}
+		var slotMinutes = opt('slotMinutes'),
+			minutes = time.getHours()*60 + time.getMinutes() - minMinute,
+			slotI = Math.floor(minutes / slotMinutes),
+			slotTop = slotTopCache[slotI];
+		if (slotTop === undefined) {
+			slotTop = slotTopCache[slotI] = body.find('tr:eq(' + slotI + ') td div')[0].offsetTop;
+		}
+		return Math.max(0, Math.round(
+			slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
+		));
+	}
+	
+	
+	function cellDate(cell) {
+		var d = addDays(cloneDate(t.visStart), cell.col*dis+dit);
+		var slotIndex = cell.row;
+		if (opt('allDaySlot')) {
+			slotIndex--;
+		}
+		if (slotIndex >= 0) {
+			addMinutes(d, minMinute + slotIndex*opt('slotMinutes'));
+		}
+		return d;
+	}
+	
+	
+	function cellIsAllDay(cell) {
+		return opt('allDaySlot') && !cell.row;
+	}
+	
+	
+	function allDayBounds() {
+		return {
+			left: axisWidth,
+			right: viewWidth
+		}
+	}
+	
+	
+	function allDayTR(index) {
+		return head.find('tr.fc-all-day');
+	}
+	
+	
+	function defaultEventEnd(event) {
+		var start = cloneDate(event.start);
+		if (event.allDay) {
+			return start;
+		}
+		return addMinutes(start, opt('defaultEventMinutes'));
+	}
+	
+	
+	
+	/* Selection
+	---------------------------------------------------------------------------------*/
+	
+	
+	function defaultSelectionEnd(startDate, allDay) {
+		if (allDay) {
+			return cloneDate(startDate);
+		}
+		return addMinutes(cloneDate(startDate), opt('slotMinutes'));
+	}
+	
+	
+	function renderSelection(startDate, endDate, allDay) {
+		if (allDay) {
+			if (opt('allDaySlot')) {
+				renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);
+			}
+		}else{
+			renderSlotSelection(startDate, endDate);
+		}
+	}
+	
+	
+	function renderSlotSelection(startDate, endDate) {
+		var helperOption = opt('selectHelper');
+		coordinateGrid.build();
+		if (helperOption) {
+			var col = dayDiff(startDate, t.visStart) * dis + dit;
+			if (col >= 0 && col < colCnt) { // only works when times are on same day
+				var rect = coordinateGrid.rect(0, col, 0, col, bodyContent); // only for horizontal coords
+				var top = timePosition(startDate, startDate);
+				var bottom = timePosition(startDate, endDate);
+				if (bottom > top) { // protect against selections that are entirely before or after visible range
+					rect.top = top;
+					rect.height = bottom - top;
+					rect.left += 2;
+					rect.width -= 5;
+					if ($.isFunction(helperOption)) {
+						var helperRes = helperOption(startDate, endDate);
+						if (helperRes) {
+							rect.position = 'absolute';
+							rect.zIndex = 8;
+							selectionHelper = $(helperRes)
+								.css(rect)
+								.appendTo(bodyContent);
+						}
+					}else{
+						selectionHelper = $(slotSegHtml(
+							{
+								title: '',
+								start: startDate,
+								end: endDate,
+								className: [],
+								editable: false
+							},
+							rect,
+							'fc-event fc-event-vert fc-corner-top fc-corner-bottom '
+						));
+						if ($.browser.msie) {
+							selectionHelper.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
+						}
+						selectionHelper.css('opacity', opt('dragOpacity'));
+					}
+					if (selectionHelper) {
+						slotBind(selectionHelper);
+						bodyContent.append(selectionHelper);
+						setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended
+						setOuterHeight(selectionHelper, rect.height, true);
+					}
+				}
+			}
+		}else{
+			renderSlotOverlay(startDate, endDate);
+		}
+	}
+	
+	
+	function clearSelection() {
+		clearOverlays();
+		if (selectionHelper) {
+			selectionHelper.remove();
+			selectionHelper = null;
+		}
+	}
+	
+	
+	function slotSelectionMousedown(ev) {
+		if (opt('selectable')) {
+			unselect(ev);
+			var _mousedownElement = this;
+			var dates;
+			hoverListener.start(function(cell, origCell) {
+				clearSelection();
+				if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) {
+					var d1 = cellDate(origCell);
+					var d2 = cellDate(cell);
+					dates = [
+						d1,
+						addMinutes(cloneDate(d1), opt('slotMinutes')),
+						d2,
+						addMinutes(cloneDate(d2), opt('slotMinutes'))
+					].sort(cmp);
+					renderSlotSelection(dates[0], dates[3]);
+				}else{
+					dates = null;
+				}
+			}, ev);
+			$(document).one('mouseup', function(ev) {
+				hoverListener.stop();
+				if (dates) {
+					if (+dates[0] == +dates[1]) {
+						trigger('dayClick', _mousedownElement, dates[0], false, ev);
+						// BUG: _mousedownElement will sometimes be the overlay
+					}
+					reportSelection(dates[0], dates[3], false, ev);
+				}
+			});
+		}
+	}
+	
+	
+	
+	/* External Dragging
+	--------------------------------------------------------------------------------*/
+	
+	
+	function dragStart(_dragElement, ev, ui) {
+		hoverListener.start(function(cell) {
+			clearOverlays();
+			if (cell) {
+				if (cellIsAllDay(cell)) {
+					renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
+				}else{
+					var d1 = cellDate(cell);
+					var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes'));
+					renderSlotOverlay(d1, d2);
+				}
+			}
+		}, ev);
+	}
+	
+	
+	function dragStop(_dragElement, ev, ui) {
+		var cell = hoverListener.stop();
+		clearOverlays();
+		if (cell) {
+			trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui);
+		}
+	}
+
+
+}

+ 46 - 0
src/agenda/AgendaWeekView.js

@@ -0,0 +1,46 @@
+
+fcViews.agendaWeek = AgendaWeekView;
+
+function AgendaWeekView(element, calendar) {
+	var t = this;
+	
+	
+	// exports
+	t.render = render;
+	
+	
+	// imports
+	AgendaView.call(t, element, calendar, 'agendaWeek');
+	var opt = t.opt;
+	var renderAgenda = t.renderAgenda;
+	var formatDates = calendar.formatDates;
+	
+	
+	
+	function render(date, delta) {
+		if (delta) {
+			addDays(date, delta * 7);
+		}
+		var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
+		var end = addDays(cloneDate(start), 7);
+		var visStart = cloneDate(start);
+		var visEnd = cloneDate(end);
+		var weekends = opt('weekends');
+		if (!weekends) {
+			skipWeekend(visStart);
+			skipWeekend(visEnd, -1, true);
+		}
+		t.title = formatDates(
+			visStart,
+			addDays(cloneDate(visEnd), -1),
+			opt('titleFormat')
+		);
+		t.start = start;
+		t.end = end;
+		t.visStart = visStart;
+		t.visEnd = visEnd;
+		renderAgenda(weekends ? 7 : 5);
+	}
+	
+
+}

+ 0 - 0
src/css/agenda.css → src/agenda/agenda.css


+ 37 - 0
src/basic/BasicDayView.js

@@ -0,0 +1,37 @@
+
+fcViews.basicDay = BasicDayView;
+
+//TODO: when calendar's date starts out on a weekend, shouldn't happen
+
+
+function BasicDayView(element, calendar) {
+	var t = this;
+	
+	
+	// exports
+	t.render = render;
+	
+	
+	// imports
+	BasicView.call(t, element, calendar, 'basicDay');
+	var opt = t.opt;
+	var renderBasic = t.renderBasic;
+	var formatDate = calendar.formatDate;
+	
+	
+	
+	function render(date, delta) {
+		if (delta) {
+			addDays(date, delta);
+			if (!opt('weekends')) {
+				skipWeekend(date, delta < 0 ? -1 : 1);
+			}
+		}
+		t.title = formatDate(date, opt('titleFormat'));
+		t.start = t.visStart = cloneDate(date, true);
+		t.end = t.visEnd = addDays(cloneDate(t.start), 1);
+		renderBasic(1, 1, false);
+	}
+	
+	
+}

+ 149 - 0
src/basic/BasicEventRenderer.js

@@ -0,0 +1,149 @@
+
+function BasicEventRenderer() {
+	var t = this;
+	
+	
+	// exports
+	t.renderEvents = renderEvents;
+	t.rerenderEvents = rerenderEvents;
+	t.clearEvents = clearEvents;
+	t.bindDaySeg = bindDaySeg;
+	
+	
+	// imports
+	DayEventRenderer.call(t);
+	var opt = t.opt;
+	var trigger = t.trigger;
+	var reportEvents = t.reportEvents;
+	var clearEventData = t.clearEventData;
+	var eventElementHandlers = t.eventElementHandlers;
+	var showEvents = t.showEvents;
+	var hideEvents = t.hideEvents;
+	var eventDrop = t.eventDrop;
+	var getDaySegmentContainer = t.getDaySegmentContainer;
+	var getHoverListener = t.getHoverListener;
+	var renderDayOverlay = t.renderDayOverlay;
+	var clearOverlays = t.clearOverlays;
+	var getRowCnt = t.getRowCnt;
+	var getColCnt = t.getColCnt;
+	var renderDaySegs = t.renderDaySegs;
+	var resizableDayEvent = t.resizableDayEvent;
+	
+	
+	// locals
+	var cachedEvents=[];
+	
+	
+	
+	/* Rendering
+	--------------------------------------------------------------------*/
+	
+	
+	function renderEvents(events) {
+		reportEvents(cachedEvents = events);
+		renderDaySegs(compileSegs(events));
+	}
+	
+	
+	function rerenderEvents(modifiedEventId) {
+		clearEvents();
+		renderDaySegs(compileSegs(cachedEvents), modifiedEventId);
+	}
+	
+	
+	function clearEvents() {
+		clearEventData();
+		getDaySegmentContainer().empty();
+	}
+	
+	
+	function compileSegs(events) {
+		var rowCnt = getRowCnt(),
+			colCnt = getColCnt(),
+			d1 = cloneDate(t.visStart),
+			d2 = addDays(cloneDate(d1), colCnt),
+			visEventsEnds = $.map(events, exclEndDay),
+			i, row,
+			j, level,
+			k, seg,
+			segs=[];
+		for (i=0; i<rowCnt; i++) {
+			row = stackSegs(sliceSegs(events, visEventsEnds, d1, d2));
+			for (j=0; j<row.length; j++) {
+				level = row[j];
+				for (k=0; k<level.length; k++) {
+					seg = level[k];
+					seg.row = i;
+					seg.level = j;
+					segs.push(seg);
+				}
+			}
+			addDays(d1, 7);
+			addDays(d2, 7);
+		}
+		return segs;
+	}
+	
+	
+	function bindDaySeg(event, eventElement, seg) {
+		eventElementHandlers(event, eventElement);
+		if (event.editable || event.editable === undefined && opt('editable')) {
+			draggableDayEvent(event, eventElement);
+			if (seg.isEnd) {
+				resizableDayEvent(event, eventElement);
+			}
+		}
+	}
+	
+	
+	
+	/* Dragging
+	----------------------------------------------------------------------------*/
+	
+	
+	function draggableDayEvent(event, eventElement) {
+		if (!opt('disableDragging') && eventElement.draggable) {
+			var hoverListener = getHoverListener();
+			var dayDelta;
+			eventElement.draggable({
+				zIndex: 9,
+				delay: 50,
+				opacity: opt('dragOpacity'),
+				revertDuration: opt('dragRevertDuration'),
+				start: function(ev, ui) {
+					trigger('eventDragStart', eventElement, event, ev, ui);
+					hideEvents(event, eventElement);
+					hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
+						eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
+						clearOverlays();
+						if (cell) {
+							dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);
+							renderDayOverlay(
+								addDays(cloneDate(event.start), dayDelta),
+								addDays(exclEndDay(event), dayDelta)
+							);
+						}else{
+							dayDelta = 0;
+						}
+					}, ev, 'drag');
+				},
+				stop: function(ev, ui) {
+					hoverListener.stop();
+					clearOverlays();
+					trigger('eventDragStop', eventElement, event, ev, ui);
+					if (dayDelta) {
+						eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
+						eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);
+					}else{
+						if ($.browser.msie) {
+							eventElement.css('filter', ''); // clear IE opacity side-effects
+						}
+						showEvents(event, eventElement);
+					}
+				}
+			});
+		}
+	}
+
+
+}

+ 453 - 0
src/basic/BasicView.js

@@ -0,0 +1,453 @@
+
+var tdHeightBug;
+
+setDefaults({
+	weekMode: 'fixed'
+});
+
+
+function BasicView(element, calendar, viewName) {
+	var t = this;
+	
+	
+	// exports
+	t.renderBasic = renderBasic;
+	t.setHeight = setHeight;
+	t.setWidth = setWidth;
+	t.renderDayOverlay = renderDayOverlay;
+	t.defaultSelectionEnd = defaultSelectionEnd;
+	t.renderSelection = renderSelection;
+	t.clearSelection = clearSelection;
+	t.dragStart = dragStart;
+	t.dragStop = dragStop;
+	t.defaultEventEnd = defaultEventEnd;
+	t.getHoverListener = function() { return hoverListener };
+	t.colContentLeft = colContentLeft;
+	t.colContentRight = colContentRight;
+	t.dayOfWeekCol = dayOfWeekCol;
+	t.cellDate = cellDate;
+	t.cellIsAllDay = function() { return true };
+	t.allDayTR = allDayTR;
+	t.allDayBounds = allDayBounds;
+	t.getRowCnt = function() { return rowCnt };
+	t.getColCnt = function() { return colCnt };
+	t.getColWidth = function() { return colWidth };
+	t.getDaySegmentContainer = function() { return daySegmentContainer };
+	
+	
+	// imports
+	View.call(t, element, calendar, viewName);
+	OverlayManager.call(t);
+	SelectionManager.call(t);
+	BasicEventRenderer.call(t);
+	var opt = t.opt;
+	var trigger = t.trigger;
+	var clearEvents = t.clearEvents;
+	var renderOverlay = t.renderOverlay;
+	var clearOverlays = t.clearOverlays;
+	var daySelectionMousedown = t.daySelectionMousedown;
+	var formatDate = calendar.formatDate;
+	
+	
+	// locals
+	var rtl, dis, dit;
+	var firstDay;
+	var nwe;
+	var rowCnt, colCnt;
+	var colWidth;
+	var viewWidth, viewHeight;
+	var thead, tbody;
+	var daySegmentContainer;
+	var coordinateGrid;
+	var hoverListener;
+	var colContentPositions;
+	
+	
+	
+	/* Rendering
+	------------------------------------------------------------*/
+	
+	
+	disableTextSelection(element.addClass('fc-grid'));
+	
+	
+	function renderBasic(r, c, showNumbers) {
+	
+		rowCnt = r;
+		colCnt = c;
+		rtl = opt('isRTL');
+		if (rtl) {
+			dis = -1;
+			dit = colCnt - 1;
+		}else{
+			dis = 1;
+			dit = 0;
+		}
+		firstDay = opt('firstDay');
+		nwe = opt('weekends') ? 0 : 1;
+		
+		var tm = opt('theme') ? 'ui' : 'fc';
+		var colFormat = opt('columnFormat');
+		var month = t.start.getMonth();
+		var today = clearTime(new Date());
+		var s, i, j, d = cloneDate(t.visStart);
+		
+		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) + "</th>";
+				addDays(d, 1);
+				if (nwe) {
+					skipWeekend(d);
+				}
+			}
+			thead = $(s + "</tr></thead>").appendTo(table);
+			
+			s = "<tbody>";
+			d = cloneDate(t.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 style='position:relative'>&nbsp;</div></div></td>";
+					addDays(d, 1);
+					if (nwe) {
+						skipWeekend(d);
+					}
+				}
+				s += "</tr>";
+			}
+			tbody = $(s + "</tbody>").appendTo(table);
+			dayBind(tbody.find('td'));
+			
+			daySegmentContainer = $("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(element);
+		
+		}else{ // NOT first time, reuse as many cells as possible
+		
+			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 style='position:relative'>&nbsp;</div></div>" +
+							"</td>";
+						addDays(d, 1);
+						if (nwe) {
+							skipWeekend(d);
+						}
+					}
+					s += "</tr>";
+				}
+				tbody.append(s);
+			}
+			dayBind(tbody.find('td.fc-new').removeClass('fc-new'));
+			
+			// re-label and re-class existing cells
+			d = cloneDate(t.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 (nwe) {
+					skipWeekend(d);
+				}
+			});
+			
+			if (rowCnt == 1) { // more changes likely (week or day view)
+			
+				// redo column header text and class
+				d = cloneDate(t.visStart);
+				thead.find('th').each(function(i, th) {
+					$(th).text(formatDate(d, colFormat));
+					th.className = th.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
+					addDays(d, 1);
+					if (nwe) {
+						skipWeekend(d);
+					}
+				});
+				
+				// redo cell day-of-weeks
+				d = cloneDate(t.visStart);
+				tbody.find('td').each(function(i, td) {
+					td.className = td.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
+					addDays(d, 1);
+					if (nwe) {
+						skipWeekend(d);
+					}
+				});
+				
+			}
+		
+		}
+		
+	}
+	
+	
+	function setHeight(height) {
+		viewHeight = height;
+		var leftTDs = tbody.find('tr td:first-child'),
+			tbodyHeight = viewHeight - thead.height(),
+			rowHeight1, rowHeight2;
+		if (opt('weekMode') == 'variable') {
+			rowHeight1 = rowHeight2 = Math.floor(tbodyHeight / (rowCnt==1 ? 2 : 6));
+		}else{
+			rowHeight1 = Math.floor(tbodyHeight / rowCnt);
+			rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1);
+		}
+		if (tdHeightBug === undefined) {
+			// bug in firefox where cell height includes padding
+			var tr = tbody.find('tr:first'),
+				td = tr.find('td:first');
+			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);
+		}
+	}
+	
+	
+	function setWidth(width) {
+		viewWidth = width;
+		colContentPositions.clear();
+		colWidth = Math.floor(viewWidth / colCnt);
+		setOuterWidth(thead.find('th').slice(0, -1), colWidth);
+	}
+	
+	
+	
+	/* Day clicking and binding
+	-----------------------------------------------------------*/
+	
+	
+	function dayBind(days) {
+		days.click(dayClick)
+			.mousedown(daySelectionMousedown);
+	}
+	
+	
+	function dayClick(ev) {
+		if (!opt('selectable')) { // SelectionManager will worry about dayClick
+			var n = parseInt(this.className.match(/fc\-day(\d+)/)[1]),
+				date = addDays(
+					cloneDate(t.visStart),
+					Math.floor(n/colCnt) * 7 + n % colCnt
+				);
+			// TODO: what about weekends in middle of week?
+			trigger('dayClick', this, date, true, ev);
+		}
+	}
+	
+	
+	
+	/* Semi-transparent Overlay Helpers
+	------------------------------------------------------*/
+	
+	
+	function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive
+		if (refreshCoordinateGrid) {
+			coordinateGrid.build();
+		}
+		var rowStart = cloneDate(t.visStart);
+		var rowEnd = addDays(cloneDate(rowStart), colCnt);
+		for (var i=0; i<rowCnt; i++) {
+			var stretchStart = new Date(Math.max(rowStart, overlayStart));
+			var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));
+			if (stretchStart < stretchEnd) {
+				var colStart, colEnd;
+				if (rtl) {
+					colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;
+					colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;
+				}else{
+					colStart = dayDiff(stretchStart, rowStart);
+					colEnd = dayDiff(stretchEnd, rowStart);
+				}
+				dayBind(
+					renderCellOverlay(i, colStart, i, colEnd-1)
+				);
+			}
+			addDays(rowStart, 7);
+			addDays(rowEnd, 7);
+		}
+	}
+	
+	
+	function renderCellOverlay(row0, col0, row1, col1) { // row1,col1 is inclusive
+		var rect = coordinateGrid.rect(row0, col0, row1, col1, element);
+		return renderOverlay(rect, element);
+	}
+	
+	
+	
+	/* Selection
+	-----------------------------------------------------------------------*/
+	
+	
+	function defaultSelectionEnd(startDate, allDay) {
+		return cloneDate(startDate);
+	}
+	
+	
+	function renderSelection(startDate, endDate, allDay) {
+		renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);
+	}
+	
+	
+	function clearSelection() {
+		clearOverlays();
+	}
+	
+	
+	
+	/* External Dragging
+	-----------------------------------------------------------------------*/
+	
+	
+	function dragStart(_dragElement, ev, ui) {
+		hoverListener.start(function(cell) {
+			clearOverlays();
+			if (cell) {
+				renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
+			}
+		}, ev);
+	}
+	
+	
+	function dragStop(_dragElement, ev, ui) {
+		var cell = hoverListener.stop();
+		clearOverlays();
+		if (cell) {
+			var d = cellDate(cell);
+			trigger('drop', _dragElement, d, true, ev, ui);
+		}
+	}
+	
+	
+	
+	/* Utilities
+	--------------------------------------------------------*/
+	
+	
+	function defaultEventEnd(event) {
+		return cloneDate(event.start);
+	}
+	
+	
+	coordinateGrid = new CoordinateGrid(function(rows, cols) {
+		var e, n, p;
+		var tds = tbody.find('tr:first td');
+		if (rtl) {
+			tds = $(tds.get().reverse());
+		}
+		tds.each(function(i, _e) {
+			e = $(_e);
+			n = e.offset().left;
+			if (i) {
+				p[1] = n;
+			}
+			p = [n];
+			cols[i] = p;
+		});
+		p[1] = n + e.outerWidth();
+		tbody.find('tr').each(function(i, _e) {
+			e = $(_e);
+			n = e.offset().top;
+			if (i) {
+				p[1] = n;
+			}
+			p = [n];
+			rows[i] = p;
+		});
+		p[1] = n + e.outerHeight();
+	});
+	
+	
+	hoverListener = new HoverListener(coordinateGrid);
+	
+	
+	colContentPositions = new HorizontalPositionCache(function(col) {
+		return tbody.find('td:eq(' + col + ') div div');
+	});
+	
+	
+	function colContentLeft(col) {
+		return colContentPositions.left(col);
+	}
+	
+	
+	function colContentRight(col) {
+		return colContentPositions.right(col);
+	}
+	
+	
+	function dayOfWeekCol(dayOfWeek) {
+		return (dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt;
+	}
+	
+	
+	function cellDate(cell) {
+		return addDays(cloneDate(t.visStart), cell.row*7 + cell.col*dis+dit);
+		// TODO: what about weekends in middle of week?
+	}
+	
+	
+	function allDayTR(i) {
+		return tbody.find('tr:eq('+i+')');
+	}
+	
+	
+	function allDayBounds(i) {
+		return {
+			left: 0,
+			right: viewWidth
+		};
+	}
+	
+	
+}

+ 46 - 0
src/basic/BasicWeekView.js

@@ -0,0 +1,46 @@
+
+fcViews.basicWeek = BasicWeekView;
+
+function BasicWeekView(element, calendar) {
+	var t = this;
+	
+	
+	// exports
+	t.render = render;
+	
+	
+	// imports
+	BasicView.call(t, element, calendar, 'basicWeek');
+	var opt = t.opt;
+	var renderBasic = t.renderBasic;
+	var formatDates = calendar.formatDates;
+	
+	
+	
+	function render(date, delta) {
+		if (delta) {
+			addDays(date, delta * 7);
+		}
+		var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
+		var end = addDays(cloneDate(start), 7);
+		var visStart = cloneDate(start);
+		var visEnd = cloneDate(end);
+		var weekends = opt('weekends');
+		if (!weekends) {
+			skipWeekend(visStart);
+			skipWeekend(visEnd, -1, true);
+		}
+		t.title = formatDates(
+			visStart,
+			addDays(cloneDate(visEnd), -1),
+			opt('titleFormat')
+		);
+		t.start = start;
+		t.end = end;
+		t.visStart = visStart;
+		t.visEnd = visEnd;
+		renderBasic(1, weekends ? 7 : 5, false);
+	}
+	
+	
+}

+ 52 - 0
src/basic/MonthView.js

@@ -0,0 +1,52 @@
+
+fcViews.month = MonthView;
+
+function MonthView(element, calendar) {
+	var t = this;
+	
+	
+	// exports
+	t.render = render;
+	
+	
+	// imports
+	BasicView.call(t, element, calendar, 'month');
+	var opt = t.opt;
+	var renderBasic = t.renderBasic;
+	var formatDate = calendar.formatDate;
+	
+	
+	
+	function render(date, delta) {
+		if (delta) {
+			addMonths(date, delta);
+			date.setDate(1);
+		}
+		var start = cloneDate(date, true);
+		start.setDate(1);
+		var end = addMonths(cloneDate(start), 1);
+		var visStart = cloneDate(start);
+		var visEnd = cloneDate(end);
+		var firstDay = opt('firstDay');
+		var nwe = opt('weekends') ? 0 : 1;
+		if (nwe) {
+			skipWeekend(visStart);
+			skipWeekend(visEnd, -1, true);
+		}
+		addDays(visStart, -((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));
+		addDays(visEnd, (7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);
+		var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));
+		if (opt('weekMode') == 'fixed') {
+			addDays(visEnd, (6 - rowCnt) * 7);
+			rowCnt = 6;
+		}
+		t.title = formatDate(start, opt('titleFormat'));
+		t.start = start;
+		t.end = end;
+		t.visStart = visStart;
+		t.visEnd = visEnd;
+		renderBasic(rowCnt, nwe ? 5 : 7, true);
+	}
+	
+	
+}

+ 0 - 0
src/css/grid.css → src/basic/basic.css


+ 43 - 0
src/common/CoordinateGrid.js

@@ -0,0 +1,43 @@
+
+function CoordinateGrid(buildFunc) {
+
+	var t = this;
+	var rows;
+	var cols;
+	
+	t.build = function() {
+		rows = [];
+		cols = [];
+		buildFunc(rows, cols);
+	};
+	
+	t.cell = function(x, y) {
+		var rowCnt = rows.length;
+		var colCnt = cols.length;
+		var i, r=-1, c=-1;
+		for (i=0; i<rowCnt; i++) {
+			if (y >= rows[i][0] && y < rows[i][1]) {
+				r = i;
+				break;
+			}
+		}
+		for (i=0; i<colCnt; i++) {
+			if (x >= cols[i][0] && x < cols[i][1]) {
+				c = i;
+				break;
+			}
+		}
+		return (r>=0 && c>=0) ? { row:r, col:c } : null;
+	};
+	
+	t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive
+		var origin = originElement.offset();
+		return {
+			top: rows[row0][0] - origin.top,
+			left: cols[col0][0] - origin.left,
+			width: cols[col1][1] - cols[col0][0],
+			height: rows[row1][1] - rows[row0][0]
+		};
+	};
+
+}

+ 232 - 0
src/common/DayEventRenderer.js

@@ -0,0 +1,232 @@
+
+function DayEventRenderer() {
+	var t = this;
+
+	
+	// exports
+	t.renderDaySegs = renderDaySegs;
+	t.resizableDayEvent = resizableDayEvent;
+	
+	
+	// imports
+	var opt = t.opt;
+	var trigger = t.trigger;
+	var reportEventElement = t.reportEventElement;
+	var showEvents = t.showEvents;
+	var hideEvents = t.hideEvents;
+	var eventResize = t.eventResize;
+	var getRowCnt = t.getRowCnt;
+	var getColCnt = t.getColCnt;
+	var getColWidth = t.getColWidth;
+	var allDayTR = t.allDayTR;
+	var allDayBounds = t.allDayBounds;
+	var colContentLeft = t.colContentLeft;
+	var colContentRight = t.colContentRight;
+	var dayOfWeekCol = t.dayOfWeekCol;
+	var getDaySegmentContainer = t.getDaySegmentContainer;
+	var bindDaySeg = t.bindDaySeg; //TODO: streamline this
+	var formatDates = t.calendar.formatDates;
+	
+	
+	
+	/* Rendering
+	-----------------------------------------------------------------------------*/
+
+
+	function renderDaySegs(segs, modifiedEventId) {
+
+		var rtl=opt('isRTL'),
+			i, segCnt=segs.length, seg,
+			event,
+			className,
+			left, right,
+			html='',
+			eventElements,
+			eventElement,
+			triggerRes,
+			hsideCache={},
+			vmarginCache={},
+			key, val,
+			rowI, top, levelI, levelHeight,
+			rowDivs=[],
+			rowDivTops=[],
+			bounds = allDayBounds(),
+			minLeft = bounds.left,
+			maxLeft = bounds.right,
+			rowCnt = getRowCnt(),
+			colCnt = getColCnt(),
+			segmentContainer = getDaySegmentContainer();
+		
+		// calculate desired position/dimensions, create html
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			event = seg.event;
+			className = 'fc-event fc-event-hori ';
+			if (rtl) {
+				if (seg.isStart) {
+					className += 'fc-corner-right ';
+				}
+				if (seg.isEnd) {
+					className += 'fc-corner-left ';
+				}
+				left = seg.isEnd ? colContentLeft(dayOfWeekCol(seg.end.getDay()-1)) : minLeft;
+				right = seg.isStart ? colContentRight(dayOfWeekCol(seg.start.getDay())) : maxLeft;
+			}else{
+				if (seg.isStart) {
+					className += 'fc-corner-left ';
+				}
+				if (seg.isEnd) {
+					className += 'fc-corner-right ';
+				}
+				left = seg.isStart ? colContentLeft(dayOfWeekCol(seg.start.getDay())) : minLeft;
+				right = seg.isEnd ? colContentRight(dayOfWeekCol(seg.end.getDay()-1)) : maxLeft;
+			}
+			html +=
+				"<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;left:"+left+"px'>" +
+					"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
+						(!event.allDay && seg.isStart ?
+							"<span class='fc-event-time'>" +
+								htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
+							"</span>"
+						:'') +
+						"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
+					"</a>" +
+					((event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
+						"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
+						: '') +
+				"</div>";
+			seg.left = left;
+			seg.outerWidth = right - left;
+		}
+		segmentContainer[0].innerHTML = html; // faster than html()
+		eventElements = segmentContainer.children();
+	
+		// retrieve elements, run through eventRender callback, bind handlers
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			eventElement = $(eventElements[i]); // faster than eq()
+			event = seg.event;
+			triggerRes = trigger('eventRender', event, event, eventElement);
+			if (triggerRes === false) {
+				eventElement.remove();
+			}else{
+				if (triggerRes && triggerRes !== true) {
+					eventElement.remove();
+					eventElement = $(triggerRes)
+						.css({
+							position: 'absolute',
+							left: seg.left
+						})
+						.appendTo(segmentContainer);
+				}
+				seg.element = eventElement;
+				if (event._id === modifiedEventId) {
+					bindDaySeg(event, eventElement, seg);
+				}else{
+					eventElement[0]._fci = i; // for lazySegBind
+				}
+				reportEventElement(event, eventElement);
+			}
+		}
+	
+		lazySegBind(segmentContainer, segs, bindDaySeg);
+	
+		// record event horizontal sides
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			if (eventElement = seg.element) {
+				val = hsideCache[key = seg.key = cssKey(eventElement[0])];
+				seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
+			}
+		}
+	
+		// set event widths
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			if (eventElement = seg.element) {
+				eventElement[0].style.width = seg.outerWidth - seg.hsides + 'px';
+			}
+		}
+	
+		// record event heights
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			if (eventElement = seg.element) {
+				val = vmarginCache[key = seg.key];
+				seg.outerHeight = eventElement[0].offsetHeight + (
+					val === undefined ? (vmarginCache[key] = vmargins(eventElement[0])) : val
+				);
+			}
+		}
+	
+		// set row heights, calculate event tops (in relation to row top)
+		for (i=0, rowI=0; rowI<rowCnt; rowI++) {
+			top = levelI = levelHeight = 0;
+			while (i<segCnt && (seg = segs[i]).row == rowI) {
+				if (seg.level != levelI) {
+					top += levelHeight;
+					levelHeight = 0;
+					levelI++;
+				}
+				levelHeight = Math.max(levelHeight, seg.outerHeight||0);
+				seg.top = top;
+				i++;
+			}
+			rowDivs[rowI] = allDayTR(rowI).find('td:first div.fc-day-content > div') // optimal selector?
+				.height(top + levelHeight);
+		}
+	
+		// calculate row tops
+		for (rowI=0; rowI<rowCnt; rowI++) {
+			rowDivTops[rowI] = rowDivs[rowI][0].offsetTop;
+		}
+	
+		// set event tops
+		for (i=0; i<segCnt; i++) {
+			seg = segs[i];
+			if (eventElement = seg.element) {
+				eventElement[0].style.top = rowDivTops[seg.row] + seg.top + 'px';
+				event = seg.event;
+				trigger('eventAfterRender', event, event, eventElement);
+			}
+		}
+	
+	}
+	
+	
+	
+	/* Resizing
+	-----------------------------------------------------------------------------------*/
+	
+	
+	function resizableDayEvent(event, eventElement) {
+		if (!opt('disableResizing') && eventElement.resizable) {
+			var colWidth = getColWidth();
+			eventElement.resizable({
+				handles: opt('isRTL') ? {w:'div.ui-resizable-w'} : {e:'div.ui-resizable-e'},
+				grid: colWidth,
+				minWidth: colWidth/2, // need this or else IE throws errors when too small
+				containment: t.element.parent().parent(), // the main element...
+				             // ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?)
+				start: function(ev, ui) {
+					eventElement.css('z-index', 9);
+					hideEvents(event, eventElement);
+					trigger('eventResizeStart', this, event, ev, ui);
+				},
+				stop: function(ev, ui) {
+					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) {
+						eventResize(this, event, dayDelta, 0, ev, ui);
+					}else{
+						eventElement.css('z-index', 8);
+						showEvents(event, eventElement);
+					}
+				}
+			});
+		}
+	}
+	
+
+}

+ 27 - 0
src/common/HorizontalPositionCache.js

@@ -0,0 +1,27 @@
+
+function HorizontalPositionCache(getElement) {
+
+	var t = this,
+		elements = {},
+		lefts = {},
+		rights = {};
+		
+	function e(i) {
+		return elements[i] = elements[i] || getElement(i);
+	}
+	
+	t.left = function(i) {
+		return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];
+	};
+	
+	t.right = function(i) {
+		return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];
+	};
+	
+	t.clear = function() {
+		elements = {};
+		lefts = {};
+		rights = {};
+	};
+	
+}

+ 44 - 0
src/common/HoverListener.js

@@ -0,0 +1,44 @@
+
+function HoverListener(coordinateGrid) {
+
+
+	var t = this;
+	var bindType;
+	var change;
+	var firstCell;
+	var cell;
+	
+	
+	t.start = function(_change, ev, _bindType) {
+		change = _change;
+		firstCell = cell = null;
+		coordinateGrid.build();
+		mouse(ev);
+		bindType = _bindType || 'mousemove';
+		$(document).bind(bindType, mouse);
+	};
+	
+	
+	function mouse(ev) {
+		var newCell = coordinateGrid.cell(ev.pageX, ev.pageY);
+		if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {
+			if (newCell) {
+				if (!firstCell) {
+					firstCell = newCell;
+				}
+				change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);
+			}else{
+				change(newCell, firstCell);
+			}
+			cell = newCell;
+		}
+	}
+	
+	
+	t.stop = function() {
+		$(document).unbind(bindType, mouse);
+		return cell;
+	};
+	
+	
+}

+ 37 - 0
src/common/OverlayManager.js

@@ -0,0 +1,37 @@
+ 
+function OverlayManager() {
+	var t = this;
+	
+	
+	// exports
+	t.renderOverlay = renderOverlay;
+	t.clearOverlays = clearOverlays;
+	
+	
+	// locals
+	var usedOverlays = [];
+	var unusedOverlays = [];
+	
+	
+	function renderOverlay(rect, parent) {
+		var e = unusedOverlays.shift();
+		if (!e) {
+			e = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>");
+		}
+		if (e[0].parentNode != parent[0]) {
+			e.appendTo(parent);
+		}
+		usedOverlays.push(e.css(rect).show());
+		return e;
+	}
+	
+
+	function clearOverlays() {
+		var e;
+		while (e = usedOverlays.shift()) {
+			unusedOverlays.push(e.hide().unbind());
+		}
+	}
+
+
+}

+ 98 - 0
src/common/SelectionManager.js

@@ -0,0 +1,98 @@
+
+//BUG: unselect needs to be triggered when events are dragged+dropped
+
+function SelectionManager() {
+	var t = this;
+	
+	
+	// exports
+	t.select = select;
+	t.unselect = unselect;
+	t.reportSelection = reportSelection;
+	t.daySelectionMousedown = daySelectionMousedown;
+	
+	
+	// imports
+	var opt = t.opt;
+	var trigger = t.trigger;
+	var defaultSelectionEnd = t.defaultSelectionEnd;
+	var renderSelection = t.renderSelection;
+	var clearSelection = t.clearSelection;
+	
+	
+	// locals
+	var selected = false;
+
+
+
+	// unselectAuto
+	if (opt('selectable') && opt('unselectAuto')) {
+		$(document).mousedown(function(ev) {
+			var ignore = opt('unselectCancel');
+			if (ignore) {
+				if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match
+					return;
+				}
+			}
+			unselect(ev);
+		});
+	}
+	
+
+	function select(startDate, endDate, allDay) {
+		unselect();
+		if (!endDate) {
+			endDate = defaultSelectionEnd(startDate, allDay);
+		}
+		renderSelection(startDate, endDate, allDay);
+		reportSelection(startDate, endDate, allDay);
+	}
+	
+	
+	function unselect(ev) {
+		if (selected) {
+			selected = false;
+			clearSelection();
+			trigger('unselect', null, ev);
+		}
+	}
+	
+	
+	function reportSelection(startDate, endDate, allDay, ev) {
+		selected = true;
+		trigger('select', null, startDate, endDate, allDay, ev);
+	}
+	
+	
+	function daySelectionMousedown(ev) { // not really a generic manager method, oh well
+		var cellDate = t.cellDate;
+		var cellIsAllDay = t.cellIsAllDay;
+		var hoverListener = t.getHoverListener();
+		if (opt('selectable')) {
+			unselect(ev);
+			var _mousedownElement = this;
+			var dates;
+			hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell
+				clearSelection();
+				if (cell && cellIsAllDay(cell)) {
+					dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);
+					renderSelection(dates[0], dates[1], true);
+				}else{
+					dates = null;
+				}
+			}, ev);
+			$(document).one('mouseup', function(ev) {
+				hoverListener.stop();
+				if (dates) {
+					if (+dates[0] == +dates[1]) {
+						trigger('dayClick', _mousedownElement, dates[0], true, ev);
+						// BUG: _mousedownElement will sometimes be the overlay
+					}
+					reportSelection(dates[0], dates[1], true, ev);
+				}
+			});
+		}
+	}
+
+
+}

+ 213 - 0
src/common/View.js

@@ -0,0 +1,213 @@
+
+
+function View(element, calendar, viewName) {
+	var t = this;
+	
+	
+	// exports
+	t.element = element;
+	t.calendar = calendar;
+	t.name = viewName;
+	t.opt = opt;
+	t.trigger = trigger;
+	t.reportEvents = reportEvents;
+	t.clearEventData = clearEventData;
+	t.eventEnd = eventEnd;
+	t.reportEventElement = reportEventElement;
+	t.eventElementHandlers = eventElementHandlers;
+	t.showEvents = showEvents;
+	t.hideEvents = hideEvents;
+	t.eventDrop = eventDrop;
+	t.eventResize = eventResize;
+	// t.title
+	// t.start, t.end
+	// t.visStart, t.visEnd
+	// t.eventsChanged // todo: maybe report to calendar instead
+	
+	
+	// imports
+	var defaultEventEnd = t.defaultEventEnd;
+	var normalizeEvent = calendar.normalizeEvent; // in EventManager
+	var rerenderEvents = calendar.rerenderEvents;
+	
+	
+	// locals
+	var eventsByID = {};
+	var eventElements = [];
+	var eventElementsByID = {};
+	var options = calendar.options;
+	
+	
+	
+	function opt(name, viewNameOverride) {
+		var v = options[name];
+		if (typeof v == 'object') {
+			return smartProperty(v, viewNameOverride || viewName);
+		}
+		return v;
+	}
+
+	
+	function trigger(name, thisObj) {
+		return calendar.trigger.apply(
+			calendar,
+			[name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t])
+		);
+	}
+	
+	
+	
+	/* Event Data
+	------------------------------------------------------------------------------*/
+	
+	
+	// report when view receives new events
+	function reportEvents(events) { // events are already normalized at this point
+		eventsByID = {};
+		var i, len=events.length, event;
+		for (i=0; i<len; i++) {
+			event = events[i];
+			if (eventsByID[event._id]) {
+				eventsByID[event._id].push(event);
+			}else{
+				eventsByID[event._id] = [event];
+			}
+		}
+	}
+	
+	
+	function clearEventData() { // todo: rename to clearReportedEvents or something
+		eventElements = [];
+		eventElementsByID = {};
+	}
+	
+	
+	// returns a Date object for an event's end
+	function eventEnd(event) {
+		return event.end ? cloneDate(event.end) : defaultEventEnd(event);
+	}
+	
+	
+	
+	/* Event Elements
+	------------------------------------------------------------------------------*/
+	
+	
+	// report when view creates an element for an event
+	function reportEventElement(event, element) {
+		eventElements.push(element);
+		if (eventElementsByID[event._id]) {
+			eventElementsByID[event._id].push(element);
+		}else{
+			eventElementsByID[event._id] = [element];
+		}
+	}
+	
+	
+	// attaches eventClick, eventMouseover, eventMouseout
+	function eventElementHandlers(event, eventElement) {
+		eventElement
+			.click(function(ev) {
+				if (!eventElement.hasClass('ui-draggable-dragging') &&
+					!eventElement.hasClass('ui-resizable-resizing')) {
+						return trigger('eventClick', this, event, ev);
+					}
+			})
+			.hover(
+				function(ev) {
+					trigger('eventMouseover', this, event, ev);
+				},
+				function(ev) {
+					trigger('eventMouseout', this, event, ev);
+				}
+			);
+		// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)
+		// TODO: same for resizing
+	}
+	
+	
+	function showEvents(event, exceptElement) {
+		eachEventElement(event, exceptElement, 'show');
+	}
+	
+	
+	function hideEvents(event, exceptElement) {
+		eachEventElement(event, exceptElement, 'hide');
+	}
+	
+	
+	function eachEventElement(event, exceptElement, funcName) {
+		var elements = eventElementsByID[event._id],
+			i, len = elements.length;
+		for (i=0; i<len; i++) {
+			if (elements[i][0] != exceptElement[0]) {
+				elements[i][funcName]();
+			}
+		}
+	}
+	
+	
+	
+	/* Event Modification Reporting
+	---------------------------------------------------------------------------------*/
+	
+	
+	function eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
+		var oldAllDay = event.allDay;
+		var eventId = event._id;
+		moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);
+		trigger('eventDrop', e, event, dayDelta, minuteDelta, allDay, function() {
+			// TODO: investigate cases where this inverse technique might not work
+			moveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);
+			rerenderEvents();
+		}, ev, ui);
+		t.eventsChanged = true;
+		rerenderEvents(eventId);
+	}
+	
+	
+	function eventResize(e, event, dayDelta, minuteDelta, ev, ui) {
+		var eventId = event._id;
+		elongateEvents(eventsByID[eventId], dayDelta, minuteDelta);
+		trigger('eventResize', e, event, dayDelta, minuteDelta, function() {
+			// TODO: investigate cases where this inverse technique might not work
+			elongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);
+			rerenderEvents();
+		}, ev, ui);
+		t.eventsChanged = true;
+		rerenderEvents(eventId);
+	}
+	
+	
+	
+	/* Event Modification Math
+	---------------------------------------------------------------------------------*/
+	
+	
+	function moveEvents(events, dayDelta, minuteDelta, allDay) {
+		minuteDelta = minuteDelta || 0;
+		for (var e, len=events.length, i=0; i<len; i++) {
+			e = events[i];
+			if (allDay !== undefined) {
+				e.allDay = allDay;
+			}
+			addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
+			if (e.end) {
+				e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
+			}
+			normalizeEvent(e, options);
+		}
+	}
+	
+	
+	function elongateEvents(events, dayDelta, minuteDelta) {
+		minuteDelta = minuteDelta || 0;
+		for (var e, len=events.length, i=0; i<len; i++) {
+			e = events[i];
+			e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);
+			normalizeEvent(e, options);
+		}
+	}
+	
+
+}

+ 129 - 0
src/common/common.css

@@ -0,0 +1,129 @@
+
+
+/* Global Event Styles
+------------------------------------------------------------------------*/
+
+.fc-event,
+.fc-agenda .fc-event-time,
+.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:
+	 *
+	 * .myclass,
+	 * .fc-agenda .myclass .fc-event-time,
+	 * .myclass a {
+	 *     background-color: black;
+	 *     border-color: black;
+	 *     color: red;
+	 *     }
+	 */
+	 
+.fc-event {
+	text-align: left;
+	}
+	
+.fc-event a {
+	overflow: hidden;
+	font-size: .85em;
+	text-decoration: none;
+	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; /* 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 */
+	}
+	
+	
+	

+ 41 - 294
src/util.js → src/common/date.js

@@ -1,10 +1,23 @@
 
 
+
+fc.addDays = addDays;
+fc.cloneDate = cloneDate;
+fc.parseDate = parseDate;
+fc.parseISO8601 = parseISO8601;
+fc.parseTime = parseTime;
+fc.formatDate = formatDate;
+fc.formatDates = formatDates;
+
+
+
 /* Date Math
 /* Date Math
 -----------------------------------------------------------------------------*/
 -----------------------------------------------------------------------------*/
 
 
-var DAY_MS = 86400000,
+var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
+	DAY_MS = 86400000,
 	HOUR_MS = 3600000,
 	HOUR_MS = 3600000,
 	MINUTE_MS = 60000;
 	MINUTE_MS = 60000;
+	
 
 
 function addYears(d, n, keepTime) {
 function addYears(d, n, keepTime) {
 	d.setFullYear(d.getFullYear() + n);
 	d.setFullYear(d.getFullYear() + n);
@@ -14,6 +27,7 @@ function addYears(d, n, keepTime) {
 	return d;
 	return d;
 }
 }
 
 
+
 function addMonths(d, n, keepTime) { // prevents day overflow/underflow
 function addMonths(d, n, keepTime) { // prevents day overflow/underflow
 	if (+d) { // prevent infinite looping on invalid dates
 	if (+d) { // prevent infinite looping on invalid dates
 		var m = d.getMonth() + n,
 		var m = d.getMonth() + n,
@@ -31,6 +45,7 @@ function addMonths(d, n, keepTime) { // prevents day overflow/underflow
 	return d;
 	return d;
 }
 }
 
 
+
 function addDays(d, n, keepTime) { // deals with daylight savings
 function addDays(d, n, keepTime) { // deals with daylight savings
 	if (+d) {
 	if (+d) {
 		var dd = d.getDate() + n,
 		var dd = d.getDate() + n,
@@ -45,7 +60,7 @@ function addDays(d, n, keepTime) { // deals with daylight savings
 	}
 	}
 	return d;
 	return d;
 }
 }
-fc.addDays = addDays;
+
 
 
 function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
 function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
 	if (+d) { // prevent infinite looping on invalid dates
 	if (+d) { // prevent infinite looping on invalid dates
@@ -55,11 +70,13 @@ function fixDate(d, check) { // force d to be on check's YMD, for daylight savin
 	}
 	}
 }
 }
 
 
+
 function addMinutes(d, n) {
 function addMinutes(d, n) {
 	d.setMinutes(d.getMinutes() + n);
 	d.setMinutes(d.getMinutes() + n);
 	return d;
 	return d;
 }
 }
 
 
+
 function clearTime(d) {
 function clearTime(d) {
 	d.setHours(0);
 	d.setHours(0);
 	d.setMinutes(0);
 	d.setMinutes(0);
@@ -68,13 +85,14 @@ function clearTime(d) {
 	return d;
 	return d;
 }
 }
 
 
+
 function cloneDate(d, dontKeepTime) {
 function cloneDate(d, dontKeepTime) {
 	if (dontKeepTime) {
 	if (dontKeepTime) {
 		return clearTime(new Date(+d));
 		return clearTime(new Date(+d));
 	}
 	}
 	return new Date(+d);
 	return new Date(+d);
 }
 }
-fc.cloneDate = cloneDate;
+
 
 
 function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
 function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
 	var i=0, d;
 	var i=0, d;
@@ -84,6 +102,7 @@ function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
 	return d;
 	return d;
 }
 }
 
 
+
 function skipWeekend(date, inc, excl) {
 function skipWeekend(date, inc, excl) {
 	inc = inc || 1;
 	inc = inc || 1;
 	while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
 	while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
@@ -92,10 +111,12 @@ function skipWeekend(date, inc, excl) {
 	return date;
 	return date;
 }
 }
 
 
+
 function dayDiff(d1, d2) { // d1 - d2
 function dayDiff(d1, d2) { // d1 - d2
 	return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
 	return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
 }
 }
 
 
+
 function setYMD(date, y, m, d) {
 function setYMD(date, y, m, d) {
 	if (y !== undefined && y != date.getFullYear()) {
 	if (y !== undefined && y != date.getFullYear()) {
 		date.setDate(1);
 		date.setDate(1);
@@ -116,7 +137,8 @@ function setYMD(date, y, m, d) {
 /* Date Parsing
 /* Date Parsing
 -----------------------------------------------------------------------------*/
 -----------------------------------------------------------------------------*/
 
 
-var parseDate = fc.parseDate = function(s, ignoreTimezone) {
+
+function parseDate(s, ignoreTimezone) {
 	if (typeof s == 'object') { // already a Date object
 	if (typeof s == 'object') { // already a Date object
 		return s;
 		return s;
 	}
 	}
@@ -134,9 +156,10 @@ var parseDate = fc.parseDate = function(s, ignoreTimezone) {
 	}
 	}
 	// TODO: never return invalid dates (like from new Date(<string>)), return null instead
 	// TODO: never return invalid dates (like from new Date(<string>)), return null instead
 	return null;
 	return null;
-};
+}
 
 
-var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
+
+function parseISO8601(s, ignoreTimezone) {
 	// derived from http://delete.me.uk/2005/03/iso8601.html
 	// derived from http://delete.me.uk/2005/03/iso8601.html
 	// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
 	// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
 	var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/);
 	var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/);
@@ -163,7 +186,7 @@ var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
 		if (m[12]) {
 		if (m[12]) {
 			date.setMilliseconds(Number("0." + m[12]) * 1000);
 			date.setMilliseconds(Number("0." + m[12]) * 1000);
 		}
 		}
-	} else {
+	}else{
 		date.setUTCFullYear(m[1]);
 		date.setUTCFullYear(m[1]);
 		if (m[3]) {
 		if (m[3]) {
 			date.setUTCMonth(m[3] - 1);
 			date.setUTCMonth(m[3] - 1);
@@ -171,7 +194,6 @@ var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
 		if (m[5]) {
 		if (m[5]) {
 			date.setUTCDate(m[5]);
 			date.setUTCDate(m[5]);
 		}
 		}
-		
 		if (m[7]) {
 		if (m[7]) {
 			date.setUTCHours(m[7]);
 			date.setUTCHours(m[7]);
 		}
 		}
@@ -190,11 +212,11 @@ var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
 		}
 		}
 		date = new Date(+date + (offset * 60 * 1000));
 		date = new Date(+date + (offset * 60 * 1000));
 	}
 	}
-	
 	return date;
 	return date;
-};
+}
+
 
 
-var parseTime = fc.parseTime = function(s) { // returns minutes since start of day
+function parseTime(s) { // returns minutes since start of day
 	if (typeof s == 'number') { // an hour
 	if (typeof s == 'number') { // an hour
 		return s * 60;
 		return s * 60;
 	}
 	}
@@ -212,18 +234,21 @@ var parseTime = fc.parseTime = function(s) { // returns minutes since start of d
 		}
 		}
 		return h * 60 + (m[2] ? parseInt(m[2]) : 0);
 		return h * 60 + (m[2] ? parseInt(m[2]) : 0);
 	}
 	}
-};
+}
 
 
 
 
 
 
 /* Date Formatting
 /* Date Formatting
 -----------------------------------------------------------------------------*/
 -----------------------------------------------------------------------------*/
+// TODO: use same function formatDate(date, [date2], format, [options])
+
 
 
-var formatDate = fc.formatDate = function(date, format, options) {
+function formatDate(date, format, options) {
 	return formatDates(date, null, format, options);
 	return formatDates(date, null, format, options);
-};
+}
 
 
-var formatDates = fc.formatDates = function(date1, date2, format, options) {
+
+function formatDates(date1, date2, format, options) {
 	options = options || defaults;
 	options = options || defaults;
 	var date = date1,
 	var date = date1,
 		otherDate = date2,
 		otherDate = date2,
@@ -300,6 +325,7 @@ var formatDates = fc.formatDates = function(date1, date2, format, options) {
 	return res;
 	return res;
 };
 };
 
 
+
 var dateFormatters = {
 var dateFormatters = {
 	s	: function(d)	{ return d.getSeconds() },
 	s	: function(d)	{ return d.getSeconds() },
 	ss	: function(d)	{ return zeroPad(d.getSeconds()) },
 	ss	: function(d)	{ return zeroPad(d.getSeconds()) },
@@ -334,282 +360,3 @@ var dateFormatters = {
 };
 };
 
 
 
 
-
-/* Element Dimensions
------------------------------------------------------------------------------*/
-
-function setOuterWidth(element, width, includeMargins) {
-	element.each(function(i, _element) {
-		_element.style.width = width - hsides(_element, includeMargins) + 'px';
-	});
-}
-
-function setOuterHeight(element, height, includeMargins) {
-	element.each(function(i, _element) {
-		_element.style.height = height - vsides(_element, includeMargins) + 'px';
-	});
-}
-
-
-function hsides(_element, includeMargins) {
-	return (parseFloat(jQuery.curCSS(_element, 'paddingLeft', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'paddingRight', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'borderLeftWidth', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'borderRightWidth', true)) || 0) +
-	       (includeMargins ? hmargins(_element) : 0);
-}
-
-function hmargins(_element) {
-	return (parseFloat(jQuery.curCSS(_element, 'marginLeft', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'marginRight', true)) || 0);
-}
-
-function vsides(_element, includeMargins) {
-	return (parseFloat(jQuery.curCSS(_element, 'paddingTop', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'paddingBottom', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'borderTopWidth', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'borderBottomWidth', true)) || 0) +
-	       (includeMargins ? vmargins(_element) : 0);
-}
-
-function vmargins(_element) {
-	return (parseFloat(jQuery.curCSS(_element, 'marginTop', true)) || 0) +
-	       (parseFloat(jQuery.curCSS(_element, 'marginBottom', true)) || 0);
-}
-
-
-
-
-function setMinHeight(element, h) {
-	h = typeof h == 'number' ? h + 'px' : h;
-	element[0].style.cssText += ';min-height:' + h + ';_height:' + h;
-}
-
-
-
-/* Position Calculation
------------------------------------------------------------------------------*/
-// nasty bugs in opera 9.25
-// position()'s top returning incorrectly with TR/TD or elements within TD
-
-var topBug;
-
-function topCorrect(tr) { // tr/th/td or anything else
-	if (topBug !== false) {
-		var cell;
-		if (tr.is('th,td')) {
-			tr = (cell = tr).parent();
-		}
-		if (topBug === undefined && tr.is('tr')) {
-			topBug = tr.position().top != tr.children().position().top;
-		}
-		if (topBug) {
-			return tr.parent().position().top + (cell ? tr.position().top - cell.position().top : 0);
-		}
-	}
-	return 0;
-}
-
-
-
-/* Coordinate Grid
------------------------------------------------------------------------------*/
-
-function CoordinateGrid(buildFunc) {
-
-	var t = this;
-	var rows;
-	var cols;
-	
-	t.build = function() {
-		rows = [];
-		cols = [];
-		buildFunc(rows, cols);
-	};
-	
-	t.cell = function(x, y) {
-		var rowCnt = rows.length;
-		var colCnt = cols.length;
-		var i, r=-1, c=-1;
-		for (i=0; i<rowCnt; i++) {
-			if (y >= rows[i][0] && y < rows[i][1]) {
-				r = i;
-				break;
-			}
-		}
-		for (i=0; i<colCnt; i++) {
-			if (x >= cols[i][0] && x < cols[i][1]) {
-				c = i;
-				break;
-			}
-		}
-		return (r>=0 && c>=0) ? { row:r, col:c } : null;
-	};
-	
-	t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive
-		var origin = originElement.offset();
-		return {
-			top: rows[row0][0] - origin.top,
-			left: cols[col0][0] - origin.left,
-			width: cols[col1][1] - cols[col0][0],
-			height: rows[row1][1] - rows[row0][0]
-		};
-	};
-
-}
-
-
-
-/* Hover Listener
------------------------------------------------------------------------------*/
-
-function HoverListener(coordinateGrid) {
-
-	var t = this;
-	var bindType;
-	var change;
-	var firstCell;
-	var cell;
-	
-	t.start = function(_change, ev, _bindType) {
-		change = _change;
-		firstCell = cell = null;
-		coordinateGrid.build();
-		mouse(ev);
-		bindType = _bindType || 'mousemove';
-		$(document).bind(bindType, mouse);
-	};
-	
-	function mouse(ev) {
-		var newCell = coordinateGrid.cell(ev.pageX, ev.pageY);
-		if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {
-			if (newCell) {
-				if (!firstCell) {
-					firstCell = newCell;
-				}
-				change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);
-			}else{
-				change(newCell, firstCell);
-			}
-			cell = newCell;
-		}
-	}
-	
-	t.stop = function() {
-		$(document).unbind(bindType, mouse);
-		return cell;
-	};
-	
-}
-
-
-
-/* Misc Utils
------------------------------------------------------------------------------*/
-
-var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
-
-function zeroPad(n) {
-	return (n < 10 ? '0' : '') + n;
-}
-
-function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
-	if (obj[name] !== undefined) {
-		return obj[name];
-	}
-	var parts = name.split(/(?=[A-Z])/),
-		i=parts.length-1, res;
-	for (; i>=0; i--) {
-		res = obj[parts[i].toLowerCase()];
-		if (res !== undefined) {
-			return res;
-		}
-	}
-	return obj[''];
-}
-
-function htmlEscape(s) {
-	return s.replace(/&/g, '&amp;')
-		.replace(/</g, '&lt;')
-		.replace(/>/g, '&gt;')
-		.replace(/'/g, '&#039;')
-		.replace(/"/g, '&quot;')
-		.replace(/\n/g, '<br />');
-}
-
-
-
-function HorizontalPositionCache(getElement) {
-
-	var t = this,
-		elements = {},
-		lefts = {},
-		rights = {};
-		
-	function e(i) {
-		return elements[i] = elements[i] || getElement(i);
-	}
-	
-	t.left = function(i) {
-		return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];
-	};
-	
-	t.right = function(i) {
-		return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];
-	};
-	
-	t.clear = function() {
-		elements = {};
-		lefts = {};
-		rights = {};
-	};
-	
-}
-
-
-
-function cssKey(_element) {
-	return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');
-}
-
-
-
-function cmp(a, b) {
-	return a - b;
-}
-
-
-
-function exclEndDay(event) {
-	if (event.end) {
-		return _exclEndDay(event.end, event.allDay);
-	}else{
-		return addDays(cloneDate(event.start), 1);
-	}
-}
-
-function _exclEndDay(end, allDay) {
-	end = cloneDate(end);
-	return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);
-}
-
-
-
-function disableTextSelection(element) {
-	element
-		.attr('unselectable', 'on')
-		.css('MozUserSelect', 'none')
-		.bind('selectstart.ui', function() { return false; });
-}
-
-/*
-function enableTextSelection(element) {
-	element
-		.attr('unselectable', 'off')
-		.css('MozUserSelect', '')
-		.unbind('selectstart.ui');
-}
-*/
-
-
-

+ 285 - 0
src/common/util.js

@@ -0,0 +1,285 @@
+
+
+/* Event Date Math
+-----------------------------------------------------------------------------*/
+
+
+function exclEndDay(event) {
+	if (event.end) {
+		return _exclEndDay(event.end, event.allDay);
+	}else{
+		return addDays(cloneDate(event.start), 1);
+	}
+}
+
+
+function _exclEndDay(end, allDay) {
+	end = cloneDate(end);
+	return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);
+}
+
+
+function segCmp(a, b) {
+	return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
+}
+
+
+function segsCollide(seg1, seg2) {
+	return seg1.end > seg2.start && seg1.start < seg2.end;
+}
+
+
+
+/* Event Sorting
+-----------------------------------------------------------------------------*/
+
+
+// event rendering utilities
+function sliceSegs(events, visEventEnds, start, end) {
+	var segs = [],
+		i, len=events.length, event,
+		eventStart, eventEnd,
+		segStart, segEnd,
+		isStart, isEnd;
+	for (i=0; i<len; i++) {
+		event = events[i];
+		eventStart = event.start;
+		eventEnd = visEventEnds[i];
+		if (eventEnd > start && eventStart < end) {
+			if (eventStart < start) {
+				segStart = cloneDate(start);
+				isStart = false;
+			}else{
+				segStart = eventStart;
+				isStart = true;
+			}
+			if (eventEnd > end) {
+				segEnd = cloneDate(end);
+				isEnd = false;
+			}else{
+				segEnd = eventEnd;
+				isEnd = true;
+			}
+			segs.push({
+				event: event,
+				start: segStart,
+				end: segEnd,
+				isStart: isStart,
+				isEnd: isEnd,
+				msLength: segEnd - segStart
+			});
+		}
+	} 
+	return segs.sort(segCmp);
+}
+
+
+// event rendering calculation utilities
+function stackSegs(segs) {
+	var levels = [],
+		i, len = segs.length, seg,
+		j, collide, k;
+	for (i=0; i<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];
+		}
+	}
+	return levels;
+}
+
+
+
+/* Event Element Binding
+-----------------------------------------------------------------------------*/
+
+
+function lazySegBind(container, segs, bindHandlers) {
+	container.unbind('mouseover').mouseover(function(ev) {
+		var parent=ev.target, e,
+			i, seg;
+		while (parent != this) {
+			e = parent;
+			parent = parent.parentNode;
+		}
+		if ((i = e._fci) !== undefined) {
+			e._fci = undefined;
+			seg = segs[i];
+			bindHandlers(seg.event, seg.element, seg);
+			$(ev.target).trigger(ev);
+		}
+		ev.stopPropagation();
+	});
+}
+
+
+
+/* Element Dimensions
+-----------------------------------------------------------------------------*/
+
+
+function setOuterWidth(element, width, includeMargins) {
+	element.each(function(i, _element) {
+		_element.style.width = width - hsides(_element, includeMargins) + 'px';
+	});
+}
+
+
+function setOuterHeight(element, height, includeMargins) {
+	element.each(function(i, _element) {
+		_element.style.height = height - vsides(_element, includeMargins) + 'px';
+	});
+}
+
+
+function hsides(_element, includeMargins) {
+	return (parseFloat($.curCSS(_element, 'paddingLeft', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'paddingRight', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'borderLeftWidth', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'borderRightWidth', true)) || 0) +
+	       (includeMargins ? hmargins(_element) : 0);
+}
+
+
+function hmargins(_element) {
+	return (parseFloat($.curCSS(_element, 'marginLeft', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'marginRight', true)) || 0);
+}
+
+
+function vsides(_element, includeMargins) {
+	return (parseFloat($.curCSS(_element, 'paddingTop', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'paddingBottom', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'borderTopWidth', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'borderBottomWidth', true)) || 0) +
+	       (includeMargins ? vmargins(_element) : 0);
+}
+
+
+function vmargins(_element) {
+	return (parseFloat($.curCSS(_element, 'marginTop', true)) || 0) +
+	       (parseFloat($.curCSS(_element, 'marginBottom', true)) || 0);
+}
+
+
+function setMinHeight(element, h) {
+	h = typeof h == 'number' ? h + 'px' : h;
+	element[0].style.cssText += ';min-height:' + h + ';_height:' + h;
+}
+
+
+
+/* Position Calculation
+-----------------------------------------------------------------------------*/
+// nasty bugs in opera 9.25
+// position()'s top returning incorrectly with TR/TD or elements within TD
+
+var topBug;
+
+function topCorrect(tr) { // tr/th/td or anything else
+	if (topBug !== false) {
+		var cell;
+		if (tr.is('th,td')) {
+			tr = (cell = tr).parent();
+		}
+		if (topBug === undefined && tr.is('tr')) {
+			topBug = tr.position().top != tr.children().position().top;
+		}
+		if (topBug) {
+			return tr.parent().position().top + (cell ? tr.position().top - cell.position().top : 0);
+		}
+	}
+	return 0;
+}
+
+
+
+/* Misc Utils
+-----------------------------------------------------------------------------*/
+
+
+//TODO: arraySlice
+//TODO: isFunction, grep ?
+
+
+function noop() { }
+
+
+function cmp(a, b) {
+	return a - b;
+}
+
+
+function zeroPad(n) {
+	return (n < 10 ? '0' : '') + n;
+}
+
+
+function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
+	if (obj[name] !== undefined) {
+		return obj[name];
+	}
+	var parts = name.split(/(?=[A-Z])/),
+		i=parts.length-1, res;
+	for (; i>=0; i--) {
+		res = obj[parts[i].toLowerCase()];
+		if (res !== undefined) {
+			return res;
+		}
+	}
+	return obj[''];
+}
+
+
+function htmlEscape(s) {
+	return s.replace(/&/g, '&amp;')
+		.replace(/</g, '&lt;')
+		.replace(/>/g, '&gt;')
+		.replace(/'/g, '&#039;')
+		.replace(/"/g, '&quot;')
+		.replace(/\n/g, '<br />');
+}
+
+
+function cssKey(_element) {
+	return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');
+}
+
+
+function disableTextSelection(element) {
+	element
+		.attr('unselectable', 'on')
+		.css('MozUserSelect', 'none')
+		.bind('selectstart.ui', function() { return false; });
+}
+
+
+/*
+function enableTextSelection(element) {
+	element
+		.attr('unselectable', 'off')
+		.css('MozUserSelect', '')
+		.unbind('selectstart.ui');
+}
+*/
+
+

+ 93 - 0
src/defaults.js

@@ -0,0 +1,93 @@
+
+var defaults = {
+
+	// display
+	defaultView: 'month',
+	aspectRatio: 1.35,
+	header: {
+		left: 'title',
+		center: '',
+		right: 'today prev,next'
+	},
+	weekends: true,
+	
+	// editing
+	//editable: false,
+	//disableDragging: false,
+	//disableResizing: false,
+	
+	allDayDefault: true,
+	ignoreTimezone: true,
+	
+	// event ajax
+	lazyFetching: true,
+	startParam: 'start',
+	endParam: 'end',
+	
+	// time formats
+	titleFormat: {
+		month: 'MMMM yyyy',
+		week: "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
+		day: 'dddd, MMM d, yyyy'
+	},
+	columnFormat: {
+		month: 'ddd',
+		week: 'ddd M/d',
+		day: 'dddd M/d'
+	},
+	timeFormat: { // for event elements
+		'': 'h(:mm)t' // default
+	},
+	
+	// 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;',
+		prevYear: '&nbsp;&lt;&lt;&nbsp;',
+		nextYear: '&nbsp;&gt;&gt;&nbsp;',
+		today: 'today',
+		month: 'month',
+		week: 'week',
+		day: 'day'
+	},
+	
+	// jquery-ui theming
+	theme: false,
+	buttonIcons: {
+		prev: 'circle-triangle-w',
+		next: 'circle-triangle-e'
+	},
+	
+	//selectable: false,
+	unselectAuto: true,
+	
+	dropAccept: '*'
+	
+};
+
+// right-to-left defaults
+var rtlDefaults = {
+	header: {
+		left: 'next,prev today',
+		center: '',
+		right: 'title'
+	},
+	buttonText: {
+		prev: '&nbsp;&#9658;&nbsp;',
+		next: '&nbsp;&#9668;&nbsp;',
+		prevYear: '&nbsp;&gt;&gt;&nbsp;',
+		nextYear: '&nbsp;&lt;&lt;&nbsp;'
+	},
+	buttonIcons: {
+		prev: 'circle-triangle-e',
+		next: 'circle-triangle-w'
+	}
+};
+
+

+ 6 - 0
src/gcal/_loader.js

@@ -0,0 +1,6 @@
+
+startload();
+
+js('gcal.js');
+
+endload();

+ 3 - 4
src/gcal.js → src/gcal/gcal.js

@@ -1,10 +1,9 @@
 /*
 /*
  * FullCalendar v@VERSION Google Calendar Extension
  * FullCalendar v@VERSION 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
+ * Copyright (c) 2010 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
  *
  *
  * Date: @DATE
  * Date: @DATE
  *
  *

+ 0 - 792
src/grid.js

@@ -1,792 +0,0 @@
-
-/* Grid-based Views: month, basicWeek, basicDay
------------------------------------------------------------------------------*/
-
-setDefaults({
-	weekMode: 'fixed'
-});
-
-views.month = function(element, options, viewName) {
-	return new Grid(element, options, {
-		render: function(date, delta) {
-			if (delta) {
-				addMonths(date, delta);
-				date.setDate(1);
-			}
-			// start/end
-			var start = this.start = cloneDate(date, true);
-			start.setDate(1);
-			this.end = addMonths(cloneDate(start), 1);
-			// visStart/visEnd
-			var visStart = this.visStart = cloneDate(start),
-				visEnd = this.visEnd = cloneDate(this.end),
-				nwe = options.weekends ? 0 : 1;
-			if (nwe) {
-				skipWeekend(visStart);
-				skipWeekend(visEnd, -1, true);
-			}
-			addDays(visStart, -((visStart.getDay() - Math.max(options.firstDay, nwe) + 7) % 7));
-			addDays(visEnd, (7 - visEnd.getDay() + Math.max(options.firstDay, nwe)) % 7);
-			// row count
-			var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));
-			if (options.weekMode == 'fixed') {
-				addDays(visEnd, (6 - rowCnt) * 7);
-				rowCnt = 6;
-			}
-			// title
-			this.title = formatDate(
-				start,
-				this.option('titleFormat'),
-				options
-			);
-			// render
-			this.renderGrid(
-				rowCnt, options.weekends ? 7 : 5,
-				this.option('columnFormat'),
-				true
-			);
-		}
-	}, viewName);
-};
-
-views.basicWeek = function(element, options, viewName) {
-	return new Grid(element, options, {
-		render: function(date, delta) {
-			if (delta) {
-				addDays(date, delta * 7);
-			}
-			var visStart = this.visStart = cloneDate(
-					this.start = addDays(cloneDate(date), -((date.getDay() - options.firstDay + 7) % 7))
-				),
-				visEnd = this.visEnd = cloneDate(
-					this.end = addDays(cloneDate(visStart), 7)
-				);
-			if (!options.weekends) {
-				skipWeekend(visStart);
-				skipWeekend(visEnd, -1, true);
-			}
-			this.title = formatDates(
-				visStart,
-				addDays(cloneDate(visEnd), -1),
-				this.option('titleFormat'),
-				options
-			);
-			this.renderGrid(
-				1, options.weekends ? 7 : 5,
-				this.option('columnFormat'),
-				false
-			);
-		}
-	}, viewName);
-};
-
-views.basicDay = function(element, options, viewName) {
-	return new Grid(element, options, {
-		render: function(date, delta) {
-			if (delta) {
-				addDays(date, delta);
-				if (!options.weekends) {
-					skipWeekend(date, delta < 0 ? -1 : 1);
-				}
-			}
-			this.title = formatDate(date, this.option('titleFormat'), options);
-			this.start = this.visStart = cloneDate(date, true);
-			this.end = this.visEnd = addDays(cloneDate(this.start), 1);
-			this.renderGrid(
-				1, 1,
-				this.option('columnFormat'),
-				false
-			);
-		}
-	}, viewName);
-};
-
-
-// rendering bugs
-
-var tdHeightBug;
-
-
-function Grid(element, options, methods, viewName) {
-	
-	var tm, firstDay,
-		nwe,            // no weekends (int)
-		rtl, dis, dit,  // day index sign / translate
-		viewWidth, viewHeight,
-		rowCnt, colCnt,
-		colWidth,
-		thead, tbody,
-		cachedEvents=[],
-		segmentContainer,
-		dayContentPositions = new HorizontalPositionCache(function(dayOfWeek) {
-			return tbody.find('td:eq(' + ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt) + ') div div');
-		}),
-		// ...
-		
-	// initialize superclass
-	view = $.extend(this, viewMethods, methods, {
-		renderGrid: renderGrid,
-		renderEvents: renderEvents,
-		rerenderEvents: rerenderEvents,
-		clearEvents: clearEvents,
-		setHeight: setHeight,
-		setWidth: setWidth,
-		defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing
-			return cloneDate(event.start);
-		}
-	});
-	view.name = viewName;
-	view.init(element, options);
-	
-	
-	
-	/* Grid Rendering
-	-----------------------------------------------------------------------------*/
-	
-	
-	disableTextSelection(element.addClass('fc-grid'));
-	
-
-	function renderGrid(r, c, colFormat, showNumbers) {
-	
-		rowCnt = r;
-		colCnt = c;
-		
-		// update option-derived variables
-		tm = options.theme ? 'ui' : 'fc';
-		nwe = options.weekends ? 0 : 1;
-		firstDay = options.firstDay;
-		if (rtl = options.isRTL) {
-			dis = -1;
-			dit = colCnt - 1;
-		}else{
-			dis = 1;
-			dit = 0;
-		}
-		
-		var month = view.start.getMonth(),
-			today = clearTime(new Date()),
-			s, i, j, d = cloneDate(view.visStart);
-		
-		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);
-				if (nwe) {
-					skipWeekend(d);
-				}
-			}
-			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 style='position:relative'>&nbsp;</div></div></td>";
-					addDays(d, 1);
-					if (nwe) {
-						skipWeekend(d);
-					}
-				}
-				s += "</tr>";
-			}
-			tbody = $(s + "</tbody>").appendTo(table);
-			dayBind(tbody.find('td'));
-			
-			segmentContainer = $("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(element);
-		
-		}else{ // NOT first time, reuse as many cells as possible
-		
-			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 style='position:relative'>&nbsp;</div></div>" +
-							"</td>";
-						addDays(d, 1);
-						if (nwe) {
-							skipWeekend(d);
-						}
-					}
-					s += "</tr>";
-				}
-				tbody.append(s);
-			}
-			dayBind(tbody.find('td.fc-new').removeClass('fc-new'));
-			
-			// 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 (nwe) {
-					skipWeekend(d);
-				}
-			});
-			
-			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);
-					if (nwe) {
-						skipWeekend(d);
-					}
-				});
-				
-				// 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);
-					if (nwe) {
-						skipWeekend(d);
-					}
-				});
-				
-			}
-		
-		}
-		
-	}
-	
-	
-	
-	function setHeight(height) {
-		viewHeight = height;
-		var leftTDs = tbody.find('tr td:first-child'),
-			tbodyHeight = viewHeight - 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 (tdHeightBug === undefined) {
-			// bug in firefox where cell height includes padding
-			var tr = tbody.find('tr:first'),
-				td = tr.find('td:first');
-			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);
-		}
-	}
-	
-	
-	function setWidth(width) {
-		viewWidth = width;
-		dayContentPositions.clear();
-		setOuterWidth(
-			thead.find('th').slice(0, -1),
-			colWidth = Math.floor(viewWidth / colCnt)
-		);
-	}
-
-	
-	
-	/* Event Rendering
-	-----------------------------------------------------------------------------*/
-	
-	
-	function renderEvents(events) {
-		view.reportEvents(cachedEvents = events);
-		renderSegs(compileSegs(events));
-	}
-	
-	
-	function rerenderEvents(modifiedEventId) {
-		clearEvents();
-		renderSegs(compileSegs(cachedEvents), modifiedEventId);
-	}
-	
-	
-	function clearEvents() {
-		view._clearEvents(); // only clears the hashes
-		segmentContainer.empty();
-	}
-	
-	
-	function compileSegs(events) {
-		var d1 = cloneDate(view.visStart),
-			d2 = addDays(cloneDate(d1), colCnt),
-			visEventsEnds = $.map(events, exclEndDay),
-			i, row,
-			j, level,
-			k, seg,
-			segs=[];
-		for (i=0; i<rowCnt; i++) {
-			row = stackSegs(view.sliceSegs(events, visEventsEnds, d1, d2));
-			for (j=0; j<row.length; j++) {
-				level = row[j];
-				for (k=0; k<level.length; k++) {
-					seg = level[k];
-					seg.row = i;
-					seg.level = j;
-					segs.push(seg);
-				}
-			}
-			addDays(d1, 7);
-			addDays(d2, 7);
-		}
-		return segs;
-	}
-	
-	
-	function renderSegs(segs, modifiedEventId) {
-		_renderDaySegs(
-			segs,
-			rowCnt,
-			view,
-			0,
-			viewWidth,
-			function(i) { return tbody.find('tr:eq('+i+')') },
-			dayContentPositions.left,
-			dayContentPositions.right,
-			segmentContainer,
-			bindSegHandlers,
-			modifiedEventId
-		);
-	}
-	
-	
-	function bindSegHandlers(event, eventElement, seg) {
-		view.eventElementHandlers(event, eventElement);
-		if (event.editable || event.editable === undefined && options.editable) {
-			draggableEvent(event, eventElement);
-			if (seg.isEnd) {
-				view.resizableDayEvent(event, eventElement, colWidth);
-			}
-		}
-	}
-	
-	
-	
-	/* Event Dragging
-	-----------------------------------------------------------------------------*/
-	
-	
-	function draggableEvent(event, eventElement) {
-		if (!options.disableDragging && eventElement.draggable) {
-			var dayDelta;
-			eventElement.draggable({
-				zIndex: 9,
-				delay: 50,
-				opacity: view.option('dragOpacity'),
-				revertDuration: options.dragRevertDuration,
-				start: function(ev, ui) {
-					view.trigger('eventDragStart', eventElement, event, ev, ui);
-					view.hideEvents(event, eventElement);
-					hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
-						eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
-						clearOverlay();
-						if (cell) {
-							dayDelta = rowDelta*7 + colDelta*dis;
-							renderDayOverlay(
-								addDays(cloneDate(event.start), dayDelta),
-								addDays(exclEndDay(event), dayDelta)
-							);
-						}else{
-							dayDelta = 0;
-						}
-					}, ev, 'drag');
-				},
-				stop: function(ev, ui) {
-					hoverListener.stop();
-					clearOverlay();
-					view.trigger('eventDragStop', eventElement, event, ev, ui);
-					if (dayDelta) {
-						eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
-						view.eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);
-					}else{
-						if ($.browser.msie) {
-							eventElement.css('filter', ''); // clear IE opacity side-effects
-						}
-						view.showEvents(event, eventElement);
-					}
-				}
-			});
-		}
-	}
-	
-	
-	
-	/* Day clicking and binding
-	---------------------------------------------------------*/
-	
-	function dayBind(days) {
-		days.click(dayClick)
-			.mousedown(selectionMousedown);
-	}
-	
-	function dayClick(ev) {
-		if (!view.option('selectable')) { // SelectionManager will worry about dayClick
-			var n = parseInt(this.className.match(/fc\-day(\d+)/)[1]),
-				date = addDays(
-					cloneDate(view.visStart),
-					Math.floor(n/colCnt) * 7 + n % colCnt
-				);
-			// TODO: what about weekends in middle of week?
-			view.trigger('dayClick', this, date, true, ev);
-		}
-	}
-	
-	
-	
-	/* Coordinate Utilities
-	--------------------------------------------------------*/
-	
-	var coordinateGrid = new CoordinateGrid(function(rows, cols) {
-		var e, n, p;
-		var tds = tbody.find('tr:first td');
-		if (rtl) {
-			tds = $(tds.get().reverse());
-		}
-		tds.each(function(i, _e) {
-			e = $(_e);
-			n = e.offset().left;
-			if (i) {
-				p[1] = n;
-			}
-			p = [n];
-			cols[i] = p;
-		});
-		p[1] = n + e.outerWidth();
-		tbody.find('tr').each(function(i, _e) {
-			e = $(_e);
-			n = e.offset().top;
-			if (i) {
-				p[1] = n;
-			}
-			p = [n];
-			rows[i] = p;
-		});
-		p[1] = n + e.outerHeight();
-	});
-	
-	var hoverListener = new HoverListener(coordinateGrid);
-	
-	
-	
-	/* Selecting
-	--------------------------------------------------------*/
-	
-	var selected = false;
-	var selectionMousedown = selection_dayMousedown(
-		view, hoverListener, cellDate, function(){return true}, renderDayOverlay, clearOverlay, reportSelection, unselect
-	);
-	
-	view.select = function(startDate, endDate, allDay) {
-		coordinateGrid.build();
-		unselect();
-		if (!endDate) {
-			endDate = cloneDate(startDate);
-		}
-		renderDayOverlay(startDate, addDays(cloneDate(endDate), 1));
-		reportSelection(startDate, endDate, allDay);
-	};
-	
-	function reportSelection(startDate, endDate, allDay, ev) {
-		selected = true;
-		view.trigger('select', view, startDate, endDate, allDay, ev);
-	}
-	
-	function unselect(ev) {
-		if (selected) {
-			clearOverlay();
-			selected = false;
-			view.trigger('unselect', view, ev);
-		}
-	}
-	view.unselect = unselect;
-	
-	selection_unselectAuto(view, unselect);
-	
-	
-	
-	/* External dragging
-	------------------------------------------------------*/
-	
-	view.dragStart = function(_dragElement, ev, ui) {
-		hoverListener.start(function(cell) {
-			clearOverlay();
-			if (cell) {
-				_renderDayOverlay(cell.row, cell.col, cell.row, cell.col);
-			}
-		}, ev);
-	};
-	
-	view.dragStop = function(_dragElement, ev, ui) {
-		var cell = hoverListener.stop();
-		clearOverlay();
-		if (cell) {
-			var d = cellDate(cell);
-			view.trigger('drop', _dragElement, d, true, ev, ui);
-		}
-	};
-	
-	
-	
-	/* Semi-transparent Overlay Helpers
-	------------------------------------------------------*/
-	
-	function renderDayOverlay(overlayStart, overlayEnd) { // overlayEnd is exclusive
-		var rowStart = cloneDate(view.visStart);
-		var rowEnd = addDays(cloneDate(rowStart), colCnt);
-		for (var i=0; i<rowCnt; i++) {
-			var stretchStart = new Date(Math.max(rowStart, overlayStart));
-			var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));
-			if (stretchStart < stretchEnd) {
-				var colStart, colEnd;
-				if (rtl) {
-					colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;
-					colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;
-				}else{
-					colStart = dayDiff(stretchStart, rowStart);
-					colEnd = dayDiff(stretchEnd, rowStart);
-				}
-				dayBind(
-					_renderDayOverlay(i, colStart, i, colEnd-1)
-				);
-			}
-			addDays(rowStart, 7);
-			addDays(rowEnd, 7);
-		}
-	}
-	
-	function _renderDayOverlay(row0, col0, row1, col1) { // row1,col1 is inclusive
-		var rect = coordinateGrid.rect(row0, col0, row1, col1, element);
-		return view.renderOverlay(rect, element);
-	}
-	
-	function clearOverlay() {
-		view.clearOverlays();
-	}
-	
-	
-	
-	/* Date Utils
-	---------------------------------------------------*/
-	
-	
-	function cellDate(cell) {
-		return addDays(cloneDate(view.visStart), cell.row*7 + cell.col*dis+dit);
-		// TODO: what about weekends in middle of week?
-	}
-	
-
-}
-
-
-function _renderDaySegs(segs, rowCnt, view, minLeft, maxLeft, getRow, dayContentLeft, dayContentRight, segmentContainer, bindSegHandlers, modifiedEventId) {
-
-	var options=view.options,
-		rtl=options.isRTL,
-		i, segCnt=segs.length, seg,
-		event,
-		className,
-		left, right,
-		html='',
-		eventElements,
-		eventElement,
-		triggerRes,
-		hsideCache={},
-		vmarginCache={},
-		key, val,
-		rowI, top, levelI, levelHeight,
-		rowDivs=[],
-		rowDivTops=[];
-		
-	// calculate desired position/dimensions, create html
-	for (i=0; i<segCnt; i++) {
-		seg = segs[i];
-		event = seg.event;
-		className = 'fc-event fc-event-hori ';
-		if (rtl) {
-			if (seg.isStart) {
-				className += 'fc-corner-right ';
-			}
-			if (seg.isEnd) {
-				className += 'fc-corner-left ';
-			}
-			left = seg.isEnd ? dayContentLeft(seg.end.getDay()-1) : minLeft;
-			right = seg.isStart ? dayContentRight(seg.start.getDay()) : maxLeft;
-		}else{
-			if (seg.isStart) {
-				className += 'fc-corner-left ';
-			}
-			if (seg.isEnd) {
-				className += 'fc-corner-right ';
-			}
-			left = seg.isStart ? dayContentLeft(seg.start.getDay()) : minLeft;
-			right = seg.isEnd ? dayContentRight(seg.end.getDay()-1) : maxLeft;
-		}
-		html +=
-			"<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;left:"+left+"px'>" +
-				"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
-					(!event.allDay && seg.isStart ?
-						"<span class='fc-event-time'>" +
-							htmlEscape(formatDates(event.start, event.end, view.option('timeFormat'), options)) +
-						"</span>"
-					:'') +
-					"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
-				"</a>" +
-				((event.editable || event.editable === undefined && options.editable) && !options.disableResizing && $.fn.resizable ?
-					"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
-					: '') +
-			"</div>";
-		seg.left = left;
-		seg.outerWidth = right - left;
-	}
-	segmentContainer[0].innerHTML = html; // faster than html()
-	eventElements = segmentContainer.children();
-	
-	// retrieve elements, run through eventRender callback, bind handlers
-	for (i=0; i<segCnt; i++) {
-		seg = segs[i];
-		eventElement = $(eventElements[i]); // faster than eq()
-		event = seg.event;
-		triggerRes = view.trigger('eventRender', event, event, eventElement);
-		if (triggerRes === false) {
-			eventElement.remove();
-		}else{
-			if (triggerRes && triggerRes !== true) {
-				eventElement.remove();
-				eventElement = $(triggerRes)
-					.css({
-						position: 'absolute',
-						left: seg.left
-					})
-					.appendTo(segmentContainer);
-			}
-			seg.element = eventElement;
-			if (event._id === modifiedEventId) {
-				bindSegHandlers(event, eventElement, seg);
-			}else{
-				eventElement[0]._fci = i; // for lazySegBind
-			}
-			view.reportEventElement(event, eventElement);
-		}
-	}
-	
-	lazySegBind(segmentContainer, segs, bindSegHandlers);
-	
-	// record event horizontal sides
-	for (i=0; i<segCnt; i++) {
-		seg = segs[i];
-		if (eventElement = seg.element) {
-			val = hsideCache[key = seg.key = cssKey(eventElement[0])];
-			seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
-		}
-	}
-	
-	// set event widths
-	for (i=0; i<segCnt; i++) {
-		seg = segs[i];
-		if (eventElement = seg.element) {
-			eventElement[0].style.width = seg.outerWidth - seg.hsides + 'px';
-		}
-	}
-	
-	// record event heights
-	for (i=0; i<segCnt; i++) {
-		seg = segs[i];
-		if (eventElement = seg.element) {
-			val = vmarginCache[key = seg.key];
-			seg.outerHeight = eventElement[0].offsetHeight + (
-				val === undefined ? (vmarginCache[key] = vmargins(eventElement[0])) : val
-			);
-		}
-	}
-	
-	// set row heights, calculate event tops (in relation to row top)
-	for (i=0, rowI=0; rowI<rowCnt; rowI++) {
-		top = levelI = levelHeight = 0;
-		while (i<segCnt && (seg = segs[i]).row == rowI) {
-			if (seg.level != levelI) {
-				top += levelHeight;
-				levelHeight = 0;
-				levelI++;
-			}
-			levelHeight = Math.max(levelHeight, seg.outerHeight||0);
-			seg.top = top;
-			i++;
-		}
-		rowDivs[rowI] = getRow(rowI).find('td:first div.fc-day-content > div') // optimal selector?
-			.height(top + levelHeight);
-	}
-	
-	// calculate row tops
-	for (rowI=0; rowI<rowCnt; rowI++) {
-		rowDivTops[rowI] = rowDivs[rowI][0].offsetTop;
-	}
-	
-	// set event tops
-	for (i=0; i<segCnt; i++) {
-		seg = segs[i];
-		if (eventElement = seg.element) {
-			eventElement[0].style.top = rowDivTops[seg.row] + seg.top + 'px';
-			event = seg.event;
-			view.trigger('eventAfterRender', event, event, eventElement);
-		}
-	}
-	
-}
-
-

+ 19 - 0
src/intro.js

@@ -0,0 +1,19 @@
+/**
+ * @preserve
+ * FullCalendar v@VERSION
+ * http://arshaw.com/fullcalendar/
+ *
+ * Use fullcalendar.css for basic styling.
+ * For event drag & drop, requires jQuery UI draggable.
+ * For event resizing, requires jQuery UI resizable.
+ *
+ * Copyright (c) 2010 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+ *
+ * Date: @DATE
+ *
+ */
+ 
+(function($, undefined) {
+

+ 3 - 126
src/css/main.css → src/main.css

@@ -8,6 +8,9 @@
  * Date: @DATE
  * Date: @DATE
  *
  *
  */
  */
+ 
+ 
+/* TODO: make font sizes look the same in all doctypes */
 
 
 
 
 .fc,
 .fc,
@@ -232,129 +235,3 @@ table.fc-header {
 	
 	
 	
 	
 	
 	
-/* Global Event Styles
-------------------------------------------------------------------------*/
-
-.fc-event,
-.fc-agenda .fc-event-time,
-.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:
-	 *
-	 * .myclass,
-	 * .fc-agenda .myclass .fc-event-time,
-	 * .myclass a {
-	 *     background-color: black;
-	 *     border-color: black;
-	 *     color: red;
-	 *     }
-	 */
-	 
-.fc-event {
-	text-align: left;
-	}
-	
-.fc-event a {
-	overflow: hidden;
-	font-size: .85em;
-	text-decoration: none;
-	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; /* 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 */
-	}
-	
-	

+ 26 - 877
src/main.js

@@ -1,128 +1,24 @@
 
 
 var fc = $.fullCalendar = {};
 var fc = $.fullCalendar = {};
-var views = fc.views = {};
+var fcViews = fc.views = {};
 
 
 
 
-/* Defaults
------------------------------------------------------------------------------*/
-
-var defaults = {
-
-	// display
-	defaultView: 'month',
-	aspectRatio: 1.35,
-	header: {
-		left: 'title',
-		center: '',
-		right: 'today prev,next'
-	},
-	weekends: true,
-	
-	// editing
-	//editable: false,
-	//disableDragging: false,
-	//disableResizing: false,
-	
-	allDayDefault: true,
-	
-	// event ajax
-	lazyFetching: true,
-	startParam: 'start',
-	endParam: 'end',
-	
-	// time formats
-	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'
-	},
-	timeFormat: { // for event elements
-		'': 'h(:mm)t' // default
-	},
-	// ignoreTimezone for ISO8601 dates in added Events
-	ignoreTimezone: true,
-	
-	// 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;',
-		prevYear: '&nbsp;&lt;&lt;&nbsp;',
-		nextYear: '&nbsp;&gt;&gt;&nbsp;',
-		today: 'today',
-		month: 'month',
-		week: 'week',
-		day: 'day'
-	},
-	
-	// jquery-ui theming
-	theme: false,
-	buttonIcons: {
-		prev: 'circle-triangle-w',
-		next: 'circle-triangle-e'
-	},
-	
-	//selectable: false,
-	unselectAuto: true,
-	
-	dropAccept: '*'
-	
-};
-
-// right-to-left defaults
-var rtlDefaults = {
-	header: {
-		left: 'next,prev today',
-		center: '',
-		right: 'title'
-	},
-	buttonText: {
-		prev: '&nbsp;&#9658;&nbsp;',
-		next: '&nbsp;&#9668;&nbsp;',
-		prevYear: '&nbsp;&gt;&gt;&nbsp;',
-		nextYear: '&nbsp;&lt;&lt;&nbsp;'
-	},
-	buttonIcons: {
-		prev: 'circle-triangle-e',
-		next: 'circle-triangle-w'
-	}
-};
-
-// function for adding/overriding defaults
-var setDefaults = fc.setDefaults = function(d) {
-	$.extend(true, defaults, d);
-};
-
-
-
-/* .fullCalendar jQuery function
------------------------------------------------------------------------------*/
-
 $.fn.fullCalendar = function(options) {
 $.fn.fullCalendar = function(options) {
 
 
+
 	// method calling
 	// method calling
 	if (typeof options == 'string') {
 	if (typeof options == 'string') {
-		var args = Array.prototype.slice.call(arguments, 1),
-			res;
+		var args = Array.prototype.slice.call(arguments, 1);
+		var res;
 		this.each(function() {
 		this.each(function() {
-			var data = $.data(this, 'fullCalendar');
-			if (data) {
-				var meth = data[options];
-				if (meth) {
-					var r = meth.apply(this, args);
-					if (res === undefined) {
-						res = r;
-					}
+			var calendar = $.data(this, 'fullCalendar');
+			if (calendar && $.isFunction(calendar[options])) {
+				var r = calendar[options].apply(calendar, args);
+				if (res === undefined) {
+					res = r;
+				}
+				if (options == 'destroy') {
+					$.removeData(this, 'fullCalendar');
 				}
 				}
 			}
 			}
 		});
 		});
@@ -131,8 +27,9 @@ $.fn.fullCalendar = function(options) {
 		}
 		}
 		return this;
 		return this;
 	}
 	}
-
-	// pluck the 'events' and 'eventSources' options
+	
+	
+	// would like to have this logic in EventManager, but needs to happen before options are extended
 	var eventSources = options.eventSources || [];
 	var eventSources = options.eventSources || [];
 	delete options.eventSources;
 	delete options.eventSources;
 	if (options.events) {
 	if (options.events) {
@@ -140,778 +37,30 @@ $.fn.fullCalendar = function(options) {
 		delete options.events;
 		delete options.events;
 	}
 	}
 	
 	
-	// first event source reserved for 'sticky' events
-	eventSources.unshift([]);
-	
-	// initialize options
+
 	options = $.extend(true, {},
 	options = $.extend(true, {},
 		defaults,
 		defaults,
 		(options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},
 		(options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},
 		options
 		options
 	);
 	);
-	var tm = options.theme ? 'ui' : 'fc'; // for making theme classes
-	
-	
-	this.each(function() {
-	
 	
 	
-		/* Instance Initialization
-		-----------------------------------------------------------------------------*/
-		
-		// element
-		var _element = this,
-			element = $(_element).addClass('fc'),
-			elementOuterWidth,
-			content = $("<div class='fc-content " + tm + "-widget-content' style='position:relative'/>").prependTo(_element),
-			suggestedViewHeight,
-			resizeUID = 0,
-			ignoreWindowResize = 0,
-			date = new Date(),
-			viewName,  // the current view name (TODO: look into getting rid of)
-			view,      // the current view
-			viewInstances = {},
-			absoluteViewElement;
-			
-			
-			
-		if (options.isRTL) {
-			element.addClass('fc-rtl');
-		}
-		if (options.theme) {
-			element.addClass('ui-widget');
-		}
-		
-		setYMD(date, options.year, options.month, options.date);
-		
-		
-		
-		/* View Rendering
-		-----------------------------------------------------------------------------*/
-		
-		function changeView(v) {
-			if (v != viewName) {
-				ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached
-
-				viewUnselect();
-				
-				var oldView = view,
-					newViewElement;
-					
-				if (oldView) {
-					if (oldView.eventsChanged) {
-						eventsDirty();
-						oldView.eventDirty = oldView.eventsChanged = false;
-					}
-					if (oldView.beforeHide) {
-						oldView.beforeHide(); // called before changing min-height. if called after, scroll state is reset (in Opera)
-					}
-					setMinHeight(content, content.height());
-					oldView.element.hide();
-				}else{
-					setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated
-				}
-				content.css('overflow', 'hidden');
-				
-				if (viewInstances[v]) {
-					(view = viewInstances[v]).element.show();
-				}else{
-					view = viewInstances[v] = fc.views[v](
-						newViewElement = absoluteViewElement =
-							$("<div class='fc-view fc-view-" + v + "' style='position:absolute'/>")
-								.appendTo(content),
-						options,
-						v // the view's name
-					);
-				}
-				
-				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');
-				}
-				
-				viewName = v;
-				render(); // after height has been set, will make absoluteViewElement's position=relative, then set to null
-				content.css('overflow', '');
-				if (oldView) {
-					setMinHeight(content, 1);
-				}
-				if (!newViewElement && view.afterShow) {
-					view.afterShow(); // called after setting min-height/overflow, so in final scroll state (for Opera)
-				}
-				
-				ignoreWindowResize--;
-			}
-		}
-		
-		
-		function render(inc) {
-			if (elementVisible()) {
-				ignoreWindowResize++; // because view.renderEvents might temporarily change the height before setSize is reached
-
-				viewUnselect();
-				
-				if (suggestedViewHeight === undefined) {
-					calcSize();
-				}
-				
-				if (!view.start || inc || date < view.start || date >= view.end) {
-					view.render(date, inc || 0); // responsible for clearing events
-					setSize(true);
-					if (!eventStart || !options.lazyFetching || view.visStart < eventStart || view.visEnd > eventEnd) {
-						fetchAndRenderEvents();
-					}else{
-						view.renderEvents(events); // don't refetch
-					}
-				}
-				else if (view.sizeDirty || view.eventsDirty || !options.lazyFetching) {
-					view.clearEvents();
-					if (view.sizeDirty) {
-						setSize();
-					}
-					if (options.lazyFetching) {
-						view.renderEvents(events); // don't refetch
-					}else{
-						fetchAndRenderEvents();
-					}
-				}
-				elementOuterWidth = element.outerWidth();
-				view.sizeDirty = false;
-				view.eventsDirty = false;
-				
-				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');
-					}
-				}
-				
-				ignoreWindowResize--;
-				view.trigger('viewDisplay', _element);
-			}
-		}
-		
-		
-		function elementVisible() {
-			return _element.offsetWidth !== 0;
-		}
-		
-		function bodyVisible() {
-			return $('body')[0].offsetWidth !== 0;
-		}
-
-		function viewUnselect() {
-			if (view) {
-				view.unselect();
-			}
-		}
-		
-		
-		// called when any event objects have been added/removed/changed, rerenders
-		function eventsChanged() {
-			eventsDirty();
-			if (elementVisible()) {
-				view.clearEvents();
-				view.renderEvents(events);
-				view.eventsDirty = false;
-			}
-		}
-		
-		// marks other views' events as dirty
-		function eventsDirty() {
-			$.each(viewInstances, function() {
-				this.eventsDirty = true;
-			});
-		}
-		
-		// called when we know the element size has changed
-		function sizeChanged() {
-			sizesDirty();
-			if (elementVisible()) {
-				calcSize();
-				setSize();
-				viewUnselect();
-				view.rerenderEvents();
-				view.sizeDirty = false;
-			}
-		}
-		
-		// marks other views' sizes as dirty
-		function sizesDirty() {
-			$.each(viewInstances, function() {
-				this.sizeDirty = true;
-			});
-		}
-		
-		
-		
-		
-		/* 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) {
-						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
-						$.inArray(src, eventSources) != -1) {              // makes sure source hasn't been removed
-							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);
-				if (options.cacheParam) {
-					params[options.cacheParam] = (new Date()).getTime(); // TODO: deprecate cacheParam
-				}
-				pushLoading();
-				$.ajax({
-					url: src,
-					dataType: 'json',
-					data: params,
-					cache: options.cacheParam || false, // don't let jquery prevent caching if cacheParam is being used
-					success: reportEventsAndPop
-				});
-			}
-			else if ($.isFunction(src)) {
-				pushLoading();
-				src(cloneDate(eventStart), cloneDate(eventEnd), reportEventsAndPop);
-			}
-			else {
-				reportEvents(src); // src is an array
-			}
-		}
-		
-		
-		// for convenience
-		function fetchAndRenderEvents() {
-			fetchEvents(function(events) {
-				view.renderEvents(events); // maintain `this` in view
-			});
-		}
-		
-		
-		
-		/* 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: function() {
-				calcSize();
-				sizesDirty();
-				eventsDirty();
-				render();
-			},
-			
-			changeView: changeView,
-			
-			getView: function() {
-				return view;
-			},
-			
-			getDate: function() {
-				return date;
-			},
-			
-			option: function(name, value) {
-				if (value === undefined) {
-					return options[name];
-				}
-				if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
-					options[name] = value;
-					sizeChanged();
-				}
-			},
-			
-			destroy: function() {
-				$(window).unbind('resize', windowResize);
-				if (header) {
-					header.remove();
-				}
-				content.remove();
-				$.removeData(_element, 'fullCalendar');
-			},
-			
-			//
-			// Navigation
-			//
-			
-			prev: function() {
-				render(-1);
-			},
-			
-			next: function() {
-				render(1);
-			},
-			
-			prevYear: function() {
-				addYears(date, -1);
-				render();
-			},
-			
-			nextYear: function() {
-				addYears(date, 1);
-				render();
-			},
-			
-			today: function() {
-				date = new Date();
-				render();
-			},
-			
-			gotoDate: function(year, month, dateNum) {
-				if (typeof year == 'object') {
-					date = cloneDate(year); // provided 1 argument, a Date
-				}else{
-					setYMD(date, year, month, 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: eventsChanged, // TODO: think of renaming eventsChanged
-			
-			//
-			// Event Source
-			//
-		
-			addEventSource: function(source) {
-				eventSources.push(source);
-				fetchEventSource(source, 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);
-			},
-			
-			//
-			// selection
-			//
-			
-			select: function(start, end, allDay) {
-				view.select(start, end, allDay===undefined ? true : allDay);
-			},
-			
-			unselect: function() {
-				view.unselect();
-			}
-			
-		};
-		
-		$.data(this, 'fullCalendar', publicMethods); // TODO: look into memory leak implications
-		
-		
-		
-		/* 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, buttonName) {
-						if (buttonName == 'title') {
-							tr.append("<td><h2 class='fc-header-title'>&nbsp;</h2></td>");
-							if (prevButton) {
-								prevButton.addClass(tm + '-corner-right');
-							}
-							prevButton = null;
-						}else{
-							var buttonClick;
-							if (publicMethods[buttonName]) {
-								buttonClick = publicMethods[buttonName];
-							}
-							else if (views[buttonName]) {
-								buttonClick = function() {
-									button.removeClass(tm + '-state-hover');
-									changeView(buttonName);
-								};
-							}
-							if (buttonClick) {
-								if (prevButton) {
-									prevButton.addClass(tm + '-no-right');
-								}
-								var button,
-									icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null,
-									text = smartProperty(options.buttonText, buttonName);
-								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
-										.click(function() {
-											if (!button.hasClass(tm + '-state-disabled')) {
-												buttonClick();
-											}
-										})
-										.mousedown(function() {
-											button
-												.not('.' + tm + '-state-active')
-												.not('.' + tm + '-state-disabled')
-												.addClass(tm + '-state-down');
-										})
-										.mouseup(function() {
-											button.removeClass(tm + '-state-down');
-										})
-										.hover(
-											function() {
-												button
-													.not('.' + tm + '-state-active')
-													.not('.' + tm + '-state-disabled')
-													.addClass(tm + '-state-hover');
-											},
-											function() {
-												button
-													.removeClass(tm + '-state-hover')
-													.removeClass(tm + '-state-down');
-											}
-										)
-										.appendTo($("<td/>").appendTo(tr));
-									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
-		-----------------------------------------------------------------------------*/
-		
-		
-		function calcSize() {
-			if (options.contentHeight) {
-				suggestedViewHeight = options.contentHeight;
-			}
-			else if (options.height) {
-				suggestedViewHeight = options.height - (header ? header.height() : 0) - vsides(content[0]);
-			}
-			else {
-				suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));
-			}
-		}
-		
-		
-		function setSize(dateChanged) {
-			ignoreWindowResize++;
-			view.setHeight(suggestedViewHeight, dateChanged);
-			if (absoluteViewElement) {
-				absoluteViewElement.css('position', 'relative');
-				absoluteViewElement = null;
-			}
-			view.setWidth(content.width(), dateChanged);
-			ignoreWindowResize--;
-		}
-		
-		
-		function windowResize() {
-			if (!ignoreWindowResize) {
-				if (view.start) { // view has already been rendered
-					var uid = ++resizeUID;
-					setTimeout(function() { // add a delay
-						if (uid == resizeUID && !ignoreWindowResize && elementVisible()) {
-							if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {
-								ignoreWindowResize++; // in case the windowResize callback changes the height
-								sizeChanged();
-								view.trigger('windowResize', _element);
-								ignoreWindowResize--;
-							}
-						}
-					}, 200);
-				}else{
-					// calendar must have been initialized in a 0x0 iframe that has just been resized
-					lateRender();
-				}
-			}
-		}
-		$(window).resize(windowResize);
-		
-		
-		
-		/* External event dropping
-		--------------------------------------------------------*/
-		
-		if (options.droppable) {
-			var _dragElement;
-			$(document)
-				.bind('dragstart', function(ev, ui) {
-					var _e = ev.target;
-					var e = $(_e);
-					if (!e.parents('.fc').length) { // not already inside a calendar
-						var accept = options.dropAccept;
-						if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {
-							_dragElement = _e;
-							view.dragStart(_dragElement, ev, ui);
-						}
-					}
-				})
-				.bind('dragstop', function(ev, ui) {
-					if (_dragElement) {
-						view.dragStop(_dragElement, ev, ui);
-						_dragElement = null;
-					}
-				});
-		}
-		
-		
-		
-		// let's begin...
-		changeView(options.defaultView);
-		
-		
-		// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize
-		if (!bodyVisible()) {
-			lateRender();
-		}
-		
-		
-		// called when we know the calendar couldn't be rendered when it was initialized,
-		// but we think it's ready now
-		function lateRender() {
-			setTimeout(function() { // IE7 needs this so dimensions are calculated correctly
-				if (!view.start && bodyVisible()) { // !view.start makes sure this never happens more than once
-					render();
-				}
-			},0);
-		}
-
 	
 	
+	this.each(function(i, _element) {
+		var element = $(_element);
+		var calendar = new Calendar(element, options, eventSources);
+		element.data('fullCalendar', calendar); // TODO: look into memory leak implications
+		calendar.render();
 	});
 	});
 	
 	
+	
 	return this;
 	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, options.ignoreTimezone));
-	event.end = parseDate(event.end, options.ignoreTimezone);
-	if (event.end && event.end <= event.start) {
-		event.end = null;
-	}
-	event._end = event.end ? cloneDate(event.end) : null;
-	if (event.allDay === undefined) {
-		event.allDay = options.allDayDefault;
-	}
-	if (event.className) {
-		if (typeof event.className == 'string') {
-			event.className = event.className.split(/\s+/);
-		}
-	}else{
-		event.className = [];
-	}
+// function for adding/overriding defaults
+function setDefaults(d) {
+	$.extend(true, defaults, d);
 }
 }
-// TODO: if there is no start date, return false to indicate an invalid event
+
 
 

+ 0 - 20
src/misc/head.txt

@@ -1,20 +0,0 @@
-/**
- * @preserve
- * FullCalendar v@VERSION
- * 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: @DATE
- *
- */
- 
-(function($, undefined) {
-

+ 0 - 0
src/misc/foot.txt → src/outro.js


+ 0 - 45
src/selection_util.js

@@ -1,45 +0,0 @@
-
-
-function selection_dayMousedown(view, hoverListener, cellDate, cellIsAllDay, renderSelection, clearSelection, reportSelection, unselect) {
-	return function(ev) {
-		if (view.option('selectable')) {
-			unselect(ev);
-			var _mousedownElement = this;
-			var dates;
-			hoverListener.start(function(cell, origCell) {
-				clearSelection();
-				if (cell && cellIsAllDay(cell)) {
-					dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);
-					renderSelection(dates[0], addDays(cloneDate(dates[1]), 1), true);
-				}else{
-					dates = null;
-				}
-			}, ev);
-			$(document).one('mouseup', function(ev) {
-				hoverListener.stop();
-				if (dates) {
-					if (+dates[0] == +dates[1]) {
-						view.trigger('dayClick', _mousedownElement, dates[0], true, ev);
-						// BUG: _mousedownElement will sometimes be the overlay
-					}
-					reportSelection(dates[0], dates[1], true, ev);
-				}
-			});
-		}
-	}
-}
-
-
-function selection_unselectAuto(view, unselect) {
-	if (view.option('selectable') && view.option('unselectAuto')) {
-		$(document).mousedown(function(ev) {
-			var ignore = view.option('unselectCancel');
-			if (ignore) {
-				if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match
-					return;
-				}
-			}
-			unselect(ev);
-		});
-	}
-}

+ 0 - 375
src/view.js

@@ -1,375 +0,0 @@
-
-/* Methods & Utilities for All Views
------------------------------------------------------------------------------*/
-
-var viewMethods = {
-
-	/*
-	 * Objects inheriting these methods must implement the following properties/methods:
-	 * - title
-	 * - start
-	 * - end
-	 * - visStart
-	 * - visEnd
-	 * - defaultEventEnd(event)
-	 * - render(events)
-	 * - rerenderEvents()
-	 *
-	 *
-	 * z-index reservations:
-	 * 3 - day-overlay
-	 * 8 - events
-	 * 9 - dragging/resizing events
-	 *
-	 */
-	
-	
-
-	init: function(element, options) {
-		this.element = element;
-		this.options = options;
-		this.eventsByID = {};
-		this.eventElements = [];
-		this.eventElementsByID = {};
-		this.usedOverlays = [];
-		this.unusedOverlays = [];
-	},
-	
-	
-	
-	// 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 ? cloneDate(event.end) : this.defaultEventEnd(event); // TODO: make sure always using copies
-	},
-	
-	
-	
-	// 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 = {};
-		for (i=0; i<len; i++) {
-			event = events[i];
-			if (eventsByID[event._id]) {
-				eventsByID[event._id].push(event);
-			}else{
-				eventsByID[event._id] = [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 resets hashes
-		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][0] != exceptElement[0]) { // AHAHAHAHAHAHAHAH
-				elements[i][funcName]();
-			}
-		}
-	},
-	
-	
-	
-	// event modification reporting
-	
-	eventDrop: function(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
-		var view = this,
-			oldAllDay = event.allDay,
-			eventId = event._id;
-		view.moveEvents(view.eventsByID[eventId], dayDelta, minuteDelta, allDay);
-		view.trigger('eventDrop', e, event, dayDelta, minuteDelta, allDay, function() { // TODO: change docs
-			// TODO: investigate cases where this inverse technique might not work
-			view.moveEvents(view.eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);
-			view.rerenderEvents();
-		}, ev, ui);
-		view.eventsChanged = true;
-		view.rerenderEvents(eventId);
-	},
-	
-	eventResize: function(e, event, dayDelta, minuteDelta, ev, ui) {
-		var view = this,
-			eventId = event._id;
-		view.elongateEvents(view.eventsByID[eventId], dayDelta, minuteDelta);
-		view.trigger('eventResize', e, event, dayDelta, minuteDelta, function() {
-			// TODO: investigate cases where this inverse technique might not work
-			view.elongateEvents(view.eventsByID[eventId], -dayDelta, -minuteDelta);
-			view.rerenderEvents();
-		}, ev, ui);
-		view.eventsChanged = true;
-		view.rerenderEvents(eventId);
-	},
-	
-	
-	
-	// event modification
-	
-	moveEvents: function(events, dayDelta, minuteDelta, allDay) {
-		minuteDelta = minuteDelta || 0;
-		for (var e, len=events.length, i=0; i<len; i++) {
-			e = events[i];
-			if (allDay !== undefined) {
-				e.allDay = allDay;
-			}
-			addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
-			if (e.end) {
-				e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
-			}
-			normalizeEvent(e, this.options);
-		}
-	},
-	
-	elongateEvents: function(events, dayDelta, minuteDelta) {
-		minuteDelta = minuteDelta || 0;
-		for (var e, len=events.length, i=0; i<len; i++) {
-			e = events[i];
-			e.end = addMinutes(addDays(this.eventEnd(e), dayDelta, true), minuteDelta);
-			normalizeEvent(e, this.options);
-		}
-	},
-	
-	
-	
-	// semi-transparent overlay (while dragging or selecting)
-	
-	renderOverlay: function(rect, parent) {
-		var e = this.unusedOverlays.shift();
-		if (!e) {
-			e = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>");
-		}
-		if (e[0].parentNode != parent[0]) {
-			e.appendTo(parent);
-		}
-		this.usedOverlays.push(e.css(rect).show());
-		return e;
-	},
-
-	clearOverlays: function() {
-		var e;
-		while (e = this.usedOverlays.shift()) {
-			this.unusedOverlays.push(e.hide().unbind());
-		}
-	},
-	
-	
-	
-	
-	// common horizontal event resizing
-
-	resizableDayEvent: function(event, eventElement, colWidth) {
-		var view = this;
-		if (!view.options.disableResizing && eventElement.resizable) {
-			eventElement.resizable({
-				handles: view.options.isRTL ? {w:'div.ui-resizable-w'} : {e:'div.ui-resizable-e'},
-				grid: colWidth,
-				minWidth: colWidth/2, // need this or else IE throws errors when too small
-				containment: view.element.parent().parent(), // the main element...
-				             // ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?)
-				start: function(ev, ui) {
-					eventElement.css('z-index', 9);
-					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.eventResize(this, event, dayDelta, 0, ev, ui);
-					}else{
-						eventElement.css('z-index', 8);
-						view.showEvents(event, eventElement);
-					}
-				}
-			});
-		}
-	},
-	
-	
-	
-	// attaches eventClick, eventMouseover, eventMouseout
-	
-	eventElementHandlers: function(event, eventElement) {
-		var view = this;
-		eventElement
-			.click(function(ev) {
-				if (!eventElement.hasClass('ui-draggable-dragging') &&
-					!eventElement.hasClass('ui-resizable-resizing')) {
-						return view.trigger('eventClick', this, event, ev);
-					}
-			})
-			.hover(
-				function(ev) {
-					view.trigger('eventMouseover', this, event, ev);
-				},
-				function(ev) {
-					view.trigger('eventMouseout', this, event, ev);
-				}
-			);
-	},
-	
-	
-	
-	// get a property from the 'options' object, using smart view naming
-	
-	option: function(name, viewName) {
-		var v = this.options[name];
-		if (typeof v == 'object') {
-			return smartProperty(v, viewName || this.name);
-		}
-		return v;
-	},
-	
-	
-	
-	// event rendering utilities
-	
-	sliceSegs: function(events, visEventEnds, 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 = visEventEnds[i];
-			if (eventEnd > start && eventStart < end) {
-				if (eventStart < start) {
-					segStart = cloneDate(start);
-					isStart = false;
-				}else{
-					segStart = eventStart;
-					isStart = true;
-				}
-				if (eventEnd > end) {
-					segEnd = cloneDate(end);
-					isEnd = false;
-				}else{
-					segEnd = eventEnd;
-					isEnd = true;
-				}
-				segs.push({
-					event: event,
-					start: segStart,
-					end: segEnd,
-					isStart: isStart,
-					isEnd: isEnd,
-					msLength: segEnd - segStart
-				});
-			}
-		} 
-		return segs.sort(segCmp);
-	}
-	
-
-};
-
-
-
-function lazySegBind(container, segs, bindHandlers) {
-	container.unbind('mouseover').mouseover(function(ev) {
-		var parent=ev.target, e,
-			i, seg;
-		while (parent != this) {
-			e = parent;
-			parent = parent.parentNode;
-		}
-		if ((i = e._fci) !== undefined) {
-			e._fci = undefined;
-			seg = segs[i];
-			bindHandlers(seg.event, seg.element, seg);
-			$(ev.target).trigger(ev);
-		}
-		ev.stopPropagation();
-	});
-}
-
-
-
-// event rendering calculation 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];
-		}
-	}
-	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;
-}
-
-
-

+ 2 - 3
tests/dbclick.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 2 - 3
tests/droppable.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 2 - 3
tests/fullheight.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 3 - 2
tests/gcal.html

@@ -1,12 +1,13 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
+<script type='text/javascript' src='../src/gcal/_loader.js'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {
 		$('#calendar').fullCalendar({
 		$('#calendar').fullCalendar({
-			//weekends: false,
+			weekends: false,
 			header: {
 			header: {
 				left: 'prev,next today',
 				left: 'prev,next today',
 				center: 'title',
 				center: 'title',

+ 20 - 22
tests/iframe.html

@@ -1,30 +1,28 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<html>
 <head>
 <head>
-	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-	<meta http-equiv="imagetoolbar" content="no" />
-	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
-	<link rel="stylesheet" type="text/css" href="fancybox/jquery.fancybox-1.2.6.css" media="screen" />
-	<script type="text/javascript" src="fancybox/jquery.fancybox-1.2.6.pack.js"></script>
-	<script type="text/javascript">
-	
-		$(document).ready(function() {
-			$('#fullcalendar-link').fancybox({
-				frameWidth: 1100,
-				frameHeight: 800
-			});
-		});
-		
-	</script>
+<link rel='stylesheet' type='text/css' href='lib/fancybox/jquery.fancybox-1.2.6.css' />
+<script type='text/javascript' src='../lib/jquery-1.4.2.min.js'></script>
+<script type='text/javascript' src='lib/fancybox/jquery.fancybox-1.2.6.pack.js'></script>
+<script type='text/javascript'>
+
+	$(document).ready(function() {
+		$('#fullcalendar-link').fancybox({
+			frameWidth: 1100,
+			frameHeight: 800
+		});
+	});
+
+</script>
 </head>
 </head>
 <body>
 <body>
-<div id="content">
+<div id='content'>
+
+<h1>FancyBox <em>v1.2.6</em></h1>
 
 
-	<h1>FancyBox <em>v1.2.6</em></h1>
-	
-	<p>
-	<a id='fullcalendar-link' class="iframe" href="plain.html">Open a FullCalendar</a>
-	</p>
+<p>
+<a id='fullcalendar-link' class='iframe' href='plain.html'>Open a FullCalendar</a>
+</p>
 
 
 </div>
 </div>
 </body>
 </body>

+ 2 - 3
tests/issue_206_parseDate_dst.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	// set your time to Tehran time (GMT+03:30)
 	// set your time to Tehran time (GMT+03:30)

+ 2 - 3
tests/issue_220_buttons_ie6.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<script type='text/javascript'>DISABLE_FIREBUG_LITE=true</script>
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 2 - 1
tests/issue_221_quick_remove_source.html

@@ -1,7 +1,8 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
+<script type='text/javascript' src='../src/gcal/_loader.js'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 	
 	
 	var gcalFeed = $.fullCalendar.gcalFeed("http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic");
 	var gcalFeed = $.fullCalendar.gcalFeed("http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic");

+ 6 - 7
tests/issue_230_height_json_events.html

@@ -1,19 +1,18 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {
 	
 	
 		$('#calendar').fullCalendar({
 		$('#calendar').fullCalendar({
-			year: 2009,
-			month: 10,
-			date: 22, 
+			//year: 2009,
+			//month: 10,
+			//date: 22, 
 			//defaultView: 'agendaWeek', // error also occured with month view
 			//defaultView: 'agendaWeek', // error also occured with month view
 			editable: true,
 			editable: true,
-			events: "../examples/json-events.php"		
+			events: "../demos/json-events.php"
 		});
 		});
 		
 		
 		$('#calendar').fullCalendar('option', 'height', $(window).height()-80);
 		$('#calendar').fullCalendar('option', 'height', $(window).height()-80);

+ 2 - 3
tests/issue_244_aspectRatio_0.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 2 - 3
tests/issue_251_empty_end_date.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 2 - 2
tests/issue_333_blinking.html

@@ -1,7 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 <head>
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type="text/javascript">
 <script type="text/javascript">
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {
@@ -93,4 +93,4 @@
 <body>
 <body>
 <div id="calendar"> </div>
 <div id="calendar"> </div>
 </body>
 </body>
-</html>
+</html>

+ 59 - 0
tests/issue_417_refetchEvents.html

@@ -0,0 +1,59 @@
+<!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='../demos/redmond/theme.css' />
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
+<script type='text/javascript' src='../src/gcal/_loader.js'></script>
+<script type='text/javascript'>
+
+	/*
+	- click on day button
+	- click refetchEvents
+	- click on month button
+	   event shouldn't disappear!!!
+	*/
+
+	$(document).ready(function() {
+	
+		var date = new Date();
+		var d = date.getDate();
+		var m = date.getMonth();
+		var y = date.getFullYear();
+		
+		$('#calendar').fullCalendar({
+			year: 2010,
+			month: 9,
+			date: 31,
+			header: {
+				left: 'prev,next today',
+				center: 'title',
+				right: 'month,agendaDay'
+			},
+			editable: true,
+			events: $.fullCalendar.gcalFeed('http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic')
+		});
+		
+	});
+
+</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>
+<button onclick="$('#calendar').fullCalendar('refetchEvents')">refetchEvents</button>
+<div id='calendar'></div>
+</body>
+</html>

+ 2 - 3
tests/issue_429_gotoDate.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 2 - 3
tests/issue_477_event_width.html

@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <html>
 <head>
 <head>
-<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
-<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript' src='../src/_loader.js?debug'></script>
 <script type='text/javascript'>
 <script type='text/javascript'>
 
 
 	$(document).ready(function() {
 	$(document).ready(function() {

+ 0 - 721
tests/jquery-ui/jquery.ui.tabs.js

@@ -1,721 +0,0 @@
-/*
- * jQuery UI Tabs 1.8.1
- *
- * Copyright (c) 2010 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/Tabs
- *
- * Depends:
- *	jquery.ui.core.js
- *	jquery.ui.widget.js
- */
-(function($) {
-
-var tabId = 0,
-	listId = 0;
-
-$.widget("ui.tabs", {
-	options: {
-		add: null,
-		ajaxOptions: null,
-		cache: false,
-		cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
-		collapsible: false,
-		disable: null,
-		disabled: [],
-		enable: null,
-		event: 'click',
-		fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
-		idPrefix: 'ui-tabs-',
-		load: null,
-		panelTemplate: '<div></div>',
-		remove: null,
-		select: null,
-		show: null,
-		spinner: '<em>Loading&#8230;</em>',
-		tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
-	},
-	_create: function() {
-		this._tabify(true);
-	},
-
-	_setOption: function(key, value) {
-		if (key == 'selected') {
-			if (this.options.collapsible && value == this.options.selected) {
-				return;
-			}
-			this.select(value);
-		}
-		else {
-			this.options[key] = value;
-			this._tabify();
-		}
-	},
-
-	_tabId: function(a) {
-		return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
-			this.options.idPrefix + (++tabId);
-	},
-
-	_sanitizeSelector: function(hash) {
-		return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
-	},
-
-	_cookie: function() {
-		var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + (++listId));
-		return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
-	},
-
-	_ui: function(tab, panel) {
-		return {
-			tab: tab,
-			panel: panel,
-			index: this.anchors.index(tab)
-		};
-	},
-
-	_cleanup: function() {
-		// restore all former loading tabs labels
-		this.lis.filter('.ui-state-processing').removeClass('ui-state-processing')
-				.find('span:data(label.tabs)')
-				.each(function() {
-					var el = $(this);
-					el.html(el.data('label.tabs')).removeData('label.tabs');
-				});
-	},
-
-	_tabify: function(init) {
-
-		this.list = this.element.find('ol,ul').eq(0);
-		this.lis = $('li:has(a[href])', this.list);
-		this.anchors = this.lis.map(function() { return $('a', this)[0]; });
-		this.panels = $([]);
-
-		var self = this, o = this.options;
-
-		var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
-		this.anchors.each(function(i, a) {
-			var href = $(a).attr('href');
-
-			// For dynamically created HTML that contains a hash as href IE < 8 expands
-			// such href to the full page url with hash and then misinterprets tab as ajax.
-			// Same consideration applies for an added tab with a fragment identifier
-			// since a[href=#fragment-identifier] does unexpectedly not match.
-			// Thus normalize href attribute...
-			var hrefBase = href.split('#')[0], baseEl;
-			if (hrefBase && (hrefBase === location.toString().split('#')[0] ||
-					(baseEl = $('base')[0]) && hrefBase === baseEl.href)) {
-				href = a.hash;
-				a.href = href;
-			}
-
-			// inline tab
-			if (fragmentId.test(href)) {
-				self.panels = self.panels.add(self._sanitizeSelector(href));
-			}
-
-			// remote tab
-			else if (href != '#') { // prevent loading the page itself if href is just "#"
-				$.data(a, 'href.tabs', href); // required for restore on destroy
-
-				// TODO until #3808 is fixed strip fragment identifier from url
-				// (IE fails to load from such url)
-				$.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data
-
-				var id = self._tabId(a);
-				a.href = '#' + id;
-				var $panel = $('#' + id);
-				if (!$panel.length) {
-					$panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
-						.insertAfter(self.panels[i - 1] || self.list);
-					$panel.data('destroy.tabs', true);
-				}
-				self.panels = self.panels.add($panel);
-			}
-
-			// invalid tab href
-			else {
-				o.disabled.push(i);
-			}
-		});
-
-		// initialization from scratch
-		if (init) {
-
-			// attach necessary classes for styling
-			this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all');
-			this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
-			this.lis.addClass('ui-state-default ui-corner-top');
-			this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom');
-
-			// Selected tab
-			// use "selected" option or try to retrieve:
-			// 1. from fragment identifier in url
-			// 2. from cookie
-			// 3. from selected class attribute on <li>
-			if (o.selected === undefined) {
-				if (location.hash) {
-					this.anchors.each(function(i, a) {
-						if (a.hash == location.hash) {
-							o.selected = i;
-							return false; // break
-						}
-					});
-				}
-				if (typeof o.selected != 'number' && o.cookie) {
-					o.selected = parseInt(self._cookie(), 10);
-				}
-				if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) {
-					o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
-				}
-				o.selected = o.selected || (this.lis.length ? 0 : -1);
-			}
-			else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release
-				o.selected = -1;
-			}
-
-			// sanity check - default to first tab...
-			o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0;
-
-			// Take disabling tabs via class attribute from HTML
-			// into account and update option properly.
-			// A selected tab cannot become disabled.
-			o.disabled = $.unique(o.disabled.concat(
-				$.map(this.lis.filter('.ui-state-disabled'),
-					function(n, i) { return self.lis.index(n); } )
-			)).sort();
-
-			if ($.inArray(o.selected, o.disabled) != -1) {
-				o.disabled.splice($.inArray(o.selected, o.disabled), 1);
-			}
-
-			// highlight selected tab
-			this.panels.addClass('ui-tabs-hide');
-			this.lis.removeClass('ui-tabs-selected ui-state-active');
-			if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
-				this.panels.eq(o.selected).removeClass('ui-tabs-hide');
-				this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active');
-
-				// seems to be expected behavior that the show callback is fired
-				self.element.queue("tabs", function() {
-					self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected]));
-				});
-				
-				this.load(o.selected);
-			}
-
-			// clean up to avoid memory leaks in certain versions of IE 6
-			$(window).bind('unload', function() {
-				self.lis.add(self.anchors).unbind('.tabs');
-				self.lis = self.anchors = self.panels = null;
-			});
-
-		}
-		// update selected after add/remove
-		else {
-			o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
-		}
-
-		// update collapsible
-		this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible');
-
-		// set or update cookie after init and add/remove respectively
-		if (o.cookie) {
-			this._cookie(o.selected, o.cookie);
-		}
-
-		// disable tabs
-		for (var i = 0, li; (li = this.lis[i]); i++) {
-			$(li)[$.inArray(i, o.disabled) != -1 &&
-				!$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled');
-		}
-
-		// reset cache if switching from cached to not cached
-		if (o.cache === false) {
-			this.anchors.removeData('cache.tabs');
-		}
-
-		// remove all handlers before, tabify may run on existing tabs after add or option change
-		this.lis.add(this.anchors).unbind('.tabs');
-
-		if (o.event != 'mouseover') {
-			var addState = function(state, el) {
-				if (el.is(':not(.ui-state-disabled)')) {
-					el.addClass('ui-state-' + state);
-				}
-			};
-			var removeState = function(state, el) {
-				el.removeClass('ui-state-' + state);
-			};
-			this.lis.bind('mouseover.tabs', function() {
-				addState('hover', $(this));
-			});
-			this.lis.bind('mouseout.tabs', function() {
-				removeState('hover', $(this));
-			});
-			this.anchors.bind('focus.tabs', function() {
-				addState('focus', $(this).closest('li'));
-			});
-			this.anchors.bind('blur.tabs', function() {
-				removeState('focus', $(this).closest('li'));
-			});
-		}
-
-		// set up animations
-		var hideFx, showFx;
-		if (o.fx) {
-			if ($.isArray(o.fx)) {
-				hideFx = o.fx[0];
-				showFx = o.fx[1];
-			}
-			else {
-				hideFx = showFx = o.fx;
-			}
-		}
-
-		// Reset certain styles left over from animation
-		// and prevent IE's ClearType bug...
-		function resetStyle($el, fx) {
-			$el.css({ display: '' });
-			if (!$.support.opacity && fx.opacity) {
-				$el[0].style.removeAttribute('filter');
-			}
-		}
-
-		// Show a tab...
-		var showTab = showFx ?
-			function(clicked, $show) {
-				$(clicked).closest('li').addClass('ui-tabs-selected ui-state-active');
-				$show.hide().removeClass('ui-tabs-hide') // avoid flicker that way
-					.animate(showFx, showFx.duration || 'normal', function() {
-						resetStyle($show, showFx);
-						self._trigger('show', null, self._ui(clicked, $show[0]));
-					});
-			} :
-			function(clicked, $show) {
-				$(clicked).closest('li').addClass('ui-tabs-selected ui-state-active');
-				$show.removeClass('ui-tabs-hide');
-				self._trigger('show', null, self._ui(clicked, $show[0]));
-			};
-
-		// Hide a tab, $show is optional...
-		var hideTab = hideFx ?
-			function(clicked, $hide) {
-				$hide.animate(hideFx, hideFx.duration || 'normal', function() {
-					self.lis.removeClass('ui-tabs-selected ui-state-active');
-					$hide.addClass('ui-tabs-hide');
-					resetStyle($hide, hideFx);
-					self.element.dequeue("tabs");
-				});
-			} :
-			function(clicked, $hide, $show) {
-				self.lis.removeClass('ui-tabs-selected ui-state-active');
-				$hide.addClass('ui-tabs-hide');
-				self.element.dequeue("tabs");
-			};
-
-		// attach tab event handler, unbind to avoid duplicates from former tabifying...
-		this.anchors.bind(o.event + '.tabs', function() {
-			var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
-					$show = $(self._sanitizeSelector(this.hash));
-
-			// If tab is already selected and not collapsible or tab disabled or
-			// or is already loading or click callback returns false stop here.
-			// Check if click handler returns false last so that it is not executed
-			// for a disabled or loading tab!
-			if (($li.hasClass('ui-tabs-selected') && !o.collapsible) ||
-				$li.hasClass('ui-state-disabled') ||
-				$li.hasClass('ui-state-processing') ||
-				self._trigger('select', null, self._ui(this, $show[0])) === false) {
-				this.blur();
-				return false;
-			}
-
-			o.selected = self.anchors.index(this);
-
-			self.abort();
-
-			// if tab may be closed
-			if (o.collapsible) {
-				if ($li.hasClass('ui-tabs-selected')) {
-					o.selected = -1;
-
-					if (o.cookie) {
-						self._cookie(o.selected, o.cookie);
-					}
-
-					self.element.queue("tabs", function() {
-						hideTab(el, $hide);
-					}).dequeue("tabs");
-					
-					this.blur();
-					return false;
-				}
-				else if (!$hide.length) {
-					if (o.cookie) {
-						self._cookie(o.selected, o.cookie);
-					}
-					
-					self.element.queue("tabs", function() {
-						showTab(el, $show);
-					});
-
-					self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
-					
-					this.blur();
-					return false;
-				}
-			}
-
-			if (o.cookie) {
-				self._cookie(o.selected, o.cookie);
-			}
-
-			// show new tab
-			if ($show.length) {
-				if ($hide.length) {
-					self.element.queue("tabs", function() {
-						hideTab(el, $hide);
-					});
-				}
-				self.element.queue("tabs", function() {
-					showTab(el, $show);
-				});
-				
-				self.load(self.anchors.index(this));
-			}
-			else {
-				throw 'jQuery UI Tabs: Mismatching fragment identifier.';
-			}
-
-			// Prevent IE from keeping other link focussed when using the back button
-			// and remove dotted border from clicked link. This is controlled via CSS
-			// in modern browsers; blur() removes focus from address bar in Firefox
-			// which can become a usability and annoying problem with tabs('rotate').
-			if ($.browser.msie) {
-				this.blur();
-			}
-
-		});
-
-		// disable click in any case
-		this.anchors.bind('click.tabs', function(){return false;});
-
-	},
-
-	destroy: function() {
-		var o = this.options;
-
-		this.abort();
-		
-		this.element.unbind('.tabs')
-			.removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible')
-			.removeData('tabs');
-
-		this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
-
-		this.anchors.each(function() {
-			var href = $.data(this, 'href.tabs');
-			if (href) {
-				this.href = href;
-			}
-			var $this = $(this).unbind('.tabs');
-			$.each(['href', 'load', 'cache'], function(i, prefix) {
-				$this.removeData(prefix + '.tabs');
-			});
-		});
-
-		this.lis.unbind('.tabs').add(this.panels).each(function() {
-			if ($.data(this, 'destroy.tabs')) {
-				$(this).remove();
-			}
-			else {
-				$(this).removeClass([
-					'ui-state-default',
-					'ui-corner-top',
-					'ui-tabs-selected',
-					'ui-state-active',
-					'ui-state-hover',
-					'ui-state-focus',
-					'ui-state-disabled',
-					'ui-tabs-panel',
-					'ui-widget-content',
-					'ui-corner-bottom',
-					'ui-tabs-hide'
-				].join(' '));
-			}
-		});
-
-		if (o.cookie) {
-			this._cookie(null, o.cookie);
-		}
-
-		return this;
-	},
-
-	add: function(url, label, index) {
-		if (index === undefined) {
-			index = this.anchors.length; // append by default
-		}
-
-		var self = this, o = this.options,
-			$li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)),
-			id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]);
-
-		$li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true);
-
-		// try to find an existing element before creating a new one
-		var $panel = $('#' + id);
-		if (!$panel.length) {
-			$panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true);
-		}
-		$panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide');
-
-		if (index >= this.lis.length) {
-			$li.appendTo(this.list);
-			$panel.appendTo(this.list[0].parentNode);
-		}
-		else {
-			$li.insertBefore(this.lis[index]);
-			$panel.insertBefore(this.panels[index]);
-		}
-
-		o.disabled = $.map(o.disabled,
-			function(n, i) { return n >= index ? ++n : n; });
-
-		this._tabify();
-
-		if (this.anchors.length == 1) { // after tabify
-			o.selected = 0;
-			$li.addClass('ui-tabs-selected ui-state-active');
-			$panel.removeClass('ui-tabs-hide');
-			this.element.queue("tabs", function() {
-				self._trigger('show', null, self._ui(self.anchors[0], self.panels[0]));
-			});
-				
-			this.load(0);
-		}
-
-		// callback
-		this._trigger('add', null, this._ui(this.anchors[index], this.panels[index]));
-		return this;
-	},
-
-	remove: function(index) {
-		var o = this.options, $li = this.lis.eq(index).remove(),
-			$panel = this.panels.eq(index).remove();
-
-		// If selected tab was removed focus tab to the right or
-		// in case the last tab was removed the tab to the left.
-		if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) {
-			this.select(index + (index + 1 < this.anchors.length ? 1 : -1));
-		}
-
-		o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
-			function(n, i) { return n >= index ? --n : n; });
-
-		this._tabify();
-
-		// callback
-		this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0]));
-		return this;
-	},
-
-	enable: function(index) {
-		var o = this.options;
-		if ($.inArray(index, o.disabled) == -1) {
-			return;
-		}
-
-		this.lis.eq(index).removeClass('ui-state-disabled');
-		o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
-
-		// callback
-		this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index]));
-		return this;
-	},
-
-	disable: function(index) {
-		var self = this, o = this.options;
-		if (index != o.selected) { // cannot disable already selected tab
-			this.lis.eq(index).addClass('ui-state-disabled');
-
-			o.disabled.push(index);
-			o.disabled.sort();
-
-			// callback
-			this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index]));
-		}
-
-		return this;
-	},
-
-	select: function(index) {
-		if (typeof index == 'string') {
-			index = this.anchors.index(this.anchors.filter('[href$=' + index + ']'));
-		}
-		else if (index === null) { // usage of null is deprecated, TODO remove in next release
-			index = -1;
-		}
-		if (index == -1 && this.options.collapsible) {
-			index = this.options.selected;
-		}
-
-		this.anchors.eq(index).trigger(this.options.event + '.tabs');
-		return this;
-	},
-
-	load: function(index) {
-		var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs');
-
-		this.abort();
-
-		// not remote or from cache
-		if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) {
-			this.element.dequeue("tabs");
-			return;
-		}
-
-		// load remote from here on
-		this.lis.eq(index).addClass('ui-state-processing');
-
-		if (o.spinner) {
-			var span = $('span', a);
-			span.data('label.tabs', span.html()).html(o.spinner);
-		}
-
-		this.xhr = $.ajax($.extend({}, o.ajaxOptions, {
-			url: url,
-			success: function(r, s) {
-				$(self._sanitizeSelector(a.hash)).html(r);
-
-				// take care of tab labels
-				self._cleanup();
-
-				if (o.cache) {
-					$.data(a, 'cache.tabs', true); // if loaded once do not load them again
-				}
-
-				// callbacks
-				self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
-				try {
-					o.ajaxOptions.success(r, s);
-				}
-				catch (e) {}
-			},
-			error: function(xhr, s, e) {
-				// take care of tab labels
-				self._cleanup();
-
-				// callbacks
-				self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
-				try {
-					// Passing index avoid a race condition when this method is
-					// called after the user has selected another tab.
-					// Pass the anchor that initiated this request allows
-					// loadError to manipulate the tab content panel via $(a.hash)
-					o.ajaxOptions.error(xhr, s, index, a);
-				}
-				catch (e) {}
-			}
-		}));
-
-		// last, so that load event is fired before show...
-		self.element.dequeue("tabs");
-
-		return this;
-	},
-
-	abort: function() {
-		// stop possibly running animations
-		this.element.queue([]);
-		this.panels.stop(false, true);
-
-		// "tabs" queue must not contain more than two elements,
-		// which are the callbacks for the latest clicked tab...
-		this.element.queue("tabs", this.element.queue("tabs").splice(-2, 2));
-
-		// terminate pending requests from other tabs
-		if (this.xhr) {
-			this.xhr.abort();
-			delete this.xhr;
-		}
-
-		// take care of tab labels
-		this._cleanup();
-		return this;
-	},
-
-	url: function(index, url) {
-		this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url);
-		return this;
-	},
-
-	length: function() {
-		return this.anchors.length;
-	}
-
-});
-
-$.extend($.ui.tabs, {
-	version: '1.8.1'
-});
-
-/*
- * Tabs Extensions
- */
-
-/*
- * Rotate
- */
-$.extend($.ui.tabs.prototype, {
-	rotation: null,
-	rotate: function(ms, continuing) {
-
-		var self = this, o = this.options;
-		
-		var rotate = self._rotate || (self._rotate = function(e) {
-			clearTimeout(self.rotation);
-			self.rotation = setTimeout(function() {
-				var t = o.selected;
-				self.select( ++t < self.anchors.length ? t : 0 );
-			}, ms);
-			
-			if (e) {
-				e.stopPropagation();
-			}
-		});
-		
-		var stop = self._unrotate || (self._unrotate = !continuing ?
-			function(e) {
-				if (e.clientX) { // in case of a true click
-					self.rotate(null);
-				}
-			} :
-			function(e) {
-				t = o.selected;
-				rotate();
-			});
-
-		// start rotation
-		if (ms) {
-			this.element.bind('tabsshow', rotate);
-			this.anchors.bind(o.event + '.tabs', stop);
-			rotate();
-		}
-		// stop rotation
-		else {
-			clearTimeout(self.rotation);
-			this.element.unbind('tabsshow', rotate);
-			this.anchors.unbind(o.event + '.tabs', stop);
-			delete this._rotate;
-			delete this._unrotate;
-		}
-
-		return this;
-	}
-});
-
-})(jQuery);

+ 0 - 0
tests/fancybox/fancy_closebox.png → tests/lib/fancybox/fancy_closebox.png


+ 0 - 0
tests/fancybox/fancy_left.png → tests/lib/fancybox/fancy_left.png


+ 0 - 0
tests/fancybox/fancy_progress.png → tests/lib/fancybox/fancy_progress.png


+ 0 - 0
tests/fancybox/fancy_right.png → tests/lib/fancybox/fancy_right.png


+ 0 - 0
tests/fancybox/fancy_shadow_e.png → tests/lib/fancybox/fancy_shadow_e.png


+ 0 - 0
tests/fancybox/fancy_shadow_n.png → tests/lib/fancybox/fancy_shadow_n.png


+ 0 - 0
tests/fancybox/fancy_shadow_ne.png → tests/lib/fancybox/fancy_shadow_ne.png


+ 0 - 0
tests/fancybox/fancy_shadow_nw.png → tests/lib/fancybox/fancy_shadow_nw.png


+ 0 - 0
tests/fancybox/fancy_shadow_s.png → tests/lib/fancybox/fancy_shadow_s.png


+ 0 - 0
tests/fancybox/fancy_shadow_se.png → tests/lib/fancybox/fancy_shadow_se.png


+ 0 - 0
tests/fancybox/fancy_shadow_sw.png → tests/lib/fancybox/fancy_shadow_sw.png


+ 0 - 0
tests/fancybox/fancy_shadow_w.png → tests/lib/fancybox/fancy_shadow_w.png


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff