HTML5-Tutorium: JavaScript: Hello World 06: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
(26 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
{{TBD|Anpassung an Teil 4 des Tutoriums. Derzeit ist diese Version noch an Teil 3 des Tutoriums angepasst.}}
{{In Bearbeitung}}
{{HTML5-Tutorium:JavaScript:HelloWorld:Menü}}
{{HTML5-Tutorium:JavaScript:HelloWorld:Menü}}
'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/es5/hello_world/WK_HelloWorld05/index.html <code>index.html</code>]
 
([https://glossar.hs-augsburg.de/beispiel/tutorium/es5/hello_world/WK_HelloWorld05/ SVN-Repository]; nach Download: <code>npm update</code>)
'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/es5/hello_world/WK_HelloWorld05/web/index.html <code>index.html</code>],
([https://glossar.hs-augsburg.de/beispiel/tutorium/es6/hello_world/WK_HelloWorld05/ SVN-Repository])
==Anwendungsfälle (Use Cases)==
==Anwendungsfälle (Use Cases)==
Gegenüber dem [[HTML5-Tutorium:_JavaScript:_Hello_World_03|dritten]] und
Gegenüber dem [[HTML5-Tutorium:_JavaScript:_Hello_World_04|vierten Teil des Tutoriums]]
[[HTML5-Tutorium:_JavaScript:_Hello_World_04|vierten Teil des Tutoriums]]
ändern sich die die Anwendungsfälle nicht.
ändern sich die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.


In diesem Teil des Tutoriums geht es darum, die Anwendung zu verbessern, so dass sie schneller ausgeliefert werden kann.
In diesem und im nächsten Teil des Tutoriums werden zwei wesentliche [[Programmierprinzipien|Grundprinzipien der Programmierung]]
Außerdem wird die Entwicklungsarbeit mit Hilfe von Automatisierungstools erleichtert.
thematisiert:
* [[Don't repeat yourself]] (DRY, “Keep your code DRY!”).
* Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien.


==Erstellen eines neuen Projektes==
==Erstellen eines neuen Projektes==


Erstellen Sie ein neues Projekt <code>HelloWorld05</code>“ und legen Sie dieses in Ihrem Repository ab.
Erzeugen Sie wie im  [[HTML5-Tutorium:_JavaScript:_Hello_World_04|vierten Teil des Tutoriums]] ein neues Projekt,
Kopieren Sie anschließend alle Dateien aus dem vierten Teil des Tutoriums und passen Sie den Titel in der HTML-Datei an
diesmal allerdings mit dem schönen Namen <code>HelloWorld05</code>“ und speichern Sie dieses wieder
 
in Ihrem SVN-Repository (Achtung: <code>node_modules</code> muss existieren und auf der Ignore-Liste stehen).
Fügen Sie ins Wurzelverzeichnis Ihres Porjektes einen neuen Ordner namens „<code>src</code>“ ein und verschieben
Sie die Ordner „<code>web/css</code>“ und „<code>web/js</code>“ in diesen Ordner. Der <code>src</code>-Ordner enthält
künftig die von Ihnen erstellten JavaScript- und CSS-Sourcen. Mit Hilfe von Node.js-Tools werden im <code>web</code>-Ordner
komprimierte Versionen dieses Dateien erstellt.
 
Zu guter Letzt committen Sie abermals.
 
===Node.js===
 
Dieses Tutorium befasst sich zwar nicht mit der Erstellung von Node.js-Server-Anwendungen, aber trotzdem benötigen wir
[[Node.js]], da für die Komprimierung von Dateien und das automatische Erstellen von JavaScript-Dokumentationen
Tools zum Einsatz kommen, die mit Hilfe von Node entwicklet wurden.
 
Installieren Sie zunächst Node.js: <code>https://nodejs.org/en/</code>, Version 6.x. Diverse Versionen finden Sie unter https://nodejs.org/en/download/.
Achten Sie darauf, dass die Option „<code>Add to PATH</code>“ ausgewählt wurde.


Starten Sie WebStorm neu und öffnen Sie das Terminal, um zu testen, ob <code>node</code> funktioniert:
Kopieren Sie nun aus Ihrer Lösung des vierten Teil des Tutoriums die Ordner <code>src</code> und <code>web</code>
(jeweils samt allen darin enthaltenen Ordnern und Dateien) sowie die Dateien <code>gruntfile.js</code>,  
<code>package.json</code>, <code>package-lock.json</code> und <code>webpack.config.js</code>
fügen Sie sie ins Wurzelverzeichnis des fünften Teils ein.


* Klick auf Icon in der linken unteren Ecke → <code>Terminal</code>
Weisen Sie WebStorm wiederum an, die Inhalte der Ordner <code>node_modules</code> und <code>web/js</code>
* Geben Sie Folgendes ins Terminal ein: <code>node --version</code>
nicht auf Syntaxfehler zu überprüfen. Gegebenenfalls müssen Sie auch wieder die Dateien <code>gruntfile.js</code>
... <code>webpack.config.js</code> unter die Versionsverwaltung von SVN stellen (<code>Add to VCS</code>).


Wenn Node.js korrekt installiert und der Pfad mit den <code>node</code>-Binaries in die Systemvariable <code>PATH</code> eingetragen wurde,
Ändern Sie in den Dateien <code>package.json</code> und <code>web/index.html</code> die Versionsnummern,
sollte die Versionsnummer von <code>node</code> ausgegeben werden.
die Beschreibung und gegebenenfalls den Pfad zum Repository Ihres Projektes.


Sie werden feststellen, das Node.js zum Großteil über Terminal-Befehle gesteuert wird.
Zu guter Letzt öffnen Sie das WebStorm-Terminal und führen den Befehl <code>npm install</code>aus.
Zu Beginn mag das für eingefleischte [[Klickibunti]]-Fans ungewohnt sein, aber Sie werden sich schnell daran gewöhnen.
Damit werden dieselben Node.js-Pakete installiert wie im vierten Teil des Tutoriums.


'''Tipp'''<br/>
Löschen Sie die Datei <code>web/js/app.bundle.js</code> und
Profis verwenden unter Windows lieber ein Terminal, das eine [[Unix]]-[[Shell]] simuliert.
rufen Sie anschließend <code>grunt</code> auf, um diese Datei erneut zu erzeugen.
(Unter Linux und Mac OS X ist das nicht notwendig. Dort läuft sowieso schon eine UNIX-Shell.)
Wenn Sie jetzt die Datei <code>index.html</code> im Browser öffnen, sollte die
 
Web-Anwendung so wie in Teil 4 der Aufgabe funktionieren.
Installieren Sie  „Git for Windows“ (https://git-for-windows.github.io/). In diesem Paket ist die „Git BASH“ enthalten.
Das ist eine Terminal-Anwendung, die eine Linux-Bash emuliert und zahlreiche nützliche Befehle wie „<code>which</code>, <code>[[vi]]</code>“ ( :-) ) etc. zur
Verfügung stellt.
 
Öffnen Sie nun ein beliebiges Terminal (WebStorm-Terminal, Git Bash, Mac-OS-X-Terminal ...)
und geben Sie folgenden Befehl ein (npm = node package manager, https://www.npmjs.com/)


==Verfeinerung der Webpack-Umgebung==
Zunächst benötigen Sie ein paar weitere Node.js-Module
<source lang="bash">
<source lang="bash">
npm install -g bower grunt-cli jsdoc yuglify mincss coffee-script jshint
npm install --save-dev es6-autobind
npm install --save-dev node-sass sass-loader extract-text-webpack-plugin
</source>
</source>


Damit werden die wichtigsten Node.js-Pakete ''global'' (Option „<code>-g</code>“) installiert, die wir im Folgenden noch benötigen.  
Im vierten Teil des Tutoriums wurde die Datei <code>initial.css</code> nicht von Webpack verwaltet,
Die globale Installation hat zur Folge, dass jedes Projekt auf diese Pakete zugreifen kann, Pakete also nicht mehrfach installiert werden müssen.
sondern direkt in das Verzeichnis <code>web/css</code> eingefügt. Damit liegt auch die
Verantwortung für die Komprimierung dieser Datei beim Programmierer. Das soll sich ändern.
Sie erweitern die Webpack-Konfiguration so, dass künftig auch diese Datei unter der Kontrolle
von Webpack steht.  


Als nächstes initialisieren Sie den Node-Paket-Manager „<code>npm</code>“ (https://docs.npmjs.com/) sowie Grunt (http://gruntjs.com/) .
===SCSS===
Grunt ist '''der''' “JavaScript Task Runner”, also ein Programm, das Aufgaben (''tasks'') wie {{zB}} das Komprimieren von Programmdateien
durchführt.


Die Initialisierung erfolgt durch die Bereitstellung von zwei Dateien „<code>package.json</code>“
Anstelle von CSS-Dateien verwenden Sie künftig SCSS-Dateien. Das ist zunächst einmal nicht weiter schwer,
und „<code>gruntfile.json</code>“ im Root-Verzeichnis der Web-Anwendung. Eine initiale Version der <code>package.json</code> könnten Sie theoretisch mit
das jede CSS-Datei automatisch auch eine SCSS-Datei ist. Bei der Verwendung von CSS können Sie
<code>npm init</code> erstellen. Einfacher ist es jedoch, wenn Sie die beiden Dateien von Hand erstellen und folgenden Code einfügen:
allerdings das Prinzip  „[[Don't repeat yourself]]“ (DRY) nicht beachten. Sie müssen für verschiedene Elemente
ständig Informationen wiederholen (gewünschter Font, Hintergrundfarbe, Größenangaben etc.). Deshalb
gibt es mehrere Projekte wie {{zB}} [[LESS]] und [[Sass]] , die den CSS-Standard erweitern, um dieses Problem
zu vermeiden. Sass verwendet allerdings eine ganz andere Syntax als CSS. Allerdings
unterstützt das Sass-Projekt auch die Sprache SCSS, die CSS einfach um weitere syntaktische Elemente ergänzt.
Zum Beispiel kann man in SCSS Konstanten definieren:


'''<code>package.json</code>''' (https://docs.npmjs.com/files/package.json)
<source lang="CSS">
<source lang="bash">
$background-color: #C5EFFC;
{
  "name": "hello_world_04",
  "version": "1.0.0",
  "description": "Hello World tutorial",
  "main": "gruntfile.js",
  "directories": {
    "doc": "./doc"
  },
  "dependencies": {},
  "devDependencies": {
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "svn",
    "url": "https://glossar.hs-augsburg.de/kowa/tutorium/es5/hello_world/WK_HelloWorld05"
  },
  "author": "Wolfgang Kowarschick",
  "license": "CC-BY-NC-SA-4.0"
}
</source>
</source>


Anmerkung: Diese Datei wird durch <code>npm</code> automatisch erstellt und geändert. Daher ist das Layout (welches mir nicht gefällt) vorgegeben.
Und nun kann man in der CSS-Datei anstelle von  <code>#C5EFFC</code> stets  <code>&#36;background-color</code>
schreiben, um die Hintergrundfarbe von bestimmten Elementen zu definieren. Wenn man nun dieses Farbe ändern will,
muss das nicht mehr bei allen Elementen einzeln passieren. Es reicht, die Farbe in der Konstantendefinition abzuändern.
Der CSS-Code ist nun DRY.


Hier sollten Sie natürlich nicht meinen Repositorypfad und meinen Namen einfügen, sondern jeweils Ihren. Sie können außerdem die
Leider unterstützt kein Browser SCSS direkt. Aber für was gibt es Transpiler wie Webpack, die eine SCSS-Datei
Lizenz, unter die Sie Ihre Software stellen, anpassen (https://spdx.org/licenses/), wenn Sie das möchten.
automatisch in eine CSS-Datei übersetzen können.


Die meisten Attribute sind selbsterklärend. Wichtig sind für uns vor allem zwei Attribute: „<code>main</code>“ und
Ersetzen Sie in Ihrem Projekt die Datei <code>src/css/main.css</code> durch
<code>devDependencies</code>. Das erste enthält den Namen der Konfigurationsdatei von Grunt. Diese fehlt noch. Also: Legen Sie sie an:
drei SCSS-Dateien: <code>_config.scss</code>, <code>initial.scss</code> und </code>app.scss</code>.


'''<code>gruntfile.js</code>'''
In der Datei <code>_config.scss</code> werden alle von den anderen SCSS-Dateien benötigten Konstanten definiert.
<source lang="javascript">
Das heißt, das Prinzip „Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien“ wird ab sofort beachtet.
module.exports = function(grunt)
Wenn man künftig am Layout einen Zeichensatz, eine Farbe, einen Hintergrund oder Ähnliches ändern will,
{
reicht es, die entsprechenden Konstanten anzupassen und schon erzeugt Webpack automatisch aktualisiere
  // Project configuration.
CSS-Dateien.
  grunt.initConfig
  ({
    pkg: grunt.file.readJSON('package.json'),
  });


  // Load the plugin that provides the "uglify" task.
Die Datei <code>initial.scss</code> enthält möglichst wenig Code. Das ist Vorlage für die Datei <code>initial.bundle.css</code>,
die im HTML-Head-Bereich geladen vor dem Body-Inhalt werden soll.
Die eigentlichen CSS-Informationen der Web-Anwendung werden in <code>app.scss</code> gespeichert. Die zugehörigen
CSS-Anweisungen werden von Webpack wie gehabt in <code>app.bundle.js</code> integriert.


  // Default task(s).
'''<code>src/css/_config.scss</code>'''
};
<source lang="CSS">
$font-family-sans:  Verdana, Helvetica, sans-serif;
$font-family-serif: "Times New Roman", Times, serif;
$background-color:  #C5EFFC;
</source>
</source>


Diese Datei ist noch ziemlich leer, aber das wird sich ändern.
Diese Datei kann nun mit Hilfe des SCSS-Befehls <code>@import</code>
in die anderen beiden  SCSS-Dateien eingefügt werden. Webpack (genauer gesagt das SASS-Modul von Webpack)
kennt diesen Befehl und führt im beim Erstellen der zugehörigen CSS-Dateien auch aus.


Vorausschauend sollten Sie eine überflüssige WebStorm-Fehlerprüfung deaktivieren, da anderenfalls künftige Versionen
Der Import-Befehl ist hier notwendig, da in der Datei <code>initial.scss</code> die Konstante <code>&#36;background-color</code>
Versionen der Datei <code>gruntfile.js</code>“ jedes Mal eine Fehlermeldung zur Folge haben, wenn die
verwendet wird. Ansonsten enthält dies Datei nur den schon bekannten CSS-Code.
Datei ins SVN-Repository geschrieben werden soll:


* <code>File</code> bzw. <code>WebStorm</code> → <code>Settings</code> bzw. <code>Preferences</code>  → <code>Editor</code> → <code>Inspections</code>
'''<code>src/css/initial.scss</code>'''
* <code>JavaScript</code> aufklappen → <code>General</code> aufklappen → <code>Unsued JavaScript / ActionScript global symbol</code> deselektieren
<source lang="CSS">
* <code>OK</code>
@import 'config';


Spannender ist in der Datei „<code>package.json</code>“ das Attribut „<code>devDependencies</code>“ (dev = developer).
body
Diese enthält eine Liste von von NodeJS-Paketen, die für die Entwicklung der Web-Anwendung benötigt werden.
{ background-color: $background-color;
Fügen wir einmal das Paket „<code>ink-docstrap</code>“ in diese Liste ein.
}
(Diese Pakte wird nachfolgend für die Erstellung der JavaScript-Dokumentation mittels JSDoc verwendet.
Es enthält ein Theme, welches deutlich schöner ist als das Standard-JSDoc-Theme.)


Führen Sie folgenden Befehl im WebStorm-Terminal (oder mittels eine beliebigen anderen Shell im Wurzelverzeichnis Ihrer Web-Anwendung) aus:
.hidden
{ display: none;
}
</source>


<source lang="bash">
Die Datei <code>app.scss</code> ist deutlich umfangreicher. Daher soll der zugehörige CSS-Code
npm install ink-docstrap --save-dev
ja auch erst gemeinsam mit der Datei  <code>app.bundle.js</code> geladen werden. Das meiste ist üblicher
</source>
CSS-Code, den Sie schon im vierten Teil des Tutoriums kennengelernt haben. Es gibt ein paar neue
Elemente, wie die CSS-Klassen-Elemente <code>.left</code> und <code>.right</code>, die in der HTML-Datei dieses
Tutoriums zusätzlich verwendet werden. Außerdem sehen Sie in der Datei noch ein  paar weitere SCSS-Elemente. Diese werden
im Anschluss an den folgenden code beschrieben.


Dies bewirkt zweierlei:
'''<code>src/css/app.scss</code>'''
<source lang="CSS">
@import 'config';


# Das Node.js-Paket „<code> ink-docstrap</code>“ sowie diverse weitere Node.js-Pakete, die diese Paket benötigt, werden einem Projektordner namens „<code>node_modules</code>“ abgelegt.
html, body
# Das Name und die Versionsnummer des Paketes werden in das Attribut „<code>devDependencies</code>“ in der  Datei „<code>package.json</code>“ eingefügt (wegen der Option „<code>--save-dev</code>“).
{ height:          100%;
  font-size:        2vw !important;
  font-family:      $font-family-sans;
  background-color: $background-color;
}


Nun steht Ihnen der Befehl
html
<source lang="bash">
{ display: table;
npm update
  width:   100%;
</source>
}
zur Verfügung. Mit diesem können Sie die lokal gespeicherte Versionen der im Attribut „<code>devDependencies</code>“ aufgeführte Node.js-Pakete
jederzeit auf die neueste Version aktualisieren. Sie können ein Paket auch löschen und dann mittels <code>npm update</code> (https://docs.npmjs.com/cli/update) wieder herstellen.
Versuchen Sie es:


<source lang="bash">
body
npm remove ink-docstrap
{ display:          table-cell;
npm list
  text-align:      center;
</source>
  vertical-align:  middle;
}


Jetzt ist der Ordner „<code>node_modules</code>“ wieder leer.
h1
{ padding-bottom: 0;
  margin-bottom: 0;
}


<source lang="bash">
#section_form
npm update
{ text-align:  center;
npm list
  width:        21em;
</source>
  margin-left:  auto;
  margin-right: auto;


Und jetzt enthält der wieder „<code>ink-docstrap</code>“ sowie andere dafür notwendige Pakete.
  h1
  { font-size:    200%;
    margin-bottom: 0.5ex;
  }
}


Sie können auch überprüfen, ob Sie in Ihrem Projekt irgendwelche veralteten Pakete benutzen (https://docs.npmjs.com/cli/outdated):
#section_hello
<source lang="bash">
{ h1
npm outdated
  { font-size: 270%;
</source>
  }
}


Kein Ergebnis ist hier ein gutes Ergebnis!
p, label
{ font-family: $font-family-serif;
  font-size:  100%;
}


Und natürlich funktioniert das Ganze auch für global gespeicherte Pakete:
label, input, button
{ width:         10em;
  font-size:    100%;
  display:      inline-block;
  box-sizing:    border-box;
  margin-bottom: 0.5ex;
}


<source lang="bash">
label
npm -g outdated
{ text-align: right;
npm -g list
}
</source>


Allerdings muss man veraltete globale Pakete erneut installieren. Zum Beispiel muss <code>npm</code>
@mixin panel()
relativ häufig aktualisiert werden (sobald  „<code>npm -g outdated</code>“ das Paket als veraltet meldet):
{ padding: 0;
  width:  50%;
}


<source lang="bash">
.left
npm install -g npm
{ float: left;
  @include panel();
}
.right
{ float: right;
  @include panel();
}
</source>
</source>


==Ausschließen diverser Dateien von automatischer Speicherung und/oder Überprüfung==
In diese SCSS-Datei werden folgende SCSS-Erweiterungen verwendet:


Sie sollten unbedingt verhindern das Node.js-Modulateien ins Repository geschrieben werden. Da sit, wie Se zuvor gesehen haben,  
* Import-Befehl: <code>@import 'config';</code>
überflüssig und nimmt '''sehr viel''' Zeit in Anspruch, da es sich um Hunderte von Dateien handelt:
* Konstanten:  <code>&#36;font-family-sans</code>, <code>&#36;font-family-serif</code>, <code>&#36;background-color</code>
* Verschachtelte Anweisungen: {{zB}} <code>h1</code> innerhalb von  <code>#section_form</code>
* Mixins, um eine Liste von Attributen nur einmal zu definieren und und mehreren Elemente wieder verwenden zu können.


* Rechtsklick im Dateibaum auf <code>node_modules</code>  → <code>Subversion</code> → <code>Ignore</code> → <code>node_modules</code>
Die verschachtelten Anweisungen strukturieren den CSS-Code deutlich besser. Es ist nicht mehr
* Sollte der vorangegangene Schritt schief gegangen sein (WebStorms Subversion-Tools sind in dieser Hinsicht ziemlich schlecht), müssen Sie den letzten Schritt gegebenenfalls mit einem anderen Tool bewerkstelligen. Unter Windows ist Tortoise dafür recht gut geeignet.
notwendig einen Selektor wie <code>#section_form</code> mehrfach zu verwenden.


Außerdem sollten Sie die automatische Überprüfung auf Fehler für alle Ordner ausschalten, die nicht von Ihnen stammen:
Sehen Sie sich den Unterschied an. In der Datei <code>main.css</code> vom vierten Teil des Tutoriums hatten Sie
folgendes geschrieben:


* Rechtsklick im Dateibaum auf  „<code>node_modules</code>“ → <code>Mark Directory as</code> → <code>excluded</code>
<source lang="CSS">
* Rechtsklick im Dateibaum auf „<code>doc</code>“ → <code>Mark Directory as</code> → <code>excluded</code>
#section_form
{
  text-align:  center;
  width:        21em;
  margin-left: auto;
  margin-right: auto;
}


Beide Ordner enthalten Dateien, die nicht von Ihnen stammen. Diese Dateien können Fehler und Hinweise enthalten,
#section_form > h1
veraltete (“deprecated”) Schnittstellen verwenden etc. (Oh ja, auch andere Programmierer machen Fehler. :-) )
{
Und wenn Sie diese beiden Ordner nicht als „<code>excluded markieren</code>“, prüft WebStorm bei jedem Commit die
  font-size:     200%;
darin enthaltenen Dateien und weist Sie auf jedes Problem hin. Das können so viele Probleme sein, dass Sie die
  margin-bottom: 0.5ex;
Probleme in Ihren eigenen Dateien vollkommen übersehen.
}
</source>


==Automatische Generierung der Schnittstellenbeschreibung==
Die SCSS-Variante ist deutlich strukturierter und prägnanter.


Installieren Sie zunächst JSDoc:
<source lang="CSS">
#section_form
{ text-align:   center;
  width:        21em;
  margin-left:  auto;
  margin-right: auto;


* Öffnen Sie das WebStorm-Terminal.
  h1
* <code>npm install -g jsdoc</code> (installiert JSDoc als Node.js-Anwendung; das haben Sie eigentlich schon gemacht, aber das macht nix :-) )
  { font-size:    200%;
* <code>npm install ink-docstrap</code> (installiert ein JSDoc-Theme namens „<code>docstrap</code>“ ([https://docstrap.github.io/docstrap/]); das haben Sie auch schon gemacht, aber das macht auch nix.)
    margin-bottom: 0.5ex;
  }
}
</source>


Übrigens: Es gibt auch noch andere Themes für JSDoc.
Insbesondere bei großen CSS-Dateien erweist sich diese kompaktere Schreibweise als vorteilhaft.


Erstellen Sie im Projektordner  „<code>conf</code>“ eine JSON-Datei namens „<code>jsdoc.json</code>“.
Ein weiteres Element, das nur SCSS bietet sind die Mixins. Sie definieren zunächst ein Mixin,
Fügen Sie in diese Datei folgenden Code ein:
das eine Folge von CSS-Attributen zusammenfasst. (Auch hier könnten wieder Verschachtelungen und
andere SCSS-Erweiterungen verwendet werden!)


<source lang="javascript">
<source lang="CSS">
{
@mixin panel()
  "tags":
{ padding: 0;
  {
   width50%;
    "allowUnknownTags": true
  },
  "source":
  {
    "include":        ["./src/js"],
    "includePattern": ".+\\.js$",
    "excludePattern": "doc"
  },
  "plugins":
  [],
  "templates":
  {
    "systemName":      "WK_HelloWorld04",
    "footer":          "",
    "copyright":      "Copyright © 2016 by Wolfgang Kowarschick, License <a href=\"https://creativecommons.org/licenses/by-nc-sa/4.0/\">CC-BY-NC-SA-4.0</a>",
    "navType":        "vertical",
    "theme":          "cerulean",
    "linenums":        true,
    "cleverLinks":    false,
    "monospaceLinks":  true,
    "collapseSymbols": true,
    "inverseNav":      false
  },
  "opts":
   {
    "template":    "node_modules/ink-docstrap/template",
    "encoding":    "utf8",
    "destination": "doc/jsdoc",
    "recurse":     true,
    "private":    true
   }
}
}
</source>  
</source>


Ersetzen Sie im Attribut „<code>copyright</code>“ meinen Namen durch Ihren, denn es ist Ihr Projekt, nicht meines. :-)
Und nun können Sie dieses Mixin in diversen andere Elemente einbinden:


In dieser Datei wird festgelegt, wie die HTML-Dokumentation des Codes, die JSDoc erstellt, aussehen soll.
<source lang="CSS">
Insbesondere ist das Template angegeben, das zur Erstellung dieser HTML-Dokumente verwendet werden soll.
.left
Es handelt sich um „<code>docstrap</code>“, welches wir zuvor heruntergeladen haben. Von der
{ float: left;
Projektroot aus gesehen, befinden sich die Template-Dateien im Ordner
  @include panel();
„<code>node_modules/ink-docstrap/template</code>“.


Weitere Konfigurationsparameter werden unter http://usejsdoc.org/about-configuring-jsdoc.html beschrieben.
.right
{ float: right;
  @include panel();
}
</source>


Sie können nun eine Dokumentation für Ihr Projekt erstellen:
In normalen CSS-Code, müssten Sie denselben Code Non-DRY formulieren:


* Öffnen Sie das WebStorm-Terminal.
<source lang="CSS">
* <code>jsdoc -c conf/jsdoc.json</code>
.left
{ float:  left;
  padding: 0;
  width:  50%;
}


Nach kurzer Zeit sollte der Ordner „<code>doc/jsdoc</code>“ erstellt und mit Inhalten gefüllt worden sein.
.right
Sehen Sie sich die Datei „<code>doc/jsdoc/index.html</code>“ im Browser an. Diese enthält nicht viel,
{ float:  right;
außer einem Drop-Down-Menü „<code>global</code>“, in dem die drei von Ihnen erstellen globalen Funktionen
  padding: 0;
„<code>sayHello</code>“, „<code>sayHelloOnEnter</code>“ und „<code>init</code>“ enthalten sind.
  width:  50%;
Klicken Sie auf eine dieser Funktionen.
}
</source>


===Vermeidung globaler Funktionen===
Wenn Sie hier das Layout der Panels ändern wollten (andere Breite, andere Ränder etc.), müssen
Sie den CSS-Code von jedem Panel einzeln ändern. In der SCSS-Datei erfolgt die Änderung dagegen DRY: Sie ändern einfach den Mixin-Code ab. 


Die Verwendung von globalen Variablen oder Funktionen in JavaScript ist extrem gefährlich.
Wenn die aktuellen Browser SCSS verstehen würden, könnte sie <code>initial.scss</code> und <code>app.scss</code> direkt
Wenn man eine JavaScript-Datei verwendet, in der
vom HTML-Code aus laden. Allerdings geht das derzeit leider nicht. Somit muss Webpack angewiesen werden, CSS-Code aus den
globale Funktionen enthalten sind, die zufälligerweise genauso heißen, wie
SCSS-Dateien zu erzeugen. Dies ist mit den beiden Node.js-Modulen <code>node-sass</code> und <code>sass-loader</code>,
globale Funktionen in der eigenen JavaScript-Datei, kann man nicht beide
die Sie bereits installiert haben, ganz einfach möglich.
Dateien laden, da globale Funktionen, die in der ersten Datei enthalten sind,
durch globale Funktionen der zweiten Datei überschrieben werden.  


Daher ist es besser, Funktionen wie „<code>sayHello</code>“, „<code>sayHelloOnEnter</code>“ und „<code>init</code>“
Ersetzen Sie in der Datei <code>webpack.config.js</code> folgenden Code
in ein JavaScript-Objekt einzufügen. In unseren Fall könnte man beispielsweise ein
JavaScript-Objekt „<code>main</code>“ erzeugen, dass diese drei Funktionen enthält.
Damit hat man nur noch eine globale Variable (<code>main</code>) und die Gefahr
einer zufälligen Namenskollision bei Verwendung mehrerer JavaScript-Dateien ist geringer.


Am besten ist es natürlich, auf globale Größen ganz zu verzichten. Dazu braucht man aber ein
<source lang="javascript">
Modul-System. Dieses ist für [[EcmaScript 6]] geplant ([https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import
{ test:   /\.css$/,
<code>import</code>] und [https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/export <code>export</code>]), wird
  use:    [ 'style-loader',
aber derzeit nur von wenigen Browsern unterstützt.
            { loader: 'css-loader', options: { minimize: true } }
          ]
},
</source>


Erserten Sie den Code in Ihrer Datei „<code>main.js</code>“ durch folgenden Code:
durch folgenden:


<source lang="javascript">
<source lang="javascript">
/** @namespace main */
{ test:   /\.(css|scss|sass)$/,
var
   use:   [ 'style-loader',
main =
            { loader: 'css-loader', options: { minimize: true } },
{
            'sass-loader'
   /**
          ]
  * Welcomes the user of the web app by displaying a welcome message
}
  * that includes his name. The name is fetched from a text input field.
</source>
  */
   sayHello:
    function()
    {
      document.getElementById('text_hello').innerHTML =
        'Hello, ' + document.getElementById("input_name").value + '!';
      document.getElementById('section_form').classList.add('hidden');
      document.getElementById('section_welcome').classList.remove('hidden');
    },


  /**
Der Test wird so erweitert, dass diese Regel jetzt nicht nur für die Verarbeitung von Dateien mit der
  * An keyboard event observer. It tests whether the enter key has been pressed.
Endung <code>.css</code> zuständig ist, sondern auch für Dateien mit den Endungen
  * If so, the sayHello method is activated. Default reactions of the browser are
<code>.sass</code> und <code>.scss</code>.
  * disabled.
  * @param {KeyboardEvent} p_event - A standard JavaScript keyboard event object
  *  (https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent)
  */
  sayHelloOnEnter:
    function(p_event)
    {
      if (p_event.code === 'Enter' || p_event.keyCode === 13)
      {
        p_event.preventDefault();
        p_event.stopPropagation();
        main.sayHello();
      }
    },


  /**
Die Liste der zugehörigen Loader wird einfach um einen Loader erweitert:  <code>sass-loader</code>.
  * Initializes the web app.
Diese Liste wird von hinten nach vorne abgearbeitet. Das heißt, eine Datei wie beispielsweise <code>app.scss</code>
  * Is to be called when the web app has been loaded completely.
wird erst mit Hilfe des Sass-Loaders in eine CSS-Datei umgewandelt, diese wird mit Hilfe des CSS-Loaders komprimiert
  */
und das Ergebnis dieser Datei wird mit Hilfe des Style-Loaders in die zugehörige JavaScript-Ausgabedatei integriert.
  init:
    function()
    {
      document.getElementById('button_submit')
              .addEventListener('click', main.sayHello);


      window.addEventListener('keydown', main.sayHelloOnEnter);
Jetzt müssen nur noch die zugehörigen JavaScript-Dateien erstellt werden.
    }
};


// Call main.init, when you are ready with loading.
Im <code>entry</code>-Objekt der Datei <code>webpack.config.js</code> ist bereits die Datei <code>src/js/app.js</code>
window.addEventListener('load', main.init);
eingetragen. Für Sie wird von Webpack die Datei <code>web/js/app.bundle.js</code> erzeugt.
</source>


Mit dem JSDoc-Kommentar „<code>@namespace main</code>
Der Name der Zieldatei wurde im <code>output</code>-Objekt von <code>webpack.config.js</code> spezifiziert.
wird angezeigt, dass die globale Variable „<code>main</code>
'''Achtung:''' Überprüfen Sie, ob das <code>output</code>-Objekt folgendermaßen definiert wurde.
als „[[Namensraum]]“ fungiert. Das heißt, <code>main</code>
enthält diverse Funktionen und evtl. andere Elemente, die irgendeinen inneren
Zusammenhang haben.


Wen Sie jetzt JSDoc erneut ausführen, beschreibt Ihre Dokumentation keine globale
<source lang="javascript">
Funktionen mehr, sondern einen Namensraum „<code>main</code>“, der die
  output:
Funktionen „<code>sayHello</code>“, „<code>sayHelloOnEnter</code>“ und „<code>init</code>“
  { filename: 'js/[name].bundle.js',
enthält. Auf diese Funktionen kann mittels „<code>main.sayHello</code>“, „<code>main.sayHelloOnEnter</code>“
    path:    absolutePath('web')
und „<code>main.init</code>“ zugegriffen werden.
  }
</source>


===Erstellung der JSDoc-Dokumentation mittels Klickibunti===
Damit diese Zieldatei insbesondere den komprimierten Code der Datei <code>src/css/app.scss</code> enthält,
muss <code>src/js/app.js</code> leicht modifiziert werden.


Falls Sie die Dokumentation nicht immer über das Terminal erstellen möchten, können Sie
Ersetzen Sie in dieser Datei den Import-Befehl
in WebStorm einen neuen Menüeintrag erstellen, über den Sie die Erzeugung der HTML-Dokumentation starten können.


Sie müssen dazu den Pfad ermitteln, unter dem Ihre <code>jsdoc</code>-Datei zu finden ist.
<source lang="javascript">
Unter Unix (Mac OS X, Linux, FreeBSD ...) lautet der Befehl, den Sie in ein Terminal eingeben müssen:
import '../css/main.css';
<source lang="bash">
which jsdoc
</source>
</source>
Unter '''Windows''' funktioniert dieser Befehl nur in der '''Git BASH'''.
durch den Import-Befehl
Außerdem müssen Sie unter Windows den Bash-Pfad modifizieren, damit auch Windows etwas damit anfangen kann.
 
Bei mir gibt dieser Befehl Folgendes aus:
<source lang="javascript">
<source lang="bash">
import '../css/app.scss';
/c/Users/kowa/AppData/Roaming/npm/jsdoc
</source>
</source>
Um <code>jsdoc</code> in WebStorm aufrufen zu können, müssen Sie in diesem Pfad „<code>/c</code>“ durch
„<code>c:</code>“ und  „<code>jsdoc</code>“ durch „<code>jsdoc.cmd</code>“ ersetzen.
(Mac-User brauchen nichts zu ändern. :-) )


Erstellen Sie nun den neuen WebStorm-Menü-Eintrag:
Die Datei <code>web/css/main.css</code> gibt es ja nicht mehr; sie wurde durch
<code>web/css/app.scss</code> ersetzt.


* <code>File</code> → <code>Settings</code> → <code>Tools</code> → <code>External Tools</code>
Damit auch <code>web/css/initial.scss</code> durch webpack verwaltet wird, benötigen wir eine zweite
* Klick auf das Plus-Icon
JavaScript-Datei.
** <code>Name</code>: <code>JSDoc</code>
** <code>Group</code>: <code>Documentation</code>
** <code>Description</code>: <code>Generates JavaScript documentation</code>
** Hacken bei allen Optionen (<code>Options</code>)
** Hacken bei allen Show-in-Optionen (<code>Show i</code>) mit Ausnahme von „<code>Search results</code>“
* <code>Program</code>: <code>c:/Users/kowa/AppData/Roaming/npm/jsdoc.cmd</code> (hier kommt Ihr zuvor ermittelter Pfad hinein)
* <code>Parameters</code>: <code>-c $ProjectFileDir$/conf/jsdoc.json</code>
* <code>Working directory</code>: <code>$ProjectFileDir$</code>
* <code>OK</code>
* <code>OK</code>


Nun finden Sie an mehreren Stellen in WebStorm einen neuens Menüpunkt  <code>Documentation</code> mit einem Unterpunkt <code>JSDoc</code>:
'''src/js/initial.js'''
<source lang="javascript">
import '../css/initial.scss';
</source>


* Hauptmenü : <code>Tools</code> → <code>Documentation</code> → <code>JSDoc</code>
Sie sehen das richtig, die Datei <code>src/js/initial.js</code> enthält eine einzige Code-Zeile.
* Rechtsklick auf Datei im Projekt-Dateibaum → <code>Documentation</code> → <code>JSDoc</code>
Sie erinnern sich? Webpack dient eigentlich nur dazu JavaScript-Dateien zu packen. Also geben wir diesen
* Rechtsklick auf Datei im Editor-Tab-Menü → <code>Documentation</code> <code>JSDoc</code>
Tool eine JavaScript-Datei, die die gewünschte CSS-Datei einfach mittels eine ES6-Import-Befehls importiert (ES6 = EcmaScript 6).
Fügen Sie nun in das <code>entry</code>-Objekt der Datei <code>webpack.config.js</code> vor der Zeile


Wenn Sie auf einen dieser Unterpunkte  „<code>JSDoc</code>“ klicken, erhalten Sie entweder eine Fehlermeldung ( :-( ) oder es wird eine neue Dokumentation erstellt
<source lang="javascript">
({{dh}}, Sie haben alles richtig gemacht :-) ).
app: absolutePath('src/js/app.js')
</source>
folgende zweite Zeile ein:


Um sicher zu gehen und um nicht mehr verwendete Dokumentationsdateien wie „<code>doc/jsdoc/global.html</code>“ zu entfernen, sollten Sie den Ordner „<code>doc/jsdoc</code>“ gemeinsam mit seinem gesamten Inhalt löschen und <code>JSDoc</code> nochmals aufrufen.
<source lang="javascript">
initial: absolutePath('src/js/initial.js')
</source>


===Sicherung im Repository===
Beachten Sie, dass in einem JavaScript-Objekt die Attribute durch Kommas voneinander getrennt werden. Fügen Sie also
an passender Stelle auch noch ein Komma ein.


Bevor Sie weitermachen: Haben Sie Ihre aktuelle Version von <code>Hello World 04</code> schon im Repository gesichert?
Wenn Sie jetzt Grunt aufrufen, sollten zwei Dateien generiert werden: <code>web/js/app.bundle.js</code> und  <code>web/js/initial.bundle.js</code>.
 
Löschen Sie nun den Ordner <code>web/css</code> (die darin befindliche Datei <code>initial.css</code> wird nicht mehr benötigt)
und ersetzen Sie in der Datei <code>index.html</code> die Zeile


Bevor Sie die Projekt-Dateien per ''Commit'' ins Repository übertragen, sollten Sie überprüfen,
<source lang="html">
dass der Ordner „<code>node_modules</code>“ auf der sogenannten „Ignore List“ steht (und damit nicht
<link rel = "stylesheet" type = "text/css" href = "css/initial.css"/>
ins Repository eingespielt wird):
</source>


* <code>Files</code> bzw. <code>WebStorm</code> → <code>Settings</code> bzw. <code>Preferences</code> → <code>Ignored Files</code>
durch folgende Zeile:
* Wenn in dieser Liste der Ordner „<code>node_modules</code>“ nicht aufgeführt wird, fügen Sie ihn mittels des Plus-Icons ein.


Sie sollten allerdings den Ordner „<code>doc</code>“ zu Ihrem
<source lang="html">
Repository hinzufügen:
<script type = "text/javascript" src = "js/initial.bundle.js"></script>
</source>


* Klick auf „<code>doc</code>im Dateibaum → <code>Subversion</code> → <code>Add to VCS</code>
Wenn Sie jetzt die Datei <code>index.html</code> im Browser öffnen, sollte sie wieder genauso funktionieren wie zuvor.


Nun können Sie Ihr Projekt committen.
'''Anmerkung''': Die Datei <code>src/js/initial.js</code> könnte natürlich noch mehr machen, als einfach nur eine CSS-Datei zu laden.
Sie könnte beispielsweise eine kleine Animation einblenden (die berühmte Sanduhr, nur etwas moderner), die solange läuft, bis
die eigentliche Web-Anwendung, {{dh}}  <code>app.bundle.js</code> vollständig geladen wurde und die Animation wieder beendet.


==Automatische Komprimierung von CSS- und Javascript-Dateien==
===Erzeugen einer CSS-Datei===


Nun folgt die letzte Optimierung der Anwendung. Die von Ihnen erstellten CSS- und Javascript-Dateien
Zurzeit enthält die JavaScript-Datei <code>web/js/initial.bundle.js</code> nur eine komprimierte CSS-Datei und etwas Code,
enthalten viele Leerzeichen, Kommentare, „sprechende“ anstelle von kurzen Variablenbezeichnern etc.
um diesen in das HTML-Dokument einzufügen. Die Google-Suche bewertet HTML-Dateien, die sauberen CSS-Code {{iAllg}} enthalten,
Das ist für Sie und alle anderen Entwickler von Vorteil. Für die Übertragung der Daten zu einem
höher, als HTML-Datei, die nur JavaScript-Code enthalten. Daher wäre es in diesem Fall sinnvoll, die komprimierte
Client (Browser) bedeutet das nur unnötiges Datenvolumen. Gerade für mobile Tarife mit Volumenbegrenzung
CSS-Datei direkt in den HTML-Code einzubinden. Das ist aber gar nicht so einfach, da Webpack keine CSS-Dateien erstellt,
sollten so wenig Daten wie möglich übertragen werden.
sondern nur JavaScript-Dateien. Aber mit einem kleine Hack funktioniert das trotzdem.


Glücklicherweise gibt es Tools, die bestehende CSS- oder Javascript-Dateien komprimieren (meist sogar so, dass
Sie haben vor auch noch die Node.js-Module <code>extract-text-webpack-plugin</code>
sich die [[Semantik]] der Dateien nicht ändert; aber wie gesagt: Auch andere Programmierer machen hin und wieder Fehler).
installiert. Mit diesem Sie eine CSS-Datei aus einer JavaScript-Datei extrahieren.


Wir verwenden die Node.js-Tools „<code>cssmin</code>“ für CSS-Dateien (https://www.npmjs.com/package/cssmin) und
Ersetzen Sie zunächst in der Datei <code>webpack.config.js</code> den Test
<code>UglifyJS2</code>“ für JavaScript-Dateien (https://github.com/mishoo/UglifyJS2). Gesteuert werden diese  “minimizer”
<source lang="javascript">
oder  “minifier” mittels dem bereits installierten ''JavaScript Task Runner'' <code>grunt</code>“.
test:   /\.(css|scss|sass)$/,
</source>
durch
<source lang="javascript">
test:   /app\.(css|scss|sass)$/,
</source>


Die für das Minimieren mittels Grunt notwendige Pakete wurden ebenfalls bereits installiert:
Damit erreichen Sie dass diese Regel jetzt nur noch für Dateien funktioniert, die auf <code>app.css</code> oder
<code>app.scss</code> oder <code>app.sass</code> enden. Die Datei <code>src/css/app.scss</code> in die
Datei <code>src/js/app.bundle.js</code> integriert werden.


<source lang="bash">
Laden Sie zunächst die ExtractTextPlugin-Erweiterung, indem Sie in die Datei <code>webpack.config.js</code>
npm install grunt grunt-contrib-watch grunt-contrib-cssmin grunt-contrib-uglify --save-dev
folgende zweite Zeile einfügen:
<source lang="javascript">
const ExtractTextPlugin = require('extract-text-webpack-plugin');
</source>
</source>


Nun müssen die Aufgaben zu Komprimieren der JavaScript- und CSS-Dateien in die Konfigurationsdatei
Für die Datei <code>src/css/initial.scss</code> fügen Sie nun in die Liste mit den Regeln eine weitere Regel  ein (Komma nicht vergessen):
eingefügt werden (vgl. http://gruntjs.com/getting-started):
 
'''<code>gruntfile.js</code>'''
<source lang="javascript">
<source lang="javascript">
module.exports = function(grunt)
{ test:  /initial\.(css|scss|sass)$/,
{
   use:   ExtractTextPlugin.extract
   // Project configuration.
        ({fallback: "style-loader",
   grunt.initConfig
          use:      [{ loader: 'css-loader', options: { minimize: true } },
  ({
                      'sass-loader'
    pkg: grunt.file.readJSON('package.json'),
                    ]
        })
}
</source>


    cssmin:
Diese benutzt das zuvor erwähnte Plugin, um die komprimierte CSS-Datei aus der Datei <code>src/js/initial.bundle.js</code>
    { options: /* https://github.com/jakubpawlowicz/clean-css */
zu extrahieren. Das erledigt sie aber nur fast. Man muss dem Plugin noch mitteilen wohin Sie die CSS-Datei speichern soll.
      { roundingPrecision:  -1,
        keepSpecialComments: 1
      },
      minimize:
      { files:
        { 'web/css/main.css': ['src/css/terminal.css', 'src/css/main.css']
        }
      }
    },


    uglify:
Dazu müssen Sie die bislang leere Plugin-Liste am Ende der Datei
    { options: /* https://github.com/gruntjs/grunt-contrib-uglify */
      { mangle:          true,
        preserveComments: function(p_node, p_comment)
                          { return /@license/.test(p_comment.value); }
      },
      minimize:
      { files: { 'web/js/main.js': ['src/js/terminal.js', 'src/js/main.js']
              }
      }
    }
  });


  // Load the plugin that provides the "uglify" task.
<source lang="javascript">
  grunt.loadNpmTasks('grunt-contrib-uglify');
plugins:
  grunt.loadNpmTasks('grunt-contrib-cssmin');
[]
 
  // Default task(s).
  grunt.registerTask('default', ['uglify', 'cssmin']);
};
</source>
</source>


Die Funktion  „<code>grunt.initConfig</code>“ aufgerufen und es wird ihr ein [[JavaScript-Objekt]] übergeben.
mit Inhalt füllen:
Im Attribut „<code>pkg</code>“ wird grund der Inhalt der Datei  „<code>package.json</code>“ übergeben, damit Grunt ermitteln kann, welche Pakete verfügbar sind.
Die beiden anderen Attribute „<code>cssmin</code>“ und „<code>uglify</code>“ (deren Namen frei wählbar sind), werden die beiden Minifier konfiguriert.


In beiden Fällen können Optionen angegeben werden, wie {{zB}}, dass CSS-Maß-Angaben nicht gerundet werden sollen (es gibt Designer, die bestehen
<source lang="javascript">
beim Pixelmaß auf vier Nachkommastellen) oder dass geeignete JavaScript-Variablen-Namen „durch die Mangel gedreht“ (''mangle''), also durch kürze Namen ersetzt werden sollen.
plugins:
Wichtiger ist jedoch die Angabe, welche Dateien überhaupt erstellt werden und was für Sourcedaten dafür verwendet werden solle.
[ new ExtractTextPlugin("css/[name].bundle.css") ]
</source>


Zu jeder Datei, die erstellt wird, kann man eine ganze Liste von Sourcedateien angeben. Das hat zur Folge, dass alle  diese Sourcedateien nacheinander
Führen Sie nun <code>grunt</code> aus. Es sollte die Datei <code>web/css/initial.bundle.css</code>
komprimiert und dann in die Zieldatei eingefügt werden. Auch das ist eine Optimierung, um das Laden einer Web-Anwendung zu beschleunigen.
erzeugt worden sein.
Eine große Datei wird per HTTP schneller übertragen als viele kleine. Künftig werden wir daher möglichst wenige komprimierte Dateien verwenden
und möglichst viele nicht-komprimierte JavaScript-Dateien in komprimierter Form nacheinander in nur eine einzige JavaScript-Datei einfügen.


Nach der Initialisierungsfunktion werden noch zwei weitere Funktionen aufgerufen. Mit <code>grunt.loadNpmTasks</code>  
Nun müssen sie in der Datei <code>index.html</code> die Zeile
werden die Grunt-Plugins geladen, die die eigentliche Komprimierung vornehmen. Und mittels <code>grunt.loadNpmTasks</code>
wird festgelegt, welche Aufgaben standardmäßig ausgeführt werden, sobald der Befehl „<code>grunt</code>“ ausgeführt wird.


So, nun sollte alles funktionieren. Öffnen Sie das Web-Storm-Terminal und tippen Sie nacheinander folgende Befehle ein:
<source lang="html">
<script type = "text/javascript" src = "js/initial.bundle.js"></script>


<source lang="bash">
grunt cssmin
grunt uglify
grunt
</source>
</source>


Sie werden feststellen, das jedes mal bestimmte Dateien in den Ordnern „<code>web/css</code>“ oder/und „<code>web/js</code>
wieder durch eine CSS-Link-Zeile ersetzen (da ja in der Datei <code>initial.bundle.js</code> kein sinnvoller Inhalt mehr enthalten ist;
erstellt werden, die mit dem Namensbestandteil „<code>min</code>“ beginnen. Sehen Sie sich die erzeugten Dateien an.
sie wurde durch das Extract-Text-Plugin  „ausgelutscht“).
Sie enthalten denselben Code wie die Original-Dateien, nur in komprimierter (und daher für den Menschen schwer lesbarer) Form.


Als nächstes muss die Datei „<code>index.html</code>“ angepasst werden. Diese lädt noch die unkomprimierten Dateien aus dem
<source lang="html">
Sourceverzeichnis. Künftig soll sie die komprimierten Dateien aus dem eigentlichen Web-Ordner laden:
<link rel = "stylesheet" type = "text/css" href = "css/initial.bundle.css"/>
 
<source lang="html5">
...
<link rel="stylesheet" type="text/css" href="css/main.css"/>
...
<script type="text/javascript" src="js/main.js"></script>
</source>
</source>


Ab sofort werden nicht mehr die Sourcedateien geladen, sondern die komprimierten, durch die Minifier erstellten Dateien.
Sie könnten nun noch die überflüssige Datei <code>web/js/initial.bundle.js</code> von webpack wieder entfernen lassen.
Das heißt aber für uns, dass wir bei jeder Änderung an den Sourcedateien den Befehl „<code>grunt</code>
Wie das geht entnehmen Sie bitte der Seite https://stackoverflow.com/questions/37408873/delete-or-not-create-a-file-for-each-entry-in-webpack
ausführen müssen, um die Aktualisierungen in die komprimierten Versionen der JavaScript bzw. CSS-Dateien zu übertragen.
sowie der [https://glossar.hs-augsburg.de/beispiel/tutorium/es6/hello_world/WK_HelloWorld05/ Musterlösung]. Wichtig ist das nicht.
Wenn Sie später mal eine kleine Warteanimation erstellen sollten, bräuchten Sie dieses Datei sowieso wieder.


Das ist lästig und geht besser.
==JSON==


==Automatische Aktualisierung der komprimierten Dateien==
Bislang haben sie den CSS-Code unter Webpack-Kontrolle gestellt und damit DRY gemacht.
Als nächstes gehen wir das nächste Problem an: Ihr Code enthält ebenfalls Konstanten und verstößt damit gegen das
[[Programmierprinzipien|Programmierprinzip]] „Konstante Werte gehören nicht in den Code, sondern in Konfigurationsdateien.“


Mit Hilfe des Node.js-Paketes „<code>grunt-contrib-watch</code>“ kann man beliebige Dateibäume überwachen,
Eine Ausnahme bilden triviale Konstanten wie <code>0</code>, <code>1</code>, <code>null</code>, <code>true</code> oder <code>false</code>, sofern sie mit großer Sicherheit nie im Code geändert werden müssen. Aber schon eine Konstante wie
ob sich darin bestimmte Dateien ändern. In einem derartigen Fall kann man automatisch andere Grunt Tasks ausführen lassen.
<code>3.1415926</code> gehört nicht in den Code. Man verwendet stattdessen besser <code>Math.PI</code> und erhält damit
Das lässt sich ausnutzen, um nach Änderungen einer CSS-Datei oder einer JavaScript-Datei die zugehörige komprimierte
die maximal mögliche Stellenzahl. (Eventuell hängt diese von der Rechnerplattform ab.)
Datei automatisch neu zu erstellen.


Öffnen Sie das WebStorm-Terminal und laden Sie das besagte Paket:
In JavaScript-Anwendungen verwendet man [[JSON]] zur Speicherung von (konstanten) Daten und zur Initialisierung der Anwendung.
Wenn ein Spiel mehrere Level hat, wir jedes Level üblicherweise in einer eigenen JSON-Datei beschrieben. Eine Level-Designerin muss
im Optimalfall nicht mehr machen, als die Assets (Grafiken, Töne, 3D-Modell etc.) zu erstellen und mit Hilfe einer
JSON-Datei die Zusammenhänge zwischen den einzelnen Elementen herstellen. Es sollte nicht notwendig sein, dass sie
den Programmcode modifizieren muss, da das Level-Design schon aufwändig genug ist.


<source lang="bash">
JSON (JavaScript Object Notation) ist ein einfaches Datenformat, mit dessen Hilfe sich komplexe Objekte sehr einfach beschreiben lassen.
npm install grunt-contrib-watch --save-dev
Eine Alternative wäre [[XML]], allerdings ist diese Auszeichnungsprache deutlich komplexer. (Ein Beispiel für XML ist
</source>  
XHMLT 1.0<ref>XHTML 1.0: https://www.w3.org/TR/2002/REC-xhtml1-20020801/</ref>, eine HTML-Variante.)


Erweitern Sie nun die Datei „<code>gruntfile.js</code>“ um einen Watch-Task:
Eine JSON-Datei ist im Prinzip eine JavaScript-Datei, die einen der folgenden Datentypen enthält<ref>http://www.json.org/json-de.html</ref>:


<source lang="javascript">
* Nullwert (<code>null</code>)
watch:
* Boolescher Wert (<code>true</code> oder <code>false</code>)
{ css:
* Zahl (Ziffernfolge mit optionalem Vorzeichen und optionalen Exponenten)
  { files:  ['src/css/**/*.css'],
* Zeichenkette (beliebige UTF-8-Zeichen, die in doppelten geraden Anführungszeichen (<code>"</code>) eingeschlossen sind)
    tasks:  ['cssmin']
* Array (eine durch Kommata getrennte Listen von null oder mehr JSON-Elementen; die Liste beginnt mit <code>[</code> und endet mit <code>]</code>)
  },
* Objekt/Hasharray/Paarliste (eine durch Kommata getrennte Listen von null oder mehr Paaren; die Liste beginnt mit <code>{</code> und endet mit <code>}</code>; jedes Paar besteht aus einer Zeichenketten, die als Schlüssel fungiert, gefolgt von einem Doppelpunkt  (<code>:</code>) gefolgt von einem beliebigen JSON-Element; in einem Objekt darf derselbe Schlüsselwert nicht zweimal vorkommen)
  js:
  { files:  ['src/js/**/*.js'],
    tasks:  ['uglify']
  },
  web:
  { files:  ['web/**/*'],
    options: { livereload: true,
              spawn:     false
            }
  }
}
</source>  


Vergessen Sie nicht, das Plugin zu laden:
Beachten Sie, dass die eine [[Rekursion|rekursive]] Definition ist: Arrays dürfen andere Arrays und Objekte enthalten, Objekte dürfen
<source lang="javascript">
andere Objekte und Arrays enthalten. JSON-Elemente können also beliebig tief geschachtelt sein.
grunt.loadNpmTasks('grunt-contrib-watch');
</source>


Der Watch-Task überwacht drei verschiedene Ordner:
Andere Werte dürfen in einer JSON-Datei nicht enthalten sein. Das heißt, es gibt keine einfachen geraden Anführungszeichen (außer '''innerhalb''' von Zeichenketten), keine Kommentare, keine Funktionen etc. '''Insbesondere überflüssige Kommas sind nicht erlaubt!'''


* Wann immer sich eine CSS-Datei im Ordner „<code>src/css</code>“ oder einem darin enthaltenen Unterordner ändert, wird der Task  „<code>cssmin</code>“ ausgeführt.
Beachten Sie bitte, dass jeden JSON-Datei auch eine
* Wann immer sich eine JavaScript-Datei im Ordner „<code>src/js</code>“ oder einem darin enthaltenen Unterordner ändert, wird der Task  „<code>uglify</code>“ ausgeführt.
JavaScript-Datei ist (die Umkehrung dieser aussage gilt nicht.). Wenn man eine JSON-Datei auswerten würde, erhielte man jedoch kein anderes Ergebnis als den Wert oder das Objekt, das in der Datei gespeichert ist.
* Wann immer sich irgendeine Datei im Web-Ordner ändert, wird eine <code>livereload</code>-Nachricht (http://livereload.com/) an einen lokalen Node-Server mit der Portnummer 35729 geschickt. (Keine Angst: Sie brauchen diesen Server nicht zu starten oder zu stoppen.)


Damit kann man Browser anweisen, die HTML-Dateien neu zu laden, wann immer sich etwas ändert.
Erstellen Sie in Ihrem Projekt  folgende zwei JSON-Dateien:
Dies erfolgt entweder mit speziellen Browser-Plugins (http://livereload.com/extensions/) oder mit einem kleinen JavaScript-Hack:
Fügen Sie ans Ende der Datei „<code>main.js</code>“ folgenden Code ein:


'''src/json/config_de.json'''
<source lang="javascript">
<source lang="javascript">
// Enable live reloading for the WebStorm web server.
if (location.port === '63342')  // WebStorm server port
{
{
   var l_script = document.createElement('script');
   "text":
   l_script.src = 'http://'+(location.host||'localhost').split(':')[0]+':35729/livereload.js';
   {
   document.body.appendChild(l_script);
    "title":    "Hallo, Fremder!",
    "question": "Wie heißen Sie?",
    "reset":   "Reset",
    "submit":  "Begrüßung",
    "hello":    "Hallo, $1!",
    "welcome":  "Willkommen bei Multimedia-Programmierung!"
  },
 
  "css":
  {
    "hidden": "hidden"
   }
}
}
</source>
Dieser Code sorgt dafür, dass in eine HTML-Datei, die die Datei „<code>main.js</code>“ einbindet,
ein zusätzliches <code>script</code>-Element
<source lang="html5">
<script src="http://localhost:35729/livereload.js></script>
</source>
</source>
erstellt und in jede HTML-Datei eingefügt wird, die von einem WebStorm-Test-Server ausgeliefert wird.
(Der URI kann anstelle des Servernamens „<code>localhost</code>“ auf den echten Namen des Entwicklungsrechners enthalten, sofern
der Entwicklungsrechner einen derartigen Namen hat.)


Unter Port 35729 wird auf dem Entwicklungsrechner von <code>grunt-contrib-watch</code> der bereits erwähnte Livereload-Server gestartet und
'''src/json/config_en.json'''
die JavaScript-Datei „<code>livereload.js</code>“ zur Verfügung gestellt. Wenn man diese Datei in seine HTML-Datei einbindet,
<source lang="javascript">
aktualisiert sich die HTML-Datei fortan automatisch, sobald <code>grunt-contrib-watch</code> eine Änderung, wie {{zB}}
{
die Aktualisierung einer CSS-Datei, einer JavaScript-Datei, der HTML-Datei selbst oder einer anderen Datei, die von der HTML-Datei eingebunden wird,
  "text":
meldet.
  {
    "title":    "Hello, Stranger!",
    "question": "What's your name?",
    "reset":    "Reset",
    "submit":  "Say hello",
    "hello":    "Hello, $1!",
    "welcome":  "Welcome to Multimedia Programming!"
  },


Allerdings wäre es falsch, <code>livereload.js</code> auf einem Live-Server ohne Testumgebung einzubinden. Dort läuft der Livereload-Server überhaupt nicht.
  "css":
Daher wird zunächst ermittelt, über welchen Port die aktuelle HTML-Datei von Server ausgeliefert wurde.
  {
Üblicherweise ist dies 80, 443, 8080, 8888 oder 8443. Andere Ports werden selten verwendet.
    "hidden": "hidden"
Der Port 63342 wird mit fast absoluter Sicherheit nicht von irgendeinem realen Server verwendet. Daher verwendet ihn WebStorm.
  }
Und daher kann mit dem Test <code>if (location.port == 63342)</code> ermittelt werden, ob die aktuelle HTML-Datei von einem WebStorm-Server
}
ausgeliefert wurde oder von einem anderen Server. (Die globale JavaScript-Variable „<code>location</code>“ enthält den URI, über den die HTML-Datei
</source>
vom Browser geladen wurde.)


Nun ist es an der Zeit, den <code>grunt-contrib-watch</code> zu testen. Öffnen Sie „<code>index.html</code>“ im Browser
Importieren Sie die erste der beiden JSON-Dateien in Ihre Datei <code>src/js/app,js</code>,
(Rechtsklick auf <code>index.html</code> → <code>Run 'index.html'</code>) und tippen Sie dann
indem Sie folgenden Import-Befehl einfügen:
<source lang="bash">
<source lang="javascript">
grunt watch
import * as config from '../json/config_de.json';
</source>
</source>
ins WebStorm-Terminal.
Ändern Sie nun einen Eintrag in der Datei „<code>main.css</code>“ ({{zB}} <code>font-family: "Comic Sans MS";</code> :-) ).
Wenn Sie diese Änderungen speichern (Strg-S, Apfel-S), sollten Sie zweierlei Reaktionen bemerken.
Zum einem wird ins Terminal die Meldung
<source lang="bash">
>> File "web/css/main.css" changed.
</source>
geschrieben und zum anderen ändert sich das Layout der HTML-Datei im Browser, da die aktualisierte CSS-Datei
automatisch vom Browser nachgeladen wurde.


Wenn Sie die Designsünde „Comic Sans MS“ rückgängig machen, ändert sich die Datei kurz darauf auch im Browser wieder.
In <code>src/js/app/greet,js</code> fügen Sie folgenden
 
Import-Befehl ein:
Das ist schon ziemlich „cool“, hat aber noch einen Schönheitsfehler: Das WebStorm-Terminal kann nicht anderweitig genutzt werden, solange
<source lang="javascript">
der Grunt-Watcher läuft. Um dieses Problem zu beheben, wird ein WebStorm-Startup-Task definiert, der den Watcher bei jedem
import * as config from '../../json/config_de.json';
Programmstart von WebStorm automatisch in einem eigenständigen [[Task]] startet. Der Watcher läuft dann, solange WebStorm geöffnet ist.
Für seine Ausgaben steht im ein eigenes Ausgabefenster zur Verfügung. Was will man mehr?
 
* <code>File</code> → <code>Settings</code> → <code>Tools</code> → <code>Startup Tasks</code> → <code></code>
* Klick auf grünes Plus-Icon → <code>Add New Configuration</code> → <code>Grunt.js</code>
** Name: <code>Watch</code>
** Gruntfile: <code>.../HelloWorld04/gruntfile.js</code> (sollte bereits korrekt eingetragen sein)
** Tasks: <code>watch</code>
** Der Node-Interpreter und das Node.js-Paket <code>grunt-cli</code> sollten ebenfalls bereits korrekt eingetragen sein.
* <code>OK</code> (Unter „<code>Run configuration</code>“ sollte jetzt „<code>Watch</code>“ stehen.)
* <code>OK</code>
 
Wenn Sie nun WebStorm neu starten, sollte und der Menüzeile am unteren Fensterrand ein Tabulator mit dem Namen „<code>Run</code>“ vorhanden sein.
Wenn Sie das zugehörige Fenster öffnen sollte dort Folgendes stehen:
 
<source lang="bash">
grunt watch
Running "watch" task
Waiting...
</source>
</source>


Sobald Sie irgendeine Änderung an eine <code>web</code>- oder <code>src</code>-Datei der Web-App vornehmen, werden alle im Watcher definierten Aktionen
Beachten Sie, dass hier eine Zugriff auf das „Großvater“-Verzeichnis <code>src</code> mittel <code>../../</code> erfolgen muss.
(automatische Komprimierung bzw. Neuladen des HTML-Datei im Browser) automatisch ausgeführt. Der Watcher läuft solange, bis Sie WebStorm beenden.
Grundsätzlich sollten Sie in Import-Befehlen immer relative Pfadnamen angeben, da sonst eine Änderung der globalen Ordnerstruktur
Es erfolgt dabei sogar noch eine Sicherheitsabfrage, on Sie den Prozess „<code>Watch</code>“ beenden wollen.
zu massiven Problemen führen kann. Achten Sie bei Pfad-Angaben insbesondere auf Groß- und Kleinschreibung.
<!-- „<code></code>“ npm install grunt-contrib-watch --save-dev-->
Gemeinerweise macht es auf Windows-Rechnern keinen Unterschied, ob sie in einem Pfadnamen Groß- oder Kleinbuchstaben
verwenden. Wenn Sie die Anwendung später auf einen Linux-Server kopieren, kommt es dann allerdings zu Problemen,  
weil der Server die Pfade mit den falschen Groß- oder Kleinbuchstaben nicht mehr findet. Sie sollten in Dateinamen
am Besten überhaupt keine Großbuchstaben verwenden.


==JSHint==
Wenn Sie jetzt <code>grunt</code> aufrufen und anschließend <code>index.html</code> im Browser öffnen,
hat sich noch nicht viel getan.


Ein weiteres sehr interessantes Tool, das den JavaScript-Entwickler unterstützt, ist JSHint (http://jshint.com/).
Ändern Sie nun den Inhalt der <code>index.html</code>. Löschen Sie alle englischen Text-Elemente.
JSHint analysiert vorhandenen JavaScript-Code und weist auf Fehler und Strukturprobleme hin.
sie sollten sie durch die angegebenen Dummy-Texte ersetzen, notwendig wäre das aber nicht:


Installieren Sie zunächst die zugehörigen Node.js-Pakete:
* <code>Hello, Stranger!</code> → <code>TITLE</code>
* <code>What's your name?</code> → <code>QUESTION</code>
* <code>Reset</code> → <code>RESET</code>
* <code>Say hello</code> → <code>SUBMIT</code>
* <code>Hello, ...</code> → <code>HELLO</code>
* <code>Welcome to Multimedia Programming!</code> → <code>WELCOME</code>


<source lang="bash">
Sie müssen außerdem noch einigen HTML-Tags zusätzlich ein <code>id</code>-Attribut zuordnen:
npm install grunt-contrib-jshint jshint-stylish --save-dev
</source>


Anschließend fügen Sie einen JSHit-Task in die Datei „<code>gruntfile.js</code>“ ein.
* H1-Element: <code>&lt;h1 id="heading_form"&gt;</code>
* Label-Element: <code>&lt;label id="input_label" ..&gt;</code>
* Reset-Button:  <code>&lt;input id="button_reset" type="reset" ...&gt;</code>
* Welcome-Paragraph: <code>&lt;p id="paragraph_hello">WELCOME&lt;/p&gt;</code>


<source lang="javascript">
Wenn Sie jetzt die <code>index.html</code> nochmals im Browser öffnen, sehen Sie nur noch die DUMMY-Texte.
jshint:
{
  all: ['gruntfile.js', 'src/**/*.js'],


  options:
Das ändert sich allerdings, wenn Sie folgende JavaScript-Befehle in die Datei <code>src/js/app.js</code> nach den
  {
Import-Befehlen einfügen:
    esversion: 5,
    eqeqeq:    true,
    eqnull:    true,
    browser:  true,
    reporter:  require('jshint-stylish')
  }
}
</source>


<source lang="javascript">
const c_config_text = config.text;


Nun können alle vom Entwickler erstellten JavaScript-Dateien analysiert werden. Geben Sie dazu im
// Initialize the app.
WebStorm-Terminal einfach folgenden Befehl ein:
document.getElementById('button_reset').value
  = c_config_text.reset;
document.getElementById('button_submit').value
  = c_config_text.submit;


<source lang="bash">
document.getElementById('heading_form').innerHTML
grunt jshint
  = c_config_text.title;
document.getElementById('input_label').innerHTML
  = c_config_text.question;
</source>
</source>


Gut ist es, wenn JSHint mit der Meldung <code>v No problems</code> antwortet.
(Die restlichen Zeilen bleiben erhalten.)  Mit diesen fünf Befehlen speichern Sie den Inhalt des Attributs
Ansonsten sollten Sie in Ihrem Code die von JSHint gemeldeten Probleme beheben.
<code>text</code> aus der eingelesenen JSON-Datei in der Konstanten
<code>c_config_text</code>. Anschließend ersetzen Sie mit Hilfe von vier weiteren Befehle
die Dummy-Texte im der Form-Section durch sinnvolle Texte.


Machen Sie ruhig mal die Probe auf's Exempel: Ersetzen Sie
Rufen Sie <code>grunt</code> auf und öffnen Sie anschließend <code>index.html</code> im Browser.
in der Datei „<code>main.js</code>“ „<code>=</code><code>==</code>“ durch „<code>==</code>“ und lassen Sie
Jetzt sollten Sie deutsche Text an Stelle von Dummy-Texten sehen. Wenn Sie jetzt allerdings einen Namen eingeben
danach JSHint laufen. Dann sollte JSHint Folgendes melden:
und auf den Begrüßungs-Button klicken, werden Sie englisch begrüßt und sehen einen weiteren Dummy-Text.


<source lang="bash">
Das heißt, Sie müssen auch noch die Datei <code>src/js/app/greet.js</code> erweitern.
Expected '===' and instead saw '=='.
</source>


Damit wird ausgedrückt, dass ein nicht-strikter Gleichheitstest verwendet wurde,
Ersetzen Sie in dieser Datei im Rumpf der Funktion <code>sayHello</code>
aber ein strikter Gleichheitstest verwendet werden sollte. Der Grund ist, dass
den darin enthalten Code durch folgenden Code:
nicht-strikte Fehlertests manchmal subtile Fehler zur Folge haben, die
nur sehr schwer zu entdecken sind.


JSHint kennt zahlreiche Optionen, die festlegen, welche Fehler und Probleme gemeldet
werden sollen und welche nicht: http://jshint.com/docs/options/.
Hier muss jeder Programmierer seinen eigenen Stil finden.
Folgende Optionen wurden im obigen Beispiel verwendet:
<dl>
</dt><code>esversion: 5</code></dt>
<dd>Des sollen die Regeln von [[EcmaScript 5]] beachtet werden.</dd>
</dt><code>eqeqeq: true</code></dt>
<dd>Es sollt stets ein strikter Gleichheitstest verwendet werden.</dd>
</dt><code>eqnull</code></dt>
<dd>Der nicht-strikte Gleichheitstest <code>... == null</code> ist allerdings erlaubt.
</dd>
</dt><code>browser: true</code></dt>
<dd>Globale Variable sollte man eigentlich grundsätzlich nicht verwenden.
Mit dieser Option werden für die globalen Variablen, die die Browser bereitgestellt werden
(<code>document</code>, <code>window</code>, <code>console</code> etc) Ausnahmen definiert.</dd>
</dl>
'''Anmerkung''': Wäre der nicht-strikte Gleichheitstest auf „<code>null</code>“ nicht erlaubt, müsste man
in viele Fällen „
<source lang="javascript">
<source lang="javascript">
if (... === null || ...=== undefined)
const l_config_text = config.text,
</source>
      l_name      = document.getElementById("input_name").value;
schreiben. Geben Sie folgende Befehle einfach mal in die Konsole Ihres Web-Browsers ein
(Firefox: <code>Strg-Shift-K</code>, Opera und Chrome: <code>Strg-Shift-I</code> → <code>Console</code>):


<source lang="javascript">
document.getElementById('paragraph_hello').innerHTML
var a;
  = l_config_text.welcome;
var b = null;
document.getElementById('heading_hello').innerHTML
  = l_config_text.hello.replace('$1', l_name);


// Strikte Gleichheitstests
document.getElementById('section_hello')
console.log(a === null);                    /* -> false */
  .classList.remove('hidden');
console.log(a === undefined);                /* -> true  */
document.getElementById('section_form')
console.log(b === null);                     /* -> true  */
  .classList.add('hidden');
console.log(b === undefined);                /* -> false */
console.log(a === null || a === undefined);  /* -> true  */
console.log(b === null || b === undefined);  /* -> true  */
 
// Nicht-strikte Gleichheitstests
console.log(a == null);                      /* -> true  */
console.log(a == undefined);                /* -> true  */
console.log(b == null);                      /* -> true  */
console.log(b == undefined);                 /* -> true  */
</source>
</source>


Zum Abschluss können Sie entweder einen WebStorm-Menü-Eintrag hinzufügen, um den JSHint jederzeit per Klickibunti starten zu können.
Die Funktion <code>sayHelloOnEnter</code> ändert sich dagegen nicht.
Oder Sie fügen gleich „<code>jslint</code>“ in die Watch-Liste ein, damit jede Änderung sofort analysiert und Fehler sofort angezeigt werden:


'''<code>gruntfile.js</code>'''
Nun sollte (nach einen <code>grunt</code>-Lauf) die Web-App wie gewünscht funktionieren.
<source lang="javascript">
watch:
{ ...
  js:
  { files:  ['src/js/**/*.js'],
    tasks:  ['uglify', 'jshint']
  },
  ...
}
</source>


Allerdings kann JSHint manchmal nerven. :-) Dagegen helfen dann spezielle Kommentare im JavaScript-Code, die
Sie können jetzt testweise mal in beiden Dateien <code>app.js</code> und <code>greet.js</code>
JSHint anweisen für die Prüfung des nachfolgenden Codes spezielle Optionen zu benutzen, die dann {{iAllg}}
die englischsprachige JSON-Datei landen, <code>grunt</code> laufen lassen und <code>index.html</code> öffnen.
eine etwas weniger strenge Überprüfung des Codes zur Folge haben (http://jshint.com/docs/).
Dann sollten Sie auf Englisch begrüßt werden. Das ist schon nicht schlecht, aber richtig DRY ist das noch nicht.
Sie müssen den Namen der JSON-Datei in '''zwei''' Dateien ändern. Also braucht es noch eine sechstes und letztes Hello-World-Tutorium ...


==Quellen==
==Quellen==

Version vom 3. November 2017, 16:06 Uhr

Dieser Artikel wird derzeit von einem Autor gründlich bearbeitet. Die Inhalte sind daher evtl. noch inkonsistent.

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 4
(unwichtige Fakten fehlen)
Quellenangaben: 3
(wichtige Quellen vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 3
(gut)

Vorlesung WebProg

Inhalt | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Vue 1 | Vue 2 | Vue 3 | Vue 4 | Vue 5 | Vue 6

Musterlösung: index.html, (SVN-Repository)

Anwendungsfälle (Use Cases)

Gegenüber dem vierten Teil des Tutoriums ändern sich die die Anwendungsfälle nicht.

In diesem und im nächsten Teil des Tutoriums werden zwei wesentliche Grundprinzipien der Programmierung thematisiert:

  • Don't repeat yourself (DRY, “Keep your code DRY!”).
  • Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien.

Erstellen eines neuen Projektes

Erzeugen Sie wie im vierten Teil des Tutoriums ein neues Projekt, diesmal allerdings mit dem schönen Namen HelloWorld05“ und speichern Sie dieses wieder in Ihrem SVN-Repository (Achtung: node_modules muss existieren und auf der Ignore-Liste stehen).

Kopieren Sie nun aus Ihrer Lösung des vierten Teil des Tutoriums die Ordner src und web (jeweils samt allen darin enthaltenen Ordnern und Dateien) sowie die Dateien gruntfile.js, package.json, package-lock.json und webpack.config.js fügen Sie sie ins Wurzelverzeichnis des fünften Teils ein.

Weisen Sie WebStorm wiederum an, die Inhalte der Ordner node_modules und web/js nicht auf Syntaxfehler zu überprüfen. Gegebenenfalls müssen Sie auch wieder die Dateien gruntfile.js ... webpack.config.js unter die Versionsverwaltung von SVN stellen (Add to VCS).

Ändern Sie in den Dateien package.json und web/index.html die Versionsnummern, die Beschreibung und gegebenenfalls den Pfad zum Repository Ihres Projektes.

Zu guter Letzt öffnen Sie das WebStorm-Terminal und führen den Befehl npm installaus. Damit werden dieselben Node.js-Pakete installiert wie im vierten Teil des Tutoriums.

Löschen Sie die Datei web/js/app.bundle.js und rufen Sie anschließend grunt auf, um diese Datei erneut zu erzeugen. Wenn Sie jetzt die Datei index.html im Browser öffnen, sollte die Web-Anwendung so wie in Teil 4 der Aufgabe funktionieren.

Verfeinerung der Webpack-Umgebung

Zunächst benötigen Sie ein paar weitere Node.js-Module

npm install --save-dev es6-autobind
npm install --save-dev node-sass sass-loader extract-text-webpack-plugin

Im vierten Teil des Tutoriums wurde die Datei initial.css nicht von Webpack verwaltet, sondern direkt in das Verzeichnis web/css eingefügt. Damit liegt auch die Verantwortung für die Komprimierung dieser Datei beim Programmierer. Das soll sich ändern. Sie erweitern die Webpack-Konfiguration so, dass künftig auch diese Datei unter der Kontrolle von Webpack steht.

SCSS

Anstelle von CSS-Dateien verwenden Sie künftig SCSS-Dateien. Das ist zunächst einmal nicht weiter schwer, das jede CSS-Datei automatisch auch eine SCSS-Datei ist. Bei der Verwendung von CSS können Sie allerdings das Prinzip „Don't repeat yourself“ (DRY) nicht beachten. Sie müssen für verschiedene Elemente ständig Informationen wiederholen (gewünschter Font, Hintergrundfarbe, Größenangaben etc.). Deshalb gibt es mehrere Projekte wie z. B. LESS und Sass , die den CSS-Standard erweitern, um dieses Problem zu vermeiden. Sass verwendet allerdings eine ganz andere Syntax als CSS. Allerdings unterstützt das Sass-Projekt auch die Sprache SCSS, die CSS einfach um weitere syntaktische Elemente ergänzt. Zum Beispiel kann man in SCSS Konstanten definieren:

$background-color:  #C5EFFC;

Und nun kann man in der CSS-Datei anstelle von #C5EFFC stets $background-color schreiben, um die Hintergrundfarbe von bestimmten Elementen zu definieren. Wenn man nun dieses Farbe ändern will, muss das nicht mehr bei allen Elementen einzeln passieren. Es reicht, die Farbe in der Konstantendefinition abzuändern. Der CSS-Code ist nun DRY.

Leider unterstützt kein Browser SCSS direkt. Aber für was gibt es Transpiler wie Webpack, die eine SCSS-Datei automatisch in eine CSS-Datei übersetzen können.

Ersetzen Sie in Ihrem Projekt die Datei src/css/main.css durch drei SCSS-Dateien: _config.scss, initial.scss und app.scss.

In der Datei _config.scss werden alle von den anderen SCSS-Dateien benötigten Konstanten definiert. Das heißt, das Prinzip „Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien“ wird ab sofort beachtet. Wenn man künftig am Layout einen Zeichensatz, eine Farbe, einen Hintergrund oder Ähnliches ändern will, reicht es, die entsprechenden Konstanten anzupassen und schon erzeugt Webpack automatisch aktualisiere CSS-Dateien.

Die Datei initial.scss enthält möglichst wenig Code. Das ist Vorlage für die Datei initial.bundle.css, die im HTML-Head-Bereich geladen vor dem Body-Inhalt werden soll. Die eigentlichen CSS-Informationen der Web-Anwendung werden in app.scss gespeichert. Die zugehörigen CSS-Anweisungen werden von Webpack wie gehabt in app.bundle.js integriert.

src/css/_config.scss

$font-family-sans:  Verdana, Helvetica, sans-serif;
$font-family-serif: "Times New Roman", Times, serif;
$background-color:  #C5EFFC;

Diese Datei kann nun mit Hilfe des SCSS-Befehls @import in die anderen beiden SCSS-Dateien eingefügt werden. Webpack (genauer gesagt das SASS-Modul von Webpack) kennt diesen Befehl und führt im beim Erstellen der zugehörigen CSS-Dateien auch aus.

Der Import-Befehl ist hier notwendig, da in der Datei initial.scss die Konstante $background-color verwendet wird. Ansonsten enthält dies Datei nur den schon bekannten CSS-Code.

src/css/initial.scss

@import 'config';

body
{ background-color: $background-color;
}

.hidden
{ display: none;
}

Die Datei app.scss ist deutlich umfangreicher. Daher soll der zugehörige CSS-Code ja auch erst gemeinsam mit der Datei app.bundle.js geladen werden. Das meiste ist üblicher CSS-Code, den Sie schon im vierten Teil des Tutoriums kennengelernt haben. Es gibt ein paar neue Elemente, wie die CSS-Klassen-Elemente .left und .right, die in der HTML-Datei dieses Tutoriums zusätzlich verwendet werden. Außerdem sehen Sie in der Datei noch ein paar weitere SCSS-Elemente. Diese werden im Anschluss an den folgenden code beschrieben.

src/css/app.scss

@import 'config';

html, body
{ height:           100%;
  font-size:        2vw !important;
  font-family:      $font-family-sans;
  background-color: $background-color;
}

html
{ display: table;
  width:   100%;
}

body
{ display:          table-cell;
  text-align:       center;
  vertical-align:   middle;
}

h1
{ padding-bottom: 0;
  margin-bottom:  0;
}

#section_form
{ text-align:   center;
  width:        21em;
  margin-left:  auto;
  margin-right: auto;

  h1
  { font-size:     200%;
    margin-bottom: 0.5ex;
  }
}

#section_hello
{ h1
  { font-size: 270%;
  }
}

p, label
{ font-family: $font-family-serif;
  font-size:   100%;
}

label, input, button
{ width:         10em;
  font-size:     100%;
  display:       inline-block;
  box-sizing:    border-box;
  margin-bottom: 0.5ex;
}

label
{ text-align: right;
}

@mixin panel()
{ padding: 0;
  width:   50%;
}

.left
{ float: left;
  @include panel();
}
.right
{ float: right;
  @include panel();
}

In diese SCSS-Datei werden folgende SCSS-Erweiterungen verwendet:

  • Import-Befehl: @import 'config';
  • Konstanten: $font-family-sans, $font-family-serif, $background-color
  • Verschachtelte Anweisungen: z. B. h1 innerhalb von #section_form
  • Mixins, um eine Liste von Attributen nur einmal zu definieren und und mehreren Elemente wieder verwenden zu können.

Die verschachtelten Anweisungen strukturieren den CSS-Code deutlich besser. Es ist nicht mehr notwendig einen Selektor wie #section_form mehrfach zu verwenden.

Sehen Sie sich den Unterschied an. In der Datei main.css vom vierten Teil des Tutoriums hatten Sie folgendes geschrieben:

#section_form
{
  text-align:   center;
  width:        21em;
  margin-left:  auto;
  margin-right: auto;
}

#section_form > h1
{
  font-size:     200%;
  margin-bottom: 0.5ex;
}

Die SCSS-Variante ist deutlich strukturierter und prägnanter.

#section_form
{ text-align:   center;
  width:        21em;
  margin-left:  auto;
  margin-right: auto;

  h1
  { font-size:     200%;
    margin-bottom: 0.5ex;
  }
}

Insbesondere bei großen CSS-Dateien erweist sich diese kompaktere Schreibweise als vorteilhaft.

Ein weiteres Element, das nur SCSS bietet sind die Mixins. Sie definieren zunächst ein Mixin, das eine Folge von CSS-Attributen zusammenfasst. (Auch hier könnten wieder Verschachtelungen und andere SCSS-Erweiterungen verwendet werden!)

@mixin panel()
{ padding: 0;
  width:   50%;
}

Und nun können Sie dieses Mixin in diversen andere Elemente einbinden:

.left
{ float: left;
  @include panel();

.right
{ float: right;
  @include panel();
}

In normalen CSS-Code, müssten Sie denselben Code Non-DRY formulieren:

.left
{ float:   left;
  padding: 0;
  width:   50%;
}

.right
{ float:   right;
  padding: 0;
  width:   50%;
}

Wenn Sie hier das Layout der Panels ändern wollten (andere Breite, andere Ränder etc.), müssen Sie den CSS-Code von jedem Panel einzeln ändern. In der SCSS-Datei erfolgt die Änderung dagegen DRY: Sie ändern einfach den Mixin-Code ab.

Wenn die aktuellen Browser SCSS verstehen würden, könnte sie initial.scss und app.scss direkt vom HTML-Code aus laden. Allerdings geht das derzeit leider nicht. Somit muss Webpack angewiesen werden, CSS-Code aus den SCSS-Dateien zu erzeugen. Dies ist mit den beiden Node.js-Modulen node-sass und sass-loader, die Sie bereits installiert haben, ganz einfach möglich.

Ersetzen Sie in der Datei webpack.config.js folgenden Code

{ test:   /\.css$/,
  use:    [ 'style-loader',
            { loader: 'css-loader', options: { minimize: true } }
          ]
},

durch folgenden:

{ test:   /\.(css|scss|sass)$/,
  use:    [ 'style-loader',
            { loader: 'css-loader', options: { minimize: true } },
            'sass-loader'
          ]
}

Der Test wird so erweitert, dass diese Regel jetzt nicht nur für die Verarbeitung von Dateien mit der Endung .css zuständig ist, sondern auch für Dateien mit den Endungen .sass und .scss.

Die Liste der zugehörigen Loader wird einfach um einen Loader erweitert: sass-loader. Diese Liste wird von hinten nach vorne abgearbeitet. Das heißt, eine Datei wie beispielsweise app.scss wird erst mit Hilfe des Sass-Loaders in eine CSS-Datei umgewandelt, diese wird mit Hilfe des CSS-Loaders komprimiert und das Ergebnis dieser Datei wird mit Hilfe des Style-Loaders in die zugehörige JavaScript-Ausgabedatei integriert.

Jetzt müssen nur noch die zugehörigen JavaScript-Dateien erstellt werden.

Im entry-Objekt der Datei webpack.config.js ist bereits die Datei src/js/app.js eingetragen. Für Sie wird von Webpack die Datei web/js/app.bundle.js erzeugt.

Der Name der Zieldatei wurde im output-Objekt von webpack.config.js spezifiziert. Achtung: Überprüfen Sie, ob das output-Objekt folgendermaßen definiert wurde.

  output:
  { filename: 'js/[name].bundle.js',
    path:     absolutePath('web')
  }

Damit diese Zieldatei insbesondere den komprimierten Code der Datei src/css/app.scss enthält, muss src/js/app.js leicht modifiziert werden.

Ersetzen Sie in dieser Datei den Import-Befehl

import '../css/main.css';

durch den Import-Befehl

import '../css/app.scss';

Die Datei web/css/main.css gibt es ja nicht mehr; sie wurde durch web/css/app.scss ersetzt.

Damit auch web/css/initial.scss durch webpack verwaltet wird, benötigen wir eine zweite JavaScript-Datei.

src/js/initial.js

import '../css/initial.scss';

Sie sehen das richtig, die Datei src/js/initial.js enthält eine einzige Code-Zeile. Sie erinnern sich? Webpack dient eigentlich nur dazu JavaScript-Dateien zu packen. Also geben wir diesen Tool eine JavaScript-Datei, die die gewünschte CSS-Datei einfach mittels eine ES6-Import-Befehls importiert (ES6 = EcmaScript 6). Fügen Sie nun in das entry-Objekt der Datei webpack.config.js vor der Zeile

app: absolutePath('src/js/app.js')

folgende zweite Zeile ein:

initial: absolutePath('src/js/initial.js')

Beachten Sie, dass in einem JavaScript-Objekt die Attribute durch Kommas voneinander getrennt werden. Fügen Sie also an passender Stelle auch noch ein Komma ein.

Wenn Sie jetzt Grunt aufrufen, sollten zwei Dateien generiert werden: web/js/app.bundle.js und web/js/initial.bundle.js.

Löschen Sie nun den Ordner web/css (die darin befindliche Datei initial.css wird nicht mehr benötigt) und ersetzen Sie in der Datei index.html die Zeile

<link rel = "stylesheet" type = "text/css" href = "css/initial.css"/>

durch folgende Zeile:

<script type = "text/javascript" src = "js/initial.bundle.js"></script>

Wenn Sie jetzt die Datei index.html im Browser öffnen, sollte sie wieder genauso funktionieren wie zuvor.

Anmerkung: Die Datei src/js/initial.js könnte natürlich noch mehr machen, als einfach nur eine CSS-Datei zu laden. Sie könnte beispielsweise eine kleine Animation einblenden (die berühmte Sanduhr, nur etwas moderner), die solange läuft, bis die eigentliche Web-Anwendung, d. h. app.bundle.js vollständig geladen wurde und die Animation wieder beendet.

Erzeugen einer CSS-Datei

Zurzeit enthält die JavaScript-Datei web/js/initial.bundle.js nur eine komprimierte CSS-Datei und etwas Code, um diesen in das HTML-Dokument einzufügen. Die Google-Suche bewertet HTML-Dateien, die sauberen CSS-Code i. Allg. enthalten, höher, als HTML-Datei, die nur JavaScript-Code enthalten. Daher wäre es in diesem Fall sinnvoll, die komprimierte CSS-Datei direkt in den HTML-Code einzubinden. Das ist aber gar nicht so einfach, da Webpack keine CSS-Dateien erstellt, sondern nur JavaScript-Dateien. Aber mit einem kleine Hack funktioniert das trotzdem.

Sie haben vor auch noch die Node.js-Module extract-text-webpack-plugin installiert. Mit diesem Sie eine CSS-Datei aus einer JavaScript-Datei extrahieren.

Ersetzen Sie zunächst in der Datei webpack.config.js den Test

test:   /\.(css|scss|sass)$/,

durch

test:   /app\.(css|scss|sass)$/,

Damit erreichen Sie dass diese Regel jetzt nur noch für Dateien funktioniert, die auf app.css oder app.scss oder app.sass enden. Die Datei src/css/app.scss in die Datei src/js/app.bundle.js integriert werden.

Laden Sie zunächst die ExtractTextPlugin-Erweiterung, indem Sie in die Datei webpack.config.js folgende zweite Zeile einfügen:

const ExtractTextPlugin = require('extract-text-webpack-plugin');

Für die Datei src/css/initial.scss fügen Sie nun in die Liste mit den Regeln eine weitere Regel ein (Komma nicht vergessen):

{ test:   /initial\.(css|scss|sass)$/,
  use:   ExtractTextPlugin.extract
         ({fallback: "style-loader",
           use:      [{ loader: 'css-loader', options: { minimize: true } },
                      'sass-loader'
                     ]
         })
}

Diese benutzt das zuvor erwähnte Plugin, um die komprimierte CSS-Datei aus der Datei src/js/initial.bundle.js zu extrahieren. Das erledigt sie aber nur fast. Man muss dem Plugin noch mitteilen wohin Sie die CSS-Datei speichern soll.

Dazu müssen Sie die bislang leere Plugin-Liste am Ende der Datei

plugins:
[]

mit Inhalt füllen:

plugins:
[ new ExtractTextPlugin("css/[name].bundle.css") ]

Führen Sie nun grunt aus. Es sollte die Datei web/css/initial.bundle.css erzeugt worden sein.

Nun müssen sie in der Datei index.html die Zeile

<script type = "text/javascript" src = "js/initial.bundle.js"></script>

wieder durch eine CSS-Link-Zeile ersetzen (da ja in der Datei initial.bundle.js kein sinnvoller Inhalt mehr enthalten ist; sie wurde durch das Extract-Text-Plugin „ausgelutscht“).

<link rel = "stylesheet" type = "text/css" href = "css/initial.bundle.css"/>

Sie könnten nun noch die überflüssige Datei web/js/initial.bundle.js von webpack wieder entfernen lassen. Wie das geht entnehmen Sie bitte der Seite https://stackoverflow.com/questions/37408873/delete-or-not-create-a-file-for-each-entry-in-webpack sowie der Musterlösung. Wichtig ist das nicht. Wenn Sie später mal eine kleine Warteanimation erstellen sollten, bräuchten Sie dieses Datei sowieso wieder.

JSON

Bislang haben sie den CSS-Code unter Webpack-Kontrolle gestellt und damit DRY gemacht. Als nächstes gehen wir das nächste Problem an: Ihr Code enthält ebenfalls Konstanten und verstößt damit gegen das Programmierprinzip „Konstante Werte gehören nicht in den Code, sondern in Konfigurationsdateien.“

Eine Ausnahme bilden triviale Konstanten wie 0, 1, null, true oder false, sofern sie mit großer Sicherheit nie im Code geändert werden müssen. Aber schon eine Konstante wie 3.1415926 gehört nicht in den Code. Man verwendet stattdessen besser Math.PI und erhält damit die maximal mögliche Stellenzahl. (Eventuell hängt diese von der Rechnerplattform ab.)

In JavaScript-Anwendungen verwendet man JSON zur Speicherung von (konstanten) Daten und zur Initialisierung der Anwendung. Wenn ein Spiel mehrere Level hat, wir jedes Level üblicherweise in einer eigenen JSON-Datei beschrieben. Eine Level-Designerin muss im Optimalfall nicht mehr machen, als die Assets (Grafiken, Töne, 3D-Modell etc.) zu erstellen und mit Hilfe einer JSON-Datei die Zusammenhänge zwischen den einzelnen Elementen herstellen. Es sollte nicht notwendig sein, dass sie den Programmcode modifizieren muss, da das Level-Design schon aufwändig genug ist.

JSON (JavaScript Object Notation) ist ein einfaches Datenformat, mit dessen Hilfe sich komplexe Objekte sehr einfach beschreiben lassen. Eine Alternative wäre XML, allerdings ist diese Auszeichnungsprache deutlich komplexer. (Ein Beispiel für XML ist XHMLT 1.0[1], eine HTML-Variante.)

Eine JSON-Datei ist im Prinzip eine JavaScript-Datei, die einen der folgenden Datentypen enthält[2]:

  • Nullwert (null)
  • Boolescher Wert (true oder false)
  • Zahl (Ziffernfolge mit optionalem Vorzeichen und optionalen Exponenten)
  • Zeichenkette (beliebige UTF-8-Zeichen, die in doppelten geraden Anführungszeichen (") eingeschlossen sind)
  • Array (eine durch Kommata getrennte Listen von null oder mehr JSON-Elementen; die Liste beginnt mit [ und endet mit ])
  • Objekt/Hasharray/Paarliste (eine durch Kommata getrennte Listen von null oder mehr Paaren; die Liste beginnt mit { und endet mit }; jedes Paar besteht aus einer Zeichenketten, die als Schlüssel fungiert, gefolgt von einem Doppelpunkt (:) gefolgt von einem beliebigen JSON-Element; in einem Objekt darf derselbe Schlüsselwert nicht zweimal vorkommen)

Beachten Sie, dass die eine rekursive Definition ist: Arrays dürfen andere Arrays und Objekte enthalten, Objekte dürfen andere Objekte und Arrays enthalten. JSON-Elemente können also beliebig tief geschachtelt sein.

Andere Werte dürfen in einer JSON-Datei nicht enthalten sein. Das heißt, es gibt keine einfachen geraden Anführungszeichen (außer innerhalb von Zeichenketten), keine Kommentare, keine Funktionen etc. Insbesondere überflüssige Kommas sind nicht erlaubt!

Beachten Sie bitte, dass jeden JSON-Datei auch eine JavaScript-Datei ist (die Umkehrung dieser aussage gilt nicht.). Wenn man eine JSON-Datei auswerten würde, erhielte man jedoch kein anderes Ergebnis als den Wert oder das Objekt, das in der Datei gespeichert ist.

Erstellen Sie in Ihrem Projekt folgende zwei JSON-Dateien:

src/json/config_de.json

{
  "text":
  {
    "title":    "Hallo, Fremder!",
    "question": "Wie heißen Sie?",
    "reset":    "Reset",
    "submit":   "Begrüßung",
    "hello":    "Hallo, $1!",
    "welcome":  "Willkommen bei Multimedia-Programmierung!"
  },

  "css":
  {
    "hidden": "hidden"
  }
}

src/json/config_en.json

{
  "text":
  {
    "title":    "Hello, Stranger!",
    "question": "What's your name?",
    "reset":    "Reset",
    "submit":   "Say hello",
    "hello":    "Hello, $1!",
    "welcome":  "Welcome to Multimedia Programming!"
  },

  "css":
  {
    "hidden": "hidden"
  }
}

Importieren Sie die erste der beiden JSON-Dateien in Ihre Datei src/js/app,js, indem Sie folgenden Import-Befehl einfügen:

import * as config from '../json/config_de.json';

In src/js/app/greet,js fügen Sie folgenden Import-Befehl ein:

import * as config from '../../json/config_de.json';

Beachten Sie, dass hier eine Zugriff auf das „Großvater“-Verzeichnis src mittel ../../ erfolgen muss. Grundsätzlich sollten Sie in Import-Befehlen immer relative Pfadnamen angeben, da sonst eine Änderung der globalen Ordnerstruktur zu massiven Problemen führen kann. Achten Sie bei Pfad-Angaben insbesondere auf Groß- und Kleinschreibung. Gemeinerweise macht es auf Windows-Rechnern keinen Unterschied, ob sie in einem Pfadnamen Groß- oder Kleinbuchstaben verwenden. Wenn Sie die Anwendung später auf einen Linux-Server kopieren, kommt es dann allerdings zu Problemen, weil der Server die Pfade mit den falschen Groß- oder Kleinbuchstaben nicht mehr findet. Sie sollten in Dateinamen am Besten überhaupt keine Großbuchstaben verwenden.

Wenn Sie jetzt grunt aufrufen und anschließend index.html im Browser öffnen, hat sich noch nicht viel getan.

Ändern Sie nun den Inhalt der index.html. Löschen Sie alle englischen Text-Elemente. sie sollten sie durch die angegebenen Dummy-Texte ersetzen, notwendig wäre das aber nicht:

  • Hello, Stranger!TITLE
  • What's your name?QUESTION
  • ResetRESET
  • Say helloSUBMIT
  • Hello, ...HELLO
  • Welcome to Multimedia Programming!WELCOME

Sie müssen außerdem noch einigen HTML-Tags zusätzlich ein id-Attribut zuordnen:

  • H1-Element: <h1 id="heading_form">
  • Label-Element: <label id="input_label" ..>
  • Reset-Button: <input id="button_reset" type="reset" ...>
  • Welcome-Paragraph: <p id="paragraph_hello">WELCOME</p>

Wenn Sie jetzt die index.html nochmals im Browser öffnen, sehen Sie nur noch die DUMMY-Texte.

Das ändert sich allerdings, wenn Sie folgende JavaScript-Befehle in die Datei src/js/app.js nach den Import-Befehlen einfügen:

const c_config_text = config.text;

// Initialize the app.
document.getElementById('button_reset').value
  = c_config_text.reset;
document.getElementById('button_submit').value
  = c_config_text.submit;

document.getElementById('heading_form').innerHTML
  = c_config_text.title;
document.getElementById('input_label').innerHTML
  = c_config_text.question;

(Die restlichen Zeilen bleiben erhalten.) Mit diesen fünf Befehlen speichern Sie den Inhalt des Attributs text aus der eingelesenen JSON-Datei in der Konstanten c_config_text. Anschließend ersetzen Sie mit Hilfe von vier weiteren Befehle die Dummy-Texte im der Form-Section durch sinnvolle Texte.

Rufen Sie grunt auf und öffnen Sie anschließend index.html im Browser. Jetzt sollten Sie deutsche Text an Stelle von Dummy-Texten sehen. Wenn Sie jetzt allerdings einen Namen eingeben und auf den Begrüßungs-Button klicken, werden Sie englisch begrüßt und sehen einen weiteren Dummy-Text.

Das heißt, Sie müssen auch noch die Datei src/js/app/greet.js erweitern.

Ersetzen Sie in dieser Datei im Rumpf der Funktion sayHello den darin enthalten Code durch folgenden Code:

const l_config_text = config.text,
      l_name      = document.getElementById("input_name").value;

document.getElementById('paragraph_hello').innerHTML
  = l_config_text.welcome;
document.getElementById('heading_hello').innerHTML
  = l_config_text.hello.replace('$1', l_name);

document.getElementById('section_hello')
  .classList.remove('hidden');
document.getElementById('section_form')
  .classList.add('hidden');

Die Funktion sayHelloOnEnter ändert sich dagegen nicht.

Nun sollte (nach einen grunt-Lauf) die Web-App wie gewünscht funktionieren.

Sie können jetzt testweise mal in beiden Dateien app.js und greet.js die englischsprachige JSON-Datei landen, grunt laufen lassen und index.html öffnen. Dann sollten Sie auf Englisch begrüßt werden. Das ist schon nicht schlecht, aber richtig DRY ist das noch nicht. Sie müssen den Namen der JSON-Datei in zwei Dateien ändern. Also braucht es noch eine sechstes und letztes Hello-World-Tutorium ...

Quellen

  1. Kowarschick (MMProg): Wolfgang Kowarschick; Vorlesung „Multimedia-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 3 (Vorlesung)