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

com.adobe.granite.ui.components.FormData Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2018 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.adobe.granite.ui.components;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Stack;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ValueMap;

/**
 * FormData represents the values of the form.
 *
 * 

* The values are represented as a {@link ValueMap}. The FormData is set at * request scope, where usually it is set by the form component and read by the * field components. *

*/ public class FormData { private static final String ATTR_STACK = FormData.class.getName(); /** * Creates a new FormData representing the given values to the request scope. * * FormData supports nesting. By calling this method, a new FormData is created * and becomes the current context. * * @param request * The request to store the values * @param values * The values of the FormData * @param nameNotFoundMode * The mode when the FormData doesn't have an entry of a certain name * @return The new instance of FormData */ @Nonnull public static FormData push(@Nonnull SlingHttpServletRequest request, @Nonnull ValueMap values, @Nonnull NameNotFoundMode nameNotFoundMode) { Stack stack = getStack(request); if (stack == null) { stack = new Stack<>(); request.setAttribute(ATTR_STACK, stack); } FormData formData = new FormData(values, nameNotFoundMode); stack.push(formData); return formData; } /** * Pops the current FormData. * * @param request * The request storing the values * @return The current FormData * @throws IllegalStateException * When this method is called before * {@link #push(SlingHttpServletRequest, ValueMap, NameNotFoundMode)} */ @SuppressWarnings("null") @Nonnull public static FormData pop(@Nonnull SlingHttpServletRequest request) throws IllegalStateException { Stack stack = getStack(request); if (stack == null || stack.isEmpty()) { throw new IllegalStateException("Pop is called before push"); } return stack.pop(); } /** * Returns the current FormData. * * @param request * The request storing the values * @return The current FormData or {@code null} if there is none */ @CheckForNull public static FormData from(@Nonnull SlingHttpServletRequest request) { Stack stack = getStack(request); if (stack == null || stack.isEmpty()) { return null; } return stack.peek(); } @SuppressWarnings("unchecked") @CheckForNull private static Stack getStack(@Nonnull SlingHttpServletRequest request) { return (Stack) request.getAttribute(ATTR_STACK); } @Nonnull private ValueMap values; @Nonnull private NameNotFoundMode mode; FormData(@Nonnull ValueMap values, @Nonnull NameNotFoundMode mode) { this.values = values; this.mode = mode; } /** * Returns the values. * * @return The values */ @Nonnull public ValueMap getValueMap() { return values; } /** * Returns the mode of the FormData. * * @return The mode */ @Nonnull public NameNotFoundMode getMode() { return mode; } /** * Returns the value for the given name, converted to type T. * *

* In the {@code NameNotFoundMode#CHECK_FRESHNESS} mode, if the given name is * not found and the FormData is fresh, then the given fieldValue is returned. * Otherwise, {@code null} is returned. *

* *

* In the {@code NameNotFoundMode#IGNORE_FRESHNESS} mode, if the given name is * not found, then the given fieldValue is returned. *

* * @param name * The name of the field * @param fieldValue * The value of the field * @param type * The class of the type * @param * The type of the value * @return The value converted to type T, or the given fieldValue, or * {@code null}, depending on the conditions described above. */ @CheckForNull public T get(@Nonnull String name, @CheckForNull T fieldValue, @Nonnull Class type) { if (mode.equals(NameNotFoundMode.IGNORE_FRESHNESS)) { if (fieldValue == null) { return values.get(name, type); } else { return values.get(name, fieldValue); } } if (!values.containsKey(name) && isFresh()) { return fieldValue; } return values.get(name, type); } /** * Returns the value for the given name, converted to type T. * *

* In the {@code NameNotFoundMode#CHECK_FRESHNESS} mode, if the given name is * not found and the FormData is fresh, then the given fieldValue is returned. * Otherwise, the given defaultValue is returned. *

* *

* In the {@code NameNotFoundMode#IGNORE_FRESHNESS} mode, if the given name is * not found, then the given fieldValue is returned. *

* * @param name * The name of the field * @param fieldValue * The value of the field * @param defaultValue * The default value * @param * The type of the value * @return The value converted to type T, or the given fieldValue, or the given * default value, depending on the conditions described above. */ @Nonnull public T get(@Nonnull String name, @Nonnull T fieldValue, @Nonnull T defaultValue) { if (mode.equals(NameNotFoundMode.IGNORE_FRESHNESS)) { return values.get(name, fieldValue); } if (!values.containsKey(name) && isFresh()) { return fieldValue; } return values.get(name, defaultValue); } /** * An overload of {@link #isSelected(String, String, boolean, boolean)} where * {@code forceIgnoreFreshness} parameter is {@code false}. * * @param name * The name of the field * @param value * The value of the field option to compare against * @param isFieldOptionSelected * {@code true} if the field option is selected; {@code false} * otherwise. * * @return Whether the given value is selected or not, or the given * isFieldOptionSelected, depending on the conditions described above. */ public boolean isSelected(@Nonnull String name, @CheckForNull String value, boolean isFieldOptionSelected) { return isSelected(name, value, isFieldOptionSelected, false); } /** * Returns {@code true} if the given value of the field option is selected; * {@code false} otherwise. * *

* In the {@code NameNotFoundMode#CHECK_FRESHNESS} mode, if the given name is * not found and the FormData is fresh, then the given isFieldOptionSelected is * returned, {@code false} otherwise. *

* *

* In the {@code NameNotFoundMode#IGNORE_FRESHNESS} mode, if the given name is * not found, then the given isFieldOptionSelected is returned. *

* * @param name * The name of the field * @param value * The value of the field option to compare against * @param isFieldOptionSelected * {@code true} if the field option is selected; {@code false} * otherwise. * @param forceIgnoreFreshness * {@code true} to force to be {@link NameNotFoundMode#IGNORE_FRESHNESS}; * {@code false} otherwise. * * @return Whether the given value is selected or not, or the given * isFieldOptionSelected, depending on the conditions described above. */ public boolean isSelected(@Nonnull String name, @CheckForNull String value, boolean isFieldOptionSelected, boolean forceIgnoreFreshness) { String[] formValues = values.get(name, String[].class); if (formValues != null) { if (value == null) { return false; } return Arrays.asList(formValues).contains(value); } if (mode.equals(NameNotFoundMode.IGNORE_FRESHNESS) || forceIgnoreFreshness) { return isFieldOptionSelected; } boolean isFresh = isFresh(); if (value != null && value.isEmpty() && !isFresh) { // GRANITE-4320: Handle a scenario when the value is an empty string // When it is an empty string, SlingPostServlet will remove the JCR property // (`contentValue` will be null). // Hence even though the `contentValue` is null, if the `value` is an empty // string we have to return true to select it. return true; } return isFresh ? isFieldOptionSelected : false; } private boolean isFresh() { // https://git.corp.adobe.com/CQ/ui-classic/blob/2152156d25759e3d8605b7e4f4598b43ffcd1f3b/content/jcr_root/libs/cq/ui/widgets/source/ext/override/widgets/form/Field.js#L121-L137 Calendar created = values.get("jcr:created", Calendar.class); Calendar lastModified = values.get("jcr:lastModified", Calendar.class); if (lastModified == null) { lastModified = values.get("cq:lastModified", Calendar.class); } if (created == null && lastModified == null) { return true; } if (created == null || lastModified == null) { return false; } long diff = lastModified.getTimeInMillis() - created.getTimeInMillis(); return diff >= 0 && diff <= 5; } /** * The mode on how to handle the scenario when the FormData doesn't have an * entry of a certain name. */ public static enum NameNotFoundMode { /** * When the FormData doesn't have an entry of a certain name, if the FormData is * fresh then the value configured at the field is used instead, otherwise (it's * not fresh) the value is taken from the FormData as usual, which will return * {@code null}. * *

* The form is fresh when {@code jcr:created} property has equal value to the * last modified property's value (taken from either {@code jcr:lastModified} or * {@code cq:lastModified}). * * If either created or last modified date is not available, it is not * considered as fresh. *

* *

* This mode is usually used for Authoring dialogs. *

*/ CHECK_FRESHNESS, /** * When the FormData doesn't have an entry of a certain name, then the value * configured at the field is used instead. */ IGNORE_FRESHNESS } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy