# MathCoach IDE API
In diesem Paket ([Das Gitblit Repository findet sich hier](https://newton.htwsaar.de/gitblit/summary/mathcoach!mathcoach-ide-api.git))
ist die öffentliche Schnittstelle zur MathCoach Entwicklungsumgebung (IDE) definiert. Mithilfe
dieser Schnittstelle können externe Werkzeuge (z.B. Editoren) erstellt werden. Ziel ist, dass
diese Werkzeuge für den Anwender komfortable - in die IDE integriert -zur Verfügung gestellt werden
können. Darüber hinaus werden als Ergänzung einige Hilfsfunktionen zum Bau von Werkzeugen angeboten.

*Beispielhafte Anwendung: Eine Datei wird angelegt und einem Demo-Editor geöffnet. Dieser
generiert eine Groovy-Aufgabe*
## Idee
Grundlegende Idee ist, dass ein externes Werkzeug nahtlos in die MathCoach IDE integriert werden
kann. Bestimmte Dateien werden anhand ihrer Dateiendung mit dem Werkzeug verknüpft, sodass der
Benutzer das passende Werkzeug durch einen einfache Klick im Dateie-Explorer starten kann. Diese
Datei wird im folgenden Kontext-Datei genannt und soll dazu dienen das interene Datenmodell (also
alle Informationen, die der Benutzer im Editor angibt) zu speichern. Das gespeicherte Datenmodell kann
zu einem späteren Zeitpunkt wieder geladen werden. Weiterhin kann das Werkzeug aus dem internen
Datenmodell eine MathCoach-Aufgabe (Groovy-Datei) generieren. Weitere Funktionalitäten - beispielsweise
das Starten der generierten Aufgabe in der Aufgaben-Vorschau der IDE - sind ebenfalls für den
Werkzeugentwickler verfügbar.
Das Realisieren von Werkzeugen auf diese Art und Weise hat zahlreiche Vorteile:
- Werkzeuge werden einheitliche und benutzerfreundlich zur Verfügung gestellt
- Grundlegende Funktionalitäten (Anlegen von Dateien, Navigieren im Dateisystem) werden bereits
durch die IDE bereitgestellt. So können Werkzeug-Entwickler ihren Fokus auf das Werkzeug legen.
- Die IDE kann gefährliche Situationen (z.B. das Überschreiben von Dateien) abfangen
und den Benutzer entscheiden lassen, wie fortgefahren werden soll.
## Entwicklung externer Werkzeuge
Externe Werkzeuge laufen ausschließlich im Webbrowser des Benutzers - es muss also
auf `HTML`, `JavaScript` und `CSS` gesetzt werden. Außerdem muss das Werkzeug unter
der Domain des jeweiligen MathCoach-Servers erreichbar sein. Zur Entwicklungszeit legt man das Werkzeug
dazu im www-Verzeichnis ab. Die von der IDE bereitgestellte `ide-lib.js` Bibliothek
muss eingebunden werden.
Dabei darf der MathCoach-Server **nicht** fest in die URL eincodiert werden. Andernfalls
kann es zu Problemen kommen, wenn das Werkzeug auf unterschiedlichen Server bereitgestellt
wird. Bei korrekter Verwendung steht die IDE API nun durch die globale Varialbe `MC` zur
Verfügung - [Dokumentation der IDE API](./interfaces/mathcoach.api.html).
> **Hinweis**: Es steht **ausschließlich** die API, welche über die globale Variable `MC`
> definiert ist, zur Verfügung! Hilfsfunktionen wie `Helpers.enableOfflineUsageIfNecessary()`
> sind grundsätzlich nicht verfügbar und müssen vom Werkzeugentwickler eingebunden
> werden - siehe "Hilfunktionen für Werkzeug-Entwickler" weiter unten.
> **Hinweis**: Erst, wenn das Werkzeug in die IDE integriert und aus dieser heraus
> gestartet wurde, kann die IDE API verwendet werden! Soll das Werkzeug auch ohne die
> IDE nutzbar sein (z.B. zum Testen), muss dies bei der Implementierung berücksichtigt
> werden. Konnte die `ide-lib.js` nicht eingebunden werden (weil das Werkzeug ohne IDE
> gestartet wurde - darum darf auch kein Server fest eincodiert werden), steht die
> globale Variable `MC` nicht zur Verfügung (`typeof MC === "undefined"`). Hier kann das
> Werkezug eine Fallunterscheidung treffen und beispielsweise eine eigene Implementierung
> über die globale Variable `MC` bereitstellen. Siehe auch `Helpers.enableOfflineUsageIfNecessary()`
> weiter unten.
### Empfohlenes Vorgehen
Damit externe Werkzeuge ein einheitliches Verhalten aufweisen, sollte wie folgt vorgegangen werden.
Als erstes muss sichergestellt werden, dass die MathCoach IDE API auch verfügbar ist. Dies ist
beispielsweise nicht der Fall, wenn das Werkzeug ohne die IDE gestartet wurde oder die IDE (aus
welchen Gründen auch immer) nicht einsatzbereit ist.
if(typeof MC === "undefined"){
// Hinweis: Hier kann die IDE API nachgebildet werden,
// sodass das Werkzeug auch "Offline" funktioniert.
// Also: MC = { isReady: async () => true, ...}
throw new Error("IDE Lib nicht eingebunden"); // TODO: show error to user
}
const isReady = await MC.isReady();
if(!isReady){
throw new Error("Die MathCoach-API ist nicht einsatzbereit."); // TODO: show error to user
}
...
Von nun an kann die IDE API vollständig genutzt werden. Zunächst sollte die Kontext-Datei (die
Datei, mit der das Werkzeug gestartet wurde) geladen werden.
Ist der Inhalt der Kontext-Datei leer, wurde die Datei neu angelegt und zum ersten mal geöffnet.
Nun soll das Werkzeug:
- Sich initialisieren. Es ist sinnvoll, dass das Werkzeug mit einem beispielhaften
Datenmodell inititalisiert wird.
- Das interne Datenmodell in die Kontext-Datei schreiben
- Die zugehörige Aufgabe generieren. Siehe auch `contextFileToExerciseFile` weiter unten.
Andernfalls kann das zuvor gespeichertes Datenmodell aus der Kontext-Datei in den
Editor geladen werden. Anschließend sollte die generierten Aufgaben in der Vorschau gestartet werden, sodass der
Benutzer besser abschätzen kann, wie sich Änderungen im Werkzeug auf die Aufgabe auswirken.
let contextFile = await MC.ide.getContextFile(); // Datei, mit der der Editor gestartet wurde
let contextFileContent = await MC.ide.fs.readFile(contextFile);
let contextFileIsEmpty = contextFileContent === "";
let exerciseFile = contextFileToExerciseFile(contextFile);
if(contextFileIsEmpty){
// TODO: Datenmodell anlegen (Idealerweise mit beispielhaften Inhalt)
// TODO: Datenmodell in Kontext-Datei schreiben, z.B. mit JSON.stringify(...)
let dataModelAsString = JSON.stringify({/* TODO */});
await MC.ide.fs.writeFile(contextFile, dataModelAsString);
// TODO: Aufgabe generieren
let generatedExerciseCode = "startup { print('Hallo Welt!') }";
await MC.ide.fs.writeFile(exerciseFile, generatedExerciseCode);
}else{
// TODO: Datenmodell laden, z.B. mit JSON.parse(contextFileContent)
// TODO: (Aufgabe neu generieren)
// TODO: init application based on your data model
}
// Aufgabe anzeigen
await MC.ide.navigator.navigateToExercise(exerciseFile);
Jedes Werkzeug sollte über eine "Speichern"-Funktion verfügen, mit der der Benutzer:
- Das interne Datenmodell in die Kontext-Datei speichert (sodass es später wieder geladen werden kann)
- Die zugehörige Aufgabe wird generiert und die Vorschau zu dieser navigiert
### Hilfsunktionen für Werkzeug-Entwickler
[Dokumentation der Hilfsfunktionen](./modules/helpers.html)
Dieses Paket beinhaltet zusätzlich Hilfsfunktionen für Werkzeug-Entwickler. Diese sind aktuell
in `TypeScript` implementiert und können bei Bedarf auch zukünftig als ES6-JavaScript
bereitgestellt werden. Zum Einbinden der Funktionen wird demzufolge ein Build-System
vorausgesetzt. Keine der Hilfsfunktionen wird durch die `ide-lib.js` ausgeliefert!
Beispielsweise werden diese wie folgt eingebunden und genutzt:
import { Helpers } from "@mathcoach/ide-api";
Helpers.enableOfflineUsageIfNecessary()
> **Hinweis**: Hilfunktionen ohne Build-System bereitzustellen gestaltet sich schwierig und
> bringt große Nachteile mit sich:
> - Als reine JavaScript-Datei - platziert auf einem Server - ist die die
> Offline-Fähigkeit (siehe `Helpers.enableOfflineUsageIfNecessary()`) von Werkzeugen nicht
> gewährleistet.
> - Werden Dateien oder Code-Ausschnitte von Hand kopiert, muss der Werkzeug-Entwickler sich
> um das Aktualisieren kümmern.
>
> Ein möglicher Kompromiss wäre die Hilsfunktionen als reine JavaScript-Datei (ES5 oder ES6)
> bereitzustellen und eine Kopie mit dem Werkezug auszuliefern. Der aktuelle Ansatz bettet
> Hilfsfunktionen durch den Build-Prozess in das Werkzeug ein.
### Beispiele
Im Verzeichnis `./examples/` finden sich Beispiele für externe Werkzeuge.
### Entwicklung kleinerer Werkzeuge
Für kleiner Werkzeuge bietet es sich an im www-Verzeichnis zu entwickeln (z.B.
`myTool/tool.html` und `myTool/tool.js`). Die MathCoach-IDE stellt Autovervollständigung beim
Editieren der `tool.js`-Datei zur Verfügung. Da es sich um eine JavaScript-Datei handelt,
ist keine Typsicherheit gegeben. Das Werkzeug muss lokal in die IDE integriert werden, siehe
weiter unten.

### Entwicklung größerer Werkzeuge
Für größere Werkzeuge sollten etablierte Entwicklungswerkzeuge verwendet werden, beispielsweise:
- [npm](https://nodejs.org/en/) um externe Bibliotheken (u.A. dieses Paket) einzubinden
- [webpack](https://webpack.js.org/) oder [Parcel](https://parceljs.org/) als Build-System um den Quellcode des Werkzeuges zu "bündeln"
- [TypeScript](https://www.typescriptlang.org/) zum typsischeren Programmieren (und/oder Dateien zu ES6 oder ES5 konformen JavaScript umzuformen)
- [Git](https://git-scm.com/) zur Versionierung des Quellcodes
- [Visual Studio Code](https://code.visualstudio.com/) als Entwicklungsumgebung
- Unit Tests
Das "gebündelte" Werkzeug muss nach dem Build-Prozess in das WWW-Verzeichnis kopiert und ebenfalls
lokal in die IDE integriert werden, siehe weiter unten.
#### MathCoach-API als npm-Package einbinden
Die MathCoach-API kann auch als npm-Package eingebunden werden, sodass eine typsichere
und komfortable Entwicklung (z.B. mit Visual Studio Code) möglich ist. Außerdem wird es
möglich die angebotenen [Hilfsfunktionen](./modules/helpers.html) zu einzubinden. Hierzu muss
die `package.json` des Werkzeug-Projektes wie folgt ergänzt werden:
{
...
"devDependencies": {
"@mathcoach/ide-api": "git+https://newton.htwsaar.de/gitblit/r/mathcoach/mathcoach-ide-api.git#1.2.0"
},
...
}
Wie man der Git-Repo URL ansieht, werden Git-Tags verwendet um eine Versionierung
[(Semantic Versioning)](https://semver.org/lang/de/) der API zu erreichen. Lässt man die Versionierung weg,
wird die aktuellste Version verwendet. (Siehe Gitblit um verfügbare Versionen einzusehen)
#### Typdefinition auch ohne Build-System nutzen
Beim Arbeiten mit Visual Studio Code kann man auch ohne Einsatz weiterer Entwicklungswerkzeuge
und Build-Systeme von der Typdefinition der IDE API profitieren. Hierzu muss ein spezielles Kommentar
an den Anfang der JavaScript-Datei platziert werden (Pfad anpassen!):
///
Dies sorgt dafür, dass Visual Studio Code Autovervollständigung samt Dokumentation der
IDE API anbieten kann. Nachteilig ist, dass die `mathcoach-api.d.ts` dazu heruntergeladen
werden muss.
#### Zertifikat-Problem beheben
Falls es Probleme mit dem HTW Zertifikat gibt, muss das Zertifikat von Newton ggf. von
Hand hinzugefügt werden. Nur so kann npm auf das Git-Repository zugreifen und den
Inhalt automatisch herunterladen.
cd /usr/local/share/ca-certificates/
sudo mkdir newton.htwsaar.de
sudo cp path/to/newton.htwsaar.de.crt /usr/local/share/ca-certificates/newton.htwsaar.de/
sudo chown 755 /usr/local/share/ca-certificates/newton.htwsaar.de
sudo chown 644 /usr/local/share/ca-certificates/newton.htwsaar.de/newton.htwsaar.de.crt
sudo update-ca-certificates
## Werkzeuge in die IDE integrieren
Damit die IDE das Werkzeug integrieren kann, muss eine Werkzeug-Deklaration registriert werden. Zur
Entwicklungszeit kann der Werkzeug-Entwickler dies lokal vornehmen. Anschließend können verknüpfte
Dateien mit dem Werkzeug geöffnet werden und erstellt werden (siehe Kontext-Menüs im IDE-Explorer).
Eine Freischaltung des Werkzeugs für alle Autoren erfolgt durch einen Administrator.
### Lokal (Nur für den Entwickler des Werkzeugs)
In der IDE muss eine Werkzeug-Deklaration angelegt werden, dazu muss die Datei `ide-settings.json` editiert werden:
{
...
"editor.external.declarations": [
{
"displayName": "Dummy",
"entry": "/mathcoach/www/YOURNAME/tool.html",
"description": "...",
"developer": "...",
"extension": "fib.json"
}
...
],
...
}
| Schlüssel | Beschreibung | Beispiel |
|---------------|---|---|
| displayName | Der Name des Werkzeugs | `"Fill-In-Blank-Editor"` |
| entry | Der Einstiegspunkt für das Werkzeugs muss sich auf dem selben Server wie die IDE befinden. | `"/mathcoach/www/YOURNAME/tool.html"` |
| description | Eine kurze Beschreibung | |
| developer | Name des Werkzeug-Entwicklers | |
| extension | Dateien anhand der Datei-Erweiterung mit dem Werkzeug verknüpfen. Hier sollte etwas eindeutiges gewählt werden | `"fib.json"` für Dateien wie `someExercise.fib.json` |
### Global (Für alle Autoren)
- Das Werkzeug samt Werkzeug-Deklaration muss an einen Administrator übergeben werden
- Der Administrator schaltet das Werkzeug nach einer kurzen Prüfung (Keine Konflikte mit anderen
Dateierweiterung, usw) frei. Beim nächsten Release von MathCoach ist das Werkzeug dann für alle
Autoren verfügbar.
## Infos zu diesem Repository
.
├── CHANGELOG.md // Dokumentation von Änderungen der API
├── examples // Beispiele
│ ├── ...
│ └── ...
├── media // Grafiken
│ └── ...
├── test // Unit Tests
│ └── ...
├── src // Hilfsfunktionen für Werkzeugentwickler
│ ├── index.ts // Einstiegspunkt
│ └── ...
├── mathcoach-api.d.ts // Typ-Definition der API
├── package.json
├── package-lock.json
├── README.md
└── tsconfig.json
#### Dokumentation erzeugen
npm install && npm run build
#### Release einer neuen Version
- Version der API in der `package.json` eintragen
- Beispiele aktualisieren
- Release Tag setzen `git tag -a VERSION -m '...'` und pushen
- IDE-Projekt prüfen: `package.json`, `ide-lib.js`, ...