top

Neues Highlighting-Feature

Als erste Funktionalität, die über das absolute Mindestmass hinausgeht, erhält diese Plattform ein code highlighting-Feature. In zwei Punkten zusammengefasst war dazu notwendig:

  1. Hinzufügen und Einbinden von Drittpackages via Webpack
  2. Coden eines custom Elemental-Blocks in Silverstripe

Der neue Codeblock kommt selbstverständlich schon in dieser Dokumentation zum Zug.

 

Hinzufügen und Einbinden von Drittpackages via Webpack

Für das highlighting auf dieser Webseite wird das package highlight.js verwendet. Es besticht durch seine geringe Grösse und die Tatsache, dass es keine weiteren dependencies hat. Ausserdem unterstützt es eine grosse Anzahl an Sprachen und wir mit einer Anzahl themes geliefert.

Der erste Schritt ist es, das package zu installieren - dies geschieht ganz einfach über den Befehl npm install highlight.js im Projektordner.

webpack erlaubt es, packages zu bündeln - also ihre zahlreichen Inhalte, dependencies und Ressourcen in einzelne, einfach zu verwendende und verwaltende statische assets zu verwandeln. webpack wird in einer besonderen .js-Datei im project root konfiguriert (webpack.config.js), deren config array um einen Eintrag für highlight.js ergänzt werden musste:

                
const config = [{
[...]
}, {
name: 'highlight.js',
entry: {
main: Path.resolve(__dirname, 'app/client/src/highlight.js/bundle.js')
},
output: {
path: Path.resolve(__dirname, 'app/client/dist/highlight.js'),
filename: 'bundle.js',
},
devtool: (ENV !== 'production') ? 'source-map' : '',
resolve: resolves(ENV, PATHS),
module: modules(ENV, PATHS),
plugins: plugins(ENV, PATHS),
}
];

Hier wird definiert, dass es in /app/client/src einen weiteren Ordner namens highlight.js gibt, in dem weitere Konfigurationen stattfinden. Diesen lege ich an. webpack erwartet darin weitere Dateien:

  • .eslintrc und .stylelintrc: Diese beiden Dateien enthalten bzw. verweisen auf die Regelwerke für die ES und CSS linter. Die linter laufen bei der Ausführung von webpack mit. Da es hier keine besonderen Anforderungen gibt, übernehme ich einfach beide Dateien 1:1 aus dem global bundle.
  • bundle.js enthält den auszuführenden JS-Code. Laut Dokumentation von highlight.js muss aus der library hljs importiert werden, womit wir dann highlightAll() ausführen können. Ausserdem verweist es auf style.scss.
  • style.scss schliesslich beinhaltet eine Angabe auf das CSS bzw. theme, das wir für hightlight.js verwenden möchten.

bundle.js sieht so aus:

                
import hljs from 'highlight.js';
import './style.scss';

hljs.highlightAll();

style.scss enthält nur diese eine Zeile. Sie verweist auf eine .scss-Datei, die sich im Installordner des Moduls befindet:

                
@import '~highlight.js/scss/atom-one-light';
                
            

Mit npm run watch wird webpack dann angewiesen, die entsprechenden Dateien in /app/client/dist zu generieren. Wichtig: Bearbeitet wird stets nur /app/client/src, /app/client/dist enthält nur die automatisch Dateien.

highlight.js ist nun konfiguriert und eingebunden. Es kann jetzt in einem Elemental-Block aufgerufen und verwendet werden.

 

Coden eines custom Elemental-Blocks in Silverstripe

Die grundlegenden Schritte für die Erstellung eines eigenen Elemental-Blocks sind die folgenden:

  1. Schreiben einer neuen Klasse, welche BaseElement extended und um notwendige Spezifika ergänzt
  2. Schreiben eines dazugehörigen template, welche den code korrekt einbettet und highlight.js aufruft.

Die neue Klasse namens CodeElement ist ziemlich einfach strukturiert. Sie ergänzt BaseElement nur um folgende Punkte:

  • Ein $db-Feld für die Angabe der Programmiersprache sowie ein Textfeld für den Text an sich
  • Die CMSFields werden angepasst, um die beiden neuen $db-Felder modifizieren zu können. Die Sprachauswahl geschieht über ein Dropdown-Menü mit vorgefertigten Optionen, die in einem array definiert sind.
  • Daneben einige Konfigurationen, die nicht weiter spannend sind.

/app/src/Elements/CodeElement.php sieht dann so aus:

                
<?php

namespace Lerndok\Elements;

class CodeElement extends BaseElement
{
[...]

private static $db = [
'Content' => 'Text',
'Language' => 'Varchar(255)'
];

public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->push(new DropdownField('Language', 'Language', array(
'language-auto' => 'Auto',
'language-plaintext' => 'plain text',
'language-html' => 'HTML',
'language-bash' => 'bash',
'language-css' => 'CSS',
'language-php' => 'PHP',
'language-javascript' => 'JS',
'language-c' => 'C',
)));
$fields->push(new TextareaField('Content'));

return $fields;
}
[...]
}

Nun fehlt nur noch das entsprechende template. Hier muss folgendes geschehen:

  • highlight.js und das dazugehörige SCSS müssen eingebunden werden, damit das highlighting ausgeführt werden kann.
  • Die entsprechenden HTML-Tags müssen an richtiger Stelle gesetzt und ggf. mit der im CMS angegebenen Sprache ergänzt werden.

Das Endergebnis in /app/templates/Lerndok/Elements/CodeElement.ss:

                
<% require themedJavascript('client/dist/highlight.js/bundle.js') %>
<% require themedCSS('client/dist/highlight.js/bundle.css') %>
<div class="content-element__content<% if $Style %> $StyleVariant<% end_if %>">
<% if $ShowTitle %>
<h2 class="content-element__title">$Title</h2>
<% end_if %>
<div class="rounded-3 p-2">
<% if $Language != "language-auto" %>
<pre>
<code class=$Language>
$Content
</code>
</pre>
<% else %>
<pre>
<code>
$Content
</code>
</pre>
<% end_if %>
</div>
</div>

Kompetenzen