1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.primefaces.extensions.component.sheet;
23
24 import java.io.IOException;
25 import java.lang.reflect.Array;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.faces.FacesException;
32 import javax.faces.component.UIComponent;
33 import javax.faces.component.behavior.ClientBehavior;
34 import javax.faces.component.behavior.ClientBehaviorContext;
35 import javax.faces.component.behavior.ClientBehaviorHolder;
36 import javax.faces.context.FacesContext;
37 import javax.faces.context.ResponseWriter;
38 import javax.faces.model.SelectItem;
39
40 import org.primefaces.behavior.ajax.AjaxBehavior;
41 import org.primefaces.extensions.util.Attrs;
42 import org.primefaces.extensions.util.ExtLangUtils;
43 import org.primefaces.extensions.util.JavascriptVarBuilder;
44 import org.primefaces.renderkit.CoreRenderer;
45 import org.primefaces.shaded.json.JSONArray;
46 import org.primefaces.shaded.json.JSONException;
47 import org.primefaces.shaded.json.JSONObject;
48 import org.primefaces.util.Constants;
49 import org.primefaces.util.FacetUtils;
50 import org.primefaces.util.HTML;
51 import org.primefaces.util.LangUtils;
52 import org.primefaces.util.WidgetBuilder;
53
54
55
56
57
58
59
60 public class SheetRenderer extends CoreRenderer {
61
62
63
64
65 @Override
66 public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
67 final ResponseWriter responseWriter = context.getResponseWriter();
68 final Sheet sheet = (Sheet) component;
69
70
71 sheet.updateColumnMappings();
72
73
74 sheet.sortAndFilter();
75
76
77 encodeMarkup(context, sheet, responseWriter);
78
79
80 encodeScript(context, sheet);
81 }
82
83
84
85
86 protected void encodeMarkup(final FacesContext context, final Sheet sheet, final ResponseWriter responseWriter)
87 throws IOException {
88
89
90
91
92 final String styleClass = sheet.getStyleClass();
93 final String clientId = sheet.getClientId(context);
94 final Integer width = sheet.getWidth();
95 final Integer height = sheet.getHeight();
96 String style = sheet.getStyle();
97
98
99 responseWriter.startElement("div", null);
100 responseWriter.writeAttribute("id", clientId, "id");
101 responseWriter.writeAttribute("name", clientId, "clientId");
102
103
104 String divclass = "ui-handsontable ui-widget";
105 if (styleClass != null) {
106 divclass = divclass + " " + styleClass;
107 }
108 if (!sheet.isValid()) {
109 divclass = divclass + " ui-state-error";
110 }
111
112 responseWriter.writeAttribute(Attrs.CLASS, divclass, "styleClass");
113 if (width != null) {
114 responseWriter.writeAttribute(Attrs.STYLE, "width: " + width + "px;", null);
115 }
116
117 encodeKeyboardTrap(context, sheet);
118 encodeHiddenInputs(context, sheet, clientId);
119 encodeFilterValues(responseWriter, sheet, clientId);
120 encodeHeader(context, responseWriter, sheet);
121
122
123 responseWriter.startElement("div", null);
124 responseWriter.writeAttribute("id", clientId + "_tbl", "id");
125 responseWriter.writeAttribute("name", clientId + "_tbl", "clientId");
126 responseWriter.writeAttribute(Attrs.CLASS, "handsontable-inner", "styleClass");
127
128 if (style == null) {
129 style = Constants.EMPTY_STRING;
130 }
131
132 if (width != null) {
133 style = style + "width: " + width + "px;";
134 }
135
136 if (height != null) {
137 style = style + "height: " + height + "px;";
138 }
139 else {
140 style = style + "height: 100%;";
141 }
142
143 responseWriter.writeAttribute(Attrs.STYLE, style, null);
144
145 responseWriter.endElement("div");
146 encodeFooter(context, responseWriter, sheet);
147 responseWriter.endElement("div");
148 }
149
150
151
152
153
154
155
156
157
158 protected void encodeOptionalAttr(final WidgetBuilder wb, final String attrName, final String value)
159 throws IOException {
160 if (value != null) {
161 wb.attr(attrName, value);
162 }
163 }
164
165
166
167
168
169
170
171
172
173 protected void encodeOptionalNativeAttr(final WidgetBuilder wb, final String attrName, final Object value)
174 throws IOException {
175 if (value != null) {
176 wb.nativeAttr(attrName, value.toString());
177 }
178 }
179
180
181
182
183
184
185
186
187 protected void encodeScript(final FacesContext context, final Sheet sheet)
188 throws IOException {
189 final WidgetBuilder wb = getWidgetBuilder(context);
190 wb.init("ExtSheet", sheet);
191
192
193 encodeInvalidData(sheet, wb);
194
195 encodeData(context, sheet, wb);
196
197
198
199 wb.nativeAttr("delta", "{}");
200
201
202 encodeFilterVar(sheet, wb);
203
204 encodeSortVar(sheet, wb);
205
206 encodeBehaviors(context, sheet, wb);
207
208 encodeOptionalNativeAttr(wb, "readOnly", sheet.isReadOnly());
209 encodeOptionalNativeAttr(wb, "fixedColumnsLeft", sheet.getFixedCols());
210 encodeOptionalNativeAttr(wb, "fixedRowsTop", sheet.getFixedRows());
211 encodeOptionalNativeAttr(wb, "fixedRowsBottom", sheet.getFixedRowsBottom());
212 encodeOptionalNativeAttr(wb, "manualColumnResize", sheet.isResizableCols());
213 encodeOptionalNativeAttr(wb, "manualRowResize", sheet.isResizableRows());
214 encodeOptionalNativeAttr(wb, "manualColumnMove", sheet.isMovableCols());
215 encodeOptionalNativeAttr(wb, "manualRowMove", sheet.isMovableRows());
216 encodeOptionalNativeAttr(wb, "allowTabOffSheet", sheet.isAllowTabOffSheet());
217 encodeOptionalNativeAttr(wb, "width", sheet.getWidth());
218 encodeOptionalNativeAttr(wb, "height", sheet.getHeight());
219 encodeOptionalNativeAttr(wb, "minRows", sheet.getMinRows());
220 encodeOptionalNativeAttr(wb, "minCols", sheet.getMinCols());
221 encodeOptionalNativeAttr(wb, "maxRows", sheet.getMaxRows());
222 encodeOptionalNativeAttr(wb, "maxCols", sheet.getMaxCols());
223 encodeOptionalAttr(wb, "stretchH", sheet.getStretchH());
224 encodeOptionalAttr(wb, "language", sheet.getLocale());
225 encodeOptionalAttr(wb, "selectionMode", sheet.getSelectionMode());
226 encodeOptionalAttr(wb, "activeHeaderClassName", sheet.getActiveHeaderStyleClass());
227 encodeOptionalAttr(wb, "commentedCellClassName", sheet.getCommentedCellStyleClass());
228 encodeOptionalAttr(wb, "currentRowClassName", sheet.getCurrentRowStyleClass());
229 encodeOptionalAttr(wb, "currentColClassName", sheet.getCurrentColStyleClass());
230 encodeOptionalAttr(wb, "currentHeaderClassName", sheet.getCurrentHeaderStyleClass());
231 encodeOptionalAttr(wb, "invalidCellClassName", sheet.getInvalidCellStyleClass());
232 encodeOptionalAttr(wb, "noWordWrapClassName", sheet.getNoWordWrapStyleClass());
233 encodeOptionalAttr(wb, "placeholderCellClassName", sheet.getPlaceholderCellStyleClass());
234 encodeOptionalAttr(wb, "readOnlyCellClassName", sheet.getReadOnlyCellStyleClass());
235 encodeOptionalNativeAttr(wb, "extender", sheet.getExtender());
236
237 String emptyMessage = sheet.getEmptyMessage();
238 if (LangUtils.isBlank(emptyMessage)) {
239 emptyMessage = "No Records Found";
240 }
241 encodeOptionalAttr(wb, "emptyMessage", emptyMessage);
242
243 encodeColHeaders(sheet, wb);
244 encodeColOptions(sheet, wb);
245 wb.finish();
246 }
247
248
249
250
251
252
253 protected void encodeInvalidData(final Sheet sheet, final WidgetBuilder wb)
254 throws IOException {
255 wb.attr("errors", sheet.getInvalidDataValue());
256 }
257
258
259
260
261
262
263 protected void encodeColHeaders(final Sheet sheet, final WidgetBuilder wb)
264 throws IOException {
265 final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, false);
266 for (final SheetColumn column : sheet.getColumns()) {
267 if (!column.isRendered()) {
268 continue;
269 }
270 vb.appendArrayValue(column.getHeaderText(), true);
271 }
272 wb.nativeAttr("colHeaders", vb.closeVar().toString());
273 }
274
275
276
277
278
279
280 protected void encodeColOptions(final Sheet sheet, final WidgetBuilder wb)
281 throws IOException {
282 final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, false);
283 for (final SheetColumn column : sheet.getColumns()) {
284 if (!column.isRendered()) {
285 continue;
286 }
287
288 final JavascriptVarBuilder options = new JavascriptVarBuilder(null, true);
289 options.appendProperty("type", column.getColType(), true);
290 options.appendProperty("copyable", "true", false);
291 final Integer width = column.getColWidth();
292 String calculatedWidth = null;
293 if (width != null) {
294 calculatedWidth = width.toString();
295 }
296
297
298 if (!column.isVisible()) {
299 calculatedWidth = "0.1";
300 }
301 if (calculatedWidth != null) {
302 options.appendProperty("width", calculatedWidth, false);
303 }
304 if (column.isReadOnly()) {
305 options.appendProperty("readOnly", "true", false);
306 }
307 options.appendProperty("trimWhitespace", column.isTrimWhitespace().toString(), false);
308 options.appendProperty("wordWrap", column.isWordWrap().toString(), false);
309
310
311 final String validateFunction = column.getOnvalidate();
312 if (validateFunction != null) {
313 final boolean quoted;
314 switch (validateFunction) {
315 case "autocomplete":
316 case "date":
317 case "numeric":
318 case "time":
319 quoted = true;
320 break;
321
322 default:
323
324 quoted = false;
325 break;
326 }
327 options.appendProperty("validator", validateFunction, quoted);
328 }
329
330 switch (column.getColType()) {
331 case "password":
332 final Integer passwordLength = column.getPasswordHashLength();
333 if (passwordLength != null) {
334 options.appendProperty("hashLength", passwordLength.toString(), false);
335 }
336 final String passwordSymbol = column.getPasswordHashSymbol();
337 if (passwordSymbol != null) {
338 options.appendProperty("hashSymbol", passwordSymbol, true);
339 }
340 break;
341 case "numeric":
342 final JavascriptVarBuilder numeric = new JavascriptVarBuilder(null, true);
343 final String pattern = column.getNumericPattern();
344 if (pattern != null) {
345 numeric.appendProperty("pattern", pattern, true);
346 }
347 final String culture = column.getNumericLocale();
348 if (culture != null) {
349 numeric.appendProperty("culture", culture, true);
350 }
351 options.appendProperty("numericFormat", numeric.closeVar().toString(), false);
352 break;
353 case "date":
354 options.appendProperty("dateFormat", column.getDateFormat(), true);
355 options.appendProperty("correctFormat", "true", false);
356 final String dateConfig = column.getDatePickerConfig();
357 if (dateConfig != null) {
358 options.appendProperty("datePickerConfig", dateConfig, false);
359 }
360 break;
361 case "time":
362 options.appendProperty("timeFormat", column.getTimeFormat(), true);
363 options.appendProperty("correctFormat", "true", false);
364 break;
365 case "dropdown":
366 encodeSelectItems(column, options);
367 break;
368 case "autocomplete":
369 options.appendProperty("strict", Boolean.toString(column.isAutoCompleteStrict()), false);
370 options.appendProperty("allowInvalid", Boolean.toString(column.isAutoCompleteAllowInvalid()),
371 false);
372 options.appendProperty("trimDropdown", Boolean.toString(column.isAutoCompleteTrimDropdown()),
373 false);
374 final Integer visibleRows = column.getAutoCompleteVisibleRows();
375 if (visibleRows != null) {
376 options.appendProperty("visibleRows", visibleRows.toString(), false);
377 }
378 encodeSelectItems(column, options);
379 break;
380 default:
381 break;
382 }
383
384 vb.appendArrayValue(options.closeVar().toString(), false);
385 }
386 wb.nativeAttr("columns", vb.closeVar().toString());
387 }
388
389 private void encodeSelectItems(final SheetColumn column, final JavascriptVarBuilder options) {
390 final JavascriptVarBuilder items = new JavascriptVarBuilder(null, false);
391 final Object value = column.getSelectItems();
392 if (value == null) {
393 return;
394 }
395 if (value.getClass().isArray()) {
396 for (int j = 0; j < Array.getLength(value); j++) {
397 final Object item = Array.get(value, j);
398 items.appendArrayValue(String.valueOf(item), true);
399 }
400 }
401 else if (value instanceof Collection) {
402 final Collection collection = (Collection) value;
403 for (final Object item : collection) {
404 items.appendArrayValue(String.valueOf(item), true);
405 }
406 }
407 else if (value instanceof Map) {
408 final Map map = (Map) value;
409
410 for (final Object item : map.keySet()) {
411 items.appendArrayValue(String.valueOf(item), true);
412 }
413 }
414
415 options.appendProperty("source", items.closeVar().toString(), false);
416 }
417
418
419
420
421 protected void encodeData(final FacesContext context, final Sheet sheet, final WidgetBuilder wb)
422 throws IOException {
423
424 final JavascriptVarBuilder jsData = new JavascriptVarBuilder(null, false);
425 final JavascriptVarBuilder jsRowKeys = new JavascriptVarBuilder(null, false);
426 final JavascriptVarBuilder jsStyle = new JavascriptVarBuilder(null, true);
427 final JavascriptVarBuilder jsRowStyle = new JavascriptVarBuilder(null, false);
428 final JavascriptVarBuilder jsReadOnly = new JavascriptVarBuilder(null, true);
429 final JavascriptVarBuilder jsRowHeaders = new JavascriptVarBuilder(null, false);
430
431 final boolean isCustomHeader = sheet.getRowHeaderValueExpression() != null;
432
433 final List<Object> values = sheet.getSortedValues();
434 int row = 0;
435 for (final Object value : values) {
436 context.getExternalContext().getRequestMap().put(sheet.getVar(), value);
437 final String rowKey = sheet.getRowKeyValueAsString(context);
438 jsRowKeys.appendArrayValue(rowKey, true);
439 encodeRow(context, rowKey, jsData, jsRowStyle, jsStyle, jsReadOnly, sheet, row);
440
441
442
443 if (sheet.isShowRowHeaders() && isCustomHeader) {
444 final String rowHeader = sheet.getRowHeaderValueAsString(context);
445 jsRowHeaders.appendArrayValue(rowHeader, true);
446 }
447 row++;
448 }
449
450 sheet.setRowVar(context, null);
451
452 wb.nativeAttr("data", jsData.closeVar().toString());
453 wb.nativeAttr("styles", jsStyle.closeVar().toString());
454 wb.nativeAttr("rowStyles", jsRowStyle.closeVar().toString());
455 wb.nativeAttr("readOnlyCells", jsReadOnly.closeVar().toString());
456 wb.nativeAttr("rowKeys", jsRowKeys.closeVar().toString());
457
458
459 if (!isCustomHeader) {
460 wb.nativeAttr("rowHeaders", Boolean.toString(sheet.isShowRowHeaders()));
461 }
462 else {
463 wb.nativeAttr("rowHeaders", jsRowHeaders.closeVar().toString());
464 }
465 }
466
467
468
469
470
471
472 protected JavascriptVarBuilder encodeRow(final FacesContext context, final String rowKey,
473 final JavascriptVarBuilder jsData, final JavascriptVarBuilder jsRowStyle,
474 final JavascriptVarBuilder jsStyle, final JavascriptVarBuilder jsReadOnly, final Sheet sheet,
475 final int rowIndex) {
476
477 final String rowStyleClass = sheet.getRowStyleClass();
478 if (rowStyleClass == null) {
479 jsRowStyle.appendArrayValue("null", false);
480 }
481 else {
482 jsRowStyle.appendArrayValue(rowStyleClass, true);
483 }
484
485
486 final JavascriptVarBuilder jsRow = new JavascriptVarBuilder(null, false);
487 int renderCol = 0;
488 for (int col = 0; col < sheet.getColumns().size(); col++) {
489 final SheetColumn column = sheet.getColumns().get(col);
490 if (!column.isRendered()) {
491 continue;
492 }
493
494
495 final String value = sheet.getRenderValueForCell(context, rowKey, col);
496 jsRow.appendArrayValue(value, true);
497
498
499 final String styleClass = column.getStyleClass();
500 if (styleClass != null) {
501 jsStyle.appendRowColProperty(rowIndex, renderCol, styleClass, true);
502 }
503
504
505 final boolean readOnly = column.isReadonlyCell();
506 if (readOnly) {
507 jsReadOnly.appendRowColProperty(rowIndex, renderCol, "true", true);
508 }
509 renderCol++;
510 }
511
512 jsData.appendArrayValue(jsRow.closeVar().toString(), false);
513 return jsData;
514 }
515
516
517
518
519 private void encodeHiddenInputs(final FacesContext fc, final Sheet sheet, final String clientId)
520 throws IOException {
521 renderHiddenInput(fc, clientId + "_input", null, false);
522 renderHiddenInput(fc, clientId + "_focus", sheet.getFocusId(), false);
523 renderHiddenInput(fc, clientId + "_selection", sheet.getSelection(), false);
524 renderHiddenInput(fc, clientId + "_sortby", Integer.toString(sheet.getSortColRenderIndex()), false);
525 renderHiddenInput(fc, clientId + "_sortorder", sheet.getSortOrder().toLowerCase(), false);
526 }
527
528
529
530
531
532
533
534
535
536 protected void encodeKeyboardTrap(final FacesContext context, final Sheet sheet)
537 throws IOException {
538 final ResponseWriter writer = context.getResponseWriter();
539 final String id = sheet.getClientId(context) + "_keyboard";
540 final String widgetVar = sheet.resolveWidgetVar(context);
541 writer.startElement("div", null);
542 writer.writeAttribute("class", "ui-helper-hidden-accessible", null);
543 writer.startElement("input", null);
544 writer.writeAttribute("id", id, null);
545 writer.writeAttribute("name", id, null);
546 writer.writeAttribute("type", "text", null);
547 writer.writeAttribute("autocomplete", "off", null);
548 writer.writeAttribute(HTML.ARIA_HIDDEN, "true", null);
549 writer.writeAttribute("tabindex", sheet.getTabindex(), null);
550 writer.writeAttribute("onfocus", String.format("PF('%s').focus();", widgetVar), null);
551 writer.endElement("input");
552 writer.endElement("div");
553 }
554
555
556
557
558 private void encodeBehaviors(final FacesContext context, final Sheet sheet, final WidgetBuilder wb)
559 throws IOException {
560
561
562 final Map<String, List<ClientBehavior>> behaviors = sheet.getClientBehaviors();
563
564 final List<ClientBehaviorContext.Parameter> params = null;
565
566 wb.append(",behaviors:{");
567 final String clientId = sheet.getClientId(context);
568
569
570 if (behaviors.containsKey("sort")) {
571 final ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
572 sheet, "sort", clientId, params);
573 final AjaxBehavior ajaxBehavior = (AjaxBehavior) behaviors.get("sort").get(0);
574 ajaxBehavior.setUpdate(ExtLangUtils.defaultString(ajaxBehavior.getUpdate()) + " " + clientId);
575 wb.append("sort").append(":").append("function(s, event)").append("{")
576 .append(behaviors.get("sort").get(0).getScript(behaviorContext)).append("}");
577 }
578 else {
579
580 wb.append("sort").append(":").append("function(s, event)").append("{").append("PrimeFaces.ab({source: '")
581 .append(clientId).append("',event: 'sort', process: '").append(clientId).append("', update: '")
582 .append(clientId).append("'});}");
583 }
584
585
586 if (behaviors.containsKey("filter")) {
587 final ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
588 sheet, "filter", clientId, params);
589 final AjaxBehavior ajaxBehavior = (AjaxBehavior) behaviors.get("filter").get(0);
590 ajaxBehavior.setUpdate(ExtLangUtils.defaultString(ajaxBehavior.getUpdate()) + " " + clientId);
591 wb.callback("filter", "function(source, event)", behaviors.get("filter").get(0).getScript(behaviorContext));
592 }
593 else {
594
595 wb.callback("filter", "function(source, event)", "PrimeFaces.ab({s: '" + clientId
596 + "', event: 'filter', process: '" + clientId + "', update: '" + clientId + "'});");
597 }
598
599 if (behaviors.containsKey("change")) {
600 final ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
601 sheet, "change", clientId, params);
602 wb.callback("change", "function(source, event)", behaviors.get("change").get(0).getScript(behaviorContext));
603 }
604
605 if (behaviors.containsKey("cellSelect")) {
606 final ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
607 sheet, "cellSelect", clientId, params);
608 wb.callback("cellSelect", "function(source, event)",
609 behaviors.get("cellSelect").get(0).getScript(behaviorContext));
610 }
611
612 if (behaviors.containsKey("columnSelect")) {
613 final ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
614 sheet, "columnSelect", clientId, params);
615 wb.callback("columnSelect", "function(source, event)",
616 behaviors.get("columnSelect").get(0).getScript(behaviorContext));
617 }
618
619 if (behaviors.containsKey("rowSelect")) {
620 final ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
621 sheet, "rowSelect", clientId, params);
622 wb.callback("rowSelect", "function(source, event)",
623 behaviors.get("rowSelect").get(0).getScript(behaviorContext));
624 }
625
626 wb.append("}");
627 }
628
629
630
631
632 private void encodeFooter(final FacesContext context, final ResponseWriter responseWriter, final Sheet sheet)
633 throws IOException {
634
635 final UIComponent footer = sheet.getFacet("footer");
636 if (FacetUtils.shouldRenderFacet(footer)) {
637 responseWriter.startElement("div", null);
638 responseWriter.writeAttribute(Attrs.CLASS, "ui-datatable-footer ui-widget-header ui-corner-bottom", null);
639 footer.encodeAll(context);
640 responseWriter.endElement("div");
641 }
642 }
643
644
645
646
647 private void encodeHeader(final FacesContext context, final ResponseWriter responseWriter, final Sheet sheet)
648 throws IOException {
649
650 final UIComponent header = sheet.getFacet("header");
651 if (FacetUtils.shouldRenderFacet(header)) {
652 responseWriter.startElement("div", null);
653 responseWriter.writeAttribute(Attrs.CLASS, "ui-datatable-header ui-widget-header ui-corner-top", null);
654 header.encodeAll(context);
655 responseWriter.endElement("div");
656 }
657 }
658
659
660
661
662 protected void encodeFilterValues(final ResponseWriter responseWriter,
663 final Sheet sheet, final String clientId) throws IOException {
664 int renderCol = 0;
665 for (final SheetColumn column : sheet.getColumns()) {
666 if (!column.isRendered()) {
667 continue;
668 }
669
670 if (column.getValueExpression("filterBy") != null) {
671 responseWriter.startElement("input", null);
672 responseWriter.writeAttribute("id", clientId + "_filter_" + renderCol, "id");
673 responseWriter.writeAttribute("name", clientId + "_filter_" + renderCol, "name");
674 responseWriter.writeAttribute("type", "hidden", null);
675 responseWriter.writeAttribute("value", column.getFilterValue(), null);
676 responseWriter.endElement("input");
677 }
678
679 renderCol++;
680 }
681 }
682
683
684
685
686
687
688 protected void encodeFilterVar(final Sheet sheet, final WidgetBuilder wb)
689 throws IOException {
690 final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, false);
691
692 for (final SheetColumn column : sheet.getColumns()) {
693 if (!column.isRendered()) {
694 continue;
695 }
696
697 if (column.getValueExpression("filterBy") == null) {
698 vb.appendArrayValue("false", true);
699 continue;
700 }
701
702 final Collection<SelectItem> options = column.getFilterOptions();
703 if (options == null) {
704 vb.appendArrayValue("true", true);
705 }
706 else {
707 final JavascriptVarBuilder vbOptions = new JavascriptVarBuilder(null, false);
708 for (final SelectItem item : options) {
709 vbOptions.appendArrayValue(
710 "{ label: \"" + item.getLabel() + "\", value: \"" + item.getValue() + "\"}", false);
711 }
712 vb.appendArrayValue(vbOptions.closeVar().toString(), false);
713 }
714
715 }
716 wb.nativeAttr("filters", vb.closeVar().toString());
717 }
718
719
720
721
722
723 protected void encodeSortVar(final Sheet sheet, final WidgetBuilder wb)
724 throws IOException {
725 final JavascriptVarBuilder vb = new JavascriptVarBuilder(null, false);
726
727 for (final SheetColumn column : sheet.getColumns()) {
728 if (!column.isRendered()) {
729 continue;
730 }
731
732 if (column.getValueExpression("sortBy") == null) {
733 vb.appendArrayValue("false", false);
734 }
735 else {
736 vb.appendArrayValue("true", false);
737 }
738 }
739 wb.nativeAttr("sortable", vb.closeVar().toString());
740 }
741
742
743
744
745
746
747
748
749
750 @Override
751 public void decode(final FacesContext context, final UIComponent component) {
752 final Sheet sheet = (Sheet) component;
753
754
755 for (final SheetColumn column : sheet.getColumns()) {
756 column.setSheet(sheet);
757 }
758
759
760 sheet.getUpdates().clear();
761
762
763
764 final Map<String, String> params = context.getExternalContext().getRequestParameterMap();
765 final String clientId = sheet.getClientId(context);
766
767
768 final String jsonUpdates = params.get(clientId + "_input");
769 final String jsonSelection = params.get(clientId + "_selection");
770
771
772 decodeSubmittedValues(sheet, jsonUpdates);
773
774
775 decodeSelection(sheet, jsonSelection);
776
777
778 decodeBehaviors(context, sheet);
779
780
781 decodeFilters(sheet, params, clientId);
782
783 final String sortBy = params.get(clientId + "_sortby");
784 final String sortOrder = params.get(clientId + "_sortorder");
785 if (sortBy != null) {
786 int col = Integer.parseInt(sortBy);
787 if (col >= 0) {
788 col = sheet.getMappedColumn(col);
789 sheet.saveSortByColumn(sheet.getColumns().get(col).getId());
790 }
791 }
792
793 if (sortOrder != null) {
794 sheet.setSortOrder(sortOrder);
795 }
796
797 final String focus = params.get(clientId + "_focus");
798 sheet.setFocusId(focus);
799 }
800
801
802
803
804 protected void decodeFilters(final Sheet sheet, final Map<String, String> params,
805 final String clientId) {
806 int renderCol = 0;
807 for (final SheetColumn column : sheet.getColumns()) {
808 if (!column.isRendered()) {
809 continue;
810 }
811
812 if (column.getValueExpression("filterBy") != null) {
813 final String value = params.get(clientId + "_filter_" + renderCol);
814 column.setFilterValue(value);
815 }
816
817 renderCol++;
818 }
819 }
820
821
822
823
824
825
826
827 @Override
828 protected void decodeBehaviors(final FacesContext context, final UIComponent component) {
829
830
831 final Map<String, List<ClientBehavior>> behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
832
833
834 if (behaviors.isEmpty()) {
835 return;
836 }
837
838
839 final Map<String, String> params = context.getExternalContext().getRequestParameterMap();
840 final String behaviorEvent = params.get("javax.faces.behavior.event");
841
842
843 if (behaviorEvent == null) {
844 return;
845 }
846
847
848 final List<ClientBehavior> behaviorsForEvent = behaviors.get(behaviorEvent);
849 if (behaviorsForEvent == null || behaviorsForEvent.isEmpty()) {
850 return;
851 }
852
853
854 final String behaviorSource = params.get("javax.faces.source");
855 final String clientId = component.getClientId();
856 if (clientId.equals(behaviorSource)) {
857 for (final ClientBehavior behavior : behaviorsForEvent) {
858 behavior.decode(context, component);
859 }
860 }
861 }
862
863
864
865
866 private void decodeSelection(final Sheet sheet, final String jsonSelection) {
867 if (LangUtils.isBlank(jsonSelection)) {
868 return;
869 }
870
871 try {
872
873 final JSONArray array = new JSONArray(jsonSelection);
874 if (array.get(0) instanceof JSONArray) {
875
876 for (int i = 0; i < array.length(); i++) {
877 updateSheetSelection(sheet, array.getJSONArray(i));
878 }
879 }
880 else {
881
882 updateSheetSelection(sheet, array);
883 }
884 sheet.setSelection(jsonSelection);
885 }
886 catch (final JSONException e) {
887 throw new FacesException("Failed parsing Ajax JSON message for cell selection event:" + e.getMessage(),
888 e);
889 }
890 }
891
892 private void updateSheetSelection(final Sheet sheet, final JSONArray array) throws JSONException {
893
894 sheet.setSelectedRow(array.getInt(0));
895 sheet.setSelectedColumn(sheet.getMappedColumn(array.getInt(1)));
896 sheet.setSelectedLastRow(array.getInt(2));
897 sheet.setSelectedLastColumn(array.getInt(3));
898 }
899
900
901
902
903 private void decodeSubmittedValues(final Sheet sheet, final String jsonData) {
904 if (LangUtils.isBlank(jsonData)) {
905 return;
906 }
907
908 try {
909
910
911
912
913
914 final JSONObject obj = new JSONObject(jsonData);
915 final Iterator<String> keys = obj.keys();
916 while (keys.hasNext()) {
917 final String key = keys.next();
918
919 final JSONArray update = obj.getJSONArray(key);
920
921 if (update.isNull(4)) {
922 continue;
923 }
924 final String rowKey = update.getString(4);
925 final int col = sheet.getMappedColumn(update.getInt(1));
926 final String newValue = String.valueOf(update.get(3));
927 sheet.setSubmittedValue(rowKey, col, newValue);
928 }
929 }
930 catch (final JSONException ex) {
931 throw new FacesException("Failed parsing Ajax JSON message for cell change event:" + ex.getMessage(),
932 ex);
933 }
934 }
935
936
937
938
939 @Override
940 public boolean getRendersChildren() {
941 return true;
942 }
943
944 }