blob: 5a0a3dfa6065964936118d106923875868fa8f28 [file] [log] [blame]
<!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 &amp; 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&#8217;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&#8217;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&lt;?&gt; model) {
return appliesIf(model instanceof BookmarkedPagesModel);
}
@Override
public Component createComponent(final String id, final IModel&lt;?&gt; 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&lt;BookmarkedPagesModel&gt; {
...
}</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 &gt; 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&lt;? extends Page&gt; 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>