diff --git a/ui/assembly/pom.xml b/ui/assembly/pom.xml new file mode 100644 index 0000000..45d0c45 --- /dev/null +++ b/ui/assembly/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + + org.richfaces.sandbox + ui + 3.3.4-SNAPSHOT + + org.richfaces.sandbox.ui + richfaces-assembly + assembly + jar + + + + + org.richfaces.cdk + maven-cdk-plugin + 3.3.4-SNAPSHOT + + + org.richfaces + RichFaces Sandbox Components + + + sandbox + sandbox + http://richfaces.org/sandbox + richfaces-sandbox + assembly + + + + **/basic.xcss, **/basic_classes.xcss, **/basic_both.xcss, **/extended.xcss, **/extended_classes.xcss, **/extended_both.xcss, **/skin*.xcss, **/tiny_mce/**, **/org/richfaces/renderkit/html/css/simple.xcss, **/org/richfaces/renderkit/html/css/violetRays.xcss + org/richfaces/skin.xcss + true + + + + + assembly + + + + + + maven-jar-plugin + 2.3.2 + + + ${project.build.directory}/dist + + + + + + + + \ No newline at end of file diff --git a/ui/coordinatesGrid-sm/coordinatesGrid.iml b/ui/coordinatesGrid-sm/coordinatesGrid.iml new file mode 100755 index 0000000..bc4f3dd --- /dev/null +++ b/ui/coordinatesGrid-sm/coordinatesGrid.iml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/coordinatesGrid-sm/pom.xml b/ui/coordinatesGrid-sm/pom.xml new file mode 100755 index 0000000..de50718 --- /dev/null +++ b/ui/coordinatesGrid-sm/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + org.richfaces.sandbox + ui + 3.3.4-SNAPSHOT + + org.richfaces.sandbox.ui + coordinatesGrid-sm + coordinatesGrid-sm + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces.sandbox.ui + + coordinatesGrid + http://richfaces.org/coordinatesGrid + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + + diff --git a/ui/coordinatesGrid-sm/src/main/config/component/coordinatesGrid.xml b/ui/coordinatesGrid-sm/src/main/config/component/coordinatesGrid.xml new file mode 100755 index 0000000..ca3f27a --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/config/component/coordinatesGrid.xml @@ -0,0 +1,129 @@ + + + ]> + + + + org.richfaces.CoordinatesGrid + org.richfaces.CoordinatesGrid + org.richfaces.component.html.HtmlCoordinatesGrid + org.richfaces.component.UICoordinatesGrid + + + + + org.richfaces.component.renderkit.html.CoordinatesGridRenderer + + + + coordinatesGrid + org.richfaces.taglib.CoordinatesGridTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + org.richfaces.taglib.CoordinatesGridTagHandler + com.sun.facelets.tag.jsf.ComponentHandler + + &ui_output_attributes; + &ajax_component_attributes; + &html_style_attributes; + + switchType + java.lang.String + + null + + + widgetVar + java.lang.String + + null + + + rows + java.lang.Integer + + null + + + cols + java.lang.Integer + + null + + + rowIndexVar + java.lang.String + + null + + + colIndexVar + java.lang.String + + null + + + rowHeaderText + java.lang.String + + null + + + colHeaderText + java.lang.String + + null + + + rowHeaderPosition + java.lang.String + + null + + + colHeaderPosition + java.lang.String + + null + + + selectable + boolean + + false + + + onselect + java.lang.String + + + null + + + onbeforeselect + java.lang.String + + + null + + + onclick + java.lang.String + + + null + + + + selectionListener + javax.faces.el.MethodBinding + org.richfaces.component.event.CoordinatesSelectionEvent + + + diff --git a/ui/coordinatesGrid-sm/src/main/config/component/gridItem.xml b/ui/coordinatesGrid-sm/src/main/config/component/gridItem.xml new file mode 100755 index 0000000..bdceb5f --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/config/component/gridItem.xml @@ -0,0 +1,58 @@ + + + + + + org.richfaces.CoordinatesGridItem + org.richfaces.Schedule + org.richfaces.component.html.HtmlCoordinatesGridItem + org.richfaces.component.UICoordinatesGridItem + + + + + coordinatesGridItem + org.richfaces.taglib.CoordinatesGridItemTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + &ui_component_attributes; + + + styleClass + java.lang.String + + + null + + + + text + java.lang.String + + + + + x + int + + + + + y + int + + + + + + diff --git a/ui/coordinatesGrid-sm/src/main/config/component/listeners.ent b/ui/coordinatesGrid-sm/src/main/config/component/listeners.ent new file mode 100755 index 0000000..5e05f9e --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/config/component/listeners.ent @@ -0,0 +1,35 @@ + + selectionListener + + binding + org.richfaces.coordinatesGridSelectionListener + The attribute takes a value-binding expression for a component property of + a backing bean + + + + org.richfaces.component.event.CoordinatesSelectionListener + + + org.richfaces.component.event.CoordinatesGridEventsProducer + + + org.richfaces.component.event.CoordinatesSelectionEvent + + + + org.richfaces.taglib.CoordinatesSelectionListenerTagHandler + + + + + org.richfaces.taglib.CoordinatesSelectionListenerTag + + + + + type + java.lang.String + The fully qualified Java class name for the listener + + \ No newline at end of file diff --git a/ui/coordinatesGrid-sm/src/main/config/component/readme b/ui/coordinatesGrid-sm/src/main/config/component/readme new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/config/component/readme diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/UICoordinatesGrid.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/UICoordinatesGrid.java new file mode 100755 index 0000000..b961b2d --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/UICoordinatesGrid.java @@ -0,0 +1,313 @@ +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.CoordinatesGridEventsProducer; +import org.richfaces.component.event.CoordinatesRefreshEvent; +import org.richfaces.component.event.CoordinatesSelectionEvent; +import org.richfaces.component.event.CoordinatesSelectionListener; +import org.richfaces.component.model.SquareRange; + +import javax.el.ELContext; +import javax.el.ValueExpression; +import javax.faces.component.UIComponent; +import javax.faces.component.UIComponentBase; +import javax.faces.context.FacesContext; +import javax.faces.el.MethodBinding; +import javax.faces.event.AbortProcessingException; +import javax.faces.event.FacesEvent; +import javax.faces.model.ArrayDataModel; +import javax.faces.model.DataModel; +import javax.faces.model.ListDataModel; +import javax.faces.model.ResultDataModel; +import javax.faces.model.ResultSetDataModel; +import javax.faces.model.ScalarDataModel; +import javax.servlet.jsp.jstl.sql.Result; +import java.io.IOException; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class UICoordinatesGrid extends UIComponentBase implements CoordinatesGridEventsProducer, AjaxComponent { + + public static final String COMPONENT_TYPE = "org.richfaces.CoordinatesGrid"; + public static final String COMPONENT_FAMILY = "org.richfaces.CoordinatesGrid"; + private DataModel model; + + public abstract Object getValue(); + + public abstract void setValue(Object value); + + public abstract String getVar(); + + public abstract void setVar(String var); + + public abstract String getRowIndexVar(); + + public abstract void setRowIndexVar(String rowIndexVar); + + public abstract String getColIndexVar(); + + public abstract void setColIndexVar(String var); + + public abstract String getRowHeaderText(); + + public abstract void setRowHeaderText(String rowHeaderText); + + public abstract String getColHeaderText(); + + public abstract void setColHeaderText(String colHeaderText); + + public abstract String getColHeaderPosition(); + + public abstract void setColHeaderPosition(String colHeaderPosition); + + public abstract String getRowHeaderPosition(); + + public abstract void setRowHeaderPosition(String rowHeaderPosition); + + public abstract String getSwitchType(); + + public abstract void setSwitchType(String switchType); + + public abstract String getWidgetVar(); + + public abstract void setWidgetVar(String widgetVar); + + public abstract String getOnclick(); + + public abstract void setOnclick(String onclick); + + public abstract String getOnbeforeselect(); + + public abstract void setOnbeforeselect(String onbeforeselect); + + public abstract String getOnselect(); + + public abstract void setOnselect(String onselect); + + public abstract Integer getRows(); + + public abstract void setRows(Integer rows); + + public abstract Integer getCols(); + + public abstract void setCols(Integer cols); + + public abstract boolean isSelectable(); + + public abstract void setSelectable(boolean selectable); + + public abstract MethodBinding getSelectionListener(); + + public abstract void setSelectionListener(MethodBinding listener); + + @Override + public void broadcast(FacesEvent event) throws AbortProcessingException { + if (event instanceof CoordinatesSelectionEvent) { + super.broadcast(event); + new AjaxEvent(this).queue(); + CoordinatesSelectionEvent selectionEvent = (CoordinatesSelectionEvent) event; + FacesContext facesContext = getFacesContext(); + AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); + MethodBinding expression = getSelectionListener(); + if (expression != null) { + expression.invoke(facesContext, new Object[]{event}); + } + try { + ajaxContext.getResponseDataMap().put("_ajax:coordinatesGridData", getData(selectionEvent.getStartX(), selectionEvent.getStartY(), selectionEvent.getEndX(), selectionEvent.getEndY(), false)); + } catch (IOException ex) { + getFacesContext().getExternalContext().log("Cannot get coordinates grid data", ex); + } + + } else if (event instanceof CoordinatesRefreshEvent) { + super.broadcast(event); + new AjaxEvent(this).queue(); + CoordinatesRefreshEvent refreshEvent = (CoordinatesRefreshEvent) event; + FacesContext facesContext = getFacesContext(); + AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); + try { + ajaxContext.getResponseDataMap().put("_ajax:coordinatesGridData", getData(refreshEvent.getStartX(), refreshEvent.getStartY(), refreshEvent.getEndX(), refreshEvent.getEndY(), true)); + } catch (IOException ex) { + getFacesContext().getExternalContext().log("Cannot get coordinates grid data", ex); + } + + } 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()); + } + } + + public void addCoordinatesSelectionListener(CoordinatesSelectionListener listener) { + addFacesListener(listener); + } + + public void removeCoordinatesSelectionListener(CoordinatesSelectionListener listener) { + removeFacesListener(listener); + } + + public CoordinatesSelectionListener[] getCoordinatesSelectionListeners() { + return (CoordinatesSelectionListener[]) getFacesListeners(CoordinatesSelectionListener.class); + } + + protected DataModel getDataModel() { + // Return any previously cached DataModel instance + if (this.model != null) { + return (model); + } + + // Synthesize a DataModel around our current value if possible + Object current = getValue(); + if (current == null) { + setDataModel(new ListDataModel(Collections.EMPTY_LIST)); + } else if (current instanceof DataModel) { + setDataModel((DataModel) current); + } else if (current instanceof List) { + setDataModel(new ListDataModel((List) current)); + } else if (Object[].class.isAssignableFrom(current.getClass())) { + setDataModel(new ArrayDataModel((Object[]) current)); + } else if (current instanceof ResultSet) { + setDataModel(new ResultSetDataModel((ResultSet) current)); + } else if (current instanceof Result) { + setDataModel(new ResultDataModel((Result) current)); + } else { + setDataModel(new ScalarDataModel(current)); + } + return (model); + + } + + public void setDataModel(DataModel model) { + this.model = model; + } + + public Map getData(int startX, int startY, int endX, int endY, boolean includeHeaders) throws IOException { + Map responseData = new HashMap(); + if (includeHeaders) { + responseData.put("rowHeaders", getRowHeadersData()); + responseData.put("colHeaders", getColHeadersData()); + } + ELContext elContext = getFacesContext().getELContext(); + ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getVar() + "}", Object.class); + List> data = new ArrayList>(); + responseData.put("data", data); + DataModel dataModel = getDataModel(); + List elements = new ArrayList(); + if (dataModel instanceof ExtendedDataModel) { + final List keys = new ArrayList(); + DataVisitor visitor = new DataVisitor() { + + public void process(FacesContext context, Object rowKey, Object argument) throws IOException { + keys.add(rowKey); + } + }; + ((ExtendedDataModel) dataModel).walk(getFacesContext(), visitor, new SquareRange(startX, startY, endX, endY), null); + for (Object key : keys) { + ((ExtendedDataModel) dataModel).setRowKey(key); + if (dataModel.isRowAvailable()) { + elements.add(dataModel.getRowData()); + } + } + } else { + for (int i = 0; i < dataModel.getRowCount(); i++) { + dataModel.setRowIndex(i); + if (dataModel.isRowAvailable()) { + elements.add(dataModel.getRowData()); + } + } + } + + for (Object element : elements) { + valueExpression.setValue(elContext, element); + List firstDataElement = new ArrayList(); + for (UIComponent child : getChildren()) { + if (child instanceof UICoordinatesGridItem) { + UICoordinatesGridItem item = (UICoordinatesGridItem) child; + if (!item.isRendered()) { + continue; + } + firstDataElement.add(item.getX()); + firstDataElement.add(item.getY()); + String text = item.getText(); + if (text == null) { + text = ""; + } + firstDataElement.add(text.trim()); + String styleClass = item.getStyleClass(); + if (styleClass == null) { + styleClass = ""; + } + firstDataElement.add(styleClass.trim()); + data.add(firstDataElement); + } + } + } + valueExpression.setValue(elContext, null); + return responseData; + } + + public List> getRowHeadersData() throws IOException { + ELContext elContext = getFacesContext().getELContext(); + ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getRowIndexVar() + "}", Object.class); + List> data = new ArrayList>(); + for (int i = 0; i < getRows(); i++) { + if (getRowIndexVar() != null) { + valueExpression.setValue(elContext, i); + } + Map row = new HashMap(); + data.add(row); + row.put("text", getRowHeaderText()); + } + if (getRowIndexVar() != null) { + valueExpression.setValue(elContext, null); + } + return data; + } + + public List> getColHeadersData() throws IOException { + ELContext elContext = getFacesContext().getELContext(); + ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getColIndexVar() + "}", Object.class); + List> data = new ArrayList>(); + for (int i = 0; i < getCols(); i++) { + if (getColIndexVar() != null) { + valueExpression.setValue(elContext, i); + } + Map col = new HashMap(); + data.add(col); + col.put("text", getColHeaderText()); + } + if (getColIndexVar() != null) { + valueExpression.setValue(elContext, null); + } + return data; + } +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/UICoordinatesGridItem.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/UICoordinatesGridItem.java new file mode 100755 index 0000000..b294eca --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/UICoordinatesGridItem.java @@ -0,0 +1,25 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UICoordinatesGridItem extends UIComponentBase { + + public static final String COMPONENT_TYPE = "org.richfaces.CoordinatesGridItem"; + public static final String COMPONENT_FAMILY = "org.richfaces.CoordinatesGrid"; + + public abstract String getStyleClass(); + + public abstract void setStyleClass(String styleClass); + + public abstract String getText(); + + public abstract void setText(String text); + + public abstract int getX(); + + public abstract void setX(int x); + + public abstract int getY(); + + public abstract void setY(int y); +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesGridEventsProducer.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesGridEventsProducer.java new file mode 100755 index 0000000..f8aa93b --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesGridEventsProducer.java @@ -0,0 +1,10 @@ +package org.richfaces.component.event; + +public interface CoordinatesGridEventsProducer { + + void addCoordinatesSelectionListener(CoordinatesSelectionListener listener); + + void removeCoordinatesSelectionListener(CoordinatesSelectionListener listener); + + CoordinatesSelectionListener[] getCoordinatesSelectionListeners(); +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesRefreshEvent.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesRefreshEvent.java new file mode 100644 index 0000000..fb4c04b --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesRefreshEvent.java @@ -0,0 +1,63 @@ +package org.richfaces.component.event; + +import javax.faces.component.UIComponent; +import javax.faces.event.FacesEvent; +import javax.faces.event.FacesListener; + +/** + * Created by IntelliJ IDEA. + * User: bernard + * Date: Oct 18, 2010 + * Time: 6:55:06 PM + */ +public class CoordinatesRefreshEvent extends FacesEvent { + + private int startX; + private int startY; + private int endX; + private int endY; + + public CoordinatesRefreshEvent(int startX, int startY, int endX, int endY, UIComponent component) { + super(component); + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + @Override + public boolean isAppropriateListener(FacesListener listener) { + return false; + } + + @Override + public void processListener(FacesListener listener) { + throw new UnsupportedOperationException(); + } + + public int getStartX() { + return startX; + } + + public int getStartY() { + return startY; + } + + public int getEndX() { + return endX; + } + + public int getEndY() { + return endY; + } + + @Override + public String toString() { + return "CoordinatesRefreshEvent{" + + "startX=" + startX + + ", startY=" + startY + + ", endX=" + endX + + ", endY=" + endY + + '}'; + } +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesSelectionEvent.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesSelectionEvent.java new file mode 100755 index 0000000..32c923f --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesSelectionEvent.java @@ -0,0 +1,63 @@ +package org.richfaces.component.event; + +import javax.faces.component.UIComponent; +import javax.faces.event.FacesEvent; +import javax.faces.event.FacesListener; + +/** + * Created by IntelliJ IDEA. + * User: bernard + * Date: Aug 17, 2010 + * Time: 2:59:13 PM + */ +public class CoordinatesSelectionEvent extends FacesEvent { + + private int startX; + private int startY; + private int endX; + private int endY; + + public CoordinatesSelectionEvent(int startX, int startY, int endX, int endY, UIComponent component) { + super(component); + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + @Override + public boolean isAppropriateListener(FacesListener listener) { + return listener instanceof CoordinatesSelectionListener; + } + + @Override + public void processListener(FacesListener listener) { + ((CoordinatesSelectionListener) listener).coordinatesSelected(this); + } + + public int getStartX() { + return startX; + } + + public int getStartY() { + return startY; + } + + public int getEndX() { + return endX; + } + + public int getEndY() { + return endY; + } + + @Override + public String toString() { + return "CoordinatesSelectionEvent{" + + "startX=" + startX + + ", startY=" + startY + + ", endX=" + endX + + ", endY=" + endY + + '}'; + } +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesSelectionListener.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesSelectionListener.java new file mode 100755 index 0000000..28c9557 --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/event/CoordinatesSelectionListener.java @@ -0,0 +1,15 @@ +package org.richfaces.component.event; + +import javax.faces.event.FacesListener; + +/** + * Created by IntelliJ IDEA. + * User: bernard + * Date: Aug 17, 2010 + * Time: 3:01:08 PM + */ +public interface CoordinatesSelectionListener extends FacesListener { + + void coordinatesSelected(CoordinatesSelectionEvent event); + +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/model/SquareRange.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/model/SquareRange.java new file mode 100755 index 0000000..d594d71 --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/model/SquareRange.java @@ -0,0 +1,53 @@ +package org.richfaces.component.model; + +import org.ajax4jsf.model.Range; + +public class SquareRange implements Range { + + private int startX; + private int startY; + private int endX; + private int endY; + + public SquareRange() { + } + + public SquareRange(int startX, int startY, int endX, int endY) { + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + public int getStartX() { + return startX; + } + + public void setStartX(int startX) { + this.startX = startX; + } + + public int getStartY() { + return startY; + } + + public void setStartY(int startY) { + this.startY = startY; + } + + public int getEndX() { + return endX; + } + + public void setEndX(int endX) { + this.endX = endX; + } + + public int getEndY() { + return endY; + } + + public void setEndY(int endY) { + this.endY = endY; + } +} diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/readme b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/readme new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/component/readme diff --git a/ui/coordinatesGrid-sm/src/main/java/org/richfaces/renderkit/html/CoordinatesGridRendererBase.java b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/renderkit/html/CoordinatesGridRendererBase.java new file mode 100755 index 0000000..946a50f --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/java/org/richfaces/renderkit/html/CoordinatesGridRendererBase.java @@ -0,0 +1,147 @@ +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.javascript.JSFunctionDefinition; +import org.ajax4jsf.javascript.JSObject; +import org.ajax4jsf.javascript.JSReference; +import org.ajax4jsf.renderkit.AjaxRendererUtils; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.richfaces.component.UICoordinatesGrid; +import org.richfaces.component.event.CoordinatesRefreshEvent; +import org.richfaces.component.event.CoordinatesSelectionEvent; + +import javax.faces.component.NamingContainer; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class CoordinatesGridRendererBase extends HeaderResourcesRendererBase { + + private static Log logger = LogFactory.getLog(CoordinatesGridRendererBase.class); + private static final String EVENT_TYPE_PARAM = "eventType"; + private static final String START_X_PARAM = "startX"; + private static final String END_X_PARAM = "endX"; + private static final String START_Y_PARAM = "startY"; + private static final String END_Y_PARAM = "endY"; + private static final String CALLBACK = "callback"; + private static final String SELECT_EVENT = "select"; + private static final String REFRESH_EVENT = "refresh"; + public static final String AJAX_MODE = "ajax"; + public static final String SERVER_MODE = "server"; + public static final String CLIENT_MODE = "client"; + + protected Class getComponentClass() { + return UICoordinatesGrid.class; + } + + @Override + protected void doDecode(FacesContext context, UIComponent component) { + super.doDecode(context, component); + UICoordinatesGrid uiCoordinatesGrid; + + if (component instanceof UICoordinatesGrid) { + uiCoordinatesGrid = (UICoordinatesGrid) component; + } else { + if (logger.isDebugEnabled()) { + logger.debug("No decoding necessary since the component " + component.getId() + + " is not an instance or a sub class of UIInplaceInput"); + } + return; + } + String startXParam = getFieldId(context, uiCoordinatesGrid, START_X_PARAM); + String startYParam = getFieldId(context, uiCoordinatesGrid, START_Y_PARAM); + String endXParam = getFieldId(context, uiCoordinatesGrid, END_X_PARAM); + String endYParam = getFieldId(context, uiCoordinatesGrid, END_Y_PARAM); + String eventTypeParam = getFieldId(context, uiCoordinatesGrid, EVENT_TYPE_PARAM); + + Map request = context.getExternalContext().getRequestParameterMap(); + + String startXString = request.get(startXParam); + String endXString = request.get(endXParam); + String startYString = request.get(startYParam); + String endYString = request.get(endYParam); + String eventType = request.get(eventTypeParam); + if ((uiCoordinatesGrid.isSelectable() && SELECT_EVENT.equals(eventType)) || REFRESH_EVENT.equals(eventType) && startXString != null && !"".equals(startXString)) { + try { + int startX = Integer.parseInt(startXString); + int startY = Integer.parseInt(startYString); + int endX = Integer.parseInt(endXString); + int endY = Integer.parseInt(endYString); + if (SELECT_EVENT.equals(eventType)) { + new CoordinatesSelectionEvent(startX, startY, endX, endY, uiCoordinatesGrid).queue(); + } else { + uiCoordinatesGrid.queueEvent(new CoordinatesRefreshEvent(startX, startY, endX, endY, uiCoordinatesGrid)); + } + } catch (Exception e) { + logger.error("Problem during decoding event for component " + component.getId() + " (params: " + startXParam + "=" + startXString + ";" + startYParam + "=" + startYString + ";" + endXParam + "=" + endXString + ";" + endYParam + "=" + endYString + ")"); + } + } + } + + protected String getFieldId(FacesContext context, UIComponent component, String attribute) { + return getUtils().clientId(context, component) + NamingContainer.SEPARATOR_CHAR + attribute; + } + + public void writeInitFunction(FacesContext context, UICoordinatesGrid component) throws IOException { + ResponseWriter writer = context.getResponseWriter(); + if (component.getWidgetVar() != null) { + writer.write("var " + component.getWidgetVar() + "="); + } + Map options = new HashMap(); + addOptionIfSet("onclick", component.getOnclick(), options); + addOptionIfSet("onbeforeselect", component.getOnbeforeselect(), options); + addOptionIfSet("onselect", component.getOnselect(), options); + addOptionIfSet("rows", component.getRows(), options); + addOptionIfSet("cols", component.getCols(), options); + addOptionIfSet("selectable", component.isSelectable(), options); + addOptionIfSet("colHeaderPosition", component.getColHeaderPosition(), options); + addOptionIfSet("rowHeaderPosition", component.getRowHeaderPosition(), options); + addOptionIfSet("data", component.getData(0, 0, component.getCols() - 1, component.getRows() - 1, true), options); + + writer.writeText(new JSObject("RichFaces.CoordinatesGrid", + component.getClientId(context), + options, + createSubmitEventFunction(context, component)).toScript(), null); + } + + protected Object createSubmitEventFunction(FacesContext context, UICoordinatesGrid component) { + JSFunction jsFunction; + Map params = new HashMap(); + params.put(getFieldId(context, component, EVENT_TYPE_PARAM), new JSReference(EVENT_TYPE_PARAM)); + params.put(getFieldId(context, component, START_X_PARAM), new JSReference(START_X_PARAM)); + params.put(getFieldId(context, component, START_Y_PARAM), new JSReference(START_Y_PARAM)); + params.put(getFieldId(context, component, END_X_PARAM), new JSReference(END_X_PARAM)); + params.put(getFieldId(context, component, END_Y_PARAM), new JSReference(END_Y_PARAM)); + if (isAjaxMode(component)) { + jsFunction = AjaxRendererUtils.buildAjaxFunction(component, context); + Map eventOptions = AjaxRendererUtils.buildEventOptions(context, component, params); + eventOptions.put("oncomplete", new JSReference(CALLBACK)); + jsFunction.addParameter(eventOptions); + } else if (SERVER_MODE.equals(component.getSwitchType())) { + jsFunction = new JSFunction("Richfaces.jsFormSubmit", + component.getClientId(context), + getUtils().getNestingForm(context, component).getClientId(context), + null, + params); + } else { + return null; + } + return new JSFunctionDefinition("event", EVENT_TYPE_PARAM, START_X_PARAM, START_Y_PARAM, END_X_PARAM, END_Y_PARAM, CALLBACK).addToBody(jsFunction); + } + + private void addOptionIfSet(String optionName, Object value, Map options) { + if (value != null && value != "") { + options.put(optionName, value); + } + } + + private boolean isAjaxMode(UICoordinatesGrid component) { + String mode = component.getSwitchType(); + return AJAX_MODE.equals(mode) || "".equals(mode) || null == mode; + } +} diff --git a/ui/coordinatesGrid-sm/src/main/resources/org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss b/ui/coordinatesGrid-sm/src/main/resources/org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss new file mode 100755 index 0000000..0da662b --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/resources/org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/coordinatesGrid-sm/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js b/ui/coordinatesGrid-sm/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js new file mode 100755 index 0000000..f8f3623 --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js @@ -0,0 +1,386 @@ +if (window.RichFaces == null) { + window.RichFaces = {}; +} +RichFaces.CoordinatesGrid = function(targetId, options, submitEventFunction) { + + var startX; + var startY; + var endX; + var endY; + var selecting = false; + this.target = document.getElementById(targetId); + var _this = this; + this.options = jQuery.extend({}, this.options, options); + if (this.target.component != null && this.target.component.destroy != null) { + this.target.component.destroy(); + } + this.target.component = this; + + var getY = function(o) { + if (o == null || o.parentNode == null || o.parentNode.rowIndex == null) { + throw "HTMLTableCellElement expected"; + } + return o.parentNode.rowIndex - 1; + }; + var getX = function(o) { + if (o == null || o.cellIndex == null) { + throw "HTMLTableCellElement expected"; + } + return o.cellIndex; + }; + /** + * Updates element on the grid with data from initial or ajax request. + * @param data array of data where: 0: x, 1: y, 2: text, 3: css class + */ + var updateElementFromData = function(data) { + var element = _this.getElementAt(data[0], data[1]); + if (element != null) { + _this.updateElement(element, {innerHTML:data[2],className:data[3]}); + } + return element; + }; + var updateRowHeaders = function(headers) { + jQuery.each(headers, function(index) { + var text = this.text; + delete this.text; + if (text != null) { + this.innerHTML = text; + } + if (_this.isLeftRowHeadersVisible()) { + _this.updateElement(_this.getElementAt(-1, index), this); + } + if (_this.isRightRowHeadersVisible()) { + _this.updateElement(_this.getElementAt(_this.options.cols, index), this); + } + }); + }; + var updateColHeaders = function(headers) { + jQuery.each(headers, function(index) { + var text = this.text; + delete this.text; + if (text != null) { + this.innerHTML = text; + } + if (_this.isTopColHeadersVisible()) { + _this.updateElement(_this.getElementAt(index, -1), this); + } + if (_this.isBottomColHeadersVisible()) { + _this.updateElement(_this.getElementAt(index, _this.options.rows), this); + } + }); + }; + var updateElementsWithRequestData = function(request, _startX, _startY, _endX, _endY) { + /** Server component should respond with data of elements matching selection */ + var data = request.getJSON('_ajax:coordinatesGridData'); + if (data != undefined) { + var elementsFromUpdate = []; + jQuery.each(data.data, function() { + var element = updateElementFromData(this); + if (element != null) { + elementsFromUpdate.push(element); + } + }); + if (data.rowHeaders != null) { + updateRowHeaders(data.rowHeaders); + } + if (data.colHeaders != null) { + updateColHeaders(data.colHeaders); + } + jQuery.each(_this.getElements(_startX, _startY, _endX, _endY), function() { + var visitedCell = this; + var exists = false; + jQuery.each(elementsFromUpdate, function() { + if (this == visitedCell) { + exists = true; + } + }); + if (!exists) { + this.className = ""; + this.innerHTML = ""; + } + }); + } + }; + var mouseDownHanlder = function() { + if (selecting) { + mouseUpHanlder.apply(this); + } else if (options.selectable) { + startX = getX(this); + startY = getY(this); + selecting = true; + } + }; + var mouseUpHanlder = function() { + if (!selecting) { + return; + } + endX = getX(this); + endY = getY(this); + selecting = false; + highlightSelection(); + if (_this.options.onbeforeselect != null) { + var result; + if (typeof _this.options.onbeforeselect == "function") { + result = _this.options.onbeforeselect(_this, _startX, _startY, _endX, _endY); + } else { + result = RichFaces.CoordinatesGrid.eval("(function(){" + _this.options.onbeforeselect + "})()", { + 'startX':startX, + 'startY':startY, + 'endX':endX, + 'endY':endY, + 'component':_this + }); + } + if (result === false) { + return; + } + } + /** + * endX and endY will be reset before ajax response comes. + */ + var _endX = endX; + var _endY = endY; + var _startX = startX; + var _startY = startY; + /** Notify server side */ + if (submitEventFunction != null) { + submitEventFunction({}, "select", _this.indexToCoordX(startX), _this.indexToCoordY(startY), _this.indexToCoordX(endX), _this.indexToCoordY(endY), + function(request, event, data) { + updateElementsWithRequestData(request, _startX, _startY, _endX, _endY); + + if (_this.options.onselect != null) { + if (typeof _this.options.onselect == "function") { + _this.options.onselect(_this, _startX, _startY, _endX, _endY); + } else { + RichFaces.CoordinatesGrid.eval("(function(){" + _this.options.onselect + "})()", { + 'startX':_startX, + 'startY':_startY, + 'endX':_endX, + 'endY':_endY, + 'component':_this + }); + } + } + delete _endX,_endY,_startX,_startY; + }); + } + endX = -1; + endY = -1; + highlightSelection(); + }; + var mouseOverHandler = function() { + if (!selecting) { + return; + } + endX = getX(this); + endY = getY(this); + highlightSelection(); + }; + var highlightSelection = function() { + jQuery("td", _this.target).each(function() { + var x = getX(this); + var y = getY(this); + if (startX <= x && x <= endX && startY <= y && y <= endY) { + jQuery(this).addClass(_this.options.highlightClass); + } else { + jQuery(this).removeClass(_this.options.highlightClass); + } + }); + }; + var clickHandler = function() { + if (_this.options.onclick != null) { + if (typeof _this.options.onclick == "function") { + _this.options.onclick(_this, getX(this), getY(this)); + } else { + RichFaces.CoordinatesGrid.eval("(function(){" + _this.options.onclick + "})()", { + 'x':getX(this), + 'y':getY(this), + 'component':_this + }); + } + } + }; + this.getElements = function(startX, startY, endX, endY) { + var elements = []; + jQuery("td", _this.target).each(function() { + var x = getX(this); + var y = getY(this); + if (startX <= x && x <= endX && startY <= y && y <= endY) { + elements.push(this); + } + }); + return elements; + }; + this.refresh = function(_startX, _startY, _endX, _endY) { + if (_startX == null && _startY == null && _endX == null && _endY == null) { + _startX = 0; + _startY = 0; + _endX = this.options.cols; + _endY = this.options.rows; + } + submitEventFunction({}, "refresh", _startX, _startY, _endX, _endY, function(request, event, data) { + updateElementsWithRequestData(request, _startX, _startY, _endX, _endY); + delete _endX,_endY,_startX,_startY; + }); + }; + /** + * @param element HTMLTableCellElement + * @param options options used to extend element, i.e. {className:'important'} + **/ + this.updateElement = function(element, options) { + if (options.className) { + options.className = "rich-table-cell " + options.className; + } + jQuery.extend(element, options); + }; + this.getElementAt = function(x, y) { + return table[0].rows[y + 1 + (_this.isTopColHeadersVisible() ? 1 : 0)].cells[x + (y > -1 && _this.isLeftRowHeadersVisible() ? 1 : 0)]; + }; + /** + * Create grid. + */ + var table = jQuery("
"); + (function() { + table.appendTo(_this.target); + var cell; + /** + * Function used for appending headers without filling them with text + */ + var appendHeaders = function(targetElement) { + var row = jQuery(""); + row.appendTo(targetElement); + row.addClass(_this.options.colHeaderClass); + if (_this.options.data.rowHeaders != null) { + if (targetElement[0].tagName != 'THEAD' && (_this.options.rowHeaderPosition == 'both' || _this.options.rowHeaderPosition == 'left')) { + cell = jQuery(""); + cell.appendTo(row); + } + for (var x = 0; x < _this.options.cols; x++) { + cell = jQuery(""); + cell.appendTo(row); + } + if (_this.options.rowHeaderPosition == 'both' || _this.options.rowHeaderPosition == 'right') { + cell = jQuery(""); + cell.appendTo(row); + } + } + }; + var thead = jQuery(""); + thead.appendTo(table); + /** Append custom SailMedia headers */ + row = jQuery(""); + row.appendTo(thead); + row.addClass(_this.options.colHeaderClass); + cell = jQuery(""); + cell.appendTo(row); + cell = jQuery(""); + cell.appendTo(row); + /** Append top column headers */ + if (_this.isTopColHeadersVisible()) { + appendHeaders(thead); + } + for (var y = 0; y < _this.options.rows; y++) { + var row = jQuery(""); + row.appendTo(table); + /** Append left row headers */ + if (_this.isLeftRowHeadersVisible()) { + cell = jQuery(""); + cell.appendTo(row); + cell.addClass(_this.options.rowHeaderClass); + } + /** Append regular cells */ + for (var x = 0; x < _this.options.cols; x++) { + cell = jQuery(""); + cell.appendTo(row); + cell.mouseup(mouseUpHanlder); + cell.mousedown(mouseDownHanlder); + cell.mouseover(mouseOverHandler); + cell.click(clickHandler); + } + /** Append right row headers */ + if (_this.isRightRowHeadersVisible()) { + cell = jQuery(""); + cell.appendTo(row); + cell.addClass(_this.options.rowHeaderClass); + } + } + var tfoot = jQuery(""); + tfoot.appendTo(table); + /** Append bottom column headers */ + if (_this.isBottomColHeadersVisible()) { + appendHeaders(tfoot); + } + /** Append custom SailMedia footer */ + row = jQuery(""); + row.appendTo(tfoot); + row.addClass(_this.options.colHeaderClass); + cell = jQuery(""); + cell.appendTo(row); + cell = jQuery(""); + cell.appendTo(row); + /** Customize headers - className and text */ + updateRowHeaders(_this.options.data.rowHeaders); + updateColHeaders(_this.options.data.colHeaders); + + /** Customize regular cell */ + if (_this.options.data.data != null) { + jQuery.each(_this.options.data.data, function() { + updateElementFromData(this) + }); + } + /** Disable text selection */ + if (options.selectable) { + table.attr('unselectable', 'on').css('MozUserSelect', 'none').bind('selectstart.ui', function() { + return false; + }); + } + })(); +} + ; +RichFaces.CoordinatesGrid.prototype.options = { + rows: 10, + cols: 10, + highlightClass: 'highlight', + colHeaderPosition: 'bottom', + rowHeaderPosition: 'left' +}; +RichFaces.CoordinatesGrid.prototype.select = function(func) { + this.options.onselect = func; +}; +RichFaces.CoordinatesGrid.prototype.destroy = function() { + jQuery("table", this.target).remove(); + delete this.target.component; +}; +RichFaces.CoordinatesGrid.prototype.isLeftRowHeadersVisible = function() { + return this.options.data.rowHeaders != null && (this.options.rowHeaderPosition == 'both' || this.options.rowHeaderPosition == 'left'); +}; +RichFaces.CoordinatesGrid.prototype.isRightRowHeadersVisible = function() { + return this.options.data.rowHeaders != null && (this.options.rowHeaderPosition == 'both' || this.options.rowHeaderPosition == 'right'); +}; +RichFaces.CoordinatesGrid.prototype.isTopColHeadersVisible = function() { + return this.options.data.colHeaders != null && (this.options.colHeaderPosition == 'both' || this.options.colHeaderPosition == 'top'); +}; +RichFaces.CoordinatesGrid.prototype.isBottomColHeadersVisible = function() { + return this.options.data.colHeaders != null && (this.options.colHeaderPosition == 'both' || this.options.colHeaderPosition == 'bottom'); +}; +RichFaces.CoordinatesGrid.prototype.indexToCoordX = function(index) { + return index - (this.isLeftRowHeadersVisible() ? 1 : 0); +}; +RichFaces.CoordinatesGrid.prototype.indexToCoordY = function(index) { + return index - (this.isTopColHeadersVisible() ? 1 : 0); +}; +/** + * This function evaluates code in template with object in ScopeChain. + * This is usefull if you need to evaluate code that uses member names + * that colide with external names that the code refers to. + * There is almost exact method in utils.js called Richfaces.eval, + * but it swallows exception thrown during evaluation, which makes debugging + * hard. + */ +RichFaces.CoordinatesGrid.eval = function(template, object) { + var value = ''; + with (object) { + value = eval(template); + } + return value; +}; diff --git a/ui/coordinatesGrid-sm/src/main/templates/htmlCoordinatesGrid.jspx b/ui/coordinatesGrid-sm/src/main/templates/htmlCoordinatesGrid.jspx new file mode 100755 index 0000000..dfa698d --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/templates/htmlCoordinatesGrid.jspx @@ -0,0 +1,36 @@ + + + + /org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss + + new org.ajax4jsf.javascript.PrototypeScript(), + new org.ajax4jsf.javascript.AjaxScript(), + /org/richfaces/renderkit/html/scripts/jquery/jquery.js, + /org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js + + + + + + + + +
+ +
+
\ No newline at end of file diff --git a/ui/coordinatesGrid-sm/src/main/templates/readme b/ui/coordinatesGrid-sm/src/main/templates/readme new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/ui/coordinatesGrid-sm/src/main/templates/readme diff --git a/ui/coordinatesGrid/pom.xml b/ui/coordinatesGrid/pom.xml new file mode 100755 index 0000000..5ca731b --- /dev/null +++ b/ui/coordinatesGrid/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + org.richfaces.sandbox + ui + 3.3.4-SNAPSHOT + + org.richfaces.sandbox.ui + coordinatesGrid + coordinatesGrid + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces.sandbox.ui + + coordinatesGrid + http://richfaces.org/sandbox/coordinatesGrid + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + + + diff --git a/ui/coordinatesGrid/src/main/config/component/coordinatesGrid.xml b/ui/coordinatesGrid/src/main/config/component/coordinatesGrid.xml new file mode 100755 index 0000000..ca3f27a --- /dev/null +++ b/ui/coordinatesGrid/src/main/config/component/coordinatesGrid.xml @@ -0,0 +1,129 @@ + + + ]> + + + + org.richfaces.CoordinatesGrid + org.richfaces.CoordinatesGrid + org.richfaces.component.html.HtmlCoordinatesGrid + org.richfaces.component.UICoordinatesGrid + + + + + org.richfaces.component.renderkit.html.CoordinatesGridRenderer + + + + coordinatesGrid + org.richfaces.taglib.CoordinatesGridTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + org.richfaces.taglib.CoordinatesGridTagHandler + com.sun.facelets.tag.jsf.ComponentHandler + + &ui_output_attributes; + &ajax_component_attributes; + &html_style_attributes; + + switchType + java.lang.String + + null + + + widgetVar + java.lang.String + + null + + + rows + java.lang.Integer + + null + + + cols + java.lang.Integer + + null + + + rowIndexVar + java.lang.String + + null + + + colIndexVar + java.lang.String + + null + + + rowHeaderText + java.lang.String + + null + + + colHeaderText + java.lang.String + + null + + + rowHeaderPosition + java.lang.String + + null + + + colHeaderPosition + java.lang.String + + null + + + selectable + boolean + + false + + + onselect + java.lang.String + + + null + + + onbeforeselect + java.lang.String + + + null + + + onclick + java.lang.String + + + null + + + + selectionListener + javax.faces.el.MethodBinding + org.richfaces.component.event.CoordinatesSelectionEvent + + + diff --git a/ui/coordinatesGrid/src/main/config/component/gridItem.xml b/ui/coordinatesGrid/src/main/config/component/gridItem.xml new file mode 100755 index 0000000..bdceb5f --- /dev/null +++ b/ui/coordinatesGrid/src/main/config/component/gridItem.xml @@ -0,0 +1,58 @@ + + + + + + org.richfaces.CoordinatesGridItem + org.richfaces.Schedule + org.richfaces.component.html.HtmlCoordinatesGridItem + org.richfaces.component.UICoordinatesGridItem + + + + + coordinatesGridItem + org.richfaces.taglib.CoordinatesGridItemTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + &ui_component_attributes; + + + styleClass + java.lang.String + + + null + + + + text + java.lang.String + + + + + x + int + + + + + y + int + + + + + + diff --git a/ui/coordinatesGrid/src/main/config/component/listeners.ent b/ui/coordinatesGrid/src/main/config/component/listeners.ent new file mode 100755 index 0000000..5e05f9e --- /dev/null +++ b/ui/coordinatesGrid/src/main/config/component/listeners.ent @@ -0,0 +1,35 @@ + + selectionListener + + binding + org.richfaces.coordinatesGridSelectionListener + The attribute takes a value-binding expression for a component property of + a backing bean + + + + org.richfaces.component.event.CoordinatesSelectionListener + + + org.richfaces.component.event.CoordinatesGridEventsProducer + + + org.richfaces.component.event.CoordinatesSelectionEvent + + + + org.richfaces.taglib.CoordinatesSelectionListenerTagHandler + + + + + org.richfaces.taglib.CoordinatesSelectionListenerTag + + + + + type + java.lang.String + The fully qualified Java class name for the listener + + \ No newline at end of file diff --git a/ui/coordinatesGrid/src/main/config/component/readme b/ui/coordinatesGrid/src/main/config/component/readme new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/ui/coordinatesGrid/src/main/config/component/readme diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/UICoordinatesGrid.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/UICoordinatesGrid.java new file mode 100755 index 0000000..cb4af0d --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/UICoordinatesGrid.java @@ -0,0 +1,307 @@ +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.CoordinatesGridEventsProducer; +import org.richfaces.component.event.CoordinatesRefreshEvent; +import org.richfaces.component.event.CoordinatesSelectionEvent; +import org.richfaces.component.event.CoordinatesSelectionListener; +import org.richfaces.component.model.SquareRange; + +import javax.el.ELContext; +import javax.el.ValueExpression; +import javax.faces.component.UIComponent; +import javax.faces.component.UIComponentBase; +import javax.faces.context.FacesContext; +import javax.faces.el.MethodBinding; +import javax.faces.event.AbortProcessingException; +import javax.faces.event.FacesEvent; +import javax.faces.model.ArrayDataModel; +import javax.faces.model.DataModel; +import javax.faces.model.ListDataModel; +import javax.faces.model.ResultDataModel; +import javax.faces.model.ResultSetDataModel; +import javax.faces.model.ScalarDataModel; +import javax.servlet.jsp.jstl.sql.Result; +import java.io.IOException; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class UICoordinatesGrid extends UIComponentBase implements CoordinatesGridEventsProducer, AjaxComponent { + + public static final String COMPONENT_TYPE = "org.richfaces.CoordinatesGrid"; + public static final String COMPONENT_FAMILY = "org.richfaces.CoordinatesGrid"; + private DataModel model; + + public abstract Object getValue(); + + public abstract void setValue(Object value); + + public abstract String getVar(); + + public abstract void setVar(String var); + + public abstract String getRowIndexVar(); + + public abstract void setRowIndexVar(String rowIndexVar); + + public abstract String getColIndexVar(); + + public abstract void setColIndexVar(String var); + + public abstract String getRowHeaderText(); + + public abstract void setRowHeaderText(String rowHeaderText); + + public abstract String getColHeaderText(); + + public abstract void setColHeaderText(String colHeaderText); + + public abstract String getColHeaderPosition(); + + public abstract void setColHeaderPosition(String colHeaderPosition); + + public abstract String getRowHeaderPosition(); + + public abstract void setRowHeaderPosition(String rowHeaderPosition); + + public abstract String getSwitchType(); + + public abstract void setSwitchType(String switchType); + + public abstract String getWidgetVar(); + + public abstract void setWidgetVar(String widgetVar); + + public abstract String getOnclick(); + + public abstract void setOnclick(String onclick); + + public abstract String getOnbeforeselect(); + + public abstract void setOnbeforeselect(String onbeforeselect); + + public abstract String getOnselect(); + + public abstract void setOnselect(String onselect); + + public abstract Integer getRows(); + + public abstract void setRows(Integer rows); + + public abstract Integer getCols(); + + public abstract void setCols(Integer cols); + + public abstract boolean isSelectable(); + + public abstract void setSelectable(boolean selectable); + + public abstract MethodBinding getSelectionListener(); + + public abstract void setSelectionListener(MethodBinding listener); + + @Override + public void broadcast(FacesEvent event) throws AbortProcessingException { + if (event instanceof CoordinatesSelectionEvent) { + super.broadcast(event); + new AjaxEvent(this).queue(); + CoordinatesSelectionEvent selectionEvent = (CoordinatesSelectionEvent) event; + FacesContext facesContext = getFacesContext(); + AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); + MethodBinding expression = getSelectionListener(); + if (expression != null) { + expression.invoke(facesContext, new Object[]{event}); + } + try { + ajaxContext.getResponseDataMap().put("_ajax:coordinatesGridData", getData(selectionEvent.getStartX(), selectionEvent.getStartY(), selectionEvent.getEndX(), selectionEvent.getEndY())); + } catch (IOException ex) { + getFacesContext().getExternalContext().log("Cannot get coordinates grid data", ex); + } + + } else if (event instanceof CoordinatesRefreshEvent) { + super.broadcast(event); + new AjaxEvent(this).queue(); + CoordinatesRefreshEvent refreshEvent = (CoordinatesRefreshEvent) event; + FacesContext facesContext = getFacesContext(); + AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); + try { + ajaxContext.getResponseDataMap().put("_ajax:coordinatesGridData", getData(refreshEvent.getStartX(), refreshEvent.getStartY(), refreshEvent.getEndX(), refreshEvent.getEndY())); + } catch (IOException ex) { + getFacesContext().getExternalContext().log("Cannot get coordinates grid data", ex); + } + + } 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()); + } + } + + public void addCoordinatesSelectionListener(CoordinatesSelectionListener listener) { + addFacesListener(listener); + } + + public void removeCoordinatesSelectionListener(CoordinatesSelectionListener listener) { + removeFacesListener(listener); + } + + public CoordinatesSelectionListener[] getCoordinatesSelectionListeners() { + return (CoordinatesSelectionListener[]) getFacesListeners(CoordinatesSelectionListener.class); + } + + protected DataModel getDataModel() { + // Return any previously cached DataModel instance + if (this.model != null) { + return (model); + } + + // Synthesize a DataModel around our current value if possible + Object current = getValue(); + if (current == null) { + setDataModel(new ListDataModel(Collections.EMPTY_LIST)); + } else if (current instanceof DataModel) { + setDataModel((DataModel) current); + } else if (current instanceof List) { + setDataModel(new ListDataModel((List) current)); + } else if (Object[].class.isAssignableFrom(current.getClass())) { + setDataModel(new ArrayDataModel((Object[]) current)); + } else if (current instanceof ResultSet) { + setDataModel(new ResultSetDataModel((ResultSet) current)); + } else if (current instanceof Result) { + setDataModel(new ResultDataModel((Result) current)); + } else { + setDataModel(new ScalarDataModel(current)); + } + return (model); + + } + + public void setDataModel(DataModel model) { + this.model = model; + } + + public List> getData(int startX, int startY, int endX, int endY) throws IOException { + ELContext elContext = getFacesContext().getELContext(); + ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getVar() + "}", Object.class); + List> data = new ArrayList>(); + DataModel dataModel = getDataModel(); + List elements = new ArrayList(); + if (dataModel instanceof ExtendedDataModel) { + final List keys = new ArrayList(); + DataVisitor visitor = new DataVisitor() { + + public void process(FacesContext context, Object rowKey, Object argument) throws IOException { + keys.add(rowKey); + } + }; + ((ExtendedDataModel) dataModel).walk(getFacesContext(), visitor, new SquareRange(startX, startY, endX, endY), null); + for (Object key : keys) { + ((ExtendedDataModel) dataModel).setRowKey(key); + if (dataModel.isRowAvailable()) { + elements.add(dataModel.getRowData()); + } + } + } else { + for (int i = 0; i < dataModel.getRowCount(); i++) { + dataModel.setRowIndex(i); + if (dataModel.isRowAvailable()) { + elements.add(dataModel.getRowData()); + } + } + } + + for (Object element : elements) { + valueExpression.setValue(elContext, element); + List firstDataElement = new ArrayList(); + for (UIComponent child : getChildren()) { + if (child instanceof UICoordinatesGridItem) { + UICoordinatesGridItem item = (UICoordinatesGridItem) child; + if (!item.isRendered()) { + continue; + } + firstDataElement.add(item.getX()); + firstDataElement.add(item.getY()); + String text = item.getText(); + if (text == null) { + text = ""; + } + firstDataElement.add(text.trim()); + String styleClass = item.getStyleClass(); + if (styleClass == null) { + styleClass = ""; + } + firstDataElement.add(styleClass.trim()); + data.add(firstDataElement); + } + } + } + valueExpression.setValue(elContext, null); + return data; + } + + public List> getRowHeadersData() throws IOException { + ELContext elContext = getFacesContext().getELContext(); + ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getRowIndexVar() + "}", Object.class); + List> data = new ArrayList>(); + for (int i = 0; i < getRows(); i++) { + if (getRowIndexVar() != null) { + valueExpression.setValue(elContext, i); + } + Map row = new HashMap(); + data.add(row); + row.put("text", getRowHeaderText()); + } + if (getRowIndexVar() != null) { + valueExpression.setValue(elContext, null); + } + return data; + } + + public List> getColHeadersData() throws IOException { + ELContext elContext = getFacesContext().getELContext(); + ValueExpression valueExpression = getFacesContext().getApplication().getExpressionFactory().createValueExpression(getFacesContext().getELContext(), "#{" + getColIndexVar() + "}", Object.class); + List> data = new ArrayList>(); + for (int i = 0; i < getCols(); i++) { + if (getColIndexVar() != null) { + valueExpression.setValue(elContext, i); + } + Map col = new HashMap(); + data.add(col); + col.put("text", getColHeaderText()); + } + if (getColIndexVar() != null) { + valueExpression.setValue(elContext, null); + } + return data; + } +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/UICoordinatesGridItem.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/UICoordinatesGridItem.java new file mode 100755 index 0000000..b294eca --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/UICoordinatesGridItem.java @@ -0,0 +1,25 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UICoordinatesGridItem extends UIComponentBase { + + public static final String COMPONENT_TYPE = "org.richfaces.CoordinatesGridItem"; + public static final String COMPONENT_FAMILY = "org.richfaces.CoordinatesGrid"; + + public abstract String getStyleClass(); + + public abstract void setStyleClass(String styleClass); + + public abstract String getText(); + + public abstract void setText(String text); + + public abstract int getX(); + + public abstract void setX(int x); + + public abstract int getY(); + + public abstract void setY(int y); +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesGridEventsProducer.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesGridEventsProducer.java new file mode 100755 index 0000000..f8aa93b --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesGridEventsProducer.java @@ -0,0 +1,10 @@ +package org.richfaces.component.event; + +public interface CoordinatesGridEventsProducer { + + void addCoordinatesSelectionListener(CoordinatesSelectionListener listener); + + void removeCoordinatesSelectionListener(CoordinatesSelectionListener listener); + + CoordinatesSelectionListener[] getCoordinatesSelectionListeners(); +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesRefreshEvent.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesRefreshEvent.java new file mode 100644 index 0000000..afb3c41 --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesRefreshEvent.java @@ -0,0 +1,53 @@ +package org.richfaces.component.event; + +import javax.faces.component.UIComponent; +import javax.faces.event.FacesEvent; +import javax.faces.event.FacesListener; + +/** + * Created by IntelliJ IDEA. + * User: bernard + * Date: Oct 18, 2010 + * Time: 6:55:06 PM + */ +public class CoordinatesRefreshEvent extends FacesEvent { + + private int startX; + private int startY; + private int endX; + private int endY; + + public CoordinatesRefreshEvent(int startX, int startY, int endX, int endY, UIComponent component) { + super(component); + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + @Override + public boolean isAppropriateListener(FacesListener listener) { + return false; + } + + @Override + public void processListener(FacesListener listener) { + throw new UnsupportedOperationException(); + } + + public int getStartX() { + return startX; + } + + public int getStartY() { + return startY; + } + + public int getEndX() { + return endX; + } + + public int getEndY() { + return endY; + } +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesSelectionEvent.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesSelectionEvent.java new file mode 100755 index 0000000..176f5f7 --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesSelectionEvent.java @@ -0,0 +1,53 @@ +package org.richfaces.component.event; + +import javax.faces.component.UIComponent; +import javax.faces.event.FacesEvent; +import javax.faces.event.FacesListener; + +/** + * Created by IntelliJ IDEA. + * User: bernard + * Date: Aug 17, 2010 + * Time: 2:59:13 PM + */ +public class CoordinatesSelectionEvent extends FacesEvent { + + private int startX; + private int startY; + private int endX; + private int endY; + + public CoordinatesSelectionEvent(int startX, int startY, int endX, int endY, UIComponent component) { + super(component); + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + @Override + public boolean isAppropriateListener(FacesListener listener) { + return listener instanceof CoordinatesSelectionListener; + } + + @Override + public void processListener(FacesListener listener) { + ((CoordinatesSelectionListener) listener).coordinatesSelected(this); + } + + public int getStartX() { + return startX; + } + + public int getStartY() { + return startY; + } + + public int getEndX() { + return endX; + } + + public int getEndY() { + return endY; + } +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesSelectionListener.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesSelectionListener.java new file mode 100755 index 0000000..28c9557 --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/event/CoordinatesSelectionListener.java @@ -0,0 +1,15 @@ +package org.richfaces.component.event; + +import javax.faces.event.FacesListener; + +/** + * Created by IntelliJ IDEA. + * User: bernard + * Date: Aug 17, 2010 + * Time: 3:01:08 PM + */ +public interface CoordinatesSelectionListener extends FacesListener { + + void coordinatesSelected(CoordinatesSelectionEvent event); + +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/model/SquareRange.java b/ui/coordinatesGrid/src/main/java/org/richfaces/component/model/SquareRange.java new file mode 100755 index 0000000..d594d71 --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/model/SquareRange.java @@ -0,0 +1,53 @@ +package org.richfaces.component.model; + +import org.ajax4jsf.model.Range; + +public class SquareRange implements Range { + + private int startX; + private int startY; + private int endX; + private int endY; + + public SquareRange() { + } + + public SquareRange(int startX, int startY, int endX, int endY) { + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + public int getStartX() { + return startX; + } + + public void setStartX(int startX) { + this.startX = startX; + } + + public int getStartY() { + return startY; + } + + public void setStartY(int startY) { + this.startY = startY; + } + + public int getEndX() { + return endX; + } + + public void setEndX(int endX) { + this.endX = endX; + } + + public int getEndY() { + return endY; + } + + public void setEndY(int endY) { + this.endY = endY; + } +} diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/component/readme b/ui/coordinatesGrid/src/main/java/org/richfaces/component/readme new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/component/readme diff --git a/ui/coordinatesGrid/src/main/java/org/richfaces/renderkit/html/CoordinatesGridRendererBase.java b/ui/coordinatesGrid/src/main/java/org/richfaces/renderkit/html/CoordinatesGridRendererBase.java new file mode 100755 index 0000000..0983606 --- /dev/null +++ b/ui/coordinatesGrid/src/main/java/org/richfaces/renderkit/html/CoordinatesGridRendererBase.java @@ -0,0 +1,149 @@ +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.javascript.JSFunctionDefinition; +import org.ajax4jsf.javascript.JSObject; +import org.ajax4jsf.javascript.JSReference; +import org.ajax4jsf.renderkit.AjaxRendererUtils; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.richfaces.component.UICoordinatesGrid; +import org.richfaces.component.event.CoordinatesRefreshEvent; +import org.richfaces.component.event.CoordinatesSelectionEvent; + +import javax.faces.component.NamingContainer; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class CoordinatesGridRendererBase extends HeaderResourcesRendererBase { + + private static Log logger = LogFactory.getLog(CoordinatesGridRendererBase.class); + private static final String EVENT_TYPE_PARAM = "eventType"; + private static final String START_X_PARAM = "startX"; + private static final String END_X_PARAM = "endX"; + private static final String START_Y_PARAM = "startY"; + private static final String END_Y_PARAM = "endY"; + private static final String CALLBACK = "callback"; + private static final String SELECT_EVENT = "select"; + private static final String REFRESH_EVENT = "refresh"; + public static final String AJAX_MODE = "ajax"; + public static final String SERVER_MODE = "server"; + public static final String CLIENT_MODE = "client"; + + protected Class getComponentClass() { + return UICoordinatesGrid.class; + } + + @Override + protected void doDecode(FacesContext context, UIComponent component) { + super.doDecode(context, component); + UICoordinatesGrid uiCoordinatesGrid; + + if (component instanceof UICoordinatesGrid) { + uiCoordinatesGrid = (UICoordinatesGrid) component; + } else { + if (logger.isDebugEnabled()) { + logger.debug("No decoding necessary since the component " + component.getId() + + " is not an instance or a sub class of UIInplaceInput"); + } + return; + } + String startXParam = getFieldId(context, uiCoordinatesGrid, START_X_PARAM); + String startYParam = getFieldId(context, uiCoordinatesGrid, START_Y_PARAM); + String endXParam = getFieldId(context, uiCoordinatesGrid, END_X_PARAM); + String endYParam = getFieldId(context, uiCoordinatesGrid, END_Y_PARAM); + String eventTypeParam = getFieldId(context, uiCoordinatesGrid, EVENT_TYPE_PARAM); + + Map request = context.getExternalContext().getRequestParameterMap(); + + String startXString = request.get(startXParam); + String endXString = request.get(endXParam); + String startYString = request.get(startYParam); + String endYString = request.get(endYParam); + String eventType = request.get(eventTypeParam); + if (uiCoordinatesGrid.isSelectable() && (SELECT_EVENT.equals(eventType) || REFRESH_EVENT.equals(eventType)) && startXString != null && !"".equals(startXString)) { + try { + int startX = Integer.parseInt(startXString); + int startY = Integer.parseInt(startYString); + int endX = Integer.parseInt(endXString); + int endY = Integer.parseInt(endYString); + if (SELECT_EVENT.equals(eventType)) { + new CoordinatesSelectionEvent(startX, startY, endX, endY, uiCoordinatesGrid).queue(); + } else { + uiCoordinatesGrid.queueEvent(new CoordinatesRefreshEvent(startX, startY, endX, endY, uiCoordinatesGrid)); + } + } catch (Exception e) { + logger.error("Problem during decoding event for component " + component.getId() + " (params: " + startXParam + "=" + startXString + ";" + startYParam + "=" + startYString + ";" + endXParam + "=" + endXString + ";" + endYParam + "=" + endYString + ")"); + } + } + } + + protected String getFieldId(FacesContext context, UIComponent component, String attribute) { + return getUtils().clientId(context, component) + NamingContainer.SEPARATOR_CHAR + attribute; + } + + public void writeInitFunction(FacesContext context, UICoordinatesGrid component) throws IOException { + ResponseWriter writer = context.getResponseWriter(); + if (component.getWidgetVar() != null) { + writer.write("var " + component.getWidgetVar() + "="); + } + Map options = new HashMap(); + addOptionIfSet("onclick", component.getOnclick(), options); + addOptionIfSet("onbeforeselect", component.getOnbeforeselect(), options); + addOptionIfSet("onselect", component.getOnselect(), options); + addOptionIfSet("rows", component.getRows(), options); + addOptionIfSet("cols", component.getCols(), options); + addOptionIfSet("selectable", component.isSelectable(), options); + addOptionIfSet("colHeaderPosition", component.getColHeaderPosition(), options); + addOptionIfSet("rowHeaderPosition", component.getRowHeaderPosition(), options); + addOptionIfSet("rowHeaders", component.getRowHeadersData(), options); + addOptionIfSet("colHeaders", component.getColHeadersData(), options); + addOptionIfSet("elements", component.getData(0, 0, component.getCols() - 1, component.getRows() - 1), options); + + writer.writeText(new JSObject("RichFaces.CoordinatesGrid", + component.getClientId(context), + options, + createSubmitEventFunction(context, component)).toScript(), null); + } + + protected Object createSubmitEventFunction(FacesContext context, UICoordinatesGrid component) { + JSFunction jsFunction; + Map params = new HashMap(); + params.put(getFieldId(context, component, EVENT_TYPE_PARAM), new JSReference(EVENT_TYPE_PARAM)); + params.put(getFieldId(context, component, START_X_PARAM), new JSReference(START_X_PARAM)); + params.put(getFieldId(context, component, START_Y_PARAM), new JSReference(START_Y_PARAM)); + params.put(getFieldId(context, component, END_X_PARAM), new JSReference(END_X_PARAM)); + params.put(getFieldId(context, component, END_Y_PARAM), new JSReference(END_Y_PARAM)); + if (isAjaxMode(component)) { + jsFunction = AjaxRendererUtils.buildAjaxFunction(component, context); + Map eventOptions = AjaxRendererUtils.buildEventOptions(context, component, params); + eventOptions.put("oncomplete", new JSReference(CALLBACK)); + jsFunction.addParameter(eventOptions); + } else if (SERVER_MODE.equals(component.getSwitchType())) { + jsFunction = new JSFunction("Richfaces.jsFormSubmit", + component.getClientId(context), + getUtils().getNestingForm(context, component).getClientId(context), + null, + params); + } else { + return null; + } + return new JSFunctionDefinition("event", EVENT_TYPE_PARAM, START_X_PARAM, START_Y_PARAM, END_X_PARAM, END_Y_PARAM, CALLBACK).addToBody(jsFunction); + } + + private void addOptionIfSet(String optionName, Object value, Map options) { + if (value != null && value != "") { + options.put(optionName, value); + } + } + + private boolean isAjaxMode(UICoordinatesGrid component) { + String mode = component.getSwitchType(); + return AJAX_MODE.equals(mode) || "".equals(mode) || null == mode; + } +} diff --git a/ui/coordinatesGrid/src/main/resources/org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss b/ui/coordinatesGrid/src/main/resources/org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss new file mode 100755 index 0000000..0da662b --- /dev/null +++ b/ui/coordinatesGrid/src/main/resources/org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/coordinatesGrid/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js b/ui/coordinatesGrid/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js new file mode 100755 index 0000000..f823bb0 --- /dev/null +++ b/ui/coordinatesGrid/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js @@ -0,0 +1,355 @@ +if (window.RichFaces == null) { + window.RichFaces = {}; +} +RichFaces.CoordinatesGrid = function(targetId, options, submitEventFunction) { + + var startX; + var startY; + var endX; + var endY; + var selecting = false; + this.target = document.getElementById(targetId); + var _this = this; + this.options = jQuery.extend({}, this.options, options); + if (this.target.component != null && this.target.component.destroy != null) { + this.target.component.destroy(); + } + this.target.component = this; + + var getY = function(o) { + if (o == null || o.parentNode == null || o.parentNode.rowIndex == null) { + throw "HTMLTableCellElement expected"; + } + return o.parentNode.rowIndex; + }; + var getX = function(o) { + if (o == null || o.cellIndex == null) { + throw "HTMLTableCellElement expected"; + } + return o.cellIndex; + }; + /** + * Updates element on the grid with data from initial or ajax request. + * @param data array of data where: 0: x, 1: y, 2: text, 3: css class + */ + var updateElementFromData = function(data) { + var element = _this.getElementAt(data[0], data[1]); + if (element != null) { + _this.updateElement(element, {innerHTML:data[2],className:data[3]}); + } + return element; + }; + var updateElementsWithRequestData = function(request, _startX, _startY, _endX, _endY) { + /** Server component should respond with data of elements matching selection */ + var elements = request.getJSON('_ajax:coordinatesGridData'); + if (elements != undefined) { + var elementsFromUpdate = []; + jQuery.each(elements, function() { + var element = updateElementFromData(this); + if (element != null) { + elementsFromUpdate.push(element); + } + }); + jQuery.each(_this.getElements(_startX, _startY, _endX, _endY), function() { + var visitedCell = this; + var exists = false; + jQuery.each(elementsFromUpdate, function() { + if (this == visitedCell) { + exists = true; + } + }); + if (!exists) { + this.className = ""; + this.innerHTML = ""; + } + }); + } + }; + var mouseDownHanlder = function() { + if (selecting) { + mouseUpHanlder.apply(this); + } else if (options.selectable) { + startX = getX(this); + startY = getY(this); + selecting = true; + } + }; + var mouseUpHanlder = function() { + if (!selecting) { + return; + } + endX = getX(this); + endY = getY(this); + selecting = false; + highlightSelection(); + if (_this.options.onbeforeselect != null) { + var result; + if (typeof _this.options.onbeforeselect == "function") { + result = _this.options.onbeforeselect(_this, _startX, _startY, _endX, _endY); + } else { + result = RichFaces.CoordinatesGrid.eval("(function(){" + _this.options.onbeforeselect + "})()", { + 'startX':startX, + 'startY':startY, + 'endX':endX, + 'endY':endY, + 'component':_this + }); + } + if (result === false) { + return; + } + } + /** + * endX and endY will be reset before ajax response comes. + */ + var _endX = endX; + var _endY = endY; + var _startX = startX; + var _startY = startY; + /** Notify server side */ + if (submitEventFunction != null) { + submitEventFunction({}, "select", + _this.indexToCoordX(startX), _this.indexToCoordY(startY), _this.indexToCoordX(endX), _this.indexToCoordY(endY), + function(request, event, data) { + updateElementsWithRequestData(request, _startX, _startY, _endX, _endY); + + if (_this.options.onselect != null) { + if (typeof _this.options.onselect == "function") { + _this.options.onselect(_this, _startX, _startY, _endX, _endY); + } else { + RichFaces.CoordinatesGrid.eval("(function(){" + _this.options.onselect + "})()", { + 'startX':_startX, + 'startY':_startY, + 'endX':_endX, + 'endY':_endY, + 'component':_this + }); + } + } + delete _endX,_endY,_startX,_startY; + }); + } + endX = -1; + endY = -1; + highlightSelection(); + }; + var mouseOverHandler = function() { + if (!selecting) { + return; + } + endX = getX(this); + endY = getY(this); + highlightSelection(); + }; + var highlightSelection = function() { + jQuery("td", _this.target).each(function() { + var x = getX(this); + var y = getY(this); + if (startX <= x && x <= endX && startY <= y && y <= endY) { + jQuery(this).addClass(_this.options.highlightClass); + } else { + jQuery(this).removeClass(_this.options.highlightClass); + } + }); + }; + var clickHandler = function() { + if (_this.options.onclick != null) { + if (typeof _this.options.onclick == "function") { + _this.options.onclick(_this, getX(this), getY(this)); + } else { + RichFaces.CoordinatesGrid.eval("(function(){" + _this.options.onclick + "})()", { + 'x':getX(this), + 'y':getY(this), + 'component':_this + }); + } + } + }; + this.getElements = function(startX, startY, endX, endY) { + var elements = []; + jQuery("td", _this.target).each(function() { + var x = getX(this); + var y = getY(this); + if (startX <= x && x <= endX && startY <= y && y <= endY) { + elements.push(this); + } + }); + return elements; + }; + this.refresh = function(_startX, _startY, _endX, _endY) { + if (_startX == null && _startY == null && _endX == null && _endY == null) { + _startX = 0; + _startY = 0; + _endX = this.options.cols; + _endY = this.options.rows; + } + submitEventFunction({}, "refresh", _startX, _startY, _endX, _endY, function(request, event, data) { + updateElementsWithRequestData(request, _startX, _startY, _endX, _endY); + delete _endX,_endY,_startX,_startY; + }); + }; + /** + * @param element HTMLTableCellElement + * @param options options used to extend element, i.e. {className:'important'} + **/ + this.updateElement = function(element, options) { + if (options.className) { + options.className = "rich-table-cell " + options.className; + } + jQuery.extend(element, options); + }; + this.getElementAt = function(x, y) { + return table[0].rows[y + (_this.isTopColHeadersVisible() ? 1 : 0)].cells[x + (_this.isLeftRowHeadersVisible() ? 1 : 0)]; + }; + /** + * Create grid. + */ + var table = jQuery("
"); + (function() { + table.appendTo(_this.target); + var cell; + /** + * Function used for appending headers without filling them with text + */ + var appendHeaders = function() { + var row = jQuery(""); + row.appendTo(table); + row.addClass(_this.options.colHeaderClass); + if (_this.options.rowHeaders != null) { + + if (_this.options.rowHeaderPosition == 'both' || _this.options.rowHeaderPosition == 'left') { + var cell = jQuery(""); + cell.appendTo(row); + } + for (var x = 0; x < _this.options.cols; x++) { + cell = jQuery(""); + cell.appendTo(row); + } + if (_this.options.rowHeaderPosition == 'both' || _this.options.rowHeaderPosition == 'right') { + cell = jQuery(""); + cell.appendTo(row); + } + } + }; + /** Append top column headers */ + if (_this.isTopColHeadersVisible()) { + appendHeaders() + } + for (var y = 0; y < _this.options.rows; y++) { + var row = jQuery(""); + row.appendTo(table); + /** Append left row headers */ + if (_this.isLeftRowHeadersVisible()) { + cell = jQuery(""); + cell.appendTo(row); + cell.addClass(_this.options.rowHeaderClass); + } + /** Append regular cells */ + for (var x = 0; x < _this.options.cols; x++) { + cell = jQuery(""); + cell.appendTo(row); + cell.mouseup(mouseUpHanlder); + cell.mousedown(mouseDownHanlder); + cell.mouseover(mouseOverHandler); + cell.click(clickHandler); + } + /** Append right row headers */ + if (_this.isRightRowHeadersVisible()) { + cell = jQuery(""); + cell.appendTo(row); + cell.addClass(_this.options.rowHeaderClass); + } + } + /** Append bottom column headers */ + if (_this.isBottomColHeadersVisible()) { + appendHeaders() + } + /** Customize headers - className and text */ + jQuery.each(_this.options.rowHeaders, function(index) { + var text = this.text; + delete this.text; + if (text != null) { + this.innerHTML = text; + } + if (_this.isLeftRowHeadersVisible()) { + _this.updateElement(_this.getElementAt(-1, index), this); + } + if (_this.isRightRowHeadersVisible()) { + _this.updateElement(_this.getElementAt(_this.options.cols, index), this); + } + }); + jQuery.each(_this.options.colHeaders, function(index) { + var text = this.text; + delete this.text; + if (text != null) { + this.innerHTML = text; + } + if (_this.isTopColHeadersVisible()) { + _this.updateElement(_this.getElementAt(index, -1), this); + } + if (_this.isBottomColHeadersVisible()) { + _this.updateElement(_this.getElementAt(index, _this.options.rows), this); + } + }); + /** Customize regular cell */ + if (_this.options.elements != null) { + jQuery.each(_this.options.elements, function() { + updateElementFromData(this) + }); + } + /** Disable text selection */ + if (options.selectable) { + table.attr('unselectable', 'on').css('MozUserSelect', 'none').bind('selectstart.ui', function() { + return false; + }); + } + })(); +} + ; +RichFaces.CoordinatesGrid.prototype.options = { + rows: 10, + cols: 10, + highlightClass: 'highlight', + colHeaderPosition: 'bottom', + rowHeaderPosition: 'left' +}; +RichFaces.CoordinatesGrid.prototype.select = function(func) { + this.options.onselect = func; +}; +RichFaces.CoordinatesGrid.prototype.destroy = function() { + jQuery("table", this.target).remove(); + delete this.target.component; +}; +RichFaces.CoordinatesGrid.prototype.isLeftRowHeadersVisible = function() { + return this.options.rowHeaders != null && (this.options.rowHeaderPosition == 'both' || this.options.rowHeaderPosition == 'left'); +}; +RichFaces.CoordinatesGrid.prototype.isRightRowHeadersVisible = function() { + return this.options.rowHeaders != null && (this.options.rowHeaderPosition == 'both' || this.options.rowHeaderPosition == 'right'); +}; +RichFaces.CoordinatesGrid.prototype.isTopColHeadersVisible = function() { + return this.options.colHeaders != null && (this.options.colHeaderPosition == 'both' || this.options.colHeaderPosition == 'top'); +}; +RichFaces.CoordinatesGrid.prototype.isBottomColHeadersVisible = function() { + return this.options.colHeaders != null && (this.options.colHeaderPosition == 'both' || this.options.colHeaderPosition == 'bottom'); +}; +RichFaces.CoordinatesGrid.prototype.indexToCoordX = function(index) { + return index - (this.isLeftRowHeadersVisible() ? 1 : 0); +}; +RichFaces.CoordinatesGrid.prototype.indexToCoordY = function(index) { + return index - (this.isTopColHeadersVisible() ? 1 : 0); +}; +/** + * This function evaluates code in template with object in ScopeChain. + * This is usefull if you need to evaluate code that uses member names + * that colide with external names that the code refers to. + * There is almost exact method in utils.js called Richfaces.eval, + * but it swallows exception thrown during evaluation, which makes debugging + * hard. + */ +RichFaces.CoordinatesGrid.eval = function(template, object) { + var value = ''; + with (object) { + value = eval(template); + } + return value; +}; diff --git a/ui/coordinatesGrid/src/main/templates/htmlCoordinatesGrid.jspx b/ui/coordinatesGrid/src/main/templates/htmlCoordinatesGrid.jspx new file mode 100755 index 0000000..dfa698d --- /dev/null +++ b/ui/coordinatesGrid/src/main/templates/htmlCoordinatesGrid.jspx @@ -0,0 +1,36 @@ + + + + /org/richfaces/renderkit/html/css/richfaces.coordinatesGrid.xcss + + new org.ajax4jsf.javascript.PrototypeScript(), + new org.ajax4jsf.javascript.AjaxScript(), + /org/richfaces/renderkit/html/scripts/jquery/jquery.js, + /org/richfaces/renderkit/html/scripts/richfaces.coordinatesGrid.js + + + + + + + + +
+ +
+
\ No newline at end of file diff --git a/ui/coordinatesGrid/src/main/templates/readme b/ui/coordinatesGrid/src/main/templates/readme new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/ui/coordinatesGrid/src/main/templates/readme diff --git a/ui/dock/pom.xml b/ui/dock/pom.xml new file mode 100644 index 0000000..00ff9ed --- /dev/null +++ b/ui/dock/pom.xml @@ -0,0 +1,73 @@ + + + + org.richfaces.sandbox + ui + 3.3.4-SNAPSHOT + + 4.0.0 + org.richfaces.sandbox.ui + dock + dock + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces.sandbox.ui + + dock + http://richfaces.org/sandbox/dock + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + + diff --git a/ui/dock/src/main/config/component/dock.xml b/ui/dock/src/main/config/component/dock.xml new file mode 100644 index 0000000..cd8c3b6 --- /dev/null +++ b/ui/dock/src/main/config/component/dock.xml @@ -0,0 +1,241 @@ + + + + org.richfaces.Dock + org.richfaces.Dock + org.richfaces.component.html.HtmlDock + org.richfaces.component.UIDock + + The Dock - as anyone familiar with a Mac will know - is a set of iconic images that expand when rolled over + with the cursor, and usually perform some action when clicked. This plugin mimics that behaviour by + transforming a contiguous set of HTML images into an expanding Dock, vertical or horizontal, with or without + labels. + + Note that this component will not work if it's children render anything else except "<script>", "<a>" + or "<img>". + + + org.richfaces.DockRenderer + org.richfaces.renderkit.html.DockRenderer + + + dock + org.richfaces.taglib.DockTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + + + &ui_component_attributes; + &html_style_attributes; + + + active + int + + This designates one of the menu's elements to be fully expanded when the dock is initialised. The option + takes a zero-based index of the position of the desired menu element (image) within the dock - so if you + want the 4th of 6 images to be expanded, set active : 3. + + Warning : There are consequences to using this option, which might possibly only become apparent when + you try it. I have provided it because it has specifically been requested, but ... if you set a mid-menu + image initially active, and the user then enters the dock at either end, it is quite likely that the + dock will simply collapse to its 'at rest' state because the resultant animation takes the mouse off the + dock! + + -1 + + + + align + java.lang.String + + values = 'top', 'middle', 'bottom', left', center', 'right' + + Fixes the horizontal/vertical main axis, and direction of expansion. + + For a horizontal menu: + * 'top' : fixes the top edge of the dock, so that images expand down + * 'middle' : fixes the middle of the images, so that images expand up and down equally + * 'bottom' : fixes the bottom edge of the dock, so that images expand up + + For a vertical menu: + * 'left' : fixes the left edge of the dock, so that images expand right + * 'center' : fixes the center of the images, so that images expand left and right equally + * 'right' : fixes the right edge of the dock, so that images expand left + + "bottom" + + + + coefficient + double + + Attenuation coefficient. This controls the relationship between the distance from the cursor and the + amount of expansion of any affected image within that distance. A coefficient of 1 makes the expansion + linear with respect to distance from cursor; a larger coefficient gives a greater degree of expansion + the closer to the cursor the affected image is (within distance). # distance : integer, default = 72 + Attenuation distance from cursor, ie the distance (in pixels) from the cursor that an image has to be + within in order to have any expansion applied. + + Note that attenuation is always calculated as if the Dock was 'at rest' (no images expanded), even + though there may be expanded images at the time. + + 1.5 + + + + duration + int + + The duration (in milliseconds) of the initial 'on-Dock' expansion, and the 'off-Dock' shrinkage. + + 300 + + + + fadeIn + int + + The amount of time (in milliseconds) for the initial fade-in of the Dock after initialisation. By + default this is set to 0 (zero), which means that the Dock is displayed in full as soon as it can be ( = + show() ). There may be occasions when a 'softer' presentation of the Dock is desirable, and setting + fadeIn to, for example, 400 would fade the Dock in over that period. + + 0 + + + + fadeLayer + java.lang.String + + By default the fade-in effect (see fadeIn above) is applied to the original target menu element. By + specifying either 'wrap' or 'dock' here, the fade-in element can be switched to the child or grand-child + (ie. div.jqDockWrap or div.jqDock, respectively) of the original target menu element. This option only + has any effect if fadeIn is set, and is really only useful for cases where, for example, background + colours have been styled on the original menu element or div.jqDock, and you don't want them to be faded + in. + + null + + + + flow + boolean + + If set, this alters the default dock behaviour such that the Dock is not auto-centered and the wrap + element (.jqDockWrap, which is relatively positioned) expands and collapses to precisely contain the + Dock (.jqDock); this allows elements positioned around the docked menu to adjust their own relative + position according to the current state of the docked menu. + + Warning : There are consequences to using this option, which might possibly only become apparent when + you try it. I have provided it because it has specifically been requested, but with flow enabled, if you + aim your mouse at a specific menu option you will probably find that quite often you don't stay on that + option without having to move the mouse again! + + false + + + + idle + int + + The period of time (in milliseconds) after the mouse has left the menu (without re-entering, obviously!) + before the Dock attempts to go to sleep. + + 0 + + + + inactivity + int + + The period of time (in milliseconds) after which the Dock will shrink if there has been no movement of + the mouse while it is over an expanded Dock. + + 0 + + + + labels + java.lang.String + + values = 'true', 'false', 'tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br' + + This enables/disables display of a label on the current image. Allowed string values are 2 characters in + length: the first character indicates horizontal position (t=top, m=middle, b=bottom) and the second + indicates vertical position (l=left, c=center, r=right). So 'br' means bottom-right! If simply set to + true, jqDock will use its default positioning for the label, which is 'tl' (top-left) for any align + setting other than 'top' or 'left'. The defaults for 'top' and 'left' alignment are 'br' (bottom-right) + and 'tr' (top-right) respectively. To determine the text for the label, jqDock looks firstly for text in + the image's 'title' attribute; if not found, it will then look for text in the 'title' attribute of the + parent link - if there is one - and use that if found. + + Please be aware that enabling this option with one of the middle/center label positions (eg. 'ml', 'bc', + etc) may have a slight effect on the performance of the Dock, simply due to the additional processing + required to position the label correctly. + + "false" + + + + loader + java.lang.String + + values = 'image', 'jquery' + + This overrides the default image loader used by jqDock. Depending on the browser, jqDock uses an image + loader based on either "new Image()", or the jQuery HTML constructor "jQuery('<img/>')...". If your + Dock is not being displayed, and you have triple checked all your image paths, try setting this option + to 'image' or 'jquery' to override the default loader. + + null + + + + noBuffer + boolean + + By default, while the dock is asleep the most recent mouse event is buffered, and when the dock is + nudged awake that buffered event is used and acted upon - before any other mouse event that might occur + subsequent to the 'nudge'. Setting the noBuffer option to true will prevent buffering of the mouse + events. + + false + + + + size + int + + This is the maximum value (in pixels) of the minor axis dimension for the 'at rest' images. For example, + an image of natural dimensions 90x120 (width x height), placed in a horizontal Dock (say, 'align' = + 'bottom') would, by default, be sized down to 36x48. This is because height is the minor axis in a + horizontal Dock, and to keep the presentation of the 'at rest' images neat and tidy it is the height + that is governed by the size option. Conversely, in a vertical Dock it would be the width that was + capped at the size value, with height being set proportionately. + + 48 + + + + step + int + + The timer interval (in milliseconds) between each animation step of the 'on-Dock' expansion, and the + 'off-Dock' shrinkage. + + 50 + + + + diff --git a/ui/dock/src/main/java/org/richfaces/component/UIDock.java b/ui/dock/src/main/java/org/richfaces/component/UIDock.java new file mode 100644 index 0000000..393fbac --- /dev/null +++ b/ui/dock/src/main/java/org/richfaces/component/UIDock.java @@ -0,0 +1,83 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UIDock extends UIComponentBase { +// ------------------------------ FIELDS ------------------------------ + + public static final String COMPONENT_FAMILY = "org.richfaces.Dock"; + + public static final String COMPONENT_TYPE = "org.richfaces.Dock"; + + public static final boolean DEFAULT_ACTIVE = false; + +// -------------------------- OTHER METHODS -------------------------- + + public abstract int getActive(); + + public abstract String getAlign(); + + public abstract double getCoefficient(); + + public abstract int getDistance(); + + public abstract int getDuration(); + + public abstract int getFadeIn(); + + public abstract String getFadeLayer(); + + public abstract int getIdle(); + + public abstract int getInactivity(); + + public abstract String getLabels(); + + public abstract String getLoader(); + + public abstract int getSize(); + + public abstract int getStep(); + + public abstract String getStyle(); + + public abstract String getStyleClass(); + + public abstract boolean isFlow(); + + public abstract boolean isNoBuffer(); + + public abstract void setActive(int active); + + public abstract void setAlign(String align); + + public abstract void setCoefficient(double coefficient); + + public abstract void setDistance(int distance); + + public abstract void setDuration(int duration); + + public abstract void setFadeIn(int fadeIn); + + public abstract void setFadeLayer(String fadeLayer); + + public abstract void setFlow(boolean flow); + + public abstract void setIdle(int idle); + + public abstract void setInactivity(int inactivity); + + public abstract void setLabels(String labels); + + public abstract void setLoader(String loader); + + public abstract void setNoBuffer(boolean noBuffer); + + public abstract void setSize(int size); + + public abstract void setStep(int step); + + public abstract void setStyle(String style); + + public abstract void setStyleClass(String styleClass); +} diff --git a/ui/dock/src/main/java/org/richfaces/renderkit/html/DockRenderer.java b/ui/dock/src/main/java/org/richfaces/renderkit/html/DockRenderer.java new file mode 100644 index 0000000..96ce2dd --- /dev/null +++ b/ui/dock/src/main/java/org/richfaces/renderkit/html/DockRenderer.java @@ -0,0 +1,154 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.RendererUtils.HTML; +import org.ajax4jsf.resource.InternetResource; +import org.richfaces.component.UIDock; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class DockRenderer extends HeaderResourcesRendererBase { +// ------------------------------ FIELDS ------------------------------ + + private static final Map DEFAULTS; + + private final InternetResource[] scripts = { + getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js"), + getResource("/org/richfaces/renderkit/html/scripts/jquery.jdock.js"), + getResource("/org/richfaces/renderkit/html/scripts/richfaces.dock.js") + }; + private final InternetResource[] styles = { + getResource("/org/richfaces/renderkit/html/css/dock.xcss") + }; + +// -------------------------- STATIC METHODS -------------------------- + + static { + Map defaults = new HashMap(); + defaults.put("active", -1); + defaults.put("align", "bottom"); + defaults.put("coefficient", 1.5); + defaults.put("duration", 300); + defaults.put("fadeIn", 0); + defaults.put("fadeLayer", ""); + defaults.put("flow", false); + defaults.put("idle", 0); + defaults.put("inactivity", 0); + defaults.put("labels", "false"); + defaults.put("loader", ""); + defaults.put("noBuffer", false); + defaults.put("size", 48); + defaults.put("step", 50); + DEFAULTS = Collections.unmodifiableMap(defaults); + } + +// --------------------- GETTER / SETTER METHODS --------------------- + + protected Class getComponentClass() { + return UIDock.class; + } + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected InternetResource[] getStyles() { + return styles; + } + +// -------------------------- OTHER METHODS -------------------------- + + @Override + protected void doEncodeBegin(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { + writer.startElement(HTML.DIV_ELEM, component); + final String clientId = getUtils().clientId(context, component); + writer.writeAttribute(HTML.id_ATTRIBUTE, clientId, HTML.id_ATTRIBUTE); + writer.startElement(HTML.DIV_ELEM, component); + writer.writeAttribute(HTML.id_ATTRIBUTE, getContainerClientId(context, component), HTML.id_ATTRIBUTE); + Object styleClass = component.getAttributes().get("styleClass"); + styleClass = styleClass == null ? "" : " " + styleClass.toString(); + writer.writeAttribute(HTML.class_ATTRIBUTE, "rf-dk" + styleClass, HTML.class_ATTRIBUTE); + Object style = component.getAttributes().get("style"); + style = style == null ? "" : style.toString(); + writer.writeAttribute(HTML.style_ATTRIBUTE, "display:none;" + style, HTML.style_ATTRIBUTE); + } + + @Override + protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { + writer.endElement(HTML.DIV_ELEM); + writer.startElement(HTML.SCRIPT_ELEM, null); + writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", "type"); + writer.writeText(new JSFunction("RichFaces.Dock", getContainerClientId(context, component), + getOptions((UIDock) component)), null); + writer.writeText(";", null); + writer.endElement(HTML.SCRIPT_ELEM); + writer.endElement(HTML.DIV_ELEM); + } + + private String getContainerClientId(FacesContext context, UIComponent component) { + return getUtils().clientId(context, component) + "Container"; + } + + protected Map getOptions(UIDock dock) throws IOException { + /** + * Include only attributes that are actually set. + */ + Map options = new HashMap(); + addOptionIfSetAndNotDefault("active", dock.getActive(), options); + addOptionIfSetAndNotDefault("align", dock.getAlign(), options); + addOptionIfSetAndNotDefault("coefficient", dock.getCoefficient(), options); + addOptionIfSetAndNotDefault("duration", dock.getDuration(), options); + addOptionIfSetAndNotDefault("fadeIn", dock.getFadeIn(), options); + addOptionIfSetAndNotDefault("fadeLayer", dock.getFadeLayer(), options); + addOptionIfSetAndNotDefault("flow", dock.isFlow(), options); + addOptionIfSetAndNotDefault("idle", dock.getIdle(), options); + addOptionIfSetAndNotDefault("inactivity", dock.getInactivity(), options); + addOptionIfSetAndNotDefault("labels", dock.getLabels(), options); + addOptionIfSetAndNotDefault("loader", dock.getLoader(), options); + addOptionIfSetAndNotDefault("noBuffer", dock.isNoBuffer(), options); + addOptionIfSetAndNotDefault("size", dock.getSize(), options); + addOptionIfSetAndNotDefault("step", dock.getStep(), options); + return options; + } + + protected void addOptionIfSetAndNotDefault(String optionName, Object value, Map options) { + if (value != null && !"".equals(value) + && !value.equals(DEFAULTS.get(optionName)) + && !(value instanceof Collection && ((Collection) value).size() == 0) + && !(value instanceof Map && ((Map) value).size() == 0)) { + options.put(optionName, value); + } + } +} diff --git a/ui/dock/src/main/resources/org/richfaces/renderkit/html/css/dock.xcss b/ui/dock/src/main/resources/org/richfaces/renderkit/html/css/dock.xcss new file mode 100644 index 0000000..cc18769 --- /dev/null +++ b/ui/dock/src/main/resources/org/richfaces/renderkit/html/css/dock.xcss @@ -0,0 +1,19 @@ + + + + +.rf-dk a { + text-decoration:none; +} + + + + + + + + + + \ No newline at end of file diff --git a/ui/dock/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.jdock.js b/ui/dock/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.jdock.js new file mode 100644 index 0000000..c280f6b --- /dev/null +++ b/ui/dock/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.jdock.js @@ -0,0 +1,27 @@ +/* + jquery.jqDock.js v1.6 +*/ +(function(k,w){if(!k.jqDock){var v=["Top","Right","Bottom","Left"],N=["Major","Minor"],z=["mouseenter","mousemove","mouseleave"],x=["docknudge","dockidle","dockfreeze"],s=["Idler","Inactive","Indock","Overdock","Offdock"],E=['
'],p={v:{wh:"height",xy:1,tl:"top",lead:0,trail:2,inv:"h"},h:{wh:"width",xy:0,tl:"left",lead:3,trail:1,inv:"v"}},m=[],F=[0,0],X=function(){},C=function(a){a=parseInt(a,10);return isNaN(a)? +0:a},t=function(a,d){for(var c=s[d]?d+1:s.length;dd)d-=a-d;return d},O=function(a){var d=m[a.data.id],c=d.Elem[a.data.idx];c.height=this.height;c.width=this.width;--d.Load<=0&&w.setTimeout(function(){k.jqDock.initDock(a.data.id)},0)},Z=function(a,d){for(var c;a&&a.ownerDocument&&a!==d;){if(c=a.className.toString().match(/jqDockMouse(\d+)/))return 1*c[1];a=a.parentNode}return-1},P=function(a,d,c){var e={},b=p[c].wh;c=p[p[c].inv].wh;e[b]= +d;e[c]=Math.round(d*a[c]/a[b]);return e},Q=function(){k(this).prev("img").trigger("click");return false},y=function(a,d){var c=a.Elem[a.Current];if(c&&a.Opts.labels)c.Label.el[d?"show":"hide"]()},R=function(a){var d=p[a.Opts.vh],c=a.Elem.length,e=-1,b=0,f,h,j,i=F[d.xy]-a.Elem[0].Wrap.parent().offset()[d.tl];if(i>=0)for(;e<0&&b
').hide().insertAfter(d.Img);if(b){h=b.charAt(0)=="b";b= +b.charAt(1)=="r";f.el.css({top:h?"auto":0,left:b?"auto":0,bottom:h?0:"auto",right:b?0:"auto"}).click(Q)}a=e.setLabel.call(a.Menu[0],d.Title,c,f.el[0]);a!==false&&k('
'+a.toString()+"
").appendTo(f.el)},I=function(a,d){var c=m[a],e=c.Opts,b=p[e.vh].wh,f=c.Elem.length,h,j,i;for(d=d||d===0?d:R(c);f--;){h=c.Elem[f];i=h.Initial;if(d>=0){j=Math.abs(d-h.Centre);if(j=c.duration)d.Stamp=0}if(b>=c.step){for(h=(c.duration-b)/c.step;f1?c.Major+Math[b<0?"floor":"ceil"](b/h):c.Final;U(a, +f,b)}if(d.Spread>d[e.wh]){d.Yard.parent()[e.wh](d.Spread+d.Border[e.lead]+d.Border[e.trail]);d[e.wh]=d.Spread}}},K=function(a,d){var c=m[a],e=c.Elem,b=e.length;t(c,2);if(c.OnDock&&!c.Stamp){for(I(a,d);b--&&e[b].Major==e[b].Final;);if(b<0)y(c,1);else{J(a);c[s[2]]=w.setTimeout(function(){K(a,d)},c.Opts.step)}}},V=function(a,d){var c=m[a],e=c.Elem,b=e.length;if(!c.OnDock){for(;b--&&e[b].Major<=e[b].Initial;);R(c);if(b<0){c.Stamp=0;for(b=e.length;b--;)e[b].Major=e[b].Final=e[b].Initial;c.Current=-1;d|| +D(c)}else{J(a);c[s[4]]=w.setTimeout(function(){V(a,d)},c.Opts.step)}}},W=function(a,d){var c=m[a],e=c.Elem,b=e.length;if(c.OnDock){for(I(a,d);b--&&e[b].Major==e[b].Final;);if(b<0||!c.Stamp){c.Stamp=0;K(a,d)}else{J(a);c[s[3]]=w.setTimeout(function(){W(a,d)},c.Opts.step)}}},B=function(a,d,c,e){var b=m[d],f=b.Elem,h=f.length;if(a===0){b.OnDock=1;b.Current>=0&&b.Current!==c&&y(b);b.Current=c;b.Stamp=e&&e>1?0:H(b);W(d,e?f[c].Centre:null)}if(a===1){if(c!==b.Current){y(b);b.Current=c}K(d)}if(a===2){t(b, +1);b.OnDock=0;y(b);for(b.Stamp=H(b);h--;)f[h].Final=f[h].Initial;V(d,!!e)}},L=function(a){var d=A(this),c=m[d],e=c?Z(a.target,this):-1,b=-1,f;if(c)if(c.Asleep){if(!c.Opts.noBuffer)c.Sleeper={target:a.target,type:a.type,pageX:a.pageX,pageY:a.pageY}}else{f=c.OnDock;t(c,0);F=[a.pageX,a.pageY];if(a.type==z[2])if(f)b=2;else D(c);else{if(c.Opts.inactivity){t(c,1);c[s[1]]=w.setTimeout(function(){B(2,d,e,1)},c.Opts.inactivity)}if(a.type==z[1])if(e<0){if(f&&c.Current>=0)b=2}else b=!f||c.Current<0?0:1;else if(e>= +0&&!f)b=0}c.Sleeper=null;b>=0&&B(b,d,e)}},M=function(a){var d=k(".jqDock",this).get(0),c=A(d),e=m[c],b=a.type==x[2],f=b?"freeze":"sleep";if(e)if(a.type==x[0]){f=e.Frozen?"thaw":"wake";if(e.Asleep&&!(e.Asleep=e.Opts.onWake.call(this,f)===false))e.Frozen=!k(this).trigger("dockwake",[f]);if(!e.Asleep){D(e);e.Sleeper&&L.call(d,e.Sleeper)}}else{t(e,0);a=!e.Asleep||b&&!e.Frozen;if(!a||e.Opts.onSleep.call(e.Menu[0],f)!==false){e.Asleep=!t(e,b?-1:1);e.Frozen=e.Frozen||b;a&&e.Menu.trigger("docksleep",[f]); +if(b)e.Stamp=e.OnDock=0;else B(2,c,0,1)}}};k.jqDock=function(){return{version:1.6,defaults:{size:48,distance:72,coefficient:1.5,duration:300,align:"bottom",labels:0,source:0,loader:0,inactivity:0,fadeIn:0,fadeLayer:"",step:50,setLabel:0,flow:0,idle:0,onReady:0,onSleep:0,onWake:0,noBuffer:0,active:-1},useJqLoader:k.browser.opera||k.browser.safari,initDock:function(a){var d=m[a],c=d.Opts,e=p[c.vh],b=p[e.inv],f=d.Border,h=d.Elem.length,j=E.join(""),i=0,n=0,o,g,l,q=c.fadeLayer;S(d.Menu[0]);for(d.Menu.children().each(function(r, +u){var ba=d.Elem[r].Wrap=k(u).wrap(j+j+"").parent();c.vh=="h"&&ba.parent().css("float","left")}).find("img").andSelf().css({position:"relative",padding:0,margin:0,borderWidth:0,borderStyle:"none",verticalAlign:"top",display:"block",width:"100%",height:"100%"});nd[e.wh])d[e.wh]=i}}for(;n;){g=d.Elem[--n];g.Final=g.Initial}e=[E[0],E[2],'
'].join("");d.Yard=k("div.jqDock", +d.Menu.wrapInner(e));for(b=4;b--;)f[b]=C(d.Yard.css("border"+v[b]+"Width"));for(d.Yard.parent().addClass("jqDockWrap").width(d.width+f[1]+f[3]).height(d.height+f[0]+f[2]);n").bind("load",{id:e,idx:n},O).attr({src:l});else{g=new Image;g.onload=function(){O.call(this,{data:{id:e,idx:n}});g.onload="";g=null};g.src=l}})});return this}}})(jQuery,window); diff --git a/ui/dock/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.dock.js b/ui/dock/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.dock.js new file mode 100644 index 0000000..68a6e3b --- /dev/null +++ b/ui/dock/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.dock.js @@ -0,0 +1,31 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +window.RichFaces = window.RichFaces || {}; +RichFaces.Dock = function(clientId, options) { + var container = jQuery(document.getElementById(clientId)); + /** + * Move all scripts generated by children out of container (jDock requirement). + */ + container.children().filter("script").appendTo(container.parent()); + return container.jqDock(options); +}; \ No newline at end of file diff --git a/ui/focus/pom.xml b/ui/focus/pom.xml new file mode 100644 index 0000000..7fa0b9a --- /dev/null +++ b/ui/focus/pom.xml @@ -0,0 +1,73 @@ + + + + ui + org.richfaces.sandbox + 3.3.4-SNAPSHOT + + 4.0.0 + org.richfaces.sandbox.ui + focus + focus + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces + + focus + http://richfaces.org/sandbox/focus + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + + diff --git a/ui/focus/src/main/config/component/focus.xml b/ui/focus/src/main/config/component/focus.xml new file mode 100644 index 0000000..61f895e --- /dev/null +++ b/ui/focus/src/main/config/component/focus.xml @@ -0,0 +1,81 @@ + + + + org.richfaces.Focus + org.richfaces.Focus + org.richfaces.component.html.HtmlFocus + org.richfaces.component.UIFocus + + + + + org.richfaces.FocusRenderer + org.richfaces.renderkit.html.HtmlFocusRenderer + + + focus + org.richfaces.taglib.FocusTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + org.richfaces.taglib.HtmlFocusTagTest + org.ajax4jsf.tests.AbstractJspTestCase + + + &ui_component_attributes; + + for + java.lang.String + + Id of component that should be focused + + "" + + + priority + java.lang.Integer + + If there are more components requesting focus, then component with lowest priority will be focused. + + + + targetClientId + java.lang.String + + If some other element then the one matching clintId of target component should be focused and it cannot be achieved with suffix, use this + attribute. + + "" + + + suffix + java.lang.String + + Suffix added to clientId. Useful for focusing radio elements. Example : suffix=":0" puts focus on first radio if target is radio. + + "" + + + timing + java.lang.String + + Moment when focus should be put. The possible values are "onJScall" and "onload". If "onJScall" is used then you must manually call + Richfaces.FocusManager.focus(). The default value is "onload". + + "onload" + + + name + java.lang.String + + Name of JavaScript function generated to trigger focus. This is required if "timing" attribute is set to "onJScall". + + null + + + diff --git a/ui/focus/src/main/config/component/focusModifier.xml b/ui/focus/src/main/config/component/focusModifier.xml new file mode 100644 index 0000000..00e7c43 --- /dev/null +++ b/ui/focus/src/main/config/component/focusModifier.xml @@ -0,0 +1,62 @@ + + + + org.richfaces.FocusModifier + org.richfaces.FocusModifier + org.richfaces.component.html.HtmlFocusModifier + org.richfaces.component.UIFocusModifier + + + + + org.richfaces.FocusModifierRenderer + org.richfaces.renderkit.html.HtmlFocusModifierRenderer + + + focusModifier + org.richfaces.taglib.FocusModifierTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + org.richfaces.taglib.HtmlFocusModifierTagTest + org.ajax4jsf.tests.AbstractJspTestCase + + &ui_component_attributes; + + targetClientId + java.lang.String + + If some other element then the one matching clintId of target component should be focused and it cannot be achieved with suffix, use this + attribute. + + "" + + + suffix + java.lang.String + + Suffix added to clientId. Useful for focusing radio elements. Example : suffix=":0" puts focu on first radio if target is radio. + + "" + + + priority + java.lang.Integer + + If there are more components requesting focus, then component with lowest priority will be focused. + + + + skipped + boolean + + If set to true, component will not be concerned when calculating default focus. + + false + + + diff --git a/ui/focus/src/main/java/org/richfaces/component/UIFocus.java b/ui/focus/src/main/java/org/richfaces/component/UIFocus.java new file mode 100644 index 0000000..b2d76c3 --- /dev/null +++ b/ui/focus/src/main/java/org/richfaces/component/UIFocus.java @@ -0,0 +1,172 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponent; +import javax.faces.component.UIComponentBase; +import javax.faces.component.UIForm; +import javax.faces.component.UIInput; +import javax.faces.context.FacesContext; +import java.util.*; + +public abstract class UIFocus extends UIComponentBase { +// ------------------------------ FIELDS ------------------------------ + + public static final String COMPONENT_FAMILY = "org.richfaces.Focus"; + + public static final String COMPONENT_TYPE = "org.richfaces.Focus"; + + public static final int DEFAULT_PRIORITY = Integer.MAX_VALUE; + + public static final String FOCUS_MODIFIER_FACET_NAME = "focusModifier"; + + public static final String TIMING_ON_LOAD = "onload"; + +// -------------------------- STATIC METHODS -------------------------- + + public static UIFocusModifier findModifier(UIComponent component) { + if (component instanceof UIFocusModifier) { + return (UIFocusModifier) component; + } + UIFocusModifier modifier = (UIFocusModifier) component.getFacet(UIFocus.FOCUS_MODIFIER_FACET_NAME); + if (modifier == null) { + for (UIComponent child : component.getChildren()) { + modifier = findModifier(child); + if (modifier != null) { + break; + } + } + } + return modifier; + } + +// -------------------------- OTHER METHODS -------------------------- + + public int calculatePriority(UIComponent component) { + final UIFocusModifier modifier = findModifier(component); + if (modifier != null && modifier.getPriority() != null) { + return modifier.getPriority(); + } + UIComponent parentForm = component.getParent(); + while (parentForm != null && !(parentForm instanceof UIForm)) { + parentForm = parentForm.getParent(); + } + if (parentForm != null) { + return getUIInputChildrenCount(parentForm, component.getId()); + } else { + return DEFAULT_PRIORITY; + } + } + + public abstract String getFor(); + + public abstract String getName(); + + public abstract Integer getPriority(); + + public abstract String getSuffix(); + + public abstract String getTargetClientId(); + + public String getTargetComponentId(FacesContext context) { + String aFor = getFor(); + + if (aFor != null && !"".equals(aFor)) { + return aFor; + } else { + if (!(getParent() instanceof UIInput)) { + Set allowedClientIds = new HashSet(); + Iterator clientIdsWithMessages = getFacesContext().getClientIdsWithMessages(); + while (clientIdsWithMessages.hasNext()) { + final String clientId = clientIdsWithMessages.next(); + if (clientId != null) { + allowedClientIds.add(clientId); + } + } + final List inputs = new ArrayList(); + getInputs(getParentForm(this), allowedClientIds, inputs); + UIInput inputWithLowestPriority = null; + int lowestPriority = Integer.MAX_VALUE; + for (UIInput input : inputs) { + final int priority = calculatePriority(input); + if (priority < lowestPriority) { + inputWithLowestPriority = input; + lowestPriority = priority; + } + } + return inputWithLowestPriority == null ? null : inputWithLowestPriority.getClientId(context); + } else { + return getParent().getClientId(context); + } + } + } + + public abstract String getTiming(); + + public abstract void setFor(String value); + + public abstract void setName(String name); + + public abstract void setPriority(Integer value); + + public abstract void setSuffix(String value); + + public abstract void setTargetClientId(String targetClientId); + + public abstract void setTiming(String timing); + + private void getInputs(UIComponent parent, Set allowedClientIds, List inputs) { + FacesContext facesContext = getFacesContext(); + for (UIComponent child : parent.getChildren()) { + if (child instanceof UIInput && (allowedClientIds.size() == 0 || allowedClientIds.contains(child.getClientId(facesContext)))) { + final UIFocusModifier modifier = findModifier(child); + if (modifier == null || !modifier.isSkipped()) { + inputs.add((UIInput) child); + } + } + getInputs(child, allowedClientIds, inputs); + } + } + + private UIForm getParentForm(UIComponent component) { + UIComponent parent = component.getParent(); + if (parent == null) { + return null; + } + if (parent instanceof UIForm) { + return (UIForm) parent; + } else { + return getParentForm(parent); + } + } + + private int getUIInputChildrenCount(UIComponent component, String breakOnId) { + final Holder childrenCount = new Holder(); + childrenCount.value = 0; + getUIInputChildrenCount(component, breakOnId, childrenCount); + return childrenCount.value; + } + + private boolean getUIInputChildrenCount(UIComponent component, String breakOnId, Holder childrenCount) { + for (UIComponent child : component.getChildren()) { + if (child.getId().equals(breakOnId)) { + return true; + } + if (child instanceof UIInput) { + final UIFocusModifier modifier = findModifier(child); + if (modifier == null || !modifier.isSkipped()) { + childrenCount.value++; + } + } else { + if (getUIInputChildrenCount(child, breakOnId, childrenCount)) return true; + } + } + return false; + } + +// -------------------------- INNER CLASSES -------------------------- + + private class Holder { +// ------------------------------ FIELDS ------------------------------ + + public T value; + } +} diff --git a/ui/focus/src/main/java/org/richfaces/component/UIFocusModifier.java b/ui/focus/src/main/java/org/richfaces/component/UIFocusModifier.java new file mode 100644 index 0000000..0ce2dfe --- /dev/null +++ b/ui/focus/src/main/java/org/richfaces/component/UIFocusModifier.java @@ -0,0 +1,29 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UIFocusModifier extends UIComponentBase { +// ------------------------------ FIELDS ------------------------------ + + public static final String COMPONENT_FAMILY = "org.richfaces.Focus"; + + public static final String COMPONENT_TYPE = "org.richfaces.FocusModifier"; + +// -------------------------- OTHER METHODS -------------------------- + + public abstract Integer getPriority(); + + public abstract String getSuffix(); + + public abstract String getTargetClientId(); + + public abstract boolean isSkipped(); + + public abstract void setPriority(Integer priority); + + public abstract void setSkipped(boolean skipped); + + public abstract void setSuffix(String value); + + public abstract void setTargetClientId(String focusClientId); +} diff --git a/ui/focus/src/main/java/org/richfaces/renderkit/html/HtmlFocusModifierRenderer.java b/ui/focus/src/main/java/org/richfaces/renderkit/html/HtmlFocusModifierRenderer.java new file mode 100644 index 0000000..6375d96 --- /dev/null +++ b/ui/focus/src/main/java/org/richfaces/renderkit/html/HtmlFocusModifierRenderer.java @@ -0,0 +1,35 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.renderkit.html; + +import org.ajax4jsf.renderkit.RendererBase; +import org.richfaces.component.UIFocusModifier; + +import javax.faces.component.UIComponent; + +public class HtmlFocusModifierRenderer extends RendererBase { + + protected Class getComponentClass() { + return UIFocusModifier.class; + } +} diff --git a/ui/focus/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java b/ui/focus/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java new file mode 100644 index 0000000..61b7593 --- /dev/null +++ b/ui/focus/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java @@ -0,0 +1,149 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.javascript.JSFunctionDefinition; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.RendererUtils; +import org.ajax4jsf.resource.InternetResource; +import org.richfaces.component.UIFocus; +import org.richfaces.component.UIFocusModifier; + +import javax.faces.FacesException; +import javax.faces.component.UIComponent; +import javax.faces.component.UIInput; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; + +public class HtmlFocusRenderer extends HeaderResourcesRendererBase { +// ------------------------------ FIELDS ------------------------------ + + private final InternetResource[] scripts = { + getResource("/org/ajax4jsf/javascript/scripts/prototype.js"), + getResource("/org/richfaces/renderkit/html/scripts/focus.js"), + }; + + private final InternetResource[] styles = {}; + +// --------------------- GETTER / SETTER METHODS --------------------- + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected InternetResource[] getStyles() { + return styles; + } + + private void checkValidity(FacesContext context, UIFocus component) { + String clientId = getUtils().clientId(context, component); + String name = component.getName(); + String timing = component.getTiming(); + String _for = component.getFor(); + String targetClientId = component.getTargetClientId(); + if ((name == null || "".equals(name.trim())) && "onJScall".equals(timing)) { + throw new FacesException( + "The name attribute of the focus component (id='" + clientId + "') must be specified when timing attribute equals to 'onJScall'"); + } + if (name != null && !"".equals(name.trim()) && !"onJScall".equals(timing)) { + throw new FacesException( + "The timing attribute of the focus component (id='" + clientId + "') must be set to 'onJScall' when name attribute is specified"); + } + if ((_for == null || "".equals(_for)) && (targetClientId == null || "".equals(targetClientId)) && !(component.getParent() instanceof UIInput) + && getUtils().getNestingForm(context, component) == null) { + throw new FacesException("Focus component must have either one of 'for' or 'targetClientId' attributes specified or be nested within UIForm or UIInput component"); + } + } + + @Override + protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) + throws IOException { + if (!(component instanceof UIFocus)) { + return; + } + UIFocus uiFocus = (UIFocus) component; + final String clientId = getUtils().clientId(context, component); + checkValidity(context, uiFocus); + Integer priority = uiFocus.getPriority(); + String targetClientId = uiFocus.getTargetClientId(); + if (targetClientId == null || "".equals(targetClientId)) { + String targetComponentId = uiFocus.getTargetComponentId(context); + String suffix = uiFocus.getSuffix(); + if (targetComponentId == null || "".equals(targetComponentId)) { + return; + } + UIComponent forcomp = getUtils().findComponentFor(component, targetComponentId); + if (forcomp == null) { + throw new FacesException("No component with id=" + targetComponentId + " found!"); + } + targetClientId = forcomp.getClientId(context); + UIFocusModifier modifier = UIFocus.findModifier(forcomp); + if (modifier != null) { + final String modifiedTargetClientId = modifier.getTargetClientId(); + if (modifiedTargetClientId != null && !modifiedTargetClientId.equals("")) { + targetClientId = modifiedTargetClientId; + } else { + suffix = modifier.getSuffix(); + } + } + if (priority == null) { + priority = uiFocus.calculatePriority(forcomp); + } + if (suffix != null && !"".equals(suffix)) { + targetClientId += suffix; + } + } + if (targetClientId == null || targetClientId.equals("")) { + return; + } + if (priority == null) { + priority = UIFocus.DEFAULT_PRIORITY; + } + writer.startElement(RendererUtils.HTML.SCRIPT_ELEM, null); + writer.writeAttribute(RendererUtils.HTML.TYPE_ATTR, "text/javascript", "type"); + writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, clientId, RendererUtils.HTML.id_ATTRIBUTE); + if (UIFocus.TIMING_ON_LOAD.equals(uiFocus.getTiming())) { + writer.write(new JSFunction("Richfaces.FocusManager.setFocus", targetClientId, priority).toScript()); + writer.write(";"); + } else { + writer.write(new JSFunction("Richfaces.FocusManager.setFocus", targetClientId, priority, clientId, + uiFocus.getTiming()).toScript()); + writer.write(";"); + } + if (uiFocus.getName() != null && !uiFocus.getName().trim().equals("")) { + final JSFunctionDefinition definition = new JSFunctionDefinition().addToBody(new JSFunction("Richfaces.FocusManager.focusStored", clientId)); + definition.setName(uiFocus.getName()); + writer.write(definition.toScript()); + writer.write(";"); + } + writer.endElement(RendererUtils.HTML.SCRIPT_ELEM); + } + + protected Class getComponentClass() { + return UIFocus.class; + } +} diff --git a/ui/focus/src/main/resources/org/richfaces/renderkit/html/scripts/focus.js b/ui/focus/src/main/resources/org/richfaces/renderkit/html/scripts/focus.js new file mode 100644 index 0000000..53c1f6e --- /dev/null +++ b/ui/focus/src/main/resources/org/richfaces/renderkit/html/scripts/focus.js @@ -0,0 +1,74 @@ +if (!window.Richfaces) window.Richfaces = {}; + +Richfaces.FocusManager = (function() { + + var m_focus; + var m_priority = 999999; + var m_domLoaded = false; + var m_timing = false; + var m_focusStore = {}; + /** Constants */ + var TIMING_ON_JS_CALL = "onJScall"; + var TIMING_ON_LOAD = "onload"; + + var focus = function(element) { + try { + if (element == null) { + if (m_focus == null) { + return; + } + element = $(m_focus); + } + if (element != null) { + element.focus(); + element.select(element); + } + } finally { + Richfaces.FocusManager.clearFocus(); + } + }; + + document.observe('dom:loaded', function() { + if (m_timing == TIMING_ON_LOAD) { + focus(null); + } + m_domLoaded = true; + }); + + return { + focus: focus, + focusStored: function(focusComponentId) { + var element = $(m_focusStore[focusComponentId]); + if (element != null) { + focus(element); + } + }, + getFocus : function() { + return m_focus; + }, + setFocus : function(id, priority, focusComponentId, timing) { + if (priority == null) { + priority = 99999; + } + if (timing != TIMING_ON_JS_CALL) { + timing = TIMING_ON_LOAD; + } + if (focusComponentId != null) { + m_focusStore[focusComponentId] = id; + } + if (m_focus == null || priority < m_priority) { + m_focus = id; + m_priority = priority == null ? 0 : priority; + m_timing = timing; + if (m_domLoaded && timing == TIMING_ON_LOAD) { + focus(); + } + } + }, + clearFocus : function() { + m_focus = null; + m_priority = 999999; + m_timing = null; + } + }; +})(); diff --git a/ui/gmapMarker/pom.xml b/ui/gmapMarker/pom.xml new file mode 100644 index 0000000..fb45e58 --- /dev/null +++ b/ui/gmapMarker/pom.xml @@ -0,0 +1,77 @@ + + + + ui + org.richfaces.sandbox + 3.3.4-SNAPSHOT + + 4.0.0 + org.richfaces.sandbox.ui + gmapMarker + gmapMarker + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces + + gmapMarker + http://richfaces.org/sandbox/gmapMarker + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + org.richfaces.ui + gmap + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + diff --git a/ui/gmapMarker/src/main/config/component/gmapMarker.xml b/ui/gmapMarker/src/main/config/component/gmapMarker.xml new file mode 100644 index 0000000..3caf64c --- /dev/null +++ b/ui/gmapMarker/src/main/config/component/gmapMarker.xml @@ -0,0 +1,152 @@ + + + + org.richfaces.GmapMarker + org.richfaces.GmapMarker + org.richfaces.component.html.HtmlGmapMarker + org.richfaces.component.UIGmapMarker + + . + ]]> + + + org.richfaces.GmapMarkerRenderer + org.richfaces.renderkit.html.GmapMarkerRenderer + + + gmapMarker + org.richfaces.taglib.GmapMarkerTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + org.richfaces.taglib.HtmlGmapMarkerTagTest + org.ajax4jsf.tests.AbstractJspTestCase + + + + &ui_component_attributes; + + latitude + java.lang.Double + + The latitude coordinate in degrees, as a number between -90 and +90. + + + + longitude + java.lang.Double + + The longitude coordinate in degrees, as a number between -180 and +180. + + + + autoPan + boolean + + Auto-pan the map as you drag the marker near the edge. + + true + + + bouncy + boolean + + Toggles whether or not the marker should bounce up and down after it finishes dragging. + + false + + + bounceGravity + java.lang.Double + + When finishing dragging, this number is used to define the acceleration rate of the marker during the + bounce down to earth. + + 1d + + + clickable + boolean + + Toggles whether or not the marker is clickable. Markers that are not clickable or draggable are inert, + consume less resources and do not respond to any events. + + false + + + draggable + boolean + + Toggles whether or not the marker will be draggable by users. Markers set up to be dragged require more + resources to set up than markers that are clickable. Any marker that is draggable is also clickable, + bouncy and auto-pan enabled by default. + + false + + + dragCrossMove + boolean + + When dragging markers normally, the marker floats up and away from the cursor. Setting this value to + true keeps the marker underneath the cursor, and moves the cross downwards instead. + + false + + + hide + boolean + + When true, indicates that the map should not initially display the GMarker. To turn on the overlay, call + GMarker.show(). + + false + + + icon + java.lang.String + + Chooses the Icon for this class. If not specified, G_DEFAULT_ICON is used. + + null + + + iconHeight + java.lang.Integer + + The height of the icon. + + null + + + iconWidth + java.lang.Integer + + The width of the icon. + + null + + + title + java.lang.String + + This string will appear as tooltip on the marker, i.e. it will work just as the title attribute on HTML + elements. + + null + + + onclick + java.lang.String + + This event is fired when the marker icon was clicked, passing in the current coordinate of the marker + within its latlng argument. Notice that + this event will also fire for the map, with the marker passed as the first argument to the event handler + there. + + null + + + diff --git a/ui/gmapMarker/src/main/java/org/richfaces/component/UIGmapMarker.java b/ui/gmapMarker/src/main/java/org/richfaces/component/UIGmapMarker.java new file mode 100644 index 0000000..85df67a --- /dev/null +++ b/ui/gmapMarker/src/main/java/org/richfaces/component/UIGmapMarker.java @@ -0,0 +1,86 @@ +package org.richfaces.component; + +import javax.faces.FacesException; +import javax.faces.component.UIComponent; +import javax.faces.component.UIComponentBase; + +public abstract class UIGmapMarker extends UIComponentBase { +// ------------------------------ FIELDS ------------------------------ + + public static final String COMPONENT_FAMILY = "org.richfaces.GmapMarker"; + + public static final String COMPONENT_TYPE = "org.richfaces.GmapMarker"; + public static final boolean DEFAULT_AUTO_PAN = true; + public static final Double DEFAULT_BOUNCE_GRAVITY = 1d; + public static final boolean DEFAULT_DRAG_CROSS_MOVE = false; + public static final boolean DEFAULT_HIDE = false; + +// -------------------------- OTHER METHODS -------------------------- + + public abstract Double getBounceGravity(); + + public abstract String getIcon(); + + public abstract Integer getIconHeight(); + + public abstract Integer getIconWidth(); + + public abstract Double getLatitude(); + + public abstract Double getLongitude(); + + public abstract String getOnclick(); + + public UIGmap getParentMap() { + UIComponent parent = getParent(); + while (parent != null && !(parent instanceof UIGmap)) { + parent = parent.getParent(); + } + if (parent == null) { + throw new FacesException("Component " + getId() + " must be nested within gmap component."); + } + return (UIGmap) parent; + } + + public abstract String getTitle(); + + public abstract boolean isAutoPan(); + + public abstract boolean isBouncy(); + + public abstract boolean isClickable(); + + public abstract boolean isDragCrossMove(); + + public abstract boolean isDraggable(); + + public abstract boolean isHide(); + + public abstract void setAutoPan(boolean autoPan); + + public abstract void setBounceGravity(Double bounceGravity); + + public abstract void setBouncy(boolean bouncy); + + public abstract void setClickable(boolean clickable); + + public abstract void setDragCrossMove(boolean dragCrossMove); + + public abstract void setDraggable(boolean draggable); + + public abstract void setHide(boolean hide); + + public abstract void setIcon(String icon); + + public abstract void setIconHeight(Integer height); + + public abstract void setIconWidth(Integer width); + + public abstract void setLatitude(Double latitude); + + public abstract void setLongitude(Double longitude); + + public abstract void setOnclick(String onclick); + + public abstract void setTitle(String title); +} diff --git a/ui/gmapMarker/src/main/java/org/richfaces/renderkit/html/GmapMarkerRenderer.java b/ui/gmapMarker/src/main/java/org/richfaces/renderkit/html/GmapMarkerRenderer.java new file mode 100644 index 0000000..16932a1 --- /dev/null +++ b/ui/gmapMarker/src/main/java/org/richfaces/renderkit/html/GmapMarkerRenderer.java @@ -0,0 +1,115 @@ +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.javascript.JSLiteral; +import org.ajax4jsf.javascript.JSObject; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.RendererUtils; +import org.ajax4jsf.resource.InternetResource; +import org.richfaces.component.UIGmap; +import org.richfaces.component.UIGmapMarker; + +import javax.faces.FacesException; +import javax.faces.component.NamingContainer; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class GmapMarkerRenderer extends HeaderResourcesRendererBase { + + private static final Map DEFAULTS; + + /** + * Following defaults are be used by addOptionIfSetAndNotDefault + */ + static { + Map defaults = new HashMap(); + defaults.put("autoPan", UIGmapMarker.DEFAULT_AUTO_PAN); + defaults.put("hide", UIGmapMarker.DEFAULT_HIDE); + defaults.put("bounceGravity", UIGmapMarker.DEFAULT_BOUNCE_GRAVITY); + defaults.put("icon", ""); + defaults.put("zIndexProcess", ""); + defaults.put("title", ""); + defaults.put("iconWidth", ""); + defaults.put("iconHeight", ""); + defaults.put("onclick", ""); + defaults.put("dragCrossMove", UIGmapMarker.DEFAULT_DRAG_CROSS_MOVE); + + DEFAULTS = Collections.unmodifiableMap(defaults); + } + + private final InternetResource[] scripts = { + getResource("script/gmap.js"), + getResource("/org/richfaces/renderkit/html/scripts/richfaces.gmapmarker.js") + }; + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected Class getComponentClass() { + return UIGmapMarker.class; + } + + @Override + protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { + UIGmapMarker marker = (UIGmapMarker) component; + Map options = new HashMap(); + if (marker.getIcon() != null) { + options.put("icon", new JSObject("GIcon", new JSLiteral("G_DEFAULT_ICON"), marker.getIcon())); + } + addOptionIfSetAndNotDefault("clickable", marker.isClickable(), options); + addOptionIfSetAndNotDefault("draggable", marker.isDraggable(), options); + addOptionIfSetAndNotDefault("bouncy", marker.isBouncy(), options); + addOptionIfSetAndNotDefault("autoPan", marker.isAutoPan(), options); + addOptionIfSetAndNotDefault("hide", marker.isHide(), options); + addOptionIfSetAndNotDefault("bounceGravity", marker.getBounceGravity(), options); + addOptionIfSetAndNotDefault("icon", marker.getIcon(), options); + addOptionIfSetAndNotDefault("title", marker.getTitle(), options); + addOptionIfSetAndNotDefault("dragCrossMove", marker.isDragCrossMove(), options); + addOptionIfSetAndNotDefault("iconWidth", marker.getIconWidth(), options); + addOptionIfSetAndNotDefault("iconHeight", marker.getIconHeight(), options); + addOptionIfSetAndNotDefault("onclick", marker.getOnclick(), options); + final UIGmap map = marker.getParentMap(); + final Map mapAttributes = map.getAttributes(); + final Object gmapVar = mapAttributes.get("gmapVar"); + if (gmapVar == null) { + throw new FacesException("Component " + map.getId() + " must have gmapVar attribute set."); + } + final UIComponent infoWindow = marker.getFacet("infoWindow"); + String infoWindowClientId = null; + if (infoWindow != null) { + writer.startElement(RendererUtils.HTML.DIV_ELEM, component); + writer.writeAttribute(RendererUtils.HTML.style_ATTRIBUTE, "display:none", null); + writer.startElement(RendererUtils.HTML.DIV_ELEM, component); + infoWindowClientId = marker.getClientId(context) + NamingContainer.SEPARATOR_CHAR + "iW"; + writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, infoWindowClientId, "id"); + infoWindow.encodeAll(context); + writer.endElement(RendererUtils.HTML.DIV_ELEM); + writer.endElement(RendererUtils.HTML.DIV_ELEM); + } + getUtils().writeScript(context, component, + new JSFunction("RichFaces.addGmapMarker", gmapVar, marker.getLatitude(), marker.getLongitude(), options, infoWindowClientId) + ); + Object oninit = mapAttributes.get("oninit"); + if (oninit == null) { + oninit = ""; + } + if (!oninit.toString().contains("RichFaces.handleGmapInit")) { + mapAttributes.put("oninit", oninit + ";" + new JSFunction("RichFaces.handleGmapInit", gmapVar)); + } + + } + + protected void addOptionIfSetAndNotDefault(String optionName, Object value, Map options) { + if (value != null && !"".equals(value) && !value.equals(DEFAULTS.get(optionName))) { + options.put(optionName, value); + } + } +} diff --git a/ui/gmapMarker/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.gmapmarker.js b/ui/gmapMarker/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.gmapmarker.js new file mode 100644 index 0000000..0e47f75 --- /dev/null +++ b/ui/gmapMarker/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.gmapmarker.js @@ -0,0 +1,68 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +window.RichFaces = window.RichFaces || {}; +RichFaces.GmapMarkers = []; +RichFaces.addGmapMarker = function(gmapVar, lat, lng, options, infoWindowId) { + RichFaces.GmapMarkers.push({gmapVar:gmapVar,lat:lat,lng:lng,options:options,infoWindowId:infoWindowId}); + RichFaces.handleGmapInit(gmapVar) +}; +RichFaces.handleGmapInit = function(gmapVar, event) { + var gmap = window[gmapVar]; + if (gmap == null) { + return; + } + while (RichFaces.GmapMarkers.length > 0) { + var data = RichFaces.GmapMarkers.pop(); + if (data.options.icon != null) { + data.options.icon = new GIcon(G_DEFAULT_ICON, data.options.icon); + if (data.options.iconWidth != null) { + data.options.icon.iconSize = new GSize(data.options.iconWidth, data.options.iconHeight); + } + } + var marker = new GMarker(new GLatLng(data.lat, data.lng, true), data.options); + if (data.options.onclick != null) { + GEvent.addListener(marker, "click", function(latlng) { + RichFaces.GmapMarkers.eval(data.options.onclick, {'marker':this,'latlng':latlng}); + }) + } + gmap.addOverlay(marker); + if (data.infoWindowId != null) { + marker.bindInfoWindow(document.getElementById(data.infoWindowId)); + } + } +}; +/** + * This function evaluates code in template with object in ScopeChain. + * This is usefull if you need to evaluate code that uses member names + * that colide with external names that the code refers to. + * There is almost exact method in utils.js called Richfaces.eval, + * but it swallows exception thrown during evaluation, which makes debugging + * hard. + */ +RichFaces.GmapMarkers.eval = function(template, object) { + var value; + with (object) { + value = eval(template); + } + return value; +}; \ No newline at end of file diff --git a/ui/imageSelectTool/pom.xml b/ui/imageSelectTool/pom.xml new file mode 100644 index 0000000..7cf2cea --- /dev/null +++ b/ui/imageSelectTool/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + org.richfaces.sandbox + ui + 3.3.4-SNAPSHOT + + org.richfaces.sandbox.ui + imageSelectTool + imageSelectTool + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces.sandbox.ui + + imageSelectTool + http://richfaces.org/sandbox/imageSelectTool + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + + + diff --git a/ui/imageSelectTool/src/main/config/component/README b/ui/imageSelectTool/src/main/config/component/README new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ui/imageSelectTool/src/main/config/component/README diff --git a/ui/imageSelectTool/src/main/config/component/imageSelectTool.xml b/ui/imageSelectTool/src/main/config/component/imageSelectTool.xml new file mode 100644 index 0000000..50f8940 --- /dev/null +++ b/ui/imageSelectTool/src/main/config/component/imageSelectTool.xml @@ -0,0 +1,119 @@ + + + + + + org.richfaces.ImageSelectTool + org.richfaces.ImageSelectTool + org.richfaces.component.html.HtmlImageSelectTool + org.richfaces.component.UIImageSelectTool + + + + + org.richfaces.component.renderkit.html.ImageSelectToolRenderer + + + + imageSelectTool + org.richfaces.taglib.ImageSelectToolTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + &ui_input_attributes; + + for + java.lang.String + + + null + + + minWidth + java.lang.Integer + Some description + + null + + + minHeight + java.lang.Integer + + + null + + + maxWidth + java.lang.Integer + + + null + + + maxHeight + java.lang.Integer + + + + + + aspectRatio + java.lang.Double + + + null + + + backgroundColor + java.lang.String + + + null + + + backgroundOpacity + java.lang.Double + + + null + + + onselect + java.lang.String + + + null + + + onchange + java.lang.String + + + null + + + var + java.lang.String + + + null + + + trueSizeWidth + java.lang.Integer + + + null + + + trueSizeHeight + java.lang.Integer + + + null + + + diff --git a/ui/imageSelectTool/src/main/java/org/richfaces/component/README b/ui/imageSelectTool/src/main/java/org/richfaces/component/README new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ui/imageSelectTool/src/main/java/org/richfaces/component/README diff --git a/ui/imageSelectTool/src/main/java/org/richfaces/component/UIImageSelectTool.java b/ui/imageSelectTool/src/main/java/org/richfaces/component/UIImageSelectTool.java new file mode 100644 index 0000000..de301bd --- /dev/null +++ b/ui/imageSelectTool/src/main/java/org/richfaces/component/UIImageSelectTool.java @@ -0,0 +1,61 @@ +package org.richfaces.component; + +import javax.faces.component.UIInput; + +public abstract class UIImageSelectTool extends UIInput { + + public static final String COMPONENT_TYPE = "org.richfaces.ImageSelectTool"; + public static final String COMPONENT_FAMILY = "org.richfaces.ImageSelectTool"; + + public abstract String getVar(); + + public abstract void setVar(String var); + + public abstract String getFor(); + + public abstract void setFor(String _for); + + public abstract String getOnchange(); + + public abstract void setOnchange(String onchange); + + public abstract String getOnselect(); + + public abstract void setOnselect(String onselect); + + public abstract Integer getMaxWidth(); + + public abstract void setMaxWidth(Integer maxWidth); + + public abstract Integer getMaxHeight(); + + public abstract void setMaxHeight(Integer maxHeight); + + public abstract Integer getMinWidth(); + + public abstract void setMinWidth(Integer minWidth); + + public abstract Integer getMinHeight(); + + public abstract void setMinHeight(Integer minHeight); + + public abstract Double getAspectRatio(); + + public abstract void setAspectRatio(Double aspectRatio); + + public abstract String getBackgroundColor(); + + public abstract void setBackgroundColor(String backgroundColor); + + public abstract Double getBackgroundOpacity(); + + public abstract void setBackgroundOpacity(Double backgroundOpacity); + + public abstract Integer getTrueSizeWidth(); + + public abstract void setTrueSizeWidth(Integer trueSizeWidth); + + public abstract Integer getTrueSizeHeight(); + + public abstract void setTrueSizeHeight(Integer trueSizeHeight); +} diff --git a/ui/imageSelectTool/src/main/java/org/richfaces/renderkit/html/ImageSelectToolRendererBase.java b/ui/imageSelectTool/src/main/java/org/richfaces/renderkit/html/ImageSelectToolRendererBase.java new file mode 100644 index 0000000..714b275 --- /dev/null +++ b/ui/imageSelectTool/src/main/java/org/richfaces/renderkit/html/ImageSelectToolRendererBase.java @@ -0,0 +1,188 @@ +package org.richfaces.renderkit.html; + +import org.ajax4jsf.context.AjaxContext; +import org.ajax4jsf.javascript.ScriptUtils; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.util.InputUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.richfaces.component.UIImageSelectTool; + +import javax.faces.FacesException; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import javax.faces.convert.Converter; +import javax.faces.convert.ConverterException; +import java.awt.*; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + +public class ImageSelectToolRendererBase extends HeaderResourcesRendererBase { + + private static Log logger = LogFactory.getLog(ImageSelectToolRendererBase.class); + + protected Class getComponentClass() { + return UIImageSelectTool.class; + } + + @Override + protected void doDecode(FacesContext context, UIComponent component) { + super.doDecode(context, component); + UIImageSelectTool uiImageSelectTool; + + if (component instanceof UIImageSelectTool) { + uiImageSelectTool = (UIImageSelectTool) component; + } else { + if (logger.isDebugEnabled()) { + logger.debug("No decoding necessary since the component " + component.getId() + + " is not an instance or a sub class of UIInplaceInput"); + } + return; + } + if (InputUtils.isDisabled(uiImageSelectTool) || InputUtils.isReadOnly(uiImageSelectTool)) { + if (logger.isDebugEnabled()) { + logger.debug(("No decoding necessary since the component " + component.getId() + " is disabled")); + } + return; + } + String inputId = getInputId(context, uiImageSelectTool); + if (inputId == null) { + throw new NullPointerException("component client id is null"); + } + Map request = context.getExternalContext().getRequestParameterMap(); + + String newValue = request.get(inputId); + if (newValue != null) { + uiImageSelectTool.setSubmittedValue(newValue); + } + } + + public String getInputId(FacesContext context, UIImageSelectTool component) { + return component.getClientId(context) + ":input"; + + } + + public Converter getConverter(FacesContext context, UIImageSelectTool component) { + Converter converter = component.getConverter(); + if (converter == null) { + converter = new RectangleConverter(); + } + return converter; + } + + @Override + public Object getConvertedValue(FacesContext context, UIComponent component, Object o) throws ConverterException { + UIImageSelectTool uiImageSelectTool = (UIImageSelectTool) component; + Converter converter = getConverter(context, uiImageSelectTool); + String valueString = (String) o; + return converter.getAsObject(context, component, valueString); + + } + + protected String getValueAsString(FacesContext context, UIComponent component) throws IOException { + UIImageSelectTool uiImageSelectTool = (UIImageSelectTool) component; + String valueString = (String) uiImageSelectTool.getSubmittedValue(); + if (valueString == null) { + Object value = uiImageSelectTool.getValue(); + if (value != null) { + Converter converter = getConverter(context, uiImageSelectTool); + valueString = converter.getAsString(context, component, value); + } + } + return valueString; + } + + public void writeInitFunction(FacesContext context, UIImageSelectTool component) throws IOException { + ResponseWriter writer = context.getResponseWriter(); + if (component.getVar() != null) { + writer.write("var " + component.getVar() + "="); + } + Map options = new HashMap(); + String forAttribute = component.getFor(); + UIComponent forComp; + String forClientId = null; + if (forAttribute == null || forAttribute.length() == 0) { + forComp = component; + while ((forComp = forComp.getParent()) != null) { + if (forComp instanceof javax.faces.component.UIGraphic) { + break; + } + } + /** + * We are not interested in UIViewRoot + */ + if (forComp.getParent() == null) { + forComp = null; + } + } else { + forComp = getUtils().findComponentFor(context, component.getParent(), forAttribute); + } + if (forComp == null) { + throw new FacesException("could not find target for croptool " + component.getId()); + } + forClientId = forComp.getClientId(context); + addOptionIfSet("ajaxRequest", AjaxContext.getCurrentInstance().isAjaxRequest(), options); + addOptionIfSet("onchange", component.getOnchange(), options); + addOptionIfSet("onselect", component.getOnselect(), options); + Rectangle rect = (Rectangle) component.getValue(); + if (rect != null) { + Map selection = new HashMap(); + selection.put("x", rect.x); + selection.put("y", rect.y); + selection.put("width", rect.width); + selection.put("height", rect.height); + addOptionIfSet("selection", selection, options); + } + addOptionIfSet("maxWidth", component.getMaxWidth(), options); + addOptionIfSet("maxHeight", component.getMaxHeight(), options); + addOptionIfSet("minWidth", component.getMinWidth(), options); + addOptionIfSet("minHeight", component.getMinHeight(), options); + addOptionIfSet("aspectRatio", component.getAspectRatio(), options); + addOptionIfSet("backgroundColor", component.getBackgroundColor(), options); + addOptionIfSet("backgroundOpacity", component.getBackgroundOpacity(), options); + addOptionIfSet("trueSizeWidth", component.getTrueSizeWidth(), options); + addOptionIfSet("trueSizeHeight", component.getTrueSizeHeight(), options); + writer.write("new RichFaces.ImageSelectTool("); + writer.write(ScriptUtils.toScript(getUtils().clientId(context, component))); + writer.write(","); + writer.write(ScriptUtils.toScript(getInputId(context, component))); + writer.write(","); + writer.write(ScriptUtils.toScript(forClientId)); + writer.write(","); + writer.write(ScriptUtils.toScript(options)); + writer.write(");"); + } + + private void addOptionIfSet(String optionName, Object value, Map options) { + if (value != null && value != "") { + options.put(optionName, value); + } + } + + private class RectangleConverter implements Converter { + + public Object getAsObject(FacesContext facesContext, UIComponent component, String s) { + StringTokenizer tokenizer = new StringTokenizer(s, ";"); + try { + Integer x = Integer.parseInt(tokenizer.nextToken()); + Integer y = Integer.parseInt(tokenizer.nextToken()); + Integer w = Integer.parseInt(tokenizer.nextToken()); + Integer h = Integer.parseInt(tokenizer.nextToken()); + return new Rectangle(x, y, w, h); + } catch (Exception e) { + throw new ConverterException("conversion failure; allowed pattern X;Y;W;H", e); + } + } + + public String getAsString(FacesContext facesContext, UIComponent component, Object o) { + if (!(o instanceof Rectangle)) { + throw new ConverterException(o + " is not instance of java.awt.Rectangle"); + } + Rectangle r = (Rectangle) o; + return r.x + ";" + r.y + ";" + r.width + ";" + r.height; + } + } +} diff --git a/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/css/Jcrop.gif b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/css/Jcrop.gif new file mode 100644 index 0000000..72ea7cc Binary files /dev/null and b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/css/Jcrop.gif differ diff --git a/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/css/richfaces.imageSelectTool.xcss b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/css/richfaces.imageSelectTool.xcss new file mode 100644 index 0000000..b33c8f9 --- /dev/null +++ b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/css/richfaces.imageSelectTool.xcss @@ -0,0 +1,50 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.Jcrop.js b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.Jcrop.js new file mode 100644 index 0000000..5dbbb91 --- /dev/null +++ b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.Jcrop.js @@ -0,0 +1,1199 @@ +/** + * jquery.Jcrop.js v0.9.8 + * jQuery Image Cropping Plugin + * @author Kelly Hallman + * Copyright (c) 2008-2009 Kelly Hallman - released under MIT License {{{ + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + + * }}} + */ + +(function($) { + +$.Jcrop = function(obj,opt) +{ + // Initialization {{{ + + // Sanitize some options {{{ + var obj = obj, opt = opt; + + if (typeof(obj) !== 'object') obj = $(obj)[0]; + if (typeof(opt) !== 'object') opt = { }; + + // Some on-the-fly fixes for MSIE...sigh + if (!('trackDocument' in opt)) + { + opt.trackDocument = $.browser.msie ? false : true; + if ($.browser.msie && $.browser.version.split('.')[0] == '8') + opt.trackDocument = true; + } + + if (!('keySupport' in opt)) + opt.keySupport = $.browser.msie ? false : true; + + // }}} + // Extend the default options {{{ + var defaults = { + + // Basic Settings + trackDocument: false, + baseClass: 'jcrop', + addClass: null, + + // Styling Options + bgColor: 'black', + bgOpacity: .6, + borderOpacity: .4, + handleOpacity: .5, + + handlePad: 5, + handleSize: 9, + handleOffset: 5, + edgeMargin: 14, + + aspectRatio: 0, + keySupport: true, + cornerHandles: true, + sideHandles: true, + drawBorders: true, + dragEdges: true, + + boxWidth: 0, + boxHeight: 0, + + boundary: 8, + animationDelay: 20, + swingSpeed: 3, + + allowSelect: true, + allowMove: true, + allowResize: true, + + minSelect: [ 0, 0 ], + maxSize: [ 0, 0 ], + minSize: [ 0, 0 ], + + // Callbacks / Event Handlers + onChange: function() { }, + onSelect: function() { } + + }; + var options = defaults; + setOptions(opt); + + // }}} + // Initialize some jQuery objects {{{ + + var $origimg = $(obj); + var $img = $origimg.clone().removeAttr('id').css({ position: 'absolute' }); + + $img.width($origimg.width()); + $img.height($origimg.height()); + $origimg.after($img).hide(); + + presize($img,options.boxWidth,options.boxHeight); + + var boundx = $img.width(), + boundy = $img.height(), + + $div = $('
') + .width(boundx).height(boundy) + .addClass(cssClass('holder')) + .css({ + position: 'relative', + backgroundColor: options.bgColor + }).insertAfter($origimg).append($img); + ; + + if (options.addClass) $div.addClass(options.addClass); + //$img.wrap($div); + + var $img2 = $('')/*{{{*/ + .attr('src',$img.attr('src')) + .css('position','absolute') + .width(boundx).height(boundy) + ;/*}}}*/ + var $img_holder = $('
')/*{{{*/ + .width(pct(100)).height(pct(100)) + .css({ + zIndex: 310, + position: 'absolute', + overflow: 'hidden' + }) + .append($img2) + ;/*}}}*/ + var $hdl_holder = $('
')/*{{{*/ + .width(pct(100)).height(pct(100)) + .css('zIndex',320); + /*}}}*/ + var $sel = $('
')/*{{{*/ + .css({ + position: 'absolute', + zIndex: 300 + }) + .insertBefore($img) + .append($img_holder,$hdl_holder) + ;/*}}}*/ + + var bound = options.boundary; + var $trk = newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)) + .css({ position: 'absolute', top: px(-bound), left: px(-bound), zIndex: 290 }) + .mousedown(newSelection); + + /* }}} */ + // Set more variables {{{ + + var xlimit, ylimit, xmin, ymin; + var xscale, yscale, enabled = true; + var docOffset = getPos($img), + // Internal states + btndown, lastcurs, dimmed, animating, + shift_down; + + // }}} + + + // }}} + // Internal Modules {{{ + + var Coords = function()/*{{{*/ + { + var x1 = 0, y1 = 0, x2 = 0, y2 = 0, ox, oy; + + function setPressed(pos)/*{{{*/ + { + var pos = rebound(pos); + x2 = x1 = pos[0]; + y2 = y1 = pos[1]; + }; + /*}}}*/ + function setCurrent(pos)/*{{{*/ + { + var pos = rebound(pos); + ox = pos[0] - x2; + oy = pos[1] - y2; + x2 = pos[0]; + y2 = pos[1]; + }; + /*}}}*/ + function getOffset()/*{{{*/ + { + return [ ox, oy ]; + }; + /*}}}*/ + function moveOffset(offset)/*{{{*/ + { + var ox = offset[0], oy = offset[1]; + + if (0 > x1 + ox) ox -= ox + x1; + if (0 > y1 + oy) oy -= oy + y1; + + if (boundy < y2 + oy) oy += boundy - (y2 + oy); + if (boundx < x2 + ox) ox += boundx - (x2 + ox); + + x1 += ox; + x2 += ox; + y1 += oy; + y2 += oy; + }; + /*}}}*/ + function getCorner(ord)/*{{{*/ + { + var c = getFixed(); + switch(ord) + { + case 'ne': return [ c.x2, c.y ]; + case 'nw': return [ c.x, c.y ]; + case 'se': return [ c.x2, c.y2 ]; + case 'sw': return [ c.x, c.y2 ]; + } + }; + /*}}}*/ + function getFixed()/*{{{*/ + { + if (!options.aspectRatio) return getRect(); + // This function could use some optimization I think... + var aspect = options.aspectRatio, + min_x = options.minSize[0]/xscale, + min_y = options.minSize[1]/yscale, + max_x = options.maxSize[0]/xscale, + max_y = options.maxSize[1]/yscale, + rw = x2 - x1, + rh = y2 - y1, + rwa = Math.abs(rw), + rha = Math.abs(rh), + real_ratio = rwa / rha, + xx, yy + ; + if (max_x == 0) { max_x = boundx * 10 } + if (max_y == 0) { max_y = boundy * 10 } + if (real_ratio < aspect) + { + yy = y2; + w = rha * aspect; + xx = rw < 0 ? x1 - w : w + x1; + + if (xx < 0) + { + xx = 0; + h = Math.abs((xx - x1) / aspect); + yy = rh < 0 ? y1 - h: h + y1; + } + else if (xx > boundx) + { + xx = boundx; + h = Math.abs((xx - x1) / aspect); + yy = rh < 0 ? y1 - h : h + y1; + } + } + else + { + xx = x2; + h = rwa / aspect; + yy = rh < 0 ? y1 - h : y1 + h; + if (yy < 0) + { + yy = 0; + w = Math.abs((yy - y1) * aspect); + xx = rw < 0 ? x1 - w : w + x1; + } + else if (yy > boundy) + { + yy = boundy; + w = Math.abs(yy - y1) * aspect; + xx = rw < 0 ? x1 - w : w + x1; + } + } + + // Magic %-) + if(xx > x1) { // right side + if(xx - x1 < min_x) { + xx = x1 + min_x; + } else if (xx - x1 > max_x) { + xx = x1 + max_x; + } + if(yy > y1) { + yy = y1 + (xx - x1)/aspect; + } else { + yy = y1 - (xx - x1)/aspect; + } + } else if (xx < x1) { // left side + if(x1 - xx < min_x) { + xx = x1 - min_x + } else if (x1 - xx > max_x) { + xx = x1 - max_x; + } + if(yy > y1) { + yy = y1 + (x1 - xx)/aspect; + } else { + yy = y1 - (x1 - xx)/aspect; + } + } + + if(xx < 0) { + x1 -= xx; + xx = 0; + } else if (xx > boundx) { + x1 -= xx - boundx; + xx = boundx; + } + + if(yy < 0) { + y1 -= yy; + yy = 0; + } else if (yy > boundy) { + y1 -= yy - boundy; + yy = boundy; + } + + return last = makeObj(flipCoords(x1,y1,xx,yy)); + }; + /*}}}*/ + function rebound(p)/*{{{*/ + { + if (p[0] < 0) p[0] = 0; + if (p[1] < 0) p[1] = 0; + + if (p[0] > boundx) p[0] = boundx; + if (p[1] > boundy) p[1] = boundy; + + return [ p[0], p[1] ]; + }; + /*}}}*/ + function flipCoords(x1,y1,x2,y2)/*{{{*/ + { + var xa = x1, xb = x2, ya = y1, yb = y2; + if (x2 < x1) + { + xa = x2; + xb = x1; + } + if (y2 < y1) + { + ya = y2; + yb = y1; + } + return [ Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb) ]; + }; + /*}}}*/ + function getRect()/*{{{*/ + { + var xsize = x2 - x1; + var ysize = y2 - y1; + + if (xlimit && (Math.abs(xsize) > xlimit)) + x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); + if (ylimit && (Math.abs(ysize) > ylimit)) + y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); + + if (ymin && (Math.abs(ysize) < ymin)) + y2 = (ysize > 0) ? (y1 + ymin) : (y1 - ymin); + if (xmin && (Math.abs(xsize) < xmin)) + x2 = (xsize > 0) ? (x1 + xmin) : (x1 - xmin); + + if (x1 < 0) { x2 -= x1; x1 -= x1; } + if (y1 < 0) { y2 -= y1; y1 -= y1; } + if (x2 < 0) { x1 -= x2; x2 -= x2; } + if (y2 < 0) { y1 -= y2; y2 -= y2; } + if (x2 > boundx) { var delta = x2 - boundx; x1 -= delta; x2 -= delta; } + if (y2 > boundy) { var delta = y2 - boundy; y1 -= delta; y2 -= delta; } + if (x1 > boundx) { var delta = x1 - boundy; y2 -= delta; y1 -= delta; } + if (y1 > boundy) { var delta = y1 - boundy; y2 -= delta; y1 -= delta; } + + return makeObj(flipCoords(x1,y1,x2,y2)); + }; + /*}}}*/ + function makeObj(a)/*{{{*/ + { + return { x: a[0], y: a[1], x2: a[2], y2: a[3], + w: a[2] - a[0], h: a[3] - a[1] }; + }; + /*}}}*/ + + return { + flipCoords: flipCoords, + setPressed: setPressed, + setCurrent: setCurrent, + getOffset: getOffset, + moveOffset: moveOffset, + getCorner: getCorner, + getFixed: getFixed + }; + }(); + + /*}}}*/ + var Selection = function()/*{{{*/ + { + var start, end, dragmode, awake, hdep = 370; + var borders = { }; + var handle = { }; + var seehandles = false; + var hhs = options.handleOffset; + + /* Insert draggable elements {{{*/ + + // Insert border divs for outline + if (options.drawBorders) { + borders = { + top: insertBorder('hline') + .css('top',$.browser.msie?px(-1):px(0)), + bottom: insertBorder('hline'), + left: insertBorder('vline'), + right: insertBorder('vline') + }; + } + + // Insert handles on edges + if (options.dragEdges) { + handle.t = insertDragbar('n'); + handle.b = insertDragbar('s'); + handle.r = insertDragbar('e'); + handle.l = insertDragbar('w'); + } + + // Insert side handles + options.sideHandles && + createHandles(['n','s','e','w']); + + // Insert corner handles + options.cornerHandles && + createHandles(['sw','nw','ne','se']); + + /*}}}*/ + // Private Methods + function insertBorder(type)/*{{{*/ + { + var jq = $('
') + .css({position: 'absolute', opacity: options.borderOpacity }) + .addClass(cssClass(type)); + $img_holder.append(jq); + return jq; + }; + /*}}}*/ + function dragDiv(ord,zi)/*{{{*/ + { + var jq = $('
') + .mousedown(createDragger(ord)) + .css({ + cursor: ord+'-resize', + position: 'absolute', + zIndex: zi + }) + ; + $hdl_holder.append(jq); + return jq; + }; + /*}}}*/ + function insertHandle(ord)/*{{{*/ + { + return dragDiv(ord,hdep++) + .css({ top: px(-hhs+1), left: px(-hhs+1), opacity: options.handleOpacity }) + .addClass(cssClass('handle')); + }; + /*}}}*/ + function insertDragbar(ord)/*{{{*/ + { + var s = options.handleSize, + o = hhs, + h = s, w = s, + t = o, l = o; + + switch(ord) + { + case 'n': case 's': w = pct(100); break; + case 'e': case 'w': h = pct(100); break; + } + + return dragDiv(ord,hdep++).width(w).height(h) + .css({ top: px(-t+1), left: px(-l+1)}); + }; + /*}}}*/ + function createHandles(li)/*{{{*/ + { + for(i in li) handle[li[i]] = insertHandle(li[i]); + }; + /*}}}*/ + function moveHandles(c)/*{{{*/ + { + var midvert = Math.round((c.h / 2) - hhs), + midhoriz = Math.round((c.w / 2) - hhs), + north = west = -hhs+1, + east = c.w - hhs, + south = c.h - hhs, + x, y; + + 'e' in handle && + handle.e.css({ top: px(midvert), left: px(east) }) && + handle.w.css({ top: px(midvert) }) && + handle.s.css({ top: px(south), left: px(midhoriz) }) && + handle.n.css({ left: px(midhoriz) }); + + 'ne' in handle && + handle.ne.css({ left: px(east) }) && + handle.se.css({ top: px(south), left: px(east) }) && + handle.sw.css({ top: px(south) }); + + 'b' in handle && + handle.b.css({ top: px(south) }) && + handle.r.css({ left: px(east) }); + }; + /*}}}*/ + function moveto(x,y)/*{{{*/ + { + $img2.css({ top: px(-y), left: px(-x) }); + $sel.css({ top: px(y), left: px(x) }); + }; + /*}}}*/ + function resize(w,h)/*{{{*/ + { + $sel.width(w).height(h); + }; + /*}}}*/ + function refresh()/*{{{*/ + { + var c = Coords.getFixed(); + + Coords.setPressed([c.x,c.y]); + Coords.setCurrent([c.x2,c.y2]); + + updateVisible(); + }; + /*}}}*/ + + // Internal Methods + function updateVisible()/*{{{*/ + { if (awake) return update(); }; + /*}}}*/ + function update()/*{{{*/ + { + var c = Coords.getFixed(); + + resize(c.w,c.h); + moveto(c.x,c.y); + + options.drawBorders && + borders['right'].css({ left: px(c.w-1) }) && + borders['bottom'].css({ top: px(c.h-1) }); + + $img.css('opacity', options.bgOpacity); + + seehandles && moveHandles(c); + awake || show(); + + options.onChange(unscale(c)); + }; + /*}}}*/ + function show()/*{{{*/ + { + $sel.show(); + $img.css('opacity',options.bgOpacity); + awake = true; + }; + /*}}}*/ + function release()/*{{{*/ + { + disableHandles(); + $sel.hide(); + $img.css('opacity',1); + awake = false; + }; + /*}}}*/ + function showHandles()//{{{ + { + if (seehandles) + { + moveHandles(Coords.getFixed()); + $hdl_holder.show(); + } + }; + //}}} + function enableHandles()/*{{{*/ + { + seehandles = true; + if (options.allowResize) + { + moveHandles(Coords.getFixed()); + $hdl_holder.show(); + return true; + } + }; + /*}}}*/ + function disableHandles()/*{{{*/ + { + seehandles = false; + $hdl_holder.hide(); + }; + /*}}}*/ + function animMode(v)/*{{{*/ + { + (animating = v) ? disableHandles(): enableHandles(); + }; + /*}}}*/ + function done()/*{{{*/ + { + animMode(false); + refresh(); + }; + /*}}}*/ + + var $track = newTracker().mousedown(createDragger('move')) + .css({ cursor: 'move', position: 'absolute', zIndex: 360 }) + + $img_holder.append($track); + disableHandles(); + + return { + updateVisible: updateVisible, + update: update, + release: release, + refresh: refresh, + setCursor: function (cursor) { $track.css('cursor',cursor); }, + enableHandles: enableHandles, + enableOnly: function() { seehandles = true; }, + showHandles: showHandles, + disableHandles: disableHandles, + animMode: animMode, + done: done + }; + }(); + /*}}}*/ + var Tracker = function()/*{{{*/ + { + var onMove = function() { }, + onDone = function() { }, + trackDoc = options.trackDocument; + + if (!trackDoc) + { + $trk + .mousemove(trackMove) + .mouseup(trackUp) + .mouseout(trackUp) + ; + } + + function toFront()/*{{{*/ + { + $trk.css({zIndex:450}); + if (trackDoc) + { + $(document) + .mousemove(trackMove) + .mouseup(trackUp) + ; + } + } + /*}}}*/ + function toBack()/*{{{*/ + { + $trk.css({zIndex:290}); + if (trackDoc) + { + $(document) + .unbind('mousemove',trackMove) + .unbind('mouseup',trackUp) + ; + } + } + /*}}}*/ + function trackMove(e)/*{{{*/ + { + onMove(mouseAbs(e)); + }; + /*}}}*/ + function trackUp(e)/*{{{*/ + { + e.preventDefault(); + e.stopPropagation(); + + if (btndown) + { + btndown = false; + + onDone(mouseAbs(e)); + options.onSelect(unscale(Coords.getFixed())); + toBack(); + onMove = function() { }; + onDone = function() { }; + } + + return false; + }; + /*}}}*/ + + function activateHandlers(move,done)/* {{{ */ + { + btndown = true; + onMove = move; + onDone = done; + toFront(); + return false; + }; + /* }}} */ + + function setCursor(t) { $trk.css('cursor',t); }; + + $img.before($trk); + return { + activateHandlers: activateHandlers, + setCursor: setCursor + }; + }(); + /*}}}*/ + var KeyManager = function()/*{{{*/ + { + var $keymgr = $('') + .css({ position: 'absolute', left: '-30px' }) + .keypress(parseKey) + .blur(onBlur), + + $keywrap = $('
') + .css({ + position: 'absolute', + overflow: 'hidden' + }) + .append($keymgr) + ; + + function watchKeys()/*{{{*/ + { + if (options.keySupport) + { + $keymgr.show(); + $keymgr.focus(); + } + }; + /*}}}*/ + function onBlur(e)/*{{{*/ + { + $keymgr.hide(); + }; + /*}}}*/ + function doNudge(e,x,y)/*{{{*/ + { + if (options.allowMove) { + Coords.moveOffset([x,y]); + Selection.updateVisible(); + }; + e.preventDefault(); + e.stopPropagation(); + }; + /*}}}*/ + function parseKey(e)/*{{{*/ + { + if (e.ctrlKey) return true; + shift_down = e.shiftKey ? true : false; + var nudge = shift_down ? 10 : 1; + switch(e.keyCode) + { + case 37: doNudge(e,-nudge,0); break; + case 39: doNudge(e,nudge,0); break; + case 38: doNudge(e,0,-nudge); break; + case 40: doNudge(e,0,nudge); break; + + case 27: Selection.release(); break; + + case 9: return true; + } + + return e; + }; + /*}}}*/ + + if (options.keySupport) $keywrap.insertBefore($img); + return { + watchKeys: watchKeys + }; + }(); + /*}}}*/ + + // }}} + // Internal Methods {{{ + + function px(n) { return '' + parseInt(n) + 'px'; }; + function pct(n) { return '' + parseInt(n) + '%'; }; + function cssClass(cl) { return options.baseClass + '-' + cl; }; + function getPos(obj)/*{{{*/ + { + // Updated in v0.9.4 to use built-in dimensions plugin + var pos = $(obj).offset(); + return [ pos.left, pos.top ]; + }; + /*}}}*/ + function mouseAbs(e)/*{{{*/ + { + return [ (e.pageX - docOffset[0]), (e.pageY - docOffset[1]) ]; + }; + /*}}}*/ + function myCursor(type)/*{{{*/ + { + if (type != lastcurs) + { + Tracker.setCursor(type); + //Handles.xsetCursor(type); + lastcurs = type; + } + }; + /*}}}*/ + function startDragMode(mode,pos)/*{{{*/ + { + docOffset = getPos($img); + Tracker.setCursor(mode=='move'?mode:mode+'-resize'); + + if (mode == 'move') + return Tracker.activateHandlers(createMover(pos), doneSelect); + + var fc = Coords.getFixed(); + var opp = oppLockCorner(mode); + var opc = Coords.getCorner(oppLockCorner(opp)); + + Coords.setPressed(Coords.getCorner(opp)); + Coords.setCurrent(opc); + + Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect); + }; + /*}}}*/ + function dragmodeHandler(mode,f)/*{{{*/ + { + return function(pos) { + if (!options.aspectRatio) switch(mode) + { + case 'e': pos[1] = f.y2; break; + case 'w': pos[1] = f.y2; break; + case 'n': pos[0] = f.x2; break; + case 's': pos[0] = f.x2; break; + } + else switch(mode) + { + case 'e': pos[1] = f.y+1; break; + case 'w': pos[1] = f.y+1; break; + case 'n': pos[0] = f.x+1; break; + case 's': pos[0] = f.x+1; break; + } + Coords.setCurrent(pos); + Selection.update(); + }; + }; + /*}}}*/ + function createMover(pos)/*{{{*/ + { + var lloc = pos; + KeyManager.watchKeys(); + + return function(pos) + { + Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); + lloc = pos; + + Selection.update(); + }; + }; + /*}}}*/ + function oppLockCorner(ord)/*{{{*/ + { + switch(ord) + { + case 'n': return 'sw'; + case 's': return 'nw'; + case 'e': return 'nw'; + case 'w': return 'ne'; + case 'ne': return 'sw'; + case 'nw': return 'se'; + case 'se': return 'nw'; + case 'sw': return 'ne'; + }; + }; + /*}}}*/ + function createDragger(ord)/*{{{*/ + { + return function(e) { + if (options.disabled) return false; + if ((ord == 'move') && !options.allowMove) return false; + btndown = true; + startDragMode(ord,mouseAbs(e)); + e.stopPropagation(); + e.preventDefault(); + return false; + }; + }; + /*}}}*/ + function presize($obj,w,h)/*{{{*/ + { + var nw = $obj.width(), nh = $obj.height(); + if ((nw > w) && w > 0) + { + nw = w; + nh = (w/$obj.width()) * $obj.height(); + } + if ((nh > h) && h > 0) + { + nh = h; + nw = (h/$obj.height()) * $obj.width(); + } + xscale = $obj.width() / nw; + yscale = $obj.height() / nh; + $obj.width(nw).height(nh); + }; + /*}}}*/ + function unscale(c)/*{{{*/ + { + return { + x: parseInt(c.x * xscale), y: parseInt(c.y * yscale), + x2: parseInt(c.x2 * xscale), y2: parseInt(c.y2 * yscale), + w: parseInt(c.w * xscale), h: parseInt(c.h * yscale) + }; + }; + /*}}}*/ + function doneSelect(pos)/*{{{*/ + { + var c = Coords.getFixed(); + if (c.w > options.minSelect[0] && c.h > options.minSelect[1]) + { + Selection.enableHandles(); + Selection.done(); + } + else + { + Selection.release(); + } + Tracker.setCursor( options.allowSelect?'crosshair':'default' ); + }; + /*}}}*/ + function newSelection(e)/*{{{*/ + { + if (options.disabled) return false; + if (!options.allowSelect) return false; + btndown = true; + docOffset = getPos($img); + Selection.disableHandles(); + myCursor('crosshair'); + var pos = mouseAbs(e); + Coords.setPressed(pos); + Tracker.activateHandlers(selectDrag,doneSelect); + KeyManager.watchKeys(); + Selection.update(); + + e.stopPropagation(); + e.preventDefault(); + return false; + }; + /*}}}*/ + function selectDrag(pos)/*{{{*/ + { + Coords.setCurrent(pos); + Selection.update(); + }; + /*}}}*/ + function newTracker() + { + var trk = $('
').addClass(cssClass('tracker')); + $.browser.msie && trk.css({ opacity: 0, backgroundColor: 'white' }); + return trk; + }; + + // }}} + // API methods {{{ + + function animateTo(a)/*{{{*/ + { + var x1 = a[0] / xscale, + y1 = a[1] / yscale, + x2 = a[2] / xscale, + y2 = a[3] / yscale; + + if (animating) return; + + var animto = Coords.flipCoords(x1,y1,x2,y2); + var c = Coords.getFixed(); + var animat = initcr = [ c.x, c.y, c.x2, c.y2 ]; + var interv = options.animationDelay; + + var x = animat[0]; + var y = animat[1]; + var x2 = animat[2]; + var y2 = animat[3]; + var ix1 = animto[0] - initcr[0]; + var iy1 = animto[1] - initcr[1]; + var ix2 = animto[2] - initcr[2]; + var iy2 = animto[3] - initcr[3]; + var pcent = 0; + var velocity = options.swingSpeed; + + Selection.animMode(true); + + var animator = function() + { + return function() + { + pcent += (100 - pcent) / velocity; + + animat[0] = x + ((pcent / 100) * ix1); + animat[1] = y + ((pcent / 100) * iy1); + animat[2] = x2 + ((pcent / 100) * ix2); + animat[3] = y2 + ((pcent / 100) * iy2); + + if (pcent < 100) animateStart(); + else Selection.done(); + + if (pcent >= 99.8) pcent = 100; + + setSelectRaw(animat); + }; + }(); + + function animateStart() + { window.setTimeout(animator,interv); }; + + animateStart(); + }; + /*}}}*/ + function setSelect(rect)//{{{ + { + setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]); + }; + //}}} + function setSelectRaw(l) /*{{{*/ + { + Coords.setPressed([l[0],l[1]]); + Coords.setCurrent([l[2],l[3]]); + Selection.update(); + }; + /*}}}*/ + function setOptions(opt)/*{{{*/ + { + if (typeof(opt) != 'object') opt = { }; + options = $.extend(options,opt); + + if (typeof(options.onChange)!=='function') + options.onChange = function() { }; + + if (typeof(options.onSelect)!=='function') + options.onSelect = function() { }; + + }; + /*}}}*/ + function tellSelect()/*{{{*/ + { + return unscale(Coords.getFixed()); + }; + /*}}}*/ + function tellScaled()/*{{{*/ + { + return Coords.getFixed(); + }; + /*}}}*/ + function setOptionsNew(opt)/*{{{*/ + { + setOptions(opt); + interfaceUpdate(); + }; + /*}}}*/ + function disableCrop()//{{{ + { + options.disabled = true; + Selection.disableHandles(); + Selection.setCursor('default'); + Tracker.setCursor('default'); + }; + //}}} + function enableCrop()//{{{ + { + options.disabled = false; + interfaceUpdate(); + }; + //}}} + function cancelCrop()//{{{ + { + Selection.done(); + Tracker.activateHandlers(null,null); + }; + //}}} + function destroy()//{{{ + { + $div.remove(); + $origimg.show(); + }; + //}}} + + function interfaceUpdate(alt)//{{{ + // This method tweaks the interface based on options object. + // Called when options are changed and at end of initialization. + { + options.allowResize ? + alt?Selection.enableOnly():Selection.enableHandles(): + Selection.disableHandles(); + + Tracker.setCursor( options.allowSelect? 'crosshair': 'default' ); + Selection.setCursor( options.allowMove? 'move': 'default' ); + + $div.css('backgroundColor',options.bgColor); + + if ('setSelect' in options) { + setSelect(opt.setSelect); + Selection.done(); + delete(options.setSelect); + } + + if ('trueSize' in options) { + xscale = options.trueSize[0] / boundx; + yscale = options.trueSize[1] / boundy; + } + + xlimit = options.maxSize[0] || 0; + ylimit = options.maxSize[1] || 0; + xmin = options.minSize[0] || 0; + ymin = options.minSize[1] || 0; + + if ('outerImage' in options) + { + $img.attr('src',options.outerImage); + delete(options.outerImage); + } + + Selection.refresh(); + }; + //}}} + + // }}} + + $hdl_holder.hide(); + interfaceUpdate(true); + + var api = { + animateTo: animateTo, + setSelect: setSelect, + setOptions: setOptionsNew, + tellSelect: tellSelect, + tellScaled: tellScaled, + + disable: disableCrop, + enable: enableCrop, + cancel: cancelCrop, + + focus: KeyManager.watchKeys, + + getBounds: function() { return [ boundx * xscale, boundy * yscale ]; }, + getWidgetSize: function() { return [ boundx, boundy ]; }, + + release: Selection.release, + destroy: destroy + + }; + + $origimg.data('Jcrop',api); + return api; +}; + +$.fn.Jcrop = function(options)/*{{{*/ +{ + function attachWhenDone(from)/*{{{*/ + { + var loadsrc = options.useImg || from.src; + var img = new Image(); + img.onload = function() { $.Jcrop(from,options); }; + img.src = loadsrc; + }; + /*}}}*/ + if (typeof(options) !== 'object') options = { }; + + // Iterate over each object, attach Jcrop + this.each(function() + { + // If we've already attached to this object + if ($(this).data('Jcrop')) + { + // The API can be requested this way (undocumented) + if (options == 'api') return $(this).data('Jcrop'); + // Otherwise, we just reset the options... + else $(this).data('Jcrop').setOptions(options); + } + // If we haven't been attached, preload and attach + else attachWhenDone(this); + }); + + // Return "this" so we're chainable a la jQuery plugin-style! + return this; +}; +/*}}}*/ + +})(jQuery); diff --git a/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.imageSelectTool.js b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.imageSelectTool.js new file mode 100644 index 0000000..ed3789a --- /dev/null +++ b/ui/imageSelectTool/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.imageSelectTool.js @@ -0,0 +1,150 @@ +if (!window.RichFaces) window.RichFaces = {}; +RichFaces.ImageSelectTool = function(selectorId, inputId, forId, options) { + /** + * domNode is element representing imageSelectTool component + */ + var domNode = document.getElementById(selectorId); + var input = jQuery(document.getElementById(inputId)); + var delegate; + var fireChangeListener = function(event) { + if (typeof(options.onchange) === "function") { + options.onchange(event); + } else if (typeof(options.onchange) === "string") { + eval(options.onchange); + } + }; + var fireSelectListener = function(event) { + if (typeof(options.onselect) === "function") { + options.onselect(event); + } else if (typeof(options.onselect) === "string") { + eval(options.onselect); + } + }; + var updateInput = function(event) { + input.val(event.x + ";" + event.y + ";" + event.width + ";" + event.height); + }; + var detach = function() { + delete domNode.component; + }; + if (domNode.component != null && typeof domNode.component.destroy == "function") { + domNode.component.destroy(); + } + domNode.component = this; + options = options || {}; + options.onChange = function(event) { + event = { + x:event.x, + y:event.y, + width:event.w, + height:event.h + }; + updateInput(event); + fireChangeListener(event); + }; + options.onSelect = function(event) { + event = { + x:event.x, + y:event.y, + width:event.w, + height:event.h + }; + updateInput(event); + fireSelectListener(event); + }; + if (options.minWidth != null && options.minHeight != null) { + options.minSize = [ options.minWidth, options.minHeight ]; + } + if (options.maxWidth != null && options.maxHeight != null) { + options.maxSize = [ options.maxWidth, options.maxHeight ]; + } + if (options.selection) { + options.setSelect = [ + options.selection.x, + options.selection.y, + options.selection.x + options.selection.width, + options.selection.y + options.selection.height + ]; + } + options.bgColor = options.backgroundColor; + options.bgOpacity = options.backgroundOpacity; + + //initialize Jcrop + function initialize() { + var image = document.getElementById(forId); + + function doInitialize() { + delegate = jQuery.Jcrop(image, options); + } + + if (image.complete) { + doInitialize(); + } else { + image.onload = doInitialize; + } + } + + if (options.ajaxRequest) { + initialize(); + } else { + jQuery(initialize()); + } + + return { + setSelection : function(x, y, w, h) { + var event = {x:x,y:y,width:w,height:h}; + updateInput(event); + delegate.setSelect([x,y,x + w,y + h]); + fireSelectListener(this.getSelection()); + }, + animateTo : function(x, y, w, h) { + var event = {x:x,y:y,width:w,height:h}; + updateInput(event); + delegate.animateTo([x,y,x + w,y + h]); + fireSelectListener(event); + }, + setOptions : function(options) { + delegate.setOptions(options); + }, + getSelection : function() { + var selection = delegate.tellSelect(); + return { + x:selection.x, + y:selection.y, + width:selection.w, + height:selection.h + }; + }, + getScaledSelection : function() { + var selection = delegate.tellScaled(); + return { + x:selection.x, + y:selection.y, + width:selection.w, + height:selection.h + }; + }, + disable : function() { + delegate.disable(); + + }, + enable : function() { + delegate.enable(); + }, + focus : function() { + delegate.focus(); + }, + getBounds : function() { + return delegate.getBounds(); + }, + getWidgetSize : function() { + return delegate.getWidgetSize(); + }, + release : function() { + delegate.release(); + }, + destroy : function() { + delegate.destroy(); + detach(); + } + }; +}; \ No newline at end of file diff --git a/ui/imageSelectTool/src/main/templates/README b/ui/imageSelectTool/src/main/templates/README new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ui/imageSelectTool/src/main/templates/README diff --git a/ui/imageSelectTool/src/main/templates/htmlImageSelectTool.jspx b/ui/imageSelectTool/src/main/templates/htmlImageSelectTool.jspx new file mode 100644 index 0000000..25a40ba --- /dev/null +++ b/ui/imageSelectTool/src/main/templates/htmlImageSelectTool.jspx @@ -0,0 +1,36 @@ + + + + /org/richfaces/renderkit/html/css/richfaces.imageSelectTool.xcss + + new org.ajax4jsf.javascript.PrototypeScript(), + new org.ajax4jsf.javascript.AjaxScript(), + /org/richfaces/renderkit/html/scripts/jquery/jquery.js, + /org/richfaces/renderkit/html/scripts/jquery.Jcrop.js, + /org/richfaces/renderkit/html/scripts/richfaces.imageSelectTool.js + + + + + + + variables.setVariable("inputId",getInputId(context,component)); + + +
+ + +
+
\ No newline at end of file diff --git a/ui/jQueryPlugin/pom.xml b/ui/jQueryPlugin/pom.xml new file mode 100644 index 0000000..f8a5541 --- /dev/null +++ b/ui/jQueryPlugin/pom.xml @@ -0,0 +1,72 @@ + + + + ui + org.richfaces.sandbox + 3.3.4-SNAPSHOT + + 4.0.0 + org.richfaces.sandbox.ui + jQueryPlugin + jQueryPlugin + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces + + jQueryPlugin + http://richfaces.org/sandbox/jQueryPlugin + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + diff --git a/ui/jQueryPlugin/src/main/config/component/jQueryPlugin.xml b/ui/jQueryPlugin/src/main/config/component/jQueryPlugin.xml new file mode 100644 index 0000000..b52c3c3 --- /dev/null +++ b/ui/jQueryPlugin/src/main/config/component/jQueryPlugin.xml @@ -0,0 +1,40 @@ + + + + + org.richfaces.JQueryPlugin + org.richfaces.JQueryPlugin + org.richfaces.component.html.HtmlJQueryPlugin + org.richfaces.component.UIJQueryPlugin + + + + + org.richfaces.JQueryPluginRenderer + org.richfaces.renderkit.html.JQueryPluginRenderer + + + jQueryPlugin + org.richfaces.taglib.JQueryPluginTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + org.richfaces.taglib.HtmlJQueryPluginTagTest + org.ajax4jsf.tests.AbstractJspTestCase + + + + &ui_component_attributes; + + src + java.lang.String + + Path to the plugin file. + + + + diff --git a/ui/jQueryPlugin/src/main/java/org/richfaces/component/UIJQueryPlugin.java b/ui/jQueryPlugin/src/main/java/org/richfaces/component/UIJQueryPlugin.java new file mode 100644 index 0000000..d938b23 --- /dev/null +++ b/ui/jQueryPlugin/src/main/java/org/richfaces/component/UIJQueryPlugin.java @@ -0,0 +1,14 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UIJQueryPlugin extends UIComponentBase { + + public static final String COMPONENT_TYPE = "org.richfaces.JQueryPlugin"; + public static final String COMPONENT_FAMILY = "org.richfaces.JQueryPlugin"; + + public abstract String getSrc(); + + public abstract void setSrc(String src); + +} diff --git a/ui/jQueryPlugin/src/main/java/org/richfaces/renderkit/html/JQueryPluginRenderer.java b/ui/jQueryPlugin/src/main/java/org/richfaces/renderkit/html/JQueryPluginRenderer.java new file mode 100644 index 0000000..29d418e --- /dev/null +++ b/ui/jQueryPlugin/src/main/java/org/richfaces/renderkit/html/JQueryPluginRenderer.java @@ -0,0 +1,49 @@ +package org.richfaces.renderkit.html; + +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.ProducerContext; +import org.ajax4jsf.resource.InternetResource; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.richfaces.component.UIJQueryPlugin; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import java.io.IOException; + +public class JQueryPluginRenderer extends HeaderResourcesRendererBase { + + private static Log logger = LogFactory.getLog(JQueryPluginRenderer.class); + + /** + * It's not an error, second jquery.js is just to avoid NullPointerException and should be overwritten + * in encodeToHead. + */ + private final InternetResource[] scripts = { + getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js"), + getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js") + }; + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected Class getComponentClass() { + return UIJQueryPlugin.class; + } + + @Override + public void encodeToHead(FacesContext context, UIComponent component, ProducerContext pc) throws IOException { + if (component instanceof UIJQueryPlugin) { + final String src = ((UIJQueryPlugin) component).getSrc(); + try { + scripts[1] = getResource(src); + } catch (Exception e) { + logger.error("Problem with loading source for component " + component.getId() + ".", e); + } + } + super.encodeToHead(context, component, pc); + } +} diff --git a/ui/lightbox/pom.xml b/ui/lightbox/pom.xml new file mode 100644 index 0000000..3920949 --- /dev/null +++ b/ui/lightbox/pom.xml @@ -0,0 +1,72 @@ + + + + ui + org.richfaces.sandbox + 3.3.4-SNAPSHOT + + 4.0.0 + org.richfaces.sandbox.ui + lightbox + lightbox + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces + + lightbox + http://richfaces.org/sandbox/lightbox + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + diff --git a/ui/lightbox/src/main/config/component/lightbox.xml b/ui/lightbox/src/main/config/component/lightbox.xml new file mode 100644 index 0000000..ed58b1a --- /dev/null +++ b/ui/lightbox/src/main/config/component/lightbox.xml @@ -0,0 +1,144 @@ + + + + org.richfaces.Lightbox + org.richfaces.Lightbox + org.richfaces.component.html.HtmlLightbox + org.richfaces.component.UILightbox + + + + + org.richfaces.LightboxRenderer + org.richfaces.renderkit.html.LightboxRenderer + + + lightbox + org.richfaces.taglib.LightboxTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + org.richfaces.taglib.HtmlLightboxTagTest + org.ajax4jsf.tests.AbstractJspTestCase + + + &ui_component_attributes; + + selector + java.lang.String + + A jQuery selector. + + + + overlayBgColor + java.lang.String + + Background color to overlay; inform a hexadecimal value like: #RRGGBB. Where RR, GG, and BB are the hexadecimal values for the red, green, and + blue values of the color. + + + + overlayOpacity + java.lang.Double + + Opacity value to overlay; inform: 0.X. Where X are number from 0 to 9. + + + + fixedNavigation + java.lang.Boolean + + Boolean that informs if the navigation (next and prev button) will be fixed or not in the interface. + + + + containerBorderSize + java.lang.Integer + + If you adjust the padding in the CSS for the container, #lightbox-container-image-box, you will need to update this value + + + + containerResizeSpeed + java.lang.Integer + + Specify the resize duration of container image. These number are miliseconds. 400 is default. + + + + txtImage + java.lang.String + + Specify text "Image". + + + + txtOf + java.lang.String + + Specify text "of". + + + + keyToClose + java.lang.String + + Letter to close the jQuery lightBox interface. Beyond this letter, the letter X and the SCAPE key is used to. Default 'c'. + + + + keyToPrev + java.lang.String + + Letter to show the previous image. Default 'p'. + + + + keyToNext + java.lang.String + + Letter to show the next image. Default 'n'. + + + + imageBlank + java.lang.String + + Blank image. + + + + imageLoading + java.lang.String + + Image loading icon. + + + + imageBtnNext + java.lang.String + + Image for "next" button. + + + + imageBtnPrev + java.lang.String + + Image for "previous" button. + + + + imageBtnClose + java.lang.String + + Image for "close" button. + + + + + diff --git a/ui/lightbox/src/main/java/org/richfaces/component/UILightbox.java b/ui/lightbox/src/main/java/org/richfaces/component/UILightbox.java new file mode 100644 index 0000000..78449f4 --- /dev/null +++ b/ui/lightbox/src/main/java/org/richfaces/component/UILightbox.java @@ -0,0 +1,83 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UILightbox extends UIComponentBase { + + public static final String COMPONENT_TYPE = "org.richfaces.Lightbox"; + public static final String COMPONENT_FAMILY = "org.richfaces.Lightbox"; + public static final int DEFAULT_CONTAINER_BORDER_SIZE = 10; + public static final int DEFAULT_CONTAINER_RESIZE_SPEED = 400; + public static final boolean DEFAULT_FIXED_NAVIGATION = false; + public static final String DEFAULT_KEY_TO_CLOSE = "c"; + public static final String DEFAULT_KEY_TO_NEXT = "n"; + public static final String DEFAULT_KEY_TO_PREV = "p"; + public static final String DEFAULT_TXT_IMAGE = "Image"; + public static final String DEFAULT_TXT_OF = "of"; + public static final String DEFAULT_OVERLAY_BG_COLOR = "#000"; + public static final double DEFAULT_OVERLAY_OPACITY = .8; + + public abstract String getSelector(); + + public abstract void setSelector(String selector); + + public abstract String getOverlayBgColor(); + + public abstract void setOverlayBgColor(String overlayBgColor); + + public abstract Double getOverlayOpacity(); + + public abstract void setOverlayOpacity(Double overlayOpacity); + + public abstract Boolean getFixedNavigation(); + + public abstract void setFixedNavigation(Boolean fixedNavigation); + + public abstract Integer getContainerBorderSize(); + + public abstract void setContainerBorderSize(Integer containerBorderSize); + + public abstract Integer getContainerResizeSpeed(); + + public abstract void setContainerResizeSpeed(Integer containerResizeSpeed); + + public abstract String getTxtImage(); + + public abstract void setTxtImage(String txtImage); + + public abstract String getTxtOf(); + + public abstract void setTxtOf(String txtOf); + + public abstract String getKeyToClose(); + + public abstract void setKeyToClose(String keyToClose); + + public abstract String getKeyToPrev(); + + public abstract void setKeyToPrev(String keyToPrev); + + public abstract String getKeyToNext(); + + public abstract void setKeyToNext(String keyToNext); + + public abstract String getImageBlank(); + + public abstract void setImageBlank(String src); + + public abstract String getImageLoading(); + + public abstract void setImageLoading(String src); + + public abstract String getImageBtnNext(); + + public abstract void setImageBtnNext(String src); + + public abstract String getImageBtnPrev(); + + public abstract void setImageBtnPrev(String src); + + public abstract String getImageBtnClose(); + + public abstract void setImageBtnClose(String src); +} diff --git a/ui/lightbox/src/main/java/org/richfaces/renderkit/html/LightboxRenderer.java b/ui/lightbox/src/main/java/org/richfaces/renderkit/html/LightboxRenderer.java new file mode 100644 index 0000000..abd21fe --- /dev/null +++ b/ui/lightbox/src/main/java/org/richfaces/renderkit/html/LightboxRenderer.java @@ -0,0 +1,109 @@ +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.RendererUtils; +import org.ajax4jsf.renderkit.compiler.TemplateContext; +import org.ajax4jsf.resource.InternetResource; +import org.ajax4jsf.resource.InternetResourceBuilder; +import org.richfaces.component.UILightbox; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class LightboxRenderer extends HeaderResourcesRendererBase { + + private static final Map DEFAULTS; + + /** + * Following defaults are be used by addOptionIfSetAndNotDefault + */ + static { + Map defaults = new HashMap(); + defaults.put("overlayBgColor", UILightbox.DEFAULT_OVERLAY_BG_COLOR); + defaults.put("overlayOpacity", UILightbox.DEFAULT_OVERLAY_OPACITY); + defaults.put("containerBorderSize", UILightbox.DEFAULT_CONTAINER_BORDER_SIZE); + defaults.put("containerResizeSpeed", UILightbox.DEFAULT_CONTAINER_RESIZE_SPEED); + defaults.put("fixedNavigation", UILightbox.DEFAULT_FIXED_NAVIGATION); + defaults.put("keyToClose", UILightbox.DEFAULT_KEY_TO_CLOSE); + defaults.put("keyToNext", UILightbox.DEFAULT_KEY_TO_NEXT); + defaults.put("keyToPrev", UILightbox.DEFAULT_KEY_TO_PREV); + defaults.put("txtImage", UILightbox.DEFAULT_TXT_IMAGE); + defaults.put("txtOf", UILightbox.DEFAULT_TXT_OF); + + DEFAULTS = Collections.unmodifiableMap(defaults); + } + + private final InternetResource[] scripts = { + getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js"), + getResource("/org/richfaces/renderkit/html/scripts/jquery.lightbox.js"), + getResource("/org/richfaces/renderkit/html/scripts/richfaces.lightbox.js") + }; + + private final InternetResource[] styles = { + getResource("/org/richfaces/renderkit/html/css/jquery.lightbox.css"), + }; + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected InternetResource[] getStyles() { + return styles; + } + + @Override + protected Class getComponentClass() { + return UILightbox.class; + } + + @Override + protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) throws IOException { + UILightbox lightbox = (UILightbox) component; + final HashMap options = new HashMap(); + addOptionIfSetAndOrDefault("imageBlank", lightbox.getImageBlank(), getURL(context, "/org/richfaces/renderkit/html/images/lightbox-blank.gif"), options); + addOptionIfSetAndOrDefault("imageLoading", lightbox.getImageLoading(), getURL(context, "/org/richfaces/renderkit/html/images/lightbox-ico-loading.gif"), options); + addOptionIfSetAndOrDefault("imageBtnNext", lightbox.getImageBtnNext(), getURL(context, "/org/richfaces/renderkit/html/images/lightbox-btn-next.gif"), options); + addOptionIfSetAndOrDefault("imageBtnPrev", lightbox.getImageBtnPrev(), getURL(context, "/org/richfaces/renderkit/html/images/lightbox-btn-prev.gif"), options); + addOptionIfSetAndOrDefault("imageBtnClose", lightbox.getImageBtnClose(), getURL(context, "/org/richfaces/renderkit/html/images/lightbox-btn-close.gif"), options); + addOptionIfSetAndNotDefault("containerBorderSize", lightbox.getContainerBorderSize(), options); + addOptionIfSetAndNotDefault("containerResizeSpeed", lightbox.getContainerResizeSpeed(), options); + addOptionIfSetAndNotDefault("fixedNavigation", lightbox.getFixedNavigation(), options); + addOptionIfSetAndNotDefault("keyToClose", lightbox.getKeyToClose(), options); + addOptionIfSetAndNotDefault("keyToNext", lightbox.getKeyToNext(), options); + addOptionIfSetAndNotDefault("keyToPrev", lightbox.getKeyToPrev(), options); + addOptionIfSetAndNotDefault("overlayBgColor", lightbox.getOverlayBgColor(), options); + addOptionIfSetAndNotDefault("overlayOpacity", lightbox.getOverlayOpacity(), options); + addOptionIfSetAndNotDefault("txtImage", lightbox.getTxtImage(), options); + addOptionIfSetAndNotDefault("txtOf", lightbox.getTxtOf(), options); + writer.startElement(RendererUtils.HTML.DIV_ELEM, component); + writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, getUtils().clientId(context, component), "id"); + getUtils().writeScript(context, component, new JSFunction("RichFaces.Lightbox", lightbox.getSelector(), options)); + writer.endElement(RendererUtils.HTML.DIV_ELEM); + } + + protected void addOptionIfSetAndNotDefault(String optionName, Object value, Map options) { + if (value != null && !"".equals(value) && !value.equals(DEFAULTS.get(optionName))) { + options.put(optionName, value); + } + } + + protected void addOptionIfSetAndOrDefault(String optionName, Object value, Object defaultValue, Map options) { + if (value != null && !"".equals(value)) { + options.put(optionName, value); + } else { + options.put(optionName, defaultValue); + } + } + + private String getURL(FacesContext context, String path) { + return InternetResourceBuilder.getInstance().createResource(null, path).getUri(context, null); + } +} diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/css/jquery.lightbox.css b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/css/jquery.lightbox.css new file mode 100644 index 0000000..62618a8 --- /dev/null +++ b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/css/jquery.lightbox.css @@ -0,0 +1,101 @@ +/** + * jQuery lightBox plugin + * This jQuery plugin was inspired and based on Lightbox 2 by Lokesh Dhakar (http://www.huddletogether.com/projects/lightbox2/) + * and adapted to me for use like a plugin from jQuery. + * @name jquery-lightbox-0.5.css + * @author Leandro Vieira Pinho - http://leandrovieira.com + * @version 0.5 + * @date April 11, 2008 + * @category jQuery plugin + * @copyright (c) 2008 Leandro Vieira Pinho (leandrovieira.com) + * @license CCAttribution-ShareAlike 2.5 Brazil - http://creativecommons.org/licenses/by-sa/2.5/br/deed.en_US + * @example Visit http://leandrovieira.com/projects/jquery/lightbox/ for more informations about this jQuery plugin + */ +#jquery-overlay { + position: absolute; + top: 0; + left: 0; + z-index: 90; + width: 100%; + height: 500px; +} +#jquery-lightbox { + position: absolute; + top: 0; + left: 0; + width: 100%; + z-index: 100; + text-align: center; + line-height: 0; +} +#jquery-lightbox a img { border: none; } +#lightbox-container-image-box { + position: relative; + background-color: #fff; + width: 250px; + height: 250px; + margin: 0 auto; +} +#lightbox-container-image { padding: 10px; } +#lightbox-loading { + position: absolute; + top: 40%; + left: 0%; + height: 25%; + width: 100%; + text-align: center; + line-height: 0; +} +#lightbox-nav { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: 10; +} +#lightbox-container-image-box > #lightbox-nav { left: 0; } +#lightbox-nav a { outline: none;} +#lightbox-nav-btnPrev, #lightbox-nav-btnNext { + width: 49%; + height: 100%; + zoom: 1; + display: block; +} +#lightbox-nav-btnPrev { + left: 0; + float: left; +} +#lightbox-nav-btnNext { + right: 0; + float: right; +} +#lightbox-container-image-data-box { + font: 10px Verdana, Helvetica, sans-serif; + background-color: #fff; + margin: 0 auto; + line-height: 1.4em; + overflow: auto; + width: 100%; + padding: 0 10px 0; +} +#lightbox-container-image-data { + padding: 0 10px; + color: #666; +} +#lightbox-container-image-data #lightbox-image-details { + width: 70%; + float: left; + text-align: left; +} +#lightbox-image-details-caption { font-weight: bold; } +#lightbox-image-details-currentNumber { + display: block; + clear: left; + padding-bottom: 1.0em; +} +#lightbox-secNav-btnClose { + width: 66px; + float: right; + padding-bottom: 0.7em; +} \ No newline at end of file diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-blank.gif b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-blank.gif new file mode 100644 index 0000000..1d11fa9 Binary files /dev/null and b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-blank.gif differ diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-close.gif b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-close.gif new file mode 100644 index 0000000..33bcf51 Binary files /dev/null and b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-close.gif differ diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-next.gif b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-next.gif new file mode 100644 index 0000000..a0d4fcf Binary files /dev/null and b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-next.gif differ diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-prev.gif b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-prev.gif new file mode 100644 index 0000000..040ee59 Binary files /dev/null and b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-btn-prev.gif differ diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-ico-loading.gif b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-ico-loading.gif new file mode 100644 index 0000000..4f1429c Binary files /dev/null and b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/images/lightbox-ico-loading.gif differ diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.lightbox.js b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.lightbox.js new file mode 100644 index 0000000..28a61bb --- /dev/null +++ b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.lightbox.js @@ -0,0 +1,472 @@ +/** + * jQuery lightBox plugin + * This jQuery plugin was inspired and based on Lightbox 2 by Lokesh Dhakar (http://www.huddletogether.com/projects/lightbox2/) + * and adapted to me for use like a plugin from jQuery. + * @name jquery-lightbox-0.5.js + * @author Leandro Vieira Pinho - http://leandrovieira.com + * @version 0.5 + * @date April 11, 2008 + * @category jQuery plugin + * @copyright (c) 2008 Leandro Vieira Pinho (leandrovieira.com) + * @license CCAttribution-ShareAlike 2.5 Brazil - http://creativecommons.org/licenses/by-sa/2.5/br/deed.en_US + * @example Visit http://leandrovieira.com/projects/jquery/lightbox/ for more informations about this jQuery plugin + */ + +// Offering a Custom Alias suport - More info: http://docs.jquery.com/Plugins/Authoring#Custom_Alias +(function($) { + /** + * $ is an alias to jQuery object + * + */ + $.fn.lightBox = function(settings) { + // Settings to configure the jQuery lightBox plugin how you like + settings = jQuery.extend({ + // Configuration related to overlay + overlayBgColor: '#000', // (string) Background color to overlay; inform a hexadecimal value like: #RRGGBB. Where RR, GG, and BB are the hexadecimal values for the red, green, and blue values of the color. + overlayOpacity: 0.8, // (integer) Opacity value to overlay; inform: 0.X. Where X are number from 0 to 9 + // Configuration related to navigation + fixedNavigation: false, // (boolean) Boolean that informs if the navigation (next and prev button) will be fixed or not in the interface. + // Configuration related to images + imageLoading: 'images/lightbox-ico-loading.gif', // (string) Path and the name of the loading icon + imageBtnPrev: 'images/lightbox-btn-prev.gif', // (string) Path and the name of the prev button image + imageBtnNext: 'images/lightbox-btn-next.gif', // (string) Path and the name of the next button image + imageBtnClose: 'images/lightbox-btn-close.gif', // (string) Path and the name of the close btn + imageBlank: 'images/lightbox-blank.gif', // (string) Path and the name of a blank image (one pixel) + // Configuration related to container image box + containerBorderSize: 10, // (integer) If you adjust the padding in the CSS for the container, #lightbox-container-image-box, you will need to update this value + containerResizeSpeed: 400, // (integer) Specify the resize duration of container image. These number are miliseconds. 400 is default. + // Configuration related to texts in caption. For example: Image 2 of 8. You can alter either "Image" and "of" texts. + txtImage: 'Image', // (string) Specify text "Image" + txtOf: 'of', // (string) Specify text "of" + // Configuration related to keyboard navigation + keyToClose: 'c', // (string) (c = close) Letter to close the jQuery lightBox interface. Beyond this letter, the letter X and the SCAPE key is used to. + keyToPrev: 'p', // (string) (p = previous) Letter to show the previous image + keyToNext: 'n', // (string) (n = next) Letter to show the next image. + // Don´t alter these variables in any way + imageArray: [], + activeImage: 0 + },settings); + // Caching the jQuery object with all elements matched + var jQueryMatchedObj = this; // This, in this context, refer to jQuery object + /** + * Initializing the plugin calling the start function + * + * @return boolean false + */ + function _initialize() { + _start(this,jQueryMatchedObj); // This, in this context, refer to object (link) which the user have clicked + return false; // Avoid the browser following the link + } + /** + * Start the jQuery lightBox plugin + * + * @param object objClicked The object (link) whick the user have clicked + * @param object jQueryMatchedObj The jQuery object with all elements matched + */ + function _start(objClicked,jQueryMatchedObj) { + // Hime some elements to avoid conflict with overlay in IE. These elements appear above the overlay. + $('embed, object, select').css({ 'visibility' : 'hidden' }); + // Call the function to create the markup structure; style some elements; assign events in some elements. + _set_interface(); + // Unset total images in imageArray + settings.imageArray.length = 0; + // Unset image active information + settings.activeImage = 0; + // We have an image set? Or just an image? Let´s see it. + if ( jQueryMatchedObj.length == 1 ) { + settings.imageArray.push(new Array(objClicked.getAttribute('href'),objClicked.getAttribute('title'))); + } else { + // Add an Array (as many as we have), with href and title atributes, inside the Array that storage the images references + for ( var i = 0; i < jQueryMatchedObj.length; i++ ) { + settings.imageArray.push(new Array(jQueryMatchedObj[i].getAttribute('href'),jQueryMatchedObj[i].getAttribute('title'))); + } + } + while ( settings.imageArray[settings.activeImage][0] != objClicked.getAttribute('href') ) { + settings.activeImage++; + } + // Call the function that prepares image exibition + _set_image_to_view(); + } + /** + * Create the jQuery lightBox plugin interface + * + * The HTML markup will be like that: +
+
+ + +
+ * + */ + function _set_interface() { + // Apply the HTML markup into body tag + $('body').append('
'); + // Get page sizes + var arrPageSizes = ___getPageSize(); + // Style overlay and show it + $('#jquery-overlay').css({ + backgroundColor: settings.overlayBgColor, + opacity: settings.overlayOpacity, + width: arrPageSizes[0], + height: arrPageSizes[1] + }).fadeIn(); + // Get page scroll + var arrPageScroll = ___getPageScroll(); + // Calculate top and left offset for the jquery-lightbox div object and show it + $('#jquery-lightbox').css({ + top: arrPageScroll[1] + (arrPageSizes[3] / 10), + left: arrPageScroll[0] + }).show(); + // Assigning click events in elements to close overlay + $('#jquery-overlay,#jquery-lightbox').click(function() { + _finish(); + }); + // Assign the _finish function to lightbox-loading-link and lightbox-secNav-btnClose objects + $('#lightbox-loading-link,#lightbox-secNav-btnClose').click(function() { + _finish(); + return false; + }); + // If window was resized, calculate the new overlay dimensions + $(window).resize(function() { + // Get page sizes + var arrPageSizes = ___getPageSize(); + // Style overlay and show it + $('#jquery-overlay').css({ + width: arrPageSizes[0], + height: arrPageSizes[1] + }); + // Get page scroll + var arrPageScroll = ___getPageScroll(); + // Calculate top and left offset for the jquery-lightbox div object and show it + $('#jquery-lightbox').css({ + top: arrPageScroll[1] + (arrPageSizes[3] / 10), + left: arrPageScroll[0] + }); + }); + } + /** + * Prepares image exibition; doing a image´s preloader to calculate it´s size + * + */ + function _set_image_to_view() { // show the loading + // Show the loading + $('#lightbox-loading').show(); + if ( settings.fixedNavigation ) { + $('#lightbox-image,#lightbox-container-image-data-box,#lightbox-image-details-currentNumber').hide(); + } else { + // Hide some elements + $('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-container-image-data-box,#lightbox-image-details-currentNumber').hide(); + } + // Image preload process + var objImagePreloader = new Image(); + objImagePreloader.onload = function() { + $('#lightbox-image').attr('src',settings.imageArray[settings.activeImage][0]); + // Perfomance an effect in the image container resizing it + _resize_container_image_box(objImagePreloader.width,objImagePreloader.height); + // clear onLoad, IE behaves irratically with animated gifs otherwise + objImagePreloader.onload=function(){}; + }; + objImagePreloader.src = settings.imageArray[settings.activeImage][0]; + }; + /** + * Perfomance an effect in the image container resizing it + * + * @param integer intImageWidth The image´s width that will be showed + * @param integer intImageHeight The image´s height that will be showed + */ + function _resize_container_image_box(intImageWidth,intImageHeight) { + // Get current width and height + var intCurrentWidth = $('#lightbox-container-image-box').width(); + var intCurrentHeight = $('#lightbox-container-image-box').height(); + // Get the width and height of the selected image plus the padding + var intWidth = (intImageWidth + (settings.containerBorderSize * 2)); // Plus the image´s width and the left and right padding value + var intHeight = (intImageHeight + (settings.containerBorderSize * 2)); // Plus the image´s height and the left and right padding value + // Diferences + var intDiffW = intCurrentWidth - intWidth; + var intDiffH = intCurrentHeight - intHeight; + // Perfomance the effect + $('#lightbox-container-image-box').animate({ width: intWidth, height: intHeight },settings.containerResizeSpeed,function() { _show_image(); }); + if ( ( intDiffW == 0 ) && ( intDiffH == 0 ) ) { + if ( $.browser.msie ) { + ___pause(250); + } else { + ___pause(100); + } + } + $('#lightbox-container-image-data-box').css({ width: intImageWidth }); + $('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css({ height: intImageHeight + (settings.containerBorderSize * 2) }); + }; + /** + * Show the prepared image + * + */ + function _show_image() { + $('#lightbox-loading').hide(); + $('#lightbox-image').fadeIn(function() { + _show_image_data(); + _set_navigation(); + }); + _preload_neighbor_images(); + }; + /** + * Show the image information + * + */ + function _show_image_data() { + $('#lightbox-container-image-data-box').slideDown('fast'); + $('#lightbox-image-details-caption').hide(); + if ( settings.imageArray[settings.activeImage][1] ) { + $('#lightbox-image-details-caption').html(settings.imageArray[settings.activeImage][1]).show(); + } + // If we have a image set, display 'Image X of X' + if ( settings.imageArray.length > 1 ) { + $('#lightbox-image-details-currentNumber').html(settings.txtImage + ' ' + ( settings.activeImage + 1 ) + ' ' + settings.txtOf + ' ' + settings.imageArray.length).show(); + } + } + /** + * Display the button navigations + * + */ + function _set_navigation() { + $('#lightbox-nav').show(); + + // Instead to define this configuration in CSS file, we define here. And it´s need to IE. Just. + $('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' }); + + // Show the prev button, if not the first image in set + if ( settings.activeImage != 0 ) { + if ( settings.fixedNavigation ) { + $('#lightbox-nav-btnPrev').css({ 'background' : 'url(' + settings.imageBtnPrev + ') left 15% no-repeat' }) + .unbind() + .bind('click',function() { + settings.activeImage = settings.activeImage - 1; + _set_image_to_view(); + return false; + }); + } else { + // Show the images button for Next buttons + $('#lightbox-nav-btnPrev').unbind().hover(function() { + $(this).css({ 'background' : 'url(' + settings.imageBtnPrev + ') left 15% no-repeat' }); + },function() { + $(this).css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' }); + }).show().bind('click',function() { + settings.activeImage = settings.activeImage - 1; + _set_image_to_view(); + return false; + }); + } + } + + // Show the next button, if not the last image in set + if ( settings.activeImage != ( settings.imageArray.length -1 ) ) { + if ( settings.fixedNavigation ) { + $('#lightbox-nav-btnNext').css({ 'background' : 'url(' + settings.imageBtnNext + ') right 15% no-repeat' }) + .unbind() + .bind('click',function() { + settings.activeImage = settings.activeImage + 1; + _set_image_to_view(); + return false; + }); + } else { + // Show the images button for Next buttons + $('#lightbox-nav-btnNext').unbind().hover(function() { + $(this).css({ 'background' : 'url(' + settings.imageBtnNext + ') right 15% no-repeat' }); + },function() { + $(this).css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' }); + }).show().bind('click',function() { + settings.activeImage = settings.activeImage + 1; + _set_image_to_view(); + return false; + }); + } + } + // Enable keyboard navigation + _enable_keyboard_navigation(); + } + /** + * Enable a support to keyboard navigation + * + */ + function _enable_keyboard_navigation() { + $(document).keydown(function(objEvent) { + _keyboard_action(objEvent); + }); + } + /** + * Disable the support to keyboard navigation + * + */ + function _disable_keyboard_navigation() { + $(document).unbind(); + } + /** + * Perform the keyboard actions + * + */ + function _keyboard_action(objEvent) { + // To ie + if ( objEvent == null ) { + keycode = event.keyCode; + escapeKey = 27; + // To Mozilla + } else { + keycode = objEvent.keyCode; + escapeKey = objEvent.DOM_VK_ESCAPE; + } + // Get the key in lower case form + key = String.fromCharCode(keycode).toLowerCase(); + // Verify the keys to close the ligthBox + if ( ( key == settings.keyToClose ) || ( key == 'x' ) || ( keycode == escapeKey ) ) { + _finish(); + } + // Verify the key to show the previous image + if ( ( key == settings.keyToPrev ) || ( keycode == 37 ) ) { + // If we´re not showing the first image, call the previous + if ( settings.activeImage != 0 ) { + settings.activeImage = settings.activeImage - 1; + _set_image_to_view(); + _disable_keyboard_navigation(); + } + } + // Verify the key to show the next image + if ( ( key == settings.keyToNext ) || ( keycode == 39 ) ) { + // If we´re not showing the last image, call the next + if ( settings.activeImage != ( settings.imageArray.length - 1 ) ) { + settings.activeImage = settings.activeImage + 1; + _set_image_to_view(); + _disable_keyboard_navigation(); + } + } + } + /** + * Preload prev and next images being showed + * + */ + function _preload_neighbor_images() { + if ( (settings.imageArray.length -1) > settings.activeImage ) { + objNext = new Image(); + objNext.src = settings.imageArray[settings.activeImage + 1][0]; + } + if ( settings.activeImage > 0 ) { + objPrev = new Image(); + objPrev.src = settings.imageArray[settings.activeImage -1][0]; + } + } + /** + * Remove jQuery lightBox plugin HTML markup + * + */ + function _finish() { + $('#jquery-lightbox').remove(); + $('#jquery-overlay').fadeOut(function() { $('#jquery-overlay').remove(); }); + // Show some elements to avoid conflict with overlay in IE. These elements appear above the overlay. + $('embed, object, select').css({ 'visibility' : 'visible' }); + } + /** + / THIRD FUNCTION + * getPageSize() by quirksmode.com + * + * @return Array Return an array with page width, height and window width, height + */ + function ___getPageSize() { + var xScroll, yScroll; + if (window.innerHeight && window.scrollMaxY) { + xScroll = window.innerWidth + window.scrollMaxX; + yScroll = window.innerHeight + window.scrollMaxY; + } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac + xScroll = document.body.scrollWidth; + yScroll = document.body.scrollHeight; + } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari + xScroll = document.body.offsetWidth; + yScroll = document.body.offsetHeight; + } + var windowWidth, windowHeight; + if (self.innerHeight) { // all except Explorer + if(document.documentElement.clientWidth){ + windowWidth = document.documentElement.clientWidth; + } else { + windowWidth = self.innerWidth; + } + windowHeight = self.innerHeight; + } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode + windowWidth = document.documentElement.clientWidth; + windowHeight = document.documentElement.clientHeight; + } else if (document.body) { // other Explorers + windowWidth = document.body.clientWidth; + windowHeight = document.body.clientHeight; + } + // for small pages with total height less then height of the viewport + if(yScroll < windowHeight){ + pageHeight = windowHeight; + } else { + pageHeight = yScroll; + } + // for small pages with total width less then width of the viewport + if(xScroll < windowWidth){ + pageWidth = xScroll; + } else { + pageWidth = windowWidth; + } + arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight); + return arrayPageSize; + }; + /** + / THIRD FUNCTION + * getPageScroll() by quirksmode.com + * + * @return Array Return an array with x,y page scroll values. + */ + function ___getPageScroll() { + var xScroll, yScroll; + if (self.pageYOffset) { + yScroll = self.pageYOffset; + xScroll = self.pageXOffset; + } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict + yScroll = document.documentElement.scrollTop; + xScroll = document.documentElement.scrollLeft; + } else if (document.body) {// all other Explorers + yScroll = document.body.scrollTop; + xScroll = document.body.scrollLeft; + } + arrayPageScroll = new Array(xScroll,yScroll); + return arrayPageScroll; + }; + /** + * Stop the code execution from a escified time in milisecond + * + */ + function ___pause(ms) { + var date = new Date(); + curDate = null; + do { var curDate = new Date(); } + while ( curDate - date < ms); + }; + // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once + return this.unbind('click').click(_initialize); + }; +})(jQuery); // Call and execute the function immediately passing the jQuery object \ No newline at end of file diff --git a/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.lightbox.js b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.lightbox.js new file mode 100644 index 0000000..dd98f05 --- /dev/null +++ b/ui/lightbox/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.lightbox.js @@ -0,0 +1,26 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +window.RichFaces = window.RichFaces || {}; +RichFaces.Lightbox = function(selector, options) { + jQuery(selector).lightBox(options); +}; \ No newline at end of file diff --git a/ui/notify/pom.xml b/ui/notify/pom.xml new file mode 100644 index 0000000..6829af6 --- /dev/null +++ b/ui/notify/pom.xml @@ -0,0 +1,73 @@ + + + + org.richfaces.sandbox + ui + 3.3.4-SNAPSHOT + + 4.0.0 + org.richfaces.sandbox.ui + notify + notify + + + + org.richfaces.cdk + maven-cdk-plugin + ${project.version} + + + generate-sources + + generate + + + + + + org.richfaces.sandbox.ui + + notify + http://richfaces.org/sandbox/notify + + + + + + maven-compiler-plugin + true + + 1.5 + 1.5 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.2 + + ${project.build.sourceEncoding} + + + + + + + org.richfaces.framework + richfaces-impl + ${project.version} + + + + UTF-8 + + + + bernard.labno.pl + MyCo Internal Repository + http://bernard.labno.pl/artifactory/libs-snapshot-local + + + + diff --git a/ui/notify/src/main/config/component/notify.xml b/ui/notify/src/main/config/component/notify.xml new file mode 100644 index 0000000..e448e1b --- /dev/null +++ b/ui/notify/src/main/config/component/notify.xml @@ -0,0 +1,61 @@ + + + ] + > + + + org.richfaces.Notify + org.richfaces.Notify + org.richfaces.component.html.HtmlNotify + org.richfaces.component.UINotify + + + + + org.richfaces.NotifyRenderer + org.richfaces.renderkit.html.NotifyRenderer + + + notify + org.richfaces.taglib.NotifyTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + + &ui_component_attributes; + &ajax_output_attributes; + ¬ifyAttributes; + + title + java.lang.String + + + "" + + + text + java.lang.String + + + "" + + + + + styleClass + java.lang.String + + + + diff --git a/ui/notify/src/main/config/component/notifyAttributes.ent b/ui/notify/src/main/config/component/notifyAttributes.ent new file mode 100644 index 0000000..959582a --- /dev/null +++ b/ui/notify/src/main/config/component/notifyAttributes.ent @@ -0,0 +1,106 @@ + + stack + java.lang.String + + Id of stack component in which this message will be displayed. + + null + + + sticky + boolean + + if you want it to fade out on its own or just sit there + + false + + + stayTime + java.lang.Integer + + the time you want it to be alive for before fading out (milliseconds) + + 8000 + + + delay + java.lang.Integer + + Miliseconds before component should be shown for the first time. + + 0 + + + appearAnimation + java.lang.String + + The animation to use when displaying and hiding the notice. + "none", "show", "fade", and "slide" are built in to jQuery. + Others require jQuery UI. + + "fade" + + + hideAnimation + java.lang.String + + The animation to use when displaying and hiding the notice. + "none", "show", "fade", and "slide" are built in to jQuery. + Others require jQuery UI. + + "fade" + + + animationSpeed + java.lang.Integer + + animation speed (milliseconds) + + null + + + showHistory + boolean + + Display a pull down menu to redisplay previous notices, + and place the notice in the history. + + true + + + nonblocking + boolean + + Non-blocking notice lets the user click elements underneath it. + + false + + + showShadow + boolean + + Display a drop shadow. + + false + + + showCloseButton + boolean + + Provide a button for the user to manually close the notice. + + true + + + nonblockingOpacity + java.lang.Double + + The opacity of the notice (if it's non-blocking) when the mouse is over it. + + .2 + + + styleClass + java.lang.String + + \ No newline at end of file diff --git a/ui/notify/src/main/config/component/notifyMessages.xml b/ui/notify/src/main/config/component/notifyMessages.xml new file mode 100644 index 0000000..be9ec0e --- /dev/null +++ b/ui/notify/src/main/config/component/notifyMessages.xml @@ -0,0 +1,55 @@ + + + ] + > + + + org.richfaces.NotifyMessages + org.richfaces.NotifyMessages + org.richfaces.component.html.HtmlNotifyMessages + org.richfaces.component.UINotifyMessages + + + + + org.richfaces.NotifyMessagesRenderer + org.richfaces.renderkit.html.NotifyMessagesRenderer + + + notifyMessages + org.richfaces.taglib.NotifyMessagesTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + + &ui_component_attributes; + &ajax_output_attributes; + ¬ifyAttributes; + + globalOnly + boolean + + + + showDetail + boolean + + + + showSummary + boolean + + + + diff --git a/ui/notify/src/main/config/component/notifyStack.xml b/ui/notify/src/main/config/component/notifyStack.xml new file mode 100644 index 0000000..f462ab0 --- /dev/null +++ b/ui/notify/src/main/config/component/notifyStack.xml @@ -0,0 +1,59 @@ + + + + + org.richfaces.NotifyStack + org.richfaces.NotifyStack + org.richfaces.component.html.HtmlNotifyStack + org.richfaces.component.UINotifyStack + + + + + org.richfaces.NotifyStackRenderer + org.richfaces.renderkit.html.NotifyStackRenderer + + + notifyStack + org.richfaces.taglib.NotifyStackTag + + org.ajax4jsf.webapp.taglib.HtmlComponentTagBase + + + + + &ui_component_attributes; + + verticalStackingDirection + java.lang.String + + + + horizontalStackingDirection + java.lang.String + + + + + push + java.lang.String + + Stack end from which message should be pushed. + Acceptable values: "up","down" + + + + + styleClass + java.lang.String + + + + diff --git a/ui/notify/src/main/java/org/richfaces/component/NotifyAttributes.java b/ui/notify/src/main/java/org/richfaces/component/NotifyAttributes.java new file mode 100644 index 0000000..918d30c --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/component/NotifyAttributes.java @@ -0,0 +1,78 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.component; + +public interface NotifyAttributes { + + boolean isSticky(); + + void setSticky(boolean sticky); + + Integer getStayTime(); + + void setStayTime(Integer time); + + Integer getDelay(); + + void setDelay(Integer delay); + + String getStyleClass(); + + void setStyleClass(String styleClass); + + String getAppearAnimation(); + + void setAppearAnimation(String appearAnimation); + + String getHideAnimation(); + + void setHideAnimation(String hideAnimation); + + Integer getAnimationSpeed(); + + void setAnimationSpeed(Integer animationSpeed); + + boolean isShowHistory(); + + void setShowHistory(boolean showHistory); + + boolean isNonblocking(); + + void setNonblocking(boolean nonblocking); + + boolean isShowShadow(); + + void setShowShadow(boolean showShadow); + + boolean isShowCloseButton(); + + void setShowCloseButton(boolean showCloseButton); + + Double getNonblockingOpacity(); + + void setNonblockingOpacity(Double nonblockingOpacity); + + String getStack(); + + void setStack(String stack); +} diff --git a/ui/notify/src/main/java/org/richfaces/component/UINotify.java b/ui/notify/src/main/java/org/richfaces/component/UINotify.java new file mode 100644 index 0000000..906d859 --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/component/UINotify.java @@ -0,0 +1,19 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UINotify extends UIComponentBase implements NotifyAttributes { + + public static final String COMPONENT_TYPE = "org.richfaces.Notify"; + public static final String COMPONENT_FAMILY = "org.richfaces.Notify"; + + public static final double DEFAULT_NONBLOCKING_OPACITY = .2; + + public abstract String getTitle(); + + public abstract void setTitle(String title); + + public abstract String getText(); + + public abstract void setText(String text); +} diff --git a/ui/notify/src/main/java/org/richfaces/component/UINotifyMessages.java b/ui/notify/src/main/java/org/richfaces/component/UINotifyMessages.java new file mode 100644 index 0000000..50a052f --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/component/UINotifyMessages.java @@ -0,0 +1,16 @@ +package org.richfaces.component; + +import org.ajax4jsf.component.AjaxOutput; + +import javax.faces.component.UIMessages; + +public abstract class UINotifyMessages extends UIMessages implements AjaxOutput, NotifyAttributes { + + public static final String COMPONENT_TYPE = "org.richfaces.NotifyMessages"; + public static final String COMPONENT_FAMILY = "org.richfaces.Notify"; + + public abstract Integer getInterval(); + + public abstract void setInterval(Integer interval); + +} diff --git a/ui/notify/src/main/java/org/richfaces/component/UINotifyStack.java b/ui/notify/src/main/java/org/richfaces/component/UINotifyStack.java new file mode 100644 index 0000000..fa27b44 --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/component/UINotifyStack.java @@ -0,0 +1,25 @@ +package org.richfaces.component; + +import javax.faces.component.UIComponentBase; + +public abstract class UINotifyStack extends UIComponentBase { + + public static final String COMPONENT_TYPE = "org.richfaces.NotifyStack"; + public static final String COMPONENT_FAMILY = "org.richfaces.Notify"; + + public abstract String getStyleClass(); + + public abstract void setStyleClass(String styleClass); + + public abstract String getStackDir1(); + + public abstract void setStackDir1(String stackDir1); + + public abstract String getStackDir2(); + + public abstract void setStackDir2(String stackDir2); + + public abstract String getPush(); + + public abstract void setPush(String stackPush); +} diff --git a/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyMessagesRenderer.java b/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyMessagesRenderer.java new file mode 100644 index 0000000..4d4ddd7 --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyMessagesRenderer.java @@ -0,0 +1,103 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.renderkit.html; + +import org.ajax4jsf.renderkit.RendererUtils; +import org.ajax4jsf.renderkit.RendererUtils.HTML; +import org.richfaces.component.UINotify; +import org.richfaces.component.UINotifyMessages; + +import javax.faces.application.FacesMessage; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.Iterator; + +public class NotifyMessagesRenderer extends NotifyRenderer { + + @Override + public void encodeEnd(FacesContext context, UIComponent component) throws IOException { + UINotifyMessages messagesComponent = (UINotifyMessages) component; + ResponseWriter writer = context.getResponseWriter(); + writer.startElement(HTML.DIV_ELEM, null); + writer.writeAttribute(HTML.id_ATTRIBUTE, RendererUtils.getInstance().clientId(context, component), "type"); + Integer delay = messagesComponent.getDelay(); + if (delay == null) { + delay = 0; + } + Integer interval = messagesComponent.getInterval(); + if (interval == null) { + interval = 0; + } + + Iterator messages = messagesComponent.isGlobalOnly() + ? context.getMessages(null) : context.getMessages(); + while (messages.hasNext()) { + FacesMessage msg = messages.next(); + UINotify notify = (UINotify) context.getApplication() + .createComponent(UINotify.COMPONENT_TYPE); + notify.setAnimationSpeed(messagesComponent.getAnimationSpeed()); + notify.setAppearAnimation(messagesComponent.getAppearAnimation()); + notify.setDelay(delay); + notify.setHideAnimation(messagesComponent.getHideAnimation()); + notify.setNonblocking(messagesComponent.isNonblocking()); + notify.setNonblockingOpacity(messagesComponent.getNonblockingOpacity()); + notify.setShowCloseButton(messagesComponent.isShowCloseButton()); + notify.setShowHistory(messagesComponent.isShowHistory()); + notify.setShowShadow(messagesComponent.isShowShadow()); + notify.setStack(messagesComponent.getStack()); + notify.setStayTime(messagesComponent.getStayTime()); + notify.setSticky(messagesComponent.isSticky()); + if (messagesComponent.isShowSummary()) { + notify.setTitle(msg.getSummary()); + } + if (messagesComponent.isShowDetail() && msg.getDetail() != null && !msg.getDetail().equals(msg.getSummary())) { + notify.setText(msg.getDetail()); + } + String styleClass = messagesComponent.getStyleClass(); + if (styleClass == null) { + styleClass = ""; + } + if (FacesMessage.SEVERITY_INFO.equals(msg.getSeverity())) { + styleClass += " rf-ny-info"; + } else if (FacesMessage.SEVERITY_WARN.equals(msg.getSeverity())) { + styleClass += " rf-ny-warn"; + } else if (FacesMessage.SEVERITY_ERROR.equals(msg.getSeverity())) { + styleClass += " rf-ny-error"; + } else if (FacesMessage.SEVERITY_FATAL.equals(msg.getSeverity())) { + styleClass += " rf-ny-fatal"; + } + styleClass = styleClass.trim(); + notify.setStyleClass(styleClass); + notify.encodeAll(context); + delay += interval; + } + writer.endElement(HTML.DIV_ELEM); + } + + @Override + protected Class getComponentClass() { + return UINotifyMessages.class; + } +} diff --git a/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyRenderer.java b/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyRenderer.java new file mode 100644 index 0000000..985ce73 --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyRenderer.java @@ -0,0 +1,165 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.RendererUtils.HTML; +import org.ajax4jsf.resource.InternetResource; +import org.richfaces.component.UINotify; +import org.richfaces.component.UINotifyStack; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class NotifyRenderer extends HeaderResourcesRendererBase { + + private static final Map DEFAULTS; + + static { + Map defaults = new HashMap(); + defaults.put("styleClass", ""); + defaults.put("nonblocking", false); + defaults.put("nonblockingOpacity", UINotify.DEFAULT_NONBLOCKING_OPACITY); + defaults.put("showHistory", true); + defaults.put("animationSpeed", "slow"); + defaults.put("opacity", 1); + defaults.put("showShadow", false); + defaults.put("showCloseButton", true); + defaults.put("appearAnimation", "fade"); + defaults.put("hideAnimation", "fade"); + defaults.put("sticky", false); + defaults.put("stayTime", 8000); + defaults.put("delay", 0); + DEFAULTS = Collections.unmodifiableMap(defaults); + } + + private final InternetResource[] scripts = { + getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js"), + getResource("/org/richfaces/renderkit/html/scripts/jquery.pnotify.js"), + getResource("/org/richfaces/renderkit/html/scripts/richfaces.notify.js") + }; + private final InternetResource[] styles = { + getResource("/org/richfaces/renderkit/html/css/jquery.pnotify.xcss") + }; + + @Override + public void encodeEnd(FacesContext context, UIComponent component) throws IOException { + if (!(component instanceof UINotify)) { + return; + } + ResponseWriter writer = context.getResponseWriter(); + writer.startElement(HTML.DIV_ELEM, null); + writer.writeAttribute(HTML.id_ATTRIBUTE, getUtils().clientId(context, component), "type"); + writer.startElement(HTML.SCRIPT_ELEM, null); + writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", "type"); + writer.writeText(new JSFunction("RichFaces.Notify", getOptions(context, (UINotify) component)), null); + writer.writeText(";", null); + writer.endElement(HTML.SCRIPT_ELEM); + writer.endElement(HTML.DIV_ELEM); + } + + protected Map getOptions(FacesContext context, UINotify notify) throws IOException { + /** + * Include only attributes that are actually set. + */ + Map options = new HashMap(); + addOptionIfSetAndNotDefault("title", notify.getTitle(), options); + addOptionIfSetAndNotDefault("text", notify.getText(), options); + addOptionIfSetAndNotDefault("sticky", notify.isSticky(), options); + addOptionIfSetAndNotDefault("stayTime", notify.getStayTime(), options); + Map animationOptions = new HashMap(); + addOptionIfSetAndNotDefault("appearAnimation", notify.getAppearAnimation(), animationOptions); + addOptionIfSetAndNotDefault("hideAnimation", notify.getHideAnimation(), animationOptions); + addOptionIfSetAndNotDefault("animation", animationOptions, options); + addOptionIfSetAndNotDefault("animationSpeed", notify.getAnimationSpeed(), options); + addOptionIfSetAndNotDefault("nonblocking", notify.isNonblocking(), options); + addOptionIfSetAndNotDefault("nonblockingOpacity", notify.getNonblockingOpacity(), options); + addOptionIfSetAndNotDefault("showHistory", notify.isShowHistory(), options); + addOptionIfSetAndNotDefault("showShadow", notify.isShowShadow(), options); + addOptionIfSetAndNotDefault("showCloseButton", notify.isShowCloseButton(), options); + UINotifyStack stack = getStackComponent(context, notify); + if (stack != null) { + addOptionIfSetAndNotDefault("stack", getUtils().clientId(context, stack), options); + } + String styleClass = notify.getStyleClass(); + if (styleClass == null) { + styleClass = ""; + } + addOptionIfSetAndNotDefault("styleClass", getStackStyleClass(context, notify) + " " + styleClass, options); + addOptionIfSetAndNotDefault("delay", notify.getDelay(), options); + return options; + } + + protected String getStackStyleClass(FacesContext context, UINotify notify) { + UINotifyStack stack = getStackComponent(context, notify); + return stack == null ? "" : stack.getStyleClass(); + } + + protected void addOptionIfSetAndNotDefault(String optionName, Object value, Map options) { + if (value != null && !"".equals(value) + && !value.equals(DEFAULTS.get(optionName)) + && !(value instanceof Collection && ((Collection) value).size() == 0) + && !(value instanceof Map && ((Map) value).size() == 0)) { + options.put(optionName, value); + } + } + + protected Class getComponentClass() { + return UINotify.class; + } + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected InternetResource[] getStyles() { + return styles; + } + + protected UINotifyStack getStackComponent(FacesContext context, UINotify notify) { + String stackId = notify.getStack(); + if (stackId == null) { + UIComponent parent = notify.getParent(); + while (parent != null && !(parent instanceof UINotifyStack)) { + parent = parent.getParent(); + } + return (UINotifyStack) parent; + } else { + UIComponent componentFor = getUtils().findComponentFor(context.getViewRoot(), stackId); + if (componentFor instanceof UINotifyStack) { + return (UINotifyStack) componentFor; + } else { + return null; + } + } + } +} diff --git a/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyStackRenderer.java b/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyStackRenderer.java new file mode 100644 index 0000000..a4f655f --- /dev/null +++ b/ui/notify/src/main/java/org/richfaces/renderkit/html/NotifyStackRenderer.java @@ -0,0 +1,86 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright , Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.richfaces.renderkit.html; + +import org.ajax4jsf.javascript.JSFunction; +import org.ajax4jsf.renderkit.HeaderResourcesRendererBase; +import org.ajax4jsf.renderkit.RendererUtils; +import org.ajax4jsf.resource.InternetResource; +import org.richfaces.component.UINotifyStack; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.context.ResponseWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class NotifyStackRenderer extends HeaderResourcesRendererBase { + + private final InternetResource[] scripts = { + getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js"), + getResource("/org/richfaces/renderkit/html/scripts/jquery.pnotify.js"), + getResource("/org/richfaces/renderkit/html/scripts/richfaces.notify.js") + }; + + @Override + public void encodeEnd(FacesContext context, UIComponent component) throws IOException { + if (!(component instanceof UINotifyStack)) { + return; + } + ResponseWriter writer = context.getResponseWriter(); + writer.startElement(RendererUtils.HTML.SCRIPT_ELEM, null); + writer.writeText(new JSFunction("RichFaces.NotifyStack.register", + RendererUtils.getInstance().clientId(context, component), + getOptions((UINotifyStack) component) + ), null); + writer.endElement(RendererUtils.HTML.SCRIPT_ELEM); + } + + protected Map getOptions(UINotifyStack stack) throws IOException { + /** + * Include only attributes that are actually set. + */ + Map options = new HashMap(); + addOptionIfSet("dir1", stack.getStackDir1(), options); + addOptionIfSet("dir2", stack.getStackDir2(), options); + addOptionIfSet("push", stack.getPush(), options); + return options; + } + + protected void addOptionIfSet(String optionName, Object value, Map options) { + if (value != null && !"".equals(value)) { + options.put(optionName, value); + } + } + + @Override + protected InternetResource[] getScripts() { + return scripts; + } + + @Override + protected Class getComponentClass() { + return UINotifyStack.class; + } +} diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/css/jquery.pnotify.xcss b/ui/notify/src/main/resources/org/richfaces/renderkit/html/css/jquery.pnotify.xcss new file mode 100644 index 0000000..5cebfa8 --- /dev/null +++ b/ui/notify/src/main/resources/org/richfaces/renderkit/html/css/jquery.pnotify.xcss @@ -0,0 +1,182 @@ + + + + +/* Notice----------------------------------*/ +.rf-ny { + top: 18px; + right: 18px; + position: absolute; + height: auto; + /* Ensure that the notices are on top of everything else. */ + z-index: 9999; +} + + + + + +.rf-ny-warn { + color:orange; +} +.rf-ny-error { + color:red; +} +.rf-ny-fatal { + color:red; + font-weight:bold; +} +/* This hides position: fixed from IE6, which doesn't understand it. */ +html > body .rf-ny { + position: fixed; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.rf-ny-co-hover { + background:red; +} +.rf-ny-cl { + float: right; + margin-left: .2em; +} + + + + + + + + + + +.rf-ny-ti { + display: block; + font-size: 1.2em; + font-weight: bold; + margin-bottom: .4em; +} +.rf-ny-te { + display: block; +} +.rf-ny-fcl { + clear: both; +} +.rf-ny-ic { + display: none; + float: left; + margin-right: .2em; + width:32px; + height:32px; +} +/* History Pulldown----------------------------------*/ + + + + + + + + + + + + + + + + + + + + + + + + + +.rf-ny-hc .rf-ny-hh { + padding: 2px; +} +.rf-ny-hc button { + cursor: pointer; + display: block; + width: 100%; +} +.rc-ny-ha { + -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/error.png b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/error.png new file mode 100644 index 0000000..cabd9c4 Binary files /dev/null and b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/error.png differ diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/fatal.png b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/fatal.png new file mode 100644 index 0000000..14a0767 Binary files /dev/null and b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/fatal.png differ diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/info.png b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/info.png new file mode 100644 index 0000000..6c69d60 Binary files /dev/null and b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/info.png differ diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/warn.png b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/warn.png new file mode 100644 index 0000000..cf6341b Binary files /dev/null and b/ui/notify/src/main/resources/org/richfaces/renderkit/html/images/warn.png differ diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.pnotify.js b/ui/notify/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.pnotify.js new file mode 100644 index 0000000..18740d7 --- /dev/null +++ b/ui/notify/src/main/resources/org/richfaces/renderkit/html/scripts/jquery.pnotify.js @@ -0,0 +1,770 @@ +/* + * jQuery Pines Notify (pnotify) Plugin 1.0.0 + * + * Copyright (c) 2009 Hunter Perrin + * + * Licensed (along with all of Pines) under the GNU Affero GPL: + * http://www.gnu.org/licenses/agpl.html + */ + +(function($) { + var history_handle_top, timer; + var body; + var jwindow; + + function $14(element, options) { + var attrFn = { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }; + var o = jQuery(element); + for (var key in options) { + if (jQuery.isFunction(options[key])) { + o.bind(key, options[key]); + } else if (key in attrFn) { + o[key](options[key]); + } else { + o.attr(key, options[key]); + } + } + return o; + } + + $.extend({ + pnotify_remove_all: function () { + var body_data = body.data("pnotify"); + /* POA: Added null-check */ + if (body_data && body_data.length) { + $.each(body_data, function() { + if (this.pnotify_remove) + this.pnotify_remove(); + }); + } + }, + pnotify_position_all: function () { + if (timer) + clearTimeout(timer); + timer = null; + var body_data = body.data("pnotify"); + if (!body_data || !body_data.length) + return; + $.each(body_data, function() { + var s = this.opts.pnotify_stack; + if (!s) return; + if (!s.nextpos1) + s.nextpos1 = s.firstpos1; + if (!s.nextpos2) + s.nextpos2 = s.firstpos2; + if (!s.addpos2) + s.addpos2 = 0; + if (this.css("display") != "none") { + var curpos1, curpos2; + var animate = {}; + // Calculate the current pos1 value. + var csspos1; + switch (s.dir1) { + case "down": + csspos1 = "top"; + break; + case "up": + csspos1 = "bottom"; + break; + case "left": + csspos1 = "right"; + break; + case "right": + csspos1 = "left"; + break; + } + curpos1 = parseInt(this.css(csspos1)); + if (isNaN(curpos1)) + curpos1 = 0; + // Remember the first pos1, so the first visible notice goes there. + if (typeof s.firstpos1 == "undefined") { + s.firstpos1 = curpos1; + s.nextpos1 = s.firstpos1; + } + // Calculate the current pos2 value. + var csspos2; + switch (s.dir2) { + case "down": + csspos2 = "top"; + break; + case "up": + csspos2 = "bottom"; + break; + case "left": + csspos2 = "right"; + break; + case "right": + csspos2 = "left"; + break; + } + curpos2 = parseInt(this.css(csspos2)); + if (isNaN(curpos2)) + curpos2 = 0; + // Remember the first pos2, so the first visible notice goes there. + if (typeof s.firstpos2 == "undefined") { + s.firstpos2 = curpos2; + s.nextpos2 = s.firstpos2; + } + // Check that it's not beyond the viewport edge. + if ((s.dir1 == "down" && s.nextpos1 + this.height() > jwindow.height()) || + (s.dir1 == "up" && s.nextpos1 + this.height() > jwindow.height()) || + (s.dir1 == "left" && s.nextpos1 + this.width() > jwindow.width()) || + (s.dir1 == "right" && s.nextpos1 + this.width() > jwindow.width())) { + // If it is, it needs to go back to the first pos1, and over on pos2. + s.nextpos1 = s.firstpos1; + s.nextpos2 += s.addpos2 + 10; + s.addpos2 = 0; + } + // Animate if we're moving on dir2. + if (s.animation && s.nextpos2 < curpos2) { + switch (s.dir2) { + case "down": + animate.top = s.nextpos2 + "px"; + break; + case "up": + animate.bottom = s.nextpos2 + "px"; + break; + case "left": + animate.right = s.nextpos2 + "px"; + break; + case "right": + animate.left = s.nextpos2 + "px"; + break; + } + } else + this.css(csspos2, s.nextpos2 + "px"); + // Keep track of the widest/tallest notice in the column/row, so we can push the next column/row. + switch (s.dir2) { + case "down": + case "up": + if (this.outerHeight(true) > s.addpos2) + s.addpos2 = this.height(); + break; + case "left": + case "right": + if (this.outerWidth(true) > s.addpos2) + s.addpos2 = this.width(); + break; + } + // Move the notice on dir1. + if (s.nextpos1) { + // Animate if we're moving toward the first pos. + if (s.animation && (curpos1 > s.nextpos1 || animate.top || animate.bottom || animate.right || animate.left)) { + switch (s.dir1) { + case "down": + animate.top = s.nextpos1 + "px"; + break; + case "up": + animate.bottom = s.nextpos1 + "px"; + break; + case "left": + animate.right = s.nextpos1 + "px"; + break; + case "right": + animate.left = s.nextpos1 + "px"; + break; + } + } else + this.css(csspos1, s.nextpos1 + "px"); + } + if (animate.top || animate.bottom || animate.right || animate.left) + this.animate(animate, {duration: 500, queue: false}); + // Calculate the next dir1 position. + switch (s.dir1) { + case "down": + case "up": + s.nextpos1 += this.height() + 10; + break; + case "left": + case "right": + s.nextpos1 += this.width() + 10; + break; + } + } + }); + // Reset the next position data. + $.each(body_data, function() { + var s = this.opts.pnotify_stack; + if (!s) return; + s.nextpos1 = s.firstpos1; + s.nextpos2 = s.firstpos2; + s.addpos2 = 0; + s.animation = true; + }); + }, + pnotify: function(options) { + if (!body) + body = $("body"); + if (!jwindow) + jwindow = $(window); + + var animating; + + // Build main options. + var opts; + if (typeof options != "object") { + opts = $.extend({}, $.pnotify.defaults); + opts.pnotify_text = options; + } else { + opts = $.extend({}, $.pnotify.defaults, options); + if (opts['pnotify_animation'] instanceof Object) { + opts['pnotify_animation'] = $.extend({ + effect_in:$.pnotify.defaults.pnotify_animation, + effect_out:$.pnotify.defaults.pnotify_animation + }, opts['pnotify_animation']); + } + } + + if (opts.pnotify_before_init) { + if (opts.pnotify_before_init(opts) === false) + return null; + } + + // This keeps track of the last element the mouse was over, so + // mouseleave, mouseenter, etc can be called. + var nonblock_last_elem; + // This is used to pass events through the notice if it is non-blocking. + var nonblock_pass = function(e, e_name) { + pnotify.css("display", "none"); + var element_below = document.elementFromPoint(e.clientX, e.clientY); + pnotify.css("display", "block"); + var jelement_below = $(element_below); + var cursor_style = jelement_below.css("cursor"); + pnotify.css("cursor", cursor_style != "auto" ? cursor_style : "default"); + // If the element changed, call mouseenter, mouseleave, etc. + if (!nonblock_last_elem || nonblock_last_elem.get(0) != element_below) { + if (nonblock_last_elem) { + dom_event.call(nonblock_last_elem.get(0), "mouseleave", e.originalEvent); + dom_event.call(nonblock_last_elem.get(0), "mouseout", e.originalEvent); + } + dom_event.call(element_below, "mouseenter", e.originalEvent); + dom_event.call(element_below, "mouseover", e.originalEvent); + } + dom_event.call(element_below, e_name, e.originalEvent); + // Remember the latest element the mouse was over. + nonblock_last_elem = jelement_below; + }; + + // Create our widget. + // Stop animation, reset the removal timer, and show the close + // button when the user mouses over. + var pnotify = $14("
", { + "class": "rf-ny " + opts.pnotify_addclass, + "css": {"display": "none"}, + "mouseenter": function(e) { + if (opts.pnotify_nonblock) e.stopPropagation(); + if (opts.pnotify_mouse_reset && animating == "out") { + // If it's animating out, animate back in really quick. + pnotify.stop(true); + pnotify.css("height", "auto").animate({"width": opts.pnotify_width, "opacity": opts.pnotify_nonblock ? opts.pnotify_nonblock_opacity : opts.pnotify_opacity}, "fast"); + } else if (opts.pnotify_nonblock && animating != "out") { + // If it's non-blocking, animate to the other opacity. + pnotify.animate({"opacity": opts.pnotify_nonblock_opacity}, "fast"); + } + if (opts.pnotify_hide && opts.pnotify_mouse_reset) pnotify.pnotify_cancel_remove(); + if (opts.pnotify_closer && !opts.pnotify_nonblock) pnotify.closer.css("visibility", "visible"); + }, + "mouseleave": function(e) { + if (opts.pnotify_nonblock) e.stopPropagation(); + nonblock_last_elem = null; + pnotify.css("cursor", "auto"); + if (opts.pnotify_nonblock && animating != "out") + pnotify.animate({"opacity": opts.pnotify_opacity}, "fast"); + if (opts.pnotify_hide && opts.pnotify_mouse_reset) pnotify.pnotify_queue_remove(); + pnotify.closer.css("visibility", "hidden"); + $.pnotify_position_all(); + }, + "mouseover": function(e) { + if (opts.pnotify_nonblock) e.stopPropagation(); + }, + "mouseout": function(e) { + if (opts.pnotify_nonblock) e.stopPropagation(); + }, + "mousemove": function(e) { + if (opts.pnotify_nonblock) { + e.stopPropagation(); + nonblock_pass(e, "onmousemove"); + } + }, + "mousedown": function(e) { + if (opts.pnotify_nonblock) { + e.stopPropagation(); + e.preventDefault(); + nonblock_pass(e, "onmousedown"); + } + }, + "mouseup": function(e) { + if (opts.pnotify_nonblock) { + e.stopPropagation(); + e.preventDefault(); + nonblock_pass(e, "onmouseup"); + } + }, + "click": function(e) { + if (opts.pnotify_nonblock) { + e.stopPropagation(); + nonblock_pass(e, "onclick"); + } + }, + "dblclick": function(e) { + if (opts.pnotify_nonblock) { + e.stopPropagation(); + nonblock_pass(e, "ondblclick"); + } + } + }); + pnotify.opts = opts; + // Create a drop shadow. + if (opts.pnotify_shadow && !$.browser.msie) + pnotify.shadow_container = $14("
", {"class": "rf-ny-sh"}).prependTo(pnotify); + // Create a container for the notice contents. + pnotify.container = $14("
", {"class": "rf-ny-co"}) + .appendTo(pnotify); + + pnotify.pnotify_version = "1.0.0"; + + // This function is for updating the notice. + pnotify.pnotify = function(options) { + // Update the notice. + var old_opts = opts; + if (typeof options == "string") + opts.pnotify_text = options; + else + opts = $.extend({}, opts, options); + pnotify.opts = opts; + // Update the shadow. + if (opts.pnotify_shadow != old_opts.pnotify_shadow) { + if (opts.pnotify_shadow && !$.browser.msie) + pnotify.shadow_container = $14("
", {"class": "rf-ny-sh"}).prependTo(pnotify); + else + pnotify.children(".rf-ny-sh").remove(); + } + // Update the additional classes. + if (opts.pnotify_addclass === false) + pnotify.removeClass(old_opts.pnotify_addclass); + else if (opts.pnotify_addclass !== old_opts.pnotify_addclass) + pnotify.removeClass(old_opts.pnotify_addclass).addClass(opts.pnotify_addclass); + // Update the title. + if (opts.pnotify_title === false) + pnotify.title_container.hide("fast"); + else if (opts.pnotify_title !== old_opts.pnotify_title) + pnotify.title_container.html(opts.pnotify_title).show(200); + // Update the text. + if (opts.pnotify_text === false) { + pnotify.text_container.hide("fast"); + } else if (opts.pnotify_text !== old_opts.pnotify_text) { + if (opts.pnotify_insert_brs) + opts.pnotify_text = opts.pnotify_text.replace(/\n/g, "
"); + pnotify.text_container.html(opts.pnotify_text).show(200); + } + pnotify.pnotify_history = opts.pnotify_history; + // Change the notice type. + if (opts.pnotify_type != old_opts.pnotify_type) + pnotify.container.toggleClass("rf-ny-co rf-ny-co-hover"); + if ((opts.pnotify_notice_icon != old_opts.pnotify_notice_icon && opts.pnotify_type == "notice") || + (opts.pnotify_error_icon != old_opts.pnotify_error_icon && opts.pnotify_type == "error") || + (opts.pnotify_type != old_opts.pnotify_type)) { + // Remove any old icon. + pnotify.container.find("div.rf-ny-ic").remove(); + // if ((opts.pnotify_error_icon && opts.pnotify_type == "error") || (opts.pnotify_notice_icon)) { + // Build the new icon. + $14("
", {"class": "rf-ny-ic"}) + .append($14("", {"class": opts.pnotify_type == "error" ? opts.pnotify_error_icon : opts.pnotify_notice_icon})) + .prependTo(pnotify.container); + // } + } + // Update the width. + if (opts.pnotify_width !== old_opts.pnotify_width) + pnotify.animate({width: opts.pnotify_width}); + // Update the minimum height. + if (opts.pnotify_min_height !== old_opts.pnotify_min_height) + pnotify.container.animate({minHeight: opts.pnotify_min_height}); + // Update the opacity. + if (opts.pnotify_opacity !== old_opts.pnotify_opacity) + pnotify.fadeTo(opts.pnotify_animate_speed, opts.pnotify_opacity); + if (!opts.pnotify_hide) + pnotify.pnotify_cancel_remove(); + else if (!old_opts.pnotify_hide) + pnotify.pnotify_queue_remove(); + pnotify.pnotify_queue_position(); + return pnotify; + }; + + // Queue the position function so it doesn't run repeatedly and use + // up resources. + pnotify.pnotify_queue_position = function() { + if (timer) + clearTimeout(timer); + timer = setTimeout($.pnotify_position_all, 10); + }; + + // Display the notice. + pnotify.pnotify_display = function() { + // If the notice is not in the DOM, append it. + if (!pnotify.parent().length || !pnotify.parent()[0].tagName) + pnotify.appendTo(body); + // Run callback. + if (opts.pnotify_before_open) { + if (opts.pnotify_before_open(pnotify) === false) + return; + } + pnotify.pnotify_queue_position(); + // First show it, then set its opacity, then hide it. + if (opts.pnotify_animation == "fade" || opts.pnotify_animation.effect_in == "fade") { + // If it's fading in, it should start at 0. + pnotify.show().fadeTo(0, 0).hide(); + } else { + // Or else it should be set to the opacity. + if (opts.pnotify_opacity != 1) + pnotify.show().fadeTo(0, opts.pnotify_opacity).hide(); + } + pnotify.animate_in(function() { + if (opts.pnotify_after_open) + opts.pnotify_after_open(pnotify); + + pnotify.pnotify_queue_position(); + + // Now set it to hide. + if (opts.pnotify_hide) + pnotify.pnotify_queue_remove(); + }); + }; + + // Remove the notice. + pnotify.pnotify_remove = function() { + if (pnotify.timer) { + window.clearTimeout(pnotify.timer); + pnotify.timer = null; + } + // Run callback. + if (opts.pnotify_before_close) { + if (opts.pnotify_before_close(pnotify) === false) + return; + } + pnotify.animate_out(function() { + if (opts.pnotify_after_close) { + if (opts.pnotify_after_close(pnotify) === false) + return; + } + pnotify.pnotify_queue_position(); + // If we're supposed to remove the notice from the DOM, do it. + if (opts.pnotify_remove) { + if (opts.pnotify_history) { + if (pnotify[0].parentNode != null) { + pnotify[0].parentNode.removeChild(pnotify[0]); + } + } else { + pnotify.remove(); + } + } + }); + }; + + // Animate the notice in. + pnotify.animate_in = function(callback) { + // Declare that the notice is animating in. (Or has completed animating in.) + animating = "in"; + var animation; + if (typeof opts.pnotify_animation.effect_in != "undefined") + animation = opts.pnotify_animation.effect_in; + else + animation = opts.pnotify_animation; + if (animation == "none") { + pnotify.show(); + callback(); + } else if (animation == "show") + pnotify.show(opts.pnotify_animate_speed, callback); + else if (animation == "fade") + pnotify.show().fadeTo(opts.pnotify_animate_speed, opts.pnotify_opacity, callback); + else if (animation == "slide") + pnotify.slideDown(opts.pnotify_animate_speed, callback); + else if (typeof animation == "function") + animation("in", callback, pnotify); + else if (pnotify.effect) + pnotify.effect(animation, {}, opts.pnotify_animate_speed, callback); + }; + + // Animate the notice out. + pnotify.animate_out = function(callback) { + // Declare that the notice is animating out. (Or has completed animating out.) + animating = "out"; + var animation; + if (typeof opts.pnotify_animation.effect_out != "undefined") + animation = opts.pnotify_animation.effect_out; + else + animation = opts.pnotify_animation; + if (animation == "none") { + pnotify.hide(); + callback(); + } else if (animation == "show") + pnotify.hide(opts.pnotify_animate_speed, callback); + else if (animation == "fade") + pnotify.fadeOut(opts.pnotify_animate_speed, callback); + else if (animation == "slide") + pnotify.slideUp(opts.pnotify_animate_speed, callback); + else if (typeof animation == "function") + animation("out", callback, pnotify); + else if (pnotify.effect) + pnotify.effect(animation, {}, opts.pnotify_animate_speed, callback); + }; + + // Cancel any pending removal timer. + pnotify.pnotify_cancel_remove = function() { + if (pnotify.timer) + window.clearTimeout(pnotify.timer); + }; + + // Queue a removal timer. + pnotify.pnotify_queue_remove = function() { + // Cancel any current removal timer. + pnotify.pnotify_cancel_remove(); + pnotify.timer = window.setTimeout(function() { + pnotify.pnotify_remove(); + }, (isNaN(opts.pnotify_delay) ? 0 : opts.pnotify_delay)); + }; + + // Provide a button to close the notice. + pnotify.closer = $14("
", { + "class": "rf-ny-cl", + "css": {"cursor": "pointer", "visibility": "hidden"}, + "click": function() { + pnotify.pnotify_remove(); + pnotify.closer.css("visibility", "hidden"); + } + }) + .append($14("", {"class": "rf-ny-cl-ic"})) + .appendTo(pnotify.container); + + // Add the appropriate icon. + // if ((opts.pnotify_error_icon && opts.pnotify_type == "error") || (opts.pnotify_notice_icon)) { + $14("
", {"class": "rf-ny-ic"}) + .append($14("", {"class": opts.pnotify_type == "error" ? opts.pnotify_error_icon : opts.pnotify_notice_icon})) + .appendTo(pnotify.container); + // } + + // Add a title. + pnotify.title_container = $14("
", { + "class": "rf-ny-tl", + "html": opts.pnotify_title + }) + .appendTo(pnotify.container); + if (opts.pnotify_title === false) + pnotify.title_container.hide(); + + // Replace new lines with HTML line breaks. + if (opts.pnotify_insert_brs && typeof opts.pnotify_text == "string") + opts.pnotify_text = opts.pnotify_text.replace(/\n/g, "
"); + // Add text. + pnotify.text_container = $14("
", { + "class": "rf-ny-te", + "html": opts.pnotify_text + }) + .appendTo(pnotify.container); + if (opts.pnotify_text === false) + pnotify.text_container.hide(); + + //Append div with clear:both class + $14("
", {"class":"rf-ny-fcl"}).appendTo(pnotify.container); + + // Set width and min height. + if (typeof opts.pnotify_width == "string") + pnotify.css("width", opts.pnotify_width); + if (typeof opts.pnotify_min_height == "string") + pnotify.container.css("min-height", opts.pnotify_min_height); + + // The history variable controls whether the notice gets redisplayed + // by the history pull down. + pnotify.pnotify_history = opts.pnotify_history; + + // Add the notice to the notice array. + var body_data = body.data("pnotify"); + if (body_data == null || typeof body_data != "object") + body_data = []; + if (opts.pnotify_stack.push == "top") + body_data = $.merge([pnotify], body_data); + else + body_data = $.merge(body_data, [pnotify]); + body.data("pnotify", body_data); + + // Run callback. + if (opts.pnotify_after_init) + opts.pnotify_after_init(pnotify); + + if (opts.pnotify_history) { + // If there isn't a history pull down, create one. + var body_history = body.data("pnotify_history"); + if (typeof body_history == "undefined") { + body_history = $14("
", { + "class": "rf-ny-hc", + "mouseleave": function() { + body_history.animate({top: "-" + history_handle_top + "px"}, {duration: 100, queue: false}); + } + }) + .append($14("
", {"class": "rf-ny-hh", "text": "Redisplay"})) + .append($14("