1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.facelets;
21
22 import org.apache.myfaces.tobago.component.Attributes;
23 import org.apache.myfaces.tobago.component.ClientBehaviors;
24 import org.apache.myfaces.tobago.internal.behavior.EventBehavior;
25 import org.apache.myfaces.tobago.internal.component.AbstractUIEvent;
26
27 import javax.el.MethodExpression;
28 import javax.faces.component.PartialStateHolder;
29 import javax.faces.component.UIComponent;
30 import javax.faces.component.behavior.ClientBehaviorHolder;
31 import javax.faces.context.FacesContext;
32 import javax.faces.event.AbortProcessingException;
33 import javax.faces.event.AjaxBehaviorEvent;
34 import javax.faces.event.AjaxBehaviorListener;
35 import javax.faces.view.BehaviorHolderAttachedObjectHandler;
36 import javax.faces.view.facelets.ComponentConfig;
37 import javax.faces.view.facelets.ComponentHandler;
38 import javax.faces.view.facelets.FaceletContext;
39 import javax.faces.view.facelets.TagAttribute;
40 import javax.faces.view.facelets.TagAttributeException;
41 import javax.faces.view.facelets.TagException;
42 import java.io.IOException;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class EventHandler extends TobagoComponentHandler implements BehaviorHolderAttachedObjectHandler {
70
71 public static final Class<?>[] AJAX_BEHAVIOR_LISTENER_SIG = new Class<?>[]{AjaxBehaviorEvent.class};
72
73 private final TagAttribute event;
74
75
76
77 public EventHandler(final ComponentConfig config) {
78 super(config);
79 event = getAttribute(Attributes.event.getName());
80 }
81
82 @Override
83 public void apply(final FaceletContext ctx, final UIComponent parent)
84 throws IOException {
85
86 super.apply(ctx, parent);
87
88
89 if (!ComponentHandler.isNew(parent)) {
90 return;
91 }
92 if (parent instanceof ClientBehaviorHolder) {
93
94 applyAttachedObject(ctx.getFacesContext(), parent);
95
96
97
98
99
100
101
102
103
104
105
106 } else {
107 throw new TagException(this.tag,
108 "Parent is not composite component or of type ClientBehaviorHolder, type is: "
109 + parent);
110 }
111 }
112
113
114
115
116
117 @Override
118 public String getEventName() {
119 if (event == null) {
120 return null;
121 } else {
122 return event.getValue();
123 }
124 }
125
126
127
128
129
130
131
132
133
134 @Override
135 public void applyAttachedObject(final FacesContext context, final UIComponent parent) {
136
137 final FaceletContext faceletContext = (FaceletContext) context
138 .getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
139
140 final ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) parent;
141 final UIComponent lastChild = parent.getChildren().stream().skip(parent.getChildCount() - 1)
142 .findFirst().orElse(null);
143 final AbstractUIEvent abstractUIEvent = lastChild instanceof AbstractUIEvent ? (AbstractUIEvent) lastChild : null;
144
145 if (abstractUIEvent != null) {
146 String eventName = getEventName();
147 if (eventName == null) {
148 eventName = clientBehaviorHolder.getDefaultEventName();
149 if (eventName == null) {
150 throw new TagAttributeException(event, "eventName could not be defined for f:ajax tag with no wrap mode.");
151 }
152 } else if (!clientBehaviorHolder.getEventNames().contains(eventName)) {
153 throw new TagAttributeException(event, "event it is not a valid eventName defined for this component");
154 }
155
156 final EventBehavior eventBehavior = createBehavior(context);
157 eventBehavior.setFor(abstractUIEvent.getId());
158
159 clientBehaviorHolder.addClientBehavior(eventName, eventBehavior);
160 }
161 }
162
163 protected EventBehavior createBehavior(final FacesContext context) {
164 return (EventBehavior) context.getApplication().createBehavior(EventBehavior.BEHAVIOR_ID);
165 }
166
167 @Override
168 public void onComponentCreated(
169 final FaceletContext faceletContext, final UIComponent component, final UIComponent parent) {
170 super.onComponentCreated(faceletContext, component, parent);
171
172 final AbstractUIEvent uiEvent = (AbstractUIEvent) component;
173 if (uiEvent.getEvent() == null) {
174 final ClientBehaviorHolder holder = (ClientBehaviorHolder) parent;
175 uiEvent.setEvent(ClientBehaviors.valueOf(holder.getDefaultEventName()));
176 }
177 }
178
179
180
181
182
183
184 @Override
185 public String getFor() {
186 return null;
187 }
188
189
190
191
192 public static final class AjaxBehaviorListenerImpl implements
193 AjaxBehaviorListener, PartialStateHolder {
194 private MethodExpression expression;
195 private boolean transientBoolean;
196 private boolean initialStateMarked;
197
198 public AjaxBehaviorListenerImpl() {
199 }
200
201 public AjaxBehaviorListenerImpl(final MethodExpression expr) {
202 expression = expr;
203 }
204
205 @Override
206 public void processAjaxBehavior(final AjaxBehaviorEvent event)
207 throws AbortProcessingException {
208 expression.invoke(FacesContext.getCurrentInstance().getELContext(),
209 new Object[]{event});
210 }
211
212 @Override
213 public boolean isTransient() {
214 return transientBoolean;
215 }
216
217 @Override
218 public void restoreState(final FacesContext context, final Object state) {
219 if (state == null) {
220 return;
221 }
222 expression = (MethodExpression) state;
223 }
224
225 @Override
226 public Object saveState(final FacesContext context) {
227 if (initialStateMarked()) {
228 return null;
229 }
230 return expression;
231 }
232
233 @Override
234 public void setTransient(final boolean newTransientValue) {
235 transientBoolean = newTransientValue;
236 }
237
238 @Override
239 public void clearInitialState() {
240 initialStateMarked = false;
241 }
242
243 @Override
244 public boolean initialStateMarked() {
245 return initialStateMarked;
246 }
247
248 @Override
249 public void markInitialState() {
250 initialStateMarked = true;
251 }
252 }
253 }