Author: nbelaevski
Date: 2010-04-28 21:40:35 -0400 (Wed, 28 Apr 2010)
New Revision: 16835
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/
branches/community/3.3.X/sandbox/samples/full-calendar/pom.xml
branches/community/3.3.X/sandbox/samples/full-calendar/src/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/ComponentBean.java
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/FullCalendarAjaxEvent.java
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/UIFullCalendar.java
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/resources/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/faces-config.xml
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/web.xml
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/fullcalendar.js
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/index.jsp
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/jquery.js
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/page.xhtml
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/richfaces.fullcalendar.js
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.core.js
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.draggable.js
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.resizable.js
Log:
Prototype for schedule component:
http://community.jboss.org/message/539813#539813
check-in
Added: branches/community/3.3.X/sandbox/samples/full-calendar/pom.xml
===================================================================
--- branches/community/3.3.X/sandbox/samples/full-calendar/pom.xml
(rev 0)
+++ branches/community/3.3.X/sandbox/samples/full-calendar/pom.xml 2010-04-29 01:40:35 UTC
(rev 16835)
@@ -0,0 +1,143 @@
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.richfaces.demo</groupId>
+ <artifactId>full-calendar</artifactId>
+ <packaging>war</packaging>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <rfVersion>3.3.3.Final</rfVersion>
+ </properties>
+
+
+ <repositories>
+ <repository>
+ <id>jboss.org</id>
+ <
url>http://repository.jboss.org/maven2</url>
+ </repository>
+ <repository>
+ <id>maven-repository2.dev.java.net</id>
+ <
url>http://download.java.net/maven/2</url>
+ </repository>
+ <repository>
+ <id>maven-repository1.dev.java.net</id>
+ <
url>http://download.java.net/maven/1</url>
+ <layout>legacy</layout>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>jboss.org</id>
+ <
url>http://repository.jboss.org/maven2</url>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>maven-jetty-plugin</artifactId>
+ <version>6.1.5</version>
+ <configuration>
+ <scanIntervalSeconds>10</scanIntervalSeconds>
+ <connectors>
+ <connector
implementation="org.mortbay.jetty.nio.SelectChannelConnector">
+ <port>8081</port>
+ <maxIdleTime>60000</maxIdleTime>
+ </connector>
+ </connectors>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <version>2.7</version>
+ <configuration>
+ <wtpversion>2.0</wtpversion>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>1.2_14</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>1.2_14</version>
+ </dependency>
+ <dependency>
+ <groupId>org.richfaces.ui</groupId>
+ <artifactId>richfaces-ui</artifactId>
+ <version>${rfVersion}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.richfaces.framework</groupId>
+ <artifactId>richfaces-impl</artifactId>
+ <version>${rfVersion}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.facelets</groupId>
+ <artifactId>jsf-facelets</artifactId>
+ <version>1.1.15.B1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jstl</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>el-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/ComponentBean.java
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/ComponentBean.java
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/ComponentBean.java 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,17 @@
+package demo.beans;
+
+import javax.faces.component.UIComponent;
+
+public class ComponentBean {
+
+ private UIComponent component = new UIFullCalendar();
+
+ public UIComponent getComponent() {
+ return component;
+ }
+
+ public void setComponent(UIComponent component) {
+ this.component = component;
+ }
+
+}
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/FullCalendarAjaxEvent.java
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/FullCalendarAjaxEvent.java
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/FullCalendarAjaxEvent.java 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,32 @@
+package demo.beans;
+
+
+import java.util.Date;
+
+import javax.faces.component.UIComponent;
+
+import org.ajax4jsf.event.AjaxEvent;
+
+public class FullCalendarAjaxEvent extends AjaxEvent {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3588719931853540807L;
+
+ private Date startDate;
+
+ private Date endDate;
+
+ public FullCalendarAjaxEvent(UIComponent component, Date startDate, Date endDate) {
+ super(component);
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public Date getEndDate() {
+ return endDate;
+ }
+}
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/UIFullCalendar.java
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/UIFullCalendar.java
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/java/demo/beans/UIFullCalendar.java 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,188 @@
+package demo.beans;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.FacesEvent;
+
+import org.ajax4jsf.context.AjaxContext;
+import org.ajax4jsf.javascript.JSFunction;
+import org.ajax4jsf.javascript.JSFunctionDefinition;
+import org.ajax4jsf.javascript.JSObject;
+import org.ajax4jsf.javascript.JSReference;
+import org.ajax4jsf.renderkit.AjaxRendererUtils;
+import org.ajax4jsf.renderkit.RendererUtils.HTML;
+
+public class UIFullCalendar extends UIComponentBase {
+
+ private static final String CALLBACK = "callback";
+ private static final String END_DATE = "endDate";
+ private static final String START_DATE = "startDate";
+
+ @Override
+ public String getFamily() {
+ return null;
+ }
+
+ private Object createAjaxFunction(FacesContext context) {
+ JSFunction ajaxFunction = AjaxRendererUtils.buildAjaxFunction(this,
+ context);
+
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put(START_DATE, new JSReference(START_DATE));
+ params.put(END_DATE, new JSReference(END_DATE));
+
+ Map<String, Object> eventOptions = AjaxRendererUtils.buildEventOptions(
+ context, this, params, true);
+ eventOptions.put("oncomplete", new JSReference(CALLBACK));
+
+ ajaxFunction.addParameter(eventOptions);
+
+ return new JSFunctionDefinition("event", START_DATE, END_DATE, CALLBACK)
+ .addToBody(ajaxFunction);
+ }
+
+ @Override
+ public void decode(FacesContext context) {
+ if (!this.isRendered()) {
+ return;
+ }
+
+ Map<String, String> requestParameterMap = context.getExternalContext()
+ .getRequestParameterMap();
+ if (requestParameterMap.get(this.getClientId(context)) != null) {
+ String startDateParam = requestParameterMap.get(START_DATE);
+ String endDateParam = requestParameterMap.get(END_DATE);
+
+ try {
+ Date startDate = new Date(Long.parseLong(startDateParam));
+ Date endDate = new Date(Long.parseLong(endDateParam));
+
+ new FullCalendarAjaxEvent(this, startDate, endDate).queue();
+ } catch (NumberFormatException e) {
+ // TODO: handle exception
+ }
+ }
+ }
+
+ @Override
+ public void broadcast(FacesEvent event) throws AbortProcessingException {
+ super.broadcast(event);
+
+ if (event instanceof FullCalendarAjaxEvent) {
+ FullCalendarAjaxEvent calendarAjaxEvent = (FullCalendarAjaxEvent) event;
+
+ FacesContext facesContext = getFacesContext();
+ AjaxContext ajaxContext = AjaxContext
+ .getCurrentInstance(facesContext);
+
+ ajaxContext.setResponseData(getCalendarData(calendarAjaxEvent
+ .getStartDate(), calendarAjaxEvent.getEndDate()));
+ }
+ }
+
+ private Object getCalendarData(Date startDate, Date endDate) {
+
+// $year = date('Y');
+// $month = date('m');
+//
+// echo json_encode(array(
+//
+// array(
+// 'id' => 111,
+// 'title' => "Event1",
+// 'start' => "$year-$month-10",
+// 'url' => "http://yahoo.com/"
+// ),
+//
+// array(
+// 'id' => 222,
+// 'title' => "Event2",
+// 'start' => "$year-$month-20",
+// 'end' => "$year-$month-22",
+// 'url' => "http://yahoo.com/"
+// )
+//
+// ));
+
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+ format.setLenient(false);
+
+ List<Map<String, Object>> data = new ArrayList<Map<String,
Object>>();
+
+ Map<String, Object> firstDataElement = new HashMap<String, Object>();
+
+ firstDataElement.put("id", 111);
+ firstDataElement.put("title", "Event 1");
+ Calendar calendar = Calendar.getInstance();
+
+ calendar.set(Calendar.DATE, 10);
+
+ firstDataElement.put("start", format.format(calendar.getTimeInMillis()));
+ firstDataElement.put("url", "http://www.yahoo.com");
+
+ data.add(firstDataElement);
+
+ Map<String, Object> secondDataElement = new HashMap<String, Object>();
+
+ secondDataElement.put("id", 222);
+ secondDataElement.put("title", "Event 2");
+ calendar.set(Calendar.DATE, 20);
+ secondDataElement.put("start", format.format(calendar.getTimeInMillis()));
+ calendar.set(Calendar.DATE, 22);
+ secondDataElement.put("end", format.format(calendar.getTimeInMillis()));
+ secondDataElement.put("url", "http://www.yahoo.com");
+
+ data.add(secondDataElement);
+
+ return data;
+ }
+
+ @Override
+ public void encodeEnd(FacesContext context) throws IOException {
+ ResponseWriter writer = context.getResponseWriter();
+ String clientId = this.getClientId(context);
+
+ writer.startElement(HTML.DIV_ELEM, this);
+ writer.writeAttribute(HTML.id_ATTRIBUTE, clientId, HTML.id_ATTRIBUTE);
+ writer.writeAttribute(HTML.class_ATTRIBUTE, "rich-fullc",
+ HTML.class_ATTRIBUTE);
+
+ UIComponent loadingFacet = getFacet("loading");
+ if (loadingFacet != null && loadingFacet.isRendered()) {
+ writer.startElement(HTML.DIV_ELEM, this);
+ writer.writeAttribute(HTML.id_ATTRIBUTE, clientId + ":loading",
+ null);
+ writer.writeAttribute(HTML.class_ATTRIBUTE, "rich-fullc-loading",
+ null);
+
+ loadingFacet.encodeAll(context);
+
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ writer.startElement(HTML.SCRIPT_ELEM, this);
+ writer
+ .writeAttribute(HTML.TYPE_ATTR, "text/javascript",
+ HTML.TYPE_ATTR);
+ writer.writeText(new JSObject("RichFaces.FullCalendar", clientId,
+ createAjaxFunction(context)).toScript(), null);
+ writer.endElement(HTML.SCRIPT_ELEM);
+
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+}
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/faces-config.xml
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/faces-config.xml
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/faces-config.xml 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+
+<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
+
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
+
+ <managed-bean>
+ <managed-bean-name>componentBean</managed-bean-name>
+ <managed-bean-class>demo.beans.ComponentBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+
+ <application>
+ <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
+ </application>
+
+</faces-config>
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/web.xml
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/web.xml
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/WEB-INF/web.xml 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
+
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <display-name>Archetype Created Web Application</display-name>
+ <context-param>
+ <param-name>org.richfaces.SKIN</param-name>
+ <param-value>blueSky</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
+ <param-value>server</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.richfaces.LoadStyleStrategy</param-name>
+ <param-value>ALL</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.richfaces.CONTROL_SKINNING_CLASSES</param-name>
+ <param-value>disable</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.richfaces.LoadScriptStrategy</param-name>
+ <param-value>DEFAULT</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.ajax4jsf.COMPRESS_SCRIPT</param-name>
+ <param-value>false</param-value>
+ </context-param>
+ <context-param>
+ <param-name>org.ajax4jsf.COMPRESS_STYLE</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <param-name>facelets.DEVELOPMENT</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <param-name>facelets.SKIP_COMMENTS</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <param-name>facelets.VIEW_MAPPINGS</param-name>
+ <param-value>*.xhtml</param-value>
+ </context-param>
+ <session-config>
+ <session-timeout>1000</session-timeout>
+ </session-config>
+ <filter>
+ <filter-name>richfaces</filter-name>
+ <filter-class>org.ajax4jsf.Filter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>richfaces</filter-name>
+ <servlet-name>Faces Servlet</servlet-name>
+ <dispatcher>REQUEST</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>ERROR</dispatcher>
+ </filter-mapping>
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>/faces/*</url-pattern>
+ </servlet-mapping>
+</web-app>
\ No newline at end of file
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/fullcalendar.js
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/fullcalendar.js
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/fullcalendar.js 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,3418 @@
+/*!
+ * FullCalendar v1.4.5
+ *
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: Sun Feb 21 20:30:11 2010 -0800
+ *
+ */
+
+(function($) {
+
+
+var fc = $.fullCalendar = {};
+var views = 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]{ '—'[ 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: ' ◄ ',
+ next: ' ► ',
+ prevYear: ' << ',
+ nextYear: ' >> ',
+ today: 'today',
+ month: 'month',
+ week: 'week',
+ day: 'day'
+ },
+
+ // jquery-ui theming
+ theme: false,
+ buttonIcons: {
+ prev: 'circle-triangle-w',
+ next: 'circle-triangle-e'
+ }
+
+};
+
+// right-to-left defaults
+var rtlDefaults = {
+ header: {
+ left: 'next,prev today',
+ center: '',
+ right: 'title'
+ },
+ buttonText: {
+ prev: ' ► ',
+ next: ' ◄ ',
+ prevYear: ' >> ',
+ nextYear: ' << '
+ },
+ 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) {
+
+ // method calling
+ if (typeof options == 'string') {
+ var args = Array.prototype.slice.call(arguments, 1),
+ res;
+ this.each(function() {
+ var data = $.data(this, 'fullCalendar');
+ if (data) {
+ var r = data[options].apply(this, args);
+ if (res == undefined) {
+ res = r;
+ }
+ }
+ });
+ if (res != undefined) {
+ return res;
+ }
+ return this;
+ }
+
+ // pluck the 'events' and 'eventSources' options
+ var eventSources = options.eventSources || [];
+ delete options.eventSources;
+ if (options.events) {
+ eventSources.push(options.events);
+ delete options.events;
+ }
+
+ // first event source reserved for 'sticky' events
+ eventSources.unshift([]);
+
+ // initialize options
+ options = $.extend(true, {},
+ defaults,
+ (options.isRTL || options.isRTL==undefined && defaults.isRTL) ? rtlDefaults :
{},
+ options
+ );
+ var tm = options.theme ? 'ui' : 'fc'; // for making theme classes
+
+
+ this.each(function() {
+
+
+ /* Instance Initialization
+ -----------------------------------------------------------------------------*/
+
+ // element
+ var _element = this,
+ element = $(_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');
+ }
+
+ if (options.year != undefined && options.year != date.getFullYear()) {
+ date.setDate(1);
+ date.setMonth(0);
+ date.setFullYear(options.year);
+ }
+ if (options.month != undefined && options.month != date.getMonth()) {
+ date.setDate(1);
+ date.setMonth(options.month);
+ }
+ if (options.date != undefined) {
+ date.setDate(options.date);
+ }
+
+
+
+ /* View Rendering
+ -----------------------------------------------------------------------------*/
+
+ function changeView(v) {
+ if (v != viewName) {
+ ignoreWindowResize++; // because setMinHeight might change the height before render
(and subsequently setSize) is reached
+
+ 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] = $.fullCalendar.views[v](
+ newViewElement = absoluteViewElement =
+ $("<div class='fc-view fc-view-" + v + "'
style='position:absolute'/>")
+ .appendTo(content),
+ options
+ );
+ }
+
+ if (header) {
+ // update 'active' view button
+ header.find('div.fc-button-' + viewName).removeClass(tm +
'-state-active');
+ header.find('div.fc-button-' + v).addClass(tm + '-state-active');
+ }
+
+ view.name = viewName = v;
+ render(); // 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
+
+ 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;
+ }
+
+
+ // 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();
+ 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 == 0) {
+ if (callback) {
+ callback(events);
+ }
+ }
+ }, i=0;
+ for (; i<eventSources.length; i++) {
+ fetchEventSource(eventSources[i], sourceDone);
+ }
+ }
+
+ // Fetch from a particular source. Append to the 'events' array
+ function fetchEventSource(src, callback) {
+ var prevViewName = view.name,
+ prevDate = cloneDate(date),
+ reportEvents = function(a) {
+ if (prevViewName == view.name && +prevDate == +date && // protects
from fast switching
+ $.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{
+ if (year != undefined) {
+ date.setFullYear(year);
+ }
+ if (month != undefined) {
+ date.setMonth(month);
+ }
+ if (dateNum != undefined) {
+ date.setDate(dateNum);
+ }
+ }
+ render();
+ },
+
+ incrementDate: function(years, months, days) {
+ if (years != undefined) {
+ addYears(date, years);
+ }
+ if (months != undefined) {
+ addMonths(date, months);
+ }
+ if (days != undefined) {
+ addDays(date, days);
+ }
+ render();
+ },
+
+ //
+ // Event Manipulation
+ //
+
+ updateEvent: function(event) { // update an existing event
+ var i, len = events.length, e,
+ startDelta = event.start - event._start,
+ endDelta = event.end ?
+ (event.end - (event._end || view.defaultEventEnd(event))) // event._end would be
null if event.end
+ : 0; // was null and event was
just resized
+ for (i=0; i<len; i++) {
+ e = events[i];
+ if (e._id == event._id && e != event) {
+ e.start = new Date(+e.start + startDelta);
+ if (event.end) {
+ if (e.end) {
+ e.end = new Date(+e.end + endDelta);
+ }else{
+ e.end = new Date(+view.defaultEventEnd(e) + endDelta);
+ }
+ }else{
+ e.end = null;
+ }
+ e.title = event.title;
+ e.url = event.url;
+ e.allDay = event.allDay;
+ e.className = event.className;
+ e.editable = event.editable;
+ normalizeEvent(e, options);
+ }
+ }
+ normalizeEvent(event, options);
+ eventsChanged();
+ },
+
+ renderEvent: function(event, stick) { // render a new event
+ normalizeEvent(event, options);
+ if (!event.source) {
+ if (stick) {
+ (event.source = eventSources[0]).push(event);
+ }
+ events.push(event);
+ }
+ eventsChanged();
+ },
+
+ removeEvents: function(filter) {
+ if (!filter) { // remove all
+ events = [];
+ // clear all array sources
+ for (var i=0; i<eventSources.length; i++) {
+ if (typeof eventSources[i] == 'object') {
+ eventSources[i] = [];
+ }
+ }
+ }else{
+ if (!$.isFunction(filter)) { // an event ID
+ var id = filter + '';
+ filter = function(e) {
+ return e._id == id;
+ };
+ }
+ events = $.grep(events, filter, true);
+ // remove events from array sources
+ for (var i=0; i<eventSources.length; i++) {
+ if (typeof eventSources[i] == 'object') {
+ eventSources[i] = $.grep(eventSources[i], filter, true);
+ }
+ }
+ }
+ eventsChanged();
+ },
+
+ clientEvents: function(filter) {
+ if ($.isFunction(filter)) {
+ return $.grep(events, filter);
+ }
+ else if (filter) { // an event ID
+ filter += '';
+ return $.grep(events, function(e) {
+ return e._id == filter;
+ });
+ }
+ return events; // else, return all
+ },
+
+ rerenderEvents: 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);
+ }
+
+ };
+
+ $.data(this, 'fullCalendar', publicMethods);
+
+
+
+ /* Header
+ -----------------------------------------------------------------------------*/
+
+ var header,
+ sections = options.header;
+ if (sections) {
+ header = $("<table class='fc-header'/>")
+ .append($("<tr/>")
+ .append($("<td
class='fc-header-left'/>").append(buildSection(sections.left)))
+ .append($("<td
class='fc-header-center'/>").append(buildSection(sections.center)))
+ .append($("<td
class='fc-header-right'/>").append(buildSection(sections.right))))
+ .prependTo(element);
+ }
+ function buildSection(buttonStr) {
+ if (buttonStr) {
+ var tr = $("<tr/>");
+ $.each(buttonStr.split(' '), function(i) {
+ if (i > 0) {
+ tr.append("<td><span
class='fc-header-space'/></td>");
+ }
+ var prevButton;
+ $.each(this.split(','), function(j, buttonName) {
+ if (buttonName == 'title') {
+ tr.append("<td><h2
class='fc-header-title'> </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);
+
+
+ // 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);
+ }
+
+
+ });
+
+ return this;
+
+};
+
+
+
+/* Important Event Utilities
+-----------------------------------------------------------------------------*/
+
+var fakeID = 0;
+
+function normalizeEvent(event, options) {
+ event._id = event._id || (event.id == undefined ? '_fc' + fakeID++ : event.id +
'');
+ if (event.date) {
+ if (!event.start) {
+ event.start = event.date;
+ }
+ delete event.date;
+ }
+ event._start = cloneDate(event.start = parseDate(event.start));
+ event.end = parseDate(event.end);
+ if (event.end && event.end <= event.start) {
+ event.end = null;
+ }
+ event._end = event.end ? cloneDate(event.end) : null;
+ if (event.allDay == undefined) {
+ event.allDay = options.allDayDefault;
+ }
+ if (event.className) {
+ if (typeof event.className == 'string') {
+ event.className = event.className.split(/\s+/);
+ }
+ }else{
+ event.className = [];
+ }
+}
+// TODO: if there is no title or start date, return false to indicate an invalid event
+
+
+/* Grid-based Views: month, basicWeek, basicDay
+-----------------------------------------------------------------------------*/
+
+setDefaults({
+ weekMode: 'fixed'
+});
+
+views.month = function(element, options) {
+ 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
+ );
+ }
+ });
+}
+
+views.basicWeek = function(element, options) {
+ 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
+ );
+ }
+ });
+};
+
+views.basicDay = function(element, options) {
+ 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
+ );
+ }
+ });
+}
+
+
+// rendering bugs
+
+var tdHeightBug;
+
+
+function Grid(element, options, methods) {
+
+ 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.init(element, options);
+
+
+
+ /* Grid Rendering
+ -----------------------------------------------------------------------------*/
+
+
+ element.addClass('fc-grid');
+ if (element.disableSelection) {
+ element.disableSelection();
+ }
+
+ 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'> </div></div></td>";
+ addDays(d, 1);
+ if (nwe) {
+ skipWeekend(d);
+ }
+ }
+ s += "</tr>";
+ }
+ tbody = $(s + "</tbody>").appendTo(table);
+ tbody.find('td').click(dayClick);
+
+ 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'> </div></div>" +
+ "</td>";
+ addDays(d, 1);
+ if (nwe) {
+ skipWeekend(d);
+ }
+ }
+ s += "</tr>";
+ }
+ tbody.append(s);
+ }
+ tbody.find('td.fc-new').removeClass('fc-new').click(dayClick);
+
+ // re-label and re-class existing cells
+ d = cloneDate(view.visStart);
+ tbody.find('td').each(function() {
+ var td = $(this);
+ if (rowCnt > 1) {
+ if (d.getMonth() == month) {
+ td.removeClass('fc-other-month');
+ }else{
+ td.addClass('fc-other-month');
+ }
+ }
+ if (+d == +today) {
+ td.removeClass('fc-not-today')
+ .addClass('fc-today')
+ .addClass(tm + '-state-highlight');
+ }else{
+ td.addClass('fc-not-today')
+ .removeClass('fc-today')
+ .removeClass(tm + '-state-highlight');
+ }
+ td.find('div.fc-day-number').text(d.getDate());
+ addDays(d, 1);
+ if (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 dayClick(ev) {
+ var n = parseInt(this.className.match(/fc\-day(\d+)/)[1]),
+ date = addDays(
+ cloneDate(view.visStart),
+ Math.floor(n/colCnt) * 7 + n % colCnt
+ );
+ view.trigger('dayClick', this, date, true, ev);
+ }
+
+
+
+ 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, visEventEnd),
+ 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 visEventEnd(event) { // returns exclusive 'visible' end, for rendering
+ if (event.end) {
+ var end = cloneDate(event.end);
+ return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
+ }else{
+ return addDays(cloneDate(event.start), 1);
+ }
+ }
+
+
+
+ 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 matrix;
+ eventElement.draggable({
+ zIndex: 9,
+ delay: 50,
+ opacity: view.option('dragOpacity'),
+ revertDuration: options.dragRevertDuration,
+ start: function(ev, ui) {
+ view.hideEvents(event, eventElement);
+ view.trigger('eventDragStart', eventElement, event, ev, ui);
+ matrix = new HoverMatrix(function(cell) {
+ eventElement.draggable('option', 'revert', !cell || !cell.rowDelta
&& !cell.colDelta);
+ if (cell) {
+ view.showOverlay(cell);
+ }else{
+ view.hideOverlay();
+ }
+ });
+ tbody.find('tr').each(function() {
+ matrix.row(this);
+ });
+ var tds = tbody.find('tr:first td');
+ if (rtl) {
+ tds = $(tds.get().reverse());
+ }
+ tds.each(function() {
+ matrix.col(this);
+ });
+ matrix.mouse(ev.pageX, ev.pageY);
+ },
+ drag: function(ev) {
+ matrix.mouse(ev.pageX, ev.pageY);
+ },
+ stop: function(ev, ui) {
+ view.hideOverlay();
+ view.trigger('eventDragStop', eventElement, event, ev, ui);
+ var cell = matrix.cell;
+ if (!cell || !cell.rowDelta && !cell.colDelta) {
+ if ($.browser.msie) {
+ eventElement.css('filter', ''); // clear IE opacity side-effects
+ }
+ view.showEvents(event, eventElement);
+ }else{
+ eventElement.find('a').removeAttr('href'); // prevents safari from
visiting the link
+ view.eventDrop(this, event, cell.rowDelta*7+cell.colDelta*dis, 0, event.allDay, ev,
ui);
+ }
+ }
+ });
+ }
+ }
+
+
+ // event resizing w/ 'view' methods...
+
+};
+
+
+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);
+ }
+ }
+
+}
+
+
+
+/* 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) {
+ 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')
+ );
+ }
+ });
+};
+
+views.agendaDay = function(element, options) {
+ 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')
+ );
+ }
+ });
+};
+
+function Agenda(element, options, methods) {
+
+ var head, body, bodyContent, bodyTable, bg,
+ colCnt,
+ 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.init(element, options);
+
+
+
+ /* Time-slot rendering
+ -----------------------------------------------------------------------------*/
+
+
+ element.addClass('fc-agenda');
+ if (element.disableSelection) {
+ element.disableSelection();
+ }
+
+ 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'> </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'> </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'> </div></div></td>"
+
+ "<th class='" + tm +
"-state-default'> </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);
+ head.find('td').click(slotClick);
+
+ // 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==0 ? 'fc-first' : (minutes==0 ? '' : 'fc-minor')) +
+ "'><th class='fc-axis fc-leftmost " + tm +
"-state-default'>" +
+ ((!slotNormal || minutes==0) ? formatDate(d, options.axisFormat) :
' ') +
+ "</th><td class='fc-slot" + i + ' ' +
+ tm + "-state-default'><div
style='position:relative'> </div></td></tr>";
+ addMinutes(d, options.slotMinutes);
+ }
+ 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);
+ body.find('td').click(slotClick);
+
+ // 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==0 ? 'fc-leftmost ' : '') +
+ (+d == +today ? tm + '-state-highlight fc-today' : 'fc-not-today')
+
+ "'><div
class='fc-day-content'><div> </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 (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);
+ setOuterWidth(topTDs.slice(-2, -1), clientWidth - axisWidth - colWidth*(colCnt-1));
+
+ bg.css({
+ left: axisWidth,
+ width: clientWidth - axisWidth
+ });
+ }
+
+
+
+
+ function slotClick(ev) {
+ var col = Math.floor((ev.pageX - bg.offset().left) / colWidth),
+ date = addDays(cloneDate(view.visStart), dit + dis*col),
+ 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, visEventEnd),
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, visEventEnd),
+ 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(day2col(dayOfWeek));
+ },
+ function(dayOfWeek) {
+ return axisWidth + colContentPositions.right(day2col(dayOfWeek));
+ },
+ daySegmentContainer,
+ bindDaySegHandlers,
+ 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 +=
+ "<div class='" + className + event.className.join(' ') +
"' style='position:absolute;z-index:8;top:" + top + "px;left:"
+ 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>";
+ }
+ 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) {
+ bindSlotSegHandlers(event, eventElement, seg);
+ }else{
+ eventElement[0]._fci = i; // for lazySegBind
+ }
+ view.reportEventElement(event, eventElement);
+ }
+ }
+
+ lazySegBind(slotSegmentContainer, segs, bindSlotSegHandlers);
+
+ // 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 visEventEnd(event) { // returns exclusive 'visible' end, for rendering
+ if (event.allDay) {
+ if (event.end) {
+ var end = cloneDate(event.end);
+ return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
+ }else{
+ return addDays(cloneDate(event.start), 1);
+ }
+ }
+ if (event.end) {
+ return cloneDate(event.end);
+ }else{
+ return addMinutes(cloneDate(event.start), options.defaultEventMinutes);
+ }
+ }
+
+
+
+ function bindDaySegHandlers(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 bindSlotSegHandlers(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 origPosition, origWidth,
+ resetElement,
+ allDay=true,
+ matrix;
+ eventElement.draggable({
+ zIndex: 9,
+ opacity: view.option('dragOpacity', 'month'), // use whatever the
month view was using
+ revertDuration: options.dragRevertDuration,
+ start: function(ev, ui) {
+ view.hideEvents(event, eventElement);
+ view.trigger('eventDragStart', eventElement, event, ev, ui);
+ origPosition = eventElement.position();
+ origWidth = eventElement.width();
+ resetElement = function() {
+ if (!allDay) {
+ eventElement
+ .width(origWidth)
+ .height('')
+ .draggable('option', 'grid', null);
+ allDay = true;
+ }
+ };
+ matrix = new HoverMatrix(function(cell) {
+ eventElement.draggable('option', 'revert', !cell || !cell.rowDelta
&& !cell.colDelta);
+ if (cell) {
+ if (!cell.row) { // on full-days
+ resetElement();
+ view.showOverlay(cell);
+ }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;
+ }
+ view.hideOverlay();
+ }
+ }else{ // mouse is outside of everything
+ view.hideOverlay();
+ }
+ });
+ matrix.row(head.find('td'));
+ bg.find('td').each(function() {
+ matrix.col(this);
+ });
+ matrix.row(body);
+ matrix.mouse(ev.pageX, ev.pageY);
+ },
+ drag: function(ev, ui) {
+ matrix.mouse(ev.pageX, ev.pageY);
+ },
+ stop: function(ev, ui) {
+ view.hideOverlay();
+ view.trigger('eventDragStop', eventElement, event, ev, ui);
+ var cell = matrix.cell,
+ dayDelta = dis * (
+ allDay ? // can't trust cell.colDelta when using slot grid
+ (cell ? cell.colDelta : 0) :
+ Math.floor((ui.position.left - origPosition.left) / colWidth)
+ );
+ if (!cell || !dayDelta && !cell.rowDelta) {
+ // over nothing (has reverted)
+ resetElement();
+ if ($.browser.msie) {
+ eventElement.css('filter', ''); // clear IE opacity side-effects
+ }
+ view.showEvents(event, eventElement);
+ }else{
+ eventElement.find('a').removeAttr('href'); // prevents safari from
visiting the link
+ view.eventDrop(
+ this, event, dayDelta,
+ allDay ? 0 : // minute delta
+ Math.round((eventElement.offset().top - bodyContent.offset().top) / slotHeight)
+ * options.slotMinutes
+ + minMinute
+ - (event.start.getHours() * 60 + event.start.getMinutes()),
+ allDay, ev, ui
+ );
+ }
+ }
+ });
+ }
+ }
+
+
+
+ // when event starts out IN TIMESLOTS
+
+ function draggableSlotEvent(event, eventElement, timeElement) {
+ if (!options.disableDragging && eventElement.draggable) {
+ var origPosition,
+ resetElement,
+ prevSlotDelta, slotDelta,
+ allDay=false,
+ matrix;
+ 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.hideEvents(event, eventElement);
+ view.trigger('eventDragStart', eventElement, event, ev, ui);
+ if ($.browser.msie) {
+ eventElement.find('span.fc-event-bg').hide(); // nested opacities mess up
in IE, just hide
+ }
+ origPosition = eventElement.position();
+ resetElement = function() {
+ // convert back to original slot-event
+ if (allDay) {
+ timeElement.css('display', ''); // show() was causing
display=inline
+ eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
+ allDay = false;
+ }
+ };
+ prevSlotDelta = 0;
+ matrix = new HoverMatrix(function(cell) {
+ eventElement.draggable('option', 'revert', !cell);
+ if (cell) {
+ if (!cell.row && options.allDaySlot) { // over full days
+ if (!allDay) {
+ // convert to temporary all-day event
+ allDay = true;
+ timeElement.hide();
+ eventElement.draggable('option', 'grid', null);
+ }
+ view.showOverlay(cell);
+ }else{ // on slots
+ resetElement();
+ view.hideOverlay();
+ }
+ }else{
+ view.hideOverlay();
+ }
+ });
+ if (options.allDaySlot) {
+ matrix.row(head.find('td'));
+ }
+ bg.find('td').each(function() {
+ matrix.col(this);
+ });
+ matrix.row(body);
+ matrix.mouse(ev.pageX, ev.pageY);
+ },
+ drag: function(ev, ui) {
+ slotDelta = Math.round((ui.position.top - origPosition.top) / slotHeight);
+ if (slotDelta != prevSlotDelta) {
+ if (!allDay) {
+ // update time header
+ var minuteDelta = slotDelta*options.slotMinutes,
+ newStart = addMinutes(cloneDate(event.start), minuteDelta),
+ newEnd;
+ if (event.end) {
+ newEnd = addMinutes(cloneDate(event.end), minuteDelta);
+ }
+ timeElement.text(formatDates(newStart, newEnd,
view.option('timeFormat')));
+ }
+ prevSlotDelta = slotDelta;
+ }
+ matrix.mouse(ev.pageX, ev.pageY);
+ },
+ stop: function(ev, ui) {
+ view.hideOverlay();
+ view.trigger('eventDragStop', eventElement, event, ev, ui);
+ var cell = matrix.cell,
+ dayDelta = dis * (
+ allDay ? // can't trust cell.colDelta when using slot grid
+ (cell ? cell.colDelta : 0) :
+ Math.floor((ui.position.left - origPosition.left) / colWidth)
+ );
+ if (!cell || !slotDelta && !dayDelta) {
+ resetElement();
+ if ($.browser.msie) {
+ eventElement
+ .css('filter', '') // clear IE opacity side-effects
+ .find('span.fc-event-bg').css('display', ''); // .show()
made display=inline
+ }
+ eventElement.css(origPosition); // sometimes fast drags make event revert to wrong
position
+ view.showEvents(event, eventElement);
+ }else{
+ view.eventDrop(
+ this, event, dayDelta,
+ allDay ? 0 : slotDelta * options.slotMinutes, // minute delta
+ allDay, ev, ui
+ );
+ }
+ }
+ });
+ }
+ }
+
+
+
+
+ /* 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
+ }
+ }
+ });
+ }
+ }
+
+
+
+
+ /* Misc
+ -----------------------------------------------------------------------------*/
+
+ // 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)
+ ));
+ }
+
+
+
+
+ function day2col(dayOfWeek) {
+ return ((dayOfWeek - Math.max(firstDay,nwe)+colCnt) % colCnt)*dis+dit;
+ }
+
+
+}
+
+
+// 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);
+ }
+ }
+ }
+ }
+}
+
+
+/* Methods & Utilities for All Views
+-----------------------------------------------------------------------------*/
+
+var viewMethods = {
+
+ // TODO: maybe change the 'vis' variables to 'excl'
+
+ /*
+ * 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 = {};
+ },
+
+
+
+ // 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)
+
+ showOverlay: function(props) {
+ if (!this.dayOverlay) {
+ this.dayOverlay = $("<div class='fc-cell-overlay'
style='position:absolute;z-index:3;display:none'/>")
+ .appendTo(this.element);
+ }
+ var o = this.element.offset();
+ this.dayOverlay
+ .css({
+ top: props.top - o.top,
+ left: props.left - o.left,
+ width: props.width,
+ height: props.height
+ })
+ .show();
+ },
+
+ hideOverlay: function() {
+ if (this.dayOverlay) {
+ this.dayOverlay.hide();
+ }
+ },
+
+
+
+ // 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;
+}
+
+
+
+
+/* Date Math
+-----------------------------------------------------------------------------*/
+
+var DAY_MS = 86400000,
+ HOUR_MS = 3600000,
+ MINUTE_MS = 60000;
+
+function addYears(d, n, keepTime) {
+ d.setFullYear(d.getFullYear() + n);
+ if (!keepTime) {
+ clearTime(d);
+ }
+ return d;
+}
+
+function addMonths(d, n, keepTime) { // prevents day overflow/underflow
+ if (+d) { // prevent infinite looping on invalid dates
+ var m = d.getMonth() + n,
+ check = cloneDate(d);
+ check.setDate(1);
+ check.setMonth(m);
+ d.setMonth(m);
+ if (!keepTime) {
+ clearTime(d);
+ }
+ while (d.getMonth() != check.getMonth()) {
+ d.setDate(d.getDate() + (d < check ? 1 : -1));
+ }
+ }
+ return d;
+}
+
+function addDays(d, n, keepTime) { // deals with daylight savings
+ if (+d) {
+ var dd = d.getDate() + n,
+ check = cloneDate(d);
+ check.setHours(9); // set to middle of day
+ check.setDate(dd);
+ d.setDate(dd);
+ if (!keepTime) {
+ clearTime(d);
+ }
+ fixDate(d, check);
+ }
+ return d;
+}
+fc.addDays = addDays;
+
+function fixDate(d, check) { // force d to be on check's YMD, for daylight savings
purposes
+ if (+d) { // prevent infinite looping on invalid dates
+ while (d.getDate() != check.getDate()) {
+ d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
+ }
+ }
+}
+
+function addMinutes(d, n) {
+ d.setMinutes(d.getMinutes() + n);
+ return d;
+}
+
+function clearTime(d) {
+ d.setHours(0);
+ d.setMinutes(0);
+ d.setSeconds(0);
+ d.setMilliseconds(0);
+ return d;
+}
+
+function cloneDate(d, dontKeepTime) {
+ if (dontKeepTime) {
+ return clearTime(new Date(+d));
+ }
+ return new Date(+d);
+}
+
+function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
+ var i=0, d;
+ do {
+ d = new Date(1970, i++, 1);
+ } while (d.getHours() != 0);
+ return d;
+}
+
+function skipWeekend(date, inc, excl) {
+ inc = inc || 1;
+ while (date.getDay()==0 || (excl && date.getDay()==1 || !excl &&
date.getDay()==6)) {
+ addDays(date, inc);
+ }
+ return date;
+}
+
+
+
+/* Date Parsing
+-----------------------------------------------------------------------------*/
+
+var parseDate = fc.parseDate = function(s) {
+ if (typeof s == 'object') { // already a Date object
+ return s;
+ }
+ if (typeof s == 'number') { // a UNIX timestamp
+ return new Date(s * 1000);
+ }
+ if (typeof s == 'string') {
+ if (s.match(/^\d+$/)) { // a UNIX timestamp
+ return new Date(parseInt(s) * 1000);
+ }
+ return parseISO8601(s, true) || (s ? new Date(s) : null);
+ }
+ // TODO: never return invalid dates (like from new Date(<string>)), return null
instead
+ return null;
+}
+
+var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) {
+ // derived from
http://delete.me.uk/2005/03/iso8601.html
+ // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
+ var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T
]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/);
+ if (!m) {
+ return null;
+ }
+ var date = new Date(m[1], 0, 1),
+ check = new Date(m[1], 0, 1, 9, 0),
+ offset = 0;
+ if (m[3]) {
+ date.setMonth(m[3] - 1);
+ check.setMonth(m[3] - 1);
+ }
+ if (m[5]) {
+ date.setDate(m[5]);
+ check.setDate(m[5]);
+ }
+ fixDate(date, check);
+ if (m[7]) {
+ date.setHours(m[7]);
+ }
+ if (m[8]) {
+ date.setMinutes(m[8]);
+ }
+ if (m[10]) {
+ date.setSeconds(m[10]);
+ }
+ if (m[12]) {
+ date.setMilliseconds(Number("0." + m[12]) * 1000);
+ }
+ fixDate(date, check);
+ if (!ignoreTimezone) {
+ if (m[14]) {
+ offset = Number(m[16]) * 60 + Number(m[17]);
+ offset *= m[15] == '-' ? 1 : -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ return new Date(+date + (offset * 60 * 1000));
+}
+
+var parseTime = fc.parseTime = function(s) { // returns minutes since start of day
+ if (typeof s == 'number') { // an hour
+ return s * 60;
+ }
+ if (typeof s == 'object') { // a Date object
+ return s.getHours() * 60 + s.getMinutes();
+ }
+ var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);
+ if (m) {
+ var h = parseInt(m[1]);
+ if (m[3]) {
+ h %= 12;
+ if (m[3].toLowerCase().charAt(0) == 'p') {
+ h += 12;
+ }
+ }
+ return h * 60 + (m[2] ? parseInt(m[2]) : 0);
+ }
+};
+
+
+
+/* Date Formatting
+-----------------------------------------------------------------------------*/
+
+var formatDate = fc.formatDate = function(date, format, options) {
+ return formatDates(date, null, format, options);
+}
+
+var formatDates = fc.formatDates = function(date1, date2, format, options) {
+ options = options || defaults;
+ var date = date1,
+ otherDate = date2,
+ i, len = format.length, c,
+ i2, formatter,
+ res = '';
+ for (i=0; i<len; i++) {
+ c = format.charAt(i);
+ if (c == "'") {
+ for (i2=i+1; i2<len; i2++) {
+ if (format.charAt(i2) == "'") {
+ if (date) {
+ if (i2 == i+1) {
+ res += "'";
+ }else{
+ res += format.substring(i+1, i2);
+ }
+ i = i2;
+ }
+ break;
+ }
+ }
+ }
+ else if (c == '(') {
+ for (i2=i+1; i2<len; i2++) {
+ if (format.charAt(i2) == ')') {
+ var subres = formatDate(date, format.substring(i+1, i2), options);
+ if (parseInt(subres.replace(/\D/, ''))) {
+ res += subres;
+ }
+ i = i2;
+ break;
+ }
+ }
+ }
+ else if (c == '[') {
+ for (i2=i+1; i2<len; i2++) {
+ if (format.charAt(i2) == ']') {
+ var subformat = format.substring(i+1, i2);
+ var subres = formatDate(date, subformat, options);
+ if (subres != formatDate(otherDate, subformat, options)) {
+ res += subres;
+ }
+ i = i2;
+ break;
+ }
+ }
+ }
+ else if (c == '{') {
+ date = date2;
+ otherDate = date1;
+ }
+ else if (c == '}') {
+ date = date1;
+ otherDate = date2;
+ }
+ else {
+ for (i2=len; i2>i; i2--) {
+ if (formatter = dateFormatters[format.substring(i, i2)]) {
+ if (date) {
+ res += formatter(date, options);
+ }
+ i = i2 - 1;
+ break;
+ }
+ }
+ if (i2 == i) {
+ if (date) {
+ res += c;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+var dateFormatters = {
+ s : function(d) { return d.getSeconds() },
+ ss : function(d) { return zeroPad(d.getSeconds()) },
+ m : function(d) { return d.getMinutes() },
+ mm : function(d) { return zeroPad(d.getMinutes()) },
+ h : function(d) { return d.getHours() % 12 || 12 },
+ hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
+ H : function(d) { return d.getHours() },
+ HH : function(d) { return zeroPad(d.getHours()) },
+ d : function(d) { return d.getDate() },
+ dd : function(d) { return zeroPad(d.getDate()) },
+ ddd : function(d,o) { return o.dayNamesShort[d.getDay()] },
+ dddd: function(d,o) { return o.dayNames[d.getDay()] },
+ M : function(d) { return d.getMonth() + 1 },
+ MM : function(d) { return zeroPad(d.getMonth() + 1) },
+ MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] },
+ MMMM: function(d,o) { return o.monthNames[d.getMonth()] },
+ yy : function(d) { return (d.getFullYear()+'').substring(2) },
+ yyyy: function(d) { return d.getFullYear() },
+ t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
+ tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
+ T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
+ TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' },
+ u : function(d) { return formatDate(d,
"yyyy-MM-dd'T'HH:mm:ss'Z'") },
+ S : function(d) {
+ var date = d.getDate();
+ if (date > 10 && date < 20) return 'th';
+ return ['st', 'nd', 'rd'][date%10-1] || 'th';
+ }
+};
+
+
+
+/* Element Dimensions
+-----------------------------------------------------------------------------*/
+
+function setOuterWidth(element, width, includeMargins) {
+ element.each(function(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;
+}
+
+
+
+/* Hover Matrix
+-----------------------------------------------------------------------------*/
+
+function HoverMatrix(changeCallback) {
+
+ var t=this,
+ tops=[], lefts=[],
+ prevRowE, prevColE,
+ origRow, origCol,
+ currRow, currCol;
+
+ t.row = function(e) {
+ prevRowE = $(e);
+ tops.push(prevRowE.offset().top + topCorrect(prevRowE));
+ };
+
+ t.col = function(e) {
+ prevColE = $(e);
+ lefts.push(prevColE.offset().left);
+ };
+
+ t.mouse = function(x, y) {
+ if (origRow == undefined) {
+ tops.push(tops[tops.length-1] + prevRowE.outerHeight());
+ lefts.push(lefts[lefts.length-1] + prevColE.outerWidth());
+ currRow = currCol = -1;
+ }
+ var r, c;
+ for (r=0; r<tops.length && y>=tops[r]; r++) ;
+ for (c=0; c<lefts.length && x>=lefts[c]; c++) ;
+ r = r >= tops.length ? -1 : r - 1;
+ c = c >= lefts.length ? -1 : c - 1;
+ if (r != currRow || c != currCol) {
+ currRow = r;
+ currCol = c;
+ if (r == -1 || c == -1) {
+ t.cell = null;
+ }else{
+ if (origRow == undefined) {
+ origRow = r;
+ origCol = c;
+ }
+ t.cell = {
+ row: r,
+ col: c,
+ top: tops[r],
+ left: lefts[c],
+ width: lefts[c+1] - lefts[c],
+ height: tops[r+1] - tops[r],
+ isOrig: r==origRow && c==origCol,
+ rowDelta: r-origRow,
+ colDelta: c-origCol
+ };
+ }
+ changeCallback(t.cell);
+ }
+ };
+
+}
+
+
+
+/* Misc Utils
+-----------------------------------------------------------------------------*/
+
+var undefined,
+ dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu',
'fri', 'sat'],
+ arrayPop = Array.prototype.pop;
+
+function zeroPad(n) {
+ return (n < 10 ? '0' : '') + n;
+}
+
+function smartProperty(obj, name) { // get a camel-cased/namespaced property of an
object
+ if (obj[name] != undefined) {
+ return obj[name];
+ }
+ var parts = name.split(/(?=[A-Z])/),
+ i=parts.length-1, res;
+ for (; i>=0; i--) {
+ res = obj[parts[i].toLowerCase()];
+ if (res != undefined) {
+ return res;
+ }
+ }
+ return obj[''];
+}
+
+function htmlEscape(s) {
+ return s
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/'/g, ''')
+ .replace(/"/g, '"')
+}
+
+
+
+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, '');
+}
+
+
+
+
+})(jQuery);
\ No newline at end of file
Added: branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/index.jsp
===================================================================
--- branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/index.jsp
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/index.jsp 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,6 @@
+<%@ page language="java" contentType="text/html;
charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1" %>
+
+<%
+ response.sendRedirect("faces/page.xhtml");
+%>
\ No newline at end of file
Added: branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/jquery.js
===================================================================
--- branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/jquery.js
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/jquery.js 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,19 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ *
http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ *
http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new
o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return
this}if(typeof E==="string"){var
G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var
I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var
F=o(I||[]);F.context=document;F.selector=E;return F}}else{return
o(H).find(E)}}else{if(o.isFunction(E)){return
o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return
this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return
this.length},get:function(E){return
E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var
G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?"
":"")+E}else{if(!
H){G.selector=this.selector+"."+H+"("+E+")"}}return
G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return
this},each:function(F,E){return o.each(this,F,E)},index:function(E){return
o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof
F==="string"){if(H===g){return
this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return
this.each(function(I){for(F in
E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return
this.attr(E,F,"curCSS")},text:function(F){if(typeof
F!=="object"&&F!=null){return
this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var
E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return
E},wrapAll:function(E){if(this[0]){var
F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(fun!
ction(){var G=this;while(G.firstChild){G=G.firstChild}return G!
}).appen
d(this)}return this},wrapInner:function(E){return
this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return
this.each(function(){o(this).wrapAll(E)})},append:function(){return
this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return
this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return
this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return
this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return
this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var
F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return
F}else{return this.pushStack(o.unique(o.map(this,function(G){return
o.find(E,G)})),"find",E)}},clone:function(G){var
E=this.map(function(){if(!o.support.no!
CloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var
J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return
o.clean([I.replace(/
jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return
this.cloneNode(true)}});if(G===true){var
H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var
I=o.data(H[F],"events");for(var K in I){for(var J in
I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return
this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return
E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return
F.nodeType===1})),"filter",E)},closest:function(E){var
G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var
H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return
H}H=H.parentNode;F++}})},not:function(E){if(typeof
E==="string"){if(f.test(E)){return this.pu!
shStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilt!
er(E,thi
s)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return
this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return
this.pushStack(o.unique(o.merge(this.get(),typeof
E==="string"?o(E):o.makeArray(E))))},is:function(E){return
!!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return
!!E&&this.is("."+E)},val:function(K){if(K===g){var
E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var
I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return
null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var
G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return
L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof
K==="number"){K+=""}return
this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var
N=o.!
makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return
E===g?(this[0]?this[0].innerHTML.replace(/
jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return
this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return
this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return
this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return
this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var
I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var
G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return
this;functi!
on K(N,O){return
M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?!
(N.getEl
ementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function
z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function
e(){return +new Date}o.extend=o.fn.extend=function(){var
J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof
J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof
J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var
F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof
L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return
J};var
b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return
o},isFunction:function(E){return s.call(E)==="[object Function]"}!
,isArray:function(E){return s.call(E)==="[object
Array]"},isXMLDoc:function(E){return
E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var
F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return
F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var
E,H=0,I=G.length;if(F){if(I===g){for(E in
G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E
in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var
J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return
G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof
I==="number"&&G=="curCSS"&&!b.test(E)?!
I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\!
s+/),fun
ction(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?"
":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return
!o.className.has(F,G)}).join(" "):""}},has:function(F,E){return
F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var
E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in
G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var
L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function
I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return
Math.max(0,Math.round(L))}ret!
urn o.curCSS(H,F,J)},curCSS:function(I,F,G){var
L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return
L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var
M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var
J=F.replace(/\-(\w)/g,function(N,O){return
O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var
H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return
L},clean:function(F,K,I){K=K||document;if(typeof
K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof
F[0]==="string"){var
H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var
G=[],E=[],L=K.createElement("di!
v");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S!
){return
}if(typeof
S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return
T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var
O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var
Q=!O.indexOf("<opt")&&[1,"<select
multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var
R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var
M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.le!
ngth){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var
J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return
E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var
H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var
F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G
in
J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type
property can't be
changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return
J.getAttributeNode(G).nodeValue}!
if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return !
I&&I.spe
cified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return
J[G]}if(!o.support.style&&H&&G=="style"){return
o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var
E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return
E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return
J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return
N.toUpperCase()});if(L){J[G]=K}return
J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var
E=[];if(G!=null){var F=G.length;if(F==null||typeof
G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return
E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}!
return -1},merge:function(H,E){var
F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return
H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var
J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return
F},grep:function(F,J,E){var G=[];for(var
H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return
G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var
I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var
C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/:
]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return
E.parentNode},parents:function(E){return
o.dir(E,"parentNode")},next:function(E){return
o.nth(E,2,"nextSibling")},prev:function(E){retu!
rn o.nth(E,2,"previousSibling")},nextAll:function(E){return o.!
dir(E,"n
extSibling")},prevAll:function(E){return
o.dir(E,"previousSibling")},siblings:function(E){return
o.sibling(E.parentNode.firstChild,E)},children:function(E){return
o.sibling(E.firstChild)},contents:function(E){return
o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var
H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return
this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var
J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var
I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return
this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeo!
f
E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return
this.each(F,arguments)}});function j(E,F){return
E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var
h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var
H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return
E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var
H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in
o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete
F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete
o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"q!
ueue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.ma!
keArray(
H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var
E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var
H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var
F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return
F===g&&H[1]?this.data(H[0]):F}else{return
this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return
this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof
E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return
this.each(function(){var
G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return
this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information:
http://sizzlejs.com/
+ */
+(function(){var
R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^
>+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var
F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof
Y!=="string"){return ab}var
Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var
ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var
ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax
error, unrecognized expression: "+(ah||Y)!
}if(H.call(ai)==="[object
Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var
aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var
aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var
aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return
ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var
Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var
Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var
U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var
V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var
ab in I.filter){!
if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=!
false;if
(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var
X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var
ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax
error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var
I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{!
"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return
T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof
T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var
W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var
X=typeof
U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var
V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var
W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var
Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var
V=L++,T=S;if(!U.match(/\W/)){var
X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var
V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var
X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof
V.getElementByI!
d!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]!
:[]}},NA
ME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var
U=[],X=Y.getElementsByName(V[1]);for(var
W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return
U.length===0?null:U}},TAG:function(T,U){return
U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W="
"+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var
X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&("
"+Y.className+"
").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return
false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var
V=0;T[V]===false;V++){}return
T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var
U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return
T},ATTR:function(X,U,V,T,Y,Z){var
W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]="
"+X[4]+" "}ret!
urn
X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var
W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return
false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return
X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return
T.disabled===false&&T.type!=="hidden"},disabled:function(T){return
T.disabled===true},checked:function(T){return
T.checked===true},selected:function(T){T.parentNode.selectedIndex;return
T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return
!T.firstChild},has:function(V,U,T){return
!!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"sub!
mit"===T.type},image:function(T){return"image"===T.type},reset!
:functio
n(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return
T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return
T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return
U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return
T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var
U=V[1],X=I.filters[U];if(X){return
X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var
Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return
true}}}},CHILD:function(T,W){var
Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return
false}}if(Z=="first"){return
true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}!
}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return
true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var
X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var
aa=T.nodeIndex-ac;if(V==0){return
aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return
U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return("
"+(U.className||U.getAttribute("class"))+"
").indexOf(T)>-1},ATTR:function(Y,W){var
V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return
T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?("
"+Z+"
").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var
T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var !
M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[!
O].sourc
e+/(?![^\[]*\])(?![^\(]*\))/.source)}var
E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return
U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var
U=W||[];if(H.call(X)==="[object
Array]"){Array.prototype.push.apply(U,X)}else{if(typeof
X.length==="number"){for(var
V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return
U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var
V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return
V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var
V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return
V}}else{if(document.createRange){G=function(W,U){var
V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var
X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplic!
ate=true}return X}}}}(function(){var
U=document.createElement("form"),V="script"+(new
Date).getTime();U.innerHTML="<input name='"+V+"'/>";var
T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof
Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return
W?W.id===X[1]||typeof
W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var
X=typeof
Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return
Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var
T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var
X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var
V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a
href='#'></a>";if(T.firstChild&&typeof
T.firstChild.getAttribute!=="undef!
ined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.h!
ref=func
tion(U){return
U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var
T=F,U=document.createElement("div");U.innerHTML="<p
class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return
E(X.querySelectorAll(Y),V)}catch(Z){}}return
T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var
T=document.createElement("div");T.innerHTML="<div class='test
e'></div><div
class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof
V.getElementsByClassName!=="undefined"&&!W){return
V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var
ab=U=="previousSibling"&&!ac;f!
or(var W=0,V=ad.length;W<V;W++){var
T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var
X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function
S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var
W=0,V=ad.length;W<V;W++){var
T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var
X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof
Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var
K=document.compareDocumentPosition?function(U,T){return
U.compareDocumentPosition(T)&16}:function(U,T){return
U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return
T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var
J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.!
match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}!
T=I.rela
tive[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return
F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return
T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return
T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return
o.grep(o.timers,function(U){return
T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return
F.matches(V,T)};o.dir=function(V,U){var
T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return
T};o.nth=function(X,T,V,W){T=T||1;var
U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return
X};o.sibling=function(V,U){var
T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return
T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var
G=H;H=this.proxy(G);!
H.data=K}var
E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return
typeof
o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var
O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var
L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var
G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof
H==="string"&&H.charAt(0)==".")){for(var I in
G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var
Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort(!
).join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}!
else{for
(var P in G[O]){if(N.test(G[O][P].type)){delete
G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in
G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete
G[O]}}})}for(F in G){break}if(!F){var
L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var
G=I.type||I;if(!E){I=typeof
I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return
g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var
J=o.data(H,"handle");if(J){J.apply(H,K)!
}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var
F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var
J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var
L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var
I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var
G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var
F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey
attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey
currentTarget data detail eventPhase fromElement handler keyCode metaK!
ey newValue originalTarget pageX pageY prevValue relatedNode r!
elatedTa
rget screenX screenY shiftKey srcElement target toElement view wheelDelta
which".split(" "),fix:function(H){if(H[h]){return H}var
F=H;H=o.Event(F);for(var
G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var
I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return
H},proxy:function(F,E){E=E||function(){return
F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},s!
pecial:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var
E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return
new
o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function
k(){return false}function u(){return
true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var
E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var
E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagatio!
nStopped:k,isImmediatePropagationStopped:k};var a=function(F){!
var E=F.
relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return
F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var
E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return
this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return
this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return
this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var
F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return
F.result}},toggle:function(G){var
E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}r!
eturn
this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return
E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return
this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return
this},live:function(G,F){var
E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return
this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return
this}});function c(H){var
E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var
K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return
o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return
G}function i(F,E){return["live",F,E.replace(/!
\./g,"`").replace(/
/g,"|")].join(".")}o.extend({isReady:false!
,readyLi
st:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var
x=false;function
B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,e!
rror").split(","),function(F,E){o.fn[E]=function(G){return
G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in
o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var
F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new
Date).getTime();K.style.display="none";K.innerHTML='
<link/><table></table><a href="/a"
style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var
H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.st!
yle.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:fal!
se,noClo
neEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete
l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var
L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var
w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof
G!=="string"){return this._load(G)}var I=G.indexOf("
");if(I>=0){var E=G.s!
lice(I,G.length);G=G.slice(0,I)}var
H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof
J==="object"){J=o.param(J);H="POST"}}}var
F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return
this},serialize:function(){return
o.param(this.serializeArray())},serializeArray:function(){return
this.map(function(){return
this.elements?o.makeArray(this.elements):this}).filter(function(){return
this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var
G=o(this).val();return
G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o!
.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend!
({get:fu
nction(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return
o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return
o.get(E,null,F,"script")},getJSON:function(E,F,G){return
o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return
o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return
l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new
XMLHttpRequest()},accepts:{xml:"application/xml,
text/xml",html:"text/html",script:"text/javascript,
application/javascript",json:"application/json,
text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var
W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof
M.data!=="string"){M.dat!
a=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete
l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var
E=e();var
U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var
Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.h!
ost)){var H=document.getElementsByTagName("head")[0];var T=doc!
ument.cr
eateElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var
O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return
g}var K=false;var
J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu,
01 Jan 1970 00:00:00
GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+",
*/*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return
false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var
N=function(X){if(J.readyState!
==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var
Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var
P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function
I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function
L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxSt!
op")}}return J},handleError:function(F,H,E,G){if(F.error){F.er!
ror(H,E,
G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return
!F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return
false},httpNotModified:function(G,E){try{var
H=G.getResponseHeader("Last-Modified");return
G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var
F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof
I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return
I},param:function(E){var G=[];function
H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var
F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunctio!
n(E[F])?E[F]():E[F])}}}return
G.join("&").replace(/%20/g,"+")}});var
m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function
t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return
G}o.fn.extend({show:function(J,L){if(J){return
this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var
E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var
G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+"
/>").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var
H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return
this}},hide:function(H,I){if(H){return
this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var
E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G]!
,"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.le!
ngth;G<F
;G++){this[G].style.display="none"}return
this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof
G==="boolean";return
o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var
H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return
this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return
this[E.queue===false?"each":"queue"](function(){var
K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M
in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return
K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var
R=new
o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var
Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cu!
r(true)||0;if(Q){var
N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return
true})},stop:function(F,E){var
G=o.timers;if(F){this.queue([])}this.each(function(){for(var
H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return
this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return
this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof
G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof
E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};retur!
n E},easing:{linear:function(G,H,E,F){return E+F*G},swing:func!
tion(G,H
,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return
this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return
E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var
E=this;function F(J){return
E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var
K=o.timers;for(var
J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n)!
;n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var
G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var
E=true;for(var F in
this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var
I in
this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.e!
lem)}return false}else{var J=G-this.startTime;this.state=J/thi!
s.option
s.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return
true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return
o.offset.bodyOffset(this[0])}var
G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this!
[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return
o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var
J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{to!
p:N,left:I}}}o.offset={initialize:function(){if(this.initializ!
ed){retu
rn}var
L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div
style="position:absolute;top:0;left:0;margin:0;border:5px solid
#000;padding:0;width:1px;height:1px;"><div></div></div><table
style="position:absolute;top:0;left:0;margin:0;border:5px solid
#000;padding:0;width:1px;height:1px;" cellpadding="0"
cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E
in
M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:functi!
on(E){o.offset.initialized||o.offset.initialize();var
G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var
I=0,H=0,F;if(this[0]){var
G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return
F},offsetParent:function(){var
E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return
o(E)}});o.each(["Left","Top"],function(F,E){var
G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return
H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||th!
is[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxMode!
l&&docum
ent.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var
E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return
this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return
this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var
J=G.toLowerCase();o.fn[J]=function(K){return
this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof
K==="string"?K:K+"px")}})})();
\ No newline at end of file
Added: branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/page.xhtml
===================================================================
--- branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/page.xhtml
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/page.xhtml 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,53 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html
xmlns="http://www.w3.org/1999/xhtml"
+
xmlns:ui="http://java.sun.com/jsf/facelets"
+
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:f="http://java.sun.com/jsf/core"
+
xmlns:a4j="http://richfaces.org/a4j"
+
xmlns:rich="http://richfaces.org/rich"
+
xmlns:c="http://java.sun.com/jstl/core">
+
+<head>
+ <a4j:loadScript src="resource:///org.ajax4jsf.javascript.AjaxScript" />
+ <a4j:loadScript src="/jquery.js" />
+ <a4j:loadScript src="/ui.core.js" />
+ <a4j:loadScript src="/ui.dragable.js" />
+ <a4j:loadScript src="/ui.resizeable.js" />
+ <a4j:loadScript src="/fullcalendar.js" />
+ <a4j:loadScript src="/richfaces.fullcalendar.js" />
+
+ <style type='text/css'>
+ body {
+ margin-top: 40px;
+ text-align: center;
+ font-size: 14px;
+ font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
+ }
+
+ .rich-fullc-loading {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ }
+
+ .rich-fullc {
+ width: 900px;
+ margin: 0 auto;
+ }
+ </style>
+</head>
+
+<body>
+
+ <h:form>
+ <ui:fragment binding="#{componentBean.component}">
+ <f:facet name="loading">
+ wait: loading...
+ </f:facet>
+ </ui:fragment>
+ </h:form>
+
+</body>
+
+
+</html>
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/richfaces.fullcalendar.js
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/richfaces.fullcalendar.js
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/richfaces.fullcalendar.js 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,60 @@
+window.RichFaces = window.RichFaces || {};
+
+window.RichFaces.FullCalendar = (function() {
+ var formatDateParam = function(date) {
+ return Math.round(date.getTime() / 1000);
+ }
+
+ return function(id, ajaxFunc) {
+ this.id = id;
+ this.ajaxFunc = ajaxFunc;
+ var elt = document.getElementById(id);
+ if (!elt) {
+ //TODO handle missing element
+ return ;
+ }
+
+ var _this = this;
+ var fillCalendarFunction = function(startDate, endDate, callback) {
+ var event = {};
+ _this.ajaxFunc({} /* stub event */,
+ formatDateParam(startDate),
+ formatDateParam(endDate),
+ function(request, event, data) {
+ callback(data);
+ }
+ );
+ };
+
+ jQuery(document).ready(function() {
+
+ jQuery(elt).fullCalendar({
+
+ editable: true,
+
+ events: fillCalendarFunction,
+
+ eventDrop: function(event, delta) {
+ alert(event.title + ' was moved ' + delta + ' days\n' +
+ '(should probably update your database)');
+ },
+
+ loading: function(bool) {
+ var loadingElt = document.getElementById(id + ":loading");
+ if (loadingElt) {
+ if (bool) {
+ jQuery(loadingElt).show();
+ } else {
+ jQuery(loadingElt).hide();
+ }
+ }
+ }
+
+ });
+
+ });
+ };
+
+}());
+
+
Added: branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.core.js
===================================================================
--- branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.core.js
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.core.js 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,519 @@
+/*
+ * jQuery UI 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (
http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ *
http://docs.jquery.com/UI
+ */
+;jQuery.ui || (function($) {
+
+var _remove = $.fn.remove,
+ isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);
+
+//Helper functions and ui object
+$.ui = {
+ version: "1.7.2",
+
+ // $.ui.plugin is deprecated. Use the proxy pattern instead.
+ plugin: {
+ add: function(module, option, set) {
+ var proto = $.ui[module].prototype;
+ for(var i in set) {
+ proto.plugins[i] = proto.plugins[i] || [];
+ proto.plugins[i].push([option, set[i]]);
+ }
+ },
+ call: function(instance, name, args) {
+ var set = instance.plugins[name];
+ if(!set || !instance.element[0].parentNode) { return; }
+
+ for (var i = 0; i < set.length; i++) {
+ if (instance.options[set[i][0]]) {
+ set[i][1].apply(instance.element, args);
+ }
+ }
+ }
+ },
+
+ contains: function(a, b) {
+ return document.compareDocumentPosition
+ ? a.compareDocumentPosition(b) & 16
+ : a !== b && a.contains(b);
+ },
+
+ hasScroll: function(el, a) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to
hide it
+ if ($(el).css('overflow') == 'hidden') { return false; }
+
+ var scroll = (a && a == 'left') ? 'scrollLeft' :
'scrollTop',
+ has = false;
+
+ if (el[scroll] > 0) { return true; }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[scroll] = 1;
+ has = (el[scroll] > 0);
+ el[scroll] = 0;
+ return has;
+ },
+
+ isOverAxis: function(x, reference, size) {
+ //Determines when x coordinate is over "b" element axis
+ return (x > reference) && (x < (reference + size));
+ },
+
+ isOver: function(y, x, top, left, height, width) {
+ //Determines when x, y coordinates is over "b" element
+ return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
+ },
+
+ keyCode: {
+ 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
+ }
+};
+
+// WAI-ARIA normalization
+if (isFF2) {
+ var attr = $.attr,
+ removeAttr = $.fn.removeAttr,
+ ariaNS = "http://www.w3.org/2005/07/aaa",
+ ariaState = /^aria-/,
+ ariaRole = /^wairole:/;
+
+ $.attr = function(elem, name, value) {
+ var set = value !== undefined;
+
+ return (name == 'role'
+ ? (set
+ ? attr.call(this, elem, name, "wairole:" + value)
+ : (attr.apply(this, arguments) || "").replace(ariaRole, ""))
+ : (ariaState.test(name)
+ ? (set
+ ? elem.setAttributeNS(ariaNS,
+ name.replace(ariaState, "aaa:"), value)
+ : attr.call(this, elem, name.replace(ariaState, "aaa:")))
+ : attr.apply(this, arguments)));
+ };
+
+ $.fn.removeAttr = function(name) {
+ return (ariaState.test(name)
+ ? this.each(function() {
+ this.removeAttributeNS(ariaNS, name.replace(ariaState, ""));
+ }) : removeAttr.call(this, name));
+ };
+}
+
+//jQuery plugins
+$.fn.extend({
+ remove: function() {
+ // Safari has a native remove event which actually removes DOM elements,
+ // so we have to use triggerHandler instead of trigger (#3037).
+ $("*", this).add(this).each(function() {
+ $(this).triggerHandler("remove");
+ });
+ return _remove.apply(this, arguments );
+ },
+
+ enableSelection: function() {
+ return this
+ .attr('unselectable', 'off')
+ .css('MozUserSelect', '')
+ .unbind('selectstart.ui');
+ },
+
+ disableSelection: function() {
+ return this
+ .attr('unselectable', 'on')
+ .css('MozUserSelect', 'none')
+ .bind('selectstart.ui', function() { return false; });
+ },
+
+ scrollParent: function() {
+ var scrollParent;
+ if(($.browser.msie && (/(static|relative)/).test(this.css('position')))
|| (/absolute/).test(this.css('position'))) {
+ scrollParent = this.parents().filter(function() {
+ return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1))
&&
(/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+ }).eq(0);
+ } else {
+ scrollParent = this.parents().filter(function() {
+ return
(/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+ }).eq(0);
+ }
+
+ return (/fixed/).test(this.css('position')) || !scrollParent.length ?
$(document) : scrollParent;
+ }
+});
+
+
+//Additional selectors
+$.extend($.expr[':'], {
+ data: function(elem, i, match) {
+ return !!$.data(elem, match[3]);
+ },
+
+ focusable: function(element) {
+ var nodeName = element.nodeName.toLowerCase(),
+ tabIndex = $.attr(element, 'tabindex');
+ return (/input|select|textarea|button|object/.test(nodeName)
+ ? !element.disabled
+ : 'a' == nodeName || 'area' == nodeName
+ ? element.href || !isNaN(tabIndex)
+ : !isNaN(tabIndex))
+ // the element and all of its ancestors must be visible
+ // the browser may report that the area is hidden
+ && !$(element)['area' == nodeName ? 'parents' :
'closest'](':hidden').length;
+ },
+
+ tabbable: function(element) {
+ var tabIndex = $.attr(element, 'tabindex');
+ return (isNaN(tabIndex) || tabIndex >= 0) &&
$(element).is(':focusable');
+ }
+});
+
+
+// $.widget is a factory to create jQuery plugins
+// taking some boilerplate code out of the plugin code
+function getter(namespace, plugin, method, args) {
+ function getMethods(type) {
+ var methods = $[namespace][plugin][type] || [];
+ return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
+ }
+
+ var methods = getMethods('getter');
+ if (args.length == 1 && typeof args[0] == 'string') {
+ methods = methods.concat(getMethods('getterSetter'));
+ }
+ return ($.inArray(method, methods) != -1);
+}
+
+$.widget = function(name, prototype) {
+ var namespace = name.split(".")[0];
+ name = name.split(".")[1];
+
+ // create plugin method
+ $.fn[name] = function(options) {
+ var isMethodCall = (typeof options == 'string'),
+ args = Array.prototype.slice.call(arguments, 1);
+
+ // prevent calls to internal methods
+ if (isMethodCall && options.substring(0, 1) == '_') {
+ return this;
+ }
+
+ // handle getter methods
+ if (isMethodCall && getter(namespace, name, options, args)) {
+ var instance = $.data(this[0], name);
+ return (instance ? instance[options].apply(instance, args)
+ : undefined);
+ }
+
+ // handle initialization and non-getter methods
+ return this.each(function() {
+ var instance = $.data(this, name);
+
+ // constructor
+ (!instance && !isMethodCall &&
+ $.data(this, name, new $[namespace][name](this, options))._init());
+
+ // method call
+ (instance && isMethodCall && $.isFunction(instance[options])
&&
+ instance[options].apply(instance, args));
+ });
+ };
+
+ // create widget constructor
+ $[namespace] = $[namespace] || {};
+ $[namespace][name] = function(element, options) {
+ var self = this;
+
+ this.namespace = namespace;
+ this.widgetName = name;
+ this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
+ this.widgetBaseClass = namespace + '-' + name;
+
+ this.options = $.extend({},
+ $.widget.defaults,
+ $[namespace][name].defaults,
+ $.metadata && $.metadata.get(element)[name],
+ options);
+
+ this.element = $(element)
+ .bind('setData.' + name, function(event, key, value) {
+ if (event.target == element) {
+ return self._setData(key, value);
+ }
+ })
+ .bind('getData.' + name, function(event, key) {
+ if (event.target == element) {
+ return self._getData(key);
+ }
+ })
+ .bind('remove', function() {
+ return self.destroy();
+ });
+ };
+
+ // add widget prototype
+ $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
+
+ // TODO: merge getter and getterSetter properties from widget prototype
+ // and plugin prototype
+ $[namespace][name].getterSetter = 'option';
+};
+
+$.widget.prototype = {
+ _init: function() {},
+ destroy: function() {
+ this.element.removeData(this.widgetName)
+ .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace
+ '-state-disabled')
+ .removeAttr('aria-disabled');
+ },
+
+ option: function(key, value) {
+ var options = key,
+ self = this;
+
+ if (typeof key == "string") {
+ if (value === undefined) {
+ return this._getData(key);
+ }
+ options = {};
+ options[key] = value;
+ }
+
+ $.each(options, function(key, value) {
+ self._setData(key, value);
+ });
+ },
+ _getData: function(key) {
+ return this.options[key];
+ },
+ _setData: function(key, value) {
+ this.options[key] = value;
+
+ if (key == 'disabled') {
+ this.element
+ [value ? 'addClass' : 'removeClass'](
+ this.widgetBaseClass + '-disabled' + ' ' +
+ this.namespace + '-state-disabled')
+ .attr("aria-disabled", value);
+ }
+ },
+
+ enable: function() {
+ this._setData('disabled', false);
+ },
+ disable: function() {
+ this._setData('disabled', true);
+ },
+
+ _trigger: function(type, event, data) {
+ var callback = this.options[type],
+ eventName = (type == this.widgetEventPrefix
+ ? type : this.widgetEventPrefix + type);
+
+ event = $.Event(event);
+ event.type = eventName;
+
+ // copy original event properties over to the new event
+ // this would happen if we could call $.event.fix instead of $.Event
+ // but we don't have a way to force an event to be fixed multiple times
+ if (event.originalEvent) {
+ for (var i = $.event.props.length, prop; i;) {
+ prop = $.event.props[--i];
+ event[prop] = event.originalEvent[prop];
+ }
+ }
+
+ this.element.trigger(event, data);
+
+ return !($.isFunction(callback) && callback.call(this.element[0], event, data)
=== false
+ || event.isDefaultPrevented());
+ }
+};
+
+$.widget.defaults = {
+ disabled: false
+};
+
+
+/** Mouse Interaction Plugin **/
+
+$.ui.mouse = {
+ _mouseInit: function() {
+ var self = this;
+
+ this.element
+ .bind('mousedown.'+this.widgetName, function(event) {
+ return self._mouseDown(event);
+ })
+ .bind('click.'+this.widgetName, function(event) {
+ if(self._preventClickEvent) {
+ self._preventClickEvent = false;
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ // Prevent text selection in IE
+ if ($.browser.msie) {
+ this._mouseUnselectable = this.element.attr('unselectable');
+ this.element.attr('unselectable', 'on');
+ }
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind('.'+this.widgetName);
+
+ // Restore text selection in IE
+ ($.browser.msie
+ && this.element.attr('unselectable', this._mouseUnselectable));
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ // TODO: figure out why we have to use originalEvent
+ event.originalEvent = event.originalEvent || {};
+ if (event.originalEvent.mouseHandled) { return; }
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var self = this,
+ btnIsLeft = (event.which == 1),
+ elIsCancel = (typeof this.options.cancel == "string" ?
$(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ self.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return self._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return self._mouseUp(event);
+ };
+ $(document)
+ .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+ // preventDefault() is used to prevent the selection of text here -
+ // however, in Safari, this causes select boxes not to be selectable
+ // anymore, so this fix is needed
+ ($.browser.safari || event.preventDefault());
+
+ event.originalEvent.mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.browser.msie && !event.button) {
+ return this._mouseUp(event);
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ $(document)
+ .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+ this._preventClickEvent = (event.target == this._mouseDownEvent.target);
+ this._mouseStop(event);
+ }
+
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(event) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overriden by extending plugin
+ _mouseStart: function(event) {},
+ _mouseDrag: function(event) {},
+ _mouseStop: function(event) {},
+ _mouseCapture: function(event) { return true; }
+};
+
+$.ui.mouse.defaults = {
+ cancel: null,
+ distance: 1,
+ delay: 0
+};
+
+})(jQuery);
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.draggable.js
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.draggable.js
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.draggable.js 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,766 @@
+/*
+ * jQuery UI Draggable 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (
http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ *
http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * ui.core.js
+ */
+(function($) {
+
+$.widget("ui.draggable", $.extend({}, $.ui.mouse, {
+
+ _init: function() {
+
+ if (this.options.helper == 'original' &&
!(/^(?:r|a|f)/).test(this.element.css("position")))
+ this.element[0].style.position = 'relative';
+
+ (this.options.addClasses && this.element.addClass("ui-draggable"));
+ (this.options.disabled &&
this.element.addClass("ui-draggable-disabled"));
+
+ this._mouseInit();
+
+ },
+
+ destroy: function() {
+ if(!this.element.data('draggable')) return;
+ this.element
+ .removeData("draggable")
+ .unbind(".draggable")
+ .removeClass("ui-draggable"
+ + " ui-draggable-dragging"
+ + " ui-draggable-disabled");
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function(event) {
+
+ var o = this.options;
+
+ if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
+ return false;
+
+ //Quit if we're not on a valid handle
+ this.handle = this._getHandle(event);
+ if (!this.handle)
+ return false;
+
+ return true;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options;
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ //If ddmanager is used for droppables, set the global draggable
+ if($.ui.ddmanager)
+ $.ui.ddmanager.current = this;
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Store the helper's css position
+ this.cssPosition = this.helper.css("position");
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.element.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus
the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+ if(o.cursorAt)
+ this._adjustOffsetFromHelper(o.cursorAt);
+
+ //Set a containment if given in the options
+ if(o.containment)
+ this._setContainment();
+
+ //Call plugins and callbacks
+ this._trigger("start", event);
+
+ //Recache the helper size
+ this._cacheHelperProportions();
+
+ //Prepare the droppable offsets
+ if ($.ui.ddmanager && !o.dropBehaviour)
+ $.ui.ddmanager.prepareOffsets(this, event);
+
+ this.helper.addClass("ui-draggable-dragging");
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to
be visible before getting its correct position
+ return true;
+ },
+
+ _mouseDrag: function(event, noPropagation) {
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Call plugins and callbacks and use the resulting position if something is returned
+ if (!noPropagation) {
+ var ui = this._uiHash();
+ this._trigger('drag', event, ui);
+ this.position = ui.position;
+ }
+
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left
= this.position.left+'px';
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top =
this.position.top+'px';
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ //If we are using droppables, inform the manager about the drop
+ var dropped = false;
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
+ dropped = $.ui.ddmanager.drop(this, event);
+
+ //if a drop comes from outside (a sortable)
+ if(this.dropped) {
+ dropped = this.dropped;
+ this.dropped = false;
+ }
+
+ if((this.options.revert == "invalid" && !dropped) ||
(this.options.revert == "valid" && dropped) || this.options.revert ===
true || ($.isFunction(this.options.revert) &&
this.options.revert.call(this.element, dropped))) {
+ var self = this;
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration,
10), function() {
+ self._trigger("stop", event);
+ self._clear();
+ });
+ } else {
+ this._trigger("stop", event);
+ this._clear();
+ }
+
+ return false;
+ },
+
+ _getHandle: function(event) {
+
+ var handle = !this.options.handle || !$(this.options.handle, this.element).length ?
true : false;
+ $(this.options.handle, this.element)
+ .find("*")
+ .andSelf()
+ .each(function() {
+ if(this == event.target) handle = true;
+ });
+
+ return handle;
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options;
+ var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) :
(o.helper == 'clone' ? this.element.clone() : this.element);
+
+ if(!helper.parents('body').length)
+ helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode :
o.appendTo));
+
+ if(helper[0] != this.element[0] &&
!(/(fixed|absolute)/).test(helper.css("position")))
+ helper.css("position", "absolute");
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left;
+ if(obj.right != undefined) this.offset.click.left = this.helperProportions.width -
obj.right + this.margins.left;
+ if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top;
+ if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height -
obj.bottom + this.margins.top;
+ },
+
+ _getParentOffset: function() {
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since
the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based
on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent
isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent,
and never recalculated upon drag
+ if(this.cssPosition == 'absolute' && this.scrollParent[0] != document
&& $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ if((this.offsetParent[0] == document.body) //This needs to be actually done for all
browsers, since pageX/pageY includes this information
+ || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase()
== 'html' && $.browser.msie)) //Ugly IE fix
+ po = { top: 0, left: 0 };
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) ||
0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition == "relative") {
+ var p = this.element.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) +
this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) +
this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
+ top: (parseInt(this.element.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var o = this.options;
+ if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
+ if(o.containment == 'document' || o.containment == 'window')
this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ $(o.containment == 'document' ? document : window).width() -
this.helperProportions.width - this.margins.left,
+ ($(o.containment == 'document' ? document : window).height() ||
document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+
+ if(!(/^(document|window|parent)$/).test(o.containment) &&
o.containment.constructor != Array) {
+ var ce = $(o.containment)[0]; if(!ce) return;
+ var co = $(o.containment).offset();
+ var over = ($(ce).css("overflow") != 'hidden');
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) +
(parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) +
(parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) -
(parseInt($(ce).css("borderLeftWidth"),10) || 0) -
(parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width -
this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) -
(parseInt($(ce).css("borderTopWidth"),10) || 0) -
(parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height -
this.margins.top
+ ];
+ } else if(o.containment.constructor == Array) {
+ this.containment = o.containment;
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) pos = this.position;
+ var mod = d == "absolute" ? 1 : -1;
+ var o = this.options, scroll = this.cssPosition == 'absolute' &&
!(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0],
this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode =
(/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top // The absolute mouse position
+ + this.offset.relative.top * mod // Only for relative positioned nodes:
Relative offset from element to offset parent
+ + this.offset.parent.top * mod // The offsetParent's offset without
borders (offset + border)
+ - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (
this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode
? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left // The absolute mouse position
+ + this.offset.relative.left * mod // Only for relative positioned nodes:
Relative offset from element to offset parent
+ + this.offset.parent.left * mod // The offsetParent's offset without
borders (offset + border)
+ - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (
this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ?
0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var o = this.options, scroll = this.cssPosition == 'absolute' &&
!(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0],
this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode =
(/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document
&& this.scrollParent[0] != this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ var pageX = event.pageX;
+ var pageY = event.pageY;
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for
options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) pageX =
this.containment[0] + this.offset.click.left;
+ if(event.pageY - this.offset.click.top < this.containment[1]) pageY =
this.containment[1] + this.offset.click.top;
+ if(event.pageX - this.offset.click.left > this.containment[2]) pageX =
this.containment[2] + this.offset.click.left;
+ if(event.pageY - this.offset.click.top > this.containment[3]) pageY =
this.containment[3] + this.offset.click.top;
+ }
+
+ if(o.grid) {
+ var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) *
o.grid[1];
+ pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] ||
top - this.offset.click.top > this.containment[3]) ? top : (!(top -
this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) :
top;
+
+ var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0])
* o.grid[0];
+ pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0]
|| left - this.offset.click.left > this.containment[2]) ? left : (!(left -
this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) :
left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY // The absolute mouse position
+ - this.offset.click.top // Click offset (relative to the element)
+ - this.offset.relative.top // Only for relative positioned nodes: Relative
offset from element to offset parent
+ - this.offset.parent.top // The offsetParent's offset without borders
(offset + border)
+ + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (
this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode
? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX // The absolute mouse position
+ - this.offset.click.left // Click offset (relative to the element)
+ - this.offset.relative.left // Only for relative positioned nodes:
Relative offset from element to offset parent
+ - this.offset.parent.left // The offsetParent's offset without borders
(offset + border)
+ + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : (
this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ?
0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _clear: function() {
+ this.helper.removeClass("ui-draggable-dragging");
+ if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval)
this.helper.remove();
+ //if($.ui.ddmanager) $.ui.ddmanager.current = null;
+ this.helper = null;
+ this.cancelHelperRemoval = false;
+ },
+
+ // From now on bulk stuff - mainly helpers
+
+ _trigger: function(type, event, ui) {
+ ui = ui || this._uiHash();
+ $.ui.plugin.call(this, type, [event, ui]);
+ if(type == "drag") this.positionAbs =
this._convertPositionTo("absolute"); //The absolute position has to be
recalculated after plugins
+ return $.widget.prototype._trigger.call(this, type, event, ui);
+ },
+
+ plugins: {},
+
+ _uiHash: function(event) {
+ return {
+ helper: this.helper,
+ position: this.position,
+ absolutePosition: this.positionAbs, //deprecated
+ offset: this.positionAbs
+ };
+ }
+
+}));
+
+$.extend($.ui.draggable, {
+ version: "1.7.2",
+ eventPrefix: "drag",
+ defaults: {
+ addClasses: true,
+ appendTo: "parent",
+ axis: false,
+ cancel: ":input,option",
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ delay: 0,
+ distance: 1,
+ grid: false,
+ handle: false,
+ helper: "original",
+ iframeFix: false,
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scope: "default",
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false
+ }
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(event, ui) {
+
+ var inst = $(this).data("draggable"), o = inst.options,
+ uiSortable = $.extend({}, ui, { item: inst.element });
+ inst.sortables = [];
+ $(o.connectToSortable).each(function() {
+ var sortable = $.data(this, 'sortable');
+ if (sortable && !sortable.options.disabled) {
+ inst.sortables.push({
+ instance: sortable,
+ shouldRevert: sortable.options.revert
+ });
+ sortable._refreshItems(); //Do a one-time refresh at start to refresh the
containerCache
+ sortable._trigger("activate", event, uiSortable);
+ }
+ });
+
+ },
+ stop: function(event, ui) {
+
+ //If we are still over the sortable, we fake the stop event of the sortable, but also
remove helper
+ var inst = $(this).data("draggable"),
+ uiSortable = $.extend({}, ui, { item: inst.element });
+
+ $.each(inst.sortables, function() {
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable
instance
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so
sortable plugins like revert still work)
+
+ //The sortable revert is supported, and we have to set a temporary dropped variable
on the draggable to support revert: 'valid/invalid'
+ if(this.shouldRevert) this.instance.options.revert = true;
+
+ //Trigger the stop of the sortable
+ this.instance._mouseStop(event);
+
+ this.instance.options.helper = this.instance.options._helper;
+
+ //If the helper has been the original item, restore properties in the sortable
+ if(inst.options.helper == 'original')
+ this.instance.currentItem.css({ top: 'auto', left: 'auto' });
+
+ } else {
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable
instance
+ this.instance._trigger("deactivate", event, uiSortable);
+ }
+
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("draggable"), self = this;
+
+ var checkPos = function(o) {
+ var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
+ var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
+ var itemHeight = o.height, itemWidth = o.width;
+ var itemTop = o.top, itemLeft = o.left;
+
+ return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft,
itemHeight, itemWidth);
+ };
+
+ $.each(inst.sortables, function(i) {
+
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
+
+ //If it intersects, we use a little isOver variable and set it once, so our move-in
stuff gets fired only once
+ if(!this.instance.isOver) {
+
+ this.instance.isOver = 1;
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as
inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event,
and our own helper (so it doesn't create a new one)
+ this.instance.currentItem =
$(self).clone().appendTo(this.instance.element).data("sortable-item", true);
+ this.instance.options._helper = this.instance.options.helper; //Store helper option
to later restore it
+ this.instance.options.helper = function() { return ui.helper[0]; };
+
+ event.target = this.instance.currentItem[0];
+ this.instance._mouseCapture(event, true);
+ this.instance._mouseStart(event, true, true);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple
of variables to reflect the changes
+ this.instance.offset.click.top = inst.offset.click.top;
+ this.instance.offset.click.left = inst.offset.click.left;
+ this.instance.offset.parent.left -= inst.offset.parent.left -
this.instance.offset.parent.left;
+ this.instance.offset.parent.top -= inst.offset.parent.top -
this.instance.offset.parent.top;
+
+ inst._trigger("toSortable", event);
+ inst.dropped = this.instance.element; //draggable revert needs that
+ //hack so receive/update callbacks work (mostly)
+ inst.currentItem = inst.element;
+ this.instance.fromOutside = inst;
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable
on every draggable drag, when it intersects with the sortable
+ if(this.instance.currentItem) this.instance._mouseDrag(event);
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the
helper by using cancelHelperRemoval
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+ this.instance.cancelHelperRemoval = true;
+
+ //Prevent reverting on this forced stop
+ this.instance.options.revert = false;
+
+ // The out event needs to be triggered independently
+ this.instance._trigger('out', event, this.instance._uiHash(this.instance));
+
+ this.instance._mouseStop(event, true);
+ this.instance.options.helper = this.instance.options._helper;
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder,
and animate the helper back to it's original size
+ this.instance.currentItem.remove();
+ if(this.instance.placeholder) this.instance.placeholder.remove();
+
+ inst._trigger("fromSortable", event);
+ inst.dropped = false; //draggable revert needs that
+ }
+
+ };
+
+ });
+
+ }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+ start: function(event, ui) {
+ var t = $('body'), o = $(this).data('draggable').options;
+ if (t.css("cursor")) o._cursor = t.css("cursor");
+ t.css("cursor", o.cursor);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data('draggable').options;
+ if (o._cursor) $('body').css("cursor", o._cursor);
+ }
+});
+
+$.ui.plugin.add("draggable", "iframeFix", {
+ start: function(event, ui) {
+ var o = $(this).data('draggable').options;
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+ $('<div class="ui-draggable-iframeFix" style="background:
#fff;"></div>')
+ .css({
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+ position: "absolute", opacity: "0.001", zIndex: 1000
+ })
+ .css($(this).offset())
+ .appendTo("body");
+ });
+ },
+ stop: function(event, ui) {
+ $("div.ui-draggable-iframeFix").each(function() {
this.parentNode.removeChild(this); }); //Remove frame helpers
+ }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data('draggable').options;
+ if(t.css("opacity")) o._opacity = t.css("opacity");
+ t.css('opacity', o.opacity);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data('draggable').options;
+ if(o._opacity) $(ui.helper).css('opacity', o._opacity);
+ }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+ start: function(event, ui) {
+ var i = $(this).data("draggable");
+ if(i.scrollParent[0] != document && i.scrollParent[0].tagName !=
'HTML') i.overflowOffset = i.scrollParent.offset();
+ },
+ drag: function(event, ui) {
+
+ var i = $(this).data("draggable"), o = i.options, scrolled = false;
+
+ if(i.scrollParent[0] != document && i.scrollParent[0].tagName !=
'HTML') {
+
+ if(!o.axis || o.axis != 'x') {
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY <
o.scrollSensitivity)
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop +
o.scrollSpeed;
+ else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop -
o.scrollSpeed;
+ }
+
+ if(!o.axis || o.axis != 'y') {
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX <
o.scrollSensitivity)
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft +
o.scrollSpeed;
+ else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft -
o.scrollSpeed;
+ }
+
+ } else {
+
+ if(!o.axis || o.axis != 'x') {
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) <
o.scrollSensitivity)
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(!o.axis || o.axis != 'y') {
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) <
o.scrollSensitivity)
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+ $.ui.ddmanager.prepareOffsets(i, event);
+
+ }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+ start: function(event, ui) {
+
+ var i = $(this).data("draggable"), o = i.options;
+ i.snapElements = [];
+
+ $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) :
o.snap).each(function() {
+ var $t = $(this); var $o = $t.offset();
+ if(this != i.element[0]) i.snapElements.push({
+ item: this,
+ width: $t.outerWidth(), height: $t.outerHeight(),
+ top: $o.top, left: $o.left
+ });
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("draggable"), o = inst.options;
+ var d = o.snapTolerance;
+
+ var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+ for (var i = inst.snapElements.length - 1; i >= 0; i--){
+
+ var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
+ t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
+
+ //Yes, I know, this is insane ;)
+ if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 <
b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d)
|| (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) ||
(l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
+ if(inst.snapElements[i].snapping) (inst.options.snap.release &&
inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem:
inst.snapElements[i].item })));
+ inst.snapElements[i].snapping = false;
+ continue;
+ }
+
+ if(o.snapMode != 'inner') {
+ var ts = Math.abs(t - y2) <= d;
+ var bs = Math.abs(b - y1) <= d;
+ var ls = Math.abs(l - x2) <= d;
+ var rs = Math.abs(r - x1) <= d;
+ if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t -
inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b,
left: 0 }).top - inst.margins.top;
+ if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0,
left: l - inst.helperProportions.width }).left - inst.margins.left;
+ if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0,
left: r }).left - inst.margins.left;
+ }
+
+ var first = (ts || bs || ls || rs);
+
+ if(o.snapMode != 'outer') {
+ var ts = Math.abs(t - y1) <= d;
+ var bs = Math.abs(b - y2) <= d;
+ var ls = Math.abs(l - x1) <= d;
+ var rs = Math.abs(r - x2) <= d;
+ if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t,
left: 0 }).top - inst.margins.top;
+ if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b -
inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0,
left: l }).left - inst.margins.left;
+ if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0,
left: r - inst.helperProportions.width }).left - inst.margins.left;
+ }
+
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event,
$.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+ };
+
+ }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+ start: function(event, ui) {
+
+ var o = $(this).data("draggable").options;
+
+ var group = $.makeArray($(o.stack.group)).sort(function(a,b) {
+ return (parseInt($(a).css("zIndex"),10) || o.stack.min) -
(parseInt($(b).css("zIndex"),10) || o.stack.min);
+ });
+
+ $(group).each(function(i) {
+ this.style.zIndex = o.stack.min + i;
+ });
+
+ this[0].style.zIndex = o.stack.min + group.length;
+
+ }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("draggable").options;
+ if(t.css("zIndex")) o._zIndex = t.css("zIndex");
+ t.css('zIndex', o.zIndex);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("draggable").options;
+ if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
+ }
+});
+
+})(jQuery);
Added:
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.resizable.js
===================================================================
---
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.resizable.js
(rev 0)
+++
branches/community/3.3.X/sandbox/samples/full-calendar/src/main/webapp/ui.resizable.js 2010-04-29
01:40:35 UTC (rev 16835)
@@ -0,0 +1,800 @@
+/*
+ * jQuery UI Resizable 1.7.2
+ *
+ * Copyright (c) 2009 AUTHORS.txt (
http://jqueryui.com/about)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ *
http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ * ui.core.js
+ */
+(function($) {
+
+$.widget("ui.resizable", $.extend({}, $.ui.mouse, {
+
+ _init: function() {
+
+ var self = this, o = this.options;
+ this.element.addClass("ui-resizable");
+
+ $.extend(this, {
+ _aspectRatio: !!(o.aspectRatio),
+ aspectRatio: o.aspectRatio,
+ originalElement: this.element,
+ _proportionallyResizeElements: [],
+ _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper'
: null
+ });
+
+ //Wrap the element if it cannot hold child nodes
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+ //Opera fix for relative positioning
+ if (/relative/.test(this.element.css('position')) && $.browser.opera)
+ this.element.css({ position: 'relative', top: 'auto', left:
'auto' });
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ this.element.wrap(
+ $('<div class="ui-wrapper" style="overflow:
hidden;"></div>').css({
+ position: this.element.css('position'),
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight(),
+ top: this.element.css('top'),
+ left: this.element.css('left')
+ })
+ );
+
+ //Overwrite the original this.element
+ this.element = this.element.parent().data(
+ "resizable", this.element.data('resizable')
+ );
+
+ this.elementIsWrapper = true;
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"),
marginTop: this.originalElement.css("marginTop"), marginRight:
this.originalElement.css("marginRight"), marginBottom:
this.originalElement.css("marginBottom") });
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom:
0});
+
+ //Prevent Safari textarea resize
+ this.originalResizeStyle = this.originalElement.css('resize');
+ this.originalElement.css('resize', 'none');
+
+ //Push the actual element to our proportionallyResize internal array
+ this._proportionallyResizeElements.push(this.originalElement.css({ position:
'static', zoom: 1, display: 'block' }));
+
+ // avoid IE jump (hard set the margin)
+ this.originalElement.css({ margin: this.originalElement.css('margin') });
+
+ // fix handlers offset
+ this._proportionallyResize();
+
+ }
+
+ this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ?
"e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s:
'.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se',
sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw:
'.ui-resizable-nw' });
+ if(this.handles.constructor == String) {
+
+ if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
+ var n = this.handles.split(","); this.handles = {};
+
+ for(var i = 0; i < n.length; i++) {
+
+ var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
+ var axis = $('<div class="ui-resizable-handle ' + hname +
'"></div>');
+
+ // increase zIndex of sw, se, ne, nw axis
+ //TODO : this modifies original option
+ if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });
+
+ //TODO : What's going on here?
+ if ('se' == handle) {
+ axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
+ };
+
+ //Insert into internal handles object and append to element
+ this.handles[handle] = '.ui-resizable-'+handle;
+ this.element.append(axis);
+ }
+
+ }
+
+ this._renderAxis = function(target) {
+
+ target = target || this.element;
+
+ for(var i in this.handles) {
+
+ if(this.handles[i].constructor == String)
+ this.handles[i] = $(this.handles[i], this.element).show();
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs,
scrolls)
+ if (this.elementIsWrapper &&
this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+ var axis = $(this.handles[i], this.element), padWrapper = 0;
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ var padPos = [ 'padding',
+ /ne|nw|n/.test(i) ? 'Top' :
+ /se|sw|s/.test(i) ? 'Bottom' :
+ /^e$/.test(i) ? 'Right' : 'Left' ].join("");
+
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+
+ }
+
+ //TODO: What's that good for? There's not anything to be executed left
+ if(!$(this.handles[i]).length)
+ continue;
+
+ }
+ };
+
+ //TODO: make renderAxis a prototype function
+ this._renderAxis(this.element);
+
+ this._handles = $('.ui-resizable-handle', this.element)
+ .disableSelection();
+
+ //Matching axis name
+ this._handles.mouseover(function() {
+ if (!self.resizing) {
+ if (this.className)
+ var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ //Axis, default = se
+ self.axis = axis && axis[1] ? axis[1] : 'se';
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autoHide) {
+ this._handles.hide();
+ $(this.element)
+ .addClass("ui-resizable-autohide")
+ .hover(function() {
+ $(this).removeClass("ui-resizable-autohide");
+ self._handles.show();
+ },
+ function(){
+ if (!self.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ self._handles.hide();
+ }
+ });
+ }
+
+ //Initialize the mouse interaction
+ this._mouseInit();
+
+ },
+
+ destroy: function() {
+
+ this._mouseDestroy();
+
+ var _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled
ui-resizable-resizing")
+ .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
+ };
+
+ //TODO: Unwrap at same DOM position
+ if (this.elementIsWrapper) {
+ _destroy(this.element);
+ var wrapper = this.element;
+ wrapper.parent().append(
+ this.originalElement.css({
+ position: wrapper.css('position'),
+ width: wrapper.outerWidth(),
+ height: wrapper.outerHeight(),
+ top: wrapper.css('top'),
+ left: wrapper.css('left')
+ })
+ ).end().remove();
+ }
+
+ this.originalElement.css('resize', this.originalResizeStyle);
+ _destroy(this.originalElement);
+
+ },
+
+ _mouseCapture: function(event) {
+
+ var handle = false;
+ for(var i in this.handles) {
+ if($(this.handles[i])[0] == event.target) handle = true;
+ }
+
+ return this.options.disabled || !!handle;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options, iniPos = this.element.position(), el = this.element;
+
+ this.resizing = true;
+ this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft()
};
+
+ // bugfix for
http://dev.jquery.com/ticket/1749
+ if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
+ el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
+ }
+
+ //Opera fixing relative position
+ if ($.browser.opera && (/relative/).test(el.css('position')))
+ el.css({ position: 'relative', top: 'auto', left: 'auto' });
+
+ this._renderProxy();
+
+ var curleft = num(this.helper.css('left')), curtop =
num(this.helper.css('top'));
+
+ if (o.containment) {
+ curleft += $(o.containment).scrollLeft() || 0;
+ curtop += $(o.containment).scrollTop() || 0;
+ }
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : {
width: el.width(), height: el.height() };
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() }
: { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() -
el.height() };
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+ //Aspect Ratio
+ this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio :
((this.originalSize.width / this.originalSize.height) || 1);
+
+ var cursor = $('.ui-resizable-' + this.axis).css('cursor');
+ $('body').css('cursor', cursor == 'auto' ? this.axis +
'-resize' : cursor);
+
+ el.addClass("ui-resizable-resizing");
+ this._propagate("start", event);
+ return true;
+ },
+
+ _mouseDrag: function(event) {
+
+ //Increase performance, avoid regex
+ var el = this.helper, o = this.options, props = {},
+ self = this, smp = this.originalMousePosition, a = this.axis;
+
+ var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
+ var trigger = this._change[a];
+ if (!trigger) return false;
+
+ // Calculate the attrs that will be change
+ var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie &&
$.browser.version < 7, csdif = this.sizeDiff;
+
+ if (this._aspectRatio || event.shiftKey)
+ data = this._updateRatio(data, event);
+
+ data = this._respectSize(data, event);
+
+ // plugins callbacks need to be called first
+ this._propagate("resize", event);
+
+ el.css({
+ top: this.position.top + "px", left: this.position.left + "px",
+ width: this.size.width + "px", height: this.size.height + "px"
+ });
+
+ if (!this._helper && this._proportionallyResizeElements.length)
+ this._proportionallyResize();
+
+ this._updateCache(data);
+
+ // calling the user callback at the end
+ this._trigger('resize', event, this.ui());
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ this.resizing = false;
+ var o = this.options, self = this;
+
+ if(this._helper) {
+ var pr = this._proportionallyResizeElements, ista = pr.length &&
(/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump
height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth)
},
+ left = (parseInt(self.element.css('left'), 10) + (self.position.left -
self.originalPosition.left)) || null,
+ top = (parseInt(self.element.css('top'), 10) + (self.position.top -
self.originalPosition.top)) || null;
+
+ if (!o.animate)
+ this.element.css($.extend(s, { top: top, left: left }));
+
+ self.helper.height(self.size.height);
+ self.helper.width(self.size.width);
+
+ if (this._helper && !o.animate) this._proportionallyResize();
+ }
+
+ $('body').css('cursor', 'auto');
+
+ this.element.removeClass("ui-resizable-resizing");
+
+ this._propagate("stop", event);
+
+ if (this._helper) this.helper.remove();
+ return false;
+
+ },
+
+ _updateCache: function(data) {
+ var o = this.options;
+ this.offset = this.helper.offset();
+ if (isNumber(data.left)) this.position.left = data.left;
+ if (isNumber(data.top)) this.position.top = data.top;
+ if (isNumber(data.height)) this.size.height = data.height;
+ if (isNumber(data.width)) this.size.width = data.width;
+ },
+
+ _updateRatio: function(data, event) {
+
+ var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
+
+ if (data.height) data.width = (csize.height * this.aspectRatio);
+ else if (data.width) data.height = (csize.width / this.aspectRatio);
+
+ if (a == 'sw') {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a == 'nw') {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function(data, event) {
+
+ var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a
= this.axis,
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth <
data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight
< data.height),
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth >
data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight
> data.height);
+
+ if (isminw) data.width = o.minWidth;
+ if (isminh) data.height = o.minHeight;
+ if (ismaxw) data.width = o.maxWidth;
+ if (ismaxh) data.height = o.maxHeight;
+
+ var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top +
this.size.height;
+ var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+
+ if (isminw && cw) data.left = dw - o.minWidth;
+ if (ismaxw && cw) data.left = dw - o.maxWidth;
+ if (isminh && ch) data.top = dh - o.minHeight;
+ if (ismaxh && ch) data.top = dh - o.maxHeight;
+
+ // fixing jump error on top/left - bug #2330
+ var isNotwh = !data.width && !data.height;
+ if (isNotwh && !data.left && data.top) data.top = null;
+ else if (isNotwh && !data.top && data.left) data.left = null;
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+
+ var o = this.options;
+ if (!this._proportionallyResizeElements.length) return;
+ var element = this.helper || this.element;
+
+ for (var i=0; i < this._proportionallyResizeElements.length; i++) {
+
+ var prel = this._proportionallyResizeElements[i];
+
+ if (!this.borderDif) {
+ var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'),
prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
+ p = [prel.css('paddingTop'), prel.css('paddingRight'),
prel.css('paddingBottom'), prel.css('paddingLeft')];
+
+ this.borderDif = $.map(b, function(v, i) {
+ var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
+ return border + padding;
+ });
+ }
+
+ if ($.browser.msie && !(!($(element).is(':hidden') ||
$(element).parents(':hidden').length)))
+ continue;
+
+ prel.css({
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
+ });
+
+ };
+
+ },
+
+ _renderProxy: function() {
+
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(this._helper) {
+
+ this.helper = this.helper || $('<div
style="overflow:hidden;"></div>');
+
+ // fix ie6 offset TODO: This seems broken
+ var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 :
0),
+ pxyoffset = ( ie6 ? 2 : -1 );
+
+ this.helper.addClass(this._helper).css({
+ width: this.element.outerWidth() + pxyoffset,
+ height: this.element.outerHeight() + pxyoffset,
+ position: 'absolute',
+ left: this.elementOffset.left - ie6offset +'px',
+ top: this.elementOffset.top - ie6offset +'px',
+ zIndex: ++o.zIndex //TODO: Don't modify option
+ });
+
+ this.helper
+ .appendTo("body")
+ .disableSelection();
+
+ } else {
+ this.helper = this.element;
+ }
+
+ },
+
+ _change: {
+ e: function(event, dx, dy) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(event, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(event, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(event, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this,
[event, dx, dy]));
+ },
+ sw: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this,
[event, dx, dy]));
+ },
+ ne: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this,
[event, dx, dy]));
+ },
+ nw: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this,
[event, dx, dy]));
+ }
+ },
+
+ _propagate: function(n, event) {
+ $.ui.plugin.call(this, n, [event, this.ui()]);
+ (n != "resize" && this._trigger(n, event, this.ui()));
+ },
+
+ plugins: {},
+
+ ui: function() {
+ return {
+ originalElement: this.originalElement,
+ element: this.element,
+ helper: this.helper,
+ position: this.position,
+ size: this.size,
+ originalSize: this.originalSize,
+ originalPosition: this.originalPosition
+ };
+ }
+
+}));
+
+$.extend($.ui.resizable, {
+ version: "1.7.2",
+ eventPrefix: "resize",
+ defaults: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ cancel: ":input,option",
+ containment: false,
+ delay: 0,
+ distance: 1,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ zIndex: 1000
+ }
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+ start: function(event, ui) {
+
+ var self = $(this).data("resizable"), o = self.options;
+
+ _store = function(exp) {
+ $(exp).each(function() {
+ $(this).data("resizable-alsoresize", {
+ width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10),
+ left: parseInt($(this).css('left'), 10), top:
parseInt($(this).css('top'), 10)
+ });
+ });
+ };
+
+ if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
+ else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); }
+ }else{
+ _store(o.alsoResize);
+ }
+ },
+
+ resize: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options, os =
self.originalSize, op = self.originalPosition;
+
+ var delta = {
+ height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) ||
0,
+ top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
+ },
+
+ _alsoResize = function(exp, c) {
+ $(exp).each(function() {
+ var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
css = c && c.length ? c : ['width', 'height', 'top',
'left'];
+
+ $.each(css || ['width', 'height', 'top', 'left'],
function(i, prop) {
+ var sum = (start[prop]||0) + (delta[prop]||0);
+ if (sum && sum >= 0)
+ style[prop] = sum || null;
+ });
+
+ //Opera fixing relative position
+ if (/relative/.test(el.css('position')) && $.browser.opera) {
+ self._revertToRelativePosition = true;
+ el.css({ position: 'absolute', top: 'auto', left: 'auto'
});
+ }
+
+ el.css(style);
+ });
+ };
+
+ if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
+ $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); });
+ }else{
+ _alsoResize(o.alsoResize);
+ }
+ },
+
+ stop: function(event, ui){
+ var self = $(this).data("resizable");
+
+ //Opera fixing relative position
+ if (self._revertToRelativePosition && $.browser.opera) {
+ self._revertToRelativePosition = false;
+ el.css({ position: 'relative' });
+ }
+
+ $(this).removeData("resizable-alsoresize-start");
+ }
+});
+
+$.ui.plugin.add("resizable", "animate", {
+
+ stop: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options;
+
+ var pr = self._proportionallyResizeElements, ista = pr.length &&
(/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump
height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var style = { width: (self.size.width - soffsetw), height: (self.size.height -
soffseth) },
+ left = (parseInt(self.element.css('left'), 10) + (self.position.left -
self.originalPosition.left)) || null,
+ top = (parseInt(self.element.css('top'), 10) + (self.position.top -
self.originalPosition.top)) || null;
+
+ self.element.animate(
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
+ duration: o.animateDuration,
+ easing: o.animateEasing,
+ step: function() {
+
+ var data = {
+ width: parseInt(self.element.css('width'), 10),
+ height: parseInt(self.element.css('height'), 10),
+ top: parseInt(self.element.css('top'), 10),
+ left: parseInt(self.element.css('left'), 10)
+ };
+
+ if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height
});
+
+ // propagating resize, and updating values for each animation step
+ self._updateCache(data);
+ self._propagate("resize", event);
+
+ }
+ }
+ );
+ }
+
+});
+
+$.ui.plugin.add("resizable", "containment", {
+
+ start: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options, el = self.element;
+ var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ?
el.parent().get(0) : oc;
+ if (!ce) return;
+
+ self.containerElement = $(ce);
+
+ if (/document/.test(oc) || oc == document) {
+ self.containerOffset = { left: 0, top: 0 };
+ self.containerPosition = { left: 0, top: 0 };
+
+ self.parentData = {
+ element: $(document), left: 0, top: 0,
+ width: $(document).width(), height: $(document).height() ||
document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else {
+ var element = $(ce), p = [];
+ $([ "Top", "Right", "Left", "Bottom"
]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
+
+ self.containerOffset = element.offset();
+ self.containerPosition = element.position();
+ self.containerSize = { height: (element.innerHeight() - p[3]), width:
(element.innerWidth() - p[1]) };
+
+ var co = self.containerOffset, ch = self.containerSize.height, cw =
self.containerSize.width,
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height =
($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ self.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options,
+ ps = self.containerSize, co = self.containerOffset, cs = self.size, cp =
self.position,
+ pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce =
self.containerElement;
+
+ if (ce[0] != document && (/static/).test(ce.css('position'))) cop =
co;
+
+ if (cp.left < (self._helper ? co.left : 0)) {
+ self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) :
(self.position.left - cop.left));
+ if (pRatio) self.size.height = self.size.width / o.aspectRatio;
+ self.position.left = o.helper ? co.left : 0;
+ }
+
+ if (cp.top < (self._helper ? co.top : 0)) {
+ self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) :
self.position.top);
+ if (pRatio) self.size.width = self.size.height * o.aspectRatio;
+ self.position.top = self._helper ? co.top : 0;
+ }
+
+ self.offset.left = self.parentData.left+self.position.left;
+ self.offset.top = self.parentData.top+self.position.top;
+
+ var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left -
cop.left)) + self.sizeDiff.width ),
+ hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top -
co.top)) + self.sizeDiff.height );
+
+ var isParent = self.containerElement.get(0) == self.element.parent().get(0),
+ isOffsetRelative =
/relative|absolute/.test(self.containerElement.css('position'));
+
+ if(isParent && isOffsetRelative) woset -= self.parentData.left;
+
+ if (woset + self.size.width >= self.parentData.width) {
+ self.size.width = self.parentData.width - woset;
+ if (pRatio) self.size.height = self.size.width / self.aspectRatio;
+ }
+
+ if (hoset + self.size.height >= self.parentData.height) {
+ self.size.height = self.parentData.height - hoset;
+ if (pRatio) self.size.width = self.size.height * self.aspectRatio;
+ }
+ },
+
+ stop: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options, cp = self.position,
+ co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
+
+ var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() -
self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
+
+ if (self._helper && !o.animate &&
(/relative/).test(ce.css('position')))
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+
+ if (self._helper && !o.animate &&
(/static/).test(ce.css('position')))
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+
+ }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+ start: function(event, ui) {
+
+ var self = $(this).data("resizable"), o = self.options, cs = self.size;
+
+ self.ghost = self.originalElement.clone();
+ self.ghost
+ .css({ opacity: .25, display: 'block', position: 'relative', height:
cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
+ .addClass('ui-resizable-ghost')
+ .addClass(typeof o.ghost == 'string' ? o.ghost : '');
+
+ self.ghost.appendTo(self.helper);
+
+ },
+
+ resize: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options;
+ if (self.ghost) self.ghost.css({ position: 'relative', height:
self.size.height, width: self.size.width });
+ },
+
+ stop: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options;
+ if (self.ghost && self.helper)
self.helper.get(0).removeChild(self.ghost.get(0));
+ }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+ resize: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options, cs = self.size, os =
self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio ||
event.shiftKey;
+ o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
+ var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy =
Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
+
+ if (/^(se|s|e)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ }
+ else if (/^(ne)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ }
+ else if (/^(sw)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.left = op.left - ox;
+ }
+ else {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ self.position.left = op.left - ox;
+ }
+ }
+
+});
+
+var num = function(v) {
+ return parseInt(v, 10) || 0;
+};
+
+var isNumber = function(value) {
+ return !isNaN(parseInt(value, 10));
+};
+
+})(jQuery);