/**
* Copyright 2014-2017 Riccardo Massera (TheCoder4.Eu) and Stephan Rauh (http://www.beyondjava.net).
*
* This file is part of BootsFaces.
*
* 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
*
* http://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 net.bootsfaces.component.panel;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import net.bootsfaces.component.ajax.AJAXRenderer;
import net.bootsfaces.render.CoreRenderer;
import net.bootsfaces.render.Responsive;
import net.bootsfaces.render.Tooltip;
/** This class generates the HTML code of <b:panel />. */
@FacesRenderer(componentFamily = "net.bootsfaces.component", rendererType = "net.bootsfaces.component.panel.Panel")
public class PanelRenderer extends CoreRenderer {
/**
* This methods receives and processes input made by the user. More
* specifically, it ckecks whether the user has interacted with the current
* b:panel. The default implementation simply stores the input value in the
* list of submitted values. If the validation checks are passed, the values
* in the <code>submittedValues</code> list are store in the backend bean.
*
* @param context
* the FacesContext.
* @param component
* the current b:panel.
*/
@Override
public void decode(FacesContext context, UIComponent component) {
Panel panel = (Panel) component;
String clientId = panel.getClientId(context);
String jQueryClientID = clientId.replace(":", "_");
// the panel uses two ids to send requests to the server!
new AJAXRenderer().decode(context, component, panel.getClientId(context));
new AJAXRenderer().decode(context, component, jQueryClientID+"content");
String collapseStateId = clientId.replace(":", "_") + "_collapsed";
String submittedValue = (String) context.getExternalContext().getRequestParameterMap().get(collapseStateId);
if (submittedValue != null) {
if (Boolean.valueOf(submittedValue) != panel.isCollapsed())
panel.setCollapsed(Boolean.valueOf(submittedValue));
}
}
/**
* This methods generates the HTML code of the current b:panel.
* <code>encodeBegin</code> generates the start of the component. After the,
* the JSF framework calls <code>encodeChildren()</code> to generate the
* HTML code between the beginning and the end of the component. For
* instance, in the case of a panel component the content of the panel is
* generated by <code>encodeChildren()</code>. After that,
* <code>encodeEnd()</code> is called to generate the rest of the HTML code.
*
* @param context
* the FacesContext.
* @param component
* the current b:panel.
* @throws IOException
* thrown if something goes wrong when writing the HTML code.
*/
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if (!component.isRendered()) {
return;
}
Panel panel = (Panel) component;
ResponseWriter rw = context.getResponseWriter();
String clientId = panel.getClientId();
String jQueryClientID = clientId.replace(":", "_");
boolean isCollapsible = panel.isCollapsible();
String accordionParent = panel.getAccordionParent();
if (isCollapsible && null == accordionParent) {
rw.startElement("div", panel);
rw.writeAttribute("class", ("panel-group" + Responsive.getResponsiveStyleClass(panel, false)).trim(), null);
rw.writeAttribute("id", clientId, "id");
}
String _look = panel.getLook();
String _title = panel.getTitle();
String _titleClass = panel.getTitleClass();
String _styleClass = panel.getStyleClass();
if (null == _styleClass) {
_styleClass = "";
} else {
_styleClass += " ";
}
rw.startElement("div", panel);
if (!(isCollapsible && null == accordionParent)) {
rw.writeAttribute("id", clientId, "id");
}
writeAttribute(rw, "dir", panel.getDir(), "dir");
// render all data-* attributes
renderPassThruAttributes(context, component, null, true);
AJAXRenderer.generateBootsFacesAJAXAndJavaScript(context, panel, rw, false);
Tooltip.generateTooltip(context, panel, rw);
String _style = panel.getStyle();
if (null != _style && _style.length() > 0) {
rw.writeAttribute("style", _style, "style");
}
if (_look != null) {
rw.writeAttribute("class", _styleClass + "panel panel-" + _look, "class");
} else {
rw.writeAttribute("class", _styleClass + "panel panel-default", "class");
}
UIComponent head = panel.getFacet("heading");
if (head != null || _title != null) {
rw.startElement("div", panel);
rw.writeAttribute("class", "panel-heading", "class");
String _titleStyle = panel.getTitleStyle();
if (null != _titleStyle) {
rw.writeAttribute("style", _titleStyle, "style");
}
if (_title != null) {
rw.startElement("h4", panel);
if (_titleClass != null) {
rw.writeAttribute("class", _titleClass, "class");
} else {
rw.writeAttribute("class", "panel-title", "class");
}
if (isCollapsible) {
writeTitleLink(panel, rw, jQueryClientID, accordionParent);
}
rw.writeText(_title, null);
if (isCollapsible) {
rw.endElement("a");
}
rw.endElement("h4");
} else {
if (isCollapsible) {
writeTitleLink(panel, rw, jQueryClientID, accordionParent);
}
head.encodeAll(context);
if (isCollapsible) {
rw.endElement("a");
}
}
rw.endElement("div");
}
rw.startElement("div", panel);
rw.writeAttribute("id", jQueryClientID + "content", null);
writeAttribute(rw, "dir", panel.getDir(), "dir");
String _contentClass = panel.getContentClass();
if (null == _contentClass)
_contentClass = "";
if (isCollapsible) {
_contentClass += " panel-collapse collapse"; // in
if (!panel.isCollapsed())
_contentClass += " in";
}
_contentClass = _contentClass.trim();
if (_contentClass.length() > 0)
rw.writeAttribute("class", _contentClass, "class");
String _contentStyle = panel.getContentStyle();
if (null != _contentStyle && _contentStyle.length() > 0) {
rw.writeAttribute("style", _contentStyle, "style");
}
// create the body
rw.startElement("div", panel);
rw.writeAttribute("class", "panel-body", "class");
if (panel.isContentDisabled()) {
rw.startElement("fieldset", panel);
rw.writeAttribute("disabled", "disabled", "null");
}
}
private void writeTitleLink(Panel panel, ResponseWriter rw, String jQueryClientID, String accordionParent)
throws IOException {
String sclass = "panel-title-link ";
rw.startElement("a", panel);
rw.writeAttribute("data-toggle", "collapse", "null");
rw.writeAttribute("data-target", "#" + jQueryClientID + "content", "null");
String style = "display:block;";
if (!panel.isShowCollapseLink()) {
style += "outline:none";
} else {
style += "outline:none;text-decoration:underline;";
}
rw.writeAttribute("style", style, "style"); //let the anchor
rw.writeAttribute("href", "javascript:;", "null");
if (panel.isCollapsed()) {
sclass += " collapsed";
}
rw.writeAttribute("class", sclass, null);
if(null != accordionParent) {
rw.writeAttribute("data-parent", "#" + accordionParent, null);
}
}
/**
* This methods generates the HTML code of the current b:panel.
* <code>encodeBegin</code> generates the start of the component. After the,
* the JSF framework calls <code>encodeChildren()</code> to generate the
* HTML code between the beginning and the end of the component. For
* instance, in the case of a panel component the content of the panel is
* generated by <code>encodeChildren()</code>. After that,
* <code>encodeEnd()</code> is called to generate the rest of the HTML code.
*
* @param context
* the FacesContext.
* @param component
* the current b:panel.
* @throws IOException
* thrown if something goes wrong when writing the HTML code.
*/
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
if (!component.isRendered()) {
return;
}
Panel panel = (Panel) component;
ResponseWriter rw = context.getResponseWriter();
if (panel.isContentDisabled()) {
rw.endElement("fieldset");
}
String clientId = panel.getClientId();
rw.endElement("div"); // panel-body
UIComponent foot = panel.getFacet("footer");
if (foot != null) {
rw.startElement("div", panel); // modal-footer
rw.writeAttribute("class", "panel-footer", "class");
foot.encodeAll(context);
rw.endElement("div"); // panel-footer
}
rw.endElement("div");
rw.endElement("div"); // panel-body
boolean isCollapsible = panel.isCollapsible();
String accordionParent = panel.getAccordionParent();
if (isCollapsible && null == accordionParent) {
String jQueryClientID = clientId.replace(":", "_");
rw.endElement("div");
rw.startElement("input", panel);
rw.writeAttribute("type", "hidden", null);
String hiddenInputFieldID = jQueryClientID + "_collapsed";
rw.writeAttribute("name", hiddenInputFieldID, "name");
rw.writeAttribute("id", hiddenInputFieldID, "id");
rw.writeAttribute("value", String.valueOf(panel.isCollapsed()), "value");
rw.endElement("input");
Map<String, String> eventHandlers = new HashMap<String, String>();
eventHandlers.put("expand", "document.getElementById('" + hiddenInputFieldID
+ "').value='false';");
eventHandlers.put("collapse", "document.getElementById('" + hiddenInputFieldID
+ "').value='true';");
new AJAXRenderer().generateBootsFacesAJAXAndJavaScriptForJQuery(context, component, rw, "#"+jQueryClientID+"content", eventHandlers);
}
Tooltip.activateTooltips(context, panel);
}
// $('#j_idt40_j_idt43content').on('show.bs.collapse', function(){ document.getElementById('j_idt40_j_idt43_collapsed').value='false'; });
}