org.primefaces.extensions.component.sheet.SheetRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of primefaces-extensions Show documentation
Show all versions of primefaces-extensions Show documentation
PrimeFaces Extensions Project for Maven.
/*
* Copyright (c) 2011-2024 PrimeFaces Extensions
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.primefaces.extensions.component.sheet;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.model.SelectItem;
import org.primefaces.behavior.ajax.AjaxBehavior;
import org.primefaces.extensions.util.Attrs;
import org.primefaces.extensions.util.ExtLangUtils;
import org.primefaces.extensions.util.JavascriptVarBuilder;
import org.primefaces.renderkit.CoreRenderer;
import org.primefaces.shaded.json.JSONArray;
import org.primefaces.shaded.json.JSONException;
import org.primefaces.shaded.json.JSONObject;
import org.primefaces.util.ComponentUtils;
import org.primefaces.util.Constants;
import org.primefaces.util.HTML;
import org.primefaces.util.LangUtils;
import org.primefaces.util.WidgetBuilder;
/**
* The Sheet renderer.
*
* @author Mark Lassiter / Melloware
* @since 6.2
*/
public class SheetRenderer extends CoreRenderer {
/**
* Encodes the Sheet component
*/
@Override
public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
final ResponseWriter responseWriter = context.getResponseWriter();
final Sheet sheet = (Sheet) component;
// update column mappings on render
sheet.updateColumnMappings();
// sort data
sheet.sortAndFilter();
// encode markup
encodeMarkup(context, sheet, responseWriter);
// encode javascript
encodeScript(context, sheet);
}
/**
* Encodes the HTML markup for the sheet.
*/
protected void encodeMarkup(final FacesContext context, final Sheet sheet, final ResponseWriter responseWriter)
throws IOException {
/*
*
*/
final String styleClass = sheet.getStyleClass();
final String clientId = sheet.getClientId(context);
final Integer width = sheet.getWidth();
final Integer height = sheet.getHeight();
String style = sheet.getStyle();
// outer div to wrapper table
responseWriter.startElement("div", null);
responseWriter.writeAttribute("id", clientId, "id");
responseWriter.writeAttribute("name", clientId, "clientId");
// note: can't use ui-datatable here because it will mess with
// handsontable cell rendering
String divclass = "ui-handsontable ui-widget";
if (styleClass != null) {
divclass = divclass + " " + styleClass;
}
if (!sheet.isValid()) {
divclass = divclass + " ui-state-error";
}
responseWriter.writeAttribute(Attrs.CLASS, divclass, "styleClass");
if (width != null) {
responseWriter.writeAttribute(Attrs.STYLE, "width: " + width + "px;", null);
}
encodeKeyboardTrap(context, sheet);
encodeHiddenInputs(context, sheet, clientId);
encodeFilterValues(responseWriter, sheet, clientId);
encodeHeader(context, responseWriter, sheet);
// handsontable div
responseWriter.startElement("div", null);
responseWriter.writeAttribute("id", clientId + "_tbl", "id");
responseWriter.writeAttribute("name", clientId + "_tbl", "clientId");
responseWriter.writeAttribute(Attrs.CLASS, "handsontable-inner", "styleClass");
if (style == null) {
style = Constants.EMPTY_STRING;
}
if (width != null) {
style = style + "width: " + width + "px;";
}
if (height != null) {
style = style + "height: " + height + "px;";
}
else {
style = style + "height: 100%;";
}
responseWriter.writeAttribute(Attrs.STYLE, style, null);
responseWriter.endElement("div");
encodeFooter(context, responseWriter, sheet);
responseWriter.endElement("div");
}
/**
* Encodes an optional attribute to the widget builder specified.
*
* @param wb the WidgetBuilder to append to
* @param attrName the attribute name
* @param value the value
* @throws IOException if any IO error occurs
*/
protected void encodeOptionalAttr(final WidgetBuilder wb, final String attrName, final String value)
throws IOException {
if (value != null) {
wb.attr(attrName, value);
}
}
/**
* Encodes an optional native attribute (unquoted).
*
* @param wb the WidgetBuilder to append to
* @param attrName the attribute name
* @param value the value
* @throws IOException if any IO error occurs
*/
protected void encodeOptionalNativeAttr(final WidgetBuilder wb, final String attrName, final Object value)
throws IOException {
if (value != null) {
wb.nativeAttr(attrName, value.toString());
}
}
/**
* Encodes the Javascript for the sheet.
*
* @param context the FacesContext
* @param sheet the Sheet
* @throws IOException if any IO error occurs
*/
protected void encodeScript(final FacesContext context, final Sheet sheet)
throws IOException {
final WidgetBuilder wb = getWidgetBuilder(context);
wb.init("ExtSheet", sheet);
// errors
encodeInvalidData(sheet, wb);
// data
encodeData(context, sheet, wb);
// the delta var that will be used to track changes client side
// stringified and placed in hidden input for submission
wb.nativeAttr("delta", "{}");
// filters
encodeFilterVar(sheet, wb);
// sortable
encodeSortVar(sheet, wb);
// behaviors
encodeBehaviors(context, sheet, wb);
encodeOptionalNativeAttr(wb, "readOnly", sheet.isReadOnly());
encodeOptionalNativeAttr(wb, "fixedColumnsLeft", sheet.getFixedCols());
encodeOptionalNativeAttr(wb, "fixedRowsTop", sheet.getFixedRows());
encodeOptionalNativeAttr(wb, "fixedRowsBottom", sheet.getFixedRowsBottom());
encodeOptionalNativeAttr(wb, "manualColumnResize", sheet.isResizableCols());
encodeOptionalNativeAttr(wb, "manualRowResize", sheet.isResizableRows());
encodeOptionalNativeAttr(wb, "manualColumnMove", sheet.isMovableCols());
encodeOptionalNativeAttr(wb, "manualRowMove", sheet.isMovableRows());
encodeOptionalNativeAttr(wb, "allowTabOffSheet", sheet.isAllowTabOffSheet());
encodeOptionalNativeAttr(wb, "width", sheet.getWidth());
encodeOptionalNativeAttr(wb, "height", sheet.getHeight());
encodeOptionalNativeAttr(wb, "minRows", sheet.getMinRows());
encodeOptionalNativeAttr(wb, "minCols", sheet.getMinCols());
encodeOptionalNativeAttr(wb, "maxRows", sheet.getMaxRows());
encodeOptionalNativeAttr(wb, "maxCols", sheet.getMaxCols());
encodeOptionalAttr(wb, "stretchH", sheet.getStretchH());
encodeOptionalAttr(wb, "language", sheet.getLocale());
encodeOptionalAttr(wb, "selectionMode", sheet.getSelectionMode());
encodeOptionalAttr(wb, "activeHeaderClassName", sheet.getActiveHeaderStyleClass());
encodeOptionalAttr(wb, "commentedCellClassName", sheet.getCommentedCellStyleClass());
encodeOptionalAttr(wb, "currentRowClassName", sheet.getCurrentRowStyleClass());
encodeOptionalAttr(wb, "currentColClassName", sheet.getCurrentColStyleClass());
encodeOptionalAttr(wb, "currentHeaderClassName", sheet.getCurrentHeaderStyleClass());
encodeOptionalAttr(wb, "invalidCellClassName", sheet.getInvalidCellStyleClass());
encodeOptionalAttr(wb, "noWordWrapClassName", sheet.getNoWordWrapStyleClass());
encodeOptionalAttr(wb, "placeholderCellClassName", sheet.getPlaceholderCellStyleClass());
encodeOptionalAttr(wb, "readOnlyCellClassName", sheet.getReadOnlyCellStyleClass());
encodeOptionalNativeAttr(wb, "extender", sheet.getExtender());
String emptyMessage = sheet.getEmptyMessage();
if (LangUtils.isBlank(emptyMessage)) {
emptyMessage = "No Records Found";
}
encodeOptionalAttr(wb, "emptyMessage", emptyMessage);
encodeColHeaders(sheet, wb);
encodeColOptions(sheet, wb);
wb.finish();
}
/**
* Encodes the necessary JS to render invalid data.
*
* @throws IOException if any IO error occurs
*/
protected void encodeInvalidData(final Sheet sheet, final WidgetBuilder wb)
throws IOException {
wb.attr("errors", sheet.getInvalidDataValue());
}
/**
* Encode the column headers
*
* @throws IOException if any IO error occurs
*/
protected void encodeColHeaders(final Sheet sheet, final WidgetBuilder wb)
throws IOException {
final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, false);
for (final SheetColumn column : sheet.getColumns()) {
if (!column.isRendered()) {
continue;
}
vb.appendArrayValue(column.getHeaderText(), true);
}
wb.nativeAttr("colHeaders", vb.closeVar().toString());
}
/**
* Encode the column options
*
* @throws IOException if any IO error occurs
*/
protected void encodeColOptions(final Sheet sheet, final WidgetBuilder wb)
throws IOException {
final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, false);
for (final SheetColumn column : sheet.getColumns()) {
if (!column.isRendered()) {
continue;
}
final JavascriptVarBuilder options = new JavascriptVarBuilder(null, true);
options.appendProperty("type", column.getColType(), true);
options.appendProperty("copyable", "true", false);
final Integer width = column.getColWidth();
String calculatedWidth = null;
if (width != null) {
calculatedWidth = width.toString();
}
// HT doesn't have a hidden property so make column small as possible will leave
// it in the DOM, if 0 then Handsontable removes it entirely
if (!column.isVisible()) {
calculatedWidth = "0.1";
}
if (calculatedWidth != null) {
options.appendProperty("width", calculatedWidth, false);
}
if (column.isReadOnly()) {
options.appendProperty("readOnly", "true", false);
}
options.appendProperty("trimWhitespace", column.isTrimWhitespace().toString(), false);
options.appendProperty("wordWrap", column.isWordWrap().toString(), false);
// validate can be a function, regex, or string
final String validateFunction = column.getOnvalidate();
if (validateFunction != null) {
final boolean quoted;
switch (validateFunction) {
case "autocomplete":
case "date":
case "numeric":
case "time":
quoted = true;
break;
default:
// its a function or regex!
quoted = false;
break;
}
options.appendProperty("validator", validateFunction, quoted);
}
switch (column.getColType()) {
case "password":
final Integer passwordLength = column.getPasswordHashLength();
if (passwordLength != null) {
options.appendProperty("hashLength", passwordLength.toString(), false);
}
final String passwordSymbol = column.getPasswordHashSymbol();
if (passwordSymbol != null) {
options.appendProperty("hashSymbol", passwordSymbol, true);
}
break;
case "numeric":
final JavascriptVarBuilder numeric = new JavascriptVarBuilder(null, true);
final String pattern = column.getNumericPattern();
if (pattern != null) {
numeric.appendProperty("pattern", pattern, true);
}
final String culture = column.getNumericLocale();
if (culture != null) {
numeric.appendProperty("culture", culture, true);
}
options.appendProperty("numericFormat", numeric.closeVar().toString(), false);
break;
case "date":
options.appendProperty("dateFormat", column.getDateFormat(), true);
options.appendProperty("correctFormat", "true", false);
final String dateConfig = column.getDatePickerConfig();
if (dateConfig != null) {
options.appendProperty("datePickerConfig", dateConfig, false);
}
break;
case "time":
options.appendProperty("timeFormat", column.getTimeFormat(), true);
options.appendProperty("correctFormat", "true", false);
break;
case "dropdown":
encodeSelectItems(column, options);
break;
case "autocomplete":
options.appendProperty("strict", Boolean.toString(column.isAutoCompleteStrict()), false);
options.appendProperty("allowInvalid", Boolean.toString(column.isAutoCompleteAllowInvalid()),
false);
options.appendProperty("trimDropdown", Boolean.toString(column.isAutoCompleteTrimDropdown()),
false);
final Integer visibleRows = column.getAutoCompleteVisibleRows();
if (visibleRows != null) {
options.appendProperty("visibleRows", visibleRows.toString(), false);
}
encodeSelectItems(column, options);
break;
default:
break;
}
vb.appendArrayValue(options.closeVar().toString(), false);
}
wb.nativeAttr("columns", vb.closeVar().toString());
}
private void encodeSelectItems(final SheetColumn column, final JavascriptVarBuilder options) {
final JavascriptVarBuilder items = new JavascriptVarBuilder(null, false);
final Object value = column.getSelectItems();
if (value == null) {
return;
}
if (value.getClass().isArray()) {
for (int j = 0; j < Array.getLength(value); j++) {
final Object item = Array.get(value, j);
items.appendArrayValue(String.valueOf(item), true);
}
}
else if (value instanceof Collection) {
final Collection collection = (Collection) value;
for (final Object item : collection) {
items.appendArrayValue(String.valueOf(item), true);
}
}
else if (value instanceof Map) {
final Map map = (Map) value;
for (final Object item : map.keySet()) {
items.appendArrayValue(String.valueOf(item), true);
}
}
options.appendProperty("source", items.closeVar().toString(), false);
}
/**
* Encode the row data. Builds row data, style data and read only object.
*/
protected void encodeData(final FacesContext context, final Sheet sheet, final WidgetBuilder wb)
throws IOException {
final JavascriptVarBuilder jsData = new JavascriptVarBuilder(null, false);
final JavascriptVarBuilder jsRowKeys = new JavascriptVarBuilder(null, false);
final JavascriptVarBuilder jsStyle = new JavascriptVarBuilder(null, true);
final JavascriptVarBuilder jsRowStyle = new JavascriptVarBuilder(null, false);
final JavascriptVarBuilder jsReadOnly = new JavascriptVarBuilder(null, true);
final JavascriptVarBuilder jsRowHeaders = new JavascriptVarBuilder(null, false);
final boolean isCustomHeader = sheet.getRowHeaderValueExpression() != null;
final List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy