5 Replies Latest reply on Aug 13, 2018 9:59 AM by Arun Patidar

    Inject a dialog tab using Filter in AEM Touch dialog

    shehjadk29320987

      Hi All,

       

      I am trying to inject one Tab in all my dialog dynamically using Filters. I have done something similar for classic dialog using some similar concept as described in this blog Programmatically adding tabs to CQ dialogs - WE ARE INSIDE Earlier this manipulation was easy as it was on the JSON.

       

      I am very close to make it work, I am able to add the tab and also it is loading properly, only thing I am struggling with is tab does not load the value in dialog even though it is saved properly into JCR. I am using AEM 6.3 with SP1 along with CFP

       

      Below is my high level technical approach

       

      http://localhost:4502/mnt/override/apps/web/platform/components/content/productgrids/_cq_d ialog.html/content/mysite/en-us/main/home/home/jcr:content/rootResource/productgrids?resou rceType=web%2Fplatform%2Fcomponents%2Fcontent%2Fproductgrids&_=1533867264646

       

      AEM makes call to this path which loads the dialog HTML, I am manipulating the HTML to insert the dialog related HTML in my filter

       

      Also as AEM touch dialogs are now component so most of the execution starts from this JSP

      /libs/cq/gui/components/authoring/dialog/dialog.jsp, below lines of code is where it loads the component and creates html for it.

       

      ResourceWrapper hideOnEditWrapper = new FilteringResourceWrapper(resource.getChild("content"));

                          ResourceWrapper contentWrapper = new WCMFilteringResourceWrapper(hideOnEditWrapper, data, sling.getService(ExpressionResolver.class), slingRequest);

                          // Standard dialog

                          cmp.include(contentWrapper, new Tag(contentAttrs));

       

      Below is my Filter code, I did tried adding service ranking hoping that whatever filter or service add value to rest of the dialog element will add it to my dialog fields also but did not got any luck, please suggest how I can load these values in dialog other possible hacky ways I can think of is to write JS listener to load data in my tab or do more nasty manipulation in java to add value also.

       

      package com.mysite.platform.core.filters;
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.io.StringWriter;
      import java.util.Map;
      
      
      import javax.servlet.Filter;
      import javax.servlet.FilterChain;
      import javax.servlet.FilterConfig;
      import javax.servlet.ServletException;
      import javax.servlet.ServletOutputStream;
      import javax.servlet.ServletRequest;
      import javax.servlet.ServletResponse;
      import javax.servlet.http.HttpServletResponse;
      import javax.servlet.http.HttpServletResponseWrapper;
      
      
      import org.apache.commons.lang.StringUtils;
      import org.apache.sling.api.SlingHttpServletRequest;
      import org.apache.sling.api.SlingHttpServletResponse;
      import org.apache.sling.commons.osgi.PropertiesUtil;
      import org.apache.sling.engine.EngineConstants;
      import org.osgi.service.component.annotations.Activate;
      import org.osgi.service.component.annotations.Component;
      import org.osgi.service.component.annotations.ConfigurationPolicy;
      import org.osgi.service.component.annotations.Deactivate;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      
      import com.mysite.platform.core.beans.ComponentDialogFilterBean;
      
      
      @Component(
              service = { Filter.class },
              immediate = true,
              configurationPolicy = ConfigurationPolicy.REQUIRE,
              property = { EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
                      "label=Component Dialog Filter", "description=Filter to add conditional configuration tab to a component dialog", "service.ranking=2147483647" })
      public class ComponentDialogFilter implements Filter
      {
          private Logger LOG = LoggerFactory.getLogger(ComponentDialogFilter.class);
          
          private ComponentDialogFilterBean componentDialogFilterBean;
          
          //Default values of OSGI service configuration
          private static String [] CC_EXCLUDE_PATHS = {"/content/experience-fragments"};
          private static String CC_HEAD_HTML_TAG_VALUE = "<a class=\"coral-TabPanel-tab\" href=\"#\" data-toggle=\"tab\">cc</a>";
          private static String CC_BODY_HTML_TAG_VALUE = "<section class=\"coral-TabPanel-pane coral-FixedColumn\"><div class=\"coral-FixedColumn-column\"><div><div class=\"coral-Form-fieldwrapper\"><label class=\"coral-Form-fieldlabel\">CC</label><input class=\"coral-Form-field\" type=\"text\" name=\"./cc\" data-foundation-validation=\"\" data-validation=\"\" is=\"coral-textfield\"></div></div></div></section>";
         
          @Override
          public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                  throws IOException, ServletException
          {
              if (request instanceof SlingHttpServletRequest && response instanceof SlingHttpServletResponse)
              {
                  final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
                  LOG.debug("Request path processed *** " + slingRequest.getRequestURI());
                  if (slingRequest.getRequestURI().contains("/_cq_dialog.html/"))
                  {
                      final HttpServletResponse servletResponse = (HttpServletResponse) response;
                      final StringHttpServletResponseWrapper responseWrapper = new StringHttpServletResponseWrapper(
                              servletResponse);
                      String dialogHTML = getDialogHTML(slingRequest, responseWrapper);
      
      
                      response.setContentType("text/html");
                      response.getWriter().write(addTabtoDialog(dialogHTML));
                  } else
                  {
                      // Not a request related to dialog continue without any modification
                      chain.doFilter(request, response);
                  }
              } else
              {
                  // Not a SlingHttpServletRequest/Response, so ignore.
                  chain.doFilter(request, response);
              }
          }
      
      
          /**
           * Gets the dialog HTML.
           * 
           * @param slingRequest The sling request.
           * @param responseWrapper The response wrapper.
           * @return The dialog HTML
           * @throws IOException Error while adapting to a page.
           * @throws ServletException Error while adapting to a page.
           */
          private String getDialogHTML(final SlingHttpServletRequest slingRequest,
                  final StringHttpServletResponseWrapper responseWrapper) throws ServletException, IOException
          {
              slingRequest.getRequestDispatcher(slingRequest.getRequestURI()).include(slingRequest, responseWrapper);
              return responseWrapper.toString();
          }
      
      
          /**
           * Add a new tab item to dialog HTML.
           * 
           * @param dialogHTML The dialog HTML.
           * @return The merged JSON.
           */
          private String addTabtoDialog(final String dialogHTML)
          {
              if (StringUtils.isNotEmpty(dialogHTML))
              {
                  String newDialogHTML = dialogHTML;
                  newDialogHTML = insertHTMLTag(newDialogHTML, componentDialogFilterBean.getCcHeadHTMLTagValue(), "</nav>",
                          1);
                  newDialogHTML = insertHTMLTag(newDialogHTML, componentDialogFilterBean.getCcBodyHTMLTagValue(),
                          "</section>", 2);
      
      
                  LOG.trace("Final modified dialog output *** " + newDialogHTML);
      
      
                  return newDialogHTML;
              }
      
      
              // In case of failure return original dialog
              return dialogHTML;
          }
      
      
          /**
           * Inserts tag in the correct location.
           * 
           * @param dialogHTML The dialog HTML.
           * @param insertedHTML The inserted HTML.
           * @param delimiterTag The delimiter tag.
           * @param order The order.
           * 
           * @return dialog output HTML.
           */
          private String insertHTMLTag(final String dialogHTML, final String insertedHTML, final String delimiterTag,
                  int order)
          {
              StringBuilder output = new StringBuilder();
              String beforeOutput = StringUtils.substringBeforeLast(dialogHTML, delimiterTag);
              String afterOutput = StringUtils.substringAfterLast(dialogHTML, delimiterTag);
      
      
              // If tag is inserted inside the delimiterTag
              if (order == 1)
              {
                  return output.append(beforeOutput).append(insertedHTML).append(delimiterTag).append(afterOutput).toString();
              } else
              {
                  return output.append(beforeOutput).append(delimiterTag).append(insertedHTML).append(afterOutput).toString();
              }
          }
      
      
          /**
           * Activate.
           *
           * @param properties The OSGi configuration properties.
           */
          @Activate
          protected final void activate(final Map<String, Object> properties)
          {
              // Initialize and keep the configuration in memory on start of component
              setConfigProperties(properties);
              LOG.debug("Component dialog filter is enabled ***");
          }
      
      
          /**
           * Deactivate method.
           */
          @Deactivate
          public void deactivate()
          {
              this.componentDialogFilterBean = null;
              LOG.debug("Component dialog filter is disabled ***");
          }
      
      
          /**
           * Setting service configuration.
           * 
           * @param properties
           */
          private void setConfigProperties(Map<String, Object> properties)
          {
              this.componentDialogFilterBean = new ComponentDialogFilterBean();
              this.componentDialogFilterBean.setEnabled(PropertiesUtil.toBoolean(properties.get("enabled"), true));
              this.componentDialogFilterBean
                      .setExcludePaths(PropertiesUtil.toStringArray(properties.get("templatePath"), CC_EXCLUDE_PATHS));
              this.componentDialogFilterBean.setCcHeadHTMLTagValue(
                      PropertiesUtil.toString(properties.get("ccHeadTagValue"), CC_HEAD_HTML_TAG_VALUE));
              this.componentDialogFilterBean.setCcBodyHTMLTagValue(
                      PropertiesUtil.toString(properties.get("ccBodyTagValue"), CC_BODY_HTML_TAG_VALUE));
      
      
              LOG.debug("ComponentDialogFilter: {}", this.componentDialogFilterBean);
          }
      
      
          @Override
          public void init(FilterConfig filterConfig) throws ServletException
          {
              LOG.debug("Component dialog filter is initialized ***");
          }
      
      
          @Override
          public void destroy()
          {
              LOG.debug("Component dialog filter is Destroyed *** ");
          }
      
      
          /**
           * Response wrapper class.
           */
          class StringHttpServletResponseWrapper extends HttpServletResponseWrapper
          {
              private final transient StringWriter stringWriter = new StringWriter();
      
      
              /**
               * Constructor.
               * 
               * @param response The response.
               */
              public StringHttpServletResponseWrapper(final HttpServletResponse response)
              {
                  super(response);
              }
      
      
              /**
               * Gets the writer.
               * 
               * @return The print writer.
               * @throws IOException Error while adapting to a page.
               */
              @Override
              public final PrintWriter getWriter() throws IOException
              {
                  return new PrintWriter(stringWriter);
              }
      
      
              /**
               * Gets the output stream.
               * 
               * @return The output stream.
               * @throws IOException Error while adapting to a page.
               */
              @Override
              public final ServletOutputStream getOutputStream() throws IOException
              {
                  return super.getOutputStream();
              }
      
      
              /**
               * Gets the string representation of response.
               * 
               * @return The response string.
               */
              public final String toString()
              {
                  return stringWriter.toString();
              }
          }
      
      
      }