Over http, the modules. This is the form to use, and the only one under which the unit tests run.
<script type="module" src="wexa_statics/js/wexa.js"></script>
Whakerexa > Getting started > JavaScript
The JavaScript of Whakerexa is a set of ES6 modules, one class per file, with no
dependency and no build step. A single module gathers them: wexa.js
imports the classes of the framework, exports them, and puts them under the global
Wexa. A page loads that one file and has the whole API.
Each component has its own page in this documentation, with a living demonstration. This page describes what holds them together: how the API is loaded, what it contains, when the code runs, and the conventions a new module follows.
ES6 modules are refused by a browser on file://. Whakerexa therefore
ships the same code twice: the modules, and wexa.bundle.js, a single
file that defines window.Wexa without any import. Both
give the same names to a page.
Over http, the modules. This is the form to use, and the only one under which the unit tests run.
<script type="module" src="wexa_statics/js/wexa.js"></script>
From the disk, the bundle. It is generated from the sources and is never edited by hand; see Bundle.
<script src="wexa_statics/js/wexa.bundle.js"></script>
A page that has to work both ways says neither of the two: it names the loader, which reads the protocol and takes the modules over http, the bundle from the disk. Every page of this documentation ends with this line.
<script src="wexa_statics/js/wexa.loader.js"
data-base="wexa_statics/"></script>
One tag does the choosing, and says at the same time what the page brings: its themes, its sets of icons, the extras it loads. Everything is registered before the framework reads the address, so a theme or a set named in the address is known when it is asked for.
<script src="wexa_statics/js/wexa.loader.js"
data-base="wexa_statics/"
data-default="wexa_theme"
data-links="btn-back,nav-menu"></script>
| Attribute | What it says |
|---|---|
data-base | Where wexa_statics/ stands, seen from the page. Required. |
data-default | The theme to apply when the address names none. |
data-themes | The themes the page takes, in the order it cycles through them: a name alone chooses among those of the framework, name:path is one the page brings. Naming none of the framework's takes them all. |
data-themes-base | Where the themes of the framework stand, when they are not under css/themes/ of the base. |
data-icons | The sets the page brings, one per line, written name:path:file,file. |
data-icons-default | The set to show when the address names none. |
data-icons-fallback | The set that answers what the others leave unanswered. |
data-links | The identifiers whose address carries the theme and the set. |
data-extras | The files to load besides wexa.js, separated by commas. Ignored on file://, where the bundle already holds them. |
A path a page writes — a theme, a set of icons, an extra — is read from
data-base only when it is written bare, as the files of the
framework are. One written ./ or ../ is read from the
page, one written / from the root of the site, one carrying a
scheme from its host.
What the framework says goes to the console, and a page says how much of it it wants to hear. It is written before the loader, on the namespace: a call would come after the messages of the loading. A name as Python writes it, or a number between 0 and 50; nothing said, the level is 20.
<script>
window.Wexa = window.Wexa || {};
window.Wexa.logLevel = 'warning';
</script>
<script src="wexa_statics/js/wexa.loader.js" data-base="wexa_statics/"></script>
Once the page is open, Wexa.logger.setLogLevel('debug') changes it,
for an author looking at what he is writing.
A page that has something of its own to start declares a function named
bootPage: it is called once everything is loaded, and receives the
namespace of the framework and the extras it asked for.
Two ways, and only two. Either the loader is asked for everything
— it reads the protocol, registers the themes and the sets, and hands the
namespace to bootPage —, or the page does the wiring itself: it names
wexa.js or wexa.bundle.js, builds its
ThemeManager, registers what it wants and declares its sets of icons.
What must not be done is half of each: a theme registered after the loader has
read the address is a name the manager has already refused.
What this is for, what it deliberately does not do, and why: logger-design.html for what the framework says, javascript-design.html for the rest.
Wexa holdsThe namespace makes a difference the framework maintains everywhere: a service that must exist exactly once is already built and answers under a lowercase name; a component a page may own several of is exposed as a class, under its own name.
| Name | Class | Answers for |
|---|---|---|
Wexa.logger |
WexaLogger |
The messages of the framework, filtered by level. |
Wexa.onload |
OnLoadManager |
The code that waits for the page to be there, in the order it was given. |
Wexa.icons |
IconManager |
The sets of icons, the one in force, and the drawing a name is answered with. |
Wexa.accessibility |
AccessibilityManager |
Color mode and contrast mode, and the parameters that carry them. |
Wexa.dialog |
DialogManager |
Opening and closing dialogs and video popups. |
Wexa.links |
LinkController |
Elements navigating through data-href, with or without parameters. |
A service is called, never instantiated.
Wexa.accessibility.switchColorScheme();
Wexa.dialog.open('dlg-about', true);
Wexa.logger.info('Page ready.');
| Class | What it does | Page |
|---|---|---|
MenuManager |
A navigation bar, its submenus, its side and mobile states. | Menus |
ProgressBar |
A progress bar, driven by a page or by a request. | Progress bar |
ToggleSelector |
A group of checkboxes with a button that checks or clears them. | Switch |
AccessibilityNav |
The bar that switches the theme, the contrast and the color mode. | Accessibility |
KeyboardController |
The keys a page answers, and the guard that gives back the others. | Accessibility |
RequestManager |
Requests to the server that serves the page, with a JSON answer or not. | — |
BaseManager |
What a manager talking to a server inherits: the form it submits, the result it shows. | — |
The classes behind the services are exported too, under their own name. A page that owns several navigation bars builds them itself, and a page that needs a second dialog manager is not forbidden one.
A component looking for an element it decorates cannot run before that element
exists. Wexa.onload holds the functions that wait, and runs them in the
order they were given, once the document is loaded. The framework uses it for
itself: wexa.js registers there what makes every data-href
element reachable with the Tab key.
Registering is enough; nothing else has to be listened to.
Wexa.onload.addLoadFunction(() => {
const menu = new Wexa.MenuManager();
menu.registerSubmenu('appmenu-framework', 'submenu-toggle-framework');
menu.initMobileToggle();
});
A module never writes into the console directly: it says it to the logger, which prefixes the message and drops it if it is below the level of the page. A level is a name as Python writes it, or the number that goes with it, and the default is 20 — information, warnings and errors are shown, debug messages are not. A page says its own before the loader, as above.
| Level | Method | For |
|---|---|---|
| 10 | debug() | What is followed while a component is being written. |
| 20 | info() | What a page does and succeeds at. |
| 30 | warn() | What is odd but has an answer. |
| 40 | error() | What failed, with the exception if there is one. |
| 50 | critical() | What stops the component from working at all. |
A page asking to see everything lowers the level; 0 silences nothing, it shows all of it.
Wexa.logger.setLogLevel('debug');
Wexa.logger.debug('Slides: 57 pages laid out.');
The extras are not in Wexa: a page that does not display a bibliography
has no reason to download the parser of one. They live in
js/extras/ and are imported by the page that needs them. The bundle
carries them all, so on file:// they are found under
Wexa as well.
Five extras are available: the table of contents, the sortable table, the theme switcher, the piano keyboard and the slides.
<script type="module">
import { Book } from '../wexa_statics/js/extras/book.js';
import { SortaTable } from '../wexa_statics/js/extras/sortatable.js';
import { ThemeManager } from '../wexa_statics/js/customize/theme_manager.js';
const themes = new ThemeManager();
themes.register('wexa_theme', '../wexa_statics/css/themes/wexa_theme.css');
themes.register('aurora', '../wexa_statics/css/themes/wexa_theme_aurora.css');
</script>
A component that has something to announce dispatches a CustomEvent on
the document. The name carries its domain first, then what happened —
slides:navigate, slides:viewmode,
wexa:slides:ready. This is also what a keyboard shortcut may be given
instead of a function.
The shortcut says the name of the event; whoever navigates listens for it.
const keyboard = new Wexa.KeyboardController();
keyboard.register({keys: ['ArrowRight'], action: 'page:next',
label: 'Next page', preventsDefault: true});
keyboard.init();
document.addEventListener('page:next', () => book.nextPage());
A new file of the framework is written like the ones already there. What follows is what they all do.
@example of its use. Every public
method is documented with its parameters and what it returns.#. A member written with a leading underscore is internal too, but
a class inheriting it may use it.localStorage. What has to survive a page carries
itself in the URL, the way the color and contrast modes do with
wexa_color and wexa_contrast.