wicket.contrib.input.events.InputBehavior.java Source code

Java tutorial

Introduction

Here is the source code for wicket.contrib.input.events.InputBehavior.java

Source

/*
 * ==============================================================================
 * Licensed 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 wicket.contrib.input.events;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.OnLoadHeaderItem;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.util.template.PackageTextTemplate;
import org.apache.wicket.util.template.TextTemplate;
import org.apache.wicket.util.value.IValueMap;

import wicket.contrib.input.events.key.KeyHookOn;
import wicket.contrib.input.events.key.KeyType;

/**
 * Add this to your button, link whatever to create a shortcut key..
 * 
 * <strong>WARNING:this behavior uses a special script for calling
 * window.onload</strong>
 * 
 * @author Nino Martinez (nino.martinez.wael *at* gmail *dot* com remember no
 *         stars)
 * 
 */
public class InputBehavior extends Behavior {

    private static final long serialVersionUID = 1L;
    private final ResourceReference SHORTCUTS_JAVASCRIPT = new PackageResourceReference(InputBehavior.class,
            "shortcut.js");
    private final KeyType[] keyCombo;
    private EventType eventType;

    private boolean autoHook = false;
    private boolean linkUnbound = false;
    private final TextTemplate shortcutJs = new PackageTextTemplate(InputBehavior.class,
            "wicket-contrib-input-behavior.js");
    private final TextTemplate shortcutJsAutoHook = new PackageTextTemplate(InputBehavior.class,
            "wicket-contrib-input-behavior-autohook.js");

    private final TextTemplate shortcutJsAutoHookLink = new PackageTextTemplate(InputBehavior.class,
            "wicket-contrib-input-behavior-autohook-link.js");

    public InputBehavior(KeyType[] keyCombo, EventType eventType) {
        this.keyCombo = keyCombo;
        this.eventType = eventType;
    }

    /**
     * if using auto hook be sure to add this behavior last, otherwise it might
     * not pickup the event.. Also it will only hook up to the last event if
     * more are present (use other constructor to specify manually)
     * 
     * 
     * Note on keyCombo
     * 
     * The shortcut keys should be specified in this format ...
     * Modifier[+Modifier..]+Key
     * 
     * Meaning that you should specify in this order, modifier keys first like
     * 'ctrl' and then normal keys like 'a'
     * 
     * @param keyCombo
     * @param autoHook
     */
    public InputBehavior(KeyType[] keyCombo) {
        this.keyCombo = keyCombo;
        autoHook = true;
    }

    /** The target component. */
    private Component component;

    @Override
    public void bind(Component component) {
        super.bind(component);
        this.component = component;
        component.setOutputMarkupId(true);

    }

    /**
     * Gets the escaped DOM id that the input will get attached to. All non word
     * characters (\W) will be removed from the string.
     * 
     * @return The DOM id of the input - same as the component's markup id}
     */
    protected final String getEscapedComponentMarkupId() {
        return component.getMarkupId().replaceAll("\\W", "");

    }

    @Override
    public void renderHead(Component c, IHeaderResponse response) {
        super.renderHead(c, response);
        response.render(JavaScriptHeaderItem.forReference(SHORTCUTS_JAVASCRIPT));
        if (!autoHook) {
            response.render(OnLoadHeaderItem.forScript(generateString(shortcutJs)));
        }
    }

    @Override
    public void onComponentTag(Component component, ComponentTag tag) {
        super.onComponentTag(component, tag);
        if (autoHook) {
            IValueMap attribs = tag.getAttributes();
            for (String attrib : attribs.keySet()) {

                List<EventType> list = Arrays.asList(EventType.values());

                for (EventType e : list) {
                    if (attrib.toLowerCase().contains(e.toString().toLowerCase())) {
                        eventType = e;

                    }
                }
            }
            // Try to bind to link so shortcut will work. Should only be done if
            // no other handlers were found
            if (component instanceof Link && eventType == null) {
                linkUnbound = true;
                return;
            }

        }
    }

    @Override
    public void afterRender(Component component) {
        // TODO Auto-generated method stub
        super.afterRender(component);
        if (autoHook) {
            Response response = component.getResponse();
            if (linkUnbound) {
                response.write(generateString(shortcutJsAutoHookLink));
            } else {
                response.write(generateString(shortcutJsAutoHook));
            }

        }
    }

    private String generateString(TextTemplate textTemplate) {
        // variables for the initialization script
        HashMap<String, Object> variables = new HashMap<String, Object>();
        String widgetId = getEscapedComponentMarkupId();

        StringBuilder keyComboString = new StringBuilder();

        boolean first = true;
        for (KeyType keyType : keyCombo) {
            if (first) {
                first = false;
            } else {

                keyComboString.append('+');
            }
            keyComboString.append(keyType.getKeyCode());
        }
        if (eventType != null) {
            variables.put("event", eventType.toString());
        }
        variables.put("keys", keyComboString.toString());
        variables.put("wicketComponentId", widgetId);

        variables.put("disable_in_input", getDisable_in_input().toString());
        variables.put("type", getType().toString());
        variables.put("propagate", getPropagate().toString());
        variables.put("target", getTarget());

        textTemplate.interpolate(variables);
        return textTemplate.asString();

    }

    /**
     * If this is set to true, keyboard capture will be disabled in input and
     * textarea fields. If these elements have focus, the keyboard shortcut will
     * not work. This is very useful for single key shortcuts. Default: false
     * 
     * @return
     */
    protected Boolean getDisable_in_input() {
        return false;
    }

    /**
     * The event type - can be 'keydown','keyup','keypress'. Default: 'keydown'
     * 
     * @return
     */
    protected KeyHookOn getType() {
        return KeyHookOn.keydown;
    }

    /**
     * Should the command be passed onto the browser afterwards?
     * 
     * @return
     */
    protected Boolean getPropagate() {
        return false;
    }

    /**
     * target - DOM Node The element that should be watched for the keyboard
     * event. Default : document
     * 
     * @return
     */
    protected String getTarget() {
        return "document";
    }

}