| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <title>Extending the Viewer :: Apache Isis</title> |
| <link rel="canonical" href="https://isis.apache.org/vw/2.0.0-M5/extending.html"> |
| <meta name="generator" content="Antora 2.3.4"> |
| <link rel="stylesheet" href="../../_/css/site.css"> |
| <link rel="stylesheet" href="../../_/css/site-custom.css"> |
| <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,700,700i|Raleway:300,400,500,700,800|Montserrat:300,400,700" rel="stylesheet"> |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css"/> |
| <link rel="home" href="https://isis.apache.org" title="Apache Isis"> |
| <link rel="next" href="hints-and-tips.html" title="Hints-n-Tips"> |
| <link rel="prev" href="customisation.html" title="Customisation"> |
| </head> |
| <body class="article"> |
| <header class="header"> |
| <nav class="navbar"> |
| <div class="navbar-brand"> |
| <a class="navbar-item" href="https://isis.apache.org"> |
| <span class="icon"> |
| <img src="../../_/img/isis-logo-48x48.png"></img> |
| </span> |
| <span>Apache Isis</span> |
| </a> |
| <button class="navbar-burger" data-target="topbar-nav"> |
| <span></span> |
| <span></span> |
| <span></span> |
| </button> |
| </div> |
| <div id="topbar-nav" class="navbar-menu"> |
| <a class="navbar-end"> |
| <div class="navbar-item hide-for-print"> |
| <span> |
| <input id="algolia-search-input" placeholder="Search"></span> |
| </span> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Quick Start</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Starter Apps</span> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/starters/helloworld.html">Hello World</a> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/starters/simpleapp.html">Simple App</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Demos & Tutorials</span> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/demo/about.html">Demo App</a> |
| <a class="navbar-item" href="https://danhaywood.gitlab.io/isis-petclinic-tutorial-docs/petclinic/1.16.2/intro.html">Petclinic (tutorial)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Resources</span> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/resources/cheatsheet.html">Cheatsheet</a> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/resources/icons.html">Icons</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Guides</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Development</span> |
| <a class="navbar-item" href="../../setupguide/2.0.0-M5/about.html">Setup Guide</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Core</span> |
| <a class="navbar-item" href="../../userguide/2.0.0-M5/about.html">User Guide</a> |
| <a class="navbar-item" href="../../refguide/2.0.0-M5/about.html">Reference Guide</a> |
| <a class="navbar-item" href="../../testing/2.0.0-M5/about.html">Testing Guide</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Libraries</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">For Use in Apps</span> |
| <a class="navbar-item" href="../../subdomains/2.0.0-M5/about.html">Subdomain Libraries</a> |
| <a class="navbar-item" href="../../valuetypes/2.0.0-M5/about.html">Value Types</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Integrate between Apps</span> |
| <a class="navbar-item" href="../../mappings/2.0.0-M5/about.html">Bounded Context Mapping Libraries</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Other</span> |
| <a class="navbar-item" href="../../incubator/2.0.0-M5/about.html">Incubator</a> |
| <a class="navbar-item" href="../../legacy/2.0.0-M5/about.html">Legacy</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Components</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Viewers</span> |
| <a class="navbar-item" href="../../vw/2.0.0-M5/about.html">Web UI (Wicket)</a> |
| <a class="navbar-item" href="../../vro/2.0.0-M5/about.html">REST API (Restful Objects)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Security</span> |
| <a class="navbar-item" href="../../security/2.0.0-M5/about.html">Security Guide</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Persistence</span> |
| <a class="navbar-item" href="../../pjpa/2.0.0-M5/about.html">JPA (EclipseLink)</a> |
| <a class="navbar-item" href="../../pjdo/2.0.0-M5/about.html">JDO (DataNucleus)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Extensions</span> |
| <a class="navbar-item" href="../../extensions/2.0.0-M5/about.html">Extensions Catalog</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Support</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Contact</span> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/support/slack-channel.html">Slack</a> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/support/mailing-list.html">Mailing Lists</a> |
| <a class="navbar-item" href="https://issues.apache.org/jira/browse/ISIS">JIRA</a> |
| <a class="navbar-item" href="https://stackoverflow.com/questions/tagged/isis">Stack Overflow</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Releases</span> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/downloads/how-to.html">Downloads</a> |
| <a class="navbar-item" href="../../relnotes/2.0.0-M5/about.html">Release Notes</a> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/archive/1-x.html">Archive (1.x)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Framework</span> |
| <a class="navbar-item" href="../../conguide/2.0.0-M5/about.html">Contributors' Guide</a> |
| <a class="navbar-item" href="../../comguide/2.0.0-M5/about.html">Committers' Guide</a> |
| <a class="navbar-item" href="../../core/2.0.0-M5/about.html">Core Design</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">ASF</a> |
| <div class="navbar-dropdown"> |
| <a class="navbar-item" href="http://www.apache.org/">Apache Homepage</a> |
| <a class="navbar-item" href="https://www.apache.org/events/current-event">Events</a> |
| <a class="navbar-item" href="https://www.apache.org/licenses/">Licenses</a> |
| <a class="navbar-item" href="https://www.apache.org/security/">Security</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a> |
| <hr class="navbar-divider"/> |
| <a class="navbar-item" href="https://whimsy.apache.org/board/minutes/Isis.html">PMC board minutes</a> |
| </div> |
| </div> |
| <a class="navbar-item" href="../../docs/2.0.0-M5/about.html"> |
| <span class="icon"> |
| <img src="../../_/img/home.png"></img> |
| </span> |
| </a> |
| </div> |
| </div> |
| </nav> |
| </header> |
| <div class="body "> |
| <div class="nav-container" data-component="vw" data-version="2.0.0-M5"> |
| <aside class="nav"> |
| <div class="panels"> |
| <div class="nav-panel-pagination"> |
| <a class="page-previous" rel="prev" href="customisation.html" title="Customisation"><span></span></a> |
| <a class="page-next" rel="next" |
| href="hints-and-tips.html" title="Hints-n-Tips"><span></span></a> |
| <!-- |
| page.parent doesn't seem to be set... |
| <a class="page-parent disabled" rel="prev" href="" title="Customisation"><span></span></a> |
| --> |
| </div> |
| <div class="nav-panel-menu is-active" data-panel="menu"> |
| <nav class="nav-menu"> |
| <h3 class="title"><a href="about.html">Web UI (Wicket Viewer)</a></h3> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="setup-and-configuration.html">Setup and Configuration</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="features.html">End-user Features</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="customisation.html">Customisation</a> |
| </li> |
| <li class="nav-item is-current-page" data-depth="1"> |
| <a class="nav-link" href="extending.html">Extending</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="hints-and-tips.html">Hints-n-Tips</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <a class="nav-link" href="security.html">Security</a> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Extensions</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="exceldownload/about.html">Excel Download</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="fullcalendar/about.html">fullcalendar</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="gmap3/about.html">GMap3</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="pdfjs/about.html">pdf.js</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </nav> |
| </div> |
| <div class="nav-panel-explore" data-panel="explore"> |
| <div class="context"> |
| <span class="title">Web UI (Wicket Viewer)</span> |
| <span class="version">2.0.0-M5</span> |
| </div> |
| <ul class="components"> |
| <li class="component"> |
| <span class="title"> </span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../docs/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">BC Mapping Libraries</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../mappings/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Committers' Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../comguide/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Contributors' Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../conguide/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Design Docs</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../core/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Extensions Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../extensions/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Incubator Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../incubator/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">JDO/DataNucleus</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../pjdo/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">JPA</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../pjpa/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Legacy Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../legacy/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Reference Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../refguide/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Release Notes</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../relnotes/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">REST API (Restful Objects Viewer)</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../vro/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Security Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../security/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Setup Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../setupguide/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Subdomains Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../subdomains/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Testing Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../testing/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Tooling</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../tooling/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">User Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../userguide/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Value Types Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../valuetypes/2.0.0-M5/about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component is-current"> |
| <span class="title">Web UI (Wicket Viewer)</span> |
| <ul class="versions"> |
| <li class="version is-current is-latest"> |
| <a href="about.html">2.0.0-M5</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </aside> |
| </div> |
| <main role="main"> |
| <div class="toolbar" role="navigation"> |
| <button class="nav-toggle"></button> |
| <a href="../../docs/2.0.0-M5/about.html" class="home-link"></a> |
| <nav class="breadcrumbs" aria-label="breadcrumbs"> |
| <ul> |
| <li><a href="about.html">Web UI (Wicket Viewer)</a></li> |
| <li><a href="extending.html">Extending</a></li> |
| </ul> |
| </nav> |
| <div class="edit-this-page"><a href="https://github.com/apache/isis/edit/2.0.0-M5/viewers/wicket/adoc/modules/ROOT/pages/extending.adoc">Edit</a></div> |
| </div> |
| <article class="doc"> |
| <a name="section-top"></a> |
| <h1 class="page">Extending the Viewer</h1> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The Wicket viewer allows you to customize the GUI in several (progressively more sophisticated) ways.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the <a href="customisation.html" class="page">customisation</a> chapter described tweaking the UI using <a href="customisation.html#custom-css" class="page">custom CSS</a> and <a href="customisation.html#custom-javascript" class="page">custom JavaScript</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In this chapter we have a number of more heavy-weight approaches:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>by writing a <a href="#custom-bootstrap-theme">custom bootstrap theme</a></p> |
| </li> |
| <li> |
| <p>by <a href="#replacing-page-elements">replacing elements of the page</a> using the <code>ComponentFactory</code> interface</p> |
| </li> |
| <li> |
| <p>by implementing <a href="#custom-pages">replacement page implementations</a> for the standard page types</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="custom-bootstrap-theme"><a class="anchor" href="#custom-bootstrap-theme"></a>Custom Bootstrap theme</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The Apache Isis Wicket viewer uses <a href="http://getbootstrap.com/">Bootstrap</a> styles and components, courtesy of the <a href="https://github.com/l0rdn1kk0n/wicket-bootstrap">Wicket Bootstrap</a> integration.</p> |
| </div> |
| <div class="paragraph"> |
| <p>By default the viewer uses the default bootstrap theme. |
| It is possible to configure the Wicket viewer to allow the user to <a href="setup-and-configuration.html#themes" class="page">select other themes</a> provided by <a href="http://bootswatch.com">bootswatch.com</a>, and if required one of these can be <a href="customisation.html#default-theme" class="page">set as the default</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>However, you may instead want to write your own custom theme, for example to fit your company’s look-n-feel/interface guidelines. |
| This is done by implementing <a href="https://github.com/l0rdn1kk0n/wicket-bootstrap">Wicket Bootstrap</a>'s <code>de.agilecoders.wicket.core.settings.ITheme</code> class. |
| This defines:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>the name of the theme</p> |
| </li> |
| <li> |
| <p>the resources it needs (the CSS and optional JS and/or fonts), and</p> |
| </li> |
| <li> |
| <p>optional urls to load them from a Content Delivery Network (CDN).</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>To make use of the custom <code>ITheme</code> the application should register it by subclassing <code>IsisWicketApplication</code> (also register this in <code>web.xml</code>) and add the following snippet:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public void init() { |
| ... |
| IBootstrapSettings settings = new BootstrapSettings(); |
| ThemeProvider themeProvider = new SingleThemeProvider(new MyTheme()); |
| settings.setThemeProvider(themeProvider); |
| Bootstrap.install(getClass(), settings); |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="replacing-page-elements"><a class="anchor" href="#replacing-page-elements"></a>Replacing page elements</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Replacing elements of the page is the most powerful general-purpose way to customize the look-n-feel of the viewer. |
| Examples include the |
| <a href="gmap3/about.html" class="page">Gmap3</a>, <a href="fullcalendar/about.html" class="page">Fullcalendar</a>, <a href="exceldownload/about.html" class="page">Excel Download</a> and <a href="pdfjs/about.html" class="page">pdf.js</a> components.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The pages generated by Apache Isis' Wicket viewer are built up of numerous elements, from fine-grained widgets for property/parameter fields, to much larger components that take responsibility for rendering an entire entity, or a collection of entities. |
| Under the covers these are all implementations of the the Apache Wicket <code>Component</code> API. |
| The larger components delegate to the smaller, of course.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="how-the-viewer-selects-components"><a class="anchor" href="#how-the-viewer-selects-components"></a>How the viewer selects components</h3> |
| <div class="paragraph"> |
| <p>Components are created using Apache Isis' <code>ComponentFactory</code> interface, which are registered in turn through the <code>ComponentFactoryRegistrar</code> interface. |
| Every component is categorizes by type (the <code>ComponentType</code> enum), and Apache Isis uses this to determine which <code>ComponentFactory</code> to use. |
| For example, the <code>ComponentType.BOOKMARKED_PAGES</code> is used to locate the <code>ComponentFactory</code> that will build the bookmarked pages panel.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Each factory is also handed a model (an implementation of <code>org.apache.wicket.IModel</code>) appropriate to its <code>ComponentType</code>; this holds the data to be rendered. |
| For example, <code>ComponentType.BOOKMARKED_PAGES</code> is given a <code>BookmarkedPagesModel</code>, while <code>ComponentType.SCALAR_NAME_AND_VALUE</code> factories are provided a model of type of type <code>ScalarModel</code> .</p> |
| </div> |
| <div class="paragraph"> |
| <p>In some cases there are several factories for a given <code>ComponentType</code>; this is most notably the case for <code>ComponentType.SCALAR_NAME_AND_VALUE</code>. |
| After doing a first pass selection of candidate factories by <code>ComponentType</code>, each factory is then asked if it <code>appliesTo(Model)</code>. |
| This is an opportunity for the factory to check the model itself to see if the data within it is of the appropriate type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Thus, the <code>BooleanPanelFactory</code> checks that the <code>ScalarModel</code> holds a boolean, while the <code>JodaLocalDatePanelFactory</code> checks to see if it holds <code>org.joda.time.LocalDate</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There will typically be only one <code>ComponentFactory</code> capable of rendering a particular <code>ComponentType</code>/<code>ScalarModel</code> combination; at any rate, the framework stops as soon as one is found.</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>There is one refinement to the above algorithm where multiple component factories might be used to render an object; this is discussed in <a href="extending/replacing-page-elements.html#additional-views-of-collections" class="page">Additional Views of Collections</a>, below.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="how-to-replace-a-component"><a class="anchor" href="#how-to-replace-a-component"></a>How to replace a component</h3> |
| <div class="paragraph"> |
| <p>This design (the <a href="http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern">chain of responsibility</a> design pattern) makes it quite straightforward to change the rendering of any element of the page. |
| For example, you might switch out Apache Isis' sliding bookmark panel and replace it with one that presents the bookmarks in some different fashion.</p> |
| </div> |
| <div class="paragraph"> |
| <p>First, you need to write a <code>ComponentFactory</code> and corresponding <code>Component</code>. |
| The recommended approach is to start with the source of the <code>Component</code> you want to switch out.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>ComponentFactory</code> should be annotated as a Spring service, typically using Spring’s <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Service.html">@Service</a> annotation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import org.springframework.stereotype.Service; |
| |
| @Service |
| public class MyBookmarkedPagesPanelFactory extends ComponentFactoryAbstract { |
| public MyBookmarkedPagesPanelFactory() { |
| super(ComponentType.BOOKMARKED_PAGES); |
| } |
| @Override |
| public ApplicationAdvice appliesTo(final IModel<?> model) { |
| return appliesIf(model instanceof BookmarkedPagesModel); |
| } |
| @Override |
| public Component createComponent(final String id, final IModel<?> model) { |
| final BookmarkedPagesModel bookmarkedPagesModel = (BookmarkedPagesModel) model; |
| return new MyBookmarkedPagesPanel(id, bookmarkedPagesModel); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>and</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class MyBookmarkedPagesPanel |
| extends PanelAbstract<BookmarkedPagesModel> { |
| ... |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Here <code>PanelAbstract</code> ultimately inherits from <code>org.apache.wicket.Component</code>. |
| Your new <code>Component</code> uses the information in the provided model (eg <code>BookmarkedPagesModel</code>) to know what to render.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Your new component will be used instead of the default implementation.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="additional-views-of-collections"><a class="anchor" href="#additional-views-of-collections"></a>Additional Views of Collections</h3> |
| <div class="paragraph"> |
| <p>As explained above, in most cases Apache Isis' Wicket viewer will search for the first <code>ComponentFactory</code> that can render an element, and use it. |
| In the case of (either standalone or parented) collections, though, the viewer will show all available views.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, out-of-the-box Apache Isis provides a table view, a summary view (totals/sums/averages of any data), and a collapsed view. |
| These are selected by clicking on the toolbar by each collection.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Additional views though could render the objects in the collection as a variety of ways; as illustrated by the <a href="gmap3/about.html" class="page">Gmap3</a>, <a href="fullcalendar/about.html" class="page">Fullcalendar</a> and <a href="exceldownload/about.html" class="page">Excel Download</a> extensions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Wicket itself has lots of components available at its <a href="http://wicketstuff.org">wicketstuff.org</a> companion website; you might find some of these useful for your own customizations.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="custom-object-view-eg-dashboard"><a class="anchor" href="#custom-object-view-eg-dashboard"></a>Custom object view (eg dashboard)</h3> |
| <div class="paragraph"> |
| <p>One further use case in particular is worth highlighting; the rendering of an entire entity. |
| Normally for entities this is done using <code>Bs3GridPanelFactory</code>, this being the first <code>ComponentFactory</code> for the <code>ComponentType.ENTITY</code> that is registered in Apache Isis default <code>ComponentFactoryRegistrarDefault</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You could, though, register your own <code>ComponentFactory</code> for entities that is targeted at a particular class of entity - some sort of object representing a dashboard, for example. |
| It can use the <code>EntityModel</code> provided to it to determine the class of the entity, checking if it is of the appropriate type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The demo app (<a href="https://demo-wicket.jdo.isis.incode.work">jdo</a> or <a href="https://demo-wicket.jpa.isis.incode.work">jpa</a>) includes an example of this technique (<code>Featured > Where in the World</code>).</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="custom-pages"><a class="anchor" href="#custom-pages"></a>Custom pages</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>In the vast majority of cases customization should be sufficient by <a href="#replacing-page-elements">replacing elements of a page</a>. |
| However, it is also possible to define an entirely new page for a given page type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The Wicket viewer defines these page types (see the <code>org.apache.isis.viewer.wicket.model.models.PageType</code> enum):</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <caption class="title">Table 1. PageType enum</caption> |
| <colgroup> |
| <col style="width: 20%;"> |
| <col style="width: 80%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Page type</th> |
| <th class="tableblock halign-left valign-top">Renders</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SIGN_IN</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The initial sign-in (aka login) page</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SIGN_UP</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The sign-up page (if <a href="../../refguide/2.0.0-M5/applib/index/services/userreg/UserRegistrationService.html" class="page">user registration</a> is enabled).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">SIGN_UP_VERIFY</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The sign-up verification page (if <a href="../../refguide/2.0.0-M5/applib/index/services/userreg/UserRegistrationService.html" class="page">user registration</a> is enabled; as accessed by link from verification email)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">PASSWORD_RESET</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The password reset page (if enabled).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HOME</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The home page, displaying either the welcome message or dashboard</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">HOME_AFTER_PAGETIMEOUT</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Variation on home page after a timeout.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ABOUT</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">The about page, accessible from link top-right</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ENTITY</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Renders a single entity or view model</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">STANDALONE_COLLECTION</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Page rendered after invoking an action that returns a collection of entites</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">VALUE</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">After invoking an action that returns a value type (though not URLs or Blob/Clobs, as these are handled appropriately automatically).</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">VOID_RETURN</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">After invoking an action that is <code>void</code></p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ACTION_PROMPT</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">(No longer used).</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The <code>PageClassList</code> interface declares which class (subclass of <code>org.apache.wicket.Page</code> is used to render for each of these types. |
| For example, Apache Isis' <code>WicketSignInPage</code> renders the signin page.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To specify a different page class, create a new implementation of <code>PageClassList</code> and annotate with an earlier precedence than the default. |
| If you are just tweaking the defaults, then its easiest to override <code>PageClassListDefault</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Service |
| @Order(OrderPrecedence.EARLY) |
| public class MyPageClassList extends PageClassListDefault { |
| protected Class<? extends Page> getSignInPageClass() { |
| return MySignInPage.class; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </article> |
| <aside class="article-aside toc hide-for-print" role="navigation"> |
| <p class="toc-title">On this page</p> |
| <div id="article-toc"></div> |
| </aside> |
| </main> |
| </div> |
| <footer class="footer"> |
| <div class="content"> |
| <div class="copyright"> |
| <p> |
| Copyright © 2010~2021 The Apache Software Foundation, licensed under the Apache License, v2.0. |
| <br/> |
| Apache, the Apache feather logo, Apache Isis, and the Apache Isis project logo are all trademarks of The Apache Software Foundation. |
| </p> |
| </div> |
| <div class="revision"> |
| <p>Revision: 2.0.0-M5.20210523-1443</p> |
| </div> |
| </div> |
| </footer> |
| <script src="../../_/js/site.js"></script> |
| <script async src="../../_/js/vendor/highlight.js"></script> |
| <script src="../../_/js/vendor/jquery-3.4.1.min.js"></script> |
| <script src="../../_/js/vendor/jquery-ui-1.12.1.custom.widget-only.min.js"></script> |
| <script src="../../_/js/vendor/jquery.tocify.min.js"></script> |
| |
| <script> |
| $(function() { |
| $("#article-toc").tocify( { |
| showEffect: "slideDown", |
| hashGenerator: "pretty", |
| hideEffect: "slideUp", |
| selectors: "h2, h3", |
| scrollTo: 120, |
| smoothScroll: true, |
| theme: "jqueryui", |
| highlightOnScroll: true |
| } ); |
| }); |
| </script> |
| |
| <script src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script> |
| <script> |
| function focusSearchInput () { document.querySelector('#algolia-search-input').focus() } |
| var search = docsearch({ |
| appId: '5ISP5TFAEN', |
| apiKey: '0fc51c28b4ad46e7318e96d4e97fab7c', |
| indexName: 'isis-apache-org', |
| inputSelector: '#algolia-search-input', |
| autocompleteOptions: { hint: false, keyboardShortcuts: ['s'] }, |
| debug: false, |
| }).autocomplete |
| search.on('autocomplete:closed', function () { search.autocomplete.setVal() }) |
| focusSearchInput() |
| window.addEventListener('load', focusSearchInput); |
| </script> |
| |
| <!-- |
| docsearch options: |
| https://docsearch.algolia.com/docs/behavior/ |
| --> |
| <!-- |
| https://www.algolia.com/doc/api-reference/api-parameters/ |
| algoliaOptions: { hitsPerPage: 6 }, |
| --> |
| </body> |
| </html> |