Snippets
Created by
Arne Vandamme
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | /*
* Copyright 2014 the original author or authors
*
* 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.foreach.across.samples.entity.application.controllers;
import com.foreach.across.core.annotations.Event;
import com.foreach.across.modules.adminweb.annotations.AdminWebController;
import com.foreach.across.modules.adminweb.menu.AdminMenuEvent;
import com.foreach.across.modules.bootstrapui.elements.BootstrapUiFactory;
import com.foreach.across.modules.bootstrapui.elements.GlyphIcon;
import com.foreach.across.modules.bootstrapui.elements.TableViewElement;
import com.foreach.across.modules.entity.views.EntityViewElementBuilderHelper;
import com.foreach.across.modules.entity.views.bootstrapui.util.SortableTableBuilder;
import com.foreach.across.modules.entity.views.util.EntityViewElementUtils;
import com.foreach.across.modules.web.ui.ViewElement;
import com.foreach.across.modules.web.ui.ViewElementBuilderContext;
import com.foreach.across.modules.web.ui.elements.ContainerViewElement;
import com.foreach.across.modules.web.ui.elements.TextViewElement;
import com.foreach.across.samples.entity.application.business.Partner;
import com.foreach.across.samples.entity.application.repositories.PartnerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static com.foreach.across.modules.bootstrapui.elements.Style.Table.BORDERED;
import static com.foreach.across.modules.bootstrapui.elements.Style.Table.CONDENSED;
import static com.foreach.across.modules.web.ui.elements.support.ContainerViewElementUtils.find;
/**
* Generates some tables using the {@link SortableTableBuilder}. Does not include the default javascript
* for activating client-side support of paging and sorting. The different tables demonstrate some of the
* features of the {@link SortableTableBuilder}.
* <p/>
* These demo pages expect a Partner entity with a *name* and *url* property. At least 3 partner entities
* should exist (with id -1, -2, -3) for this controller to work.
*
* @author Arne Vandamme
* @see SortableTableWithPagingController
* @since 2.0.0
*/
@AdminWebController
@RequestMapping("/sortableTable")
public class SortableTableSimpleController
{
private PartnerRepository partnerRepository;
private EntityViewElementBuilderHelper builderHelper;
private BootstrapUiFactory bootstrapUiFactory;
@Autowired
public SortableTableSimpleController( PartnerRepository partnerRepository,
EntityViewElementBuilderHelper builderHelper,
BootstrapUiFactory bootstrapUiFactory ) {
this.partnerRepository = partnerRepository;
this.builderHelper = builderHelper;
this.bootstrapUiFactory = bootstrapUiFactory;
}
/**
* Register the section in the administration menu.
*/
@Event
@SuppressWarnings("unused")
protected void registerMenuItems( AdminMenuEvent adminMenu ) {
adminMenu.builder()
.group( "/test", "Functionality demos" ).and()
.group( "/test/st", "Sortable tables" ).and()
.item( "/test/st/noPaging", "Paging/sorting disabled", "/sortableTable" ).order( 1 )
.and()
.item( "/test/st/paging", "Paging/sorting enabled", "/sortableTableWithPaging" )
.order( 2 );
}
/**
* Entry point that adds the different tables to the model.
* This method does not much more but dispatch to the specific table creation methods.
* See the separate methods for more documentation.
*/
@RequestMapping(method = RequestMethod.GET)
public String listSortableTables( Model model, ViewElementBuilderContext builderContext ) {
List<Partner> partners = partnerRepository.findAll();
model.addAttribute(
"message",
"These tables do not support paging or sorting because the default javascript is not included."
);
Map<String, ViewElement> generatedTables = new LinkedHashMap<>();
generatedTables.put(
"Minimal table configuration - listing all properties",
minimalTableOfAllProperties( partners, builderContext )
);
generatedTables.put(
"Table without any results",
noResultsTable( builderContext )
);
generatedTables.put(
"Table with specific properties and custom styling",
styledTableWithSelectedProperties( partners, builderContext )
);
generatedTables.put(
"Table with footer and styling added after being generated",
postProcessedTable( partners, builderContext )
);
generatedTables.put(
"Table with additional cell",
tableWithCustomCell( partners, builderContext )
);
model.addAttribute( "generatedTables", generatedTables );
return "th/entityModuleTest/sortableTables";
}
/**
* [1]
* Generates a table with only the minimum number of properties of SortableTableBuilder set.
* All builders are pre-configured using the EntityConfiguration of our Partner entity.
* This is done in the EntityViewElementBuilderHelper class.
*/
private ViewElement minimalTableOfAllProperties( List<Partner> partners,
ViewElementBuilderContext builderContext ) {
return builderHelper.createSortableTableBuilder( Partner.class )
.items( partners ) // rows in the table
.properties( "*" ) // columns - render all default properties of Partner
.build( builderContext ); // build the actual TableViewElement (and surrounding containers)
}
/**
* [2]
* Generates a table that does not have any results, because we do not add any items.
* The default noResults panel will be generated.
*/
private ViewElement noResultsTable( ViewElementBuilderContext builderContext ) {
return builderHelper.createSortableTableBuilder( Partner.class )
.properties( "*" )
.build( builderContext );
}
/**
* [3]
* Customizes the look and feel of the table using the methods available on the builder.
* These cover most of the common use cases like rendering only the table, disabling sorting etc.
*/
private ViewElement styledTableWithSelectedProperties( List<Partner> partners,
ViewElementBuilderContext builderContext ) {
return builderHelper.createSortableTableBuilder( Partner.class )
.items( partners )
.properties( "id", "url", "name" ) // specify the properties in order
.tableStyles( CONDENSED, BORDERED ) // add some bootstrap table styles
.tableOnly() // only render the table - not the surrounding panel with paging/results information
.noSorting() // disable sorting on all properties
.hideResultNumber() // hide the result number column
.build( builderContext );
}
/**
* [4]
* Generate the default table but make some changes to the ViewElement after it has been built.
* Not necessarily the easiest or even best way to achieve what you want, but it can be done.
* This code demonstrates making view elements directly, skipping the BootstrapUiFactory.
* <p>
* IMPORTANT: SortableTableBuilder uses a ViewElementGenerator for the building of the rows. That means
* the rows itself are actually only built when being rendered. That means it is not possible to actually
* modify the generated rows individually.
*/
private ViewElement postProcessedTable( List<Partner> partners, ViewElementBuilderContext builderContext ) {
ContainerViewElement container = builderHelper.createSortableTableBuilder( Partner.class )
.items( partners )
.properties( "*" )
.build( builderContext );
// after the table has been generated we receive a container of elements (including the panel),
// find the actual table element and make some modifications
find( container, SortableTableBuilder.ELEMENT_TABLE, TableViewElement.class )
.ifPresent( table -> {
// set custom style attribute
table.setAttribute( "style", "border: solid 3px red;" );
// manually create ViewElement instances
TableViewElement.Footer footer = new TableViewElement.Footer();
TableViewElement.Row footerRow = new TableViewElement.Row();
TableViewElement.Cell footerCell = new TableViewElement.Cell();
footerCell.setColumnSpan( 3 );
footerCell.addChild( new TextViewElement( "Manually added footer row." ) );
footerRow.addChild( footerCell );
footer.addChild( footerRow );
table.setFooter( footer );
}
);
return container;
}
/**
* [5]
* Customize the table by adding a column with a link that opens the partner url in a new window.
* Illustrates how you can access the entity for which the row is being generated.
*/
private ViewElement tableWithCustomCell( List<Partner> partners,
ViewElementBuilderContext builderContext ) {
return builderHelper
.createSortableTableBuilder( Partner.class )
.items( partners )
.properties( "*" )
.headerRowProcessor( ( ctx, element ) -> {
// add cell to the header
element.addChild( bootstrapUiFactory.table().heading().build( ctx ) );
} )
.valueRowProcessor( ( ctx, element ) -> {
Partner partner = EntityViewElementUtils.currentEntity( ctx, Partner.class );
// add cell linking to the url of the partner
element.addChild(
bootstrapUiFactory.table().cell().add(
bootstrapUiFactory.button()
.link( partner.getUrl() )
.icon( new GlyphIcon( GlyphIcon.NEW_WINDOW ) )
.iconOnly()
.attribute( "target", "_blank" )
.text( "Visit partner website" )
).build( ctx )
);
} )
.build( builderContext );
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | /*
* Copyright 2014 the original author or authors
*
* 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.foreach.across.samples.entity.application.controllers;
import com.foreach.across.modules.adminweb.annotations.AdminWebController;
import com.foreach.across.modules.bootstrapui.elements.BootstrapUiFactory;
import com.foreach.across.modules.bootstrapui.elements.TableViewElement;
import com.foreach.across.modules.entity.EntityModule;
import com.foreach.across.modules.entity.views.EntityViewElementBuilderHelper;
import com.foreach.across.modules.entity.views.bootstrapui.util.SortableTableBuilder;
import com.foreach.across.modules.entity.views.util.EntityViewElementUtils;
import com.foreach.across.modules.web.resource.WebResource;
import com.foreach.across.modules.web.resource.WebResourceRegistry;
import com.foreach.across.modules.web.ui.ViewElement;
import com.foreach.across.modules.web.ui.ViewElementBuilderContext;
import com.foreach.across.samples.entity.application.business.Partner;
import com.foreach.across.samples.entity.application.repositories.PartnerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Generates some tables using the {@link SortableTableBuilder} and includes the client-side support
* for paging and sorting.
*
* @author Arne Vandamme
* @see SortableTableSimpleController
* @since 2.0.0
*/
@AdminWebController
@RequestMapping("/sortableTableWithPaging")
public class SortableTableWithPagingController
{
private PartnerRepository partnerRepository;
private EntityViewElementBuilderHelper builderHelper;
private BootstrapUiFactory bootstrapUiFactory;
@Autowired
public SortableTableWithPagingController( PartnerRepository partnerRepository,
EntityViewElementBuilderHelper builderHelper,
BootstrapUiFactory bootstrapUiFactory ) {
this.partnerRepository = partnerRepository;
this.builderHelper = builderHelper;
this.bootstrapUiFactory = bootstrapUiFactory;
}
/**
* Registers the CSS/Javascript packed with EntityModule to enable paging and sorting support
* on all tables on the page.
*/
@ModelAttribute
public void registerWebResources( WebResourceRegistry registry ) {
registry.addWithKey( WebResource.CSS, EntityModule.NAME, "/css/entity/entity-module.css", WebResource.VIEWS );
registry.addWithKey(
WebResource.JAVASCRIPT_PAGE_END, EntityModule.NAME, "/js/entity/entity-module.js", WebResource.VIEWS
);
}
/**
* Entry point that adds the different tables to the model.
* Fetches the page of partner entities we wish to render, using a page size of 2.
* This method does not much more but dispatch to the specific table creation methods.
* See the separate methods for more documentation.
*/
@RequestMapping(method = RequestMethod.GET)
public String renderPageTablesWithPageSizeOf2(
@PageableDefault(size = 2) Pageable pageable,
Model model,
ViewElementBuilderContext builderContext
) {
Page<Partner> partners = partnerRepository.findAll( pageable );
model.addAttribute(
"message",
"These tables fully support the default sorting and paging coming with the EntityModule."
);
Map<String, ViewElement> generatedTables = new LinkedHashMap<>();
generatedTables.put(
"Table with checkbox and selected values",
tableWithCheckbox( partners, builderContext )
);
generatedTables.put(
"Table with specific sortable properties",
tableWithSpecificSortableProperties( partners, builderContext )
);
model.addAttribute( "generatedTables", generatedTables );
return "th/entityModuleTest/sortableTables";
}
/**
* [1]
* Generates a table with the surrounding panel where both the sort headers and the pager buttons work.
* Also adds a checkbox column to the table, with some selected values.
*/
private ViewElement tableWithCheckbox( Page<Partner> partners,
ViewElementBuilderContext builderContext ) {
// selected partners that should be checked
Collection<Partner> selectedPartners
= Arrays.asList( partnerRepository.findOne( -1L ), partnerRepository.findOne( -3L ) );
return builderHelper.createSortableTableBuilder( Partner.class )
.items( partners )
.properties( "*" )
.hideResultNumber()
.headerRowProcessor( ( builderCtx, row ) -> {
TableViewElement.Cell cell = new TableViewElement.Cell();
cell.setHeading( true );
cell.addChild(
// the checkbox should be unwrapped in order to render correctly
bootstrapUiFactory.checkbox()
.unwrapped()
.htmlId( "select-all-partners" )
.build( builderCtx )
);
row.addFirstChild( cell );
} )
.valueRowProcessor( ( builderCtx, row ) -> {
Partner partner = EntityViewElementUtils.currentEntity( builderCtx, Partner.class );
TableViewElement.Cell cell = new TableViewElement.Cell();
cell.addChild(
bootstrapUiFactory.checkbox()
.unwrapped()
.controlName( "partners" )
.selected( selectedPartners.contains( partner ) )
.value( partner.getId() )
.build( builderCtx )
);
row.addFirstChild( cell );
} )
.build( builderContext );
}
/**
* [2]
* Generates the table where only one property can be sorted on.
* Note that this table follows the paging and sorting settings of the first table,
* but only the single column can be sorted on in the table itself.
*/
private ViewElement tableWithSpecificSortableProperties( Page<Partner> partners,
ViewElementBuilderContext builderContext ) {
return builderHelper.createSortableTableBuilder( Partner.class )
.items( partners )
.properties( "name", "url" )
.sortableOn( "name" ) // only allow sorting on the name property
.tableOnly()
.build( builderContext );
}
}
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.