WebStencils

Aus RAD Studio
Wechseln zu: Navigation, Suche

In RAD Studio Version 12.2 wurde WebStencils eingeführt, eine serverseitige, skriptbasierte Integration und Verarbeitung von HTML-Dateien für die WebBroker- und RAD Server-Technologien. Mit diesem flexiblen Feature können Sie moderne Websites auf Grundlage beliebiger JavaScript-Bibliotheken entwickeln, die durch die von einer serverseitigen RAD Studio-Anwendung extrahierten und verarbeiteten Daten unterstützt werden. Damit können Sie Websites erstellen, die voll und ganz Ihren speziellen Anforderungen genügen.

WebStencils soll helfen, die Navigation in Websites durch Nutzung von Webtechnologien (WebBroker, DataSnap, RAD Server) und serverseitigem Scripting zu unterstützen. Beispielsweise können Sie WebStencils einsetzen, um HTML-Seiten mit Standardtools zu erstellen und beliebige CSS- und JavaScript-Bibliotheken zu übernehmen. Dabei bleibt die Möglichkeit erhalten, Daten aus den von der Anwendung generierten Seiten hinzuzufügen, wie beispielsweise das Ergebnis einer Datenbankabfrage.

Zudem kann WebStencils eine gute Grundlage für HTMX als Webentwicklungslösung sein. HTMX-Seiten können von der serverseitigen Codegenerierung profitieren und sich zur Inhaltsaktualisierung in REST-Server einklinken. Delphi-Webtechnologien bieten die Seitengenerierung und REST-APIs auf einem sehr hohen Qualitätsniveau.

WebStencil-Syntax

Die WebStencils-Skriptsprache in RAD Studio hat eine einfache Syntax, die auf zwei Elementen basiert:

  • Dem Symbol @
  • Geschweiften Klammern { }

Verwenden des Symbols @

WebStencils verwendet das Symbol @ als Sondermarker anstelle von HTML/XML-Tags oder anderen Notationen. Dem Symbol @ folgt:

  • Der Name eines Objekts oder Felds.
  • Ein spezielles Verarbeitungsschlüsselwort.
  • Ein weiteres @-Symbol.
    Tipp: Die Verwendung des Symbols @ ist flexibler. Sie müssen es daher in einigen Anwendungsszenarien, wie in Headern, nicht duplizieren.

Der allgemeine Wertzugriff basiert auf der Punktnotation als object.value, daher sind Tags wie die folgenden vorhanden:

@object.value

Der Name des Objekts ist ein symbolischer lokaler Name, der mit einem tatsächlichen Objekt einer Serveranwendung übereinstimmen kann, das mit einem Registrierungsprozess der Skriptausführung zugewiesen ist. Es kann auch im Code bei der Verarbeitung der Ereignisbehandlungsroutine OnGetValue aufgelöst werden kann.

Der Wert besteht aus dem Namen der Eigenschaft (bei einem generischen Objekt), dem Namen eines Felds (wenn das Objekt von TDataSet geerbt ist) und einem String, der in der dem Prozessor zugeordneten Ereignisbehandlungsroutine OnGetValue übergeben wird.

Hinweis: Die Ausgabe der von WebStencils verarbeiteten Werte wird mit der Methode TNetEncoding.HTML.Encode verschlüsselt. Sie können die Verschlüsselung mit der Syntax @\value unterdrücken.

Zugreifen auf verschachtelte Objekte und Datenmengen

Sie können mit dem Symbol @ auch auf verschachtelte Objekte und Datenmengen in den folgenden Szenarien mit der vorgeschlagenen Syntax zugreifen:

  • Verschachtelte Klassen und Objekte:
    @MyObject.SubObject.ProperyName
    
  • Tabellen in verschachtelten Datenmengen:
    @MyDataSet.DataSetField.SubField
    

Verwenden von geschweiften Klammern für Blöcke {}

Die zweite Notation verwendet geschweifte Klammern, { und }, um konditionale oder wiederholte Blöcke zu kennzeichnen.

Andere Verwendungen von geschweiften Klammern in der Quellcodedatei (der HTML-Datei) werden ignoriert. Mit anderen Worten: Die geschweiften Klammern werden nur verarbeitet, wenn sie nach einer speziellen konditionalen WebStencils-Anweisung verwendet werden.

Zugreifen auf Werte in der Punktnotation

Sehen Sie sich das folgende HTML-WebStencils-Fragment als Beispiel an:

<h2>GetValue</h2>
<p>Value obtained from data: @data.name</p>
<p>Value obtained with request @@data.value: @data.value</p>

Die Symbole @@ werden übersprungen (es wird ein einzelnes @ in der Ausgabe erwartet) und nur die einzelnen lösen die Verarbeitung aus. Außerdem müssen beide Symbole, der Objektname und der Wertname, gültige Delphi-Bezeichner sein und dürfen keine Leerzeichen enthalten oder mit Zahlen beginnen. Unterstriche und Zahlen als Teil des gleichen Namens werden akzeptiert.

Ereignisbehandlungsroutine OnValue

Es ist möglich, Daten anhand einer Komponente mit der Ereignisbehandlungsroutine OnValue bereitzustellen. Zum Beispiel:</br> Delphi:

procedure TWebModule13.WebStencilsValueFromEventValue(Sender: TObject;
  const ObjectName, FieldName: string; var ReplaceText: string; 
  var Handled: Boolean)
begin
  if SameText (ObjectName, 'data') then
  begin
    Handled := True;
    ReplaceText := 'You requested ' + FieldName;
  end;
end;

Im obigen Codebeispiel prüft der Code nur den Objektnamen (den ersten Teil des Symbols vor dem Punkt). Es wird aber empfohlen, auch den FieldName (das Symbol nach dem Punkt) zu prüfen.


C++:

void __fastcall TWebModule13::WebStencilsValueFromEventValue(TObject *Sender,
  const String ObjectName, const String FieldName, String &ReplaceText, bool &Handled)
{
  if (SameText(ObjectName, "data"))
  {
    Handled = true;
    ReplaceText = "You requested " + FieldName;
  }
}

Im obigen Beispiel ist String der mit Delphi kompatible UnicodeString in C++Builder. SameText ist eine String-Vergleichsfunktion ohne Berücksichtigung der Groß-/Kleinschreibung, die von SysUtils bereitgestellt wird. Zum Schluss werden &ReplaceText und &Handled per Referenz übergeben, um Änderungen zu ermöglichen und dem var-Verhalten von Delphi zu entsprechen.

Verwenden eines Objekts im Skriptvariablen-Dictionary

Der alternative Ansatz besteht darin, die Werte mithilfe eines Objekts bereitzustellen. In diesem Fall müssen Sie das Objekt konfigurieren und mit dem Produzenten der Aktion verknüpfen.

Dies ist ein vollständiges Beispiel, in dem von einer TMyObject-Klasse mit der String-Eigenschaft "Name" ausgegangen wird:</br> Delphi:

procedure TWebModule1.WebModule1WebActionItem2Action(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  WebStencilsProcessor1.InputLines.Text := '''
    <h2>GetValue</h2>
    <p>Value obtained from data: @world.Name</p>
  ''';
  var MyObj := TMyObject.Create();
  MyObj.Name := 'Hello hello';
  WebStencilsProcessor1.AddVar('world', MyObj, True);
  Response.Content := WebStencilsProcessor1.Content;
  Handled := True;
end;

Die Ausgabe des obigen Beispiels lautet:

"Value obtained from data: Hello Hello"

Beachten Sie, dass das Objekt mit dem Namen 'world' registriert ist, der später in dem WebStencils-Skript verwendet wird.


C++:

void __fastcall TWebModule1::WebModule1WebActionItem2Action(TObject *Sender,
  TWebRequest *Request, TWebResponse *Response, bool &Handled)
{
  WebStencilsProcessor1->InputLines->Text =
    "<h2>GetValue</h2>\n"
    "<p>Value obtained from data: @world.Name</p>";

  TMyObject *MyObj = new TMyObject();
  MyObj->Name = "Hello hello";

  WebStencilsProcessor1->AddVar("world", MyObj, true);

  Response->Content = WebStencilsProcessor1->Content;
  Handled = true;
}

Ausdrücke

Im Folgenden finden Sie die unterstützten Ausdrücke:

  • @ (<Ausdruck>): Variablenmarker. Der Ausdruck muss in Klammern eingeschlossen sein.
  • @if (<Ausdruck>): "if"-Befehl. Der Ausdruck muss in Klammern eingeschlossen sein.
  • @Import (<Ausdruck>), @LayoutPage (<Ausdruck>), @AddPage (<Ausdruck>): "Datei"-Befehle. Der Ausdruck muss in Klammern eingeschlossen sein.

Das folgende Beispiel zeigt nur die Unterschiede der obigen Optionen:

WebStencilsProcessor1.InputLines.Text := '''
    <h2>GetExpression</h2>
    <p>Value obtained from data: @(world.value*2)</p>
  ''';
  MyObj.Value := 2;

Das Ergebnis in der Ausgabe lautet:

"Value obtained from data: 4"

Zusätzlich zu einfachen Ausdrücken können Sie das System durch benutzerdefinierte Funktionsaufrufe erweitern. Hier ist ein Codebeispiel, das eine Concat-Funktion registriert, die zwei String-Parameter erhält:</br> Delphi:

uses
  System.Bindings.EvalProtocol, System.Bindings.Methods;

  TBindingMethodsFactory.RegisterMethod(
   TMethodDescription.Create(
    MakeInvokable(function(Args: TArray<IValue>): IValue
    begin
     Result := TValueWrapper.Create(
      Args[0].GetValue.AsString + Args[1].GetValue.AsString);
    end),
    'Concat', 'Concat', '', True, '', nil));

In einem WebStencils-Skript können Sie es in einem Ausdruck wie folgt verwenden:

@(Concat('aaa', 'bbb']]


C++:

#include <System.Bindings.EvalProtocol.hpp>
#include <System.Bindings.Methods.hpp>
#include <System.Rtti.hpp>
#include <System.SysUtils.hpp>

using namespace System::Bindings::EvalProtocol;
using namespace System::Bindings::Methods;
using namespace System::Rtti;

class TValueWrapper : public TInterfacedObject, public IValue
{
private:
    TValue FValue;

public:
    __fastcall TValueWrapper(const TValue &AValue) : FValue(AValue) {}

    virtual TValue __fastcall GetValue() { return FValue; }

    // Implement other IValue methods as needed...
};

void RegisterCustomBindingMethod()
{
    TBindingMethodsFactory::RegisterMethod(
        new TMethodDescription(
            MakeInvokable([](const TArray<IValue*> &Args) -> IValue*
            {
                String s1 = Args[0]->GetValue().ToString();
                String s2 = Args[1]->GetValue().ToString();
                return new TValueWrapper(TValue::From<String>(s1 + s2));
            }),
            "Concat", "Concat", "", true, "", nullptr));
}


Switch-Anweisung

Außer der @if-Anweisung können Sie auch die Anweisungen @switch oder @case verwenden.</br> Hier ist ein Syntaxbeispiel:

@switch(@user.role) {
  @case "admin" { 
    <div>Admin Panel</div>
  } @case "moderator" { 
    <div>Moderator Tools</div>
  } @default { 
    <div>Regular User View</div>
  }
}

Beachten Sie für das obige Beispiel, dass:

  • Case-Werte Literale oder Ausdrücke mit @(Ausdruck) sein können.
  • Nur der erste übereinstimmende Case ausgeführt wird.
  • Die Verwendung von @default optional ist und ausgeführt wird, wenn kein Case zutrifft.

Verwenden einer Datenmenge

Die alternative Option ist die Verwendung eines aktuellen Datensatzes einer Datenmenge anstelle eines Objekts. In diesem Fall könnte Ihr Code wie folgt aussehen:</br> Delphi:

procedure TWebModule13.WebModule13waCompanyAction(Sender: TObject;
    Request: TWebRequest; Response: TWebResponse;
    var Handled: Boolean];
  begin  
   ClientDataSet1.Open;
   if not WebStencilsValueFromObject.InVars  ('dataset'] then
    WebStencilsValueFromObject.AddVar(
      'dataset', ClientDataSet1, False]; // False = do not destroy
  Response.Content := WebStencilsValueFromObject.Content;
  ClientDataSet1.Close;
end;


C++:

void __fastcall TWebModule13::WebModule13waCompanyAction(TObject *Sender,
  TWebRequest *Request, TWebResponse *Response, bool &Handled)
{
  ClientDataSet1->Open();

  if (!WebStencilsValueFromObject->InVars("dataset"))
  {
    WebStencilsValueFromObject->AddVar("dataset", ClientDataSet1, false); // false = do not destroy
  }

  Response->Content = WebStencilsValueFromObject->Content;

  ClientDataSet1->Close();
}

Das übereinstimmende HTML kann Referenzen zu anderen Feldern des Datensatzes enthalten. Eine Beispielausgabe finden Sie unten:

<div class="list-group w-50">
  @foreach dataset {
    <a href="/[email protected]" class="list-group-item  
        list-group-item-action" aria-current="true">
    <div class="d-flex w-100 justify-content-between">
      <h5 class="mb-1">@loop.company</h5>
      <small>@loop.country</small>
    </div>
    <p class="mb-1">@loop.city</p>
    <small>@loop.state</small>
  </a>
}

Zugreifen auf Eigenschaften einer Datenmenge

Die Notation @ von WebStencils für eine Datenmenge ermöglicht zusätzlich zum Feld den Zugriff auf die Datenmengeneigenschaften. Sie können @data.RecordCount verwenden, um auf die Eigenschaft RecordCount zuzugreifen und im Falle eines Konflikts können die Datenmengenfelder Vorrang vor den Eigenschaften mit demselben Namen erhalten.

Dies umfasst auch den Zugriff auf Feldinformationen wie:

@foreach field in customers.fields

Und umfasst auch den Zugriff auf Feldeigenschaften:

@foreach customer in customers {
    @customer.address.visible
    @customer.phone.displaylabel
}

Verwenden von Modulvariablen

Alternativ können Sie zum Registrieren eines bestimmten Objekts für einen WebStencilsProcessor ein Modul mit mehreren Objekten hinzufügen. Ein "Modul" in diesem Kontext bezieht sich auf eine Sammlung zugehöriger Objekte oder Funktionen. Für jedes Feld oder jede Eigenschaft des Moduls kann das Attribut [WebStencilsVar] angegeben werden. Damit können Sie festlegen, wie der WebStencilsProcessor die Daten verarbeiten soll.

Angenommen, Ihr Datenmodul hat eine FDMemTable1-Komponente mit dem Typ TFDMemTable, die als [WebStencilsVar] markiert ist, und das Feld LastName enthält. Dann können Sie beispielsweise schreiben:

  WebStencilsProcessor1.InputLines.Text := '''
    <h2>GetTableData</h2>
    <p>Value obtained from table: @(FDMemTable1.LastName)</p>
  ''';
  WebStencilsProcessor1.AddModule(self);

Das obige Beispiel gibt den Wert von LastName für den ersten Datensatz zurück. Verwenden Sie eine @for-Schleife, um all Datensätze anzuzeigen.

Verwenden zusätzlicher Variablen

Fügen Sie der Skript-Engine zusätzliche Variablen außerhalb der Objekt- und Datenmengenmodelle hinzu. Anstatt eine bestimmte Datenstruktur hinzuzufügen, bietet dieser Mechanismus eine anonyme Methode, mit der Sie eine benutzerdefinierte Suche in eine benutzerdefinierte Datenstruktur implementieren können. Hier sind die Methoden dafür:

TWebStencilsDataVars.Add(LookupFunc), AddInitFunc(LookupFunc)
TWebStencilsProcessor.AddVar(LookupFunc), AddInitFunc(LookupFunc)
TWebStencilsEngine.AddVar(LookupFunc), AddInitFunc(LookupFunc)

Sehen Sie sich dazu das folgende Beispiel an:

type
  TMap = TDictionary<string, string>;
var
  LDict: TMap;
begin
  LDict := TMap.Create;
  LDict.Add('APP_VERSION', '1.0.0');
  LDict.Add('APP_NAME', 'WebStencils demo');
  LDict.Add('COMPANY_NAME', 'Embarcadero Inc.');
  LDict.Add('DEBUG_MODE', 'True');

  FWebStencilsProcessor.AddVar('env', LDict, True,
    function(AVar: TWebStencilsDataVar; const APropName: string; 
      var AValue: string): Boolean
    begin
      Result := TMap(AVar.TheObject).TryGetValue(APropName.ToUpper, AValue);
    end);

Sie können sie auch in einer Vorlage wie folgt verwenden:

 @env.APP_NAME - @env.APP_VERSION
 @if env.DEBUG_MODE {
   <div>Debug mode active</div>
 }

WebStencil-Schlüsselwörter

Die WebStencils-Engine verwendet die folgenden Sonder-Tags als Schlüsselwörter (beachten Sie, dass Sie diese Namen nicht als Skriptvariablen verwenden dürfen).

Schlüsselwort Beschreibung
@query Verwenden Sie dieses Schlüsselwort zum Lesen von HTTP-Abfrageparametern.
@page Dieses Schlüsselwort ermöglicht den Zugriff auf den Seitennamen und die URL-Argumente (weitere Informationen finden Sie bei der Eigenschaft PathTemplate). Mit einem dieser Werte können Sie auf den tatsächlichen Anforderungs-URL-Pfad zugreifen:
  • @page.request_path
  • @page.request_segment
@lang Verwenden Sie dieses Schlüsselwort als Übersetzungsunterstützung. Es löst ein separates OnLang-Ereignis anstatt des OnValue-Ereignisses aus.
@* .. *@ Verwenden Sie dieses Schlüsselwort zum Hinzufügen von Kommentaren zu dem Skript. Die Kommentare werden im Ergebnis-HTML unterdrückt.
@if object.value { … } [@else { … }] Führt den folgenden Block zwischen den geschweiften Klammern nur aus, wenn der Wert true ist.
@if (<expression>) Verwenden Sie dieses Schlüsselwort, um Inhalt konditional zu rendern. Wenn der Ausdruck zu true ausgewertet wird, wird der zugehörige Inhalt in die Ausgabe einbezogen. Ansonsten wird er unterdrückt.
@if not object.value { ... } [@else { … }] Führt den folgenden Block zwischen den geschweiften Klammern aus, wenn der Wert nicht true ist.
Zum Beispiel:
 @if obj1.ValueBelowTen {
	  <p>@obj1.name <span> has a value of </span> @obj1.value</p>
	}
@ForEach (var object in list) { … } Führt den folgenden Block zwischen den geschweiften Klammern so oft aus, wie es Elemente im Enumerator gibt.
Unterstützt aktuell:
  • Datenmengen
  • TObjectList, das dem Prozessor-Dictionary hinzugefügt werden muss.
  • Jedes Objekt mit der Methode GetEnumerator, bei der der Enumerator einen Objektwert zurückgibt.
@ForEach object { … } Führt den folgenden Block zwischen den geschweiften Klammern so oft aus, wie es Elemente im Enumerator gibt.
Unterstützt aktuell Datenmengen und TObjectList, die als Skriptvariablen hinzugefügt werden müssen.
@loop Verwenden Sie dieses Schlüsselwort in einem Block, um das aktuelle Aufzählungselement (Liste oder Datenmenge) zu referenzieren. Gefolgt vom Namen einer Eigenschaft oder eines Felds, ohne einen Namen für die Objekte zu verwenden.
@Import Ermöglicht es Ihnen, eine externe Datei an einer bestimmten Stelle der externen Datei zusammenzuführen, wobei für den Dateinamen die Erweiterung .HTML angenommen wird.
Das Format ist:
@import filename [ {<alias1> = <var1> [..., <aliasN> = <varN>]} ]
@Scaffolding Platzhalter für Scaffolding. Ein Mechanismus zur dynamischen Generierung von HTML basierend auf der Datenstruktur der Anwendung (Objekteigenschaften oder Datenbankfelder). Das auf der Serverseite generierte HTML kann auch andere Tags für den Zugriff auf die Daten enthalten.
Das folgende Beispiel zeigt ein einfaches HTML-Layout, das von der Ereignisbehandlungsroutine OnScaffolding für jedes Feld in der Datenbank generiert wird:
procedure TWebModule1.ProcessorCompanyScaffolding(Sender: TObject;
  const AQualifClassName: string; var AReplaceText: string);
begin
  if SameText (AQualifClassName, 'Company') then
  begin
    AReplaceText := '';
    for var I := 0 to ClientDataSet1.Fields.Count -1 do
      AReplaceText := AReplaceText + '<p>'+ 
        ClientDataSet1.Fields[I].FieldName +
        ': @dataset.' + ClientDataSet1.Fields[I].FieldName + '</p>';
  end;
end;
@switch, @case, and @default Führt eine bedingte Mehrfachverzweigung durch. Es wertet einen gegebenen Ausdruck aus und gleicht ihn mit definierten @case-Werten ab, wobei der entsprechende Block gerendert wird. Die @default-Direktive wird verwendet, wenn keiner der @case-Werte übereinstimmt.
@LoginRequired Hält die Ausführung an, wenn eine Anmeldung erforderlich ist und der Benutzer nicht angemeldet ist.
@LoginRequired (<role>) Die Engine prüft, ob der Benutzer angemeldet ist, aber auch, ob für den Benutzer die spezifische Rolle aktiv ist, und sperrt die Seite entsprechend der Berechtigung.
Zum Beispiel: @LoginRequired (admin)

Import-Aliase

Das folgende Beispiel zeigt, wie Import-Aliase verwendet werden.

@import one {@o1 = @object, @d1 = @data} Hello

In diesem Code sind @object und @data tatsächliche Variablen innerhalb des Ausführungsskripts. Die Aliase @o1 und @d1 sind Skriptvariablen innerhalb des Skripts "one" und können als reguläre Variablen innerhalb dieses Skripts aufgerufen werden. Dadurch kann das Skript QA-Skriptvariablen unter verschiedenen Namen übergeben, vorausgesetzt, der vom Skript erwartete Name ist ein Alias.

WebStencils-Vorlagen: Layout und Text

Eine unverzichtbare Funktion einer Vorlagen-Engine ist die Möglichkeit, eine gemeinsam genutzte HTML-Vorlage mit dem tatsächlichen Inhalt einer Seite zusammenzuführen. Dies wird (wie in der .NET-Version) mithilfe von vier speziellen Symbolen erreicht:

  • @LayoutPage Dateiname: Dieser Befehl wird auf einer bestimmten HTML-Seite (normalerweise am Anfang) verwendet, um die Vorlagendatei anzugeben, die als Struktur für die Seite verwendet werden soll. Mehrere Seiten können dieselbe Vorlage gemeinsam verwenden, aber nicht alle Seiten in einem Projekt (auch wenn sie TWebStencilsEngine verwenden) oder einem virtuellen Ordner müssen dieselbe Vorlage verwenden.
Hinweis: Beachten Sie, dass Sie diesen Befehl nur einmal auf einer Seite verwenden sollten. Wenn Sie versuchen, mehrere @LayoutPage anzugeben, wird der Befehl durch eine Exception blockiert.
  • @RenderBody: Dieser Befehl (ohne Parameter) ist ein Platzhalter in einer Vorlagendatei, der angibt, wo der tatsächliche Inhalt einer bestimmten Seite platziert werden soll.

Im Folgenden finden Sie ein Beispiel für die Verwendung von @LayoutPage und @RenderBody:

Test.html

@LayoutPage BaseTemplate
   <h2>Page Test3</h2>
   <p>Local data param one is @page.name (the page name)</p>

BaseTemplate.html

<html lang="en">
  <head>
    <!-- Bootstrap CSS 
    <link href="https://.../bootstrap.min.css" rel="stylesheet">
  </head>
  <body>
    <nav class="navbar navbar-expand-md bg-dark mb-4">...
    <main class="container">
      <div class="bg-light p-5 rounded">
      @RenderBody
      </div>
    </main>
  </body>
</html>


Darüber hinaus können Sie einige zusätzliche Header aus dem jeweiligen Dokument in die Vorlage einfügen (z. B. eine erforderliche JavaScript-Datei, die in die Seite eingebunden werden muss, oder ein seitenbezogenes zusätzliches CSS). In diesem Fall wird der Mechanismus umgekehrt:

@ExtraHeader { ... }: Wird auf der HTML-Seite verwendet, um einen Codeblock anzugeben, der als zusätzliche Header-Information hinzugefügt werden soll.</br>Unterstützt auch die Inhaltsweitergabe durch verschachtelte Layout-Hierarchien:

    • @ExtraHeader-Blöcke, die auf Seiten definiert sind, werden automatisch über mehrere Layout-Ebenen hinweg angezeigt.
    • Der Inhalt wird in die Endausgabe eingefügt, unabhängig von Zwischen-Layouts.
    • Ermöglicht eine flexible Layout-Gestaltung mit Basis-, Zwischen- und seitenspezifischen Layouts.
  • @RenderHeader: Gibt die Vorlagendatei (normalerweise den HTML-Header-Abschnitt) an, wo der zusätzliche Header, falls verfügbar, hinzugefügt werden soll.
Hinweis: Beide Optionen sind optional.

Beispiel:

<!-- page.html -->
@extends layouts/intermediate
@ExtraHeader {
  <style>.highlight { color: green; }</style>
}

<!-- layouts/intermediate.html -->
@extends layouts/base
@ExtraHeader {
  <meta name="viewport" content="width=device-width, initial-scale=1">
}

<!-- layouts/base.html -->
<head>
  @RenderHeader
</head>

Im obigen Beispiel werden das CSS aus page.html und das Meta-Tag aus intermediate.html in die endgültige @RenderHeader-Ausgabe eingefügt.

WebStencils-Komponenten

Das WebStencils-Package installiert zwei verschiedene Komponenten: einen Prozessor mit einer einzelnen Datei und eine Engine, die einzelne Prozessoren instantiieren und eine globale Konfiguration für Standalone-Prozessoren oder für manuell verbundene bereitstellen kann.

Diese Kernkomponente kann eine HTML-Datei übernehmen, die WebStencils-Notation einbetten und sie nach der Verarbeitung der @-Tags in reines HTML konvertieren.

Die Klasse TWebStencilsProcessor verarbeitet eine einzelne Datei (in der Regel mit einer HTML-Erweiterung) und die zugehörige Vorlage, falls vorhanden. Der Prozessor kann eigenständig verwendet und zu TWebActionItem.Producer zugewiesen werden oder er kann erstellt und von TWebStencilsEngine als Post-Prozessor von Textdateien aufgerufen werden, die von einem Datei-Dispatcher zurückgegeben werden.

Komponente WebStencilsEngine

Die Komponente engine kann in zwei Szenarien verwendet werden:

  • Um eine oder mehrere WebStencilsProcessor-Komponenten zu verbinden und gemeinsame Einstellungen und gemeinsames Verhalten bereitzustellen.
  • Um WebStencilsProcessor-Komponenten zu erstellen und um nur diese Komponente in Webmodulen zu platzieren.

Automatische Integration in Sitzungen

Wenn verfügbar, kann WebStencils automatisch in Websitzungen integriert werden. Dazu ist keine zusätzliche Einrichtung erforderlich. Das funktioniert automatisch, wenn WebRequest.Sessions vorhanden ist.

Auf die Sitzungsdaten kann über @session.property zugegriffen werden. Alle Objekte in WebRequest.Session.DataVars werden automatisch als Vorlagenvariablen registriert. UserLoggedIn und UserRoles werden ebenfalls automatisch aus WebRequest.Session.User gefüllt.

Dazu ein Beispiel:

@if session.Authenticated { 
  <div>User authenticated</div>
  @session.sessionid
}

@if session.UserHasRole(‘admin’) { 
  <div>User is an Admin</div>
}

Sicherheits-Positivliste

Aus Sicherheitsgründen implementiert WebStencils einen Positivlistenmechanismus für Eigenschaften, um die Offenlegung sensibler Informationen, wie Verbindungsstrings für Datenbanken, zu verhindern. Standardmäßig kann nur auf sichere Eigenschaften zugegriffen werden. Im Folgenden finden Sie die sicheren Eigenschaften:

  • Für TDataSet: Active, FieldByName, First, Last, Next, Prior, Bof, Eof, FieldCount, Fields, Found, RecordCount, RecNo.
  • Für TStrings: Contains, ContainsName, IndexOf, IndexOfName, CommaText, Count, IsEmpty, DelimitedText, Names, KeyNames, Values, ValueFromIndex, Strings, Text.

Anpassen der Positivliste

Benutzer können die Sicherheits-Positivliste mit der Eigenschaft TWebStencilsProcessor.Whitelist anpassen. Mit der Konfigurationsmethode können Benutzer die zugelassenen und blockierten Member festlegen. Siehe das folgende Beispiel:

procedure Configure(const AClass: <PTypeInfo, TClass, TObject>; 
                    const AAllowedMembers: TArray<string>;
                    const ABlockedMembers: TArray<string>; 
                    AReset: Boolean);
  • AClass: Der zu konfigurierende PTypeInfo/TClass/TObject-Typ (z. B. TDataSet, TStrings).
  • AAllowedMembers: Ein Array mit Eigenschafts- oder Methodennamen, die der Benutzer zulassen möchte.
  • ABlockedMembers: Ein Array mit Eigenschafts- oder Methodennamen, die der Benutzer blockieren möchte.
  • AReset: True bei der Verwendung zum Ersetzen einer vorhandenen Positivliste oder False zum Hinzufügen zur Liste.

Hier ist ein Beispiel dazu, wie Sie einer vorhandenen Positivliste weitere zulässige Member hinzufügen:

TWebStencilsProcessor.Whitelist.Configure(TMyClass, 
  ['CustomProp'], nil, False);

Das folgende Beispiel zeigt, wie Sie eine Positivliste vollständig überschreiben (AReset = True):

TWebStencilsProcessor.Whitelist.Configure(TDataSet, 
  ['RecordCount', 'RecNo'], nil, True);

Dieses Beispiel zeigt, wie bestimmte Member blockiert werden:

TWebStencilsProcessor.Whitelist.Configure(MyObject, 
  nil, ['CustomProp'], False);

Die Positivliste ist global für die Anwendung und gilt für die gesamte WebStencils-Verarbeitung.

WebStencils mit RAD Server verwenden

Die WebStencils-Vorlagenbibliothek kann auch in RAD Server-Anwendungen verwendet werden. Es wird empfohlen, die vorhandene TEMSFileResource-Komponente mit einer TWebStencilsEngine-Komponente zu kombinieren. Die erste ordnet das Dateisystem zu und die zweite verwaltet die HTTP-Zuordnung sowie die Vorlagenverarbeitung. Die Komponenten werden mit der Eigenschaft Dispatcher der WebStencil-Engine verbunden.

Das folgende Beispiel zeigt die Konfiguration, mit der zwei Komponenten zu einem RAD Server-Webmodul hinzugefügt werden:

 object html: TEMSFileResource
    PathTemplate = '..\..\html\{filename}'
  end
  object WebStencilsEngine1: TWebStencilsEngine
    Dispatcher = html
    PathTemplates = <
      item
        Template = '/'
        Redirect = '/test1.html'
      end
      item
        Template = '/list'
        Redirect = '/companylist.html'
      end
      item
        Template = '/company'
        OnPathInit = WebStencilsEngine1PathTemplates2PathInit
      end
      ...>
  end

Mit PathTemplates werden eingehende URLs zu tatsächlichen Dateien zugeordnet. So sieht die Konfiguration beim Entwurf aus:

=link

Außerdem muss die übergeordnete Zuordnung im Datenmodul konfiguriert werden:

type
  [ResourceName('testfile')]
  TTestfileResource1 = class(TDataModule)
    [ResourceSuffix('./')]
    [ResourceSuffix('get', './')]
    [EndpointProduce('get', 'text/html')]
    html: TEMSFileResource;

Um mehrere verschiedene Pfade (im Vergleich zu dem oben dargestellten) zuzuordnen, fügen Sie zusätzliche TEMSFileResource-Komponenten hinzu. Die TWebStencilsEngine-Komponente kann nur einen Dispatcher in der entsprechenden Eigenschaft angeben. Verknüpfen Sie weitere Dispatcher mit dem folgenden Code:

AddProcessor(html2, WebStencilsEngine1);

Siehe auch

Überblick über RAD Server