Package com.liferay.faces.alloy.component.accordion

Source Code of com.liferay.faces.alloy.component.accordion.AccordionRenderer

/**
* Copyright (c) 2000-2014 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.faces.alloy.component.accordion;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;

import com.liferay.faces.alloy.component.tab.Tab;
import com.liferay.faces.alloy.component.tab.TabCollapseEvent;
import com.liferay.faces.alloy.component.tab.TabExpandEvent;
import com.liferay.faces.alloy.component.tab.TabUtil;
import com.liferay.faces.alloy.renderkit.AlloyRendererUtil;
import com.liferay.faces.util.component.ComponentUtil;
import com.liferay.faces.util.component.Styleable;
import com.liferay.faces.util.helper.IntegerHelper;
import com.liferay.faces.util.lang.StringPool;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;
import com.liferay.faces.util.render.RendererUtil;


/**
* @author  Vernon Singleton
*/
//J-
@FacesRenderer(componentFamily = Accordion.COMPONENT_FAMILY, rendererType = Accordion.RENDERER_TYPE)
@ResourceDependencies(
  {
    @ResourceDependency(library = "liferay-faces-alloy", name = "alloy.css"),
    @ResourceDependency(library = "liferay-faces-alloy", name = "alloy.js"),
    @ResourceDependency(library = "liferay-faces-reslib", name = "build/aui-css/css/bootstrap.min.css"),
    @ResourceDependency(library = "liferay-faces-reslib", name = "build/aui/aui-min.js"),
    @ResourceDependency(library = "liferay-faces-reslib", name = "liferay.js")
  }
)
//J+
public class AccordionRenderer extends AccordionRendererBase {

  // Private Constants
  private static final String ANIMATED = "animated";
  private static final String CONTAINER = "container";
  private static final String CONTENT_COLLAPSED_CLASSES = "content toggler-content toggler-content-collapsed";
  private static final String CONTENT_EXPANDED_CLASSES = "content toggler-content toggler-content-expanded";
  private static final String DOT_CONTENT = ".content";
  private static final String DOT_HEADER = ".header";
  private static final String HEADER_COLLAPSED_CLASSES = "header toggler-header toggler-header-collapsed";
  private static final String HEADER_EXPANDED_CLASSES = "header toggler-header toggler-header-expanded";
  private static final String EXPANDED = "expanded";
  private static final String EXPANDED_CHANGE = "expandedChange";

  // Logger
  private static final Logger logger = LoggerFactory.getLogger(AccordionRenderer.class);

  @Override
  public void decodeClientState(FacesContext facesContext, UIComponent uiComponent) {

    // Apply the client-side state of the selected index.
    Accordion accordion = (Accordion) uiComponent;
    String hiddenFieldName = accordion.getClientId(facesContext) + SELECTED_INDEX;
    Map<String, String> requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
    String selectedIndex = requestParameterMap.get(hiddenFieldName);

    if (selectedIndex != null) {
      accordion.setSelectedIndex(IntegerHelper.toInteger(selectedIndex, -1));
    }
  }

  @Override
  public void encodeChildren(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // If iteration should take place over a data-model, then
    Accordion accordion = (Accordion) uiComponent;
    Integer selectedIndex = accordion.getSelectedIndex();
    Object value = accordion.getValue();
    String var = accordion.getVar();
    boolean iterateOverDataModel = ((value != null) && (var != null));
    ResponseWriter responseWriter = facesContext.getResponseWriter();

    if (iterateOverDataModel) {

      // Get the first child tab and use it as a prototype tab.
      Tab prototypeChildTab = TabUtil.getFirstChildTab(accordion);

      if (prototypeChildTab != null) {

        // Encode a header <div> and content <div> for each row in the data-model.
        int rowCount = accordion.getRowCount();

        for (int i = 0; i < rowCount; i++) {
          accordion.setRowIndex(i);

          boolean selected = ((selectedIndex != null) && (i == selectedIndex));
          encodeHeader(facesContext, responseWriter, uiComponent, prototypeChildTab, selected);
          encodeContent(facesContext, responseWriter, uiComponent, prototypeChildTab, selected);
        }

        accordion.setRowIndex(-1);
      }
      else {
        logger.warn("Unable to iterate because alloy:accordion does not have an alloy:tab child element.");
      }
    }

    // Otherwise, encode a header <div> and content <div> for each child tab of the specified accordion.
    else {
      List<UIComponent> children = uiComponent.getChildren();
      int childCount = children.size();

      for (int i = 0; i < childCount; i++) {

        UIComponent child = children.get(i);

        if ((child instanceof Tab) && child.isRendered()) {
          Tab childTab = (Tab) child;
          boolean selected = ((selectedIndex != null) && (i == selectedIndex));
          encodeHeader(facesContext, responseWriter, uiComponent, childTab, selected);
          encodeContent(facesContext, responseWriter, uiComponent, childTab, selected);
        }
        else {
          logger.warn("Unable to render child element of alloy:accordion since it is not alloy:tab");
        }
      }
    }

    accordion.setRowIndex(-1);
  }

  @Override
  public void encodeClientState(FacesContext facesContext, ResponseWriter responseWriter, UIComponent uiComponent)
    throws IOException {

    // Encode the hidden field that contains the client-side state of the selected index.
    Accordion accordion = (Accordion) uiComponent;
    responseWriter.startElement(StringPool.INPUT, accordion);

    String hiddenFieldName = accordion.getClientId(facesContext) + SELECTED_INDEX;
    responseWriter.writeAttribute(StringPool.ID, hiddenFieldName, null);
    responseWriter.writeAttribute(StringPool.NAME, hiddenFieldName, null);
    responseWriter.writeAttribute(StringPool.TYPE, StringPool.HIDDEN, null);
    responseWriter.writeAttribute(StringPool.VALUE, accordion.getSelectedIndex(), null);
    responseWriter.endElement(StringPool.INPUT);
  }

  @Override
  public void encodeJavaScriptCustom(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // The outermost div was initially styled with "display:none;" in order to prevent blinking when Alloy's
    // JavaScript attempts to hide the div. At this point in JavaScript execution, Alloy is done manipulating the
    // DOM and it is necessary to set the style back to "display:block;" so that the component will be visible.
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.write(AlloyRendererUtil.A_DOT_ONE);
    responseWriter.write(StringPool.OPEN_PARENTHESIS);
    responseWriter.write(StringPool.APOSTROPHE);

    String clientId = uiComponent.getClientId(facesContext);
    String escapedClientId = StringPool.POUND + RendererUtil.escapeClientId(clientId);
    responseWriter.write(escapedClientId);
    responseWriter.write("')._node['style'].display='block';");

    // Encode a script that will handle the client-side state of the selected tab index, as well as submitting
    // Ajax requests to support server-side events.
    Accordion accordion = (Accordion) uiComponent;

    // var clientVarName = Liferay.component('clientKey');
    String clientVarName = ComponentUtil.getClientVarName(facesContext, accordion);
    String clientKey = accordion.getClientKey();

    if (clientKey == null) {
      clientKey = clientVarName;
    }

    // var clientVar = Liferay.component('clientVarName');
    encodeLiferayComponentVar(responseWriter, clientVarName, clientKey);

    // var toggglers = clientVarName.items;
    responseWriter.write(StringPool.VAR);
    responseWriter.write(StringPool.SPACE);
    responseWriter.write("togglers");
    responseWriter.write(StringPool.EQUAL);
    responseWriter.write(clientVarName);
    responseWriter.write(StringPool.PERIOD);
    responseWriter.write("items");
    responseWriter.write(StringPool.SEMICOLON);

    // var totalTogglers = togglers.length;
    responseWriter.write(StringPool.VAR);
    responseWriter.write(StringPool.SPACE);
    responseWriter.write("totalTogglers");
    responseWriter.write(StringPool.EQUAL);
    responseWriter.write("togglers.length;");

    // for (var i=0; i < totalTogglers ;i++) {
    responseWriter.write("for(var i=0;i<totalTogglers;i++)");
    responseWriter.write(StringPool.OPEN_CURLY_BRACE);

    StringBuffer behaviorCallback = new StringBuffer();

    //J-
    // var eventTabIndex = 0, togglers = j_idt23.items, total = togglers.length, i = 0;
    // for (i = 0; i < total; i++) {
    //     if (togglers[i] == event.target) {
    //       eventTabIndex = i;
    //     }
    // };
    //J+

    behaviorCallback.append("var eventTabIndex=0,togglers=");
    behaviorCallback.append(clientVarName);
    behaviorCallback.append(".items,total=togglers.length,i=0;");
    behaviorCallback.append("for(i=0;i<total;i++){if(togglers[i]==event.target){eventTabIndex=i;}};");

    // var hidden = document.getElementById('clientId:selectedIndex');
    String hiddenFieldId = clientId + SELECTED_INDEX;
    behaviorCallback.append("var hidden=document.getElementById('");
    behaviorCallback.append(hiddenFieldId);
    behaviorCallback.append(StringPool.APOSTROPHE);
    behaviorCallback.append(StringPool.CLOSE_PARENTHESIS);
    behaviorCallback.append(StringPool.SEMICOLON);

    // var prevTabIndex = hidden.value;
    behaviorCallback.append("var prevTabIndex=hidden.value;");

    //J-
    // if (event.newVal) {
    //     hidden.value=eventTabIndex;
    // }
    //     else if (prevTabIndex==eventTabIndex) {
    //       hidden.value='';
    //     }
    // }
    //J+
    behaviorCallback.append(
      "if(event.newVal){hidden.value=eventTabIndex;}else if (prevTabIndex==eventTabIndex){hidden.value='';};");

    Map<String, List<ClientBehavior>> clientBehaviorMap = accordion.getClientBehaviors();
    Collection<String> eventNames = accordion.getEventNames();

    for (String eventName : eventNames) {
      List<ClientBehavior> clientBehaviorsForEvent = clientBehaviorMap.get(eventName);

      if (clientBehaviorsForEvent != null) {

        for (ClientBehavior clientBehavior : clientBehaviorsForEvent) {

          ClientBehaviorContext clientBehaviorContext = ClientBehaviorContext.createClientBehaviorContext(
              facesContext, accordion, eventName, clientId, null);
          String clientBehaviorScript = clientBehavior.getScript(clientBehaviorContext);

          // If <f:ajax event="tabExpanded" /> is specified in the view, then render a script that submits
          // an Ajax request.
          if (TabExpandEvent.TAB_EXPAND.equals(eventName)) {

            //J-
            // if (event.newVal) {
            //     jsf.ajax.request(this, event, {'javax.faces.behavior.event': 'tabExpand'});
            // }
            //J+
            behaviorCallback.append("if(event.newVal)");
            behaviorCallback.append(StringPool.OPEN_CURLY_BRACE);
            behaviorCallback.append(clientBehaviorScript);
            behaviorCallback.append(StringPool.CLOSE_CURLY_BRACE);
          }

          // Similarly, if <f:ajax event="tabCollapsed" /> is specified in the view, then render a script
          // that submits an Ajax request.
          else if (TabCollapseEvent.TAB_COLLAPSE.equals(eventName)) {

            //J-
            // if ((!event.newVal) && (prevTabIndex == eventTabIndex)) {
            //     jsf.ajax.request(this, event, {'javax.faces.behavior.event': 'tabCollapse'});
            // }
            //J+
            behaviorCallback.append("if((!event.newVal)&&(prevTabIndex==eventTabIndex))");
            behaviorCallback.append(StringPool.OPEN_CURLY_BRACE);
            behaviorCallback.append(clientBehaviorScript);
            behaviorCallback.append(StringPool.CLOSE_CURLY_BRACE);
          }
        }
      }
    }

    encodeEventCallback(responseWriter, "togglers[i]", StringPool.AFTER, EXPANDED_CHANGE,
      behaviorCallback.toString());

    responseWriter.write(StringPool.CLOSE_CURLY_BRACE);
  }

  @Override
  public void encodeMarkupBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // Encode the starting <div> element that represents the accordion.
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.startElement(StringPool.DIV, uiComponent);
    responseWriter.writeAttribute(StringPool.ID, uiComponent.getClientId(facesContext), StringPool.ID);
    RendererUtil.encodeStyleable(responseWriter, (Styleable) uiComponent);
  }

  @Override
  public void encodeMarkupEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // Encode the closing </div> element for the accordion.
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.endElement(StringPool.DIV);
  }

  protected void encodeContent(FacesContext facesContext, ResponseWriter responseWriter, UIComponent uiComponent,
    Tab tab, boolean selected) throws IOException {

    // Encode the starting <div> element that represents the specified tab's content.
    responseWriter.startElement(StringPool.DIV, tab);

    // Encode the div's class attribute according to the specified tab's collapsed/expanded state.
    String contentClass = CONTENT_COLLAPSED_CLASSES;

    if (selected) {
      contentClass = CONTENT_EXPANDED_CLASSES;
    }

    // If the specified tab has a contentClass, then append it to the class attribute before encoding.
    String tabContentClass = tab.getContentClass();

    if (tabContentClass != null) {
      contentClass += StringPool.SPACE + tabContentClass;
    }

    responseWriter.writeAttribute(StringPool.CLASS, contentClass, Styleable.STYLE_CLASS);

    // Encode the children of the specified tab as the actual content.
    tab.encodeAll(facesContext);

    // Encode the closing </div> element for the specified tab.
    responseWriter.endElement(StringPool.DIV);
  }

  protected void encodeHeader(FacesContext facesContext, ResponseWriter responseWriter, UIComponent uiComponent,
    Tab tab, boolean selected) throws IOException {

    // Encode the starting <div> element that represents the specified tab's header.
    responseWriter.startElement(StringPool.DIV, tab);

    // Encode the div's class attribute according to the specified tab's collapsed/expanded state.
    String headerClass = HEADER_COLLAPSED_CLASSES;

    if (selected) {
      headerClass = HEADER_EXPANDED_CLASSES;
    }

    // If the specified tab has a headerClass, then append it to the class attribute before encoding.
    String tabHeaderClass = tab.getHeaderClass();

    if (tabHeaderClass != null) {
      headerClass += StringPool.SPACE + tabHeaderClass;
    }

    responseWriter.writeAttribute(StringPool.CLASS, headerClass, Styleable.STYLE_CLASS);

    // If the header facet exists for the specified tab, then encode the header facet.
    UIComponent headerFacet = tab.getFacet(StringPool.HEADER);

    if (headerFacet != null) {
      headerFacet.encodeAll(facesContext);
    }

    // Otherwise, render the label of the specified tab.
    else {
      String headerText = (String) tab.getHeaderText();

      if (headerText != null) {
        responseWriter.write(headerText);
      }
    }

    // Encode the closing </div> element for the specified tab.
    responseWriter.endElement(StringPool.DIV);
  }

  @Override
  protected void encodeHiddenAttributes(FacesContext facesContext, ResponseWriter responseWriter, Accordion accordion,
    boolean first) throws IOException {

    // render: true
    encodeWidgetRender(responseWriter, first);

    // container
    first = false;
    encodeClientId(responseWriter, CONTAINER, accordion.getClientId(facesContext), first);

    // animated
    encodeBoolean(responseWriter, ANIMATED, true, first);

    // closeAllOnExpand
    Boolean multiple = accordion.isMultiple();
    encodeBoolean(responseWriter, CLOSE_ALL_ON_EXPAND, !multiple, first);

    // content
    encodeString(responseWriter, StringPool.CONTENT, DOT_CONTENT, first);

    // header
    encodeString(responseWriter, StringPool.HEADER, DOT_HEADER, first);

    // expanded: false
    encodeBoolean(responseWriter, EXPANDED, false, first);
  }

  @Override
  public boolean getRendersChildren() {
    return true;
  }
}
TOP

Related Classes of com.liferay.faces.alloy.component.accordion.AccordionRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.