/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.wicket.ajax;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.lang.Checks;
import org.apache.wicket.util.string.Strings;
import org.danekja.java.util.function.serializable.SerializableConsumer;
/**
* An ajax behavior that is attached to a certain client-side (usually javascript) event, such as
* click, change, keydown, etc.
* <p>
* Example:
*
* <pre>
* WebMarkupContainer div=new WebMarkupContainer(...);
* div.setOutputMarkupId(true);
* div.add(new AjaxEventBehavior("click") {
* protected void onEvent(AjaxRequestTarget target) {
* System.out.println("ajax here!");
* }
* }
* </pre>
*
* This behavior will be linked to the <em>click</em> javascript event of the div WebMarkupContainer
* represents, and so anytime a user clicks this div the {@link #onEvent(AjaxRequestTarget)} of the
* behavior is invoked.
*
* <p>
* <strong>Note</strong>: {@link #getEvent()} method cuts any <em>on</em> prefix from the given event name(s).
* This is being done for easier migration of applications coming from Wicket 1.5.x where Wicket used
* inline attributes like 'onclick=...'. If the application needs to use custom events with names starting with
* <em>on</em> then {@link #getEvent()} should be overridden.
* </p>
*
* @since 1.2
*
* @author Igor Vaynberg (ivaynberg)
* @see #onEvent(AjaxRequestTarget)
*/
public abstract class AjaxEventBehavior extends AbstractDefaultAjaxBehavior
{
private static final long serialVersionUID = 1L;
private final String event;
/**
* Construct.
*
* @param event
* the event this behavior will be attached to
*/
public AjaxEventBehavior(String event)
{
Args.notEmpty(event, "event");
onCheckEvent(event);
this.event = event;
}
@Override
public void renderHead(final Component component, final IHeaderResponse response)
{
super.renderHead(component, response);
if (component.isEnabledInHierarchy())
{
CharSequence js = getCallbackScript(component);
response.render(OnDomReadyHeaderItem.forScript(js.toString()));
}
}
@Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
super.updateAjaxAttributes(attributes);
String evt = getEvent();
Checks.notEmpty(evt, "getEvent() should return non-empty event name(s)");
attributes.setEventNames(evt);
}
/**
*
* @param event
* the event this behavior will be attached to
* @deprecated Wicket 8 Remove this method for Wicket 8.0.0
*/
@Deprecated
protected void onCheckEvent(final String event)
{
if (event.startsWith("on"))
{
String shortName = event.substring(2);
throw new IllegalArgumentException(
String.format("Since version 6.0.0 Wicket uses JavaScript event registration so there is no need of the leading " +
"'on' in the event name '%s'. Please use just '%s'. Wicket 8.x won't manipulate the provided event " +
"names so the leading 'on' may break your application."
, event, shortName.toLowerCase(Locale.ENGLISH)));
}
}
/**
* @return event
* the event this behavior is attached to
*/
public String getEvent()
{
String[] splitEvents = event.split("\\s+");
List<String> cleanedEvents = new ArrayList<>(splitEvents.length);
for (String evt : splitEvents)
{
if (Strings.isEmpty(evt) == false)
{
cleanedEvents.add(evt);
}
}
return Strings.join(" ", cleanedEvents);
}
@Override
protected final void respond(final AjaxRequestTarget target)
{
onEvent(target);
}
/**
* Listener method for the ajax event
*
* @param target
* the current request handler
*/
protected abstract void onEvent(final AjaxRequestTarget target);
/**
* Creates an {@link AjaxEventBehavior} based on lambda expressions
*
* @param eventName
* the event name
* @param onEvent
* the {@code SerializableConsumer} which accepts the {@link AjaxRequestTarget}
* @return the {@link AjaxEventBehavior}
*/
public static AjaxEventBehavior onEvent(String eventName, SerializableConsumer<AjaxRequestTarget> onEvent)
{
Args.notNull(onEvent, "onEvent");
return new AjaxEventBehavior(eventName)
{
private static final long serialVersionUID = 1L;
@Override
protected void onEvent(AjaxRequestTarget target)
{
onEvent.accept(target);
}
};
}
}