All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.butterfaces.component.html.action.AbstractKeyCodeAction Maven / Gradle / Ivy

There is a newer version: 3.5.0
Show newest version
/**
 * Copyright 2012 Lars Michaelis
 * 
 * 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 org.butterfaces.component.html.action;

import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;
import java.util.logging.Logger;

/**
 * Action is used to set a onKeyPress event on ambient form. A click-event will
 * be invoked on key code action ambient component. Note that not all jsf
 * components support click event.
 * The concrete implementation of this class has to define on which key code the
 * click event will be fired.
 */
public abstract class AbstractKeyCodeAction extends UIComponentBase {

	private static final Logger LOGGER = Logger.getLogger(AbstractKeyCodeAction.class.getName());

	private static final String SCRIPT_ELEMENT = "script";
	private static final String SCRIPT_LANGUAGE_ATTRIBUTE = "language";
	private static final String SCRIPT_LANGUAGE_JAVASCRIPT = "JavaScript";
	private static final String SCRIPT_TYPE_ATTRIBUTE = "type";
	private static final String SCRIPT_TYPE_TEXT_JAVASCRIPT = "text/javascript";

	protected static final String PROPERTY_RENDERED = "rendered";

	public abstract String getListeningKeyCode();

	public abstract String getFormActionMarker();

	@Override
	public String getFamily() {
		return "defaultAction";
	}

	public boolean isRendered() {
		final Object eval = this.getStateHelper().eval(PROPERTY_RENDERED);
		return eval == null ? true : (Boolean) eval;
	}

	public void setRendered(final boolean rendered) {
		this.updateStateHelper(PROPERTY_RENDERED, rendered);
	}

	@Override
	public void encodeEnd(final FacesContext context) throws IOException {
		if (!isRendered()) {
			return;
		}

		final UIComponent actionComponent = this.getParent();
		final String actionComponentId = actionComponent.getClientId(context);
		final UIForm form = getForm(actionComponent);

		if (form == null) {
			LOGGER.warning("AbstractKeyCodeAction does not have an ambient form. Form is required");
		} else {
			markForm(form, this.getClientId(context));

			final ResponseWriter responseWriter = context.getResponseWriter();
			writeActionScript(responseWriter, form, actionComponentId);
		}
	}

	private void writeActionScript(final ResponseWriter responseWriter, final UIForm form,
			final String actionComponentId) throws IOException {
		responseWriter.startElement(SCRIPT_ELEMENT, this);

		responseWriter.writeAttribute(SCRIPT_LANGUAGE_ATTRIBUTE, SCRIPT_LANGUAGE_JAVASCRIPT, SCRIPT_LANGUAGE_ATTRIBUTE);
		responseWriter.writeAttribute(SCRIPT_TYPE_ATTRIBUTE, SCRIPT_TYPE_TEXT_JAVASCRIPT, SCRIPT_TYPE_ATTRIBUTE);

		responseWriter.write(createFunctionCode(form.getClientId(), actionComponentId));

		responseWriter.endElement(SCRIPT_ELEMENT);
	}

	private String createFunctionCode(final String formId, final String actionComponentId) {
		final StringBuilder sb = new StringBuilder();

		// TODO [larmic] check other onkeypress functions

		sb.append("document.forms['" + formId + "'].onkeypress = ");
		sb.append("new Function(\"event\", \"" + createBody(actionComponentId) + "\");");

		return sb.toString();
	}

	private String createBody(final String actionComponentId) {
		final StringBuilder sb = new StringBuilder();

		// IE and FF have different events
		sb.append("if (!event) { event = window.event; }");
		// IE and FF have different source elements
		sb.append("var evt = event.target?event.target:event.srcElement;");
		// check if event is fired by text area
		sb.append("if (evt.tagName.toLowerCase() != 'textarea') {");
		sb.append("{var keycode;");
		sb.append("if (window.event) keycode = window.event.keyCode;");
		sb.append("else if (event) keycode = event.which;");
		sb.append("else return true;");
		sb.append("if (keycode == " + getListeningKeyCode() + ")");
		sb.append("{document.getElementById('" + actionComponentId + "').click();return false; }");
		sb.append("else return true; }");
		sb.append("}");
		sb.append("return true;");

		return sb.toString();
	}

	private void markForm(final UIForm form, final String componentId) {
		if (isFormMarked(form) && !isFormMarkedWithId(form, componentId)) {
			LOGGER.warning("AbstractKeyCodeAction only supports one key event");
		} else {
			form.getAttributes().put(getFormActionMarker(), componentId);
		}
	}

	private boolean isFormMarked(final UIForm form) {
		return form.getAttributes().containsKey(getFormActionMarker());
	}

	private boolean isFormMarkedWithId(final UIForm form, final String componentId) {
		return form.getAttributes().get(getFormActionMarker()).equals(componentId);
	}

	// TODO [larmic] find a better way
	private UIForm getForm(UIComponent component) {
		while (component != null) {
			if (component instanceof UIForm) {
				break;
			}
			component = component.getParent();
		}
		return (UIForm) component;
	}

	private void updateStateHelper(final String propertyName, final Object value) {
		this.getStateHelper().put(propertyName, value);

		final ValueExpression ve = this.getValueExpression(propertyName);

		if (ve != null) {
			ve.setValue(this.getFacesContext().getELContext(), value);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy