Shell-APP

Shell-APP

 Funktionsumfang der Shell-App

Die Shell-App stellt einen äußeren Rahmen zur Darstellung, Navigation und Interaktion mehrerer Ressourcen dar. Du kannst das Bedienkonzept der Ressourcen mithilfe der Shell-App vereinheitlichen.

 Technische Hintergrundinformationen

Die Shell-App stellt die Schnittstelle d.api bereit. Apps verwenden diese API u.a. für die Navigation innerhalb der Shell-App.

 Verwenden der API-Funktionen

Im Folgenden lernst du die unterschiedlichen Möglichkeiten kennen, die Schnittstellen der Shell-App für deine Anforderungen zu verwenden.

 Anzeigen einer Ressource in der Shell-App

Um eine Ressource in der Shell-App anzuzeigen, musst du die d.api im Head-Element der Ressource per Script-Tag einbinden. Beim Laden der Ressource wird während der Initialisierung der d.api kontrolliert, ob um die Ressource herum schon eine Shell-App geladen wurde.

Wenn keine Shell-App gefunden wird, versucht die d.api unter https://_SYSTEMBASE_URI_/shell die Shell-App aufzurufen und übergibt den relativen Pfad der eigenen Ressource als Fragment. Daraufhin wird die Shell-App geladen, die dann als erste Ressource die ursprünglich aufgerufene Ressource mithilfe des URI-Fragmentes lädt. Die Ressource wird erneut geladen, wodurch auch die d.api erneut initialisiert wird.

Da nun eine Shell-App geladen ist bzw. schon war, wird diese Shell-App in der d.api referenziert und die Funktionsaufrufe an die d.api weitergeleitet.

Die d.api wird über ein CDN (Content Delivery Network) ausgeliefert. Du kannst eine konkrete Version wie folgt einbinden:


<html>
  <head>
  ...
  <script src="https://cdn.service.d-velop.cloud/dapi/v2.13.1/dapi.js"></script>
  </head>
  <body></body>
</html>

Du kannst die neueste Version folgendermaßen einbinden:


<html>
  <head>
  ...
  <script src="https://cdn.service.d-velop.cloud/dapi/latest/dapi.js"></script>
  </head>
  <body></body>
</html>

Hinweis

Für eine konkrete Version wird ein Cache-Header von einem Jahr verwendet, da sich diese Dateien nicht mehr ändern.

Für die neueste Version wird der Cache-Header auf 30 Sekunden eingestellt, damit Änderungen spätestens nach 30 Sekunden übernommen werden.

 Ändern des Titels einer Ressource

Mit der d.api-Funktion dapi.publishTitle(title: string) kannst du den Titel deiner Ressource jederzeit ändern.


dapi.publishTitle('new resource title');

Hinweis

Wenn ein leerer String übermittelt wird (z.B. wenn ein anzuzeigender Wert nicht eingetragen ist), dann wird in der alten Shell-App anstatt des leeren Strings [ ] angezeigt.

 Ändern der URI einer Ressource in der Browserhistorie

Mit der d.api-Funktion dapi.publishLocation(uri: string) kannst du die URI deiner Ressource in der Browserhistorie ändern.


dapi.publishLocation('new resource uri');

Hinweis

Die Uri muss absolut sein.

 Anzeigen eines globalen Dialogs

Mit der Funktion dapi.openDialog(uri: string, height: number, width: number, absoluteValues?: boolean) kannst du einen globalen Dialog anzeigen. Ein globaler Dialog wird über die gesamte Shell-App hinweg angezeigt. Dazu musst du eine URI zu den Inhalten im Dialog sowie die Höhe und die Breite des Dialogs angeben. Wenn du für den optionalen Parameter absoluteValue den Wert true übermittelst, werden die Werte für Höhe und Breite als absolute Werte interpretiert (d.h. sie werden direkt in Pixel übersetzt).


dapi.openDialog('/app/dialogresource.html', 30, 40);

Dieser Aufruf erzeugt einen Dialog mit einer Höhe von 30 Prozent und einer Breite von 40 Prozent.


dapi.openDialog('/app/dialogresource.html', 300, 400, true);

Dieser Aufruf erzeugt einen Dialog mit einer Höhe von 300 und einer Breite von 400 Pixeln.

Wichtig

Du solltest globale Dialoge nur verwenden, wenn sich der Inhalt des Dialogs auf die gesamte Shell-App und deren Inhalte bezieht. Für Inhalte, die sich auf die Ressource beziehen, solltest du Dialoge innerhalb von Ressourcen verwenden. So wissen Anwendende, zu welcher Ressource der Dialog gehört.

info: Die übermittelten Werte für Höhe und Breite werden beim Erzeugen des Dialogs in entsprechende CSS-Klassen übersetzt. Dadurch können die tatsächlich verwendeten Werte im Browser von den in der Funktion übergebenen Werten abweichen. Wenn für absoluteValue der Wert true angegeben ist, werden die Werte direkt als Pixelwerte verwendet.

Um den Dialog zu schließen, können Benutzer einfach neben den Dialog auf den Backdrop (Bereich im Hintergrund) klicken.

Um den Dialog zu schließen, nachdem der Benutzer im Dialog eine Aktion ausgeführt hat, muss deine App dapi.closeDialog() aufrufen. Wenn diese Funktion aufgerufen wird, ohne dass ein Dialog angezeigt wird, geschieht nichts.

 Starten eines Downloads aus einer Ressource heraus

Mit der d.api-Funktion dapi.download( href: string ) wird ein Download in einem versteckten iFrame gestartet.

Hinweis

Der Download darf nur von Haupt- oder Nebenressourcen ausgelöst werden. Ob die Hauptressource im Vollbildmodus ist, spielt keine Rolle.

 Ermitteln, ob eine Ressource aktuell die Hauptressource ist

Verwende die d.api-Funktion dapi.isMainResource(), um zu prüfen, ob deine Ressource aktuell die Hauptressource ist. Die Funktion gibt einen boolean-Wert zurück.

 Navigieren zur nächsten Ressource

Du kannst die Navigation zu einer anderen Ressource mit einem einfachen Anchor-Tag auslösen, das in der Target-Eigenschaft den Wert dapi_navigate einfügt.


<a href="/path/to/new/resource" target="dapi_navigate">other resource</a>

Du kannst du Funktion auch für Anchor-Tags mit enthaltenen Kindelementen verwenden.


<a href="/path/to/new/resource" target="dapi_navigate">
  <div>
      <p>
          Click me!
      </p>
  </div>
</a>

Natürlich kannst du auch mit der Funktion dapi.navigate(uri: string) aus JavaScript heraus eine Navigation auslösen.


dapi.navigate('/path/to/resource');

 Schließen einer Ressource

Verwende die d.api-Funktion dapi.closeResourceIfMainResource(), um eine Ressource per API zu schließen.


dapi.closeResourceIfMainResource();

Die Funktion wird nur dann ausgeführt, wenn die aufrufende Ressource als Hauptressource angezeigt wird. Die Eigenschaft dapi.isMainResource() muss also den Wert true liefern. Ansonsten passiert nichts.

 Verhindern, dass eine Ressource geschlossen wird

Mit der d.api-Funktion dapi.setClosable(false) kannst du festlegen, ob eine Ressource einfach verlassen werden kann. Du kannst einen Callback registrieren, der aufgerufen wird, wenn die Ressource geschlossen werden soll (z.B. in einem Bestätigungsdialog). Innerhalb dieses Bestätigungsdialogs können Benutzer dann z.B. bestätigen, dass sie die Ressource wirklich verlassen möchten.


    dapi.setClosable(false);
    dapi.setInterruptNavigationCallback(( invokeFinish ) => { } )

Wenn das Verlassen z.B. nach dem Bestätigen des Dialogs ermöglicht werden soll, muss deine App nacheinander die Funktionen dapi.setClosable( true ); und invokeFinish() aufrufen. Diese Funktion wird automatisch von der Shell-App als Parameter übergeben. Die Shell-App versucht dann erneut, die Hauptressource zu schließen. Der Callback kann aber auch nur eine einfache Ausgabe sein, dass die Ressource nicht verlassen werden kann.

Hinweis

Bitte verwende setClosable() bzw. setInterruptNavigationCallback() (die Funktion setInterruptCloseCallback() wird für diesen Anwendungsfall nicht unterstützt).

 Anzeigen einer Ressource im Vollbildmodus

Verwende die d.api-Funktion dapi.activateSingleResourceMode(), um du eine Ressource im Vollbildmodus anzuzeigen.


dapi.activateSingleResourceMode();

Wichtig

Verwende diese Funktion immer mit der dapi.deactivateSingleResourceMode()-Funktion, um wieder in das ursprüngliche, vom Benutzer eingestellte Layout zu wechseln.

 Verlassen des Vollbildmodus

Verwende die Funktion dapi.deactivateSingleResourceMode(), um den Vollbildmodus zu verlassen und in das benutzerspezifische Layout zu wechseln.


dapi.deactivateSingleResourceMode();

Wichtig

Verwende diese Funktion nur, wenn du zuvor mit der Funktion dapi.activateSingleResourceMode() in den Vollbildmodus gewechselt bist, damit das benutzerspezifisch eingestellte Layout beibehalten wird.

 Erhalten einer Benachrichtigung, dass deine Ressource angezeigt wird

Mit der dapi-Funktion dapi.setResourceVisibilityChangedCallback(callback: (isResourceVisible: boolean) => void) kannst du der Shell-App eine Funktion übergeben, die immer bei Änderungen der Sichtbarkeit der Ressource aufgerufen wird. Dadurch kannst du z.B. nachvollziehen, ob die Ressource ein- oder ausgeblendet wird.


dapi.setResourceVisibilityChangedCallback((isResourceVisible) => {
        if (isResourceVisible) {
            console.log(`the resource is visible`);
        } else {
            console.log(`the resource is invisible`);
        }
    });

Beim Aufruf wird ein Parameter als boolescher Wert an den Callback übergeben. Der Parameter enthält den Wert true, wenn die Ressource sichtbar ist und false, wenn sie nicht angezeigt wird. Mit diesem Aufruf kannst du beispielsweise ein automatisches Aktualisieren der Ressource aussetzen, solange die Ressource ausgeblendet ist.

 Wissenswertes zu Kontextaktionen (ContextActions)

In der Shell-App gibt es das Konzept der Kontextaktionen. Das sind Aktionen, die alle in Bezug auf die angezeigte Ressource verwendet werden können. Es gibt navigierende und nicht navigierende Aktionen. Eine navigierende Aktion ist z.B. das Wechseln von einem Dokument aus zu der übergeordneten Akte.

Außerdem gibt es nicht-navigierende Kontextaktionen. Diese Kontextaktionen lösen Aktionen innerhalb der angezeigten Ressource aus, die sich aber nur auf die Ressource selbst auswirken. Eine nicht-navigierende Aktion ist z.B. eine Aufgabe als gelesen zu markieren.

 Bereitstellen von Kontextaktionen

Du kannst Kontextaktionen mit dem Link-Tag im Header der Ressource registrieren.


<html>
  <head>
  ...
  <link rel="ctxaction" type="text/html" href="/Shell-App/docs/details.html" title="context action name" data-icon="/relative/path/to/ctxAct.png">
  </head>
  <body></body>
</html>

Du kannst Kontextaktionen auch aus JavaScript heraus registrieren. Verwende für diese Registrierung die d.api-Funktion dapi.setContextActions(contextActions: IContextAction[]). Du kannst dieser Funktion ein Array von Kontextaktionen übergeben, die dann den Benutzern angezeigt werden. Eine Kontextaktion kann folgende Attribute haben:


interface IContextAction {
    /**
     * URI of navigation target
     */
    href?: string;

    /**
     * Function to execute if contextAction is invoked.
     * @returns {}
     */
    callback?: () => void;

    /**
     * Name of the function to execute if contextAction is invoked.
     * NOTE: A function with the corresponding callbackName must be registered first and currently only bridges can register such functions. It is not possible for regular resources.
     */
    callbackName? : string;

    /**
     * Arguments for the callback invocation.
     */
    callbackArgs?: any[];

    /**
     * Title of ContextAction
     */
    title: string;

    /**
     * URI of icon
     */
    icon: string;

    /**
     * Open the reference target of the context action in the outer supply.
     */
    openInOuterSupply?: boolean;
}

dapi.setContextActions( [
  {
      type: "text/html",
      href: "relative/path/to/resource[.html]",
      title: "ContextActionName",
      icon: "relative/path/to/ContextActionIcon.png"
  }
] );

Du kannst Javascript verwenden, um auch nicht-navigierende Kontextaktionen zu registrieren.


dapi.setContextActions([
    {
        title: "Say hello",
        icon: "relative/path/to/ContextActionIcon.png",
        callback: (args) => {
            alert("Hello "+args[0]+"!")
        },
        callbackArgs: ["you"]
    }
]);

Wenn die Kontextaktion Say hello angeklickt wird, wird ein Benachrichtigungsdialog mit der Nachricht "Hello you!" angezeigt.

Hinweis

Das Attribut callbackArgs ist optional und kann auch den Wert undefined enthalten.


 Ausblenden von Kontextaktionen

Um Kontextaktionen auszublenden, rufe die Funktion dapi.setContextActions() mit einem leeren Array auf.


dapi.setContextActions([])

 Verwenden von d.api-Events

 Mitteilen von Änderungen an einer Ressource

Wenn sich der Status einer Ressource geändert hat oder eine Ressource gelöscht wurde, sollten andere Ressourcen mit einer inhaltlichen Abhängigkeit zu dieser Ressource darüber informiert werden. Das ist z.B. hilfreich, damit sich diese anderen Ressourcen selber aktualisieren können.

Mit der Funktion dapi.dispatchResourceEvent(event: IResourceEvent) kannst du ein entsprechendes Event abschicken. Andere Ressourcen können dann darauf reagieren, wenn sie sich auf diese Events registriert haben. Dazu musst du ein ResourceEvent-Ereignis erzeugen. Das Ereignis erwartet den Eventtyp (changed oder deleted) und die URI der Ressource als Parameter. Mit der dispatchResourceEvent-Funktion wird das Ereignis anschließend an die registrierten Event-Listener gesendet. Die URI der Ressource ist notwendig, damit registrierte Event-Listener entscheiden können, ob das Ereignis relevant ist oder ignoriert werden kann.

 Reagieren auf Änderungen in anderen Ressourcen

Du kannst auf Änderungen in anderen Ressourcen reagieren, indem du dich mit der Funktion dapi.addResourceEventListener(eventType: string, callback: (event: IResourceEvent) => void) auf ResourceEvent-Ereignisse registrierst. Der Eventtyp hat folgende Attribute:


interface IResourceEvent {
    /**
     * Name of the event.
     * - changed : the resource has been changed
     * - deleted : the resource has been deleted
     */
    name: string;

    /**
     * uri of affected resource.
     */
    uri: string;
}

Wenn ein entsprechendes Ereignis abgeschickt wird, wird der Callback aufgerufen. Darin kannst du dann auf die Änderungen an der Ressource oder das Löschen reagieren.

Als Beispiel nehmen wir an, es gibt eine Ressource /app/todos.html, in der Aufgaben aufgelistet sind. Ein Klick auf eine Aufgabe ruft eine d.api-Navigation zu der jeweiligen Detailressource auf.

Die Ressource /app/todos.html hat folgende Event-Listener für Ressourcen registriert:


    dapi.addResourceEventListener( 'deleted', function ( resourceEvent ){

        var $todos = dux.query( 'tr' );

        $todos.each( function ( idx, todo ){
            var link = dux.query( todo ).data( 'href' );

            if ( link === resourceEvent.uri ) {
                dux.query( todo ).remove();
                dapi.navigate( 'dapi_blank' );
            }

        } );
    } );

    dapi.addResourceEventListener( 'changed', function ( resourceEvent ){

        var $todos = dux.query( 'tr' );

        $todos.each( function ( idx, todo ){
            var link = dux.query( todo ).data( 'href' );

            if ( link === resourceEvent.uri ) {

                var $task = dux.query( todo ).children( 'td' ).eq( 1 );

                if ( !dux.query( todo ).hasClass( 'text-muted' ) ) {
                    dux.query( todo ).addClass( 'text-muted' );
                    $task.html( '<p class="small">Done</p>' + $task.text() );
                }
            }

        } );
    } );

In der Detailressource /app/task1.html gibt es eine Kontextaktion Löschen, die ein deleted-Event auslöst. Mit diesem Event wird folgende Funktion aufgerufen:


dapi.dispatchResourceEvent( new dapi.ResourceEvent( 'deleted', window.location.pathname ) );

Es gibt außerdem eine Schaltfläche Aufgabe erledigt, welche beim Anklicken folgende Funktion aufruft:


dapi.dispatchResourceEvent(new dapi.ResourceEvent('changed', window.location.pathname));

Beim Klick auf Aufgabe erledigt wird in der /app/todos.html-Ressource das Element in der Liste, welches auf /app/task1.html verweist, als erledigt markiert.

Beim Klick auf die Kontextaktion Löschen wird das Listenelement entfernt und es wird zu einer leeren Ressource navigiert.

Hinweis

Die Umsetzung orientiert sich an der Implementierung der Ereignisverarbeitung im Browser (vgl. Creating and triggering events).

 Verwenden des neuen Bedienkonzepts

 Anzeigen einer Ressource im neuen Bedienkonzept

Mittlerweile gibt es ein neues, moderneres Bedienkonzept der Shell-App. Dieses basiert auf Googles Material Design, weshalb wir empfehlen, auch für die Ressourcen Material Design zu verwenden.

Eine Ressource wird im neuen Bedienkonzept angezeigt, wenn im Header das Attribut window.nextGenerationApp den Wert true enthält.


<script>
    window.nextGenerationApp = true;
</script>

Du musst dieses Attribut vor der Einbindung der d.api einfügen.

 Verwenden der Seitenleiste

Die Seitenleiste (sidebar) ist der Bereich, der am Rand der Shell-App angezeigt wird.

 Anzeigen eigener Inhalte in der Seitenleiste

Jede Ressource kann eine Seite als Inhalt für die Seitenleiste definieren. Verwende zum Anzeigen von Inhalten in der Seitenleiste die d.api-Funktion dapi.setSidebarContent(uri: href).


dapi.setSidebarContent('/app/Sidebar.html');

 Leeren der Seitenleiste

Du kannst die Seitenleiste leeren, um sie in den Zustand vor dem Hinzufügen des Inhalts zu versetzen. Verwende zum Leeren der Seitenleiste die Funktion dapi.setSidebarContent(uri: href) mit der URI about:blank:


dapi.setSidebarContent('about:blank');

 Öffnen der Seitenleiste

Verwende die d.api-Funktion dapi.openSidebar() zum Öffnen der Seitenleiste. Mit dieser Funktion wird die Seitenleiste aufgeklappt.

 Minimieren der Seitenleiste

Verwende die d.api-Funktion dapi.closeSidebar() zum Minimieren der Seitenleiste. Mit dieser Funktion wird die Seitenleiste eingeklappt.

 Reagieren auf Änderungen der Sichtbarkeit der Seitenleiste

Verwende die d.api-Funktion dapi.setSidebarVisualStateChangedCallback( callback: (visual: boolean) => void ), um auf Änderungen an der Sichtbarkeit zu reagieren. Der Callback wird immer ausgeführt, wenn die Seitenleiste geöffnet oder geschlossen wird.

 Austauschen von Daten zwischen der Seitenleiste und der angezeigten Ressource

Mit der d.api-Funktion dapi.transferDataObject( dataObj: object ) kann ein beliebiges Objekt von der Seitenleiste zur Hauptressource oder von der Hauptressource zur Seitenleiste übermittelt werden. Mithilfe der d.api-Funktion dapi.addDataObjectListener( callback: (dataObj) => void ) kannst du auf diese Übermittlung reagieren.

 Verwenden des Inner Supply (Anzeigebereich)

Der Inner Supply wird neben der Hauptressource angezeigt. Er kann z.B. eine geöffnete Aufgabe sein. Der Inner Supply befindet sich unter der App-Leiste (TopAppBar) der Shell-App und beinhaltet eine automatisch benannte App-Leiste mit dem Titel der ausgewählten Ressource (z.B. der Titel einer Aufgabe). Verwende den Inner Supply für Inhalte, die sich direkt auf die Hauptressource beziehen, wie z.B. eine Detailansicht. Die Inhalte sollten möglichst nur darstellend sein und keine größeren Aktionen beinhalten. Falls solche Aktionen oder eine direkte Weiternavigation nötig sind, verwende den Outer Supply.

Hinweis

Eine Navigation aus dem Inner Supply heraus ist nicht möglich. Die Ansicht dient lediglich zur Darstellung von weiteren Informationen und ist für sich genommen keine Ressource.

 Öffnen des Inner Supply

Du kannst den Inner Supply mit der d.api-Funktion dapi.openInnerSupply(uri: string) öffnen.


dapi.openInnerSupply('/app/InnerSupply.html');

Hinweis

Falls der Outer Supply noch geöffnet ist, wird er mit dieser Funktion geschlossen.

 Schließen des Inner Supply

Du kannst den Inner Supply mit der d.api-Funktion dapi.closeInnerSupply() schließen.

 Verwenden des Outer Supply (Anzeigebereich)

Der Outer Supply befindet sich ebenfalls neben der Hauptressource, im Gegensatz zum Inner Supply wird der entsprechende Inhalt aber über die App-Leiste hinaus angezeigt. Er dient als eine Art kleinere Ressource. Der Inhalt muss sich nicht direkt auf die Hauptressource beziehen. Eine Navigation aus dem Outer Supply heraus ist möglich.

 Öffnen des Outer Supply

Du kannst den Outer Supply mit der d.api-Funktion dapi.openOuterSupply(uri: string) öffnen.


dapi.openOuterSupply('/app/OuterSupply.html');

Hinweis

Wenn der Inner Supply noch geöffnet ist, wird er mit dieser Funktion geschlossen.

 Schließen des Outer Supply

Du kannst den Outer Supply mit der d.api-Funktion dapi.closeOuterSupply() schließen.