# Tag

Das Framework kann durch Plugins um Batix-Tags (`<bx:tagname>`) erweitert werden, welche dann in normalen Quelltexten wie Komplettseiten oder Textbausteinen verwendet werden können.

```kotlin
fun registerTag(tagInfo: TagInfo)
```

Es gibt zwei Arten von Tags: Frontend- und Backend-Tags. Der Unterschied besteht darin, dass sich Backend-Tags in der Verwaltung darstellen oder dort konfiguriert werden können (wie z. B. `<bx:text>` oder `<bx:containerfilter>`), Frontend-Tags hingegen können dies nicht.

## Frontend-Tags

Frontend-Tags werden mithilfe von `TagInfo.frontend` registriert und müssen von `com.batix.plugins.PluginFrontendTag` abgeleitet sein. Es reicht im einfachsten Fall, die Methode `addFrontendSourceText(StringBuffer)` zu überschreiben. An den `StringBuffer` hängt man die Ausgabe an und gibt diesen am Ende wieder zurück.

```kotlin
registerTag(TagInfo.frontend("tagname", MyFrontendTag::class.java, null))
```

<p class="callout warning">**Injection Vulnerability**  
Es müssen (HTML-)Steuerzeichen passend encoded werden, um Injectionlücken zu vermeiden.</p>

Es empfiehlt sich daher die Methode `writeEncodedOutput(String, StringBuffer)` zu benutzen. Dieser übergibt man als ersten Parameter den gewünschten (uncodierten) Ausgabetext und reicht als zweiten Parameter den `StringBuffer` durch, den man übergeben bekommen hat. Die Methode sorgt automatisch dafür, dass entsprechend der aktuellen Frontendseite das passende Encoding (z. B. htmlencode bei HTML-Seiten) gewählt wird. Außerdem unterstützt das Tag damit automatisch den Parameter `encode` (also z. B. `<bx:tagname encode="plain" />`).

## Backend-Tags

Backend-Tags werden mithilfe von `TagInfo.backend` registriert und müssen von `com.batix.plugins.PluginBackendTag` abgeleitet sein. Hier müssen neben `addFrontendSourceText(StringBuffer)` noch die Methoden `getDataTable()` und `addAdminSourceText(StringBuffer)` überschrieben werden.

```kotlin
registerTag(TagInfo.backend("tagname", MyBackendTag::class.java, null))
```

Der erste Parameter (`"tagname"`) ist dabei der Name des Tags, wie er dann auch hinter `<bx:` verwendet wird. Als zweiter Parameter wird die implementierende Klasse übergeben. Der letzte Parameter ist ein optionales String-Array, falls das Tag nur für bestimmte Projekte (anhand webdir) zur Verfügung stehen soll.

Ist das Tag offen verwendbar (also z. B. `<bx:tagname>etwas Inhalt...</bx:tagname>`), kann der Inhalt (*Body*) mittels `computeBody()` ausgeführt und das Ergebnis ausgelesen werden. Eventuelle Batix-Tags im Body werden damit auch evaluiert.

## Parameter

Einem Tag können im Quelltext Parameter übergeben werden.

```html
<bx:tagname mode="short" maxlen="5" pretty />
```

Diese Parameter können mit den `get*Parameter(key: String)`-Methoden ausgelesen werden – `key` ist der Name des Parameters. Mit `containsParameter(key: String)` kann festgestellt werden, ob ein Parameter angegeben wurde oder nicht.

```kotlin
fun getStringParameter(key: String): String?
fun getStringParameter(key: String, defaultValue: String?): String?

fun getIntParameter(key: String): Integer
fun getIntParameter(key: String, defaultValue: Integer): Integer

fun getBooleanParameter(key: String): Boolean
```

## Backend-Tag Speicherung

Backend-Tags stellen ein Eingabeelement für Redakteure oder Admins bereit. Dafür muss im Quellcode ein sogenannter Titel am Tag vergeben werden. Bei `<bx:tagname.Anrede />` ist der Titel beispielsweise "Anrede". Dieser wird dem Benutzer im Backend angezeigt.

Das bedeutet, dass die vom Benutzer getätigten Eingaben in der Datenbank gespeichert werden müssen. Die Methode `getDataTable()` teilt dem Framework mit, in welcher Tabelle die Daten zu speichern sind. Für kurze, einzeilige Texte ist das "EZT", für längere Texte "MZT". Der entsprechende Wert ist von `getDataTable()` einfach als String zurückzugeben.

Die Methode `addAdminSourceText(StringBuffer)` ist für das Rendern des entsprechenden Eingabefeldes zuständig. Für kurze Texte kann das ein `<input type="text">` sein. Der Name des Inputs muss als Prefix die Tabelle (gleicher Wert wie bei `getDataTable()`), einen Punkt als Separator und als Suffix den Titel des Tags enthalten (dieser ist als Feld `titel` verfügbar). Er muss also beispielsweise "EZT.Anrede" lauten. Ist bereits ein Wert gespeichert, ist das Feld `dataId` gefüllt. Dessen Wert muss dann noch, inklusive einem weiteren Punkt, an den Name angehangen werden.

<p class="callout info">**Vorgefertigte Methoden**  
Als Best-Practice empfiehlt sich die Verwendung der Methoden `appendAdminHeadline(StringBuffer)` und `appendPublishStatus(StringBuffer)`, um eine konsistente Ausgabe des Titels und des Veröffentlichungsstatus zu erreichen.</p>

Der Aufruf `getData("INHALT")` gibt den aktuell in der Datenbank gespeicherten Wert zurück. Dieser kann dann zur Ausgabe im Frontend sowie zur Vorbefüllung des Eingabefelds im Backend verwendet werden.

## Beispiel

### Frontend-Tag

Das Tag wird in der Plugin-Hauptklasse mithilfe von `TagInfo.frontend` registriert.

```kotlin
override fun load() {
  registerTag(TagInfo.frontend("unixtime", UnixTimeTag::class.java, null))
}
```

Dieses Beispiel-Tag gibt den aktuellen Epoch-Timestamp aus.

```kotlin
import com.batix.plugins.PluginFrontendTag
import com.batix.tags.BatixTagData
import java.time.Instant

class UnixTimeTag(data: BatixTagData?) : PluginFrontendTag(data) {
  override fun addFrontendSourceText(sb: StringBuffer): StringBuffer {
    val time = Instant.now().epochSecond
    writeEncodedOutput(time.toString(), sb)
    return sb
  }
}
```

Der Aufruf im Quellcode ist minimal.

```html
<bx:unixtime />
```

Die Ausgabe im Frontend ist dann z. B. *1584620787*.

### Backend-Tag

In der Plugin-Hauptklasse wird das Tag mit `TagInfo.backend` registriert.

```kotlin
override fun load() {
  registerTag(TagInfo.backend("formattedtime", FormattedTimeTag::class.java, null))
}
```

Die Tag-Klasse implementiert die Frontend-Logik sowie die Anzeige des Eingabeelements im Backend.

```kotlin
import com.batix.Tools
import com.batix.plugins.PluginBackendTag
import com.batix.tags.BatixTagData
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*

class FormattedTimeTag(data: BatixTagData?) : PluginBackendTag(data) {
  override fun addFrontendSourceText(sb: StringBuffer): StringBuffer {
    // Backendeingabe lesen
    val pattern = getData("INHALT") as String? ?: "dd.MM.yyyy HH:mm:ss"

    // Parameter aus Quelltext lesen
    val locale = Locale.forLanguageTag(getStringParameter("locale", "de-DE"))

    val now = LocalDateTime.now()
    val formatter = DateTimeFormatter.ofPattern(pattern, locale)
    writeEncodedOutput(formatter.format(now), sb)
    return sb
  }

  override fun getDataTable(): String {
    return "EZT"
  }

  override fun addAdminSourceText(sb: StringBuffer): StringBuffer {
    val inhalt = getData("INHALT") as String? ?: ""

    appendAdminHeadline(sb)
    appendPublishStatus(sb)

    var inputName = "$dataTable.$titel"
    if (dataId != null && dataId != "del") {
      inputName += ".$dataId"
    }

    sb.append("""<input type="text" name="${Tools.htmlEncode(inputName)}" """)
    sb.append("""value="${Tools.htmlEncode(inhalt)}">""")

    return sb
  }
}
```

Im Quelltext wird das Tag dann inklusive Titel verwendet.

```html
<bx:formattedtime.Datum_1 />

<bx:formattedtime.Datum_2 locale="en-US" />
```

In der Verwaltung können Eingaben getätigt werden.

![tag-beispiel.png](https://batix.help/uploads/images/gallery/2025-05/scaled-1680-/rJlnHilQYC8xvdEX-tag-beispiel-png.png)

Im Frontend wird dann z. B. folgender Text ausgegeben:

```
13:28

19. March
```