Inhaltsverzeichnis

24.6.2.4 Projekt 4

Im vierten Projekt `webapp4` werden weitere 6 Webseiten als Erweiterung des Projektes `webapp3` auf der Basis der Klasse Webpage erzeugt. Die Webseite mit einem (SQLite-)Datenbank-Report sehen Sie hier:

DB-REPORT

Abbildung 24.6.2.4.1: (SQLite-)Datenbank-Report (Ausschnitt)

24.6.2.4.1 Template-Datei Main.webpage

Die Webpage Main.webpage ist auch in diesem Projekt die wichtigste Datei des Templates, denn sie enthält am Anfang einen Gambas-Block für das Auslesen der im Webbrowser gesetzten Sprache sowie der angeforderten Webseite und dann den Head-Bereich mit einem Platzhalter. Danach folgt HTML mit weiteren Platzhaltern für die Layout-Bereiche Header, Navigation, Content und Footer:

 [1] <%
 [2] '-- Variable declaration must come before any HTML
 [3]     Dim sCurSite As String
 [4]     Dim aSiteList As New String[]
 [5]
 [6] '-- The browser tells the server which language (locale) it is set to via Request.Language.
 [7]     System.Language = Request.Language ' Example: de_DE.UTF8
 [8] '-- Insert a list to filter the pages
 [9]     aSiteList = Main.SiteList
 [10]
 [11]     If Request.Query Then
 [12]        If aSiteList.Exist(Request.Query) Then
 [13]           sCurSite = Request.Query
 [14]        Endif
 [15]     Else
 [16]        sCurSite = aSiteList[0]
 [17]     Endif
 [18] %>
 [19] <!DOCTYPE html>
 [20] <html lang="de">
 [21]   <!-- BEGIN SITE-HEAD -->
 [22]   <head>
 [23]     <meta charset="UTF-8">
 [24]     <!-- Setting for display on mobile devices | MediaQueries -->
 [25]     <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
 [26]     <!-- The description is used for display in search engines! -->
 [27]     <meta name="description" content="TEMPLATE: WEBPAGE GAMBAS HTML CSS JS">
 [28]     <!-- The title of the web page is displayed in the browser tab! -->
 [29]     <title><%=sCurSite%></title> <!--  < 30 Zeichen -->
 [30]     <!-- Reference to an icon. The favicon is displayed in the browser tab! -->
 [31]     <link rel="icon" type="image/png" href="./favicon/favicon_blue_32.ico">
 [32]     <!-- Reference to a central CSS file in the /css folder -->
 [33]     <link rel="stylesheet" type="text/css" href="./css/style.css">
 [34]     <!-- Reference to a JavaScript file in the /js folder -->
 [35]     <script src="./js/set_time.js"></script>
 [36]   </head>
 [37]   <!-- END SITE-HEAD -->
 [38]   <body onload="JSTimer1();">
 [39]     <<IncHeader>>
 [40]     <br>
 [41]     <<IncNavigation>>
 [42]     <br>
 [43]     <main>
 [44]       <<IncContent>>
 [45]     </main>
 [46]     <<IncFooter>>
 [47]   </body>
 [48] </html>

Die Gambas-Klassen-Datei main.class enthält eine erweiterte Liste der aktuell verfügbaren Webseiten, die in der Variablen `SiteList` gespeichert wird:

' Gambas class file

  Public SiteList As String[] = ["Start", "Umgebung", "Zeit", "Datum", "Multimedia", "DBReport", "Formular", "FPlotter", "Impressum"]

Kommentar

 1. <!--BEGIN SITE-HEADER -->
 2. <header class="site-header">
 3.   <img class="site-logo" src="./icons/logo3_256x256.png" alt="Gambas-Logo">
 4.   <p class="site-slogan">Webseiten mit Gambas-Webpage erzeugen</p>
 5. </header>
 6. <!-- END SITE-HEADER -->

24.6.2.4.2 Template-Datei IncContent.webpage

Die Webpage IncContent.webpage enthält u.a. 9 Platzhalter, die in Abhängigkeit von der angeforderten Webseite (Request-Query) durch den Inhalt der einzelnen Webseiten ersetzt werden.

 [1] <!-- START: INSERT SELECTED CONTENT -->
 [2]   <%Select Request.Query
 [3]      Case "Umgebung"%>
 [4]        <<IncEnvironment>>
 [5]      <% Case "Zeit"%>
 [6]        <<IncTime>>
 [7]      <%Case "Datum"%>
 [8]        <<IncDate>>
 [9]      <%Case "Multimedia"%>
 [10]        <<IncMultimedia>>
 [11]      <%Case "DBReport"%>
 [12]        <<IncDBReport>>
 [13]      <%Case "Formular"%>
 [14]        <<IncFormular>>
 [15]      <%Case "FPlotter"%>
 [16]        <<IncFPlotter>>
 [17]      <%Case "Impressum"%>
 [18]        <<IncImpressum>>
 [19]      <%Default%>
 [20]        <<IncHome>>
 [21]   <%End Select%>
 [22] <!-- END: INSERT CONTENT -->

Die Gambas-Klassen-Datei IncContent.class ist leer.

Kommentar

Hinweis:

Der Inhalt der Webpage IncNavigation.webpage ist der gleiche wie im Web-Projekt `webapp3` und wird 1:1 übernommen.

24.6.2.4.3 Erweiterungen

In den folgenden sechs Absätzen wird der HTML-Quelltext für den Bereich 'Content' der Webseiten Zeit, Datum, Multimedia, DBReport, Formular und FPlotter angegeben und kommentiert.

24.6.2.4.3.1 Template-Datei IncTime.webpage

Die Webpage IncTime.webpage enthält u.a. einen Platzhalter (Zeile 5) für die einzufügende aktuelle Uhrzeit:

 [1] <!-- INSERT TIME  -->
 [2] <h1>Aktuelle Zeit</h1>
 [3] <div class="thin-box">
 [4]   <figure>
 [5]     <h2 id="set_time"></h2>
 [6]   </figure>
 [7] </div>

Die Gambas-Klassen-Datei IncTime.class ist leer.

Kommentar

UHRZEIT

Abbildung 24.6.2.4.2: Anzeige der aktuellen Uhrzeit

24.6.2.4.3.2 Template-Datei IncDate.webpage

Die Webpage IncDate.webpage enthält in der Zeile 5 u.a. einen Platzhalter für das einzufügende Datum in einem bestimmten Format:

 [1] <!-- INSERT DATE  -->
 [2] <h1>Aktuelles Datum</h1>
 [3] <div class="thin-box">
 [4]   <figure>
 [5]     <h2><%=Format(Now, "dddd - d. mmmm yyyy")%></h2>
 [6]   </figure>
 [7] </div>

Kommentar

24.6.2.4.3.3 Template-Datei IncMultimedia.webpage

Was wäre eine Webseite ohne Bilder und andere multimediale Elemente wie Sound- oder Video? Genau diese drei Elemente werden in die Webseite IncMultimedia.webpage nacheinander eingefügt:

 [1] <h1>Multimedia</h1>
 [2]
 [3] <!-- INSERT IMAGE  -->
 [4] <div class="thin-box">
 [5]   <h3>Bilder flexibel einfügen</h3>
 [6]   <hr>
 [7]   <figure>
 [8]     <img src="./images/tom_780x1012.png" alt="Tom" width="343" height="445">
 [9]     <figcaption>Tom im Rockkonzert in Berlin</figcaption>
 [10]   </figure>
 [11] </div>
 [12] <!-- INSERT AUDIO -->
 [13] <div class="thin-box">
 [14]   <h3>Audio-Dateien einfügen</h3>
 [15]   <hr>
 [16]   <figure>
 [17]     <!-- Bedienelemente anzeigen und Metadaten laden -->
 [18]     <audio src="./audiovideo/tom.mp3" type="audio/mp3" controls></audio>
 [19]     <figcaption>Sänger: Tom -> Der Berliner</figcaption>
 [20]   </figure>
 [21] </div>
 [22] <!-- INSERT VIDEO -->
 [23] <div class="thin-box">
 [24]   <h3>Video-Dateien einfügen</h3>
 [25]   <hr>
 [26]   <figure>
 [27]     <video src="./audiovideo/viehscheid.mp4" controls></video>
 [28]     <figcaption>Viehscheid in Gunzesried (Allgäu)</figcaption>
 [29]   </figure>
 [30] </div>

Kommentar

TOM

Abbildung 24.6.2.4.3: Bild-Anzeige

SOUND

Abbildung 24.6.2.4.4: Bedienelemente Sound

VIDEO

Abbildung 24.6.2.4.5: Bedienelemente Video (und Fußzeile)

Die Gambas-Klassen-Datei IncMultimedia.class ist leer.

24.6.2.4.3.4 Template-Datei IncDBReport.webpage

Die Webpage IncDBReport.webpage ist nennenswert kurz und enthält einen Platzhalter für den einzufügenden Datenbank-Report:

 [1]  <% Print DBReport(); %>
 [2]  <br>

Die Erzeugung des (SQLite-)Datenbank-Reports wird in die Gambas-Klassendatei IncDBReport.class ausgelagert:

 [1] ' Gambas class file
 [2]
 [3] Public rDBResult As Result
 [4] Public cDBConnection As New Connection
 [5]
 [6] Public Function DBReport() As String
 [7]
 [8]     Dim iRecord, iField As Integer
 [9]     Dim sSQL, sHTML As String
 [10]     Dim aFieldNamesDisplayed As String[]
 [11]
 [12]     aFieldNamesDisplayed = ["ID", "Vorname", "Nachname", "Wohnort", "PLZ", "Straße", "Geburtstag",
                            "Festnetz", "Mobil", "EMail"]
 [13]
 [14]     cDBConnection.Type = "sqlite3"
 [15]     cDBConnection.Host = Application.Path &/ ".public/db"
 [16]     cDBConnection.Name = "contacts.sqlite"
 [17]
 [18]     Try cDBConnection.Open()
 [19]     If Error Then
 [20]   '-- Option: sHTML &= "<h1>A DB connection could not be established!</h1>"
 [21]       CGI.Error("A DB connection could not be established!")
 [22]       Return
 [23]     Endif
 [24]
 [25]     cDBConnection.Exec("PRAGMA short_column_names = ON")
 [26]
 [27]     sSQL = "SELECT * FROM contacts"
 [28]
 [29]     Try rDBResult = cDBConnection.Exec(sSQL)
 [30]     If Error Then
 [31]       Error.Raise("<h1>Error!<br>" & Error.Text & "</h1>")
 [32]     Endif
 [33]
 [34]     If rDBResult.Count = 0 Then
 [35]       Error.Raise("<h1>The number of selected records is zero!</h1>")
 [36]     Endif
 [37]
 [38] '-- Enter the field names in the table header
 [39]     If rDBResult.Available Then
 [40]       sHTML &= "<h1 style=\"margin-bottom:0.6rem;\">"
 [41]       sHTML &= "Datenbank-Report"
 [42]       sHTML &= "</h1>"
 [43]       sHTML &= "<h3 style=\"margin-bottom:1.4rem;\">"
 [44]       sHTML &= Format(Now, "dddd - d. mmmm yyyy") & " - " & Format$(Now, "hh:nn") & " Uhr"
 [45]       sHTML &= "</h3>"
 [46]       sHTML &= ""
 [47]       sHTML &= "<table>"
 [48]       sHTML &= "<tr>"
 [49]       For iField = 0 To rDBResult.Fields.Count - 1
 [50]         sHTML &= "<th>" & aFieldNamesDisplayed[iField] & "</th>"
 [51]       Next
 [52]       sHTML &= "</tr>"
 [53]
 [54]   '-- Fill the (HTML)table with the DB data
 [55]       For iRecord = 0 To rDBResult.Count - 1
 [56]         sHTML &= "<tr>"
 [57]         rDBResult.MoveTo(iRecord)
 [58]
 [59]         For iField = 0 To rDBResult.Fields.Count - 1
 [60]           If rDBResult.Fields[iField].Name = "gebdatum" Then
 [61]             sHTML &= "<td>" & Format(rDBResult[iField], "dd.mm.yyyy") & "</td>"
 [62]           Else
 [63]             sHTML &= "<td>" & rDBResult[iField] & "</td>"
 [64]           Endif
 [65]         Next '-- Column
 [66]         sHTML &= "</tr>"
 [67]       Next   '-- DB-Record
 [68]
 [69]       sHTML &= "</table>"
 [70]       sHTML &= gb.Lf
 [71]
 [72]     Endif
 [73]
 [74] '-- Ausgabe des kompletten HTML als HTML-Block
 [75]     Return sHTML
 [76]
 [77]     Catch
 [78]     Return Error.Text
 [79]
 [80] End

Kommentar

DATABASE

Abbildung 24.6.2.4.6: (SQLite-)Datenbank-Report (Ausschnitt)

24.6.2.4.3.5 Template-Datei IncFormular.webpage

An dieser Stelle werden nur ein bestimmtes Formular, die Verarbeitung der Formulardaten sowie deren Auswertung beschrieben. Die Struktur von Formularen und die Syntax von (HTML-)Formularen sowie deren Felder sind nicht Gegenstand dieser Beschreibung. Dem interessierten Leser sei die Recherche selbst nahegelegt. Ein guter Startpunkt ist https://wiki.selfhtml.org/wiki/HTML/Tutorials/Formulare/Was_ist_ein_Webformular%3F#Buttons.

Quelltext der Webpage IncFormular.webpage:

 [1] <%
 [2]     Dim i As Integer
 [3]     Dim sField, sErrorMessage As String
 [4]     Dim vValue As Variant
 [5]     Dim aRequestFields, aFieldList As New String[]
 [6]     Dim cData, cRadioList As New Collection
 [7]
 [8]     cData.Add("off", "material")
 [9]     cData.Add("off", "confirmation_gdpr")
 [10]
 [11]     cRadioList.Add("Ubuntu", "ubuntu")
 [12]     cRadioList.Add("Mint", "mint")
 [13]     cRadioList.Add("Eine andere Distribution", "another")
 [14]
 [15]     aFieldList = ["token", "firstname", "lastname", "birthday", "email", "material",
                  "os_version", "message", "confirmation_gdpr"]
 [16]
 [17]     aRequestFields = Request.Post.Fields
 [18]
 [19]     If Request.Method = "POST" And Request.Post["token"] = "ok" Then
 [20]        For Each sField In aRequestFields
 [21]          Select sField
 [22]            Case "material"
 [23]              cData.Add("on", "material")
 [24]            Case "confirmation_gdpr"
 [25]              cData.Add("on", "confirmation_gdpr")
 [26]            Case "message"
 [27]               If Request.Post[sField] = "" Then
 [28]                  cData.Add("empty", "message")
 [29]               Else
 [30]                  cData.Add(Request.Post[sField], sField)
 [31]               Endif
 [32]            Default
 [33]              cData.Add(Request.Post[sField], sField)
 [34]          End Select
 [35]        Next
 [36]
 [37]        For Each vValue In cData
 [38]          Select Case cData.Key
 [39]            Case "confirmation_gdpr"
 [40]              If Html(vValue) = "off" Then
 [41]                 sErrormessage = "Ohne Ihre Einwilligung zur Erfassung, Speicherung ... .<br><br>"
 [42]              Endif
 [43]          End Select
 [44]        Next
 [45]
 [46]        If sErrorMessage = "" Then
 [47] %>
 [48]           <br>
 [49]           <h3>Anmeldung zum Gambas-Grundkurs</h3>
 [50]           <p>Hallo <%=cData["firstname"]%>!<br><br>Sie haben sich erfolgreich angemeldet. ... .</p>
 [51] <%
 [52]        Else
 [53] %>
 [54]           <h3>Hinweis zur Online-Anmeldung zum Gambas-Grundkurs</h3>
 [55] <%
 [56]           Print sErrorMessage
 [57]           Print "<br>"
 [58] %>
 [59]           <button onclick=" history.back()">Zurück zum Formular</button>
 [60] <%
 [61]        Endif
 [62]     Else
 [63] %>
 [64]        <h1>Anmeldung zum Gambas-Grundkurs</h1>
 [65]        <p></p>
 [66]
 [67]        <form action=<%=Application.Root%>?Formular method="post" accept-charset="UTF-8">
 [68]
 [69]          <fieldset>
 [70]            <legend>Persönliche Daten</legend>
 [71]              <!-- Verstecktes Feld zum Nachweis, dass die Daten aus diesem Formular stammen -->
 [72]              <input type="hidden" id="token" name="token" value="ok">
 [73]
 [74]              <label for="firstname">Ihr Vorname</label>
 [75]              <input type="text" id="firstname" name="firstname" required autofocus>
 [76]
 [77]              <label for="lastname">Ihr Nachname</label>
 [78]              <input type="text" id="lastname" name="lastname" required>
 [79]
 [80]              <label for="birthday">Ihr Geburtsdatum (optional)</label>
 [81]              <input type="date" id="birthday" name="birthday">
 [82]
 [83]              <label for="email">Ihre EMail-Adresse</label>
 [84]              <input type="email" id="email" name="email" required>
 [85]          </fieldset>
 [86]
 [87]          <fieldset>
 [88]            <legend>Kursmaterial</legend>
 [89]            <input type="checkbox" id="material" name="material">
 [90]            <label>Soll das Kurs-Material schon vor dem Kurs zugeschickt werden?</label>
 [91]          </fieldset>
 [92]
 [93]          <fieldset>
 [94]            <legend>Welche Linux-Distribution nutzen Sie aktuell?</legend>
 [95]            <div class="radiobox">
 [96]              <input type="radio" id="ubuntu" name="os_version" value="ubuntu">
 [97]              <label>Ubuntu</label>
 [98]            </div>
 [99]            <div class="radiobox">
 [100]              <input type="radio" id="mint" name="os_version" value="mint" checked="checked">
 [101]              <label>Mint</label>
 [102]            </div>
 [103]            <div class="radiobox">
 [104]              <input type="radio" id="another" name="os_version" value="another">
 [105]              <label>Eine andere Distribution</label>
 [106]            </div>
 [107]          </fieldset>
 [108]
 [109]          <fieldset>
 [110]            <legend>Grundkurs</legend>
 [111]            <label for="message">Ihre Nachricht an die Kursleitung (optional)</label>
 [112]            <textarea id="message" name="message"></textarea>
 [113]          </fieldset>
 [114]
 [115]          <fieldset>
 [116]            <legend>DSGVO</legend>
 [117]            <!-- General Data Protection Regulation (gdpr) - Datenschutz-Grundverordnung -->
 [118]            <input type="checkbox" id="confirmation_gdpr" name="confirmation_gdpr" checked>
 [119]            <label>Mit der Nutzung dieses Formulars erklären Sie sich mit der Erfassung, Speicherung und Verarbeitung Ihrer Daten bis zum Abschluss des Kurses einverstanden.</label>
 [120]          </fieldset>
 [121]
 [122]          <button type="submit">Zum Gambas-Kurs verbindlich anmelden</button>
 [123]
 [124]        </form>
 [125] <%
 [126]      Endif
 [127] %>
 [128]      <br>

Kommentar

QUITTUNG

Abbildung 24.6.2.4.7: Formular-Quittung

Hinweise

Formular-Felder vom Typ 'radio' und 'checkbox' sind mit besonderer Sorgfalt auszuwerten. Der Grund liegt darin, dass Feldnamen von diesen Typen nicht in das String-Array Request.Post.Fields aufgenommen werden, wenn sie nicht ausgewählt oder markiert wurden! Ein leeres Text-Feld dagegen wird mit dem Feldnamen in das String-Array Request.Post.Fields aufgenommen, aber einem leeren String als Feldwert.

Beispiel:

Das Formular im Projekt `webapp4` hat 9 Formular-Felder – eines davon vom Typ 'hidden' mit dem festen Feldwert 'ok'. Die Formular-Felder `material`, `confirmation_gdpr` (Typ 'checkbox') und `os_version` (Typ 'radio') werden nicht ausgewählt und das (Text-)Feld `message` bleibt leer.

Lassen Sie sich nach dem Abschicken des Formulars die Feldnamen und Feldwerte aller Formularfelder ausgeben:

aRequestFields = Request.Post.Fields

If Request.Method = "POST" And Request.Post["token"] = "ok" Then
   For i = 0 To aRequestFields.Max
     Print "Field " & (i+1) & " => " & aRequestFields[i] & " --->  Field_Value = " & Html(Request.Post[aRequestFields[i]]) & "<br>"
   Next
   ...
EndIf

ergibt sich exemplarisch diese Liste mit den Feldnamen und deren Feldwerte:

Field 1 => token 		---> Field_Value = ok
Field 2 => firstname 	        ---> Field_Value = Klaus
Field 3 => lastname 		---> Field_Value = Mayer
Field 4 => birthday 		---> Field_Value = 1999-11-03
Field 5 => email 		---> Field_Value = klaus.mayer.99@web.de
Field 6 => message 		---> Field_Value =

Es fehlen 3 Felder in Request.Post.Fields und damit in der Feldliste! Ein Ansatz, um diesen Mangel zu beheben besteht darin, eine Variable cData vom Typ Collection zu definieren und mit passenden Werten zu initialisieren:

cData.Add("off", "material")
cData.Add("off", "confirmation_gdpr")

In einer Kontrollstruktur werden alle Felder in Request.Post.Fields ausgelesen und passende Werte zugewiesen:

    aRequestFields = Request.Post.Fields

    If Request.Method = "POST" And Request.Post["token"] = "ok" Then
       For Each sField In aRequestFields
         Select sField
           Case "material"
             cData.Add("on", "material")
           Case "confirmation_gdpr"
             cData.Add("on", "confirmation_gdpr")
           Case "message"
              If Request.Post[sField] = "" Then
                 cData.Add("empty", "message")
              Else
                 cData.Add(Request.Post[sField], sField)
              Endif
           Default
             cData.Add(Request.Post[sField], sField)
         End Select
       Next

Damit besitzt jedes Feld einen Wert. So können Sie sich zur Kontrolle alle 9 Schlüssel-Wert-Paare der Collection `cData` anzeigen lassen:

For Each vValue In cData
  Print cData.Key & "   " & String.Chr(187) & "   " & Html(vValue) & "<br>"
Next

Ausgabe in der IDE-Konsole:

material 		» off
confirmation_gdpr 	» off
token 			» ok
firstname 		» Klaus
lastname 		» Mayer
birthday 		» 1999-11-03
email 			» klaus.mayer.99@web.de
os_version 	        » mint
message 		» empty

Für Felder vom Typ 'radio' wird folgender Weg vorgeschlagen: Da Radio-Button eine Gruppe von beschrifteten Button sind, von denen der Anwender genau einen auswählen kann, wird eine bestimmte Auswahl über das checked-Attribut mit checked=„checked“ vorselektiert. Damit wird das Feld 'os_version' stets im String-Array Request.Post.Fields vorhanden sein:

   <fieldset>
     <legend>Welche Linux-Distribution nutzen Sie aktuell?</legend>
     <div class="radiobox">
       <input type="radio" id="ubuntu" name="os_version" value="ubuntu">
       <label>Ubuntu</label>
     </div>
     <div class="radiobox">
       <input type="radio" id="mint" name="os_version" value="mint" checked="checked">
       <label>Mint</label>
     </div>
     <div class="radiobox">
       <input type="radio" id="another" name="os_version" value="another">
       <label>Eine andere Distribution</label>
     </div>
   </fieldset>

Diese vorgegebene Auswahl kann der Anwender allerdings jederzeit ändern.

Um sicherzustellen, dass alle als verpflichtend ausgewiesenen Felder auch tatsächlich mit einem Wert ausgefüllt wurden, gibt es zwei Strategien. Eine prüft erst nach dem Absenden des Formulars, ob zu dem Feld auch ein Wert existiert und legt dann dem Nutzer das teilweise ausgefüllte Formular so lange mit einem passenden Kommentar vor, bis alle Werte vorliegen. Die andere besteht darin, ausgewählte Formular-Attribute zu verwenden. Pflichtfelder erhalten das required-Attribut:

<input type="text" id="firstname" name="firstname" required autofocus>

Solange die Eingaben nicht valide sind, wird ein Absenden des Formulars verhindert und eine Meldung ausgegeben wie „Bitte füllen Sie dieses Feld aus“.

Zusätzlich können Sie für ausgewählte Felder wie (Text-)Felder die Attribute 'pattern' und 'title' verwenden, wobei für das Attribut 'pattern' in den folgenden zwei Beispielen reguläre Ausdrücke verwendet werden:

pattern="^[A-Za-z]+$" title="Nur Buchstaben sind gültige Zeichen!"

oder bei einem Eingabefeld für eine EMail-Adresse:

pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$" title="Muster: localpart@domain.tld"

Der Text des Titels erscheint als Tool-Tipp, wenn Sie mit der Maus einen Augenblick über dem Feld bleiben.

24.6.2.4.3.6 Template-Datei IncFPlotter.webpage

Der Funktionsplotter ist eine Adaption des JS-Plotterbeispiels auf der Webseite https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Funktionsplotter. Angegeben wird der komplette Quelltext für die Erzeugung der Graphen von drei (unterschiedlichen) Funktionen, die Sie frei definieren können oder aus der Liste der vordefinierten Funktionen auswählen:

 [1]   <!-- Functionality of the plotter -->
 [2]   <script src="./js/pl.cs.js" charset="utf-8"></script>
 [3]   <script src="./js/pl.plot.js" charset="utf-8"></script>
 [4]   <script src="./js/pl.plotter.js" charset="utf-8"></script>
 [5]
 [6]   <h1>Funktionsplotter</h1>
 [7]
 [8]   <figure id="plotarea"></figure>
 [9]   <div hidden id="wertetabelle" aria-live="polite"></div>
 [10]
 [11]   <fieldset id="plotter">
 [12]     <div aria-live="polite">
 [13]       <label id="f1">f<sub>1</sub>(x) = <input type="text" id="fkt1" value="sin(x)/x"></label>
 [14]       <label id="f2">f<sub>2</sub>(x) = <input type="text" id="fkt2" value="sin(x)"></label>
 [15]       <label id="f3">f<sub>3</sub>(x) = <input type="text" id="fkt3" value="cos(x)"></label>
 [16]     </div>
 [17]     <div>
 [18]       <label style="padding-left: 1rem">x<sub>min</sub> = <input type="number" step="any" id="idxmin" value="-6.8"></label>
 [19]       <label style="padding-left: 2rem">x<sub>max</sub> = <input type="number" step="any" id="idxmax" value="7.8"></label>
 [20]       <button style="padding-left: 1rem" id="plotbutton">Funktionsschar zeichnen</button>
 [21]     </div>
 [22]   </fieldset>
 [23]
 [24]   <p id="vdeffkt">Vordefinierte Funktionen:<br>
 [25]     <button>AM</button>,
 [26]     <button>PM</button>,
 [27]     <button>sin(x)/x</button>,
 [28]     <button>sinh</button>,
 [29]     <button>cosh</button>,
 [30]     <button>tanh</button> und
 [31]     <button>Puls</button>.
 [32]   </p>
 [33]
 [34]   <p id="jsfkt">Javascript unterstützt die folgenden Funktionen:<br>
 [35]     <button>abs</button>,
 [36]     <button>acos</button>,
 [37]     <button>asin</button>,
 [38]     <button>atan</button>,
 [39]     <button>cos</button>,
 [40]     <button>exp</button>,
 [41]     <button>log</button>,
 [42]     <button>pow</button>,
 [43]     <button>sin</button>,
 [44]     <button>sqrt</button> und
 [45]     <button>tan</button>.
 [46]   </p>
 [47]   <p>Bitte den Definitionsbereich der Funktionen beachten!</p>
 [48]   <hr>
 [49]   <p style="font-size: 0.9rem; color: gray;">Der Funktionsplotter ist eine Adaption des JS-Plotterbeispiels auf der Webseite  https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Funktionsplotter</p>

Die komplette Funktionalität des Plotters steckt in drei JavaScript-Skripten. Den Style der Funktionsbilder können geändert werden, wenn Sie die entsprechenden JavaScript-Skripte verändern.

PLOTTER

Abbildung 24.6.2.4.8: Funktionsbilder in einem besonderen Style

24.6.2.4.4 Übertragung der Web-Applikation auf den Webserver

Die Webseiten des Projektes 4 wurden beim Autor auf seinem Arbeitsplatz-Computer entwickelt. Auf diesem wurde auch der Webserver Lighttpd installiert und konfiguriert. Da die Webseiten auch im Intranet aufgerufen werden sollen, wurde nach einer Möglichkeit gesucht, die ausführbare Gambas-Datei index.gambas als Webserver-Programm sowie die benötigten Ressourcen-Dateien aus dem Projekt-Ordner `webapp4` in den Web-Ordner '/usr/lib/cgi-bin/webapp3' auf dem Arbeitsplatz-Computer zu kopieren:

hans@pc:~/GB3BUCH/24K_NetzwerkN/24.6.2.4_WP4/BuchProjekt/webapp4$
.
├── index.gambas
├── .public
│   ├── audiovideo
│   ├── css
│   ├── db
│   ├── favicon
│   ├── icons
│   ├── images
│   └── js
...

hans@pc:/usr/lib/cgi-bin/webapp4$
.
├── index.gambas
├── audiovideo
├── css
├── favicon
├── icons
├── images
├── js
└── .public
    └── db

Sie können die erforderlichen Ordner und Dateien mit erhöhten Rechten im Dateimanager kopieren oder nutzen das folgende Bash-Skript:

#!/bin/bash
#
# -- Definition of colour values in the terminal
#--------------------------------------------------------------------------------------
RE="\033[0;31m"                 # red
GR="\033[0;32m"                 # green
BL="\033[0;34m"                 # blue
REB="\033[1;31m"                # red bold
GRB="\033[1;32m"                # green bold
BLB="\033[1;34m"                # blue bold
FGB="\033[1m\033[42m\033[37m"   # bold + withe + green background
NO="\033[0m"                    # normal
#--------------------------------------------------------------------------------------

if [ -z "$1" ]; then
   echo "ERROR! The parameter string is an empty string."
   exit 99
else
   pass=$1
fi

echo
webserver="lighttpd"
echo "WEBSERVER = ${webserver}"

target_basic_path="/usr/lib/cgi-bin"
echo "TARGET-BASIC-PATH = ${target_basic_path}"

pwd="${PWD##*/}"
echo "PWD = ${pwd}"

target_site_path=${target_basic_path}/${pwd}
echo "TARGET-SITE-PATH = ${target_site_path}"

#IP address of the local (web) server
ipaddress="192.168.0.4"
echo "IP-ADDRESS = ${ipaddress}"

source_path=$(pwd)
echo "SOURCE-PATH = ${source_path}"

output=$(ping -c 1  ${ipaddress})

substring="min/avg/max/mdev"

if [[ ${output} =~ ${substring} ]]; then
   echo
   echo -e "${BLB}» The web server on the intranet with the IP address '${ipaddress}' can be reached.${NO}"
 #  echo
else
   echo
   echo -e "${REB}» ERROR\n» The web server in the intranet with IP '${ipaddress}' is not accessible!${NO}"
   echo
   exit 99
fi

#--------------------------------------------------------------------------------------

echo ${pass} | sudo -S mkdir ${target_site_path} 2>/dev/null
echo ${pass} | sudo -S chmod 777 ${target_site_path}

echo -e "${BLB}» The directories and files are copied ...${NO}"
echo

echo ${pass} | sudo -S cp ${source_path}/index.gambas ${target_site_path}

cd ${source_path}/.public/audiovideo
find . -print | cpio -pdmu ${target_site_path}/audiovideo

cd ${source_path}/.public/css
find . -print | cpio -pdmu ${target_site_path}/css

cd ${source_path}/.public/favicon
find . -print | cpio -pdmu ${target_site_path}/favicon

cd ${source_path}/.public/icons
find . -print | cpio -pdmu ${target_site_path}/icons

cd ${source_path}/.public/images
find . -print | cpio -pdmu ${target_site_path}/images

cd ${source_path}/.public/js
find . -print | cpio -pdmu ${target_site_path}/js

cd ${source_path}/.public/db
find . -print | cpio -pdmu ${target_site_path}/.public/db

echo ${pass} | sudo -S chmod 755 ${target_site_path}

#--------------------------------------------------------------------------------------

echo
echo -e "${REB}Continue with <ENTER>${NO}"
read e

Der Aufruf des Bash-Skriptes beim Autor erfolgt im Projektordner in einer Konsole:

hans@pc-a-mint20:~/GB3BUCH/24K_NetzwerkN/24.6.2.4_WP4/BuchProjekt/webapp4$ ./cpwp2server.sh <user.passwort>

WEBSERVER = lighttpd
TARGET-BASIC-PATH = /usr/lib/cgi-bin
PWD = webapp4
TARGET-SITE-PATH = /usr/lib/cgi-bin/webapp4
IP-ADDRESS = 192.168.0.4
SOURCE-PATH = /home/hans/GB3BUCH/24K_NetzwerkN/24.6.2.4_WP4/BuchProjekt/webapp4

» The web server on the intranet with the IP address '192.168.0.4' can be reached.
» The directories and files are copied ...

27373 Blöcke
19 Blöcke
11 Blöcke
87 Blöcke
2268 Blöcke
203 Blöcke
44 Blöcke

Continue with <ENTER>

hans@pc-a-mint20:~/GB3BUCH/24K_NetzwerkN/24.6.2.4_WP4/BuchProjekt/webapp4$

24.6.2.4.5 Aufruf der Webseiten

Danach können Sie die Webseiten im Intranet vom Webserver abrufen und in Ihrem Webbrowser anzeigen:

http://192.168.0.4/cgi-bin/webapp4/index.gambas

Download