Web-Client – Anpassungen für unterschiedliche Endgeräte

Das HTML-Frontend von REWOO Scope ist eine Plattform, die zahlreiche Möglichkeiten bietet, Daten auf dem Desktop, Tablet oder Smartphone übersichtlich und klar strukturiert darzustellen.

Der Web-Client ist bereits auch ohne weiteren Modellieraufwand voll einsatzfähig. Dennoch können zusätzliche Anpassungen vorgenommen werden, um die User Experience auf den verschiedenen Geräten weiter auf die jeweiligen Erwartungen abzustimmen.

Dabei stehen hier die Möglichkeiten unterschiedlicher Sprachen und Frameworks zur Verfügung. Dazu gehören unter anderem:

  • HTML
  • CSS
  • JavaScript
  • jQuery
  • Bootstrap

Die meisten Konfigurationsmöglichkeiten finden sich im Designer auf den Seiten Layouts und Code.

Layouts für unterschiedliche Bildschirmgrößen optimieren

Da Layouts, wie sie für den Desktop erstellt werden, auf kleineren Bildschirmen leicht überladen und unübersichtlich wirken, gibt es die Möglichkeit, die Aufteilung, Größe und Position von Feldern auf Mobil-Geräten anders darstellen zu lassen als auf Laptops und Desktops. Damit ist es möglich, für jede Auflösung ein optimiertes Datenblatt-Layout anzubieten.

Um für die unterschiedlichen Bildschirme zu entwerfen, kann man entweder rechts oben zwischen den vier Bildschirmklassen umschalten, um dann jeweils mit den Plus- und Minus-Buttons die einzelnen Spalten und Zeilen zu vergrößern oder zu verkleinern. Oder man öffnet bei einer Spalte oder Zeile mit dem Zahnrad die Layouteinstellungen. Dort kann man direkt für alle Bildschirmklassen die Größe ändern und weitere CSS-Klassen angeben.

Als Grundlage für das Layout verwendet REWOO Scope das Framework Bootstrap 3. Alle Regeln, Möglichkeiten und CSS-Klassen des Bootstrap-Gridsystems können hier verwendet werden (mehr Informationen dazu auf der offiziellen Bootstrap-Webseite).

Datenblatttyp-spezifisches CSS

HTML-ID - Zeilen und Spalten kann eine ID zugewiesen werden, um sie leichter mit CSS zu stylen oder per JavaScript darauf zugreifen zu können. Außerdem ist eine HTML-Id Voraussetzung, um in der Hilfe-Tour eine Erklärung für diesen Teil des Formulars zu speichern.

CSS-Klassen - Einzelnen Zeilen und Spalten können zusätzliche CSS-Klassen zugewiesen werden.

Size - Hiermit wird die Spaltenbreite für die einzelnen Geräteklassen festgelegt, wie es in Bootstrap getan wird. Die einzelnen Input-Felder stehen für die einzelnen Geräteklassen, von links nach recht: xs, sm, md, lg. Alle Regeln des Bootstrap-Gridsystems sind hier anwendbar.

Offset - Hiermit wird der Linksabstand einer Spalte für die einzelnen Geräteklassen festgelegt, wie es in Bootstrap getan wird. Die einzelnen Input-Felder stehen für die einzelnen Geräteklassen, von links nach recht: xs, sm, md, lg. Alle Regeln des Bootstrap-Gridsystems sind hier anwendbar.

Layout automatisch erzeugen

Wenn ein altes Flex-Layout vorhanden ist, kann daraus automatisch ein HTML-Layout erstellt werden. Das erzeugte Layout kann anschließend weiter verändert und angepasst werden.

HTML-Layout automatisch erzeugen

Veränderung des Designs (CSS)

Das HTML-Frontend von REWOO Scope kommt mit einer dienlichen, schlichten und für Scope typischen Farbgebung. Diese kann allerdings an eigene Bedürfnisse angepasst werden. Änderung der Farbgebung und auch einige Anpassungen des Grunddesigns sind damit möglich. So lässt sich zum Beispiel ein eigenes Branding oder Logo anzeigen oder ein Corporate Design auf Scope anwenden.

Die Veränderungen müssen als CSS in Scope eingepflegt werden. Dafür stehen unterschiedliche Möglichkeiten zur Wahl:

Globale CSS-Einbindung

Änderungen, die sich auf den gesamten Client auswirken sollen, können von einem Administrator als CSS direkt in der Konfiguration von REWOO Scope hinterlegt werden.

Nähere Hinweise dazu finden Sie im Kapitel Konfiguration im Technischen Handbuch.

Layout-spezifische CSS-Einbindung

Sollen Änderungen nur auf ausgewählten Formular-Layouts erscheinen oder unterschiedliche Datenblätter verschiedentlich gestaltet werden, kann Layout-spezifisches CSS hinterlegt werden. Dazu wählen Sie im Designer die Seite für den Code und wechseln dann zum gewünschten Formulartyp und Layout. Dort können jetzt im CSS-Feld alle Änderungen gespeichert werden. Das hier hinterlegte CSS wird nur auf Formularen des jeweiligen Typs mit dem angegebenen Layout verwendet. Um das CSS allen Layouts dieses Typs zur Verfügung zu stellen, muss der Registerreiter "Typ CSS" editiert werden. Datenblatttyp-spezifisches CSS

CSS-Beispiele

Breite der Reiter über dem Formular
Wenn das Formular mehrere Seiten hat, werden über dem Formular Reiter für das Blättern eingeblendet. Mit folgendem Code kann die maximale Breite der Reiter verändert werden
.datasheet-role-tab {
    max-width: 40em;
}
Wenn der Reiter statt dessen den ganzen Text anzeigen soll, wenn der Mauszeiger über den Reiter fährt, kann das mit folgendem Code erreicht werden
.datasheet-role-tab:hover {
    text-overflow: clip;
    white-space: normal;
    word-break: break-all;
}

Anpassen des Menüs

Menüeinträge ausblenden

Über das globale CSS kann nicht nur das generelle Aussehen des Menüs, sondern auch die Anzahl der angebotenen Menüoptionen gesteuert werden. Hierzu wurde jedem Menüeintrag eine passende ID zugeordnet. Diese sind im Einzelnen:

  • menu-item-start: Verweis auf die persönliche Startseite des Benutzers
  • menu-item-bookmarks: Liste der Lesezeichen
  • menu-item-tables: Verweis auf die Liste der Tabellenansichten
  • menu-item-kanbans: Verweis auf die Liste der Kanban-Tafeln
  • menu-item-calendars: Verweis auf den Kalender
  • menu-item-inbox: Verweis auf die Inbox
  • menu-item-navigator: Verweis auf den Navigator
  • menu-item-search: Verweis auf die Volltext-Suchseite
  • menu-item-back: Zurück zur vorherigen Seite
  • menu-item-tools: Verweis auf die Seite mit weiteren Werkzeugen
  • menu-item-logout: Ausloggen des Benutzers
Nachfolgend ein Beispiel, das zeigt, wie der Link zur Inbox ausgeblendet werden kann. Die anderen Menüpunkte können analog aus- oder eingeschaltet werden.
#menu-item-inbox {
    display: none;
}

Wichtig ist dabei, dass der Eintrag nur ausgeblendet wird. Kennt der Benutzer den konkreten Link zur gewünschten Seite, kann er diese natürlich weiterhin aufrufen.

Menü immer eingeklappt darstellen

Standardmäßig wird das Menü ausgeklappt am linken Rand dargestellt. Erst wenn der Bildschirm des Benutzers eine bestimmte Größe unterschreitet (z. B. auf einem Smartphone) wird das Menü eingeklappt und dafür in der linken oberen Ecke ein sogenannter "Sandwich-Button" dargestellt. Nach dem Klick auf diesen Button, wird das Menü wieder angezeigt. Über den in der Konfiguration einstellbaren Parameter mobile.menu.alwaysSandwich kann das Menü grundsätzlich eingeklappt dargestellt werden.

Anpassen von Feldern

Neben der Möglichkeit das Aussehen der Felder beliebig mit CSS anzupassen, gibt es teilweise auch die Möglichkeit, das Verhalten bzw. Aussehen über Konfigurationsparameter zu steuern.
Position der Plus- und Minus-Buttons bei Tabellen
Standardmäßig wird bei Tabellen-Feldern rechts neben jeder Zeile ein Plus- und ein Minus-Button eingeblendet. Sollen diese Controls auf der linken Seite erscheinen, so kann dies über den Konfigurations-Parameter mobile.entries.tableControlsLayout eingestellt werden. Wird dieser auf den Wert "left" gesetzt, so werden die entsprechenden Buttons auf der linken Seite jeder Tabellenzeile eingeblendet. Dabei werden die Buttons aber in umgekehrter Reihenfolge dargestellt, d.h. es kommt zuerst der Plus-Button und dann der Minus-Button.

Einblenden des Schnellspeichern-Dialogs

Standardmäßig wird nach Benutzeränderungen an einem Datenblatt (oder beim Kopieren eines Elements) ein kleines Popup angezeigt, sobald der Benutzer etwas nach unten gescrolled hat. Über diesen Dialog können die Änderungen entweder direkt gespeichert oder verworfen (oder im Kopieren-Fall das Element direkt angelegt) werden. Das Popup ist über den Konfigurations-Parameter mobile.quickOperationsPopup.enabled auch ausschaltbar. Die Farben des Dialogs werden per CSS und dem "background"-Attribut für die folgenden Klassen angepasst:
  • popup-header (Titelzeile des Popups)
  • popup-content (Inhalt des Popups)

Zusätzliches JavaScript einbinden

Globales JavaScript

JavaScript-Code, der im gesamten Mobile-Client eingebunden werden soll, kann von einem Administrator direkt in der Konfiguration von REWOO Scope hinterlegt werden.

Nähere Hinweise dazu finden Sie im Kapitel Konfiguration im Technischen Handbuch.

Lokales JavaScript

Zusätzlich kann für jeden Typ JavaScript-Code definiert werden. Damit lassen sich auf Wunsch weitere Mechanismen und Funktionalitäten einbauen. Dazu wählen Sie im Designer die Seite für den Code und wechseln dann zum gewünschten Formulartyp und Layout. Dort können jetzt für den ganzen Typ oder das einzelne Layout im JavaScript-Feld zusätzlicher Code hinterlegt werden. Datenblatttyp-spezifisches JavaScript

Beispiele

Autosave von Datenblättern
Bindet man den folgenden Code-Snippet als typweites JavaScript ein, wird alle 180.000ms (d.h. alle 3 Minuten) das aktuell geöffnete Datenblatt dieses Typs automatisch gespeichert, sofern vom Benutzer Änderungen vorgenommen wurden. Diese werden indirekt daran erkannt, dass der Speichern-Button (mit der Id 'save') aktiv ist. Wichtig dabei: da hier das manuelle Speichern des Benutzers per Script "emuliert" wird, treten auch dieselben Effekte wie beim händischen Speichern auf, d.h. zum Einen wird bei jedem Speichervorgang eine neue Version des Formulars erzeugt, zum Anderen wird nach dem Speichern das Formular neu geladen (weshalb der Bildschirm nach oben gescrolled wird).
setInterval(function() {
    $('#save').each(function() {
        if (!($(this).prop('disabled'))) {
            console.log('Autosave');
            $(this).submit();
        }
    });
}, 180000);
leere Datenblattfelder ausblenden
Mit diesem Snippet lassen sich Felder, die keinen Inhalt haben für den User ausblenden. Dies ist hilfreich, wenn man für bestimmte Berechtigungs-Gruppen dedizierte Anischten bauen möchte, die dann nur relevante Informationen enthalten. Die definierten Klassen (hier: "privat-infos" und "privat-infos-inhalt") müssen im HTML Designer dann den jeweiligen Bootstrap Containern zugewiesen werden. Die erste Klasse definiert dabei den Container, der entfernt werden soll. Die zweite muss bei dem Feld eingetragen werden, bei dem der Inhalt überprüft werden soll.
$('.privat-infos').each(function () {
	if ($(this).find('.privat-infos-inhalt .content input').attr('value').trim().length == 0) {
		$(this).hide();
	}
});
Sollen mehrere Bedingungen geprüft werden, können die Bedingungen entsprechend erweitert werden. Hierbei muss jedoch für jedes weitere Inhalts-Feld eine eigene Klasse angegeben werden:
$('.privat-infos').each(function () {
	if ($(this).find('.privat-infos-inhalt .content input').attr('value').trim().length == 0 && $(this).find('.privat-infos-inhalt2 .content input').attr('value').trim().length == 0) {
		$(this).hide();
	}
});
Soll ein mehrzeiliges String Feld zur Prüfung benutzt werden, so muss die Bedingung leicht modifiziert werden:
if ($(this).find('.privat-infos-inhalt .content div').text().trim().length == 0) {
Datenblattfelder in Echtzeit Ein- oder Ausblenden
Mit Hilfe von nachfolgendem Code Beispiel ist es möglich, bestimmte Datenblattfelder ein oder auszublenden, abhängig von einer Benutzereingabe. Im Beispiel wird eine Checkbox verwendet, um Felder einzublenden, welche standardmäßig ausgeblendet sind. Damit der Code funktioniert muss für die betroffenen Felder, die ein- oder ausgeblendet werden sollen, eine CSS-Klasse hinterlegt werden (hier "serientermin"). Das Feld welches zur Prüfung verwendet werden soll, muss eine HTML ID (hier "serientermincheck") besitzen.

	var serie = document.getElementById("inverse_entry_171");
	var details = document.getElementsByClassName("serientermin");
	var seriewert = serie.getAttribute("value");
	if (seriewert == 'false'){
		for (var i=0;i<details.length;i+=1) {
			details[i].style.display = "none";
		}
	}
	$('#serientermincheck').change(function(){
		seriewert = serie.getAttribute("value");
		if (seriewert == 'true'){
			for (var i=0;i<details.length;i+=1) {
				details[i].style.display = "block";
			}
		} else {
			for (var i=0;i<details.length;i+=1) {
				details[i].style.display = "none";
			}
	}
})
Deaktivieren von Buttons nach Usereingabe
Da im HTML-Client das Drücken eines Buttons dazu führt, dass die Seite neu geladen wird, besteht die Gefahr, dass vorab gemachte User-Eingaben durch den Klick verloren gehen. Um dies zu verhindern ist es in manchen Fällen sinnvoll, dass die Buttons deaktiviert werden, sofern der User vorab am Datenblatt Änderungen vorgenommen hat. Dies lässt sich durch den nachfolgenden Code erreichen.

(function() {
    var disabledBtnCaptions = collectBtnCaptions($('.entry input[type="button"]:disabled, .entry button:disabled'));
    function collectBtnCaptions(elements) {
       var captions = [];
       elements.each(function() {
         captions.push(getBtnCaption(this));
       });
       return captions;
    }
    function getBtnCaption(element) {
       if ($(element).is('input')) {
         return $(element).attr('id');
       }
       return $(element).children().text();
    }
    $(document).on('headerBtnChanged', function (event, changedElementId) {
       var changedBtn = $('#' + changedElementId);
       if (changedBtn.attr('name') === 'save') {
         var allSheetBtns = $('.entry.copybutton input[type="button"], .entry.actionbutton button, .entry.signature button, .entry.connectionbutton button, .entry.tableviewbutton input[type="button"]');
         allSheetBtns.each(function() {
           var caption = getBtnCaption(this);
           var btn = $(this);
           if (disabledBtnCaptions.indexOf(caption) > -1) {
             return;
           }
           if (changedBtn.attr('disabled')) {
              btn.removeAttr('disabled');
         } else {
              btn.attr('disabled', 'disabled');
          }
         });
       }
    });
})();

Validatoren

Validatoren ermöglichen die Überprüfung von Werten und Benutzereingaben nach vorgegebenen Regeln. Ist eine Benutzereingabe ungültig (zum Beispiel ein Wert zu klein oder zu lang), wird eine Fehlermeldung angezeigt und das Datenblatt lässt sich so lange nicht speichern, bis die Eingabe korrigiert wurde. Zur einfachen Definition solcher Validatoren bietet REWOO Scope eine eigene Validator-API an, die im Folgenden beschrieben wird.

Aktuell unterstützt werden String, Date und Number (Email-Felder haben von Haus aus einen Validator eingebaut, der auf gültige E-Mail-Adressen überprüft. Es muss also kein zusätzlicher Validator dafür erstellt werden). Ein Validator kann dabei sowohl für normale Felder, als auch für Felder innerhalb von Tabellen definiert werde.

Syntax

Der folgende Beispielcode zeigt die Syntax der Validator-API und muss für die Verwendung mit anderen Feldern lediglich leicht angepasst werden. Dieser Code muss im Designer bei dem jeweiligen Datenblatt-Typ als Skript hinterlegt werden (siehe Abschnitt "Zusätzliches JavaScript einbinden").
addValidator("Feldname", function(value, context) {
    if ( Bedingung ) {
        return "Fehlermeldung";
    }
    return null;
});

Feldname - Der Name des zu validierenden Feldes.

Fehlermeldung - Die Nachricht (als String), die der Nutzer bei einer Fehleingabe zu sehen bekommt.

Bedingung - Hier findet die eigentliche Überprüfung statt, normalerweise in Form eines Vergleichs zwischen dem aktuellen Wert eines Feldes mit einem konstanten Wert oder einem anderen Feldwert. Da es sich dabei um einen herkömmlichen JavaScript-Ausdruck handelt, sind sämtliche Booleschen Ausdrücke erlaubt. Darüber hinaus können Bedingungen auch geschachtelt und kombiniert werden, oder mehrere unterschiedliche Checks innerhalb einer addValidator-Funktion durchgeführt werden. Nachfolgend eine Auswahl der Wichtigsten von JavaScript unterstützten Vergleichsoperatoren:

Operator Funktion
== ist gleich
!= ist nicht gleich
< ist kleiner als
<= ist kleiner gleich
> ist größer als
>= ist größer gleich

Number- und Date-Felder verwenden

Feldwerte werden immer als String zurückgegeben. Wird allerdings ein Number- oder ein Date-Feld referenziert, muss dieser Wert erst in eine Zahl oder ein Datum konvertiert werden, um anschließend mit anderen Zahlen- und Datumswerten verglichen werden zu können. Dazu können die folgende Funktion verwendet werden (Einheiten werden dann ignoriert):
toNumber(value)
toDate(value, format, language)

Anmerkung - Der toDate-Funktion müssen zusätzlich zum reinen Datumswert noch das vorliegende Datumsformat (z.B. "dd.mm.yyyy" für das deutsche Datumsformat) sowie eine Sprache (z.B. "de" für deutsch oder "en" für englisch) mitübergeben werden, um den String-Wert erfolgreich in einen Datumswert umwandeln zu können.

Vergleich mit einem anderen Feld

Innerhalb einer addValidator-Funktion lässt sich auch ein weiteres Feld auslesen, um es anschließend mit dem aktuellen Feld zu vergleichen. Hierfür kann die Funktion getValue benutzt werden, die folgende Signatur aufweist:
getValue(entryTitle[, context] [, notifyOnChanges])
Die Funktion weist zwei optionale Parameter auf. Dabei muss context immer dann übergeben werden, wenn der referenzierte Feldname ein Feld innerhalb einer Tabelle darstellt (damit ersichtlich ist, was die aktuelle Zeile ist). Wir raten aber grundsätzlich zur Übergabe des Kontextes. Der Parameter notifyOnChanges ist standardmäßig auf true gesetzt. In diesem Fall führen auch Änderungen des referenzierten Feldes zu einer Neuauswertung der Validator-Funktion. Wird dies nicht gewünscht, muss der Parameter manuell auf false gesetzt werden. Soll der Wert eines normalen Feldes mit dem Titel Feldname ausgelesen werden, kann dies mit folgendem Aufruf realisiert werden:
getValue("Feldname")
Das nachfolgende Beispiel zeigt hingegen, wie man von einem Zellen-Validator aus den Wert einer weiteren Tabellen-Zelle (mit dem Spaltennamen Feld2) innerhalb derselben Zeile ausliest.
getValue("Feld2", context)

Beispiele

Folgende Beispiele sollen den vielfältigen Einsatz der addValidator-Funktion verdeutlichen. Wichtige Code-Teile sind farblich hervorgehoben.
Auftragswert darf nicht kleiner als 0 sein
addValidator("Auftragswert", function(value, context) {
    if ( toNumber(value) < 0 ) {
        return "Der Auftragswert darf nicht kleiner als 0 sein!";
    }
    return null;
});
Urlaubsantrag darf nicht keine und nicht mehr als 5 Tage umfassen
addValidator("Zu beantragende Urlaubstage", function(value, context) {
    if ( toNumber(value) <= 0 ) {
        return "Bitte geben Sie eine gültige Tagesanzahl an!";
    }
    if ( toNumber(value) > 5 ) {
        return "Es können nicht mehr als 5 Urlaubstage am Stück genommen werden.";
    }
    return null;
});
Lieferadresse und Rechnungsadresse müssen identisch sein
addValidator("Adresse für Lieferungen", function(value, context) {
    var rechnungsadresse = getValue("Rechnungsadresse", context);
    if ( value != rechnungsadresse ) {
        return "Lieferadresse muss sein: " + rechnungsadresse;
    }
    return null;
});
Anzahl für einen Arbeitsschritt aufgewendete Stunden darf nicht größer sein als die Gesamtstunden (beide Werte sind in einer Tabelle enthalten)
addValidator("Stunden Arbeitsschritt", function(value, context) {
    if ( toNumber(value) < toNumber(getValue("Gesamtstunden", context)) ) {
        return "Sie können nicht mehr Stunden für den Arbeitsschritt aufwenden, als Sie insgesamt gearbeitet haben!";
    }
    return null;
});

Veto-Funktionen

Veto-Funktionen sind Validatoren recht ähnlich, allerdings hängen sie nicht an einem einzelnen Eingabe-Feld oder einer Tabelle, sondern können völlig losgelöst von Datenblatt-Inhalten das Speichern bzw. Kopieren eines Datenblatts verhindern. Veto-Funktionen werden grundsätzlich erst nach der Ausführung aller herkömmlichen Validatoren beachtet: melden diese bereits einen Fehler, wird das Ergebnis der Veto-Funktion ignoriert und auch nicht angezeigt.

Syntax

Der folgende Beispielcode zeigt die Syntax beim Hinzufügen einer neuen Veto-Funktion als JavaScript über den Datenblatt-Designer (siehe Abschnitt "Zusätzliches JavaScript einbinden").

addVeto(Zielelement, function() {
    if ( Bedingung ) {
        return "Fehlermeldung";
    }
    return null;
}, Ereignis, Kontext-Selektor);

Zielelement - Ein Verweis auf das DOM-Element, welches im Falle eines Vetos die Fehlermeldung als Container beinhalten soll. Wichtig: das Ziel-Element muss zwingend die Klasse "form-group" aufweisen, u.U. muss diese Klasse dem Element zuvor noch per JavaScript dynamisch hinzugefügt werden.

Fehlermeldung - Die Nachricht (als String), die der Nutzer im Falle eines Vetos zu sehen bekommt.

Bedingung - Eine beliebige Bedingung, um zu entscheiden, ob ein Veto eingelegt werden soll oder nicht.

Ereignis (Optional) - Da eine Veto-Funktion nur dann neu ausgewertet wird, wenn auch herkömmliche Validatoren neu ausgewertet werden würden (z.B. bei der Eingabe eines Werts in ein Formularfeld), kann es notwendig werden, die Veto-Funktion auch bei anderen Gelegenheiten aufzurufen (beispielsweise beim Anklicken eines Steuerelements auf der Seite). Aus diesem Grund kann über diesen Parameter ein Ereignis angegeben werden, bei dem eine vollständige Neuauswertung der Validatoren (und damit auch der Veto-Funktionen) angestoßen werden soll. Das Ereignis muss als String angegeben werden, der von jQuery als "Event" interpretiert werden kann (siehe jQuery-Dokumentation).

Kontent-Selektor (Zwinged, wenn "Ereignis" angeben wird) - Gibt den Kontext an, innerhalb dessen auf das Ereignis gelauscht werden soll. Der Selektor muss als String angegeben werden, der von jQuery interpretiert werden kann