001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Guillaume Renard
018 */
019package org.nuxeo.ecm.platformui.web.form;
020
021import java.io.IOException;
022
023import javax.faces.component.UIComponent;
024import javax.faces.component.html.HtmlForm;
025import javax.faces.context.FacesContext;
026
027import org.apache.commons.lang.StringUtils;
028import org.nuxeo.runtime.api.Framework;
029import org.nuxeo.runtime.services.config.ConfigurationService;
030
031import com.sun.faces.renderkit.html_basic.FormRenderer;
032
033/**
034 * Nuxeo h:form tag renderer override, to include javascript code preventing multiple submissions of the form.
035 *
036 * @since 5.7.3
037 */
038public class NxFormRenderer extends FormRenderer {
039
040    public static final String ENABLE_DOUBLE_CLICK_SHIELD = "nuxeo.jsf.enableDoubleClickShield";
041
042    public static final String ENABLE_DOUBLE_CLICK_ON_ELEMENT = "disableDoubleClickShield";
043
044    public static final String DOUBLE_CLICK_SHIELD_CSS_CLASS_FLAG = "doubleClickShielded";
045
046    protected static boolean isDoubleShieldEnabled() {
047        ConfigurationService configurationService = Framework.getService(ConfigurationService.class);
048        return !configurationService.isBooleanPropertyFalse(ENABLE_DOUBLE_CLICK_SHIELD);
049    }
050
051    protected static boolean dcDisabledOnElement(UIComponent component) {
052        if (component != null) {
053            Object dcDisabledOnElement = component.getAttributes().get(ENABLE_DOUBLE_CLICK_ON_ELEMENT);
054            if (dcDisabledOnElement != null) {
055                if (dcDisabledOnElement instanceof String) {
056                    return Boolean.TRUE.equals(Boolean.valueOf((String) dcDisabledOnElement));
057                } else if (dcDisabledOnElement instanceof Boolean) {
058                    return Boolean.TRUE.equals(dcDisabledOnElement);
059                }
060            }
061        } else {
062            return true;
063        }
064        return false;
065    }
066
067    protected static boolean containsDoubleClickShieldClass(final String styleClass) {
068        if (styleClass != null) {
069            String[] split = styleClass.split(" ");
070            for (String s : split) {
071                if (s.equals(DOUBLE_CLICK_SHIELD_CSS_CLASS_FLAG)) {
072                    return true;
073                }
074            }
075        }
076        return false;
077    }
078
079    @Override
080    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
081
082        if (component.isRendered() && isDoubleShieldEnabled()) {
083            if (!dcDisabledOnElement(component)) {
084                String styleClass = (String) ((HtmlForm) component).getAttributes().get("styleClass");
085                if (StringUtils.isBlank(styleClass)) {
086                    ((HtmlForm) component).setStyleClass(DOUBLE_CLICK_SHIELD_CSS_CLASS_FLAG);
087                } else {
088                    if (!containsDoubleClickShieldClass(styleClass)) {
089                        ((HtmlForm) component).setStyleClass(styleClass + " " + DOUBLE_CLICK_SHIELD_CSS_CLASS_FLAG);
090                    }
091                }
092            }
093        }
094
095        super.encodeBegin(context, component);
096
097    }
098
099}