diff --git a/src/main/config/component/schedule.xml b/src/main/config/component/schedule.xml index f8a3d12..be12fbe 100644 --- a/src/main/config/component/schedule.xml +++ b/src/main/config/component/schedule.xml @@ -36,7 +36,7 @@ --> &ui_component_attributes; &commonViewAttributes; - + &ajax_component_attributes; @@ -53,6 +53,15 @@ "ajax" + widgetVar + java.lang.String + + Variable name of JavaScript component. + default: null + + null + + view java.lang.String @@ -456,7 +465,30 @@ onItemSelected java.lang.String - + JavaScript code for handling event. + Following data will be available in context: +
    +
  • item - selected item
  • +
  • event - javascript event
  • +
  • view - object representing current view
  • +
+
+ null +
+ + onItemSelectedComplete + java.lang.String + + JavaScript code called when ajax request triggered when item + is selected has finished. + Following data will be available in context: + null @@ -464,7 +496,14 @@ onItemDragStart java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + null @@ -472,7 +511,14 @@ onItemDragStop java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + null @@ -480,7 +526,14 @@ onItemResizeStart java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + null @@ -488,7 +541,14 @@ onItemResizeStop java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + null @@ -496,7 +556,53 @@ onItemDrop java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + + + null + + + onItemDropComplete + java.lang.String + + JavaScript code called when ajax request triggered when item + is dropped has finished. + Following data will be available in context: + null @@ -504,7 +610,47 @@ onItemResized java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + + + null + + + onItemResizedComplete + java.lang.String + + JavaScript code called when ajax request triggered when item + is resized has finished. + Following data will be available in context: + null @@ -512,7 +658,13 @@ onItemMouseover java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + null @@ -520,15 +672,42 @@ onItemMouseout java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + + + null + + + onViewChanged + java.lang.String + + JavaScript code for handling event. + Any return instruction will be ignored + so this code cannot block anything. + Following data will be available in context: + null - onViewDisplay + onViewChangedComplete java.lang.String - + JavaScript code called when ajax request triggered when view + changes has finished. + Following data will be available in context: + null @@ -536,7 +715,36 @@ onDateSelected java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + + + null + + + onDateSelectedComplete + java.lang.String + + JavaScript code called when ajax request triggered when date + is selected has finished. + Following data will be available in context: + null @@ -544,7 +752,67 @@ onDateRangeSelected java.lang.String - + JavaScript code for handling event. + Following data will be available in context: + + + null + + + onDateRangeSelectedComplete + java.lang.String + + JavaScript code called when ajax request triggered when date + range is selected has finished. + Following data will be available in context: + + + null + + + onDateRangeChanged + java.lang.String + + JavaScript code for handling event. + Any return instruction will be ignored + so this code cannot block anything. + Following data will be available in context: + + + null + + + onDateRangeChangedComplete + java.lang.String + + JavaScript code called when ajax request triggered when displayed + date range is changed has finished. + Following data will be available in context: + null @@ -555,7 +823,6 @@ null - itemMoveListener @@ -594,6 +861,10 @@ javax.faces.el.MethodBinding + + &listeners; diff --git a/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java b/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java index ff363e0..3a43c0f 100644 --- a/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java +++ b/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java @@ -1,5 +1,11 @@ package org.richfaces.component; +/** + * Interface with common attributes of all view components. + * Saves some lines in UISchedule...View classes. + * + * @author Bernard Labno + */ public interface ScheduleCommonViewAttributes { public String getTimeFormat(); diff --git a/src/main/java/org/richfaces/component/UISchedule.java b/src/main/java/org/richfaces/component/UISchedule.java index 19b5801..8a0bf2a 100644 --- a/src/main/java/org/richfaces/component/UISchedule.java +++ b/src/main/java/org/richfaces/component/UISchedule.java @@ -1,8 +1,12 @@ package org.richfaces.component; +import org.ajax4jsf.component.AjaxActionComponent; +import org.ajax4jsf.component.AjaxComponent; import org.ajax4jsf.context.AjaxContext; +import org.ajax4jsf.event.AjaxEvent; import org.ajax4jsf.model.DataVisitor; import org.ajax4jsf.model.ExtendedDataModel; +import org.ajax4jsf.renderkit.RendererUtils; import org.richfaces.component.event.*; import org.richfaces.component.model.DateRange; @@ -22,16 +26,24 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; -public abstract class UISchedule extends UIComponentBase implements ScheduleCommonViewAttributes, ScheduleListenerEventsProducer { +public abstract class UISchedule extends UIComponentBase implements ScheduleCommonViewAttributes, ScheduleListenerEventsProducer, AjaxComponent { public static final String COMPONENT_TYPE = "org.richfaces.Schedule"; public static final String COMPONENT_FAMILY = "org.richfaces.Schedule"; + /** + * Values of view attribute. + */ public static final String VIEW_MONTH = "month"; public static final String VIEW_BASIC_WEEK = "basicWeek"; public static final String VIEW_AGENDA_WEEK = "agendaWeek"; public static final String VIEW_BASIC_DAY = "basicDay"; public static final String VIEW_AGENDA_DAY = "agendaDay"; + /** + * Values of weekMode attribute. + */ public static final String WEEK_MODE_FIXED = "fixed"; + public static final String WEEK_MODE_LIQUID = "liquid"; + public static final String WEEK_MODE_VARIABLE = "variable"; private DataModel model; public abstract Object getValue(); @@ -174,6 +186,10 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm public abstract void setOnItemSelected(String onItemSelect); + public abstract String getOnItemSelectedComplete(); + + public abstract void setOnItemSelectedComplete(String onItemSelectedComplete); + public abstract String getOnItemDragStart(); public abstract void setOnItemDragStart(String onItemDragStart); @@ -186,6 +202,10 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm public abstract void setOnItemDrop(String onItemDrop); + public abstract String getOnItemDropComplete(); + + public abstract void setOnItemDropComplete(String onItemDropComplete); + public abstract String getOnItemResizeStart(); public abstract void setOnItemResizeStart(String onItemResizeStart); @@ -198,6 +218,10 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm public abstract void setOnItemResized(String onItemMouseover); + public abstract String getOnItemResizedComplete(); + + public abstract void setOnItemResizedComplete(String setOnItemResizedComplete); + public abstract String getOnItemMouseover(); public abstract void setOnItemMouseover(String onItemMouseover); @@ -206,18 +230,38 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm public abstract void setOnItemMouseout(String onItemMouseout); - public abstract String getOnViewDisplay(); + public abstract String getOnViewChanged(); + + public abstract void setOnViewChanged(String onViewChanged); + + public abstract String getOnViewChangedComplete(); - public abstract void setOnViewDisplay(String onViewDisplay); + public abstract void setOnViewChangedComplete(String onViewDisplayComplete); public abstract String getOnDateSelected(); public abstract void setOnDateSelected(String onDaySelected); + public abstract String getOnDateSelectedComplete(); + + public abstract void setOnDateSelectedComplete(String setOnDateSelectedComplete); + public abstract String getOnDateRangeSelected(); public abstract void setOnDateRangeSelected(String onDateRangeSelected); + public abstract String getOnDateRangeSelectedComplete(); + + public abstract void setOnDateRangeSelectedComplete(String onDateRangeSelectedComplete); + + public abstract String getOnDateRangeChanged(); + + public abstract void setOnDateRangeChanged(String onDateRangeChanged); + + public abstract String getOnDateRangeChangedComplete(); + + public abstract void setOnDateRangeChangedComplete(String onDateRangeChangedComplete); + // TODO do we use MethodBinding or MethodExpression? public abstract MethodBinding getItemMoveListener(); @@ -248,10 +292,35 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm public abstract void setDateSelectedListener(MethodBinding listener); + public abstract String getWidgetVar(); + + public abstract void setWidgetVar(String widgetVar); + + /** + * React on various events. + * Vetoable events are first broadcasted to listeners bound via EL to + * component attribtues and then if no veto is raised then to the rest of + * listeners. + * In case of non vetoable events the order of broadcast is reverse. + * Vetoable events are: ScheduleItemMoveEvent, ScheduleItemResizeEvent + * Non-vetoable events: ScheduleDateRangeChangedEvent, ScheduleItemSelectedEvent, + * ScheduleViewChangedEvent, ScheduleDateSelectedEvent, + * ScheduleDateRangeSelectedEvent + * In case of ScheduleDateRangeChangedEvent new items are returned + * via response data map of ajaxContext. + * In case of ScheduleItemMoveEvent and ScheduleItemResizeEvent, the + * decision if veto was raised is sent back to client via response data map + * of ajaxContext as boolean. + * + * @param event broadcasted event + * @throws AbortProcessingException if broadcasting of particular event + * should stop + */ @Override public void broadcast(FacesEvent event) throws AbortProcessingException { if (event instanceof ScheduleDateRangeChangedEvent) { super.broadcast(event); + new AjaxEvent(this).queue(); ScheduleDateRangeChangedEvent calendarAjaxEvent = (ScheduleDateRangeChangedEvent) event; FacesContext facesContext = getFacesContext(); AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); @@ -273,8 +342,9 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm Object result = expression.invoke(facesContext, new Object[]{event}); allow = ((Boolean) result); } - ajaxContext.setResponseData(allow); + ajaxContext.getResponseDataMap().put("_ajax:scheduleData", allow); super.broadcast(event); + new AjaxEvent(this).queue(); } else if (event instanceof ScheduleItemResizeEvent) { FacesContext facesContext = getFacesContext(); AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); @@ -284,10 +354,12 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm Object result = expression.invoke(facesContext, new Object[]{event}); allow = ((Boolean) result); } - ajaxContext.setResponseData(allow); + ajaxContext.getResponseDataMap().put("_ajax:scheduleData", allow); super.broadcast(event); + new AjaxEvent(this).queue(); } else if (event instanceof ScheduleItemSelectedEvent) { super.broadcast(event); + new AjaxEvent(this).queue(); FacesContext facesContext = getFacesContext(); MethodBinding expression = getItemSelectedListener(); if (expression != null) { @@ -295,6 +367,7 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm } } else if (event instanceof ScheduleViewChangedEvent) { super.broadcast(event); + new AjaxEvent(this).queue(); FacesContext facesContext = getFacesContext(); MethodBinding expression = getViewChangedListener(); if (expression != null) { @@ -302,6 +375,7 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm } } else if (event instanceof ScheduleDateSelectedEvent) { super.broadcast(event); + new AjaxEvent(this).queue(); FacesContext facesContext = getFacesContext(); MethodBinding expression = getDateSelectedListener(); if (expression != null) { @@ -309,11 +383,38 @@ public abstract class UISchedule extends UIComponentBase implements ScheduleComm } } else if (event instanceof ScheduleDateRangeSelectedEvent) { super.broadcast(event); + new AjaxEvent(this).queue(); FacesContext facesContext = getFacesContext(); MethodBinding expression = getDateRangeSelectedListener(); if (expression != null) { expression.invoke(facesContext, new Object[]{event}); } + } else if (event instanceof AjaxEvent) { + FacesContext context = getFacesContext(); + // complete re-Render fields. AjaxEvent deliver before render + // response. + AjaxContext.getCurrentInstance(context).addRegionsFromComponent(this); + // Put data for send in response + Object data = getData(); + AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context); + if (null != data) { + ajaxContext.setResponseData(data); + } + String focus = getFocus(); + if (null != focus) { + // search for component in tree. + // XXX - use more pourful search, as in h:outputLabel + // component. + UIComponent focusComponent = RendererUtils.getInstance(). + findComponentFor(this, focus); + if (null != focusComponent) { + focus = focusComponent.getClientId(context); + } + ajaxContext.getResponseDataMap().put(AjaxActionComponent.FOCUS_DATA_ID, focus); + } + ajaxContext.setOncomplete(getOncomplete()); + } else { + super.broadcast(event); } } diff --git a/src/main/java/org/richfaces/component/UIScheduleBasicDayView.java b/src/main/java/org/richfaces/component/UIScheduleBasicDayView.java index f8a83bd..ac4c89d 100644 --- a/src/main/java/org/richfaces/component/UIScheduleBasicDayView.java +++ b/src/main/java/org/richfaces/component/UIScheduleBasicDayView.java @@ -2,7 +2,7 @@ package org.richfaces.component; import javax.faces.component.UIComponentBase; -public abstract class UIScheduleBasicDayView extends UIComponentBase implements ScheduleCommonViewAttributes{ +public abstract class UIScheduleBasicDayView extends UIComponentBase implements ScheduleCommonViewAttributes { public static final String COMPONENT_TYPE = "org.richfaces.ScheduleBasicDayView"; public static final String COMPONENT_FAMILY = "org.richfaces.Schedule"; diff --git a/src/main/java/org/richfaces/component/event/ScheduleDateRangeChangedEvent.java b/src/main/java/org/richfaces/component/event/ScheduleDateRangeChangedEvent.java index 02fce6b..54d1fe6 100644 --- a/src/main/java/org/richfaces/component/event/ScheduleDateRangeChangedEvent.java +++ b/src/main/java/org/richfaces/component/event/ScheduleDateRangeChangedEvent.java @@ -1,11 +1,9 @@ package org.richfaces.component.event; -import java.util.Date; - import javax.faces.component.UIComponent; - import javax.faces.event.FacesEvent; import javax.faces.event.FacesListener; +import java.util.Date; public class ScheduleDateRangeChangedEvent extends FacesEvent { diff --git a/src/main/java/org/richfaces/component/event/ScheduleDateSelectedEvent.java b/src/main/java/org/richfaces/component/event/ScheduleDateSelectedEvent.java index 75a66e9..fa21a2f 100644 --- a/src/main/java/org/richfaces/component/event/ScheduleDateSelectedEvent.java +++ b/src/main/java/org/richfaces/component/event/ScheduleDateSelectedEvent.java @@ -1,9 +1,9 @@ package org.richfaces.component.event; -import java.util.Date; import javax.faces.component.UIComponent; import javax.faces.event.FacesEvent; import javax.faces.event.FacesListener; +import java.util.Date; public class ScheduleDateSelectedEvent extends FacesEvent { diff --git a/src/main/java/org/richfaces/component/event/ScheduleItemMoveListener.java b/src/main/java/org/richfaces/component/event/ScheduleItemMoveListener.java index d30484f..8bed1a4 100644 --- a/src/main/java/org/richfaces/component/event/ScheduleItemMoveListener.java +++ b/src/main/java/org/richfaces/component/event/ScheduleItemMoveListener.java @@ -2,7 +2,7 @@ package org.richfaces.component.event; import javax.faces.event.FacesListener; -public interface ScheduleItemMoveListener extends FacesListener{ +public interface ScheduleItemMoveListener extends FacesListener { void itemMove(ScheduleItemMoveEvent event); } diff --git a/src/main/java/org/richfaces/component/event/ScheduleItemResizeListener.java b/src/main/java/org/richfaces/component/event/ScheduleItemResizeListener.java index 032e16e..e28fefd 100644 --- a/src/main/java/org/richfaces/component/event/ScheduleItemResizeListener.java +++ b/src/main/java/org/richfaces/component/event/ScheduleItemResizeListener.java @@ -2,7 +2,7 @@ package org.richfaces.component.event; import javax.faces.event.FacesListener; -public interface ScheduleItemResizeListener extends FacesListener{ +public interface ScheduleItemResizeListener extends FacesListener { void itemResize(ScheduleItemResizeEvent event); } diff --git a/src/main/java/org/richfaces/component/event/ScheduleViewChangedListener.java b/src/main/java/org/richfaces/component/event/ScheduleViewChangedListener.java index 2da6982..19d8001 100644 --- a/src/main/java/org/richfaces/component/event/ScheduleViewChangedListener.java +++ b/src/main/java/org/richfaces/component/event/ScheduleViewChangedListener.java @@ -2,7 +2,7 @@ package org.richfaces.component.event; import javax.faces.event.FacesListener; -public interface ScheduleViewChangedListener extends FacesListener{ +public interface ScheduleViewChangedListener extends FacesListener { void viewChanged(ScheduleViewChangedEvent event); } diff --git a/src/main/java/org/richfaces/component/model/DateRange.java b/src/main/java/org/richfaces/component/model/DateRange.java index d47b583..0b65734 100644 --- a/src/main/java/org/richfaces/component/model/DateRange.java +++ b/src/main/java/org/richfaces/component/model/DateRange.java @@ -1,8 +1,9 @@ package org.richfaces.component.model; -import java.util.Date; import org.ajax4jsf.model.Range; +import java.util.Date; + public class DateRange implements Range { private Date startDate; diff --git a/src/main/java/org/richfaces/renderkit/ScheduleRendererBase.java b/src/main/java/org/richfaces/renderkit/ScheduleRendererBase.java index 11e4b87..043dcb0 100644 --- a/src/main/java/org/richfaces/renderkit/ScheduleRendererBase.java +++ b/src/main/java/org/richfaces/renderkit/ScheduleRendererBase.java @@ -121,6 +121,10 @@ public abstract class ScheduleRendererBase extends AjaxComponentRendererBase { ResponseWriter writer = context.getResponseWriter(); String clientId = component.getClientId(context); Locale locale = context.getViewRoot().getLocale(); + String widgetVar = component.getWidgetVar(); + if (widgetVar != null) { + writer.writeText("var " + widgetVar + " = ", null); + } writer.writeText(new JSObject("RichFaces.Schedule", clientId, locale.toString(), getOptions(component), DATE_RANGE_CHANGED_EVENT, @@ -205,18 +209,27 @@ public abstract class ScheduleRendererBase extends AjaxComponentRendererBase { options.put("header", headerOptions); } addOptionIfSet("allDayDefault", schedule.getAllDayByDefault(), options); + addOptionIfSet("onItemSelected", schedule.getOnItemSelected(), options); + addOptionIfSet("onItemSelectedComplete", schedule.getOnItemSelectedComplete(), options); addOptionIfSet("onItemDrop", schedule.getOnItemDrop(), options); + addOptionIfSet("onItemDropComplete", schedule.getOnItemDropComplete(), options); addOptionIfSet("onItemResized", schedule.getOnItemResized(), options); + addOptionIfSet("onItemResizedComplete", schedule.getOnItemResizedComplete(), options); addOptionIfSet("onItemResizeStart", schedule.getOnItemResizeStart(), options); addOptionIfSet("onItemResizeStop", schedule.getOnItemResizeStop(), options); addOptionIfSet("onItemDragStart", schedule.getOnItemDragStart(), options); addOptionIfSet("onItemDragStop", schedule.getOnItemDragStop(), options); addOptionIfSet("onItemMouseover", schedule.getOnItemMouseover(), options); addOptionIfSet("onItemMouseout", schedule.getOnItemMouseout(), options); - addOptionIfSet("onViewDisplay", schedule.getOnViewDisplay(), options); + addOptionIfSet("onViewChanged", schedule.getOnViewChanged(), options); + addOptionIfSet("onViewChangedComplete", schedule.getOnViewChangedComplete(), options); addOptionIfSet("onDateSelected", schedule.getOnDateSelected(), options); + addOptionIfSet("onDateSelectedComplete", schedule.getOnDateSelectedComplete(), options); addOptionIfSet("onDateRangeSelected", schedule.getOnDateRangeSelected(), options); + addOptionIfSet("onDateRangeSelectedComplete", schedule.getOnDateRangeSelectedComplete(), options); + addOptionIfSet("onDateRangeChanged", schedule.getOnDateRangeChanged(), options); + addOptionIfSet("onDateRangeChangedComplete", schedule.getOnDateRangeChangedComplete(), options); if (schedule.getDate() != null) { Calendar calendar = Calendar.getInstance(); calendar.setTime(schedule.getDate()); diff --git a/src/main/java/org/richfaces/taglib/ScheduleTagHandlerBase.java b/src/main/java/org/richfaces/taglib/ScheduleTagHandlerBase.java index 1964387..b49e6d7 100644 --- a/src/main/java/org/richfaces/taglib/ScheduleTagHandlerBase.java +++ b/src/main/java/org/richfaces/taglib/ScheduleTagHandlerBase.java @@ -1,18 +1,15 @@ package org.richfaces.taglib; import com.sun.facelets.FaceletContext; -import com.sun.facelets.tag.MetaRule; -import com.sun.facelets.tag.MetaRuleset; -import com.sun.facelets.tag.Metadata; -import com.sun.facelets.tag.MetadataTarget; -import com.sun.facelets.tag.TagAttribute; +import com.sun.facelets.tag.*; import com.sun.facelets.tag.jsf.ComponentConfig; import com.sun.facelets.tag.jsf.ComponentHandler; -import javax.faces.component.UIComponent; -import javax.faces.el.MethodBinding; import org.richfaces.event.NodeExpandedEvent; import org.richfaces.event.NodeSelectedEvent; +import javax.faces.component.UIComponent; +import javax.faces.el.MethodBinding; + public class ScheduleTagHandlerBase extends ComponentHandler { private final static String DATE_RANGE_CHANGED_LISTENER = "dateRangeChangedListener"; diff --git a/src/main/resources/org/richfaces/component/UIScheduleMessages_en.properties b/src/main/resources/org/richfaces/component/UIScheduleMessages_en.properties index 8a85c05..ac1ea48 100644 --- a/src/main/resources/org/richfaces/component/UIScheduleMessages_en.properties +++ b/src/main/resources/org/richfaces/component/UIScheduleMessages_en.properties @@ -37,10 +37,10 @@ org.richfaces.component.UISchedule.dayNamesShort.WEDNESDAY=Wed org.richfaces.component.UISchedule.dayNamesShort.THURSDAY=Thu org.richfaces.component.UISchedule.dayNamesShort.FRIDAY=Fri org.richfaces.component.UISchedule.dayNamesShort.SATURDAY=Sat -org.richfaces.component.UISchedule.buttonTexts.prev= ◄  -org.richfaces.component.UISchedule.buttonTexts.next= ►  -org.richfaces.component.UISchedule.buttonTexts.prevYear= <<  -org.richfaces.component.UISchedule.buttonTexts.nextYear= >>  +org.richfaces.component.UISchedule.buttonTexts.prev= ◄  +org.richfaces.component.UISchedule.buttonTexts.next= ►  +org.richfaces.component.UISchedule.buttonTexts.prevYear= <<  +org.richfaces.component.UISchedule.buttonTexts.nextYear= >>  org.richfaces.component.UISchedule.buttonTexts.today=today org.richfaces.component.UISchedule.buttonTexts.month=month org.richfaces.component.UISchedule.buttonTexts.week=week diff --git a/src/main/resources/org/richfaces/component/UIScheduleMessages_pl.properties b/src/main/resources/org/richfaces/component/UIScheduleMessages_pl.properties index 361ca72..c045e2f 100644 --- a/src/main/resources/org/richfaces/component/UIScheduleMessages_pl.properties +++ b/src/main/resources/org/richfaces/component/UIScheduleMessages_pl.properties @@ -37,10 +37,10 @@ org.richfaces.component.UISchedule.dayNamesShort.WEDNESDAY=\u015Aro org.richfaces.component.UISchedule.dayNamesShort.THURSDAY=Czw org.richfaces.component.UISchedule.dayNamesShort.FRIDAY=Pi\u0105 org.richfaces.component.UISchedule.dayNamesShort.SATURDAY=Sob -org.richfaces.component.UISchedule.buttonTexts.prev= ◄  -org.richfaces.component.UISchedule.buttonTexts.next= ►  -org.richfaces.component.UISchedule.buttonTexts.prevYear= <<  -org.richfaces.component.UISchedule.buttonTexts.nextYear= >>  +org.richfaces.component.UISchedule.buttonTexts.prev= ◄  +org.richfaces.component.UISchedule.buttonTexts.next= ►  +org.richfaces.component.UISchedule.buttonTexts.prevYear= <<  +org.richfaces.component.UISchedule.buttonTexts.nextYear= >>  org.richfaces.component.UISchedule.buttonTexts.today=Dzi\u015B org.richfaces.component.UISchedule.buttonTexts.month=Miesi\u0105c org.richfaces.component.UISchedule.buttonTexts.week=Tydzie\u0144 diff --git a/src/main/resources/org/richfaces/renderkit/html/css/fullcalendar.css b/src/main/resources/org/richfaces/renderkit/html/css/fullcalendar.css index 888f6ea..6ef114b 100644 --- a/src/main/resources/org/richfaces/renderkit/html/css/fullcalendar.css +++ b/src/main/resources/org/richfaces/renderkit/html/css/fullcalendar.css @@ -10,566 +10,555 @@ * TODO adjust class names to richfaces naming conventions */ - .fc, .fc .fc-header, .fc .fc-content { - font-size: 1em; - } - + font-size: 1em; +} + .fc { - direction: ltr; - text-align: left; - } - -.fc table { - border-collapse: collapse; - border-spacing: 0; - } - -.fc td, .fc th { - padding: 0; - vertical-align: top; - } + direction: ltr; + text-align: left; +} +.fc table { + border-collapse: collapse; + border-spacing: 0; +} +.fc td, .fc th { + padding: 0; + vertical-align: top; +} /* Header ------------------------------------------------------------------------*/ - + table.fc-header { - width: 100%; - } - + width: 100%; +} + .fc-header-left { - width: 25%; - } - + width: 25%; +} + .fc-header-left table { - float: left; - } - + float: left; +} + .fc-header-center { - width: 50%; - text-align: center; - } - + width: 50%; + text-align: center; +} + .fc-header-center table { - margin: 0 auto; - } - + margin: 0 auto; +} + .fc-header-right { - width: 25%; - } - + width: 25%; +} + .fc-header-right table { - float: right; - } - + float: right; +} + .fc-header-title { - margin-top: 0; - white-space: nowrap; - } - + margin-top: 0; + white-space: nowrap; +} + .fc-header-space { - padding-left: 10px; - } - + padding-left: 10px; +} + /* right-to-left */ .fc-rtl .fc-header-title { - direction: rtl; - } - - + direction: rtl; +} /* Buttons ------------------------------------------------------------------------*/ .fc-header .fc-state-default, .fc-header .ui-state-default { - margin-bottom: 1em; - cursor: pointer; - } - + margin-bottom: 1em; + cursor: pointer; +} + .fc-header .fc-state-default { - border-width: 1px 0; - padding: 0 1px; - } - + border-width: 1px 0; + padding: 0 1px; +} + .fc-header .fc-state-default, .fc-header .fc-state-default a { - border-style: solid; - } - + border-style: solid; +} + .fc-header .fc-state-default a { - display: block; - border-width: 0 1px; - margin: 0 -1px; - width: 100%; - text-decoration: none; - } - + display: block; + border-width: 0 1px; + margin: 0 -1px; + width: 100%; + text-decoration: none; +} + .fc-header .fc-state-default span { - display: block; - border-style: solid; - border-width: 1px 0 1px 1px; - padding: 3px 5px; - } - + display: block; + border-style: solid; + border-width: 1px 0 1px 1px; + padding: 3px 5px; +} + .fc-header .ui-state-default { - padding: 4px 6px; - } - + padding: 4px 6px; +} + .fc-header .fc-state-default span, .fc-header .ui-state-default span { - white-space: nowrap; - } - + white-space: nowrap; +} + /* for adjacent buttons */ - + .fc-header .fc-no-right { - padding-right: 0; - } - + padding-right: 0; +} + .fc-header .fc-no-right a { - margin-right: 0; - border-right: 0; - } - + margin-right: 0; + border-right: 0; +} + .fc-header .ui-no-right { - border-right: 0; - } - + border-right: 0; +} + /* for fake rounded corners */ - + .fc-header .fc-corner-left { - margin-left: 1px; - padding-left: 0; - } - + margin-left: 1px; + padding-left: 0; +} + .fc-header .fc-corner-right { - margin-right: 1px; - padding-right: 0; - } - + margin-right: 1px; + padding-right: 0; +} + /* DEFAULT button COLORS */ - + .fc-header .fc-state-default, .fc-header .fc-state-default a { - border-color: #777; /* outer border */ - color: #333; - } + border-color: #777; /* outer border */ + color: #333; +} .fc-header .fc-state-default span { - border-color: #fff #fff #d1d1d1; /* inner border */ - background: #e8e8e8; - } - + border-color: #fff #fff #d1d1d1; /* inner border */ + background: #e8e8e8; +} + /* PRESSED button COLORS (down and active) */ - + .fc-header .fc-state-active a { - color: #fff; - } - + color: #fff; +} + .fc-header .fc-state-down span, .fc-header .fc-state-active span { - background: #888; - border-color: #808080 #808080 #909090; /* inner border */ - } - + background: #888; + border-color: #808080 #808080 #909090; /* inner border */ +} + /* DISABLED button COLORS */ - + .fc-header .fc-state-disabled a { - color: #999; - } - + color: #999; +} + .fc-header .fc-state-disabled, .fc-header .fc-state-disabled a { - border-color: #ccc; /* outer border */ - } - + border-color: #ccc; /* outer border */ +} + .fc-header .fc-state-disabled span { - border-color: #fff #fff #f0f0f0; /* inner border */ - background: #f0f0f0; - } - - - + border-color: #fff #fff #f0f0f0; /* inner border */ + background: #f0f0f0; +} + /* Content Area & Global Cell Styles ------------------------------------------------------------------------*/ - + .fc-widget-content { - border: 1px solid #ccc; /* outer border color */ - } - + border: 1px solid #ccc; /* outer border color */ +} + .fc-content { - clear: both; - } - + clear: both; +} + .fc-content .fc-state-default { - border-style: solid; - border-color: #ccc; /* inner border color */ - } - -.fc-content .fc-state-highlight { /* today */ - background: #ffc; - } - + border-style: solid; + border-color: #ccc; /* inner border color */ +} + +.fc-content .fc-state-highlight { +/* today */ + background: #ffc; +} + .fc-content .fc-not-today { - background: none; - } - -.fc-cell-overlay { /* semi-transparent rectangle while dragging */ - background: #9cf; - opacity: .2; - filter: alpha(opacity=20); /* for IE */ - } - -.fc-view { /* prevents dragging outside of widget */ - width: 100%; - overflow: hidden; - } - - - + background: none; +} + +.fc-cell-overlay { +/* semi-transparent rectangle while dragging */ + background: #9cf; + opacity: .2; + filter: alpha(opacity = 20); /* for IE */ +} + +.fc-view { +/* prevents dragging outside of widget */ + width: 100%; + overflow: hidden; +} + /* Global Event Styles ------------------------------------------------------------------------*/ .fc-event, .fc-agenda .fc-event-time, .fc-event a { - border-style: solid; - border-color: #36c; /* default BORDER color (probably the same as background-color) */ - background-color: #36c; /* default BACKGROUND color */ - color: #fff; /* default TEXT color */ - } - - /* Use the 'className' CalEvent property and the following - * example CSS to change event color on a per-event basis: - * - * .myclass, - * .fc-agenda .myclass .fc-event-time, - * .myclass a { - * background-color: black; - * border-color: black; - * color: red; - * } - */ - + border-style: solid; + border-color: #36c; /* default BORDER color (probably the same as background-color) */ + background-color: #36c; /* default BACKGROUND color */ + color: #fff; /* default TEXT color */ +} + +/* Use the 'className' CalEvent property and the following + * example CSS to change event color on a per-event basis: + * + * .myclass, + * .fc-agenda .myclass .fc-event-time, + * .myclass a { + * background-color: black; + * border-color: black; + * color: red; + * } + */ + .fc-event { - text-align: left; - } - + text-align: left; +} + .fc-event a { - overflow: hidden; - font-size: .85em; - text-decoration: none; - cursor: pointer; - } - + overflow: hidden; + font-size: .85em; + text-decoration: none; + cursor: pointer; +} + .fc-event-editable { - cursor: pointer; - } - + cursor: pointer; +} + .fc-event-time, .fc-event-title { - padding: 0 1px; - } - + padding: 0 1px; +} + /* for fake rounded corners */ .fc-event a { - display: block; - position: relative; - width: 100%; - height: 100%; - } - + display: block; + position: relative; + width: 100%; + height: 100%; +} + /* right-to-left */ .fc-rtl .fc-event a { - text-align: right; - } - + text-align: right; +} + /* resizable */ - + .fc .ui-resizable-handle { - display: block; - position: absolute; - z-index: 99999; - border: 0 !important; /* important overrides pre jquery ui 1.7 styles */ - background: url(data:image/gif;base64,AAAA) !important; /* hover fix for IE */ - } - - - + display: block; + position: absolute; + z-index: 99999; + border: 0 !important; /* important overrides pre jquery ui 1.7 styles */ + background: url(data:image/gif;base64,AAAA) !important; /* hover fix for IE */ +} + /* Horizontal Events ------------------------------------------------------------------------*/ .fc-event-hori { - border-width: 1px 0; - margin-bottom: 1px; - } - + border-width: 1px 0; + margin-bottom: 1px; +} + .fc-event-hori a { - border-width: 0; - } - + border-width: 0; +} + /* for fake rounded corners */ - + .fc-content .fc-corner-left { - margin-left: 1px; - } - + margin-left: 1px; +} + .fc-content .fc-corner-left a { - margin-left: -1px; - border-left-width: 1px; - } - + margin-left: -1px; + border-left-width: 1px; +} + .fc-content .fc-corner-right { - margin-right: 1px; - } - + margin-right: 1px; +} + .fc-content .fc-corner-right a { - margin-right: -1px; - border-right-width: 1px; - } - + margin-right: -1px; + border-right-width: 1px; +} + /* resizable */ - + .fc-event-hori .ui-resizable-e { - top: 0 !important; /* importants override pre jquery ui 1.7 styles */ - right: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: e-resize; - } - + top: 0 !important; /* importants override pre jquery ui 1.7 styles */ + right: -3px !important; + width: 7px !important; + height: 100% !important; + cursor: e-resize; +} + .fc-event-hori .ui-resizable-w { - top: 0 !important; - left: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: w-resize; - } - + top: 0 !important; + left: -3px !important; + width: 7px !important; + height: 100% !important; + cursor: w-resize; +} + .fc-event-hori .ui-resizable-handle { - _padding-bottom: 14px; /* IE6 had 0 height */ - } - - + _padding-bottom: 14px; /* IE6 had 0 height */ +} /* Month View, Basic Week View, Basic Day View ------------------------------------------------------------------------*/ .fc-grid table { - width: 100%; - } - + width: 100%; +} + .fc .fc-grid th { - border-width: 0 0 0 1px; - text-align: center; - } - + border-width: 0 0 0 1px; + text-align: center; +} + .fc .fc-grid td { - border-width: 1px 0 0 1px; - } - + border-width: 1px 0 0 1px; +} + .fc-grid th.fc-leftmost, .fc-grid td.fc-leftmost { - border-left: 0; - } - + border-left: 0; +} + .fc-grid .fc-day-number { - float: right; - padding: 0 2px; - } - + float: right; + padding: 0 2px; +} + .fc-grid .fc-other-month .fc-day-number { - opacity: 0.3; - filter: alpha(opacity=30); /* for IE */ - /* opacity with small font can sometimes look too faded - might want to set the 'color' property instead - making day-numbers bold also fixes the problem */ - } - + opacity: 0.3; + filter: alpha(opacity = 30); /* for IE */ + /* opacity with small font can sometimes look too faded + might want to set the 'color' property instead + making day-numbers bold also fixes the problem */ +} + .fc-grid .fc-day-content { - clear: both; - padding: 2px 2px 0; /* distance between events and day edges */ - } - + clear: both; + padding: 2px 2px 0; /* distance between events and day edges */ +} + /* event styles */ - + .fc-grid .fc-event-time { - font-weight: bold; - } - + font-weight: bold; +} + /* right-to-left */ .fc-rtl .fc-grid { - direction: rtl; - } - + direction: rtl; +} + .fc-rtl .fc-grid .fc-day-number { - float: left; - } - + float: left; +} + .fc-rtl .fc-grid .fc-event-time { - float: right; - } - + float: right; +} + /* Agenda Week View, Agenda Day View ------------------------------------------------------------------------*/ .fc .fc-agenda th, .fc .fc-agenda td { - border-width: 1px 0 0 1px; - } - + border-width: 1px 0 0 1px; +} + .fc .fc-agenda .fc-leftmost { - border-left: 0; - } - + border-left: 0; +} + .fc-agenda tr.fc-first th, .fc-agenda tr.fc-first td { - border-top: 0; - } - + border-top: 0; +} + .fc-agenda-head tr.fc-last th { - border-bottom-width: 1px; - } - + border-bottom-width: 1px; +} + .fc .fc-agenda-head td, .fc .fc-agenda-body td { - background: none; - } - + background: none; +} + .fc-agenda-head th { - text-align: center; - } - + text-align: center; +} + /* the time axis running down the left side */ - + .fc-agenda .fc-axis { - width: 50px; - padding: 0 4px; - vertical-align: middle; - white-space: nowrap; - text-align: right; - font-weight: normal; - } - + width: 50px; + padding: 0 4px; + vertical-align: middle; + white-space: nowrap; + text-align: right; + font-weight: normal; +} + /* all-day event cells at top */ - + .fc-agenda-head tr.fc-all-day th { - height: 35px; - } - + height: 35px; +} + .fc-agenda-head td { - padding-bottom: 10px; - } - + padding-bottom: 10px; +} + .fc .fc-divider div { - font-size: 1px; /* for IE6/7 */ - height: 2px; - } - + font-size: 1px; /* for IE6/7 */ + height: 2px; +} + .fc .fc-divider .fc-state-default { - background: #eee; /* color for divider between all-day and time-slot events */ - } + background: #eee; /* color for divider between all-day and time-slot events */ +} /* body styles */ - + .fc .fc-agenda-body td div { - height: 20px; /* slot height */ - } - + height: 20px; /* slot height */ +} + .fc .fc-agenda-body tr.fc-minor th, .fc .fc-agenda-body tr.fc-minor td { - border-top-style: dotted; - } - -.fc-agenda .fc-day-content { - padding: 2px 2px 0; /* distance between events and day edges */ - } - + border-top-style: dotted; +} +.fc-agenda .fc-day-content { + padding: 2px 2px 0; /* distance between events and day edges */ +} /* Vertical Events ------------------------------------------------------------------------*/ .fc-event-vert { - border-width: 0 1px; - } - + border-width: 0 1px; +} + .fc-event-vert a { - border-width: 0; - } - + border-width: 0; +} + /* for fake rounded corners */ - + .fc-content .fc-corner-top { - margin-top: 1px; - } - + margin-top: 1px; +} + .fc-content .fc-corner-top a { - margin-top: -1px; - border-top-width: 1px; - } - + margin-top: -1px; + border-top-width: 1px; +} + .fc-content .fc-corner-bottom { - margin-bottom: 1px; - } - + margin-bottom: 1px; +} + .fc-content .fc-corner-bottom a { - margin-bottom: -1px; - border-bottom-width: 1px; - } - + margin-bottom: -1px; + border-bottom-width: 1px; +} + /* event content */ - + .fc-event-vert span { - display: block; - position: relative; - z-index: 2; - } - + display: block; + position: relative; + z-index: 2; +} + .fc-event-vert span.fc-event-time { - white-space: nowrap; - _white-space: normal; - overflow: hidden; - border: 0; - font-size: 10px; - } - + white-space: nowrap; + _white-space: normal; + overflow: hidden; + border: 0; + font-size: 10px; +} + .fc-event-vert span.fc-event-title { - line-height: 13px; - } - -.fc-event-vert span.fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */ - position: absolute; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #fff; - opacity: .3; - filter: alpha(opacity=30); /* for IE */ - } - + line-height: 13px; +} + +.fc-event-vert span.fc-event-bg { +/* makes the event lighter w/ a semi-transparent overlay */ + position: absolute; + z-index: 1; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #fff; + opacity: .3; + filter: alpha(opacity = 30); /* for IE */ +} + /* resizable */ - + .fc-event-vert .ui-resizable-s { - bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ - width: 100% !important; - height: 8px !important; - line-height: 8px !important; - font-size: 11px !important; - font-family: monospace; - text-align: center; - cursor: s-resize; - } + bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ + width: 100% !important; + height: 8px !important; + line-height: 8px !important; + font-size: 11px !important; + font-family: monospace; + text-align: center; + cursor: s-resize; +} diff --git a/src/main/resources/org/richfaces/renderkit/html/scripts/gcal.js b/src/main/resources/org/richfaces/renderkit/html/scripts/gcal.js index 773d326..c34babd 100644 --- a/src/main/resources/org/richfaces/renderkit/html/scripts/gcal.js +++ b/src/main/resources/org/richfaces/renderkit/html/scripts/gcal.js @@ -12,60 +12,60 @@ (function($) { - $.fullCalendar.gcalFeed = function(feedUrl, options) { - - feedUrl = feedUrl.replace(/\/basic$/, '/full'); - options = options || {}; - - return function(start, end, callback) { - var params = { - 'start-min': $.fullCalendar.formatDate(start, 'u'), - 'start-max': $.fullCalendar.formatDate(end, 'u'), - 'singleevents': true, - 'max-results': 9999 - }; - var ctz = options.currentTimezone; - if (ctz) { - params.ctz = ctz = ctz.replace(' ', '_'); - } - $.getJSON(feedUrl + "?alt=json-in-script&callback=?", params, function(data) { - var events = []; - if (data.feed.entry) { - $.each(data.feed.entry, function(i, entry) { - var startStr = entry['gd$when'][0]['startTime'], - start = $.fullCalendar.parseISO8601(startStr, true), - end = $.fullCalendar.parseISO8601(entry['gd$when'][0]['endTime'], true), - allDay = startStr.indexOf('T') == -1, - url; - $.each(entry.link, function() { - if (this.type == 'text/html') { - url = this.href; - if (ctz) { - url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz; - } - } - }); - if (allDay) { - $.fullCalendar.addDays(end, -1); // make inclusive - } - events.push({ - id: entry['gCal$uid']['value'], - title: entry['title']['$t'], - url: url, - start: start, - end: end, - allDay: allDay, - location: entry['gd$where'][0]['valueString'], - description: entry['content']['$t'], - className: options.className, - editable: options.editable || false - }); - }); - } - callback(events); - }); - } - - } + $.fullCalendar.gcalFeed = function(feedUrl, options) { + + feedUrl = feedUrl.replace(/\/basic$/, '/full'); + options = options || {}; + + return function(start, end, callback) { + var params = { + 'start-min': $.fullCalendar.formatDate(start, 'u'), + 'start-max': $.fullCalendar.formatDate(end, 'u'), + 'singleevents': true, + 'max-results': 9999 + }; + var ctz = options.currentTimezone; + if (ctz) { + params.ctz = ctz = ctz.replace(' ', '_'); + } + $.getJSON(feedUrl + "?alt=json-in-script&callback=?", params, function(data) { + var events = []; + if (data.feed.entry) { + $.each(data.feed.entry, function(i, entry) { + var startStr = entry['gd$when'][0]['startTime'], + start = $.fullCalendar.parseISO8601(startStr, true), + end = $.fullCalendar.parseISO8601(entry['gd$when'][0]['endTime'], true), + allDay = startStr.indexOf('T') == -1, + url; + $.each(entry.link, function() { + if (this.type == 'text/html') { + url = this.href; + if (ctz) { + url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz; + } + } + }); + if (allDay) { + $.fullCalendar.addDays(end, -1); // make inclusive + } + events.push({ + id: entry['gCal$uid']['value'], + title: entry['title']['$t'], + url: url, + start: start, + end: end, + allDay: allDay, + location: entry['gd$where'][0]['valueString'], + description: entry['content']['$t'], + className: options.className, + editable: options.editable || false + }); + }); + } + callback(events); + }); + } + + } })(jQuery); diff --git a/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.schedule.js b/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.schedule.js index 67581d8..9c0a831 100644 --- a/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.schedule.js +++ b/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.schedule.js @@ -41,6 +41,12 @@ window.RichFaces.Schedule = (function() { return; } } + if (options.onDateRangeChanged != null) { + RichFaces.Schedule.eval("(function(){" + options.onDateRangeChanged + "})()", { + 'startDate':startDate, + 'endDate':endDate + }); + } if (_this.submitEventFunction != null) { _this.submitEventFunction({} /* stub event */, null, @@ -54,32 +60,58 @@ window.RichFaces.Schedule = (function() { if (scheduleData != undefined) { callback(scheduleData); } + if (options.onDateRangeChangedComplete != null) { + RichFaces.Schedule.eval("(function(){" + options.onDateRangeChangedComplete + "})()", { + 'startDate':startDate, + 'endDate':endDate, + 'request':request, + 'data':data, + 'items':scheduleData + }); + } } ); } }; - var itemDragStart = function(item, event) { + var itemDragStart = function(item, event, ui, view) { if (options.onItemDragStart != null) { - eval("(function(){" + options.onItemDragStart + "})()"); + RichFaces.Schedule.eval("(function(){" + options.onItemDragStart + "})()", { + 'item':item, + 'event':event, + 'ui':ui, + 'view':view + }); } }; - var itemDragStop = function(item, event) { + var itemDragStop = function(item, event, ui, view) { if (options.onItemDragStop != null) { - eval("(function(){" + options.onItemDragStop + "})()"); + RichFaces.Schedule.eval("(function(){" + options.onItemDragStop + "})()", { + 'item':item, + 'event':event, + 'ui':ui, + 'view':view + }); } }; - var itemDrop = function(item, dayDelta, minuteDelta, allDay, revertFunc, event) { + var itemDrop = function(item, dayDelta, minuteDelta, allDay, revertFunc, event, ui, view) { + var result; if (options.onItemDrop != null) { - var result = eval("(function(){" + options.onItemDrop + "})()"); - if (result != null) { - if (result === false) { - revertFunc(); - } + result = RichFaces.Schedule.eval("(function(){" + options.onItemDrop + "})()", { + 'item':item, + 'dayDelta':dayDelta, + 'minuteDelta':minuteDelta, + 'allDay':allDay, + 'event':event, + 'ui':ui, + 'view':view + }); + if (result === false) { + revertFunc(); return; } } if (_this.submitEventFunction != null) { - _this.submitEventFunction({} /* stub event */, + _this.submitEventFunction(event, null, itemMovedEventName, item.id, @@ -87,25 +119,49 @@ window.RichFaces.Schedule = (function() { null, dayDelta, minuteDelta, allDay, function(request, event, data) { - if (data != undefined && data !== true) { + var decision = request.getJSON('_ajax:scheduleData'); + var vetoed = false; + if (decision != undefined && decision !== true) { revertFunc(); + vetoed = true; + } + if (options.onItemDropComplete != null) { + RichFaces.Schedule.eval("(function(){" + options.onItemDropComplete + "})()", { + 'item':item, + 'dayDelta':dayDelta, + 'minuteDelta':minuteDelta, + 'allDay':allDay, + 'event':event, + 'ui':ui, + 'view':view, + 'request':request, + 'data':data, + 'vetoed':vetoed + }); } } ); } + return; }; - var itemResized = function(item, dayDelta, minuteDelta, revertFunc, event) { + var itemResized = function(item, dayDelta, minuteDelta, revertFunc, event, ui, view) { + var result; if (options.onItemResized != null) { - var result = eval("(function(){" + options.onItemResized + "})()"); - if (result != null) { - if (result === false) { - revertFunc(); - } + result = RichFaces.Schedule.eval("(function(){" + options.onItemResized + "})()", { + 'item':item, + 'dayDelta':dayDelta, + 'minuteDelta':minuteDelta, + 'event':event, + 'ui':ui, + 'view':view + }); + if (result === false) { + revertFunc(); return; } } if (_this.submitEventFunction != null) { - _this.submitEventFunction({} /* stub event */, + _this.submitEventFunction(event, null, itemResizedEventName, item.id, @@ -113,93 +169,181 @@ window.RichFaces.Schedule = (function() { null, dayDelta, minuteDelta, null, function(request, event, data) { - if (data != undefined && data !== true) { + var decision = request.getJSON('_ajax:scheduleData'); + var vetoed = false; + if (decision != undefined && decision !== true) { revertFunc(); + vetoed = true; + } + if (options.onItemResizedComplete != null) { + RichFaces.Schedule.eval("(function(){" + options.onItemResizedComplete + "})()", { + 'item':item, + 'dayDelta':dayDelta, + 'minuteDelta':minuteDelta, + 'event':event, + 'ui':ui, + 'view':view, + 'request':request, + 'data':data, + 'vetoed':vetoed + }); } } ); } }; - var itemResizeStart = function(item, event) { + var itemResizeStart = function(item, event, ui, view) { if (options.onItemResizeStart != null) { - eval("(function(){" + options.onItemResizeStart + "})()"); + RichFaces.Schedule.eval("(function(){" + options.onItemResizeStart + "})()", { + 'item':item, + 'event':event, + 'ui':ui, + 'view':view + }); } }; - var itemResizeStop = function(item, event) { + var itemResizeStop = function(item, event, ui, view) { if (options.onItemResizeStop != null) { - eval("(function(){" + options.onItemResizeStop + "})()"); + RichFaces.Schedule.eval("(function(){" + options.onItemResizeStop + "})()", { + 'item':item, + 'event':event, + 'ui':ui, + 'view':view + }); } }; - var itemMouseover = function(item) { + var itemMouseover = function(item, event, view) { if (options.onItemMouseover != null) { - eval("(function(){" + options.onItemMouseover + "})()"); + RichFaces.Schedule.eval("(function(){" + options.onItemMouseover + "})()", { + 'item':item, + 'event':event, + 'view':view + }); } }; - var itemMouseout = function(item) { + var itemMouseout = function(item, event, view) { if (options.onItemMouseout != null) { - eval("(function(){" + options.onItemMouseout + "})()"); + RichFaces.Schedule.eval("(function(){" + options.onItemMouseout + "})()", { + 'item':item, + 'event':event, + 'view':view + }); } }; - var itemClick = function(item, event) { + var itemClick = function(item, event, view) { + var result; if (options.onItemSelected != null) { - var result = eval("(function(){" + options.onItemSelected + "})()"); - if (result != null) { - return; - } + result = RichFaces.Schedule.eval("(function(){" + options.onItemSelected + "})()", { + 'item':item, + 'event':event, + 'view':view + }); + } + if (result === false) { + return false; } if (_this.submitEventFunction != null) { - _this.submitEventFunction({}, + _this.submitEventFunction(event, null, itemSelectedEventName, item.id, - null, null, null, null, null, null + null, null, null, null, null, function(request, event, data) { + if (options.onItemSelectedComplete != null) { + RichFaces.Schedule.eval("(function(){" + options.onItemSelectedComplete + "})()", { + 'item':item, + 'event':event, + 'view':view, + 'request':request, + 'data':data + }); + } + } ); } + return result; }; - var dayClick = function(date, allDay, event) { + var dayClick = function(date, allDay, event, view) { + var result; if (options.onDateSelected != null) { - var result = eval("(function(){" + options.onDateSelected + "})()"); - if (result != null) { - throw "return not allowed in onDaySelect"; - } + result = RichFaces.Schedule.eval("(function(){" + options.onDateSelected + "})()", { + 'date':date, + 'allDay':allDay, + 'event':event, + 'view':view + }); + } + if (result === false) { + return false; } if (_this.submitEventFunction != null) { - _this.submitEventFunction({}, + _this.submitEventFunction(event, null, daySelectedEventName, - null, formatDateParam(date), null, null, null, allDay, null + null, formatDateParam(date), null, null, null, allDay, function(request, event, data) { + if (options.onDateSelectedComplete != null) { + RichFaces.Schedule.eval("(function(){" + options.onDateSelectedComplete + "})()", { + 'date':date, + 'allDay':allDay, + 'request':request, + 'event':event, + 'view':view, + 'data':data + }); + } + } ); } + return result; }; var selectedView; - //TODO how to hide all (except for view param) scopeChain from code in options.onViewDisplay? - var viewDisplay = function(view) { - if (options.onViewDisplay != null) { - var result = eval("(function(){" + options.onViewDisplay + "})()"); - if (result != null) { - throw "return not allowed in onViewDisplay"; - } - } + var viewChanged = function(view) { if (selectedView != view && selectedView != undefined) { + if (options.onViewChanged != null) { + RichFaces.Schedule.eval("(function(){" + options.onViewChanged + "})()", { + 'view':view + }); + } if (_this.submitEventFunction != null) { _this.submitEventFunction({}, view.name, viewChangedEventName, - null, null, null, null, null, null, null + null, null, null, null, null, null, function(request, event, data) { + if (options.onViewChangedComplete != null) { + RichFaces.Schedule.eval("(function(){" + options.onViewChangedComplete + "})()", { + 'view':view, + 'request':request, + 'data':data + }); + } + } ); } } selectedView = view; }; - var onDateRangeSelected = function(startDate, endDate, allDay) { + var onDateRangeSelected = function(startDate, endDate, allDay, view) { if (!component.fullCalendar('option', 'selectable')) { - return; + return false; } + var result; if (options.onDateRangeSelected != null) { - var result = eval("(function(){" + options.onDateRangeSelected + "})()"); - if (result != null) { - return; - } + result = RichFaces.Schedule.eval("(function(){" + options.onDateRangeSelected + "})()", { + 'startDate':startDate, + 'endDate':endDate, + 'allDay':allDay, + 'view':view + }); + } + if (result === false) { + /** + * Unselect must be in all three places below in order to + * avoid situation where, while event is being sent via ajax + * to server, client side selection disapeares. + * Current implementation shortens delay between selection + * disapearing and potentialy created event appearing. + */ + component.fullCalendar('unselect'); + return false; } if (_this.submitEventFunction != null) { _this.submitEventFunction({}, @@ -209,11 +353,22 @@ window.RichFaces.Schedule = (function() { function(request, event, data) { component.fullCalendar('refetchEvents'); component.fullCalendar('unselect'); + if (options.onDateRangeSelected != null) { + RichFaces.Schedule.eval("(function(){" + options.onDateRangeSelectedComplete + "})()", { + 'startDate':startDate, + 'endDate':endDate, + 'allDay':allDay, + 'view':view, + 'request':request, + 'data':data + }); + } } ); } else { component.fullCalendar('unselect'); } + return result; }; options = jQuery.extend({ events: fillCalendarFunction, @@ -226,14 +381,26 @@ window.RichFaces.Schedule = (function() { eventClick: itemClick, eventMouseover: itemMouseover, eventMouseout: itemMouseout, - viewDisplay: viewDisplay, + viewDisplay: viewChanged, dayClick: dayClick, select: onDateRangeSelected }, options); jQuery(document).ready(function() { component = jQuery(elt).fullCalendar(options); + elt.component = _this; + _this.component = component; }); }; }()); -window.RichFaces.Schedule.prototype.messages = {}; \ No newline at end of file +window.RichFaces.Schedule.prototype.refetchItems = function() { + this.component.fullCalendar('refetchEvents'); +}; +window.RichFaces.Schedule.prototype.messages = {}; +window.RichFaces.Schedule.eval = function(template, object) { + var value = ''; + with (object) { + value = eval(template); + } + return value; +}; \ No newline at end of file diff --git a/src/main/resources/org/richfaces/renderkit/html/scripts/ui.core.js b/src/main/resources/org/richfaces/renderkit/html/scripts/ui.core.js index 5493e0a..698d6a0 100644 --- a/src/main/resources/org/richfaces/renderkit/html/scripts/ui.core.js +++ b/src/main/resources/org/richfaces/renderkit/html/scripts/ui.core.js @@ -7,513 +7,530 @@ * * 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.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); diff --git a/src/main/resources/org/richfaces/renderkit/html/scripts/ui.draggable.js b/src/main/resources/org/richfaces/renderkit/html/scripts/ui.draggable.js index 0402f0e..d4eec22 100644 --- a/src/main/resources/org/richfaces/renderkit/html/scripts/ui.draggable.js +++ b/src/main/resources/org/richfaces/renderkit/html/scripts/ui.draggable.js @@ -12,755 +12,763 @@ */ (function($) { -$.widget("ui.draggable", $.extend({}, $.ui.mouse, { + $.widget("ui.draggable", $.extend({}, $.ui.mouse, { - _init: function() { + _init: function() { - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; + 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.options.addClasses && this.element.addClass("ui-draggable")); + (this.options.disabled && this.element.addClass("ui-draggable-disabled")); - this._mouseInit(); + 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(); - }, + 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) { + _mouseCapture: function(event) { - var o = this.options; + var o = this.options; - if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) - return false; + 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; + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) + return false; - return true; + return true; - }, + }, - _mouseStart: function(event) { + _mouseStart: function(event) { - var o = this.options; + var o = this.options; - //Create and append the visible helper - this.helper = this._createHelper(event); + //Create and append the visible helper + this.helper = this._createHelper(event); - //Cache the helper size - this._cacheHelperProportions(); + //Cache the helper size + this._cacheHelperProportions(); - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) - $.ui.ddmanager.current = this; + //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. - */ + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ - //Cache the margins of the original element - this._cacheMargins(); + //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(); + //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 - }; + //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 - }); + $.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; + //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); + //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(); + //Set a containment if given in the options + if (o.containment) + this._setContainment(); - //Call plugins and callbacks - this._trigger("start", event); + //Call plugins and callbacks + this._trigger("start", event); - //Recache the helper size - this._cacheHelperProportions(); + //Recache the helper size + this._cacheHelperProportions(); - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); + //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; - }, + 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) { + _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; - } + //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); + 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() { - $('
') - .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); - } -}); + 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() { + $('
') + .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); diff --git a/src/main/resources/org/richfaces/renderkit/html/scripts/ui.resizable.js b/src/main/resources/org/richfaces/renderkit/html/scripts/ui.resizable.js index 6172d6c..946f717 100644 --- a/src/main/resources/org/richfaces/renderkit/html/scripts/ui.resizable.js +++ b/src/main/resources/org/richfaces/renderkit/html/scripts/ui.resizable.js @@ -12,789 +12,803 @@ */ (function($) { -$.widget("ui.resizable", $.extend({}, $.ui.mouse, { + $.widget("ui.resizable", $.extend({}, $.ui.mouse, { - _init: function() { + _init: function() { - var self = this, o = this.options; - this.element.addClass("ui-resizable"); + 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 - }); + $.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)) { + //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' }); + //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( - $('
').css({ - position: this.element.css('position'), - width: this.element.outerWidth(), - height: this.element.outerHeight(), - top: this.element.css('top'), - left: this.element.css('left') - }) - ); + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $('
').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') - ); + //Overwrite the original this.element + this.element = this.element.parent().data( + "resizable", this.element.data('resizable') + ); - this.elementIsWrapper = true; + 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}); + //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'); + //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' })); + //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') }); + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css('margin') }); - // fix handlers offset - this._proportionallyResize(); + // 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) { + 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 = {}; + 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++) { + for (var i = 0; i < n.length; i++) { - var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; - var axis = $('
'); + var handle = $.trim(n[i]), hname = 'ui-resizable-' + handle; + var axis = $('
'); - // 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 }); + // 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'); - }; + //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); - } + //Insert into internal handles object and append to element + this.handles[handle] = '.ui-resizable-' + handle; + this.element.append(axis); + } - } + } + + this._renderAxis = function(target) { - this._renderAxis = function(target) { + target = target || this.element; - target = target || this.element; + for (var i in this.handles) { - for(var i in this.handles) { + if (this.handles[i].constructor == String) + this.handles[i] = $(this.handles[i], this.element).show(); - 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)) { - //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; - 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(); - //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(""); - //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); - target.css(padPos, padWrapper); + this._proportionallyResize(); - this._proportionallyResize(); + } - } + //TODO: What's that good for? There's not anything to be executed left + if (!$(this.handles[i]).length) + continue; - //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); - //TODO: make renderAxis a prototype function - this._renderAxis(this.element); + this._handles = $('.ui-resizable-handle', this.element) + .disableSelection(); - 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'; + } + }); - //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(); + } + }); + } - //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(); - //Initialize the mouse interaction - this._mouseInit(); + }, - }, + destroy: function() { - destroy: function() { + this._mouseDestroy(); - 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(); + }; - 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(); + } - //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); - this.originalElement.css('resize', this.originalResizeStyle); - _destroy(this.originalElement); + }, - }, + _mouseCapture: function(event) { - _mouseCapture: function(event) { + var handle = false; + for (var i in this.handles) { + if ($(this.handles[i])[0] == event.target) handle = true; + } - var handle = false; - for(var i in this.handles) { - if($(this.handles[i])[0] == event.target) handle = true; - } + return this.options.disabled || !!handle; - return this.options.disabled || !!handle; + }, - }, + _mouseStart: function(event) { - _mouseStart: function(event) { + var o = this.options, iniPos = this.element.position(), el = this.element; - var o = this.options, iniPos = this.element.position(), el = this.element; + this.resizing = true; + this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; - 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 }); + } - // 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' }); - //Opera fixing relative position - if ($.browser.opera && (/relative/).test(el.css('position'))) - el.css({ position: 'relative', top: 'auto', left: 'auto' }); + this._renderProxy(); - this._renderProxy(); + var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); - 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; + } - 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 }; - //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); - //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); - 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; + }, - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; - }, + _mouseDrag: function(event) { - _mouseDrag: function(event) { + //Increase performance, avoid regex + var el = this.helper, o = this.options, props = {}, + self = this, smp = this.originalMousePosition, a = this.axis; - //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; - 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; - // 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); - if (this._aspectRatio || event.shiftKey) - data = this._updateRatio(data, event); + data = this._respectSize(data, event); - data = this._respectSize(data, event); + // plugins callbacks need to be called first + this._propagate("resize", 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" + }); - 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(); - if (!this._helper && this._proportionallyResizeElements.length) - this._proportionallyResize(); + this._updateCache(data); - this._updateCache(data); + // calling the user callback at the end + this._trigger('resize', event, this.ui()); - // calling the user callback at the end - this._trigger('resize', event, this.ui()); + return false; + }, - return false; - }, + _mouseStop: function(event) { - _mouseStop: function(event) { + this.resizing = false; + var o = this.options, self = this; - 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; - 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; - var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + if (!o.animate) + this.element.css($.extend(s, { top: top, left: left })); - if (!o.animate) - this.element.css($.extend(s, { top: top, left: left })); + self.helper.height(self.size.height); + self.helper.width(self.size.width); - self.helper.height(self.size.height); - self.helper.width(self.size.width); + if (this._helper && !o.animate) this._proportionallyResize(); + } - if (this._helper && !o.animate) this._proportionallyResize(); - } + $('body').css('cursor', 'auto'); - $('body').css('cursor', 'auto'); + this.element.removeClass("ui-resizable-resizing"); - this.element.removeClass("ui-resizable-resizing"); + this._propagate("stop", event); - this._propagate("stop", event); + if (this._helper) this.helper.remove(); + return false; - 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; + }, - _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) { - _updateRatio: function(data, event) { + var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - 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 (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); + } - 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; + }, - return data; - }, + _respectSize: function(data, event) { - _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); - 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; - 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); - 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; - 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; - // 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; + }, - return data; - }, + _proportionallyResize: function() { - _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 || $('
'); + + // 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); - 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 || $('
'); - - // 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 - } -}); + if (/document/.test(oc) || oc == document) { + self.containerOffset = { left: 0, top: 0 }; + self.containerPosition = { left: 0, top: 0 }; -/* - * 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 - }; - } - }, + self.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } - 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; - } + // 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.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 }); + self.containerOffset = element.offset(); + self.containerPosition = element.position(); + self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - if (self._helper && !o.animate && (/static/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - } -}); + 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); -$.ui.plugin.add("resizable", "ghost", { - - start: function(event, ui) { + self.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, - 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; - } - } + 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 num = function(v) { + return parseInt(v, 10) || 0; + }; -var isNumber = function(value) { - return !isNaN(parseInt(value, 10)); -}; + var isNumber = function(value) { + return !isNaN(parseInt(value, 10)); + }; })(jQuery); diff --git a/src/main/templates/org/richfaces/htmlSchedule.jspx b/src/main/templates/org/richfaces/htmlSchedule.jspx index 2d5e2fa..d2a78b3 100644 --- a/src/main/templates/org/richfaces/htmlSchedule.jspx +++ b/src/main/templates/org/richfaces/htmlSchedule.jspx @@ -16,6 +16,7 @@ org.ajax4jsf.javascript.AjaxScript, /org/ajax4jsf/javascript/scripts/form.js, /org/richfaces/renderkit/html/scripts/form.js, + /org/richfaces/renderkit/html/scripts/utils.js, /org/richfaces/renderkit/html/scripts/jquery/jquery.js, /org/richfaces/renderkit/html/scripts/ui.core.js, /org/richfaces/renderkit/html/scripts/ui.draggable.js, @@ -31,6 +32,6 @@ x:passThruWithExclusions="value,name,type,id"> \ No newline at end of file