Bookmarks
Überblick
Bookmarks ermöglichen es Anwendern schneller zwischen wichtigen Bereichen innerhalb eines Dokuments zu navigieren. Hierzu werden einzelne Seiten im ersten Schritt mit einem Bookmark versehen. Anschließend kann über spezielle Elemente der grafischen Benutzeroberfläche einfach und schnell zwischen Bookmarks gesprungen werden.
Im Lieferumfang des jadice web toolkit enthalten sind Buttons und Commands, mittels derer Anwender Bookmarks erstellen und löschen sowie zwischen Bookmarks navigieren können. Als Anwendungsbeispiel dient die Enterprise-Demo, in deren rechter Sidebar die Bookmark-Funktionalität integriert ist. Die folgende Abbildung zeigt den zugehörigen Ausschnitt:

Persistierung
Neben der clientseitigen Erstellung und Verwendung von Bookmarks gibt es die Möglichkeit, clientseitig erstellte Bookmarks zu persistieren, um diese in einem künftigen Bearbeitungsprozess erneut zu verwenden. Um dies zu erreichen, können clientseitig erstellte Bookmarks zunächst an den JWT Server gesendet und anschließend von dort in einem Drittsystem persistiert werden. Wird das zugehörige Dokument in der Zukunft erneut bearbeitet, können die persistierten Bookmarks im Rahmen des Dokument-Ladeprozesses aus dem Drittsystem ausgelesen und dem Dokument auf der Serverseite als Property hinzugefügt werden. Zusammen mit dem Dokument werden diese hierbei an den Client verschickt und stehen dem Anwender nach Abschluss des Ladevorgangs erneut für eine einfache und schnelle Navigation zur Verfügung.
Die Persistierung von Bookmarks lässt sich in 2 Funktionen unterteilen:
-
Speichern von Bookmarks
-
Laden persistierter Bookmarks
Speichern von Bookmarks
Das Speichern von Bookmarks erfolgt in einem kundenspezifischen Message-Listener. Der Client sendet dazu einen Snapshot des Dokuments an den Server. Beim Erzeugen des Snapshots wandelt das jadice web toolkit die clientseitige BookmarkList in eine SerializableBookmarkList um und überträgt sie als Document-Property.
Clientseitig wird der Snapshot des Dokuments in einem Command erzeugt, das von
AbstractMessagingCapableDocumentCommand erbt, und über
getTransferableDocument() in das Anfrage-DTO übernommen:
@Override
protected void execute() {
// SaveBookmarksRequestDTO: eigenes JavaScriptObject-DTO mit einem Feld "document"
final SaveBookmarksRequestDTO dto = SaveBookmarksRequestDTO.create(getTransferableDocument());
ServerConnection.get().send(Message.create("SAVE_BOOKMARKS", dto), false, response -> {
if (DefaultMessageNames.EOC.equals(response.getMessageName())) {
final ConversationEndDTO eoc = response.getPayload().cast();
// Auswertung von eoc.wasSuccessful()
}
});
}
Serverseitig wird aus dem Snapshot mit dem DocumentSnapshotConverter
ein Document erzeugt. Dessen Property
SerializableBookmarkList.PROPERTY_KEY_SERIALIZABLE_BOOKMARK_LIST
enthält die Bookmarks:
@Data
@NoArgsConstructor
public final class SaveBookmarksRequestDTO {
private DocumentSnapshotDTO document; // com.levigo.jadice.web.server.messaging.DocumentSnapshotDTO
}
@Component
@MessageName("SAVE_BOOKMARKS")
public class SaveBookmarksMessageListener implements MessageListener<SaveBookmarksRequestDTO> {
@Autowired
private ExecutorService executorService;
@Autowired
private DocumentSnapshotConverter snapshotConverter;
@Override
public CancelHandler consume(SaveBookmarksRequestDTO dto, IncomingMessageContext ctx) {
final Future<?> future = executorService.submit(() -> run(dto, ctx));
return () -> future.cancel(true);
}
private void run(SaveBookmarksRequestDTO dto, IncomingMessageContext ctx) {
try {
final Document doc = snapshotConverter.convert(ctx, dto.getDocument());
// retrieve the bookmarks from the document
final SerializableBookmarkList bookmarks = (SerializableBookmarkList) doc.getProperties().get(
SerializableBookmarkList.PROPERTY_KEY_SERIALIZABLE_BOOKMARK_LIST);
if (bookmarks != null) {
for (SerializableBookmark b : bookmarks.getAll()) {
// place your logic to persist the bookmark here
}
}
ctx.sendSuccess();
} catch (Exception e) {
ctx.sendFail(e);
}
}
}
Die Property ist nur vorhanden, wenn clientseitig bereits eine
BookmarkList für das Dokument existiert, d.h. wenn Bookmarks geladen
oder erstellt wurden. Die Seitenindizes der Bookmarks beziehen sich auf
die Seitenreihenfolge des Snapshots, clientseitige Seitenverschiebungen
sind also bereits berücksichtigt.
Laden persistierter Bookmarks
Das Laden von Bookmarks erfolgt in einer kundenspezifischen Implementierung eines DocumentDataProvider. In der read-Methode wird dabei vor dem Lesevorgang eine Instanz der Klasse SerializableBookmarkList als Document-Property gemäß des folgenden Codefragments erstellt.
@Override
public final void read(Reader reader, final S source) throws JadiceException, IOException {
// Place your logic to read persisted bookmarks here and create an instance of
// SerializableBookmark for each of them. For the reason of simplicity we assume 3 persisted
// bookmarks - on pageIndexes 7, 15 and 31.
SerializableBookmark b1 = new SerializableBookmark(7);
SerializableBookmark b2 = new SerializableBookmark(15);
SerializableBookmark b3 = new SerializableBookmark(31);
// Create a SerializableBookmarkList and add each persisted bookmark to it
SerializableBookmarkList bms = new SerializableBookmarkList();
bms.add(b1);
bms.add(b2);
bms.add(b3);
// To make sure the bookmarks are transferred to the client the list has to be added as a
// document property BEFORE calling reader.read()
reader.getDocument().getProperties().put(SerializableBookmarkList.PROPERTY_KEY_SERIALIZABLE_BOOKMARK_LIST, bms);
// read the document
...
reader.read(in);
}
Die zugehörigen Bookmarks werden beim Aufruf von reader.read()
zusammen mit dem Dokument an den Client geschickt und stehen für die
clientseitige API zur Verfügung, sobald sich das Client-Dokument im
Zustand Document.BasicState.READY befindet.
Ein funktionsfähiges Codebeispiel, das als Vorlage für die Persistierung dienen kann, findet sich in den Showcases.
Serverseitige und clientseitige Bookmark-API
Zu beachten ist, dass sich die serverseitige und die clientseitige Bookmark-API unterscheiden. Die serverseitige Bookmark-API besteht aus den beiden Klassen SerializableBookmark und SerializableBookmarkList (siehe Codefragmente im Kapitel Persistierung). Diese beiden Klassen dienen ausschließlich als Datencontainer zum Speichern und Laden von Bookmarks.
Die eigentliche Bookmark-Funktionalität wird über die mächtigere clientseitige Bookmark-API zur Verfügung gestellt. Deren Highlevel-Schicht besteht dabei aus den Commands AddBookmarkCommand, NextBookmarkCommand, PreviousBookmarkCommand, RemoveBookmarkCommand, RemoveAllBookmarksCommand und AbstractBookmarkCommand. Darunter verbirgt sich die Lowlevel-Schicht bestehend aus den Klassen BookmarkListFactory und BookmarkFactory für die Erzeugung und den beiden Interfaces BookmarkList und Bookmark für die Verwendung.
Kundenspezifische Bookmarks
Für die Umsetzung spezifischerer Anforderungen, für deren Abbildung die produkteigenen Commands nicht ausreichend sind, können über die Klassen der Lowlevel Bookmark-API kundenspezifische Bookmark-Commands implementiert werden. Als Orientierungshilfe eignen sich dabei die im Produktumfang enthaltenen Commands (siehe Serverseitige und clientseitige Bookmark-API).
Ein funktionsfähiges Codebeispiel, das als Vorlage für die Implementierung kundenspezifischer Commands dienen kann, findet sich in den Showcases.