This topic contains the following sections:
The Dynamic Tabs UI Shell Template (UI Shell) is used to address one of the necessary attributes of a software product: usability. Elements addressed are:
The UI Shell is a template with behaviors. Commonly provided behaviors aid predictability and control -- attributes of usability. These behaviors center around navigation. When implemented essentially the same across the application, the application feels predictable. The user feels in control.
The most salient behavior supported by the UI Shell is dynamic tabs. The tabs are dynamic in that they are rendered and dismissed upon demand by the user.
The ADF UI shell page template contains facets, attributes, ADF components, and a Java Bean to provide behavior. Multiple ADF page fragments (defined as bounded taskflows) run in a series of dynamic tabs on the page. A page fragment is a JSF JSP document (.jsff) that can be rendered as content of another JSF page. It is similar to a page, except that it cannot contain elements such as <f:view>. The template itself manages the dynamic tabs; allows facilities to open new tabs with given taskflow identifiers; and handles dirty state for those tabs. The template handles a maximum of 15 taskflows represented as tabs.
The template defines four areas with ten facets in a generally described 3 rows by 2 column layout. The UI Shell is one of two templates provided "out-of-the-box" from Oracle. It is called "Dynamic Tab Shell." Any newly created JSF or JSP page can be based on this template.
A chief challenge in UI development is rational consistency -- providing the user with predictable locations and behaviors for the most salient features. Because the ADF UI Shell is a template, it provides guidance for development teams to deliver a consistent UI to their customers. The primary assumption of the UI Shell is that each page based on the template will represent a significant module of an application, if not separate applications. As a consequence, the "boilerplate" portion of the UI (e.g., branding, ubiquitous controls, obligatory legal statements) are more easily held consistent in form, placement, and function -- as they are defined once per page. The more interactive portion of the application, that content which delivers the features and functions that define the application, are presented in the "workarea" of the template. The UI Shell identifies those areas through named facets (e.g., navigation) and regions (e.g., dynamic tabs). Nearly all, if not all, of the product's value add can be surfaced in these areas within a single page as bounded ADF taskflows containing one or more ADF page fragments.
Navigation rules between applications represented as single pages can be defined in unbounded ADF taskflows and presented to the user as global navigation controls (e.g., global tabs, buttons, links) providing convenient access to a suite of separate, but related products.
The UI Shell template and Java bean is contained within an ADF jar shipped with JDeveloper/ADF. The Java bean has a list of methods (i.e., APIs) available only to this template. The UI layout of the template has ten named facets. The template also has nine attributes which pass in values to each page based on the template. There are also embedded components to round out the Look and Feel (L&F) of the template.
Facet Name | Description |
---|---|
globalLinks | Links that appear in the top right hand corner of the page are placed here -- just to the left of status facet. Global Links provide access to content that is applicable on almost every page of an application. They are typically outside the navigational hierarchy or structure of the application. Examples include Preferences, Help, and Sign Out. |
status | Location where user account information is presented. |
globalToolbar | Located above the globalTabs facet, this should contain UI elements for actions that affect the entire page (such as adding or removing a global tab). |
globalSearch | Flushed right of the globalToolbar facet, it can be used to provide the input area for a global search. |
globalTabs | This facet should contiain the top most tabs of the page. An af:navigationPane which is either bound to an xml menu model or contains af:commandNavigationLinks to traverse the site or intranet would be a good choice for this area. These tabs are not part of the template and are thus not managed by the template. For example, each tab is a separate page or page template. |
innerToolbar | A location for toolbar content that is placed between the global tab and the inner content region (e.g., the dynamic tabs). This should contain UI elements for actions that affect the dynamic tabs (such as adding or removing a tab). |
welcome | Content in this facet is displayed before any tabs are launched and after all tabs (i.e., taskflows) are closed. |
navigation | The left hand side area of the page template. This section usually contains a taskflow with links that can launch new dynamic tabs also containing taskflows. |
copyright | This area should contain the copyright text that will show up in the bottom left hand corner of the page. If needed, this facet can contain additional content, such as other legal notices, as this area will stretch to accommodate its contents. |
about | This section covers the bottom left hand corner of the page. It can contain any content, but is typically used to describe the product (e.g., version number), the vendor, and policies (e.g., terms of use, privacy) through a series of links to those pages. |
Attribute Name | Description |
---|---|
logoImagePath | The image path to use for the logo. If this is absent, the Oracle logo will be used. |
brandingTitle | The title used in the top left next to the logo. This should be the main title for this page -- describing the product or suite represented in the page. |
statusWidth | The amount of horizontal space given for the text in the status facet. The default is 200px. |
headerSplitterPosition | The amount of vertical space that should be given to the branding area of the page. The header section is composed of the logo, title, global links, and status areas. This defaults to 30px from the top. |
headerSplitterDisabled | Enables a splitter control whereby the user can resize the branding area. The default is false. |
globalSplitterPosition | The amount of vertical space that should be given to the global section of the page. The global section is composed of the global toolbar and global search areas. The default is 25px from the bottom of the headerSplitterPosition attribute. |
navSplitterPosition | The amount of horizontal space that is given to the navigation area and is thus space taken away from the dynamic tab content region. The default is 200px from the start (e.g., left). |
navSplitterDisabled | Enables a splitter control whereby the user can resize the navigation area. The default is true. |
legalAreaPosition | The amount of vertical space that should be given to the legal area of the page. The legal section is composed of the copyright and about areas. The default is 20px from the bottom. |
dirtyTabPopupTitle | When there is a request to close a tab that is dirty, a popup dialog warns the user about whether or not to continue closing the tab (i.e., taskflow). The title for the dialog is specified by this attribute. |
dirtyTabPopupText | When there is a request to close a tab that is dirty, a popup dialog warns the user about whether or not to continue closing the tab (i.e., taskflow). The text for the dialog is specified by this attribute. |
tooManyTabsPopupTitle | When the maximum number of tabs (i.e., taskflows) is reached, and an additional tab is requested, a popup dialog informs the user of that limit. The maximum number of tabs the template allows is 15. The title for the dialog is specified by this attribute. |
tooManyTabsPopupText | When the maximum number of tabs (i.e., taskflows) is reached, and an additional tab is requested, a popup dialog informs the user of that limit. The text for the dialog is specified by this attribute. |
Component | Description |
---|---|
Branding Bar | A series of nested layout components, style classes, images, components and aforementioned facets to provide space efficient customizable branding for the application. |
Status Indicator | Displays various icons (animated and static) to indicate server activity. The icons for the status indicator component are set in the skinning (CSS) file. |
Panel Splitters | Components that partition the page into its five areas: header, global, navigational, local, and legal. The allocation between the navigational and local area is adjustable at runtime by the user via s splitter control if its value is set to the default value of true. |
Decorative Boxes | Provides a bordered look (i.e. rounded corners). It act as a L&F transition between areas on a page. For example, a page that has a dark background for its template can use the decorative box to transition to a white background for its local content area. It is bordered by eight styled areas that are controlled using skinning keys. |
Close icon | Aligned right of the dynamic tabs, this icon appears when the number of open task flows within a tab is greater than one. Clicking this icon (X) closes any selected tab that is in a clean vs dirty state. Enabled, mouseover, mousedown, and mouse up states are provided "Out of the Box" for this control. |
Java APIs
The behaviors of the template are provided through a class called TabContext. TabContext contains methods to launch new tabs, as well as other forms of manipulation of the tabs. The best practice to leverage the APIs within TabContext is through a managed bean written in Java.
/* Copyright (c) 2008, 2009, Oracle and/or its
affiliates. All rights reserved. */
import oracle.ui.pattern.dynamicShell.TabContext
TabContext tabContext = TabContext.getCurrentInstance();
All public APIs are EL accessible.
The addTab
API will always launch new tabs into the local content area. This API is appropriate for use cases where multiple instances of the same task flow are desired to each have a separate tab, such as "create new."
/*Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. */
try
{
tabContext.addTab("Some Localized Title of the Tab","/path/to/taskflow#taskflowId");
}
catch (TabContext.TabOverFlowException toe)
toe.handleDefault();
}
Line 6 can throw a TabOverFlowException. This will occur if there is an attempt to open more than the maximum number of available tabs (i.e., taskflows) at run time. This case can be handled in any way preferred or use the handleDefault()
method to call a popup warning dialog to appear to the user. When this exception is thrown, the requested tab will not open for the user. The maximum number of tabs the UI Shell allows is 15.
The addOrSelectTab
API will always launch one instance of the tab by detecting whether it has already launched. If so, that tab is selected instead. This API is appropriate for use cases where a single instances of a task flow is desired with a tab, such as "edit object." If the taskflow for that object is open, then a gesture by the user to re-launch that edit object taskflow will return selection to its tab.
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */
try
{
tabContext.addOrSelectTab("Some Localized Title of the Tab",
"/path/to/taskflow#taskflowId");
}
catch (TabContext.TabOverFlowException toe)
{
toe.handleDefault();
}
There are use cases where the goal is not to use tabs (i.e., present the user with two or more task flows launched serially within tabs) but to have a single "replace-in-place" UI. In this UI, tabs are absent, the opened task flow occupies the entire local content region of the page. The tabContext.setMainContent
API provides for that use case.
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */
tabContext.setMainContent("/some/path/to/taskflow#taskflowId");
Note: The single task flow (i.e., replace-in-place) and tabbed task flow cannot be used concurrently on the same page. An attempt to call this API when tabbed task flows are showing or an attempt to launch a new tabbed task flow when the content region is showing, will result in an exception. It also makes for poor UI.
In addition to the Close icon which presence and behavior are provided automatically by the ADF UI Shell template, tabs and their task flows can be closed programmatically (e.g., from within the task flow) via the removeCurrentTab
API.
/*Copyright (c) 2008, 2009, Oracle and/or its
affiliates. All rights reserved. */
tabContext.removeCurrentTab();
Both the Close icon embedded with the UI Shell template and the removeCurrentTab
method will check whether the taskflow within the selected tab is clean or dirty. Presently the model could be checked for dirty state; however, the model does not track how it was made dirty (e.g., the current task flow or another). What this template provides at the ADF View level is the markCurrentTabDirty
API to indicate that the current task flow is dirty by setting the style of the tab label to italic. This API could be triggered by a custom method that listens for a value change on the task flow shown within the tab. Conversely, after any changes have been committed (e.g., saved to DB), this same API could be called to indicate a clean task flow by setting the style of the tab label back to normal.
/*Copyright (c) 2008, 2009, Oracle and/or its
affiliates. All rights reserved. */
tabContext.markCurrentTabDirty(true);
By passing in false to the markCurrentTabDirty
API, the tab label style is set to normal.
As mentioned previously, both the embedded Close icon and the removeCurrentTab API will check whether the current tab (i.e., task flow) is clean or dirty. However, there may be cases where there is a need to check whether the state of the current tab or any open tab is dirty (e.g., prior to page navigation). The isCurrentTabDirty
or isAnyTabDirty
API could check for the corresponding case before navigating.
/*Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. */
// check the dirty state of the current tab
boolean isCurrentTabDirty = tabContext.isCurrentTabDirty();
// check the dirty state of all the tabs (will return true if any tab is dirty)
boolean isAnyTabDirty = tabContext.isTagSetDirty();
Note that when typing to reference for this method directly isTagSetDirty
has an unexpected spelling.
There are use cases where it is important to know if any tabs are visible in the UI. For example, the UI may call for a particular toolbar item to enable or render when one or more tabs are present. The embedded Close icon exhibits this behavior automatically -- it renders when one or more tabs appear. The selectedTabIndex
API can use the Rendered
or Disabled
property of any UI construct for that purpose.
/*Copyright (c) 2008, 2009, Oracle and/or its
affiliates. All rights reserved. */
tabContext.selectedTabIndex();
The tab index is zero based. So if any tabs are present, the value of selectedTabIndex
would be zero or greater.
To access TabContext methods from within a task flow, define a parameter for TabContext in the task flow. The UI Shell template passes in TabContext.
Element | Value |
---|---|
name | tabContext |
class | oracle.ui.pattern.dynamicShell.TabContext |
required | true |
The task flow XML file should look similar to this.
<input-parameter-definition>
<name>tabContext</name>
<class>oracle.ui.pattern.dynamicShell.TabContext</class>
<required/>
</input-parameter-definition>
This places the TabContext in the pageFlowScope.
The UI Shell has four principle areas or partitions. Each will be discussed in turn and illustrated in summary.
Global Area
The global area extends across the full width at the top of the UI Shell. It provides a consistent and persistent context for the user. It is the portion of the template "boilerplate" that provides the user with a sense of place. It should contain the UI controls that in general drive the contents of the other two "work" areas of the UI. Facets and attributes are provided in this area to suggest what those UI controls and displays should be, including: Logo, Branding Bar, Global Links, Global Toolbar, Global Search, and Global Tab.
Navigational Area
The navigational area uses either the navigation facet (e.g., left pane of the UI shell) or the innerToolbar facet (tool bar placed between the global tab and the inner content region). It can have controls that, in general, drive the contents of the local area. In other words, users should get the sense, after extended use of an application, that the navigational area controls act upon the local area and its contents.
Local Area
The local area is in the center of the UI Shell. Its where the user performs the bulk of the tasks. In other words, it is the main work area and typically takes a transactional form with UI controls and displays. Consequently, the splitter that divides the left pane navigational area from the local area was designed to favor the local area. That is, out of the box, significantly more real estate is allocated to the local area and, by default, the splitter closes to the left (i.e., all remaining space is allocated to the local area). The dynamic tabs method or the single replace-in-place method of presenting task flows is articulated in the local area Tab Methods .
Legal Area
The legal area extends the full width of the UI Shell at the bottom. It is the portion of the template "boilerplate" where legal notices, statements, and policies relevant to the application can appear. Like the global area, it can contain UI controls that navigate to other locations. Facets are provided in this area to suggest what those UI controls and displays should be, including, Copyright, About, Privacy, and so forth.
Launch Methods
Task flows can be launched by any UI construct into the local area via APIs provided by the ADF UI Shell template. In this pattern, three different examples of those constructs are given and illustrated: left hand side (LHS), inner toolbar, and from within a task flows.
When the user selects a link or button in the LHS pane, a taskflow opens in the Local Area.
Alternatively, the user can select a menu item or toolbar option to open a taskflow into the Local Area.
The last described alternative launch method is the user selecting a UI control in the current taskflow that launches a subsequent taskflow in the local area.
Close Methods
Task flows can be closed by APIs provided by the ADF UI Shell template. Three different examples of those constructs are given: Embedded Close Icon; Inner Toolbar Close option, and Close Button Within the Task Flow Example.
The embedded (no additional coding required) close icon renders on the same horizontal plane to the far right of the page when a taskflow is opened within a tab. The user activates the close icon on the selected taskflow (i.e., tab) which is dismissed from view.
With the inner toolbar close option, the user activates a close menu or toolbar item on the selected taskflow (i.e., tab) which is then dismissed from view.
A close button within the UI of the taskflow allows the user to dismiss that taskflow in the local area prior to or at the conclusion of the taskflow. Of course, the taskflow could "auto-dismiss" at the conclusion of a taskflow. However that is "bad" UI. The opening and closing of a user's task within a taskflow should always be under the control of the user.
Dirty" & "Clean" State Indication
When the state of user data changes within a task flow, that state change is indicated by changing the text style of the tab label from normal to italic (e.g., the Next Activity). This is most affective in UIs where the user will alternate between several taskflows across multiple tabs in the process of completing a task (e.g., copy data between task flows). In so doing, it would be helpful to remind the user -- particularly after a task interruption -- of which taskflow has changed data (i.e., dirty).
When all changed user data is committed (i.e., saved) the taskflow is "clean." At that point, the text style of the tab label toggles from italic to normal.
When the user attempts to close a task flow and the state of that task flow is "dirty", the user will receive a warning that the pending action could result in data loss. At that point the user should have a choice of one of two options.
Both options are viable to the user. In the first case, the user has made changes for which there is a desire to abandon. In the second case, the user may have inadvertently or unwittingly triggered a close on the task flow for which there is no desire to abandon recent changes.
The unsaved data warning that the user receives automatically at run time is a feature of the UI Shell in cases where it is a tab that is being closed while in a dirty state. Note. This feature is not available for cases outside of this template.
This feature should not be confused with the unsaved data warning on page navigation. That feature is not automatic but must be enabled at design time (DT) on a page by page case (e.g., each page based on the UI Shell template). When enabled, it provides a warning to the user in cases of navigation at the page level -- as oppose to the region level -- where pending changes have not been committed and the state of the page will be reset. In this case as well, the user has made changes for which there is a desire to abandon; or, the user inadvertently or unwittingly triggered a close at the page level for which there is no desire to abandon recent changes. The warning dialog presented in this case affords the user the same two choices. This feature is available in all cases, that is, with or without the use of the UI Shell template. For a description of how to enable this feature read the Warning on Unsaved Changes Functional UI Pattern on OTN at https://www.oracle.com/application-development/technologies/adf/unsaveddatawarning.html.
The UI Shell Template supports two tab methods: dynamic tabs or no tabs.
Dynamic tabs lets the user spawn new tabs for each taskflow instance and then closing it when, for example, the task has been completed. Taskflows can be launched within dynamic tabs by any UI construct (e.g., left hand side pane, toolbar, from within another taskflow). The tabs are dynamic in the sense that the tabs appear to the user when the contained task flow is launched and disappear when the contained task flow is closed.
Multiple instances of the same bounded taskflow can open in dynamic tabs. Create New is a typical use case where multiple instances of the same bounded taskflow is desired.
More typically, a single instance of a bounded taskflow opens in an dynamic tab. In the first invocation of taskflows of this type, a tab containing that taskflow appears. Any subsequent invocation of any of those taskflows, while they remain open, shifts the selected state to that taskflow.
Finally, there is the option of a replace-in-place single instance bounded taskflow. In the first invocation of a taskflow of this type, a single instance taskflow appears occupying the entire local content area (i.e., no tab). Any subsequent invocations of any taskflow results in a replace-in-place user experience (i.e., the subsequent taskflow also occupies the entire local content area replacing the previous taskflow). Note : This method can only be used exclusively of the other two (i.e., Dynamic Tabs for Multiple Instances and Dynamic Tabs for Single Instances) per page.
Too Many Tabs Warning Dialog
When the requested number of open task flows (i.e., tabs) exceeds the maximum allowed by the UI Shell (15), the user will automatically receive a "too many tabs" warning dialog. The dialog title text and body text are attributes of the UI Shell and can be specified at design time.
Detecting the Presence of Tabs
It is possible to determine if any tabs are open in the UI. This is useful for enabling or rendering any UI construct that has either the Disabled
or Rendered
property. The Close icon is an example use of this API. It is not rendered until one or more tabs are present. One example would be to enable/disable menu items at the presence or absence of tabs. Another would be to render or hide toolbar buttons at the presence or absence of tabs or taskflows.
Adding a Welcome Page
Often an application will have an introductory, "start", or "welcome" page. This can be the default UI for the user visiting the application. The UI Shell template has a single facet that can be used for this purpose. It is identified as the welcome facet. Content within the welcome facet displays when no other content (e.g., taskflows) are open on the page. Thus, its content appears as default when the page is displayed or when all taskflows are closed.
To recreate the demonstration application used to illustrate the UI Shell template, follow the steps below. The implementation of this demonstration is divided into 5 major steps.
Create Application Workspace
To start the development of a demonstration application:
UIShell
or other appropriate name for the Application Name.uiShellModel
and uiShellViewController
for the Model and ViewController respectively, or other appropriate names.src
or other appropriate prefix.Create the Demonstration Application Unbounded Task Flow
The demonstration application is composed of three jsp pages, each represented as a global tab.
Create the Page Flow for the Global TabsThe Control Flow Cases between the pages will be specified in the adfc-config.xml file.
First
, Second
, and Third
, respectively.First
activity.First
.Control Flow Case
from the Component Palette and add a case from the wild card control flow rule to the Second
activity.Second
.Third
activity.Third
.When completed, the adfc-config.xml diagram should appear as illustrated.
Create JSP Files Based on the UI Shell Template
Each page will be created based on the UI Shell template in turn. Although not fully illustrated here, each page is assumed, in practice, to represent a single application to the user. The goal here is to create three pages whereby major features and UI methods offered by the UI Shell template can be demonstrated.
Creating Pages
In this section, each page associated with each view activity will be created in turn, starting with First.
First
view activity.First.jspx
for the File Name.The DT view of the UI Shell template should appear in the Visual Editor.
First Page
for the Title property.Create the page associated with the Second view activity.
In this section, the page associated with the second view activity will be created, called Second.
adfc-config.xml
file, create the Second page by double-click on the Second
view activity.Second.jspx
for the File Name.The DT view of the UI Shell template should appear in the Visual Editor.
Second Page
for the Title property.Create the page associated with the Third view activity
In this section, the page associated with the third view activity will be created, called Third.
adfc-config.xml
file, create the Third page by double-click on the Third
view activity.Third.jspx
for the File Name..The DT view of the UI Shell template should appear in the Visual Editor.
Third Page
for the Title property.Add Global Tabs to Each Page
UI tabs are added to allow the user to navigate between pages of the application. There are three pages in this sample application.
To add global tabs to the first page:
globalTabs
facet in the Visual Editor.First
for the Text property.true
.Second
for the Text property.Third
for the Text property.To add global tabs to the second page:
globalTabs
facet in the Visual Editor.globalTabs
facet.First
for the Text property.Second
for the Text property.true
.Third
for the Text property.To add global tabs to the third page:
globalTabs
facet in the Visual EditorglobalTabs
facet.First
for the Text property.Second
for the Text property.Third
for the Text property.true
.Create Page Fragments and Taskflows
Taskflows can be called by contextual events from the navigational area to be rendered in the local content area. A taskflow may also be called from another taskflow within the local content area. In both cases, the result could be a taskflow within a dynamic tab (i.e., single instance, multiple instance) or within a replace-in-place panel that occupies the entire local area. Taskflows themselves could be comprised of a single page fragment or multiple page fragments. In either case, taskflows are bound and as a collection can present nearly all, if not all, of the value add defining an application.
For demonstrations purposes only, four taskflows will be created. Each will contain a single page fragment.
Create taskflow to use as multiple instance
To create the taskflow to demonstrate dynamic tabs of multiple instances:
new.xml
for the task flow File Name.C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\WEB-INF\flows
This is a convenience to improve the workspace organization.
multiple
.multiple
view activity (e.g., double-click).
This should result in the Create New JSF Page Fragment dialog in the Directory field, append the path to read:
C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\fragments
. This is a convenience to improve the workspace organization.
This is a new activity!
for the Value property.color:Purple; font-size:x-large; font-weight:bold;
First Steps
.Step 1: Do something
, Step 2: And then something else
, Step 3: Be happy!
for the Value property of each Output Text component, respectively.Second Steps
.Step 4: Make something cool
, Step 5: Get everyone to buy it
, Step 6: Prosper!!
for the Value property of each Output Text component, respectively.Create three task flows and associated page fragments to use as single instance dynamic tabs
To create the first taskflow and associated fragment:
first.xml
for the task flow name.C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\WEB-INF\flows
If not, use the Browse button to select WEB-INF > flows.
one
.one
view activity (e.g., double-click).The Directory field should default to: C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\fragments
If not, use the Browse button to select fragments.
First Steps
.Step 1: Do something
, Step 2: And then something else
, Step 3: Be happy!
for the Value property of each Output Text component, respectively.Second Steps
.Step 4: Make something cool
, Step 5: Get everyone to buy it
, Step 6: Prosper!!
for the Value property of each Output Text component, respectively.To create the second taskflow and associated fragment:
second.xml
for the task flow name.two
.two
view activity (e.g., double-click).The Directory field should default to: C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\fragments
If not, use the Browse button to select fragments.
vertical
.The second activity!
for the Value property.color:Orange; font-size:x-large; font-weight:bold;
Third Activity
in the Text property.To create the third taskflow and associated fragment:
third.xml
for the task flow name.three
.three
view activity (e.g., double-click).The Directory field should default to: C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\fragments
If not, use the Browse button to select WEB-INF > fragments.
vertical
.The third activity!
for the Value property.color:Blue; font-size:x-large; font-weight:bold;
Finish This Activity
in the Text property.Create Managed Bean
Note: Access to the APIs within TabContext are available only after a page within the application workspace has been added based on the Oracle Dynamic Tabs Shell template. Pages based on the Oracle Dynamic Tabs Shell template were created earlier.
To create a managed bean whereby the TabContext APIs can be called more conveniently:
Launcher
for Class Name.src.view
for the Package name or other appropriate package name.Launcher.java
file and save the file.
/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */
package src.view;
import javax.faces.event.ActionEvent;
import oracle.ui.pattern.dynamicShell.TabContext;
/**
* Launcher is a backingBean-scope managed bean. The public methods are
* available to EL. The methods call TabContext APIs available to the
* Dynamic Tab Shell Template. The boolean value for _launchActivity
* determines whether another tab instance is created or selected. Each tab
* (i.e., task flow) is tracked by ID. The title is the tab label.
*/
public class Launcher
{
public void multipleInstanceActivity(ActionEvent actionEvent)
{
/**
* Example method when called repeatedly, will open another instance as
* oppose to selecting a previously opened tab instance. Note the boolean
* to create another tab instance is set to true.
*/
_launchActivity(
"A New Activity",
"/WEB-INF/flows/new.xml#new",
true);
}
public void launchFirstActivity(ActionEvent actionEvent)
{
/**
* Example method to call a single instance task flow. Note the boolean
* to create another tab instance is set to false. The taskflow ID is used
* to track whether to create a new tab or select an existing one.
*/
_launchActivity(
"The First Activity",
"/WEB-INF/flows/first.xml#first",
false);
}
public void launchSecondActivity(ActionEvent actionEvent)
{
_launchActivity(
"Next Activity",
"/WEB-INF/flows/second.xml#second",
false);
}
public void launchThirdActivity(ActionEvent actionEvent)
{
_launchActivity(
"Third Activity",
"/WEB-INF/flows/third.xml#third",
false);
}
public void closeCurrentActivity(ActionEvent actionEvent)
{
TabContext tabContext = TabContext.getCurrentInstance();
int tabIndex = tabContext.getSelectedTabIndex();
if (tabIndex != -1)
{
tabContext.removeTab(tabIndex);
}
}
public void currentTabDirty(ActionEvent e)
{
/**
* When called, marks the current tab "dirty". Only at the View level
* is it possible to mark a tab dirty since the model level does not
* track to which tab data belongs.
*/
TabContext tabContext = TabContext.getCurrentInstance();
tabContext.markCurrentTabDirty(true);
}
public void currentTabClean(ActionEvent e)
{
TabContext tabContext = TabContext.getCurrentInstance();
tabContext.markCurrentTabDirty(false);
}
private void _launchActivity(String title, String taskflowId, boolean newTab)
{
try
{
if (newTab)
{
TabContext.getCurrentInstance().addTab(
title,
taskflowId);
}
else
{
TabContext.getCurrentInstance().addOrSelectTab(
title,
taskflowId);
}
}
catch (TabContext.TabOverflowException toe)
{
// causes a dialog to be displayed to the user saying that there are
// too many tabs open - the new tab will not be opened...
toe.handleDefault();
}
}
public void launchFirstReplaceNPlace(ActionEvent actionEvent)
{
TabContext tabContext = TabContext.getCurrentInstance();
try
{
tabContext.setMainContent("/WEB-INF/flows/first.xml#first");
}
catch (TabContext.TabContentAreaDirtyException toe)
{
// TODO: warn user TabContext api needed for this use case.
}
}
public void launchSecondReplaceNPlace(ActionEvent actionEvent)
{
TabContext tabContext = TabContext.getCurrentInstance();
try
{
tabContext.setMainContent("/WEB-INF/flows/second.xml#second");
}
catch (TabContext.TabContentAreaDirtyException toe)
{
// TODO: warn user TabContext api needed for this use case.
}
}
}
A reference to the managed bean should be added to the adfc-config.xml
file. This will allow the pages to pass control to the methods called within Launcher to realize the dynamic tab behavior.
To accomplish this:
launcher
for the Name.src.view.Launcher
for the Class.backingBean
for the Scope.Call Task Flows as Dynamic Tabs from Managed Bean
The methods within Launcher are accessible via EL. Each page will demonstrate a different method within Launcher.
To call three taskflows, each as a dynamic tab via a managed bean in the navigation pane in the first page:
For demonstration purposes, components comprising a UI will be nested within the navigation facet. However, it would be better practice to create a navigation taskflow. This would allow, for example, the convenience of adding it as a dynamic region to this facet. The result could be different navigation options based on the role or responsibility of the authenticated user -- each dynamic region containing a different navigation taskflow.
The Decroative Box adds rounded corners to its children. It also supports changing of the rendered theme of its children. In other words, it can act as a L&F transition between areas on a page. In this case, it distinguishes the Navigation Area from the Local Content Area.
vertical
.Choose your activity
for the Value property.font-size:large; font-weight:bold;
Start First Activity
for the Text property.launcher
in the Managed Bean drop down.launchFirstActivity
in the Method drop down.The Edit Property: ActionListener dialog will insert the following expression (EL): #{backingBeanScope.launcher.launchFirstActivity}
. Similar EL will be inserted with each use of the dialog for the Managed Bean: launcher
.
true
.Start Next Thing
for the Text property.true
.Execute Third Task
for the Text property.launcher
in the Managed Bean drop down.launchThirdActivity
in the Method drop down.true
.The Second page will demonstrate closing a taskflow from the toolbar, as well as, marking a tab dirty then clean.
To call three taskflows, each as a dynamic tab via a managed bean in the navigation toolbar in the second page:
vertical
.The Group component is necessary here to align both a menubar components and toolbar components horizontally in the same toolbar.
Action
.New
.launcher
in the Managed Bean drop down.multipleInstanceActivity
in the Method drop down.Next Activity
for the Text property.launcher
in the Managed Bean drop down.launchSecondActivity
in the Method drop down.Final Task
for the Text property.launcher
in the Managed Bean drop down.launchThirdActivity
in the Method drop down.Close
.launcher
in the Managed Bean drop down.closeCurrentActivity
in the Method drop down.#{viewScope.tabContext.selectedTabIndex < 0}
.
The viewScope object tabContext.selectedTabIndex
is made available via the TabContext
class. All available scope objects can be inspected via the Expression Builder ADF Managed Beans tree node on any page based on the UI Shell template. When the tabContext.selectedTabIndex
is less than zero (i.e., no dynamic tabs are open) the Close menu option is disabled.
Optionally, textual toolbar buttons, iconic toolbar buttons (if appropriate icons are available), or additional menu items (except for the first toolbar button) could be added.
The following steps assume icons are available for the enabled, disabled, mouseover, and mousedown states.
launcher
in the Managed Bean drop down.multipleInstanceActivity
in the Method drop down.launcher
in the Managed Bean drop down.currentTabDirty
in the Method drop down.
A more appropriate UI approach might be to set the tab dirty with a method call from a value change listener on input component(s) within the taskflow.
#{viewScope.tabContext.selectedTabIndex >= 0}
.
When the tabContext.selectedTabIndex
is greater than or equal zero (i.e., dynamic tabs are open) this property is true and the icon is rendered. Conversely, the Disabled property in the Behavior section of the Property Inspector could have been used with the appropriate EL to simply disable the icon when no dynamic tabs were opened. Both behaviors are good UI for toolbars depending on the larger context and UI goals. In either case, the same method (i.e., rendered, disabled) should be used for functions that are highly correlated.
launcher
in the Managed Bean drop down.currentTabClean
in the Method drop down.
A more appropriate UI approach might be to set the tab clean with a method call from button (e.g., submit, save) within the taskflow.
#{viewScope.tabContext.selectedTabIndex >= 0}
.
When the tabContext.selectedTabIndex
is greater than or equal zero (i.e., dynamic tabs are open) this property is true and the icon is rendered. Conversely, the Disabled property in the Behavior section of the Property Inspector could have been used with the appropriate EL to simply disable the icon when the no dynamic tabs were opened. Both behaviors are good UI for toolbars depending on the larger context and UI goals. In either case, the same method (i.e., rendered, disabled) should be used for functions that are highly correlated.
Note: Since a replace-in-place method cannot be called from a page that has dynamic tabs open (not only would it throw an exception, it is a poor UI method), the Third Page will be used.
To call three taskflows, each as a Replace-in-Place UI via a managed bean in the navigation toolbar in the third page:
vertical
.Action
.First Activity
for the Text property.launcher
in the Managed Bean drop down.launchFirstReplaceNPlace
in the Method drop down.Second Activity
for the Text property.launcher
in the Managed Bean drop down.launchSecondReplaceNPlace
in the Method drop down.
The taskflow called has within it a button when activated launches a separate taskflow. If the current taskflow is in a clean state, that subsequent taskflow will be called as a replace-in-place taskflow whether that call uses the TabContext.setMainContent
or the TabContext.getCurrentInstance
API. When the subsequent taskflow has a return or is closed, the calling taskflow is rendered. If the current taskflow is dirty, the call to the subsequent taskflow fails silently. This is a known issue.
launcher
in the Managed Bean drop down.closeCurrentActivity
in the Method drop down.#{viewScope.tabContext.selectedTabIndex < 0}
.Note: If the calling taskflow is open when the called taskflow is closed, selection returns to the calling taskflow when the replace-in-place method is used. When the dynamic tab method is used, the selection returns to the first called task flow.
To call a taskflow as a dynamic tab from another taskflow via a managed bean:
tabContext
for the Name.oracle.ui.pattern.dynamicShell.TabContex
for the Class.Adding the input paramter allows access to TabContext methods from within a task flow.
Third Activity
.launcher
in the Managed Bean drop down.launchThirdActivity
in the Method drop down.To call a taskflow as a Replace-in-Place UI from another taskflow via a managed bean:
Call taskflow three from within taskflow two with the TabContext.setMainContent
API from within the Third.jspx page. Because taskflow two will not "close" when taskflow three is called, navigation is transferred back to taskflow two when taskflow three is eventually closed.
Note: If a taskflow is in a dirty state, the UI Shell template as with other close methods (e.g., Close icon, Close menu item) will automatically raise an unsaved data warning dialog to the user.
To close a taskflow from within, prior to completion via a managed bean:
tabContext
for the Name.oracle.ui.pattern.dynamicShell.TabContex
for the Class.Adding the input paramter allows access to TabContext methods from within a task flow.
Finish This Activity
.launcher
in the Managed Bean drop down.closeCurrentActivity
in the Method drop down.An optional "Welcome Page" can be added to each page of the demo. It is advisable to add content to the welcome facet of each page based on the UI Shell template.
Create an Optional Welcome taskflow
The following steps will describe adding Welcome content to First.jspx only:
welcome.xml
for the task flow File Name.C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\WEB-INF\flows
This is a convenience to improve the workspace organization.
you
.you
view activity (e.g., double-click).
This should result in the Create New JSF Page Fragment dialog. In the Directory field, append the path to read:
C:\JDeveloper\mywork\UIShell\uiShellViewController\public_html\fragments
. This is a convenience to improve the workspace organization.
center
.vertical
.Welcome to Our Application!
in the Value field.color:Blue; font-size:x-large; font-weight:bold;
30
.Welcome
facet of First.jspx.The Welcome page should appear within First.jspx.
Run Application
At this point, run the demonstration application from any of the jspx pages (i.e., First, Second, Third) to see the various behaviors of the UI Shell.
Instead of completing these step, an ADF application on OTN called UIShell is available at https://www.oracle.com/docs/tech/developer-tools/uishellapp.zip. It can be unzipped into the designated work area and opened with JDeveloper. Simply download UIShell.zip; unzip the archive; and open the UIShell.jws with JDeveloper. This pattern has been tested against JDeveloper Studio 12c (12.1.2.0.0).
Use Case Example for Using the Dynamic Tab Shell Template Source Directly
As stated in Pattern Implementation, when a page is based on the Oracle Dynamic Tab Shell template, the template and its associated ADF artifacts and Java classes are added to the JDeveloper workspace (i.e., the ADF application) by reference. There are use cases where it is more convenient to include these ADF artifacts and Java classes into a workspace (i.e., *.jws) directly. For example, the content for the facets (e.g., global links, legal notices) for a series of pages based on the template may all be identical. Instead of copying that content over and over to each created page based on the template, it may be more efficient to add that content once to the dynamicTabShell.jspx (i.e., the template file) and then deploy that workspace as an ADF library for reuse. The modified template is available to team members with those modifications in place. The Oracle Dynamic Tab Shell template source is available as a JDeveloper workspace on OTN within an archive at https://www.oracle.com/technetwork/developer-tools/adf/dynamic-tab-shell-src-121200.zip.
As separate to the dynamic tab feature provided by the ADF UI Shell, contemporary browsers give the user the ability to open multiple tabs within the browser. Each browser tab can view different URLs allowing the user to browse different websites simultaneously, or even the same website multiple times.
While the implementation of this is browser specific, currently all contemporary browsers including Apple's Safari, Google's Chrome, Microsoft's Internet Explorer and Mozilla Firefox do not maintain separate network sessions to websites for each browser tab. Rather if a user is visiting the same website multiple times across browser tabs, the same user session will be used.
From the server side Oracle's ADF does provide the ability to support multi browser tabs sharing the same session though it is left up to the ADF programmer to decide if they wish their application to support this through the correct use of pageFlowScope beans. While it does seem desirable to support this be default, allowing the user to surf your application multiple times simultaneously can impact the load on your system so you need to consider your options.
In considering the ADF UI Shell's options it does not support multi browser tabs by default. To enable this you must add the context parameter USE_PAGEFLOW_TAB_TRACKING equal to true in your web.xml.
To enable multi browser tab support for the ADF UI Shell in your application:
There is a known issues with the Oracle Dynamic Shell Template. The unsaved data warning dialog unavailable with tabcontext.setmaincontent.
Related Topics
https://www.oracle.com/application-development/technologies/adf/unsaveddatawarning.html