org.omnifaces.component.input.ScriptParam Maven / Gradle / Ivy
/*
* Copyright 2020 OmniFaces
*
* 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
*
* https://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.omnifaces.component.input;
import static java.lang.String.format;
import static org.omnifaces.el.ExpressionInspector.getValueReference;
import static org.omnifaces.util.FacesLocal.getRequestParameter;
import static org.omnifaces.util.FacesLocal.getScriptParameters;
import static org.omnifaces.util.Reflection.invokeMethods;
import java.util.HashSet;
import java.util.Set;
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.context.FacesContext;
import org.omnifaces.cdi.PostScriptParam;
import org.omnifaces.util.Faces;
/**
*
* The <o:scriptParam>
is a component that extends the standard <f:viewParam>
* with support for setting results of client-side evaluated JavaScript code in bean.
*
*
Usage
*
* It's similar to the <f:viewParam>
.
*
* <f:metadata>
* <o:scriptParam script="new Date().getTimezoneOffset()" value="#{bean.clientTimeZoneOffset}" />
* <o:scriptParam script="window.screen.width" value="#{bean.clientScreenWidth}" />
* <o:scriptParam script="someFunctionName()" value="#{bean.resultOfSomeFunctionName}" />
* </f:metadata>
*
*
* You can use the render
attribute to declare which components should be updated when a script parameter
* has been set.
*
* <f:metadata>
* <o:scriptParam script="foo()" value="#{bean.resultOfFoo}" render="fooResult" />
* </f:metadata>
* ...
* <h:body>
* ...
* <h:panelGroup id="fooResult">
* <ui:fragment rendered="#{not empty bean.resultOfFoo}">
* The result of foo() script is: #{bean.resultOfFoo}
* </ui:fragment>
* </h:panelGroup>
* ...
* </h:body>
*
*
* Note that as it extends from the standard <f:viewParam>
, its built-in conversion and validation
* functionality is also supported on this component. So, the following is also possible:
*
* <f:metadata>
* <o:scriptParam script="window.navigator" value="#{bean.clientNavigator}" />
* </f:metadata>
*
* With a clientNavigator
being an instance of javax.json.JsonObject
:
*
* private JsonObject clientNavigator;
*
* And this converter:
*
* package com.example;
*
* import java.io.StringReader;
* import javax.faces.component.UIComponent;
* import javax.faces.context.FacesContext;
* import javax.faces.convert.Converter;
* import javax.faces.convert.ConverterException;
* import javax.faces.convert.FacesConverter;
* import javax.json.Json;
* import javax.json.JsonObject;
*
* @FacesConverter(forClass = JsonObject.class)
* public class JsobObjectConverter implements Converter<JsonObject> {
*
* @Override
* public String getAsString(FacesContext context, UIComponent component, JsonObject modelValue) {
* if (modelValue == null) {
* return "";
* }
*
* return modelValue.toString();
* }
*
* @Override
* public JsonObject getAsObject(FacesContext context, UIComponent component, String submittedValue) {
* if (submittedValue == null || submittedValue.isEmpty()) {
* return null;
* }
*
* try {
* return Json.createReader(new StringReader(submittedValue)).readObject();
* }
* catch (Exception e) {
* throw new ConverterException("Not a valid JSON object", e);
* }
* }
* }
*
*
* Events
*
* When the script params have been set, then any method with the {@link PostScriptParam} annotation will be fired:
*
* @PostScriptParam
* public void initScriptParams() {
* // ...
* }
*
*
* This is useful in case you want to preload the model for whatever is rendered by
* <o:scriptParam render>
.
*
* @author Bauke Scholtz
* @since 3.6
* @see OnloadParam
* @see PostScriptParam
* @see Faces#getScriptParameters()
*/
@FacesComponent(ScriptParam.COMPONENT_TYPE)
public class ScriptParam extends OnloadParam {
// Public constants -----------------------------------------------------------------------------------------------
/** The component type, which is {@value org.omnifaces.component.input.ScriptParam#COMPONENT_TYPE}. */
public static final String COMPONENT_TYPE = "org.omnifaces.component.input.ScriptParam";
/** The omnifaces event value, which is {@value org.omnifaces.component.input.ScriptParam#EVENT_VALUE}. */
public static final String EVENT_VALUE = "setScriptParamValues";
// Private constants ----------------------------------------------------------------------------------------------
private static final String SCRIPT_INIT = "OmniFaces.ScriptParam.run('%s', %s)";
private enum PropertyKeys {
SCRIPT;
@Override public String toString() { return name().toLowerCase(); }
}
// Init -----------------------------------------------------------------------------------------------------------
@Override
protected String getInitScript(FacesContext context) {
StringBuilder scripts = new StringBuilder("{");
for (ScriptParam scriptParam : getScriptParameters(context)) {
scripts.append("'").append(scriptParam.getClientId()).append("':").append(scriptParam.getScript()).append(',');
}
scripts.append("}");
return format(SCRIPT_INIT, getClientId(), scripts);
}
// Actions --------------------------------------------------------------------------------------------------------
@Override
protected String getEventValue(FacesContext context) {
return EVENT_VALUE;
}
@Override
protected void decodeAll(FacesContext context) {
Set