AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Delphi-PRAXiS - Lounge Delphi-News aus aller Welt RAD Studio Web Development Reimagined with the WebStencils Template Engine
Thema durchsuchen
Ansicht
Themen-Optionen

RAD Studio Web Development Reimagined with the WebStencils Template Engine

Ein Thema von DP News-Robot · begonnen am 18. Sep 2024
Antwort Antwort
Benutzerbild von DP News-Robot
DP News-Robot

Registriert seit: 4. Jun 2010
15.392 Beiträge
 
#1

RAD Studio Web Development Reimagined with the WebStencils Template Engine

  Alt 18. Sep 2024, 14:10
WebStencils main goal*is to significantly extend the existing web technologies in RAD Studio (WebBroker, DataSnap, RAD Server) by providing server-side scripting and turning RAD Server from a Web Service engine into a Web Site and Web Service tool.*This means the ability to create HTML pages with standard tools and adopt any CSS and JavaScript libraries, while retaining the ability to add data from the generated pages coming from the application, like the result of a database query or any other complex data processing.*

In other words the main goal is to help with navigational and interactive websites: A blog, an online catalog, an online ordering system, a reference like a dictionary, and a wiki. These are all examples of navigational websites. In addition, WebStencils can be a good foundation for HTMX as a solution for web development. The two technologies go nicely together. HTMX pages can benefit from server-side code generation and hook into REST servers regarding content updates. Delphi web technologies can offer page generation and REST APIs at a very high-quality level.

From PageProducer to WebStencilsProcessor

Historically, the WebBroker and DataSnap libraries used the PageProducer component and derived ones to customize the HTML returned by a web server application. The processing was very limited and there was no simple way to have a shared template for the website pages. Also, the tag-based notation () wasn't very easy to use. WebStencils offers a different notation (the previous tag will become*@custom.value) that's easier to write and maintain into a complex HTML page, adds conditional and looping statements, and introduces a template and include mechanisms.

At the same time, the new WebStencilsProcessor components is a drop-in replacement for a PageProducer, as it implements the same interface and can be used in a WebBroker or DataSnap WebAction. You can add this component to a WebModule (the design-time data modules used by RAD Studio web applications), hook it to an action, and you'll be good to get started with it. Before I get to a demo, though, let's go over the syntax and a few other key elements of WebStencils.

This is an example of the WebStencilsProcessor component connected to an action in WebBroker:



The WebStencils Syntax

The WebStencils scripting language in RAD Studio has a rather simple syntax based on two elements:

  • The*@ symbol*as a special marker you add to HTML. The @ symbol is followed by:
    • The name of an object or field.
    • A special processing keyword (like*foreach, if, layoutpage, loginrequired, loop, renderbody, include, query).
    • Another @ to output an actual @
  • Curly braces { }*for optional or repeated block, used by conditional statements and loops
Accessing an Object Value

The general value access is based on a dot notation as* @myobject.value . What does this stand for?

The name of the object*(myobject)*is*a symbolic local name. It can be define in multiple ways:

  • It can be a script variable, a symbolic named map to an actual object in your server side application and assigned to the WebStencilsProcessor before the script is executed
  • It can be a WebModule variable marked with an attribute (only in Delphi)
  • It can be resolved in code while processing an OnGetValue event handler of the specific WebStencilsProcessor component. In this case, you can look up the name in any data structure of your server application, with complete flexibility.
The name of the specific element of the object (value) can be mapped to:

  • The name of a property for the object itself
  • The name of a field if the object is a DataSet
  • A generic string passed to the OnGetValue event handler associated with the processor.
Accessing Values with the Dot Notation

Suppose you have an HTML WebStencils snippet with this code:

GetValue

Value obtained from data: @data.name

You can provide the data using a component with this event handler (the*OnValue*event):

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; In this simple case, the code checks only the object name (the first part of the symbol before the dot), but in general, you'd also want to check the FieldName, the symbol after the dot).

The alternative approach is to provide the values using an object. In this case, we must configure and associate the object with the action's producer.
</br> This is a complete example, assuming a*TMyObject*class with a*Name*string property:

procedure TWebModule1.WebModule1WebActionItem2Action(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin WebStencilsProcessor1.InputLines.Text := ''' GetValue

Value obtained from data: @world.Name

'''; var MyObj := TMyObject.Create(); MyObj.Name := 'Hello hello'; WebStencilsProcessor1.AddVar('world', MyObj, True); Response.Content := WebStencilsProcessor1.Content; Handled := True; end; The code defined the HTML template, using a Delphi multiline string, creates an object registering it as a script variable (calling*AddVar), registered with the name 'world', and executes the script by accessing to its*Content*property. The result is "Value obtained from data: Hello hello."

Using a DataSet

The alternative option is to use the current record of a dataset rather than an object. In this case (given a ClientDataSet), your initialization code might look like this:



This code registers a ClientDataSet with the name*dataset.*The matching HTML can have references to the object and some of the fields of each of the records, by using a*foreach*loop and the*@loop*WebStencils keywords to refer to the current element of the loop (that is, the current record):



This results in an output like the following output:



Templates: Layout and Body

A must-have feature of a template engine is the ability to merge a shared HTML template with the actual content of a page. This is accomplished using:

  • @LayoutPage*filename : This command is used in a specific HTML page (generally at the top) to indicate which template file to use as the structure for the specific page. Multiple pages can share the same template, but not all pages in a project (even using TWebStencilsEngine) or a virtual folder need to use the same template. Notice you should use this only once on a page. If you attempt to use more than one @LayoutPage, it is blocked by an exception.
  • @RenderBody : This command (with no parameters) is a placeholder in a template file that indicates where to place the actual content of a specific page.
Here is an example of the use of*@LayoutPage*and*@RenderBody*in a specific page and a sample template. As you can see the page refers to the specific template, while the template has a general placeholder indicating where to merge in the page content. Notice that this is a reduce version of the HTML code used to generate the page shown above.

Test.html

Page Test3

Local data param one is @page.name (the page name)

BaseTemplate.html

... @RenderBody
The Two WebStencils Components

To end this quick introduction to WebStencils (full coverage will easily take a small book!) I want to mention the two different components provided by the new WebStencils package:

  • The WebStencilsProcessor Component. This core component can take an HTML file, embed the WebStencils notation, and convert it to plain HTML after processing the @ tags.
    </br> The component can processes an HTML string in memory or a file (and its associated template, if any). The processor may be *

    • Used standalone and assigned to the TWebActionItem.Producer property
    • It can be created and called automatically by TWebStencilsEngine component to execute the actual processing
  • The WebStencilsEngine Component: This is the "engine" component, which can be used in two different scenarios:
    • You can connect it to one or more WebStencilsProcessor components to provide shared settings and behavior rather than customizing each specific processor.
    • You can let it create WebStencilsProcessor components when needed and place only this component on your web modules.
Here is a WebModule with both components:



I know this isn't terribly obvious at first sight, but overall the WebStencilsProcessor is used to process a single URL (and you can have many in an app) while the WebStencilsEngine can define it's own mapping of URLs to actual files to process, offering also a mechanism to execute specific server side code for each -- but that would require another blog post.

Introducing WebStencilsEngine

Up to now in this blog post we have seen simple demos using the*Processors*component associated directly or indirectly to an action in WebBroker. This is nice, but won't scale to a Web server with dozens or hundreds of different URLs. That's why there is also an*Engine*component. But how does it work? How to you map URLs to files to process and how do you associate specific code to be executed on the server? The WebStencilsEngine component has a PathTemplates collection property you can use to associate a URL path to a specific file. This is an example in a RAD Server package:



The PathTemplates collection property serves also a different purpose, which explains why there are value listed with not mapping (like*company): You can associate to each item in the collection an event handle with initialization code to be executed when the URL matches, similarly to the code in the*OnAction*event handlers earlier. For example, the following code for the company URL checks if there is an ID parameter passed in the URL and saved in the script variables and uses it to locate a specific record in the dataset to display on the web page:



There is Way More

The WebStencils engine is fairly complex. There are more WebStencils keywords and I've covered here and dozens of properties, methods, and events in the two components. Here is the main Embarcadero DocWiki link for*WebStencils, but we are working on extensive documentation and we know that one independent experts is working on a book. I might blog more, as well.



Weiterlesen...
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:20 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz