Übersicht
In manchen Anwendungen ist es ein zusätzlicher Komfort, wenn der Nutzer Informationen als Sprachausgabe abrufen kann, zum Beispiel Verpackungshinweise im Warenausgang. Die Sprachausgabe steht in den gängigen Browsern in guter Qualität zur Verfügung, ohne dass etwas zusätzlich installiert werden muss.

Den zu sprechenden Text können wir auf ABAP-Ebene aus Anwendungsdaten frei zusammenstellen.  Ganz ähnlich wie im Artikel Charts und Diagramme erläutert, benutzen wir ein verstecktes Feld zum Datentransport "ABAP -> HTML" und zum Aufruf einer JavaScript-Funktion, welche die Sprachausgabe durchführt.


Beispiel
In der Anzeige von Kundenbesuchen bieten wir einen "Audio" Button an, der die wesentlichen Daten zum Kundenbesuch vorliest:



Implementierung
Das Audiosymbol zeigen wir in HTML durch ein Image "audio.png" an. Bei einem Klick auf das Audiosymbol wird die ABAP Methode "audio" gestartet:

<img src="../../../icons/audio.png" 
     style="width:28px; border-radius:6px;"
     onclick="S10Apply('audio');" />

In der ABAP Methode stellen wir den gewünschten Text zusammen. Im Beispiel ruft die Methode "audio" der Klasse "customer" eine weitere Methode "speech_output" der Klasse "visit" auf und setzt den zu sprechenden Text in ein Klassenattribut "speech_output":


* class "customer" 
data:
   speech_output type string.
 
method audio.
  speech_output =  myvisit->speech_output( ).
endmethod.
 
 
* class "visit"
 method speech_output.

* date and time
    datadate_out(20),
          time_out type string.
    
    write vdate to date_out.
    time_out vtime(2&& |:| && vtime+2(2&&  |h 
                    && etime(2&& |:| && etime+2(2&& |h .|.

    text s10getuservalue'weekday_long' 
                   && | | && date_out && || && time_out.
* topic and participants 
    datatopic        type string,
          participants type string.

    case sy-langu.
      when 'D'.
        topic 'Thema: '.
        participants 'Teilnehmer: '.

      when 'F'.
        topic 'Sujet: '.
        participants 'Participants: '.

      when others.
        topic 'Topic: '.
        participants 'Participants: '.

    endcase.

    text text && topic && ktext && |.|.
    text text && participants.
    loop at visit_ap_table into mycontact.
      text text && mycontact->fullname && |,
                && mycontact->parau && ||.
    endloop.

* long texts
    if text01 is not initial.
      text text && title01 && |.|.
      text text && text01.
    endif.

    if text02 is not initial.
      text text && title02 && |.|.
      text text && text02.
    endif.

    if text03 is not initial.
      text text && title03 && |.|.
      text text && text03.
    endif.

  endmethod.

Der String "speech_output" soll in HTML nicht angezeigt, sondern zur Sprachausgabe an eine JavaScript-Routine übergeben werden. Wir definieren dazu ein HTML-Element vom Typ "hidden", das über name= an das ABAP-Klassenattribut "speech_output" gebunden ist:

 <!--speech output -->
<input type="hidden" 
        class="input" 
        name="speech_output" 
        onchange="speak(this);" />

                    

Bei einer Änderung des Inhalts wird durch die "onchange=" Angabe die JavaScript-Funktion "speak" aufgerufen, die den Inhalt an die Sprachausgabe des Browsers weiterleitet:

// speech output
var speaker = new SpeechSynthesisUtterance();

function speak(f) {

    var mytext = f.value;
    f.value = '';

    if (speechSynthesis.speaking) {
        speechSynthesis.pause();
        speechSynthesis.cancel();
        return;
    };

    speaker.text = mytext;
    speaker.lang = S10Language();
    speaker.volume = 1;  
    speaker.rate = 1; 
    speaker.pitch = 1;  
    speechSynthesis.speak(speaker);
}

In der JavaScript-Funktion "speak" stellen wir als erstes den zu sprechenden Text in eine Variable "mytext" und löschen dann den Inhalt des "hidden" Elements. Wenn wir das nicht tun, wird nämlich bei einem späteren erneuten Klick auf das Audiosymbol für den gleichen Besuch die "onchange" Funktion nicht erneut ausgeführt, da der Inhalt sich nicht geändert hat.

Als nächstes fragen wir ab, ob gerade eine Sprachausgabe läuft. Falls ja, wird diese beendet, sodass der Benutzer immer mit einem nochmaligen Klick auf das Audiosymbol eine laufende Sprachausgabe abbrechen kann.

Anschließend setzen wir einige Parameter (Textsprache, Lautstärke, ...) und starten die Sprachausgabe.


Erläuterung der HTML-Elemente vom Typ "hidden"
Ein Element

<input type='hidden' ...>

wird nicht angezeigt, kann aber zur Übertragung des Wertes eines ABAP Klassenattributs nach HTML und umgekehrt genutzt werden.

Falls Sie nur die "download" Richtung ABAP->HTML benötigen, verwenden Sie class='output':

<input type='hidden' class='output' name='attrname'>

Hierbei ist "attrname" der Name des ABAP-Klassenattributs. Der Inhalt des Klassenattributs wird vom S10 Framework in das <input> Element übertragen und kann dort als Attribut "value" gelesen werden. Meist verwendet man Klassenattribute vom Typ "string"; es sind aber auch alle anderen Datentypen möglich. Der Inhalt wird auf HTML-Ebene immer in externem Format gemäss den Benutzereinstellungen (Datum, Dezimalpunkt) zur Verfügung gestellt.

Falls Sie auch die "upload" Richtung HTML->ABAP benötigen, verwenden Sie class="input":

<input type='hidden' class='input' name='attrname'>

In den meisten Anwendungsfällen möchte man nach dem Datentransport eine JavaScript-Funktion aufrufen, die lokal etwas Bestimmtes mit den Daten tut, beispielsweise ein Diagramm erzeugt oder wie im Beispiel oben die Spachausgabe eines Textes durchführt. Das erreichen wir durch die Angabe onchange=, welche bei Änderung des Inhalts die angegebene JavaScript-Funktion aufruft:

<input type='hidden' class='output' name='attrname' onchange="...">

Zum Testen können Sie den Inhalt als Nachricht ausgeben:

<input type='hidden' class='output' name='attrname' onchange="alert(this.value)">

Die angegebene JavaScript-Funktion wird nur aufgerufen, wenn sich der Inhalt geändert hat. Initialwert ist der leere String. Solange das genannte Klassenattribut also leer ist, wird auch nichts aufgerufen.

Falls Sie den Inhalt mehrerer Attribute benötigen, arbeiten Sie am besten mit mehreren <input> Elementen und starten die JavaScript-Funktion mit einem weiteren <input type='hidden'>, indem Sie in ABAP einen Zähler hochsetzen und damit "onchange" auslösen. Beispiel:

<input type='hidden' class='output' name='charttitle' id='charttitle'>
<input type='hidden' class='output' name='charttype' id='charttype'>
<input type='hidden' class='output' name='chartfigures' id='chartfigures'>

<input type='hidden' class='output' name='chartstep' onchange="generate_chart()">

In ABAP haben Sie "chartstep" definiert durch

data: chartstep type i.

Sie erhöhen "chartstep" um 1, sobald Sie ein neues Diagramm generieren möchten.

In der aufgerufenen JavaScript Funktion "generate_chart()" können Sie auf die Inhalte wie folgt zugreifen:

var mytitle = document.getElementById('charttitle').value;
var mytype = document.getElementById('charttype').value;
var myfigures = document.getElementById('chartfigures').value;

Komponente: S10 Framework