Advanced UI components
Overview
Flavour provides some custom UI components to solve common tasks. They are optimized to work with Twitter Bootstrap, so class names generated by these components are compatible with Bootstrap. If you don’t use Bootstrap, you may write your CSS which add styles to corresponding classes. The easiest way to learn which classes you need is to apply components and examine DOM in your browser’s dev tools, or simply look through the source code of the components.
Additionally, Flavour uses its own classes for some components. It also comes with predefined CSS, which is optional.
For quick start you may simply include following lines to your HTML:
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="flavour/widgets.css">
Advanced components packages are not included by default, so you should use following processing instruction in your templates:
<?use w:org.teavm.flavour.widgets?>
Calendar
HTML 5 introduces different input
types, including date
.
However, sometimes you may want to polyfill this component,
in order to get more customizable styles,
to change date format, and so forth.
Flavour provides two components to edit date fields.
First one is calendar
that insert calendar into web page:
<w:calendar value="expression" onchange="action" locale="expression" />
where
value="expression"
specifiesDate
value which is displayed by the component.onchange="action"
is optional attribute that specifies change handler.locale="expression"
is optionalString
attribute that specifies locale. Calendar appearance may differ in different locales, for example, highlight weekdays with respect to given country.
Second one is date
attribute that adds drop-down calendar to input
field:
<input type="text" w:date="{ format: expression, locale: expression }">
Modal dialog
To show view object as a modal dialog, you can use Popup.showModal
method.
This method accepts view object that additionally implements PopupContent
.
PopupContent
requires to implement single method called setDelegate
.
When Flavour creates modal window, it passes its representative to setDelegate
,
so that modal view could interact with popup window, for example, close it.
Note that unlike most JavaScript frameworks, Popup.showModal
exits after the dialog been closed,
either by user, who pushed close button, or programmatically via PopupDelegate.close
.
This behaviour is similar to most desktop UI frameworks, like Swing and SWT.
Running actions in background
TeaVM allows to run background actions in Thread
.
However, Flavour does not know anything about threads and won’t update DOM
if thread updates state of view objects.
Instead, you should use BackgroundWorker
class that:
- updates templates after background action gets finished;
- provides
busy
state, that indicates whetherBackgroundWorker
is running any actions.
Example:
BackgroundWorker worker = new BackgroundWorker();
worker.run(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
})
You can monitor worker’s state by calling isBusy()
method.
It’s useful to expose isBusy()
state to view objects so that template could disable corresponding
UI elements until action completes.
Paginator
Flavour provides API that allows to show small parts of a large collection, page-by-page.
This API includes several parts.
First, you should implement DataSource
interface, for example:
public class SimpleDataSource<T> implements DataSource<T> {
private List<T> list;
public SimpleDataSource(List<T> list) {
this.list = list;
}
@Override
public List<T> fetch(int offset, int limit) {
if (offset >= list.size()) {
return Collections.emptyList();
}
return new ArrayList<>(list.subList(offset, Math.min(list.size(), offset + limit)));
}
@Override
public int count() {
return list.size();
}
}
The real-world implementation may communicate server via REST API,
and server, in turn, may query data from database
(in case of SQL database offset
and limit
parameters map directly to corresponding SQL query clauses).
Second, create PagedCursor
instance, for example:
PagedCursor<String> cursor = new PagedCursor<>(new SimpleDataSource<>(Arrays.asList("foo", "bar")));
Third, bind this cursor to DOM:
<ul>
<std:foreach var="item" in="cursor">
<html:text value="item"/>
</std:foreach>
</ul>
Finally, bind the same cursor to paginator component. It has the following syntax:
<w:paginator data="expression" max-pages="expression" page-link="(pageNumber, consumer) -> expression"/>
Where
data="expression"
is a cursor that displays data.max-pages="expression"
is an optional expression that specifies the maximum number of pages that will be shown by the component.page-link="(pageNumber, consumer) -> expression"
is an optional lambda expression that generates link to page. See html:link component for description ofconsumer
parameter. It this attribute presents, paginator will update current URL as users clicks the page button.
Note that actually paginator accepts Pageable
implementation as a data source,
so you may implement Pageable
yourself rather than using PagedCursor
.
- Previous
- Next