From a692a5a37ebdb46dcaa522e5db8d2ccdf523925c Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Thu, 17 Oct 2024 17:04:03 +0200 Subject: [PATCH] Updated book search sample --- .../bin/templates/baselayout.html | 90 ++++++++++++++++--- .../bin/templates/index.html | 20 +++-- .../bin/templates/search_results.html | 82 ++++++++--------- ...VCFramework.View.Renderers.TemplatePro.pas | 6 +- sources/TemplatePro.pas | 80 ++++++++++++++--- 5 files changed, 200 insertions(+), 78 deletions(-) diff --git a/samples/instant_search_with_htmx_and_templatepro/bin/templates/baselayout.html b/samples/instant_search_with_htmx_and_templatepro/bin/templates/baselayout.html index 06df502d..6e64c189 100644 --- a/samples/instant_search_with_htmx_and_templatepro/bin/templates/baselayout.html +++ b/samples/instant_search_with_htmx_and_templatepro/bin/templates/baselayout.html @@ -1,24 +1,94 @@ + Books Search - {{block "headers"}}{{endblock}} + + +{{block "headers"}}{{endblock}} + -
- {{block "body"}}{{endblock}} +
+ {{block "body"}}{{endblock}}
-
-

- TemplatePRO {{""|version}} by Daniele Teti. - - The source code is licensed Apache 2.0. -

-
+
+

+ TemplatePRO {{:|version}} by Daniele Teti. + + The source code is licensed Apache 2.0. +

+
+ \ No newline at end of file diff --git a/samples/instant_search_with_htmx_and_templatepro/bin/templates/index.html b/samples/instant_search_with_htmx_and_templatepro/bin/templates/index.html index 6679cab3..23236cd9 100644 --- a/samples/instant_search_with_htmx_and_templatepro/bin/templates/index.html +++ b/samples/instant_search_with_htmx_and_templatepro/bin/templates/index.html @@ -1,15 +1,19 @@ {{extends "baselayout.html"}} {{block "body"}}
-
- -
-
-

⭐ DMVCFramework + HTMX :: Instant Search Demo ⭐

+
+

Instant Search Demo

+

DMVCFramework + TemplatePro + HTMX

+
+
+
+
+
-ciao
{{endblock}} \ No newline at end of file diff --git a/samples/instant_search_with_htmx_and_templatepro/bin/templates/search_results.html b/samples/instant_search_with_htmx_and_templatepro/bin/templates/search_results.html index 20a52743..c092e0c7 100644 --- a/samples/instant_search_with_htmx_and_templatepro/bin/templates/search_results.html +++ b/samples/instant_search_with_htmx_and_templatepro/bin/templates/search_results.html @@ -1,47 +1,37 @@

{{:books|count}} book/s found

- - - - - - - - - - - - {{if !books}} - - - - {{endif}} - {{for book in books}} - - - - - - - - {{endfor}} - -
IDBook TitleBook AuthorRatingGenre
- No books found -
{{:book.id|lpad,8,"0"}}{{:book.book_name}}{{:book.author_name}} - {{if book.rating|ge,1}}⭐{{endif}} - {{if book.rating|ge,2}}⭐{{endif}} - {{if book.rating|ge,3}}⭐{{endif}} - {{if book.rating|ge,4}}⭐{{endif}} - {{if book.rating|ge,5}}⭐{{endif}} - - {{:book.genre|uppercase}} -
\ No newline at end of file + +
+
+
+
ID
+
Book Title
+
Book Author
+
Rating
+
Genre
+
+
+
+ {{if !books}} +
+ No books found +
+ {{endif}} + {{for book in books}} +
+
{{:book.id|lpad,8,"0"}}
+
{{:book.book_name}}
+
{{:book.author_name}}
+
+ {{if book.rating|ge,1}}⭐{{endif}} + {{if book.rating|ge,2}}⭐{{endif}} + {{if book.rating|ge,3}}⭐{{endif}} + {{if book.rating|ge,4}}⭐{{endif}} + {{if book.rating|ge,5}}⭐{{endif}} +
+
+ {{:book.genre|uppercase}} +
+
+ {{endfor}} +
+
diff --git a/sources/MVCFramework.View.Renderers.TemplatePro.pas b/sources/MVCFramework.View.Renderers.TemplatePro.pas index 46fea981..22a08e39 100644 --- a/sources/MVCFramework.View.Renderers.TemplatePro.pas +++ b/sources/MVCFramework.View.Renderers.TemplatePro.pas @@ -179,13 +179,17 @@ begin lCompiledTemplate.AddFilter('fromquery', function (const aValue: TValue; const aParameters: TArray): TValue begin + if not aValue.IsEmpty then + begin + raise ETProRenderException.Create('Filter "fromquery" cannot be applied to a value [HINT] Use {{:|fromquery,"parname"}}'); + end; if Length(aParameters) = 1 then begin Result := Self.WebContext.Request.QueryStringParam(aParameters[0]); end else begin - Result := '(Error: Expected 1 param, got ' + Length(aParameters).ToString + ')'; + raise ETProRenderException.Create('Expected 1 param for filter "fromquery", got ' + Length(aParameters).ToString); end; end); if Assigned(FBeforeRenderCallback) then diff --git a/sources/TemplatePro.pas b/sources/TemplatePro.pas index e78c7538..2fb10c82 100644 --- a/sources/TemplatePro.pas +++ b/sources/TemplatePro.pas @@ -35,7 +35,7 @@ uses System.RTTI; const - TEMPLATEPRO_VERSION = '0.7.0'; + TEMPLATEPRO_VERSION = '0.7.1'; type ETProException = class(Exception) @@ -241,6 +241,7 @@ type procedure ProcessJumps(const aTokens: TList); procedure Compile(const aTemplate: string; const aTokens: TList; const aFileNameRefPath: String); overload; constructor Create(const aEncoding: TEncoding; const aOptions: TTProCompilerOptions = []); overload; + procedure MatchFilter(lVarName: string; var lFuncName: string; var lFuncParamsCount: Integer; var lFuncParams: TArray); public function Compile(const aTemplate: string; const aFileNameRefPath: String = ''): ITProCompiledTemplate; overload; constructor Create(aEncoding: TEncoding = nil); overload; @@ -333,7 +334,7 @@ end; procedure FunctionError(const aFunctionName, aErrMessage: string); begin - raise ETProRenderException.Create(Format('%s in function %s', [aErrMessage, aFunctionName])) at ReturnAddress; + raise ETProRenderException.Create(Format('[%1:s] %0:s (error in filter call for function [%1:s])', [aErrMessage, aFunctionName])) at ReturnAddress; end; function _Comparand(const aComparandType: TComparandType; const aValue: TValue; const aParameters: TArray; const aLocaleFormatSettings: TFormatSettings): TValue; @@ -701,6 +702,17 @@ begin Create(aEncoding, []); end; +procedure TTProCompiler.MatchFilter(lVarName: string; var lFuncName: string; var lFuncParamsCount: Integer; var lFuncParams: TArray); +begin + MatchSpace; + if not MatchVariable(lFuncName) then + Error('Invalid function name applied to variable ' + lVarName); + MatchSpace; + lFuncParams := GetFunctionParameters; + lFuncParamsCount := Length(lFuncParams); + MatchSpace; +end; + function TTProCompiler.CurrentChar: Char; begin Result := fInputString.Chars[fCharIndex] @@ -899,6 +911,8 @@ var lContentOnThisLine: Integer; lStrVerbatim: string; lLayoutFound: Boolean; + lFoundVar: Boolean; + lFoundFilter: Boolean; begin aTokens.Add(TToken.Create(ttSystemVersion, TEMPLATEPRO_VERSION, '')); lLastToken := ttEOF; @@ -978,9 +992,12 @@ begin if CurrentChar = ':' then // variable begin + lFoundVar := False; + lFoundFilter := False; Step; if MatchVariable(lVarName) then { variable } begin + lFoundVar := True; if lVarName.IsEmpty then Error('Invalid variable name'); lFuncName := ''; @@ -990,15 +1007,17 @@ begin MatchSpace; if MatchSymbol('|') then begin - MatchSpace; - if not MatchVariable(lFuncName) then - Error('Invalid function name applied to variable ' + lVarName); - MatchSpace; - lFuncParams := GetFunctionParameters; - lFuncParamsCount := Length(lFuncParams); - MatchSpace; + MatchFilter(lVarName, lFuncName, lFuncParamsCount, lFuncParams); end; + end + else if MatchSymbol('|') then + begin + lFoundFilter := True; + MatchFilter(lVarName, lFuncName, lFuncParamsCount, lFuncParams); + end; + if lFoundVar or lFoundFilter then + begin if not MatchEndTag then begin Error('Expected end tag "' + END_TAG + '" near ' + GetSubsequentText); @@ -1020,7 +1039,11 @@ begin end; end; end; - end; // matchvariable + end + else + begin + Error('Expected variable or filter near ' + GetSubsequentText); + end; end else begin @@ -1631,15 +1654,42 @@ begin end else if SameText(aFunctionName, 'uppercase') then begin - Result := UpperCase(aValue.AsString); + if not aValue.IsEmpty then + begin + CheckParNumber(0, aParameters); + Result := UpperCase(aValue.AsString); + end + else + begin + CheckParNumber(1, aParameters); + Result := UpperCase(aParameters[0]); + end; end else if SameText(aFunctionName, 'lowercase') then begin - Result := lowercase(aValue.AsString); + if not aValue.IsEmpty then + begin + CheckParNumber(0, aParameters); + Result := lowercase(aValue.AsString); + end + else + begin + CheckParNumber(1, aParameters); + Result := lowercase(aParameters[0]); + end; end else if SameText(aFunctionName, 'capitalize') then begin - Result := CapitalizeString(aValue.AsString, True); + if not aValue.IsEmpty then + begin + CheckParNumber(0, aParameters); + Result := CapitalizeString(aValue.AsString, True); + end + else + begin + CheckParNumber(1, aParameters); + Result := CapitalizeString(aParameters[0], True); + end; end else if SameText(aFunctionName, 'trunc') then begin @@ -1760,6 +1810,10 @@ begin end else if SameText(aFunctionName, 'version') then begin + if not aValue.IsEmpty then + begin + FunctionError(aFunctionName, 'cannot be applied to a value - [HINT] Use {{:|' + aFunctionName + '}}'); + end; CheckParNumber(0, aParameters); Result := TEMPLATEPRO_VERSION; end