/*
* � Copyright IBM Corp. 2014, 2015
*
* 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 com.ibm.xsp.theme.bootstrap.renderkit.html.extlib.data;
import java.io.IOException;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.component.UIViewRootEx;
import com.ibm.xsp.extlib.component.data.AbstractDataView;
import com.ibm.xsp.extlib.component.data.ExtraColumn;
import com.ibm.xsp.extlib.component.data.UIDataView;
import com.ibm.xsp.extlib.component.data.ValueColumn;
import com.ibm.xsp.extlib.component.image.IconEntry;
import com.ibm.xsp.extlib.resources.ExtLibResources;
import com.ibm.xsp.extlib.util.ExtLibRenderUtil;
import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.ibm.xsp.model.TabularDataModel;
import com.ibm.xsp.model.domino.DominoViewDataModel;
import com.ibm.xsp.renderkit.html_basic.HtmlRendererUtil;
import com.ibm.xsp.renderkit.html_extended.RenderUtil;
import com.ibm.xsp.theme.bootstrap.resources.Resources;
import com.ibm.xsp.theme.bootstrap.util.BootstrapUtil;
import com.ibm.xsp.util.FacesUtil;
import com.ibm.xsp.util.JSUtil;
public class DataViewRenderer extends com.ibm.xsp.extlib.renderkit.html_extended.data.DataViewRenderer {
protected static final int PROP_UNREADICONCLASS = 300;
protected static final int PROP_READICONCLASS = 301;
@Override
protected Object getProperty(int prop) {
switch(prop) {
case PROP_BLANKIMG: return Resources.get().BLANK_GIF;
// note, for an Alt, there's a difference between the empty string and null
case PROP_BLANKIMGALT: return ""; //$NON-NLS-1$
case PROP_ALTTEXTCLASS: return "lotusAltText"; // $NON-NLS-1$
case PROP_HEADERCLASS: return "clearfix"; // $NON-NLS-1$
case PROP_HEADERLEFTSTYLE: return null;
case PROP_HEADERLEFTCLASS: return "pull-left"; // $NON-NLS-1$
case PROP_HEADERRIGHTSTYLE: return null;
case PROP_HEADERRIGHTCLASS: return "pull-right"; // $NON-NLS-1$
case PROP_FOOTERCLASS: return "clearfix"; // $NON-NLS-1$
case PROP_FOOTERLEFTSTYLE: return null;
case PROP_FOOTERLEFTCLASS: return "pull-left"; // $NON-NLS-1$
case PROP_FOOTERRIGHTSTYLE: return null;
case PROP_FOOTERRIGHTCLASS: return "pull-right"; // $NON-NLS-1$
case PROP_TABLECLASS: return "clearfix table dataview"; // $NON-NLS-1$
case PROP_TABLEROWEXTRA: return "lotusMeta lotusNowrap"; // $NON-NLS-1$
case PROP_COLLAPSEICON: return Resources.get().BLANK_GIF;
case PROP_COLLAPSEICONSTYLE: return "padding-right:8px"; // $NON-NLS-1$
case PROP_COLLAPSEICONCLASS: return Resources.get().getIconClass("minus-sign"); // $NON-NLS-1$
case PROP_EXPANDICON: return Resources.get().BLANK_GIF;
case PROP_EXPANDICONSTYLE: return "padding-right:8px"; // $NON-NLS-1$
case PROP_EXPANDICONCLASS: return Resources.get().getIconClass("plus-sign"); // $NON-NLS-1$
case PROP_TABLEROWINDENTPX: return 20;
case PROP_TABLEFIRSTCELLCLASS: return "xspFirstCell"; // $NON-NLS-1$
case PROP_SHOWICONDETAILSCLASS: return Resources.get().getIconClass("chevron-down"); // $NON-NLS-1$
case PROP_HIDEICONDETAILSCLASS: return Resources.get().getIconClass("chevron-up"); // $NON-NLS-1$
case PROP_UNREADICONCLASS: return Resources.get().getIconClass("file")+ " xspUnreadIcon"; // $NON-NLS-1$ $NON-NLS-2$
case PROP_READICONCLASS: return Resources.get().getIconClass("file")+" xspReadIcon"; // $NON-NLS-1$ $NON-NLS-2$
case PROP_TABLEHDRCOLIMAGE_SORTBOTH_ASCENDING: return Resources.get().getIconClass("sort-by-attributes"); // $NON-NLS-1$
case PROP_TABLEHDRCOLIMAGE_SORTBOTH_DESCENDING: return Resources.get().getIconClass("sort-by-attributes-alt"); // $NON-NLS-1$
case PROP_TABLEHDRCOLIMAGE_SORTBOTH: return Resources.get().getIconClass("sort"); // $NON-NLS-1$
case PROP_TABLEHDRCOLIMAGE_SORTED_ASCENDING: return Resources.get().getIconClass("sort-by-attributes"); // $NON-NLS-1$
case PROP_TABLEHDRCOLIMAGE_SORTED_DESCENDING: return Resources.get().getIconClass("sort-by-attributes-alt"); // $NON-NLS-1$
// the bootstrap sort header icons are 16x13 px
case PROP_TABLEHDRCOLIMAGE_SORT_WIDTH: return "16"; //$NON-NLS-1$
case PROP_TABLEHDRCOLIMAGE_SORT_HEIGHT: return "13"; //$NON-NLS-1$
// adjust the empty icon style for better indentation
case PROP_EMPTYICONSTYLE: return "width:20px;height:13px;"; // $NON-NLS-1$
case PROP_SUMMARYTITLECLASS: return "xspDataViewSummary"; // $NON-NLS-1$
}
return super.getProperty(prop);
}
@Override
protected void writeShowHideDetailContent(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException {
if(!viewDef.hasSummary || !viewDef.hasDetail) {
return;
}
// In case this is diabled for this particular row
if(viewDef.rowDisableHideRow) {
return;
}
boolean detailsOnClient = viewDef.detailsOnClient;
String linkId = c.getClientId(context) + (viewDef.rowDetailVisible?HIDE_DELIMITER:SHOW_DELIMITER) + viewDef.rowPosition;
w.startElement("a",c);
w.writeAttribute("id",linkId,null); // $NON-NLS-1$
w.writeAttribute("href","javascript:;",null); // $NON-NLS-1$ $NON-NLS-2$
//LHEY97CCSZ adding the role=button
w.writeAttribute("role", "button", null); // $NON-NLS-1$ // $NON-NLS-2$
String label = (String)getProperty(viewDef.rowDetailVisible ? PROP_HIDEICONDETAILSTOOLTIP : PROP_SHOWICONDETAILSTOOLTIP);
if(StringUtil.isNotEmpty(label)) {
w.writeAttribute("title", label, null); // $NON-NLS-1$
w.writeAttribute("aria-label", label, null); // $NON-NLS-1$
}
if(detailsOnClient) {
writeDetailsOnClientJS(context, w, c, viewDef);
}
String clazz = (String)getProperty(viewDef.rowDetailVisible?PROP_HIDEICONDETAILSCLASS:PROP_SHOWICONDETAILSCLASS);
w.startElement("span",c); // $NON-NLS-1$
w.writeAttribute("class",clazz,null); // $NON-NLS-1$
String spanId = c.getClientId(context) + "_shChevron"; // $NON-NLS-1$
w.writeAttribute("id",spanId,null); // $NON-NLS-1$
// Defect 195925 - replace unnecessary title attribute with sr-only div containing text
BootstrapUtil.renderIconTextForA11Y(w, label);
w.endElement("span"); // $NON-NLS-1$
w.endElement("a");
if(!detailsOnClient) {
if(viewDef.viewRowRefresh) {
String refreshId = c.getClientId(context)+NamingContainer.SEPARATOR_CHAR+UIDataView.ROW_ID;
setupSubmitOnClick(context, c, linkId, linkId, refreshId);
} else {
setupSubmitOnClick(context, c, linkId, linkId, null);
}
}
}
// From 9.0.1 JSUtils
public static void addSingleQuoteString(StringBuilder b, String s) {
if( null == s ){
b.append("null"); // $NON-NLS-1$
}else if( s.length() == 0 ){
b.append("''"); // $NON-NLS-1$
}else{
b.append('\'');
JSUtil.appendJavaScriptString(b, s);
b.append('\'');
}
}
@Override
protected void writeExpandCollapseIcon(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException {
boolean leaf = isRowLeaf(context, c, viewDef);
if(leaf) {
String icon = (String)getProperty(PROP_EMPTYICON);
if(icon!=null) {
w.startElement("img",c); // $NON-NLS-1$
w.writeAttribute("src",HtmlRendererUtil.getImageURL(context,icon),null); // $NON-NLS-1$
String iconAlt = (String) getProperty(PROP_EMPTYICONALT);
if( ExtLibRenderUtil.isAltPresent(iconAlt) ){
// "" - present but empty
w.writeAttribute("alt",iconAlt,null); //$NON-NLS-1$
}
String style = (String)getProperty(PROP_EMPTYICONSTYLE);
if(StringUtil.isNotEmpty(style)) {
w.writeAttribute("style",style,null); // $NON-NLS-1$
}
String clazz = (String)getProperty(PROP_EMPTYICONCLASS);
if(StringUtil.isNotEmpty(clazz)) {
w.writeAttribute("class",clazz,null); // $NON-NLS-1$
}
w.endElement("img"); // $NON-NLS-1$
}
} else {
String categoryId = c.getClientId(context) + "__rowCat:" + viewDef.rowPosition; // $NON-NLS-1$
w.writeAttribute("id",categoryId,null); // $NON-NLS-1$
boolean expanded = isRowExpanded(context, c, viewDef);
String icon = (String)getProperty(expanded ? PROP_COLLAPSEICON : PROP_EXPANDICON);
if(icon!=null) {
String linkId = c.getClientId(context) + (expanded?SHRINK_DELIMITER:EXPAND_DELIMITER) + viewDef.rowPosition;
w.startElement("a",c);
w.writeAttribute("id",linkId,null); // $NON-NLS-1$
w.writeAttribute("href","javascript:;",null); // $NON-NLS-1$ $NON-NLS-2$
//LHEY97CCSZ adding the role=button
w.writeAttribute("role", "button", null); // $NON-NLS-1$ // $NON-NLS-2$
String iconAlt = (String) getProperty(expanded? PROP_COLLAPSEICONALT : PROP_EXPANDICONALT);
w.writeAttribute("title", iconAlt, null); //$NON-NLS-1$
w.writeAttribute("aria-label", iconAlt, null); //$NON-NLS-1$
w.writeAttribute("aria-expanded", Boolean.toString(expanded), null); // $NON-NLS-1$
w.writeAttribute("aria-describedby",categoryId,null); // $NON-NLS-1$
w.startElement("span",c); // $NON-NLS-1$
w.writeAttribute("title", iconAlt, null); //$NON-NLS-1$
String style = (String)getProperty(expanded ? PROP_COLLAPSEICONSTYLE : PROP_EXPANDICONSTYLE);
if(StringUtil.isNotEmpty(style)) {
w.writeAttribute("style",style,null); // $NON-NLS-1$
}
String clazz = (String)getProperty(expanded ? PROP_COLLAPSEICONCLASS : PROP_EXPANDICONCLASS);
if(StringUtil.isNotEmpty(clazz)) {
w.writeAttribute("class",clazz,null); // $NON-NLS-1$
}
//Defect 195918
BootstrapUtil.renderIconTextForA11Y(w, iconAlt);
w.endElement("span"); // $NON-NLS-1$
w.endElement("a"); // $NON-NLS-1$
setupSubmitOnClick(context, c, linkId, linkId, null);
}
}
}
@Override
protected void writeIconColumn(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException {
w.startElement("td",c); // $NON-NLS-1$
w.writeAttribute("role", "gridcell", null); // $NON-NLS-1$ $NON-NLS-2$
if(viewDef.iconColumn!=null) {
String colStyle = viewDef.iconColumn.getStyle();
if(StringUtil.isNotEmpty(colStyle)) {
w.writeAttribute("style",colStyle,null); // $NON-NLS-1$
}
String colClazz = viewDef.iconColumn.getStyleClass();
if(!viewDef.hasCheckBoxColumn && !viewDef.hasIconColumn) {
colClazz = ExtLibUtil.concatStyleClasses(colClazz,(String)getProperty(PROP_TABLEFIRSTCELLCLASS));
}
if(StringUtil.isNotEmpty(colClazz)) {
w.writeAttribute("class",colClazz,null); // $NON-NLS-1$
}
}
if(viewDef.iconFacet!=null) {
FacesUtil.renderComponent(context, viewDef.iconFacet);
} else {
IconEntry entry = findIcon(context, w, c, viewDef);
if(entry!=null) {
String src = entry.getUrl();
if(StringUtil.isNotEmpty(src)) {
boolean unread = src.contains("xpPostUnread"); // $NON-NLS-1$
w.startElement("div",c); // $NON-NLS-1$
String alt = entry.getAlt();
String title = entry.getTitle();
if(StringUtil.isEmpty(title)){
if(StringUtil.isNotEmpty(alt)){
w.writeAttribute("title", alt, null); //$NON-NLS-1$
}
}else{
w.writeAttribute("title", title, null); //$NON-NLS-1$
}
String iconStyle = entry.getStyle();
if(StringUtil.isNotEmpty(iconStyle)) {
w.writeAttribute("style",iconStyle,null); // $NON-NLS-1$
}
String iconClass = (String)getProperty(unread?PROP_UNREADICONCLASS:PROP_READICONCLASS);
if(StringUtil.isNotEmpty(iconClass)) {
w.writeAttribute("class",iconClass,null); // $NON-NLS-1$
}
String ariaLabel = null;
if(StringUtil.isEmpty(title)){
if(StringUtil.isNotEmpty(alt)){
ariaLabel = alt;
}else{
if( unread ){
ariaLabel = com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer.Unreaddocument"); //$NON-NLS-1$
}else{
ariaLabel = com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer.Readdocument"); //$NON-NLS-1$
}
}
}else{
ariaLabel = title;
}
//Write accessibility properties
w.writeAttribute("aria-label", ariaLabel, null); // $NON-NLS-1$
w.writeAttribute("aria-hidden", "true", null); // $NON-NLS-1$ $NON-NLS-2$
w.endElement("div"); // $NON-NLS-1$
BootstrapUtil.renderIconTextForA11Y(w, ariaLabel);
}
}
}
w.endElement("td"); // $NON-NLS-1$
}
@Override
protected void writeDataColumn(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException {
// Prevent the column to be diisplayed when no data exists
if(!viewDef.hasSummary && !viewDef.hasDetail) {
return;
}
w.startElement("td",c); // $NON-NLS-1$
w.writeAttribute("role", "gridcell", null); // $NON-NLS-1$ $NON-NLS-2$
//Add aria-describedby property that references the header id
if (null != viewDef.summaryColumn) {
String colTitle = viewDef.summaryColumn.getColumnTitle();
if(StringUtil.isNotEmpty(colTitle)) {
String thId = c.getNonChildClientId(context) + "_th_" + colTitle; //$NON-NLS-1$
if (StringUtil.isNotEmpty(thId)) {
w.writeAttribute("aria-describedby", thId, null); // $NON-NLS-1$
}
}
}
int width = 100/viewDef.multiColumnCount;
w.writeAttribute("style","width: "+width+"%",null); // $NON-NLS-1$ $NON-NLS-2$
if(!viewDef.hasCheckBoxColumn && !viewDef.hasIconColumn) {
String clazz = (String)getProperty(PROP_TABLEFIRSTCELLCLASS);
if(StringUtil.isNotEmpty(clazz)) {
w.writeAttribute("class",clazz,null); // $NON-NLS-1$
}
}
// Enclosing divsfcol
w.startElement("div",c); // $NON-NLS-1$
int level = getColumnIndentLevel(context, c, viewDef);
int catLevel = Math.max(0, viewDef.categoryCount-1);
String indentStyle = getIndentStyle(context, c, viewDef, level+catLevel);
if(StringUtil.isNotEmpty(indentStyle)) {
w.writeAttribute("style",indentStyle,null); // $NON-NLS-1$
}
//Remove padding-top when collapse/expand icon is displayed
if(viewDef.collapsibleRows) {
if (null != viewDef.summaryColumn) {
String summaryStyle = viewDef.summaryColumn.getStyle();
String style = ExtLibUtil.concatStyles("padding-top:0px;", summaryStyle); // $NON-NLS-1$
viewDef.summaryColumn.setStyle(style);
}
}
// Write the summary data
writeSummary(context, w, c, viewDef);
// Write the details
writeDetail(context, w, c, viewDef);
w.endElement("div"); // $NON-NLS-1$
w.endElement("td"); // $NON-NLS-1$
}
@Override
protected void writeColumnHeader(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, ValueColumn vc, int colIndex) throws IOException {
// Write the summary column
w.startElement("th",c); // $NON-NLS-1$
w.writeAttribute("scope", "col", null); // $NON-NLS-1$ $NON-NLS-2$
w.writeAttribute("role", "columnheader", null); // $NON-NLS-1$ $NON-NLS-2$
String style = ExtLibUtil.concatStyles((String)getProperty(PROP_TABLEHDRCOLSTYLE),vc!=null?vc.getHeaderStyle():null);
if(StringUtil.isNotEmpty(style)) {
w.writeAttribute("style",style,null); // $NON-NLS-1$
}
String clazz = ExtLibUtil.concatStyleClasses((String)getProperty(colIndex==0 ? PROP_TABLEHDRFIRSTCOLCLASS : PROP_TABLEHDRCOLCLASS),vc!=null?vc.getHeaderStyleClass():null);
if(StringUtil.isNotEmpty(clazz)) {
w.writeAttribute("class",clazz,null); // $NON-NLS-1$
}
if(vc!=null) {
String colTitle = vc.getColumnTitle();
if(StringUtil.isNotEmpty(colTitle)) {
String colName = vc.getColumnName();
// Kind of hard coded here, which is not clean...
boolean dominoStyleIcons = viewDef.dataModel instanceof DominoViewDataModel;
boolean sortable = false;
if(StringUtil.isNotEmpty(colTitle)) {
//Add id to the th element
String thId = c.getClientId(context) + "_th_" + colTitle; //$NON-NLS-1$
w.writeAttribute("id", thId, null); //$NON-NLS-1$
sortable = isColumnSortable(context, c, viewDef, colName);
}
if(sortable) {
// adding aria sort to th element
int sortState = getColumnSortState(context, c, viewDef, colName);
if (sortState == TabularDataModel.RESORT_ASCENDING) {
w.writeAttribute("aria-sort", "ascending", null); // $NON-NLS-1$ $NON-NLS-2$
}
else if (sortState == TabularDataModel.RESORT_DESCENDING) {
w.writeAttribute("aria-sort", "descending", null); // $NON-NLS-1$ $NON-NLS-2$
}
else if (sortState == TabularDataModel.RESORT_BOTH) {
w.writeAttribute("aria-sort", "other", null); // $NON-NLS-1$ $NON-NLS-2$
}else {
w.writeAttribute("aria-sort", "none", null); // $NON-NLS-1$ $NON-NLS-2$
}
w.startElement("span",c); // $NON-NLS-1$
String linkId = c.getClientId(context) + SORT_DELIMITER + colName;
w.startElement("a",c);
w.writeAttribute("id",linkId,null); // $NON-NLS-1$
String headerTitle = vc.getHeaderLinkTitle();
if(StringUtil.isEmpty(headerTitle)){
// "Click to reverse sort";
headerTitle = com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer_SortLinkTooltip_ClickToReverseSort"); //$NON-NLS-1$
}
//adding the Header accessibility title
int dominoSortIconCode = getDominoSortIconCode(context, c, viewDef, colName);
w.writeAttribute("title", headerTitle, null); // $NON-NLS-1$
String iconTextDescription = getSortIconDescription(dominoSortIconCode);
w.writeAttribute("aria-label", colName + ", " + iconTextDescription, null); // $NON-NLS-1$
if(!dominoStyleIcons) {
if(sortState==TabularDataModel.RESORT_ASCENDING) {
String clazz2 = (String)getProperty(PROP_TABLEHDRCOLLKASCCLASS);
if(StringUtil.isNotEmpty(clazz2)) {
w.writeAttribute("class",clazz2,null); // $NON-NLS-1$
}
} else if(sortState==TabularDataModel.RESORT_DESCENDING) {
String clazz2 = (String)getProperty(PROP_TABLEHDRCOLLKDESCLASS);
if(StringUtil.isNotEmpty(clazz2)) {
w.writeAttribute("class",clazz2,null); // $NON-NLS-1$
}
}
}
w.writeAttribute("href","javascript:;",null); // $NON-NLS-1$ $NON-NLS-2$
//LHEY97CCSZ adding the role=button
w.writeAttribute("role", "button", null); // $NON-NLS-1$ // $NON-NLS-2$
setupSubmitOnClick(context, c, linkId, linkId, null);
}else{
w.startElement("span",c); // $NON-NLS-1$
}
boolean multiColumn = viewDef.multiColumnCount>1;
if(!multiColumn || sortable) {
w.writeText(colTitle,null);
}
if(sortable) {
w.endElement("a");
}
if(dominoStyleIcons) {
int dominoSortIconCode = getDominoSortIconCode(context, c, viewDef, colName);
String sort = getDominoSortIcon(context, c, viewDef, dominoSortIconCode);
if(StringUtil.isNotEmpty(sort)) {
w.startElement("div",c); // $NON-NLS-1$
w.writeAttribute("class", sort, null); //$NON-NLS-1$x
w.writeAttribute("aria-hidden", "true", null); // $NON-NLS-1$ $NON-NLS-2$
w.endElement("div"); // $NON-NLS-1$
}
}
w.endElement("span"); // $NON-NLS-1$
}
}
w.endElement("th"); // $NON-NLS-1$
}
public String getSortIconDescription(int dominoSortIconCode){
switch(dominoSortIconCode){
case SORT_1_COLUMN_SORTABLE_BOTH_CURRENTLY_NOT_SORTED:
case SORT_4_COLUMN_SORTABLE_ASCENDING_CURRENTLY_NOT_SORTED:{
// "Sortable column, currently not sorted"
return com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer.Sortablecolumncurrentlynotsorted"); //$NON-NLS-1$
}
case SORT_2_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_ASCENDING:
case SORT_5_COLUMN_SORTABLE_ASCENDING_CURRENTLY_SORTED_ASCENDING:{
// "Sortable column, currently sorted in ascending order"
return com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer.Sortablecolumncurrentlysortedinas"); //$NON-NLS-1$
}
case SORT_3_COLUMN_SORTABLE_BOTH_CURRENTLY_SORTED_DESCENDING:
case SORT_7_COLUMN_SORTABLE_DESCENDING_CURRENTLY_SORTED_DESCENDING:{
// "Sortable column, currently sorted in descending order"
return com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer.Sortablecolumncurrentlysortedinde"); //$NON-NLS-1$
}
case SORT_6_COLUMN_SORTABLE_DESCENDING_CURRENTLY_NOT_SORTED:{
// "Column sortable in descending order, currently not sorted "
return com.ibm.xsp.extlib.controls.ResourceHandler.getString("DataViewRenderer.Columnsortableindescendingordercu"); //$NON-NLS-1$
}
}
return "";
}
@Override
protected void writeCheckboxAccessibilityAttributes(FacesContext context, ResponseWriter w, String checkBoxId) throws IOException {
//Add aria-checked attribute
w.writeAttribute("aria-checked", "false", null);// $NON-NLS-1$ // $NON-NLS-2$
//Add JS onclick code to handle toggling aria-checked attribute
StringBuilder onclick = new StringBuilder();
onclick.append("return XSP.toggleCheckboxAria("); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, checkBoxId); // $NON-NLS-1$
onclick.append(")"); // $NON-NLS-1$
w.writeAttribute("onclick", onclick.toString(), null); // $NON-NLS-1$
}
@Override
protected void writeHeaderCheckboxAccessibilityAttributes(FacesContext context, ResponseWriter w, String viewId, String headerCheckboxId) throws IOException {
w.writeAttribute("aria-checked", "false", null);// $NON-NLS-1$ // $NON-NLS-2$
//Add JS onclick code to handle toggling aria-checked attribute
StringBuilder onclick = new StringBuilder();
onclick.append("return XSP.toggleHeaderCheckboxAria("); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, viewId);
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, headerCheckboxId); // $NON-NLS-1$
onclick.append(")"); // $NON-NLS-1$
w.writeAttribute("onclick", onclick.toString(), null); // $NON-NLS-1$
}
@Override
protected void writeExtraColumn(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef, ExtraColumn col, int colIdx) throws IOException {
w.startElement("td",c); // $NON-NLS-1$
String value = formatColumnValue(context, c, viewDef, col);
if(!StringUtil.isEmpty(value)) {
w.writeAttribute("role", "gridcell", null); // $NON-NLS-1$ $NON-NLS-2$
//Add aria-describedby property that references the header id
String colTitle = col.getColumnTitle();
if(StringUtil.isNotEmpty(colTitle)) {
String thId = c.getNonChildClientId(context) + "_th_" + colTitle; //$NON-NLS-1$
if (StringUtil.isNotEmpty(thId)) {
w.writeAttribute("aria-describedby", thId, null); // $NON-NLS-1$ $NON-NLS-2$
}
}
}
UIComponent facet = getExtraFacet(c,colIdx);
if(facet!=null) {
// TODO should use the column complex-type's style, and styleClass
// even when using the facet for the column contents.
FacesUtil.renderComponent(context, facet);
} else {
String style = col.getStyle();
if(StringUtil.isNotEmpty(style)) {
w.writeAttribute("style", style, null); // $NON-NLS-1$
}
String clazz = col.getStyleClass();
if(StringUtil.isEmpty(clazz)) {
clazz = (String)getProperty(PROP_TABLEROWEXTRA);
}
if(StringUtil.isNotEmpty(clazz)) {
w.writeAttribute("class", clazz, null); // $NON-NLS-1$
}
// Write a link if there is an href
String href = getColumnUrl(context, c, viewDef, col);
if(StringUtil.isNotEmpty(href)) {
w.startElement("a",c);
RenderUtil.writeLinkAttribute(context,w,href);
// Write the title if there is any
String title = getTitle(context, c, viewDef, col);
if(StringUtil.isNotEmpty(title)) {
w.writeAttribute("title", title,null); // $NON-NLS-1$
}
}else{
w.startElement("div",c); // $NON-NLS-1$
}
writeColumnValue(context, w, c, viewDef, col);
if(StringUtil.isNotEmpty(href)) {
w.endElement("a");
}else{
w.endElement("div"); // $NON-NLS-1$
}
}
w.endElement("td"); // $NON-NLS-1$
}
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
// Encode the necessary resource
UIViewRootEx rootEx = (UIViewRootEx)context.getViewRoot();
ExtLibResources.addEncodeResource(rootEx, Resources.bootstrapCheckbox);
ExtLibResources.addEncodeResource(rootEx, ExtLibResources.extlibExtLib);
super.encodeBegin(context, component);
}
@Override
protected void writeShowHide(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException {
//Disable superclass client show/hide JS, as bootstrap version implemented below
//in writeDetailsOnClientJS and in xsp.mixin.js. But keep the hidden field
if(viewDef.detailsOnClient && viewDef.collapsibleDetails) {
writeClientShowHideHiddenField(context, w, c, viewDef);
//addClientShowHideScript(context, w, c, viewDef);
}
}
protected void writeDetailsOnClientJS(FacesContext context, ResponseWriter w, AbstractDataView c, ViewDefinition viewDef) throws IOException {
//TODO re-work the hide/show detail on client JS in super classes to make this
//a single reusable method across all data views and forum views
//TODO Hacky clientId retrieval of the dataView control
//replace with a proper getClientId method for the dataview
//c.getClientId(context) gives back the id of the row
String rowId = c.getClientId(context);
String dataViewID = rowId.substring(0, rowId.lastIndexOf(":"+viewDef.dataModel.getRowIndex()));
//Add JS onclick code to handle toggling aria-checked attribute
StringBuilder onclick = new StringBuilder();
onclick.append("return XSP.xbtShowHideDetails("); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, dataViewID);
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, Integer.toString(viewDef.dataModel.getRowIndex()));
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, viewDef.rowPosition);
onclick.append(", "); // $NON-NLS-1$
onclick.append(viewDef.summaryOrDetailVisible);
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, (String)getProperty(PROP_SHOWICONDETAILSCLASS));
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, (String)getProperty(PROP_HIDEICONDETAILSCLASS));
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, (String)getProperty(PROP_SHOWICONDETAILSTOOLTIP));
onclick.append(", "); // $NON-NLS-1$
JSUtil.addSingleQuoteString(onclick, (String)getProperty(PROP_HIDEICONDETAILSTOOLTIP));
onclick.append(")"); // $NON-NLS-1$
w.writeAttribute("onclick", onclick.toString(), null); // $NON-NLS-1$
// Build JS for onkeyup event to swap collapse/expand properties
// when enter or space are pressed (see ExtLib.js)
StringBuilder onkeydown = new StringBuilder();
onkeydown.append("var xbtIsTriggerKey = XSP.xbtIsTriggerKey(event);"); // $NON-NLS-1$
onkeydown.append("if(xbtIsTriggerKey){"); // $NON-NLS-1$
onkeydown.append("event.preventDefault();"); // $NON-NLS-1$
onkeydown.append("event.stopPropagation();"); // $NON-NLS-1$
onkeydown.append(onclick);
onkeydown.append("}"); // $NON-NLS-1$
w.writeAttribute("onkeydown", onkeydown.toString(), null); // $NON-NLS-1$
}
}