001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.ajax;
018:
019: import org.apache.wicket.IClusterable;
020: import org.apache.wicket.markup.ComponentTag;
021: import org.apache.wicket.util.string.Strings;
022: import org.apache.wicket.util.time.Duration;
023:
024: /**
025: * An ajax behavior that is attached to a certain client-side (usually
026: * javascript) event, such as onClick, onChange, onKeyDown, etc.
027: * <p>
028: * Example:
029: *
030: * <pre>
031: * WebMarkupContainer div=new WebMarkupContainer(...);
032: * div.setOutputMarkupId(true);
033: * div.add(new AjaxEventBehavior("onclick") {
034: * protected void onEvent(AjaxRequestTarget target) {
035: * System.out.println("ajax here!");
036: * }
037: * }
038: * </pre>
039: *
040: * This behavior will be linked to the onclick javascript event of the div
041: * WebMarkupContainer represents, and so anytime a user clicks this div the
042: * {@link #onEvent(AjaxRequestTarget)} of the behavior is invoked.
043: *
044: * @since 1.2
045: *
046: * @author Igor Vaynberg (ivaynberg)
047: */
048: public abstract class AjaxEventBehavior extends
049: AbstractDefaultAjaxBehavior {
050: private static long sequence = 0;
051:
052: private static final long serialVersionUID = 1L;
053:
054: private final String event;
055:
056: private ThrottlingSettings throttlingSettings;
057:
058: /**
059: * Construct.
060: *
061: * @param event
062: * event this behavior will be attached to
063: */
064: public AjaxEventBehavior(final String event) {
065: if (Strings.isEmpty(event)) {
066: throw new IllegalArgumentException(
067: "argument [event] cannot be null or empty");
068: }
069:
070: onCheckEvent(event);
071:
072: this .event = event;
073: }
074:
075: /**
076: * Sets the throttle delay for this behavior. Throttled behaviors only
077: * execute once withing the given delay even though they are triggered
078: * multiple times.
079: * <p>
080: * For example, this is useful when attaching this behavior to the
081: * onkeypress event. It is not desirable to have an ajax call made every
082: * time the user types so we throttle that call to a desirable delay, such
083: * as once per second. This gives us a near real time ability to provide
084: * feedback without overloading the server with ajax calls.
085: *
086: *
087: * @param throttleDelay
088: * throttle delay
089: * @return this for chaining
090: */
091: public final AjaxEventBehavior setThrottleDelay(
092: Duration throttleDelay) {
093: throttlingSettings = new ThrottlingSettings(
094: "th" + (++sequence), throttleDelay);
095: return this ;
096: }
097:
098: /**
099: *
100: * @see org.apache.wicket.behavior.AbstractAjaxBehavior#onComponentTag(org.apache.wicket.markup.ComponentTag)
101: */
102: protected void onComponentTag(final ComponentTag tag) {
103: super .onComponentTag(tag);
104:
105: // only add the event handler when the component is enabled.
106: if (this .getComponent().isEnabled()) {
107: tag.put(event, getEventHandler());
108: }
109: }
110:
111: /**
112: *
113: * @return event handler
114: */
115: protected CharSequence getEventHandler() {
116: CharSequence handler = getCallbackScript();
117: if (event.equalsIgnoreCase("href")) {
118: handler = "javascript:" + handler;
119: }
120: return handler;
121: }
122:
123: protected CharSequence generateCallbackScript(
124: CharSequence partialCall) {
125: CharSequence script = super .generateCallbackScript(partialCall);
126: final ThrottlingSettings ts = throttlingSettings;
127:
128: if (ts != null) {
129: script = AbstractDefaultAjaxBehavior.throttleScript(script,
130: ts.getId(), ts.getDelay());
131: }
132: return script;
133: }
134:
135: /**
136: *
137: * @param event
138: */
139: protected void onCheckEvent(final String event) {
140: }
141:
142: /**
143: *
144: * @return event
145: */
146: public final String getEvent() {
147: return event;
148: }
149:
150: /**
151: *
152: * @see org.apache.wicket.ajax.AbstractDefaultAjaxBehavior#respond(org.apache.wicket.ajax.AjaxRequestTarget)
153: */
154: protected final void respond(final AjaxRequestTarget target) {
155: onEvent(target);
156: }
157:
158: /**
159: * Listener method for the ajax event
160: *
161: * @param target
162: */
163: protected abstract void onEvent(final AjaxRequestTarget target);
164:
165: /**
166: * Class to keep track of throttling settings.
167: *
168: * @author ivaynberg
169: */
170: private static class ThrottlingSettings implements IClusterable {
171: private static final long serialVersionUID = 1L;
172:
173: private final Duration delay;
174: private final String id;
175:
176: /**
177: * Construct.
178: *
179: * @param id
180: * throttle id
181: * @param delay
182: * throttle delay
183: */
184: public ThrottlingSettings(final String id, final Duration delay) {
185: super ();
186: this .id = id;
187: this .delay = delay;
188: }
189:
190: /**
191: * @return throttle delay
192: */
193: public Duration getDelay() {
194: return delay;
195: }
196:
197: /**
198: * @return throttle id
199: */
200: public String getId() {
201: return id;
202: }
203:
204: }
205: }
|