The front-end API is all the facilities that run on the browser.
This includes HTML, CSS, JavaScript, image files, etc. The Kiss
back-end does not produce or modify HTML or JavaScript code. These
files are served, unaltered, by the server as they are on the back-end
disk. The Kiss model is that the browser receives these files
from the server, and that they include all the code that the browser
needs to perform its function. Besides these static files, all data
is communicated between the back-end and front-end via REST services.
Having all of the display logic running on the front-end or user’s browser makes a lot of sense for the following reasons:
All of this leads to the following:
The front-end API is documented in the file manual/jsdoc/index.html.
On the front-end, the class Server is what deals with the REST
communications between the front-end and back-end. In it, there are a
handful of methods that deal with the environment, such as the back-end
URL. All communications between the back-end and front-end are done
with JSON.
The way it works is the login service requires a username and password, and it returns a login token (UUID). That token is used in all future calls, and it gets automatically invalidated after a certain amount of non-use time. There is no state kept on the back-end. Each REST call must login to the back-end with the provided token in order to be authenticated to communicate.
The method used to communicate is named Server.call(). It is passed the
path to the REST service, the REST service method name, and a JSON
object that is sent to the back-end method. A Promise is
returned that is used to obtain the result of the call. This
can also be used with async/await.
There is also a logout method that simply erases the
login token so that future communications cannot occur.
The Server class also includes a method (fileUploadSend)
that makes it easy to upload files.
Although HTML provides what is needed for real applications, it provides those facilities at too low a level to be useful without a lot of custom code. Custom components (tags) allow you to encapsulate that advanced behavior into what is used as and appears as native functionality.
Kiss provides the ability to create your own custom HTML tags
or elements as well as use those provided by Kiss. There are
two principal user methods that make this work.
Utils.useComponent is used to load either a Kiss defined
component or one you define yourself (there is no difference). This
loads the JavaScript file that defines the new tag. All of the
components that come with the Kiss system are under the
src/main/frontend/kiss/component directory. You can see those
files for examples of how custom tags are defined.
New application pages are loaded with the Utils.loadPage
method. In addition to loading the HTML and JavaScript code
associated with that page, this method performs the processing
necessary to make the components work. It does this intelligently so
that, for example, one component can use another component without any
special loading order requirement.
Briefly, the code that describes the custom tag must describe what the tag is replaced with. Ultimately, it must boil down to straight HTML, CSS, and JavaScript code.
Let’s say you have a pop-up window that allows a user to search for employees, products, or whatever. The user gets a variety of search capabilities and the selected item is returned. Let’s further say that you need this functionality in several places within your application. These are tagless components. They aren’t placed with a custom tag. They are a response to an event like a button push. Tagless components allow you to encapsulate a block of functionality (including pop-up windows) into a neat package that can be reused in any number of places.
The method used to load tagless components is
Utils.useTaglessComponent. Later, when the tagless component
is needed, one would execute Kiss.MyComponent.run(in_data, on_exit) (where
MyComponent is the name of your tagless component).
in_data represents possible data passed to the component on entry.
on_exit is a function that gets executed when the component exits.
Arguments passed to on_exit are determined by the component.
Kiss supports draggable, modal popup windows. HTML is used to describe the layout of the popup, and JavaScript is used to control the appearance of the popup.
The HTML portion is represented as a top-level popup tag
that represents the entire popup. Within the top-level popup
there must be two child tags named popup-title and
popup-body. The first represents the single line header, and
the second represents the body of the popup window.
The top-level popup tag’s attribute section must contain the following:
id="my-popup"an ID is needed to reference the popup
width="600px" height="300px"Set the height and width of the popup
An example is as follows:
<popup id="my-popup" width="600px" height="300px">
<popup-title>The title</popup-title>
<popup-body>
The content
<div style="display: inline-block; position: absolute; bottom: 20px; right: 20px;">
<push-button id="cancel" style="margin-left: 15px;">Cancel</push-button>
<push-button id="ok" style="margin-left: 15px;">Ok</push-button>
</div>
</popup-body>
</popup>
There are only two JavaScript functions used to control the popup.
Utils.popup_open(id [, focus-id])open the popup indicated by the id, and if focus-id is present, set initial focus to that control
Utils.popup_close()close the most recent popup
Your defined responses to the buttons on the popup determine your dealings with the data on the popup and when to close it.
Kiss includes facilities that make it easy to upload files.
The HTML uses a <file-upload> control, and the
Server.fileUploadSend() method handles the transfer to the
back-end. The file-upload control provides helper methods
such as numberOfUploadFiles() and getFormData().
On the back-end, the servlet provides methods to access uploaded
files: getUploadFileCount(), getUploadFileName(),
getUploadBufferedInputStream(), and saveUploadFile().
See the included example application and the Kiss book for complete front-end and back-end file upload examples.
Kiss includes an ever-growing set of utilities to help deal with common tasks.
These utilities are located under the src/main/frontend/kiss directory and have names such as
DateTimeUtils.js, DateUtils.js, TimeUtils.js, Utils.js, etc. These utilities
are documented in the front-end API documentation.
Application state that must survive page navigation and browser reloads
is kept in a single client-side store named AppState. The login
token is not treated specially; it is simply one reserved entry stored
alongside any other front-end state. AppState is the only part
of the system that accesses the browser’s Web Storage directly.
By default each browser tab is its own isolated session: state survives
a reload but is not shared between tabs, so two tabs never overwrite each
other’s data and a new tab requires its own login. This behavior is
configurable (per-tab, shared across all tabs, or in-memory only). Data
passed between screens (Utils.saveData and Utils.getData)
is also kept in AppState, so it too survives a reload.
Because the token persists, a reloaded or deep-linked page resumes the existing session automatically. When the back-end is restarted, however, its in-memory sessions are gone; Kiss detects this and asks the user to log in again rather than resuming onto a dead session.
Kiss gives each screen its own URL through a hash-based router
(Router). Because routing happens entirely in the browser by way
of the URL hash (for example #/customer/123), it requires no
server-side URL rewriting and behaves identically on the development
server, file://, Tomcat, and Electron. Each screen
becomes deep-linkable and bookmarkable, and the browser Back and Forward
buttons navigate between screens.
Routes are declared in the application file
src/main/frontend/routes.js. A route may carry path parameters
(for example :id) that the target screen can read. Screens that
need no special handling require no entry at all: with file-based
fallback enabled, a URL matching no declared route is loaded as a screen
of the same name from a configured root directory.
Routes that require a logged-in user (the default) are guarded. A deep link followed while logged out is redirected to the login screen, carrying the requested location, so that after authenticating the user lands on the page they originally requested.
Browsers have a mind of their own in terms of deciding when to use their cache for a file and when to download a new one. This can cause no end of trouble when code gets changed. Some user files end up being old from the browser cache, and others are freshly downloaded. The old and new files don’t agree with each other and all sorts of errors occur.
Kiss includes a facility that forces every downloaded file to be
re-fetched whenever the application is upgraded, while still taking
maximal advantage of the browser cache when the files have not changed.
It is driven by a single version number and requires no server
configuration, so it works on the development server, file://,
Tomcat, and Electron alike.
The version lives in index.html, which is the one file Kiss
keeps perpetually fresh. Because index.html is always current,
its version is always current, and every other file the application
downloads is requested with that version appended – so a single change
to the version forces all of them to be re-downloaded. Once the new
files are loaded, the browser cache works as normal until the next
version change. When a production WAR is built, Kiss
stamps a fresh version automatically, so every release force-refreshes
all clients with no manual step. During development the mechanism is
turned off, so edited files are seen immediately on reload.
Kiss delivers a Content-Security-Policy together with a set
of standard security response headers (clickjacking protection,
X-Content-Type-Options, Referrer-Policy, and, over HTTPS,
Strict-Transport-Security) on every response. The
Content-Security-Policy restricts where the page may load scripts,
styles, images, and network connections from, which closes off the most
common cross-site-scripting attacks.
These headers are added by a filter that ships inside the application
WAR and registers itself automatically, so no servlet-container
(Tomcat) configuration is required. The supplied policy already
accommodates the Kiss front-end; an application that introduces a
new external origin (for example a separated production back-end) adjusts
the policy in one place.
Although not a part of the Kiss system, there are some very valuable technologies and libraries that have been used with Kiss in order to create some very powerful solutions.
The first is the Lovefield library, which adds SQL capabilities on the browser side. Data is persisted on the user’s browser and remains through browser or machine reboots. The library is located at https://github.com/google/lovefield
A recent technology that has been used to enable browser applications
that run when there is no Internet connection is called Service
Workers. There is a package at
https://developers.google.com/web/tools/workbox that makes
working with service workers very easy.
For in-depth coverage of the front-end component system, grid integration, popup windows, and utility classes, see the Kiss book.