All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.foreach.across.modules.adminweb.ui.PageContentStructure Maven / Gradle / Ivy

/*
 * 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.modules.adminweb.ui;

import com.foreach.across.modules.adminweb.AdminWeb;
import com.foreach.across.modules.web.ui.ViewElement;
import com.foreach.across.modules.web.ui.elements.AbstractNodeViewElement;
import com.foreach.across.modules.web.ui.elements.ConfigurableTextViewElement;
import com.foreach.across.modules.web.ui.elements.NodeViewElement;
import com.foreach.across.modules.web.ui.elements.TextViewElement;
import com.foreach.across.modules.web.ui.elements.support.ContainerViewElementUtils;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * Represents the content structure of a single page.
 * A standard content structure has the following elements:
 * 
    *
  • header
  • *
  • feedback section
  • *
  • nav
  • *
  • body section
  • *
  • footer
  • *
* All elements have their own pcs-prefixed css class added, and everything * will be wrapped in a single div with class pcs. *

* Children added directly to the {@link PageContentStructure} will be added to the body section when rendering. * If rendered as a tab layout, this will be the active tab pane. *

* Request-bound bean: {@link PageContentStructure} is declared as an exposed request-bound bean. * This means a controller can write a {@link PageContentStructure} that will be put on the request under the default * attribute name. Any model attribute set directly will replace the bean structure! * * @author Arne Vandamme * @since 2.0.0 */ public class PageContentStructure extends AbstractNodeViewElement { /** * This should equal the default {@link org.springframework.web.bind.annotation.ModelAttribute} name generated * based on the class name. */ public static final String MODEL_ATTRIBUTE = "pageContentStructure"; public static final String TEMPLATE = AdminWeb.PAGE_CONTENT; public static final String ELEMENT_PAGE_TITLE = "pageTitle"; public static final String ELEMENT_PAGE_TITLE_TEXT = "pageTitleText"; public static final String ELEMENT_PAGE_TITLE_SUB_TEXT = "pageTitleSubText"; public static final String ELEMENT_BODY_SECTION = "body"; public static final String CSS_PCS = "pcs"; public static final String CSS_HEADER = "pcs-header"; public static final String CSS_FOOTER = "pcs-footer"; public static final String CSS_NAV = "pcs-nav"; public static final String CSS_FEEDBACK_SECTION = "pcs-feedback-section"; public static final String CSS_BODY_SECTION = "pcs-body-section"; @Getter @Setter private boolean renderAsTabs; @Getter private final NodeViewElement header; @Getter private final NodeViewElement feedback; @Getter private final NodeViewElement footer; @Getter private final NodeViewElement nav; public PageContentStructure() { super( "div" ); addCssClass( CSS_PCS ); header = new NodeViewElement( "header" ); header.addCssClass( CSS_HEADER ); footer = new NodeViewElement( "footer" ); footer.addCssClass( CSS_FOOTER ); nav = new NodeViewElement( "nav" ); nav.addCssClass( CSS_NAV ); feedback = new NodeViewElement( "section" ); feedback.addCssClass( CSS_FEEDBACK_SECTION ); } /** * Add an element directly to the header section. * This will not create the default header content. If you want to alter the default page title text * and sub text structure created, you should use either {@link #addToPageTitle(ViewElement)} or * {@link #addToPageTitleSubText(ViewElement)}. * * @param element to add */ public void addToHeader( ViewElement element ) { header.addChild( element ); } /** * Add an element directly to the page title element. * The element will be added after the sub text element. If you want to add an element before, * you should use the {@link #withPageTitle(Consumer)} method. *

* Calling this method will create the default header if the header section is still empty. * * @param element to add */ public void addToPageTitle( ViewElement element ) { withPageTitle( n -> n.addChild( element ) ); } /** * Add an element directly to the page title sub text element. *

* Calling this method will create the default header if the header section is still empty. * * @param element to add */ public void addToPageTitleSubText( ViewElement element ) { withPageTitleSubText( n -> n.addChild( element ) ); } /** * Add an element directly to the nav section. * * @param element to add */ public void addToNav( ViewElement element ) { nav.addChild( element ); } /** * Add an element directly to the feedback section. * * @param element to add */ public void addToFeedback( ViewElement element ) { feedback.addChild( element ); } /** * Add an element directly to the footer section. * * @param element to add */ public void addToFooter( ViewElement element ) { footer.addChild( element ); } /** * Perform one or more actions with the header element. * * @param consumer to execute */ public void withHeader( Consumer consumer ) { consumer.accept( header ); } /** * Perform one or more actions with the footer element. * * @param consumer to execute */ public void withFooter( Consumer consumer ) { consumer.accept( footer ); } /** * Perform one or more actions with the nav element. * * @param consumer to execute */ public void withNav( Consumer consumer ) { consumer.accept( nav ); } /** * Perform one or more actions with the feedback section element. * * @param consumer to execute */ public void withFeedback( Consumer consumer ) { consumer.accept( feedback ); } /** * Set the page title text directly. Requires an element named {@link #ELEMENT_PAGE_TITLE_TEXT} to be present, * else this method will do nothing. *

* Calling this method will create the default header if the header section if still empty. * * @param pageTitle text to set */ public void setPageTitle( String pageTitle ) { createDefaultHeaderIfHeaderSectionEmpty(); ContainerViewElementUtils .find( header, ELEMENT_PAGE_TITLE_TEXT, ConfigurableTextViewElement.class ) .ifPresent( t -> t.setText( pageTitle ) ); } /** * Get the current page title text set. Retrieves the value from the child element named * {@link #ELEMENT_PAGE_TITLE_TEXT}, will return {@code null} if title not set or no page title element. * * @return title text if could be found */ public String getPageTitle() { return ContainerViewElementUtils .find( header, ELEMENT_PAGE_TITLE_TEXT, ConfigurableTextViewElement.class ) .map( ConfigurableTextViewElement::getText ) .orElse( null ); } /** * Perform one or more actions with the page title element. * The page title is the element named {@link #ELEMENT_PAGE_TITLE} inside the header section, * it usually contains both the page title text and sub text elements. *

* Calling this method will create the default header if the header section is still empty. * * @param consumer to execute */ public void withPageTitle( Consumer consumer ) { createDefaultHeaderIfHeaderSectionEmpty(); ContainerViewElementUtils .find( header, ELEMENT_PAGE_TITLE, NodeViewElement.class ) .ifPresent( consumer ); } /** * Perform one or more actions with the page title subtext element. * The page title subtext is the element named {@link #ELEMENT_PAGE_TITLE_SUB_TEXT}, usually a <small> * element inside of the page title element inside the header section. *

* Calling this method will create the default header if the header section is still empty. * * @param consumer to execute */ public void withPageTitleSubText( Consumer consumer ) { createDefaultHeaderIfHeaderSectionEmpty(); ContainerViewElementUtils .find( header, ELEMENT_PAGE_TITLE_SUB_TEXT, NodeViewElement.class ) .ifPresent( consumer ); } private void createDefaultHeaderIfHeaderSectionEmpty() { if ( !header.hasChildren() ) { TextViewElement titleText = new TextViewElement( ELEMENT_PAGE_TITLE_TEXT, null ); NodeViewElement heading = new NodeViewElement( ELEMENT_PAGE_TITLE, "h3" ); heading.addCssClass( "page-header" ); heading.addChild( titleText ); heading.addChild( new TextViewElement( " " ) ); NodeViewElement actionsElement = new NodeViewElement( ELEMENT_PAGE_TITLE_SUB_TEXT, "small" ); heading.addChild( actionsElement ); header.addChild( heading ); } } /** * @return list of elements that make up the actual content body */ public List getContentChildren() { return super.getChildren(); } @Override public List getChildren() { List children = new ArrayList<>(); if ( header.hasChildren() ) { children.add( header ); } if ( feedback.hasChildren() ) { children.add( feedback ); } NodeViewElement body = new NodeViewElement( ELEMENT_BODY_SECTION, "section" ); body.addCssClass( CSS_BODY_SECTION ); if ( super.hasChildren() ) { if ( renderAsTabs ) { NodeViewElement tabWrapper = new NodeViewElement( "div" ); tabWrapper.addCssClass( "tabbable", "filled" ); if ( nav.hasChildren() ) { tabWrapper.addChild( nav ); } tabWrapper.addChild( body ); NodeViewElement tabContent = new NodeViewElement( "div" ); tabContent.addCssClass( "tab-content" ); body.addChild( tabContent ); NodeViewElement tabPane = new NodeViewElement( "div" ); tabPane.addCssClass( "tab-pane", "active" ); tabPane.addChildren( getContentChildren() ); tabContent.addChild( tabPane ); children.add( tabWrapper ); } else { if ( nav.hasChildren() ) { children.add( nav ); } children.add( body ); body.addChildren( getContentChildren() ); } } if ( footer.hasChildren() ) { children.add( footer ); } return children; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy