Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
hpehl committed May 6, 2024
1 parent bcb6147 commit 8b0d598
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 23 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,9 @@ Finally, use the static methods in `org.jboss.elemento.mathml.MathML` to create

# Flow

The module `elemento-flow` provides a way to execute a list of asynchronous tasks in parallel or sequentially, or to execute a single task repeatedly as long as certain conditions are met.
The class [Flow](https://hal.github.io/elemento/apidocs/org/jboss/elemento/flow/Flow.html) provides methods to execute a list of asynchronous tasks in parallel or sequentially, or to execute a single task repeatedly as long as certain conditions are met.

See the API documentation of [Flow](https://hal.github.io/elemento/apidocs/org/jboss/elemento/flow/Flow.html) for more details.
See the API documentation of [`org.jboss.elemento.flow`](https://hal.github.io/elemento/apidocs/org/jboss/elemento/flow/package-summary.html) for more details.

## Parallel

Expand Down Expand Up @@ -447,36 +447,37 @@ Flow.repeat(new FlowContext(), currentTime)

Elemento offers a very basic router. The router is minimal invasive and built around a few simple concepts:

- `Route`: Annotation that can be used to decorate pages. An annotation processor collects all classes annotated with `@Route` and generates an implementation of `Routes`.
- `Routes`: Provides a map of places and their corresponding pages. This can be used to register all places in one go.
- `@Route`: Annotation to mark a page implementation as place. An annotation processor collects all pages annotated with `@Route` and generates an instance of `Places`. Routes can have parameters like in `/contacts/:contactId`.
- `Place`: Data class that represents a place in an application. A place is identified by a route, and can have an optional title and a custom root element. If present the children of the root element are replaced by the elements of the page.
- `Page`: Simple interface that represents a collection of HTML elements. Implementations need to implement a single method: `Iterable<HTMLElement> elements()`
- `Places`: Builder to set up places. Supports nested places and loaders.
- `Page`: Simple interface that represents a collection of HTML elements. Implementations need to implement a single method: `Iterable<HTMLElement> elements(Place, Parameter, LoaderData)`.
- `PlaceManager`: Class that keeps track of registered places, handles navigation events, and updates the DOM accordingly. The place manager can be customized using builder like methods and has a `start()` method to show the initial page.
- `Loader<T>`: Functional interface to asynchronously load data, before a page is added to the DOM. The loader function gets the place and parameters as input and returns a promise of the data to be loaded: `Promise<T> load(Place place, Parameter parameter)`.

See the API documentation of [PlaceManager](https://hal.github.io/elemento/apidocs/org/jboss/elemento/router/PlaceManager.html) for more details.

```java
@Route("/")
public class HomePage implements Page {
@Route("/home")
public static class HomePage implements Page {

@Override
public Iterable<HTMLElement> elements() {
public Iterable<HTMLElement> elements(Place place, Parameter parameter, LoaderData data) {
return singletonList(div()
.add(h(1, "Welcome"))
.add(p().textContent("Hello world!"))
.element());
}
}

public class Application {
public static class Application {

public void entryPoint() {
body().add(div().id("main"));
new PlaceManager()
.root(By.id("main"))
.register(new Place("/"), HomePage::new)
.register(place("/home"), HomePage::new)
// could also be registered with
// .register(RoutesImpl.INSTANCE.places());
// .register(new GeneratedPlaces())
.start();
}
}
Expand Down
22 changes: 22 additions & 0 deletions logger/src/main/java/org/jboss/elemento/logger/Logger.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ public class Logger {

// ------------------------------------------------------ static API

/**
* Retrieves or creates a logger with the specified category.
*
* @param category the category of the logger
* @return the logger instance
*/
public static Logger getLogger(String category) {
Logger logger;
if (category == null || category.isEmpty()) {
Expand All @@ -98,17 +104,33 @@ public static Logger getLogger(String category) {
return logger;
}

/**
* Sets the global log level.
*
* @param level the desired log level to be set
*/
public static void setLevel(Level level) {
Logger.level = level;
console.info("Set global log level to %s", level.name());
}

/**
* Sets the log level for a given category.
*
* @param category the category for which to set the log level
* @param level the log level to be set
*/
public static void setLevel(String category, Level level) {
levelOverrides.addLevel(category, level);
applyOverrides();
console.info("Set log level for %s to %s", category, level.name());
}

/**
* Resets the log level for the specified category to the global log level.
*
* @param category the category for which the log level needs to be reset
*/
@JsMethod
public static void resetLevel(String category) {
levelOverrides.removeLevel(category);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.List;

import javax.annotation.processing.Filer;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
Expand Down
2 changes: 1 addition & 1 deletion router/src/demo/java/PlaceManagerDemo.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void entryPoint() {
.root(By.id("main"))
.register(place("/home"), HomePage::new)
// could also be registered with
// .register(RoutesImpl.INSTANCE.places())
// .register(new GeneratedPlaces())
.start();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@
*/
package org.jboss.elemento.router;

/**
* An interface that represents a handler for performing actions after a place is changed.
*/
@FunctionalInterface
public interface AfterPlaceHandler {

/**
* Executes the specified actions after a place is changed.
*
* @param placeManager the PlaceManager instance that manages the places
* @param place the new place that has been changed to
*/
void afterPlace(PlaceManager placeManager, Place place);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package org.jboss.elemento.router;

/**
* This functional interface represents a handler that is executed before a place transition occurs.
*/
@FunctionalInterface
public interface BeforePlaceHandler {

Expand Down
13 changes: 13 additions & 0 deletions router/src/main/java/org/jboss/elemento/router/Loader.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,21 @@

import elemental2.promise.Promise;

/**
* Functional interface representing a loader function that loads data for a given place.
*
* @param <T> the type of data to be loaded
*/
@FunctionalInterface
public interface Loader<T> {

/**
* Loads data for a given place using a specified parameter.
*
* @param place the place for which data needs to be loaded
* @param parameter the parameter used for loading data
* @param <T> the type of data to be loaded
* @return a Promise representing the asynchronous loading operation
*/
Promise<T> load(Place place, Parameter parameter);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package org.jboss.elemento.router;

/**
* The LoaderData class represents data loaded by a loader. It can be used to retrieve loaded data.
*/
public class LoaderData {

public static final LoaderData NONE = new LoaderData(null);
Expand Down
4 changes: 4 additions & 0 deletions router/src/main/java/org/jboss/elemento/router/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

import static java.util.Collections.emptyMap;

/**
* The Parameter class is used to represent parameters in a route path. A parameter is a part of the path that starts with a
* colon (e.g. ":id"). Parameters are used to retrieve values from a path.
*/
public class Parameter {

static boolean isParameter(String value) {
Expand Down
2 changes: 1 addition & 1 deletion router/src/main/java/org/jboss/elemento/router/Path.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static String normalize(String path) {
}

static String[] split(String path) {
if (path != null && !path.isEmpty() && !path.isBlank()) {
if (path != null && !path.trim().isEmpty()) {
String normalizedNoSlash = normalize(path).substring(1);
if (!normalizedNoSlash.isEmpty()) {
return normalizedNoSlash.split("/");
Expand Down
14 changes: 10 additions & 4 deletions router/src/main/java/org/jboss/elemento/router/Place.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@
import static org.jboss.elemento.router.Path.normalize;

/**
* Represents a place in an application. A place is identified by a route, and can have an optional title and a custom root
* element.
* Represents a place in an application. A place is identified by a route that can have parameters, an optional title, a custom
* root and an optional {@link Loader}. element.
* <p>
* If the route has parameters, the {@link PlaceManager} will collect it and pass it to the page when calling
* {@link Page#elements(Place, Parameter, LoaderData)}.
* <p>
* If the page has a {@link Loader}, the {@link PlaceManager} will call it and pass the loaded data as {@link LoaderData} to the
* page when calling {@link Page#elements(Place, Parameter, LoaderData)}.
* <p>
* If a title is given, the {@link PlaceManager} will change the document title accordingly. If a custom root selector or
* element is given, the {@link PlaceManager} will replace the contents of that element with the {@link Page} registered for
Expand All @@ -53,7 +59,7 @@ public static Place place(String route) {
Loader<?> loader;

Place(String route) {
if (route == null || route.isEmpty() || route.isBlank()) {
if (route == null || route.trim().isEmpty()) {
throw new IllegalArgumentException("Route must not be null or empty!");
}
this.route = normalize(route);
Expand Down Expand Up @@ -94,7 +100,7 @@ public String toString() {
builder.append(", custom root");
}
if (loader != null) {
builder.append(", with loader");
builder.append(", <loader>");
}
builder.append(')');
return builder.toString();
Expand Down
17 changes: 11 additions & 6 deletions router/src/main/java/org/jboss/elemento/router/PlaceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import static org.jboss.elemento.Elements.div;
import static org.jboss.elemento.Elements.h;
import static org.jboss.elemento.Elements.p;
import static org.jboss.elemento.Elements.pre;
import static org.jboss.elemento.Elements.removeChildrenFrom;
import static org.jboss.elemento.EventType.bind;
import static org.jboss.elemento.EventType.click;
Expand Down Expand Up @@ -312,13 +313,15 @@ private Promise<Boolean> gotoPlace(PlaceManagerStruct pms) {
logger.debug("Load data for %s", pms.place);
return pms.place.loader.load(pms.place, pms.parameter)
.then(data -> {
logger.debug("Create page for %s", pms.place);
logger.debug("Data loaded successfully. Create page for %s", pms.place);
pms.data = new LoaderData(data);
pms.page = pageSupplier.get();
return gotoPage(pms);
})
.catch_(error -> {
pms.data = new LoaderData(String.valueOf(error));
String errorAsString = String.valueOf(error);
logger.error("Unable to load page for %s: %s", pms.place, errorAsString);
pms.data = new LoaderData(errorAsString);
pms.page = noData(pms.place);
return gotoPage(pms);
});
Expand Down Expand Up @@ -368,7 +371,7 @@ private Page notFound(Place place) {
private Page noData(Place place) {
logger.debug("No data for %s", place);
if (noData != null) {
return notFound.get();
return noData.get();
} else {
return new DefaultNoData();
}
Expand All @@ -395,8 +398,9 @@ private static class PlaceManagerStruct {

private static final String ROOT_STYLE = "display:grid;place-items:center;height:100vh";
private static final String CONTAINER_STYLE = "width:50%;height:50%;";
private static final String HEADER_STYLE = "font-size:3rem;text-align:center";
private static final String PARAGRAPH_STYLE = "font-size:1.5rem;text-align:center";
private static final String HEADER_STYLE = "font-size:3rem;text-align:center;margin-bottom:1rem";
private static final String PARAGRAPH_STYLE = "font-size:1.5rem;text-align:center;margin-bottom:1rem";
private static final String ERROR_STYLE = "font-size:1.2rem;text-align:center;text-wrap:wrap;";

private static class DefaultNotFound implements Page {

Expand All @@ -422,7 +426,8 @@ public Iterable<HTMLElement> elements(Place place, Parameter parameter, LoaderDa
.add(div().style(CONTAINER_STYLE)
.add(h(1, "No data").style(HEADER_STYLE))
.add(p().style(PARAGRAPH_STYLE)
.add("The data for page '" + place.route + "' could not be loaded: " + error)))
.add("The data for page '" + place.route + "' could not be loaded."))
.add(pre().style(ERROR_STYLE).textContent(error)))
.element());
}
}
Expand Down
20 changes: 20 additions & 0 deletions router/src/main/java/org/jboss/elemento/router/Places.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@

import static org.jboss.elemento.router.Path.normalize;

/**
* Represents a collection of places in an application. Each place is associated with a page supplier. Supports nested places
* and loaders.
*/
public class Places implements Iterable<Map.Entry<Place, Supplier<Page>>> {

// ------------------------------------------------------ factory
Expand All @@ -45,16 +49,29 @@ public Iterator<Map.Entry<Place, Supplier<Page>>> iterator() {

// ------------------------------------------------------ builder

/**
* Adds a Place and the corresponding page supplier to the collection of places.
*/
public Places add(Place place, Supplier<Page> page) {
pages.put(place, page);
return this;
}

/**
* Adds all the places from the given Places object to this places object.
*/
public Places add(Places places) {
pages.putAll(places.pages);
return this;
}

/**
* Adds the children places to the current collection of places. Each child place is created by appending the child's route
* to the given parent path. The child places and their corresponding page suppliers are added to the current collection.
*
* @param path the parent path to append to the child routes
* @param places the child places to add
*/
public Places children(String path, Places places) {
for (Map.Entry<Place, Supplier<Page>> entry : places.pages.entrySet()) {
Place child = new Place(failSafeRoute(path, entry.getKey()), entry.getKey());
Expand All @@ -63,6 +80,9 @@ public Places children(String path, Places places) {
return this;
}

/**
* Assigns a given loader for a specific place.
*/
public Places loader(Place place, Loader<?> loader) {
if (pages.containsKey(place)) {
for (Place p : pages.keySet()) {
Expand Down

0 comments on commit 8b0d598

Please sign in to comment.