package org.nocket.component.table.js; import java.util.List; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxNavigationToolbar; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractToolbar; import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.NoRecordsToolbar; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.OddEvenItem; import org.apache.wicket.model.IModel; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.resource.PackageResourceReference; import org.apache.wicket.util.string.Strings; import org.nocket.component.header.jquery.JQueryHelper; import org.nocket.component.table.IRowItemSettable; import org.nocket.component.table.ReflectionUtil; import org.nocket.component.table.TableItemPosition; import org.nocket.component.table.behavior.ClickAjaxEventBehavior; import org.nocket.component.table.behavior.DblClickAjaxEventBehavior; import org.nocket.component.table.behavior.IRowClickEventAware; /** * Table with Java-Script sort capability. It depends on JQuery Library. * * @author blaz02 * * @param <T> * Model object type following Java-Bean convention. * */ @SuppressWarnings("serial") public class DMDJavaScriptDataTable<T> extends DataTable<T, String> implements IRowClickEventAware<T>, IRowItemSettable { private IRowClickEventAware<T> rowClickDelegate; private SortableDataProvider<T, String> dataProvider; private Class rowItemClass; public DMDJavaScriptDataTable(String id, List<IColumn<T, String>> columns, SortableDataProvider<T, String> dataProvider, int rowsPerPage, TableItemPosition navigationbarPosition) { super(id, columns, dataProvider, rowsPerPage); this.dataProvider = dataProvider; addToolbar(navigationbarPosition, newNavigationToolbar()); addToolbar(TableItemPosition.top, new JavaScriptHeaderToolbar(this, dataProvider)); addToolbar(TableItemPosition.bottom, new NoRecordsToolbar(this)); setOutputMarkupId(true); } protected void addToolbar(TableItemPosition position, AbstractToolbar abstractToolbar) { if (TableItemPosition.bottom.equals(position)) { addBottomToolbar(abstractToolbar); } else { addTopToolbar(abstractToolbar); } } /** * Create a navigation toolbar for the data table. Returns a * DMDAjaxNavigationToolbar by default. Override it with: * * <pre> * return new NavigationToolbar(this); * </pre> * * if you want to page the table with the classic way. * * * @return the desired navigation toolbar */ protected AbstractToolbar newNavigationToolbar() { return new AjaxNavigationToolbar(this); } @Override public void renderHead(IHeaderResponse response) { super.renderHead(response); JQueryHelper.initJQuery(response); response.render(JavaScriptHeaderItem.forReference( new PackageResourceReference(DMDJavaScriptDataTable.class, "jquery.tablesorter.min.js"))); response.render(JavaScriptHeaderItem.forScript("Wicket.Event.add(window, \"domready\", " + "function(event) { " + jsInitScript() + ";});", "js_table_sorter")); } @Override protected void onConfigure() { super.onConfigure(); AjaxRequestTarget ajaxRequestTarget = RequestCycle.get().find(AjaxRequestTarget.class); if (ajaxRequestTarget != null) { ajaxRequestTarget.appendJavaScript("Wicket.Event.add(window, \"domready\", " + "function(event) { " + jsInitScript() + ";});"); } } @Override protected Item<T> newRowItem(String id, int index, final IModel<T> model) { Class clazz = rowItemClass != null ? rowItemClass : OddEvenItem.class; Item<T> item = (Item<T>) ReflectionUtil.newInstance(clazz, new Class[] { String.class, int.class, IModel.class }, new Object[] { id, index, model }); // Add event listeners to each row // Doubleclick listener DblClickAjaxEventBehavior<T> newOnDblClicktEvent = this.newOnDblClickEvent(model); if (newOnDblClicktEvent != null) item.add(newOnDblClicktEvent); // Singleclick listener ClickAjaxEventBehavior<T> newOnClickEvent = this.newOnClickEvent(model); if (newOnClickEvent != null) item.add(newOnClickEvent); return item; } @Override public void onComponentTag(final ComponentTag tag) { String className = "sortable"; CharSequence oldClassName = tag.getAttribute("class"); if (Strings.isEmpty(oldClassName)) { tag.put("class", className); } else { tag.put("class", oldClassName + " " + className); } super.onComponentTag(tag); } public void setRowClickDelegate(IRowClickEventAware<T> rowClickDelegate) { this.rowClickDelegate = rowClickDelegate; } public DblClickAjaxEventBehavior<T> newOnDblClickEvent(IModel<T> model) { return rowClickDelegate == null ? null : rowClickDelegate.newOnDblClickEvent(model); } public ClickAjaxEventBehavior<T> newOnClickEvent(IModel<T> model) { return rowClickDelegate == null ? null : rowClickDelegate.newOnClickEvent(model); } @Override public void setRowItemClass(Class rowItemClass) { this.rowItemClass = rowItemClass; } /** * Returns model for proper initialization of tablesorter. Method builds * Java-Script snippet which must be placed after the table and rendered * after request (page get as well as ajax). Example: * * <pre> * $('table.sortable').tablesorter({ headers: { 1: { sorter: false}, 2: {sorter: false} }, sortList: [[3,0]] }); * </pre> * * Second and third columns are not sortable. Initial sort is put on the * fourth column. * * @return JS Snippet to initialize the JQuery Tablesorter */ public String jsInitScript() { final StringBuilder sb = new StringBuilder(); int columnIdx = 0; int sortColumnIdx = -1; boolean appended = false; String initialSortProperty = null; SortParam<String> sort = dataProvider.getSort(); if (sort != null) { initialSortProperty = sort.getProperty(); } sb.append("$('table.sortable').tablesorter({ headers: {"); for (IColumn<?, String> column : getColumns()) { if (column.getSortProperty() == null) { if (appended) sb.append(","); sb.append(columnIdx).append(": { sorter: false } "); appended = true; } else { if (column.getSortProperty().equalsIgnoreCase(initialSortProperty)) sortColumnIdx = columnIdx; } columnIdx++; } ; // Sort initial state if (sortColumnIdx > -1) { sb.append("}, sortList: [[" + sortColumnIdx + ",0]]"); } else { sb.append("}"); } sb.append("});"); return sb.toString(); } }