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
+ ${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 extends UIComponent> 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 extends UIComponent> 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
+ ${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 extends UIComponent> 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
+ ${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
+ htmlImageSelectTool.jspx
+
+
+ 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 extends UIComponent> 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
+ ${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 extends UIComponent> 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
+ ${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 extends UIComponent> 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
+ ${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 extends UIComponent> 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 extends UIComponent> 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("", {
+ "class": "rf-ny-ha",
+ "text": "All",
+ // "mouseenter": function(){
+ // $(this).addClass("ui-state-hover");
+ // },
+ // "mouseleave": function(){
+ // $(this).removeClass("ui-state-hover");
+ // },
+ "click": function() {
+ // Display all notices. (Disregarding non-history notices.)
+ $.each(body.data("pnotify"), function() {
+ if (this.pnotify_history && this.pnotify_display)
+ this.pnotify_display();
+ });
+ return false;
+ }
+ }))
+ .append($14("", {
+ "class": "rf-ny-hl",
+ "text": "Last",
+ // "mouseenter": function(){
+ // $(this).addClass("ui-state-hover");
+ // },
+ // "mouseleave": function(){
+ // $(this).removeClass("ui-state-hover");
+ // },
+ "click": function() {
+ // Look up the last history notice, and display it.
+ var i = 1;
+ var body_data = body.data("pnotify");
+ while (!body_data[body_data.length - i] || !body_data[body_data.length - i].pnotify_history || body_data[body_data.length - i].is(":visible")) {
+ if (body_data.length - i === 0)
+ return false;
+ i++;
+ }
+ var n = body_data[body_data.length - i];
+ if (n.pnotify_display)
+ n.pnotify_display();
+ return false;
+ }
+ }))
+ .appendTo(body);
+
+ // Make a handle so the user can pull down the history pull down.
+ var handle = $14("", {
+ "class": "rf-ny-hp",
+ "mouseenter": function() {
+ body_history.animate({top: "0"}, {duration: 100, queue: false});
+ }
+ })
+ .appendTo(body_history);
+
+ // Get the top of the handle.
+ history_handle_top = handle.offset().top + 2;
+ // Hide the history pull down up to the top of the handle.
+ body_history.css({top: "-" + history_handle_top + "px"});
+ // Save the history pull down.
+ body.data("pnotify_history", body_history);
+ }
+ }
+
+ // Mark the stack so it won't animate the new notice.
+ opts.pnotify_stack.animation = false;
+
+ // Display the notice.
+ pnotify.pnotify_display();
+
+ return pnotify;
+ }
+ });
+
+ // Some useful regexes.
+ var re_on = /^on/;
+ var re_mouse_events = /^(dbl)?click$|^mouse(move|down|up|over|out|enter|leave)$|^contextmenu$/;
+ var re_ui_events = /^(focus|blur|select|change|reset)$|^key(press|down|up)$/;
+ var re_html_events = /^(scroll|resize|(un)?load|abort|error)$/;
+ // Fire a DOM event.
+ var dom_event = function(e, orig_e) {
+ var event_object;
+ e = e.toLowerCase();
+ if (document.createEvent && this.dispatchEvent) {
+ // FireFox, Opera, Safari, Chrome
+ e = e.replace(re_on, '');
+ if (e.match(re_mouse_events)) {
+ // This allows the click event to fire on the notice. There is
+ // probably a much better way to do it.
+ $(this).offset();
+ event_object = document.createEvent("MouseEvents");
+ event_object.initMouseEvent(
+ e, orig_e.bubbles, orig_e.cancelable, orig_e.view, orig_e.detail,
+ orig_e.screenX, orig_e.screenY, orig_e.clientX, orig_e.clientY,
+ orig_e.ctrlKey, orig_e.altKey, orig_e.shiftKey, orig_e.metaKey, orig_e.button, orig_e.relatedTarget
+ );
+ } else if (e.match(re_ui_events)) {
+ event_object = document.createEvent("UIEvents");
+ event_object.initUIEvent(e, orig_e.bubbles, orig_e.cancelable, orig_e.view, orig_e.detail);
+ } else if (e.match(re_html_events)) {
+ event_object = document.createEvent("HTMLEvents");
+ event_object.initEvent(e, orig_e.bubbles, orig_e.cancelable);
+ }
+ if (!event_object) return;
+ this.dispatchEvent(event_object);
+ } else {
+ // Internet Explorer
+ if (!e.match(re_on)) e = "on" + e;
+ event_object = document.createEventObject(orig_e);
+ this.fireEvent(e, event_object);
+ }
+ };
+
+ $.pnotify.defaults = {
+ // The notice's title.
+ pnotify_title: false,
+ // The notice's text.
+ pnotify_text: false,
+ // Additional classes to be added to the notice. (For custom styling.)
+ pnotify_addclass: "",
+ // Create a non-blocking notice. It lets the user click elements underneath it.
+ pnotify_nonblock: false,
+ // The opacity of the notice (if it's non-blocking) when the mouse is over it.
+ pnotify_nonblock_opacity: .2,
+ // Display a pull down menu to redisplay previous notices, and place the notice in the history.
+ pnotify_history: true,
+ // Width of the notice.
+ pnotify_width: "300px",
+ // Minimum height of the notice. It will expand to fit content.
+ pnotify_min_height: "16px",
+ // Type of the notice. "notice" or "error".
+ pnotify_type: "notice",
+ // The icon class to use if type is notice.
+ pnotify_notice_icon: "",
+ // The icon class to use if type is error.
+ pnotify_error_icon: "",
+ // The animation to use when displaying and hiding the notice. "none", "show", "fade", and "slide" are built in to jQuery. Others require jQuery UI. Use an object with effect_in and effect_out to use different effects.
+ pnotify_animation: "fade",
+ // Speed at which the notice animates in and out. "slow", "def" or "normal", "fast" or number of milliseconds.
+ pnotify_animate_speed: "slow",
+ // Opacity of the notice.
+ pnotify_opacity: 1,
+ // Display a drop shadow.
+ pnotify_shadow: false,
+ // Provide a button for the user to manually close the notice.
+ pnotify_closer: true,
+ // After a delay, remove the notice.
+ pnotify_hide: true,
+ // Delay in milliseconds before the notice is removed.
+ pnotify_delay: 8000,
+ // Reset the hide timer if the mouse moves over the notice.
+ pnotify_mouse_reset: true,
+ // Remove the notice's elements from the DOM after it is removed.
+ pnotify_remove: true,
+ // Change new lines to br tags.
+ pnotify_insert_brs: true,
+ // The stack on which the notices will be placed. Also controls the direction the notices stack.
+ pnotify_stack: {"dir1": "down", "dir2": "left", "push": "bottom"}
+ };
+})(jQuery);
\ No newline at end of file
diff --git a/ui/notify/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.notify.js b/ui/notify/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.notify.js
new file mode 100644
index 0000000..04e3d0c
--- /dev/null
+++ b/ui/notify/src/main/resources/org/richfaces/renderkit/html/scripts/richfaces.notify.js
@@ -0,0 +1,174 @@
+/*
+ * 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.NotifyStack = (function() {
+ var stacks = {};
+ return {
+ register: function(id, stack) {
+ var existingStack = stacks[id];
+ if (existingStack != null) {
+ stack = jQuery.extend(existingStack, stack);
+ delete stack.addpos1;
+ delete stack.addpos2;
+ delete stack.animation;
+ delete stack.firstpos1;
+ delete stack.firstpos2;
+ delete stack.nextpos1;
+ delete stack.nextpos2;
+ }
+ stack.id = id;
+ stacks[id] = stack;
+ },
+ getStack: function(id) {
+ var stack = stacks[id];
+ if (stack == null) {
+ stack = jQuery.extend({}, jQuery.pnotify.defaults.pnotify_stack);
+ this.register(id, stack);
+ }
+ return stack;
+ }
+ }
+})();
+
+RichFaces.Notify = function(options) {
+ /**
+ * Copies attributes from one objects to other object, but
+ * can change the name of target attributes.
+ */
+ function extend(target, source, translation) {
+ for (var attr in source) {
+ var targetAttr = translation[attr] != null ? translation[attr] : attr;
+ target[targetAttr] = source[attr];
+ if (attr != 'stack' && target[targetAttr] instanceof Object) {
+ target[targetAttr] = extend({}, target[targetAttr], translation);
+ }
+ }
+ return target;
+ }
+
+ options = jQuery.extend({stack:'default'}, options);
+ if (options != null && typeof options.stack == "string") {
+ options.stack = RichFaces.NotifyStack.getStack(options.stack);
+ }
+ var delegateOptions = extend({}, options, {
+ 'title':'pnotify_title' ,
+ 'text': 'pnotify_text',
+ 'styleClass': 'pnotify_addclass',
+ 'nonblocking': 'pnotify_nonblock',
+ 'nonblockingOpacity': 'pnotify_nonblock_opacity',
+ 'showHistory': 'pnotify_history',
+ 'animation': 'pnotify_animation',
+ 'appearAnimation': 'effect_in',
+ 'hideAnimation': 'effect_out',
+ 'animationSpeed': 'pnotify_animate_speed',
+ 'opacity': 'pnotify_opacity',
+ 'showShadow': 'pnotify_shadow',
+ 'showCloseButton': 'pnotify_closer',
+ 'sticky': 'pnotify_hide',
+ 'stayTime': 'pnotify_delay',
+ 'stack': 'pnotify_stack'
+ });
+ if (options.sticky !== null) {
+ delegateOptions.pnotify_hide = !options.sticky;
+ }
+ jQuery(document).ready(function() {
+ if (options.delay) {
+ setTimeout(function() {
+ jQuery.pnotify(delegateOptions);
+ }, options.delay);
+ } else {
+ jQuery.pnotify(delegateOptions);
+ }
+ });
+};
+
+//TODO remove this fix when it gets in to jquery.js
+(function() {
+ var safariCompatMode;
+ var getCompatMode = function() {
+ var compatMode = document.compatMode;
+ if (!compatMode && jQuery.browser.safari) {
+ if (!safariCompatMode) {
+ //detect compatMode as described in http://code.google.com/p/doctype/wiki/ArticleCompatMode
+ var width = jQuery(document.createElement("div")).attr('style', 'position:absolute;width:0;height:0;width:1')
+ .css('width');
+ safariCompatMode = compatMode = (width == '1px' ? 'BackCompat' : 'CSS1Compat');
+ } else {
+ compatMode = safariCompatMode;
+ }
+ }
+
+ return compatMode;
+ };
+
+
+ // Create innerHeight, innerWidth, outerHeight and outerWidth methods
+ jQuery.each([ "Height", "Width" ], function(i, name) {
+
+ var tl = i ? "Left" : "Top", // top or left
+ br = i ? "Right" : "Bottom", // bottom or right
+ lower = name.toLowerCase();
+
+ // innerHeight and innerWidth
+ jQuery.fn["inner" + name] = function() {
+ return this[0] ?
+ jQuery.css(this[0], lower, false, "padding") :
+ null;
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn["outer" + name] = function(margin) {
+ return this[0] ?
+ jQuery.css(this[0], lower, false, margin ? "margin" : "border") :
+ null;
+ };
+
+ var type = name.toLowerCase();
+
+ jQuery.fn[ type ] = function(size) {
+ // Get window width or height
+ return this[0] == window ?
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ getCompatMode() == "CSS1Compat" && document.documentElement[ "client" + name ] ||
+ document.body[ "client" + name ] :
+
+ // Get document width or height
+ this[0] == document ?
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ Math.max(
+ document.documentElement["client" + name],
+ document.body["scroll" + name], document.documentElement["scroll" + name],
+ document.body["offset" + name], document.documentElement["offset" + name]
+ ) :
+
+ // Get or set width or height on the element
+ size === undefined ?
+ // Get width or height on the element
+ (this.length ? jQuery.css(this[0], type) : null) :
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ this.css(type, typeof size === "string" ? size : size + "px");
+ };
+
+ });
+}());
\ No newline at end of file
diff --git a/ui/pom.xml b/ui/pom.xml
new file mode 100644
index 0000000..c8bff1a
--- /dev/null
+++ b/ui/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+ org.richfaces.sandbox.bernard-aggregator
+ ui
+ 3.3.4-SNAPSHOT
+ pom
+ ui
+
+
+ coordinatesGrid-sm
+ coordinatesGrid
+ dock
+ focus
+ gmapMarker
+ imageSelectTool
+ jQueryPlugin
+ lightbox
+ notify
+ schedule
+ watermark
+ radio
+
+
+
+
diff --git a/ui/radio/pom.xml b/ui/radio/pom.xml
new file mode 100644
index 0000000..0c889c9
--- /dev/null
+++ b/ui/radio/pom.xml
@@ -0,0 +1,76 @@
+
+
+ 4.0.0
+
+ org.richfaces.sandbox
+ ui
+ 3.3.4-SNAPSHOT
+
+ org.richfaces.sandbox.ui
+ radio
+ radio
+
+
+
+ org.richfaces.cdk
+ maven-cdk-plugin
+ ${project.version}
+
+
+ generate-sources
+
+ generate
+
+
+
+
+
+ org.richfaces.sandbox.ui
+
+ radio
+ http://richfaces.org/sandbox/radio
+
+
+
+
+
+ maven-compiler-plugin
+ true
+
+
+ 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/radio/src/main/config/component/radio.xml b/ui/radio/src/main/config/component/radio.xml
new file mode 100644
index 0000000..a4cc99b
--- /dev/null
+++ b/ui/radio/src/main/config/component/radio.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+ javax.faces.HtmlSelectOneRadio
+ javax.faces.SelectOne
+ javax.faces.component.html.HtmlSelectOneRadio
+ javax.faces.component.UISelectOne
+
+ org.richfaces.renderkit.html.SelectOneRadioRenderer
+ org.richfaces.renderkit.html.SelectOneRadioRenderer
+
+
+ selectOneRadio
+ org.richfaces.taglib.SelectOneRadioTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &html_input_radio_attributes;
+
+ alt
+ java.lang.String
+
+
+ datafld
+ java.lang.String
+
+
+ dataformatas
+ java.lang.String
+
+
+ datasrc
+ java.lang.String
+
+
+
+ disabled
+ java.lang.Boolean
+ Disabled state of an element or button
+
+
+ readonly
+ java.lang.Boolean
+ Flag indicating that this component will prohibit
+ changes by you. The element may receive focus
+ unless it has also been disabled
+
+
+
+
+
+ org.richfaces.Radio
+ org.richfaces.Radio
+ org.richfaces.component.html.HtmlRadio
+ org.richfaces.component.UIRadio
+
+
+
+
+ org.richfaces.renderkit.html.RadioRenderer
+ org.richfaces.renderkit.html.SingleRadioRenderer
+
+
+ radio
+ org.richfaces.taglib.RadioTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+
+ org.richfaces.taglib.RadioTagHandler
+ com.sun.facelets.tag.jsf.ComponentHandler
+
+ &html_events;
+ &html_control_events;
+ &ui_output_attributes;
+
+ for
+ java.lang.String
+
+ Id of selectMenuRadio.
+
+
+
+ index
+ java.lang.Integer
+
+ SelectItem index.
+
+
+
+
diff --git a/ui/radio/src/main/config/component/readme b/ui/radio/src/main/config/component/readme
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/radio/src/main/config/component/readme
diff --git a/ui/radio/src/main/java/org/richfaces/component/UIRadio.java b/ui/radio/src/main/java/org/richfaces/component/UIRadio.java
new file mode 100644
index 0000000..7c6b9e3
--- /dev/null
+++ b/ui/radio/src/main/java/org/richfaces/component/UIRadio.java
@@ -0,0 +1,122 @@
+package org.richfaces.component;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIOutput;
+import javax.faces.component.UISelectItem;
+import javax.faces.component.UISelectItems;
+import javax.faces.context.FacesContext;
+import javax.faces.model.SelectItem;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public abstract class UIRadio extends UIOutput {
+// ------------------------------ FIELDS ------------------------------
+
+ public static final String COMPONENT_FAMILY = "org.richfaces.Radio";
+
+ public static final String COMPONENT_TYPE = "org.richfaces.Radio";
+
+// -------------------------- STATIC METHODS --------------------------
+
+ /**
+ * Return a List of {@link javax.faces.model.SelectItem}
+ * instances representing the available options for this component,
+ * assembled from the set of {@link javax.faces.component.UISelectItem}
+ * and/or {@link javax.faces.component.UISelectItems} components that are
+ * direct children of this component. If there are no such children, an
+ * empty Iterator
is returned.
+ *
+ * @param context The {@link javax.faces.context.FacesContext} for the current request.
+ * If null, the UISelectItems behavior will not work.
+ * @param component the component
+ * @return a List of the select items for the specified component
+ * @throws IllegalArgumentException if context
+ * is null
+ */
+ public static List getSelectItems(FacesContext context,
+ UIComponent component) {
+ if (context == null) {
+ throw new IllegalArgumentException("Context param must not be null.");
+ }
+
+ ArrayList list = new ArrayList();
+ for (UIComponent kid : component.getChildren()) {
+ if (kid instanceof UISelectItem) {
+ UISelectItem item = (UISelectItem) kid;
+ Object value = item.getValue();
+
+ if (value == null) {
+ list.add(new SelectItem(item.getItemValue(),
+ item.getItemLabel(),
+ item.getItemDescription(),
+ item.isItemDisabled(),
+ item.isItemEscaped()));
+ } else if (value instanceof SelectItem) {
+ list.add((SelectItem) value);
+ } else {
+ throw new IllegalArgumentException(
+ "Argument Error: An option for component ''" + component.getId() + "'' was not an instance of javax.faces.model.SelectItem. Type found: ''" + value.getClass().getName() + "''.");
+ }
+ } else if (kid instanceof UISelectItems) {
+ Object value = ((UISelectItems) kid).getValue();
+ if (value instanceof SelectItem) {
+ list.add((SelectItem) value);
+ } else if (value instanceof SelectItem[]) {
+ SelectItem[] items = (SelectItem[]) value;
+ // we manually copy the elements so that the list is
+ // modifiable. Arrays.asList() returns a non-mutable
+ // list.
+ //noinspection ManualArrayToCollectionCopy
+ for (SelectItem item : items) {
+ list.add(item);
+ }
+ } else if (value instanceof Collection) {
+ for (Object element : ((Collection) value)) {
+ if (SelectItem.class.isInstance(element)) {
+ list.add((SelectItem) element);
+ } else {
+ throw new IllegalArgumentException(
+ "Argument Error: An option for component ''" + component.getId() + "'' was not an instance of javax.faces.model.SelectItem. Type found: ''" + value.getClass().getName() + "''.");
+ }
+ }
+ } else if (value instanceof Map) {
+ Map optionMap = (Map) value;
+ for (Object o : optionMap.entrySet()) {
+ Map.Entry entry = (Map.Entry) o;
+ Object key = entry.getKey();
+ Object val = entry.getValue();
+ if (key == null || val == null) {
+ continue;
+ }
+ list.add(new SelectItem(val,
+ key.toString()));
+ }
+ } else {
+ throw new IllegalArgumentException("Expected a child component type of ''UISelectItem/UISelectItems'' for component type ''" + component.getFamily() + "(" + component.getId() + ")''. Found ''" + (value != null ? value.getClass().getName() : "null") + "''.");
+ }
+ }
+ }
+ return (list);
+ }
+
+// -------------------------- OTHER METHODS --------------------------
+
+ public abstract String getFor();
+
+ public abstract Integer getIndex();
+
+ public SelectItem getSelectItem(FacesContext context, UIComponent targetComponent) {
+ final List list = getSelectItems(context, targetComponent);
+ try {
+ return list.get(getIndex());
+ } catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException("Component ''" + getId() + "'' has wrong value of index attribute (" + getIndex() + "). Target component ''" + targetComponent.getId() + "'' has only " + list.size() + " items.");
+ }
+ }
+
+ public abstract void setFor(String _for);
+
+ public abstract void setIndex(Integer index);
+}
diff --git a/ui/radio/src/main/java/org/richfaces/component/readme b/ui/radio/src/main/java/org/richfaces/component/readme
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/radio/src/main/java/org/richfaces/component/readme
diff --git a/ui/radio/src/main/java/org/richfaces/renderkit/html/SelectOneRadioRenderer.java b/ui/radio/src/main/java/org/richfaces/renderkit/html/SelectOneRadioRenderer.java
new file mode 100644
index 0000000..835060b
--- /dev/null
+++ b/ui/radio/src/main/java/org/richfaces/renderkit/html/SelectOneRadioRenderer.java
@@ -0,0 +1,14 @@
+package org.richfaces.renderkit.html;
+
+import com.sun.faces.renderkit.html_basic.RadioRenderer;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import java.io.IOException;
+
+public class SelectOneRadioRenderer extends RadioRenderer {
+
+ @Override
+ public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
+ }
+}
diff --git a/ui/radio/src/main/java/org/richfaces/renderkit/html/SingleRadioRenderer.java b/ui/radio/src/main/java/org/richfaces/renderkit/html/SingleRadioRenderer.java
new file mode 100644
index 0000000..54ad5d7
--- /dev/null
+++ b/ui/radio/src/main/java/org/richfaces/renderkit/html/SingleRadioRenderer.java
@@ -0,0 +1,86 @@
+package org.richfaces.renderkit.html;
+
+import org.ajax4jsf.renderkit.RendererBase;
+import org.richfaces.component.UIRadio;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import java.io.IOException;
+
+public class SingleRadioRenderer extends RendererBase {
+ private String convertToString(Object obj) {
+ return (obj == null ? "" : obj.toString());
+ }
+
+ @Override
+ protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent _component) throws IOException {
+ UIRadio component = (UIRadio) _component;
+ java.lang.String clientId = component.getClientId(context);
+ final UIComponent targetComponent = getUtils().findComponentFor(component, component.getFor());
+ final javax.faces.model.SelectItem item = component.getSelectItem(context, targetComponent);
+ boolean checked = false;
+ if (targetComponent instanceof javax.faces.component.UIOutput) {
+ final Object currentValue = ((javax.faces.component.UIOutput) targetComponent).getValue();
+ final Object itemValue = item.getValue();
+ checked = itemValue == null ? currentValue == null : itemValue.equals(currentValue);
+ }
+
+ writer.startElement("input", component);
+ getUtils().writeAttribute(writer, "id", clientId);
+ getUtils().writeAttribute(writer, "name", getUtils().clientId(context, targetComponent));
+ getUtils().writeAttribute(writer, "type", "radio");
+ getUtils().writeAttribute(writer, "value", item.getValue());
+ if (checked) {
+ getUtils().writeAttribute(writer, "checked", "checked");
+ }
+ //
+// pass thru attributes
+//
+ getUtils().encodeAttributesFromArray(context, component, new String[]{
+ "accept",
+ "accesskey",
+ "align",
+ "alt",
+ "checked",
+ "dir",
+ "disabled",
+ "lang",
+ "maxlength",
+ "onblur",
+ "onchange",
+ "onclick",
+ "ondblclick",
+ "onfocus",
+ "onkeydown",
+ "onkeypress",
+ "onkeyup",
+ "onmousedown",
+ "onmousemove",
+ "onmouseout",
+ "onmouseover",
+ "onmouseup",
+ "onselect",
+ "readonly",
+ "size",
+ "src",
+ "style",
+ "tabindex",
+ "title",
+ "usemap",
+ "xml:lang"});
+
+ writer.endElement("input");
+ writer.startElement("label", component);
+ getUtils().writeAttribute(writer, "for", clientId);
+
+ writer.writeText(convertToString(item.getLabel()), null);
+
+ writer.endElement("label");
+ }
+
+ @Override
+ protected Class extends UIComponent> getComponentClass() {
+ return UIRadio.class;
+ }
+}
diff --git a/ui/radio/src/main/resources/META-INF/faces-config.xml b/ui/radio/src/main/resources/META-INF/faces-config.xml
new file mode 100644
index 0000000..8346a0a
--- /dev/null
+++ b/ui/radio/src/main/resources/META-INF/faces-config.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+ javax.faces.HtmlSelectOneRadio
+ javax.faces.component.html.HtmlSelectOneRadio
+
+
+ javax.faces.SelectOne
+ org.richfaces.renderkit.html.SelectOneRadioRenderer
+
+
+
+
+ HTML_BASIC
+
+ javax.faces.SelectOne
+
+ org.richfaces.renderkit.html.SelectOneRadioRenderer
+
+
+ org.richfaces.renderkit.html.SelectOneRadioRenderer
+
+
+
+
+
+
+
+
diff --git a/ui/schedule/pom.xml b/ui/schedule/pom.xml
new file mode 100644
index 0000000..ba964f9
--- /dev/null
+++ b/ui/schedule/pom.xml
@@ -0,0 +1,86 @@
+
+
+ 4.0.0
+
+ ui
+ org.richfaces.sandbox
+ 3.3.4-SNAPSHOT
+
+ org.richfaces.sandbox.ui
+ schedule
+ schedule
+
+
+
+ org.richfaces.cdk
+ maven-cdk-plugin
+ ${project.version}
+
+
+ generate-sources
+
+ generate
+
+
+
+ generate-test-sources
+ generate-test-sources
+
+ generate-tests
+
+
+
+
+
+ org.richfaces.ui
+
+ schedule
+ http://richfaces.org/sandbox/schedule
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+ displayedDaysForMonthViewCalculationTestData
+ ${basedir}/src/test/resources/displayedDaysForMonthViewCalculationTestData.txt
+
+
+
+ displayedDaysForWeekViewCalculationTestData
+ ${basedir}/src/test/resources/displayedDaysForWeekViewCalculationTestData.txt
+
+
+ displayedDaysForDayViewCalculationTestData
+ ${basedir}/src/test/resources/displayedDaysForDayViewCalculationTestData.txt
+
+
+
+
+
+
+
+ UTF-8
+
+
+
+ org.richfaces.framework
+ richfaces-impl
+ ${project.version}
+
+
+
+
+ bernard.labno.pl
+ MyCo Internal Repository
+ http://bernard.labno.pl/artifactory/libs-snapshot-local
+
+
+
+
diff --git a/ui/schedule/src/main/config/component/README b/ui/schedule/src/main/config/component/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/schedule/src/main/config/component/README
diff --git a/ui/schedule/src/main/config/component/commonViewAttributes.ent b/ui/schedule/src/main/config/component/commonViewAttributes.ent
new file mode 100644
index 0000000..8a77f0e
--- /dev/null
+++ b/ui/schedule/src/main/config/component/commonViewAttributes.ent
@@ -0,0 +1,43 @@
+
+ timeFormat
+ java.lang.String
+
+ Determines the time-text that will be displayed on each event.
+ Time-text will only be displayed for Event Objects that have allDay equal to false.
+ default for agendaDay and agendaWeek: 'h:mm{ - h:mm}', // 5:00 - 6:30
+ default for all others: 'h(:mm)t' // 7p
+
+ null
+
+
+ columnFormat
+ java.lang.String
+
+ Determines the text that will be displayed on the calendar's column headings.
+ default for month: 'ddd', // Mon
+ default for week: 'ddd M/d', // Mon 9/7
+ default for day: 'dddd M/d' // Monday 9/7
+
+ null
+
+
+ titleFormat
+ java.lang.String
+
+ Determines the text that will be displayed in the header's title.
+ default for month: 'MMMM yyyy', // September 2009
+ default for week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}", // Sep 7 - 13 2009
+ default for day: 'dddd, MMM d, yyyy' // Tuesday, Sep 8, 2009
+
+ null
+
+
+ dragOpacity
+ java.lang.Double
+
+ The opacity of an event while it is being dragged.
+ default for agendaWeek: .5
+ default for other views: 1
+
+ null
+
\ No newline at end of file
diff --git a/ui/schedule/src/main/config/component/listeners.ent b/ui/schedule/src/main/config/component/listeners.ent
new file mode 100644
index 0000000..09188a9
--- /dev/null
+++ b/ui/schedule/src/main/config/component/listeners.ent
@@ -0,0 +1,250 @@
+
+ itemSelectListener
+
+ binding
+ org.richfaces.scheduleItemSelectListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleItemSelectListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleItemSelectEvent
+
+
+
+ org.richfaces.taglib.ScheduleItemSelectListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.ItemSelectListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
+
+
+ itemMoveListener
+
+ binding
+ org.richfaces.scheduleItemMoveListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleItemMoveListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleItemMoveEvent
+
+
+
+ org.richfaces.taglib.ScheduleItemMoveListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.ItemMoveListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
+
+
+ itemResizeListener
+
+ binding
+ org.richfaces.scheduleItemResizeListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleItemResizeListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleItemResizeEvent
+
+
+
+ org.richfaces.taglib.ScheduleItemResizeListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.ItemResizeListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
+
+
+ viewChangeListener
+
+ binding
+ org.richfaces.scheduleViewChangeListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleViewChangeListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleViewChangeEvent
+
+
+
+ org.richfaces.taglib.ScheduleViewChangeListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.ViewChangeListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
+
+
+ dateRangeChangeListener
+
+ binding
+ org.richfaces.scheduleDateRangeChangeListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleDateRangeChangeListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleDateRangeChangeEvent
+
+
+
+ org.richfaces.taglib.ScheduleDateRangeChangeListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.DateRangeChangeListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
+
+ dateRangeSelectListener
+
+ binding
+ org.richfaces.scheduleDateRangeSelectdListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleDateRangeSelectListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleDateRangeSelectEvent
+
+
+
+ org.richfaces.taglib.ScheduleDateRangeSelectListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.DateRangeSelectListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
+
+
+ dateSelectListener
+
+ binding
+ org.richfaces.scheduleDateSelectListener
+ The attribute takes a value-binding expression for a component property of
+ a backing bean
+
+
+
+ org.richfaces.component.event.ScheduleDateSelectListener
+
+
+ org.richfaces.component.event.ScheduleListenerEventsProducer
+
+
+ org.richfaces.component.event.ScheduleDateSelectEvent
+
+
+
+ org.richfaces.taglib.ScheduleDateSelectListenerTagHandler
+
+
+
+
+ org.richfaces.taglib.DateSelectListenerTag
+
+
+
+
+ type
+ java.lang.String
+ The fully qualified Java class name for the listener
+
+
\ No newline at end of file
diff --git a/ui/schedule/src/main/config/component/schedule.xml b/ui/schedule/src/main/config/component/schedule.xml
new file mode 100644
index 0000000..c643db3
--- /dev/null
+++ b/ui/schedule/src/main/config/component/schedule.xml
@@ -0,0 +1,778 @@
+]
+ >
+
+
+ org.richfaces.Schedule
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlSchedule
+ org.richfaces.component.UISchedule
+
+
+
+
+ org.richfaces.renderkit.ScheduleRenderer
+ org/richfaces/htmlSchedule.jspx
+ org.richfaces.renderkit.ScheduleRendererBase
+
+
+ schedule
+ org.richfaces.taglib.ScheduleTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+
+ org.richfaces.taglib.ScheduleTagHandler
+ org.richfaces.taglib.ScheduleTagHandlerBase
+
+ &ui_component_attributes; &commonViewAttributes; &ajax_component_attributes;
+
+ switchType
+ java.lang.String
+
+ Available options:
+
+ - ajax
+ - server
+ - client
+
+
+ "ajax"
+
+
+ widgetVar
+ java.lang.String
+
+ Variable name of JavaScript component. default: null
+
+ null
+
+
+ view
+ java.lang.String
+
+ Schedule has a number of different "views", or ways of displaying days and events. The following 5 views are all built in to schedule:
+
+ - month
+ - basicWeek
+ - basicDay
+ - agendaWeek
+ - agendaDay
+
+ default: 'month'
+
+ null
+
+
+ headerLeft
+ java.lang.String
+
+ Defines the buttons and title at the top of the calendar. Values separated by a comma will be displayed adjacently. Values separated by a space
+ will be displayed with a small gap in between. Strings can contain any of the following values:
+
+ -
+ title
+ - text containing the current month/week/day
+
+ -
+ prev
+ - button for moving the calendar back one month/week/day
+
+ -
+ next
+ - button for moving the calendar forward one month/week/day
+
+ -
+ prevYear
+ - button for moving the calendar back on year
+
+ -
+ nextYear
+ - button for moving the calendar forward one year
+
+ -
+ today
+ - button for moving the calendar to the current month/week/day
+
+ -
+ a view name
+ - button that will switch the calendar to any of the available views; see defaultView
+
+
+ default: 'title'
+
+ null
+
+
+ headerCenter
+ java.lang.String
+
+ Defines the buttons and title at the top of the calendar. Values separated by a comma will be displayed adjacently. Values separated by a space
+ will be displayed with a small gap in between. Strings can contain any of the following values:
+
+ -
+ title
+ - text containing the current month/week/day
+
+ -
+ prev
+ - button for moving the calendar back one month/week/day
+
+ -
+ next
+ - button for moving the calendar forward one month/week/day
+
+ -
+ prevYear
+ - button for moving the calendar back on year
+
+ -
+ nextYear
+ - button for moving the calendar forward one year
+
+ -
+ today
+ - button for moving the calendar to the current month/week/day
+
+ -
+ a view name
+ - button that will switch the calendar to any of the available views; see defaultView
+
+
+ default: ''
+
+ null
+
+
+ headerRight
+ java.lang.String
+
+ Defines the buttons and title at the top of the calendar. Values separated by a comma will be displayed adjacently. Values separated by a space
+ will be displayed with a small gap in between. Strings can contain any of the following values:
+
+ -
+ title
+ - text containing the current month/week/day
+
+ -
+ prev
+ - button for moving the calendar back one month/week/day
+
+ -
+ next
+ - button for moving the calendar forward one month/week/day
+
+ -
+ prevYear
+ - button for moving the calendar back on year
+
+ -
+ nextYear
+ - button for moving the calendar forward one year
+
+ -
+ today
+ - button for moving the calendar to the current month/week/day
+
+ -
+ a view name
+ - button that will switch the calendar to any of the available views; see defaultView
+
+
+ default: 'today prev,next'
+
+ null
+
+
+ allDaySlot
+ java.lang.Boolean
+
+ Determines if the "all-day" slot is displayed at the top of the calendar. When hidden with false, all-day events will not be displayed in agenda
+ views. default: true
+
+ null
+
+
+ allDayText
+ java.lang.String
+
+ The text titling the "all-day" slot at the top of the calendar. default: 'all-day'
+
+ null
+
+
+ axisFormat
+ java.lang.String
+
+ Determines the time-text that will be displayed on the vertical axis of the agenda views. The default value will produce times that look like
+ "5pm" and "5:30pm". default: 'h(:mm)tt'
+
+ null
+
+
+ slotMinutes
+ java.lang.Integer
+
+ The frequency for displaying time slots, in minutes. The default will make a slot every half hour. default: 30
+
+ null
+
+
+ defaultEventMinutes
+ java.lang.Integer
+
+ Determines the length (in minutes) an event appears to be when it has an unspecified end date. By default, if an Event Object has no end, it
+ will appear to be 2 hours. This option only affects events that appear in the agenda slots, meaning they have allDay set to true. default: 120
+
+ null
+
+
+ firstHour
+ java.lang.Integer
+
+ Determines the first hour that will be visible in the scroll pane. Values must be from 0-23, where 0=midnight, 1=1am, etc. The user will be able
+ to scroll upwards to see events before this time. If you want to prevent users from doing this, use the minTime option instead. default: 6
+
+ null
+
+
+ minTime
+ java.lang.String
+
+ Determines the first hour/time that will be displayed, even when the scrollbars have been scrolled all the way up. This can be a number like 5
+ (which means 5am), a string like '5:30' (which means 5:30am) or a string like '5:30am'. default: 0
+
+ null
+
+
+ maxTime
+ java.lang.String
+
+ Determines the last hour/time (exclusively) that will be displayed, even when the scrollbars have been scrolled all the way down. This can be a
+ number like 22 (which means 10pm), a string like '22:30' (which means 10:30pm) or a string like '10:30pm'. default: 24
+
+ null
+
+
+ firstDay
+ java.lang.Integer
+
+ The day that each week begins. The value must be a number that represents the day of the week. Sunday=0, Monday=1, Tuesday=2, etc. default: 0
+
+ null
+
+
+ isRTL
+ java.lang.Boolean
+
+ Displays the calendar in right-to-left mode. default: false
+
+ null
+
+
+ showWeekends
+ java.lang.Boolean
+
+ Whether to include Saturday/Sunday columns in any of the calendar views. default: true
+
+ null
+
+
+ height
+ java.lang.Integer
+
+ Will make the entire calendar (including header) a pixel height. By default, this option is unset and the calendar's height is calculated by
+ aspectRatio.
+
+ null
+
+
+ contentHeight
+ java.lang.Integer
+
+ Will make the calendar's content area a pixel height. By default, this option is unset and the calendar's height is calculated by aspectRatio.
+
+ null
+
+
+ aspectRatio
+ java.lang.Double
+
+ Determines the width-to-height aspect ratio of the calendar. A calendar is a block-level element that fills its entire avaiable width. The
+ calendar’s height, however, is determined by this ratio of width-to-height. (Hint: larger numbers make smaller heights). default: 1.35
+
+ null
+
+
+ allDayByDefault
+ java.lang.Boolean
+
+ Determines the default value for each Event Object's allDay property, when it is unspecified. default: true
+
+ null
+
+
+
+ editable
+ java.lang.Boolean
+
+ Determines whether the events on the calendar can be modified. This determines if the events can be dragged and resized. Enables/disables both
+ at the same time. If you don't want both, use editable in conjunction with disableDragging and disableResizing. This option can be overridden on
+ a per-event basis with the Event Object editable property. default: false
+
+ null
+
+
+ selectable
+ java.lang.Boolean
+
+ Allows a user to highlight multiple days or timeslots by clicking and dragging. To let the user make selections by clicking and dragging, this
+ option must be set to true. default: false
+
+ null
+
+
+ selectHelper
+ java.lang.Boolean
+
+ Whether to draw a "placeholder" event while the user is dragging. A value of true will draw a "placeholder" event while the user is dragging
+ (similar to what Google Calendar does for its week and day views). A value of false (the default) will draw the standard highlighting over each
+ cell. default: false
+
+ null
+
+
+ unselectAuto
+ java.lang.Boolean
+
+ Whether clicking elsewhere on the page will cause the current selection to be cleared. This option can only take effect when selectable is set
+ to true. default: true
+
+ null
+
+
+ unselectCancel
+ java.lang.String
+
+ A way to specify elements that will ignore the unselectAuto option. Clicking on elements that match this jQuery selector will prevent the
+ current selection from being cleared (due to the unselectAuto option). This option is useful if you have a "Create an event" form that shows up
+ in response to the user making a selection. When the user clicks on this form, you probably don't want to the current selection to go away.
+ Thus, you should add a class to your form such as "my-form", and set the unselectAuto option to ".my-form". default: ''
+
+ null
+
+
+ disableDragging
+ java.lang.Boolean
+
+ Disables all event dragging, even when events are editable. default: false
+
+ null
+
+
+ disableResizing
+ java.lang.Boolean
+
+ Disables all event resizing, even when events are editable. default: false
+
+ null
+
+
+ dragRevertDuration
+ java.lang.Integer
+
+ Time in millisecond it takes for an event to revert to its original position after an unsuccessful drag. default: 500
+
+ null
+
+
+
+ date
+ java.util.Date
+
+ The initial date when schedule loads. default:
+ current date
+
+ null
+
+
+
+ onbeforeitemselect
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - view - object representing current view
+
+
+ null
+
+
+ onitemselect
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when item is selected has finished. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - view - object representing current view
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+ onitemdragstart
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+
+
+ null
+
+
+ onitemdragstop
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+
+
+ null
+
+
+ onitemresizestart
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+
+
+ null
+
+
+ onitemresizestop
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+
+
+ null
+
+
+ onbeforeitemdrop
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - dayDelta - holds the number of days the event was moved forward (a positive number) or backwards (a negative number)
+
+ - minuteDelta - holds the number of minutes the event was moved forward (a positive number) or backwards (a negative number). Only useful
+ for the agenda views. In other views, 0 is passed in.
+
+ - allDay - is true if the event has been dropped on a day in month view, or the "all-day" slot in the agenda views. It will be false if
+ dropped on a slot in the agenda views (meaning it has been assigned a time).
+
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+
+
+ null
+
+
+ onitemdrop
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when item is dropped has finished. Following data will be available in context:
+
+ - item - selected item
+ - dayDelta - holds the number of days the event was moved forward (a positive number) or backwards (a negative number)
+
+ - minuteDelta - holds the number of minutes the event was moved forward (a positive number) or backwards (a negative number). Only useful
+ for the agenda views. In other views, 0 is passed in.
+
+ - allDay - is true if the event has been dropped on a day in month view, or the "all-day" slot in the agenda views. It will be false if
+ dropped on a slot in the agenda views (meaning it has been assigned a time).
+
+ - vetoed - is true if server side listener has raised veto and modification has been reverted
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+ onbeforeitemresize
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - dayDelta - holds the number of days the event was moved forward (a positive number) or backwards (a negative number)holds the number of
+ minutes the event was moved forward (a positive number) or backwards (a negative number). Only useful for the agenda views. In other
+ views, 0 is passed in.
+
+ - minuteDelta - holds the number of minutes the event was moved forward (a positive number) or backwards (a negative number). Only useful
+ for the agenda views. In other views, 0 is passed in.
+
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+
+
+ null
+
+
+ onitemresize
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when item is resized has finished. Following data will be available in context:
+
+ - item - selected item
+ - dayDelta - holds the number of days the event was moved forward (a positive number) or backwards (a negative number)
+
+ - minuteDelta - holds the number of minutes the event was moved forward (a positive number) or backwards (a negative number). Only useful
+ for the agenda views. In other views, 0 is passed in.
+
+ - vetoed - is true if server side listener has raised veto and modification has been reverted
+ - event - javascript event
+ - ui - jQuery UI object
+ - view - object representing current view
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+ onitemmouseover
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - view - object representing current view
+
+
+ null
+
+
+ onitemmouseout
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - item - selected item
+ - event - javascript event
+ - view - object representing current view
+
+
+ null
+
+
+ onbeforeviewchange
+ java.lang.String
+
+ JavaScript code for handling event.
+ Any return instruction will be ignored
+ so this code cannot block anything. Following data will be available in context:
+
+ - view - object representing current view
+
+
+ null
+
+
+ onviewchange
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when view changes has finished. Following data will be available in context:
+
+ - view - object representing current view
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+ onbeforedateselect
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - date - selected date
+ - allDay - is true if the event has been dropped on a day in month view, or the "all-day" slot in the agenda views.
+
+ - event - javascript event
+ - view - object representing current view
+
+
+ null
+
+
+ ondateselect
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when date is selected has finished. Following data will be available in context:
+
+ - date - selected date
+ - allDay - is true if the event has been dropped on a day in month view, or the "all-day" slot in the agenda views.
+
+ - event - javascript event
+ - view - object representing current view
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+ onbeforedaterangeselect
+ java.lang.String
+
+ JavaScript code for handling event. Following data will be available in context:
+
+ - startDate - selection start date
+ - endDate - selection end date
+ - allDay - is true if the event has been dropped on a day in month view, or the "all-day" slot in the agenda views.
+
+ - view - object representing current view
+
+
+ null
+
+
+ ondaterangeselect
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when date range is selected has finished. Following data will be available in context:
+
+ - startDate - selection start date
+ - endDate - selection end date
+ - allDay - is true if the event has been dropped on a day in month view, or the "all-day" slot in the agenda views.
+
+ - view - object representing current view
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+
+ onbeforedaterangechange
+ java.lang.String
+
+ JavaScript code for handling event.
+ Any return instruction will be ignored
+ so this code cannot block anything. Following data will be available in context:
+
+ - startDate - start date
+ - endDate - end date
+
+
+ null
+
+
+ ondaterangechange
+ java.lang.String
+
+ JavaScript code called when ajax request triggered when displayed date range is changed has finished. Following data will be available in
+ context:
+
+ - startDate - selection start date
+ - endDate - selection end date
+ - request - ajax request
+ - data - data returned by ajax request
+
+
+ null
+
+
+ onviewdisplay
+ java.lang.String
+
+ JavaScript code called when the schedule loads and every time a different date-range is displayed. Following data will be available in context:
+
+ - view - object representing current view
+
+
+ null
+
+
+ styleClass
+ java.lang.String
+
+ null
+
+
+
+ itemMoveListener
+ javax.faces.el.MethodBinding
+ boolean
+
+
+
+ itemResizeListener
+ javax.faces.el.MethodBinding
+
+
+
+ itemSelectListener
+ javax.faces.el.MethodBinding
+
+
+
+ viewChangeListener
+ javax.faces.el.MethodBinding
+
+
+
+ dateRangeChangeListener
+ javax.faces.el.MethodBinding
+
+
+
+ dateRangeSelectListener
+ javax.faces.el.MethodBinding
+
+
+
+ dateSelectListener
+ javax.faces.el.MethodBinding
+
+
+
+ &listeners;
+
diff --git a/ui/schedule/src/main/config/component/scheduleAgendaDayView.xml b/ui/schedule/src/main/config/component/scheduleAgendaDayView.xml
new file mode 100644
index 0000000..a57d760
--- /dev/null
+++ b/ui/schedule/src/main/config/component/scheduleAgendaDayView.xml
@@ -0,0 +1,28 @@
+
+
+ ]
+ >
+
+
+ org.richfaces.ScheduleAgendaDayView
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlScheduleAgendaDayView
+ org.richfaces.component.UIScheduleAgendaDayView
+
+
+
+
+ scheduleAgendaDayView
+ org.richfaces.taglib.ScheduleAgendaDayViewTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &ui_component_attributes;
+ &commonViewAttributes;
+
+
diff --git a/ui/schedule/src/main/config/component/scheduleAgendaWeekView.xml b/ui/schedule/src/main/config/component/scheduleAgendaWeekView.xml
new file mode 100644
index 0000000..06fa991
--- /dev/null
+++ b/ui/schedule/src/main/config/component/scheduleAgendaWeekView.xml
@@ -0,0 +1,28 @@
+
+
+ ]
+ >
+
+
+ org.richfaces.ScheduleAgendaWeekView
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlScheduleAgendaWeekView
+ org.richfaces.component.UIScheduleAgendaWeekView
+
+
+
+
+ scheduleAgendaWeekView
+ org.richfaces.taglib.ScheduleAgendaWeekViewTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &ui_component_attributes;
+ &commonViewAttributes;
+
+
diff --git a/ui/schedule/src/main/config/component/scheduleBasicDayView.xml b/ui/schedule/src/main/config/component/scheduleBasicDayView.xml
new file mode 100644
index 0000000..04f813f
--- /dev/null
+++ b/ui/schedule/src/main/config/component/scheduleBasicDayView.xml
@@ -0,0 +1,28 @@
+
+
+ ]
+ >
+
+
+ org.richfaces.ScheduleBasicDayView
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlScheduleBasicDayView
+ org.richfaces.component.UIScheduleBasicDayView
+
+
+
+
+ scheduleBasicDayView
+ org.richfaces.taglib.ScheduleBasicDayViewTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &ui_component_attributes;
+ &commonViewAttributes;
+
+
diff --git a/ui/schedule/src/main/config/component/scheduleBasicWeekView.xml b/ui/schedule/src/main/config/component/scheduleBasicWeekView.xml
new file mode 100644
index 0000000..5ed9c16
--- /dev/null
+++ b/ui/schedule/src/main/config/component/scheduleBasicWeekView.xml
@@ -0,0 +1,28 @@
+
+
+ ]
+ >
+
+
+ org.richfaces.ScheduleBasicWeekView
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlScheduleBasicWeekView
+ org.richfaces.component.UIScheduleBasicWeekView
+
+
+
+
+ scheduleBasicWeekView
+ org.richfaces.taglib.ScheduleBasicWeekViewTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &ui_component_attributes;
+ &commonViewAttributes;
+
+
diff --git a/ui/schedule/src/main/config/component/scheduleItem.xml b/ui/schedule/src/main/config/component/scheduleItem.xml
new file mode 100644
index 0000000..84a0996
--- /dev/null
+++ b/ui/schedule/src/main/config/component/scheduleItem.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+ org.richfaces.ScheduleItem
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlScheduleItem
+ org.richfaces.component.UIScheduleItem
+
+
+
+
+ scheduleItem
+ org.richfaces.taglib.ScheduleItemTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &ui_component_attributes;
+
+ styleClass
+ java.lang.String
+
+
+ null
+
+
+ startDate
+ java.util.Date
+
+
+
+
+ endDate
+ java.util.Date
+
+
+
+
+ eventId
+ java.lang.String
+
+
+
+
+ title
+ java.lang.String
+
+
+
+
+ allDay
+ java.lang.Boolean
+
+
+ null
+
+
+ url
+ java.lang.String
+ null
+
+
+ editable
+ java.lang.Boolean
+ null
+
+
+
+ data
+ java.lang.Object
+ null
+
+
+
diff --git a/ui/schedule/src/main/config/component/scheduleMonthView.xml b/ui/schedule/src/main/config/component/scheduleMonthView.xml
new file mode 100644
index 0000000..15c999c
--- /dev/null
+++ b/ui/schedule/src/main/config/component/scheduleMonthView.xml
@@ -0,0 +1,56 @@
+
+
+ ]
+ >
+
+
+ org.richfaces.ScheduleMonthView
+ org.richfaces.Schedule
+ org.richfaces.component.html.HtmlScheduleMonthView
+ org.richfaces.component.UIScheduleMonthView
+
+
+
+
+ scheduleMonthView
+ org.richfaces.taglib.ScheduleMonthViewTag
+
+ org.ajax4jsf.webapp.taglib.HtmlComponentTagBase
+
+
+ &ui_component_attributes;
+ &commonViewAttributes;
+
+ weekMode
+ java.lang.String
+
+ Determines the number of weeks displayed in a month view. Also determines each week's height.
+ Available options:
+
+ -
+ fixed
+ - The calendar will always be 6 weeks tall. The height will always be the same, as determined by
+ height, contentHeight, or aspectRatio.
+
+ -
+ liquid
+ - The calendar will have either 4, 5, or 6 weeks, depending on the month. The height of the
+ weeks will stretch to fill the available height, as determined by height, contentHeight, or
+ aspectRatio.
+
+ -
+ variable
+ - The calendar will have either 4, 5, or 6 weeks, depending on the month. Each week will have
+ the same constant height, meaning the calendar’s height will change month-to-month.
+
+
+ default: 'fixed'
+
+ null
+
+
+
diff --git a/ui/schedule/src/main/java/org/richfaces/component/README b/ui/schedule/src/main/java/org/richfaces/component/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ui/schedule/src/main/java/org/richfaces/component/README
diff --git a/ui/schedule/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java b/ui/schedule/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java
new file mode 100644
index 0000000..d539fe2
--- /dev/null
+++ b/ui/schedule/src/main/java/org/richfaces/component/ScheduleCommonViewAttributes.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+ * Interface with common attributes of all view components.
+ * Saves some lines in UISchedule...View classes.
+ *
+ * @author Bernard Labno
+ */
+public interface ScheduleCommonViewAttributes {
+// -------------------------- OTHER METHODS --------------------------
+
+ public String getColumnFormat();
+
+ public Double getDragOpacity();
+
+ public String getTimeFormat();
+
+ public String getTitleFormat();
+
+ public void setColumnFormat(String format);
+
+ public void setDragOpacity(Double dragOpacity);
+
+ public void setTimeFormat(String format);
+
+ public void setTitleFormat(String format);
+}
diff --git a/ui/schedule/src/main/java/org/richfaces/component/UISchedule.java b/ui/schedule/src/main/java/org/richfaces/component/UISchedule.java
new file mode 100644
index 0000000..c746136
--- /dev/null
+++ b/ui/schedule/src/main/java/org/richfaces/component/UISchedule.java
@@ -0,0 +1,809 @@
+package org.richfaces.component;
+
+import org.ajax4jsf.component.AjaxActionComponent;
+import org.ajax4jsf.component.AjaxComponent;
+import org.ajax4jsf.context.AjaxContext;
+import org.ajax4jsf.event.AjaxEvent;
+import org.ajax4jsf.model.DataVisitor;
+import org.ajax4jsf.model.ExtendedDataModel;
+import org.ajax4jsf.renderkit.RendererUtils;
+import org.richfaces.component.event.*;
+import org.richfaces.component.model.DateRange;
+
+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.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public abstract class UISchedule extends UIComponentBase implements ScheduleCommonViewAttributes, ScheduleListenerEventsProducer, AjaxComponent {
+// ------------------------------ FIELDS ------------------------------
+
+ public static final String COMPONENT_FAMILY = "org.richfaces.Schedule";
+
+ public static final String COMPONENT_TYPE = "org.richfaces.Schedule";
+
+ /**
+ * Values of switchType attribute
+ */
+ public static final String SWITCH_TYPE_AJAX = "ajax";
+
+ public static final String SWITCH_TYPE_CLIENT = "client";
+
+ public static final String SWITCH_TYPE_SERVER = "server";
+
+ public static final String VIEW_AGENDA_DAY = "agendaDay";
+
+ public static final String VIEW_AGENDA_WEEK = "agendaWeek";
+
+ public static final String VIEW_BASIC_DAY = "basicDay";
+
+ public static final String VIEW_BASIC_WEEK = "basicWeek";
+
+ /**
+ * Values of view attribute.
+ */
+ public static final String VIEW_MONTH = "month";
+
+ /**
+ * Values of weekMode attribute.
+ */
+ public static final String WEEK_MODE_FIXED = "fixed";
+
+ public static final String WEEK_MODE_LIQUID = "liquid";
+
+ public static final String WEEK_MODE_VARIABLE = "variable";
+
+ public static final boolean DEFAULT_ALL_DAY_DEFAULT = true;
+
+ public static final boolean DEFAULT_ALL_DAY_SLOT = true;
+
+ public static final double DEFAULT_ASPECT_RATIO = 1.35;
+
+ public static final String DEFAULT_AXIS_FORMAT = "h(:mm)tt";
+
+ public static final boolean DEFAULT_DISABLE_DRAGGING = false;
+
+ public static final boolean DEFAULT_DISABLE_RESIZING = false;
+
+ public static final double DEFAULT_DRAG_OPACITY = .3;
+
+ public static final int DEFAULT_DRAG_REVERT_DURATION = 500;
+
+ public static final boolean DEFAULT_EDITABLE = false;
+
+ public static final int DEFAULT_EVENT_MINUTES = 120;
+
+ public static final int DEFAULT_FIRST_DAY = Calendar.SUNDAY;
+
+ public static final int DEFAULT_FIRST_HOUR = 6;
+
+ public static final String DEFAULT_MAX_TIME = "24";
+
+ public static final String DEFAULT_MIN_TIME = "0";
+
+ public static final boolean DEFAULT_RTL = false;
+
+ public static final boolean DEFAULT_SELECTABLE = false;
+
+ public static final boolean DEFAULT_SELECT_HELPER = false;
+
+ public static final boolean DEFAULT_SHOW_WEEKENDS = true;
+
+ public static final int DEFAULT_SLOT_MINUTES = 30;
+
+ public static final String DEFAULT_SWITCH_TYPE = SWITCH_TYPE_AJAX;
+
+ public static final boolean DEFAULT_UNSELECT_AUTO = true;
+
+ public static final String DEFAULT_UNSELECT_CANCEL = "";
+
+ public static final String DEFAULT_VIEW = VIEW_MONTH;
+
+ public static final String DEFAULT_WEEK_MODE = WEEK_MODE_FIXED;
+
+ private DataModel model;
+
+// -------------------------- STATIC METHODS --------------------------
+
+ public static int getFirstDay(UISchedule schedule) {
+ Integer firstDay = schedule.getFirstDay();
+ return firstDay == null ? UISchedule.DEFAULT_FIRST_DAY : firstDay;
+ }
+
+ public static Date getFirstDisplayedDay(UISchedule schedule) {
+ Calendar calendar = Calendar.getInstance();
+ Date date = schedule.getDate();
+ if (date != null) {
+ calendar.setTime(date);
+ }
+ int firstDayOfWeek = getFirstDay(schedule);
+ calendar.setFirstDayOfWeek(firstDayOfWeek);
+ String view = getView(schedule);
+ boolean showWeekends = isShowWeekends(schedule);
+ if (VIEW_MONTH.equals(view)) {
+ calendar.set(Calendar.DATE, 1);
+ if (!showWeekends) {
+ int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
+ if (dayOfWeek == Calendar.SUNDAY) {
+ calendar.add(Calendar.DATE, 1);
+ } else if (dayOfWeek == Calendar.SATURDAY) {
+ calendar.add(Calendar.DATE, 2);
+ }
+ }
+ if (!showWeekends && firstDayOfWeek == Calendar.SUNDAY) {
+ firstDayOfWeek++;
+ }
+ /**
+ * Following 1 line is a fix to what i believe is a bug of java.util.Calendar
+ */
+ calendar.get(Calendar.DAY_OF_WEEK);
+ calendar.set(Calendar.DAY_OF_WEEK, firstDayOfWeek);
+ return calendar.getTime();
+ } else if (VIEW_AGENDA_WEEK.equals(view) || VIEW_BASIC_WEEK.equals(view)) {
+ calendar.set(Calendar.DAY_OF_WEEK, firstDayOfWeek);
+ if (!showWeekends) {
+ int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
+ if (dayOfWeek == Calendar.SUNDAY) {
+ calendar.add(Calendar.DATE, 1);
+ } else if (dayOfWeek == Calendar.SATURDAY) {
+ calendar.add(Calendar.DATE, 2);
+ }
+ }
+ return calendar.getTime();
+ } else if (VIEW_AGENDA_DAY.equals(view) || VIEW_BASIC_DAY.equals(view)) {
+ return calendar.getTime();
+ } else {
+ throw new IllegalStateException("Invalid view attribute: " + view);
+ }
+ }
+
+ public static Date getLastDisplayedDate(UISchedule schedule) {
+ Calendar calendar = Calendar.getInstance();
+ int firstDayOfWeek = getFirstDay(schedule);
+ String view = getView(schedule);
+ boolean showWeekends = isShowWeekends(schedule);
+ if (VIEW_MONTH.equals(view)) {
+ if (WEEK_MODE_FIXED.equals(getWeekMode(schedule))) {
+ calendar.setTime(getFirstDisplayedDay(schedule));
+ calendar.add(Calendar.DAY_OF_YEAR, 42);
+ } else {
+ Date date = schedule.getDate();
+ if (date != null) {
+ calendar.setTime(date);
+ }
+
+ if (!showWeekends && firstDayOfWeek == Calendar.SUNDAY) {
+ firstDayOfWeek++;
+ }
+ calendar.setFirstDayOfWeek(firstDayOfWeek);
+ calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
+ int dayOfWeek = firstDayOfWeek + 6;
+ if (dayOfWeek > Calendar.SATURDAY) {
+ dayOfWeek -= 7;
+ }
+ /**
+ * Following 1 line is a fix to what i believe is a bug of java.util.Calendar
+ */
+ calendar.get(Calendar.DAY_OF_WEEK);
+ calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
+ calendar.add(Calendar.DATE, 1);
+ }
+ return calendar.getTime();
+ } else if (VIEW_AGENDA_WEEK.equals(view) || VIEW_BASIC_WEEK.equals(view)) {
+ calendar.setFirstDayOfWeek(firstDayOfWeek);
+ calendar.setTime(getFirstDisplayedDay(schedule));
+ calendar.add(Calendar.DATE, 7);
+ if (!showWeekends) {
+ int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
+ if (dayOfWeek - 1 == Calendar.SUNDAY) {
+ calendar.add(Calendar.DATE, -2);
+ } else if (dayOfWeek - 1 == Calendar.SATURDAY) {
+ calendar.add(Calendar.DATE, -1);
+ }
+ }
+ return calendar.getTime();
+ } else if (VIEW_AGENDA_DAY.equals(view) || VIEW_BASIC_DAY.equals(view)) {
+ calendar.setTime(getFirstDisplayedDay(schedule));
+ calendar.add(Calendar.DATE, 1);
+ return calendar.getTime();
+ } else {
+ throw new IllegalStateException("Invalid view attribute: " + view);
+ }
+ }
+
+ public static String getView(UISchedule schedule) {
+ String view = schedule.getView();
+ return view == null ? UISchedule.DEFAULT_VIEW : view;
+ }
+
+ public static String getWeekMode(UISchedule schedule) {
+ String weekMode = schedule.getWeekMode();
+ return weekMode == null ? UISchedule.DEFAULT_WEEK_MODE : weekMode;
+ }
+
+ /**
+ * Here go static methods for getting value or default value of attributes.
+ */
+ /**
+ * @param schedule
+ * @return
+ */
+ public static boolean isShowWeekends(UISchedule schedule) {
+ Boolean showWeekends = schedule.getShowWeekends();
+ return showWeekends == null ? UISchedule.DEFAULT_SHOW_WEEKENDS : schedule.getShowWeekends();
+ }
+
+// ------------------------ INTERFACE METHODS ------------------------
+
+
+// --------------------- Interface ScheduleListenerEventsProducer ---------------------
+
+ public void addItemSelectListener(ScheduleItemSelectListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeItemSelectListener(ScheduleItemSelectListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleItemSelectListener[] getItemSelectListeners() {
+ return (ScheduleItemSelectListener[]) getFacesListeners(ScheduleItemSelectListener.class);
+ }
+
+ public void addItemMoveListener(ScheduleItemMoveListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeItemMoveListener(ScheduleItemMoveListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleItemMoveListener[] getItemMoveListeners() {
+ return (ScheduleItemMoveListener[]) getFacesListeners(ScheduleItemMoveListener.class);
+ }
+
+ public void addItemResizeListener(ScheduleItemResizeListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeItemResizeListener(ScheduleItemResizeListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleItemResizeListener[] getItemResizeListeners() {
+ return (ScheduleItemResizeListener[]) getFacesListeners(ScheduleItemResizeListener.class);
+ }
+
+ public void addViewChangeListener(ScheduleViewChangeListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeViewChangeListener(ScheduleViewChangeListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleViewChangeListener[] getViewChangeListeners() {
+ return (ScheduleViewChangeListener[]) getFacesListeners(ScheduleViewChangeListener.class);
+ }
+
+ public void addDateRangeChangeListener(ScheduleDateRangeChangeListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeDateRangeChangeListener(ScheduleDateRangeChangeListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleDateRangeChangeListener[] getDateRangeChangeListeners() {
+ return (ScheduleDateRangeChangeListener[]) getFacesListeners(ScheduleDateRangeChangeListener.class);
+ }
+
+ public void addDateRangeSelectListener(ScheduleDateRangeSelectListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeDateRangeSelectListener(ScheduleDateRangeSelectListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleDateRangeSelectListener[] getDateRangeSelectListeners() {
+ return (ScheduleDateRangeSelectListener[]) getFacesListeners(ScheduleDateRangeSelectListener.class);
+ }
+
+ public void addDateSelectListener(ScheduleDateSelectListener listener) {
+ addFacesListener(listener);
+ }
+
+ public void removeDateSelectListener(ScheduleDateSelectListener listener) {
+ removeFacesListener(listener);
+ }
+
+ public ScheduleDateSelectListener[] getDateSelectListeners() {
+ return (ScheduleDateSelectListener[]) getFacesListeners(ScheduleDateSelectListener.class);
+ }
+
+// -------------------------- OTHER METHODS --------------------------
+
+ /**
+ * React on various events.
+ * Vetoable events are first broadcasted to listeners bound via EL to
+ * component attribtues and then if no veto is raised then to the rest of
+ * listeners.
+ * In case of non vetoable events the order of broadcast is reverse.
+ * Vetoable events are: ScheduleItemMoveEvent, ScheduleItemResizeEvent
+ * Non-vetoable events: ScheduleDateRangeChangeEvent, ScheduleItemSelectEvent,
+ * ScheduleViewChangeEvent, ScheduleDateSelectEvent,
+ * ScheduleDateRangeSelectEvent
+ * In case of ScheduleDateRangeChangeEvent new items are returned
+ * via response data map of ajaxContext.
+ * In case of ScheduleItemMoveEvent and ScheduleItemResizeEvent, the
+ * decision if veto was raised is sent back to client via response data map
+ * of ajaxContext as boolean.
+ *
+ * @param event broadcasted event
+ * @throws AbortProcessingException if broadcasting of particular event
+ * should stop
+ */
+ @Override
+ public void broadcast(FacesEvent event) throws AbortProcessingException {
+ if (event instanceof ScheduleDateRangeChangeEvent) {
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ ScheduleDateRangeChangeEvent calendarAjaxEvent = (ScheduleDateRangeChangeEvent) event;
+ FacesContext facesContext = getFacesContext();
+ AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext);
+ MethodBinding expression = getDateRangeChangeListener();
+ if (expression != null) {
+ expression.invoke(facesContext, new Object[]{event});
+ }
+ try {
+ ajaxContext.getResponseDataMap().put("_ajax:scheduleData", getScheduleData(calendarAjaxEvent.getStartDate(), calendarAjaxEvent.getEndDate()));
+ } catch (IOException ex) {
+ getFacesContext().getExternalContext().log("Cannot get schedule data", ex);
+ }
+ } else if (event instanceof ScheduleItemMoveEvent) {
+ FacesContext facesContext = getFacesContext();
+ AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext);
+ MethodBinding expression = getItemMoveListener();
+ boolean allow = true;
+ if (expression != null) {
+ Object result = expression.invoke(facesContext, new Object[]{event});
+ allow = ((Boolean) result);
+ }
+ ajaxContext.getResponseDataMap().put("_ajax:scheduleData", allow);
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ } else if (event instanceof ScheduleItemResizeEvent) {
+ FacesContext facesContext = getFacesContext();
+ AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext);
+ MethodBinding expression = getItemResizeListener();
+ boolean allow = true;
+ if (expression != null) {
+ Object result = expression.invoke(facesContext, new Object[]{event});
+ allow = ((Boolean) result);
+ }
+ ajaxContext.getResponseDataMap().put("_ajax:scheduleData", allow);
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ } else if (event instanceof ScheduleItemSelectEvent) {
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ FacesContext facesContext = getFacesContext();
+ MethodBinding expression = getItemSelectListener();
+ if (expression != null) {
+ expression.invoke(facesContext, new Object[]{event});
+ }
+ } else if (event instanceof ScheduleViewChangeEvent) {
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ FacesContext facesContext = getFacesContext();
+ MethodBinding expression = getViewChangeListener();
+ if (expression != null) {
+ expression.invoke(facesContext, new Object[]{event});
+ }
+ } else if (event instanceof ScheduleDateSelectEvent) {
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ FacesContext facesContext = getFacesContext();
+ MethodBinding expression = getDateSelectListener();
+ if (expression != null) {
+ expression.invoke(facesContext, new Object[]{event});
+ }
+ } else if (event instanceof ScheduleDateRangeSelectEvent) {
+ super.broadcast(event);
+ new AjaxEvent(this).queue();
+ FacesContext facesContext = getFacesContext();
+ MethodBinding expression = getDateRangeSelectListener();
+ if (expression != null) {
+ expression.invoke(facesContext, new Object[]{event});
+ }
+ } else if (event instanceof AjaxEvent) {
+ FacesContext context = getFacesContext();
+ // complete re-Render fields. AjaxEvent deliver before render
+ // response.
+ AjaxContext.getCurrentInstance(context).addRegionsFromComponent(this);
+ // Put data for send in response
+ Object data = getData();
+ AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
+ if (null != data) {
+ ajaxContext.setResponseData(data);
+ }
+ String focus = getFocus();
+ if (null != focus) {
+ // search for component in tree.
+ // XXX - use more pourful search, as in h:outputLabel
+ // component.
+ UIComponent focusComponent = RendererUtils.getInstance().
+ findComponentFor(this, focus);
+ if (null != focusComponent) {
+ focus = focusComponent.getClientId(context);
+ }
+ ajaxContext.getResponseDataMap().put(AjaxActionComponent.FOCUS_DATA_ID, focus);
+ }
+ ajaxContext.setOncomplete(getOncomplete());
+ } else {
+ super.broadcast(event);
+ }
+ }
+
+ public abstract Boolean getAllDayByDefault();
+
+ public abstract Boolean getAllDaySlot();
+
+ public abstract String getAllDayText();
+
+ public abstract Double getAspectRatio();
+
+ public abstract String getAxisFormat();
+
+ public abstract Integer getContentHeight();
+
+ public abstract Date getDate();
+
+ public abstract MethodBinding getDateRangeChangeListener();
+
+ public abstract MethodBinding getDateRangeSelectListener();
+
+ public abstract MethodBinding getDateSelectListener();
+
+ public abstract Integer getDefaultEventMinutes();
+
+ public abstract Boolean getDisableDragging();
+
+ public abstract Boolean getDisableResizing();
+
+ public abstract Integer getDragRevertDuration();
+
+ public abstract Boolean getEditable();
+
+ public abstract Integer getFirstDay();
+
+ public abstract Integer getFirstHour();
+
+ public abstract String getHeaderCenter();
+
+ public abstract String getHeaderLeft();
+
+ public abstract String getHeaderRight();
+
+ public abstract Integer getHeight();
+
+ public abstract Boolean getIsRTL();
+
+ public abstract MethodBinding getItemMoveListener();
+
+ public abstract MethodBinding getItemResizeListener();
+
+ public abstract MethodBinding getItemSelectListener();
+
+ public abstract String getMaxTime();
+
+ public abstract String getMinTime();
+
+ public abstract String getOnbeforedaterangeselect();
+
+ public abstract String getOnbeforedateselect();
+
+ public abstract String getOnbeforeitemdrop();
+
+ public abstract String getOnbeforeitemresize();
+
+ public abstract String getOnbeforeitemselect();
+
+ public abstract String getOndaterangechange();
+
+ public abstract String getOndaterangeselect();
+
+ public abstract String getOndateselect();
+
+ public abstract String getOnitemdragstart();
+
+ public abstract String getOnitemdragstop();
+
+ public abstract String getOnitemdrop();
+
+ public abstract String getOnitemmouseout();
+
+ public abstract String getOnitemmouseover();
+
+ public abstract String getOnitemresize();
+
+ public abstract String getOnitemresizestart();
+
+ public abstract String getOnitemresizestop();
+
+ public abstract String getOnitemselect();
+
+ public abstract String getOnviewchange();
+
+ public abstract String getOnviewdisplay();
+
+ /**
+ * Range is [startDate;endDate), which means that start date is inclusive
+ * and end date is exclusive.
+ *
+ * @param startDate
+ * @param endDate
+ * @return
+ * @throws IOException
+ */
+ public List