mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Added rating and indicator in "instant_search_with_htmx"
This commit is contained in:
parent
4b8b89d4da
commit
34238a48ee
Binary file not shown.
@ -3,5 +3,10 @@ CREATE TABLE books (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
book_name TEXT NOT NULL,
|
||||
author_name TEXT NOT NULL,
|
||||
genre TEXT NOT NULL
|
||||
);
|
||||
genre TEXT NOT NULL,
|
||||
rating INTEGER DEFAULT (0) NOT NULL);
|
||||
|
||||
|
||||
/* fill data and then generate rating using the following update */
|
||||
|
||||
update books set rating = abs(random() % 6)
|
@ -62,8 +62,6 @@ begin
|
||||
// When MVCSerializeNulls = False empty nullables and nil are not serialized at all.
|
||||
MVCSerializeNulls := True;
|
||||
|
||||
MVCUseTemplatesCache := False;
|
||||
|
||||
try
|
||||
if WebRequestHandler <> nil then
|
||||
WebRequestHandler.WebModuleClass := WebModuleClass;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{563921D8-AB80-4E14-AD4E-36870C7E2008}</ProjectGuid>
|
||||
<ProjectVersion>20.1</ProjectVersion>
|
||||
<ProjectVersion>20.2</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>htmx_templatepro.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
@ -125,14 +125,9 @@
|
||||
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
|
||||
</Excluded_Packages>
|
||||
</Delphi.Personality>
|
||||
<Deployment Version="4">
|
||||
<Deployment Version="5">
|
||||
<DeployFile LocalName="bin\ServerSideViews.exe" Configuration="Debug" Class="ProjectOutput"/>
|
||||
<DeployFile LocalName="bin\htmx_templatepro.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>htmx_templatepro.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="bin\htmx_templatepro.exe" Configuration="Debug" Class="ProjectOutput"/>
|
||||
<DeployClass Name="AdditionalDebugSymbols">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
@ -141,16 +136,6 @@
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidClasses">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>64</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>64</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidFileProvider">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\xml</RemoteDir>
|
||||
@ -161,12 +146,6 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidGDBServer">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeArmeabiFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi</RemoteDir>
|
||||
|
@ -14,6 +14,16 @@
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
|
||||
<Base_Android>true</Base_Android>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
|
||||
<Base_Android64>true</Base_Android64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Linux64' and '$(Base)'=='true') or '$(Base_Linux64)'!=''">
|
||||
<Base_Linux64>true</Base_Linux64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
@ -63,6 +73,16 @@
|
||||
<VerInfo_Locale>1040</VerInfo_Locale>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Android)'!=''">
|
||||
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34</VerInfo_Keys>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<EnabledSysJars>activity-1.7.2.dex.jar;annotation-experimental-1.3.0.dex.jar;annotation-jvm-1.6.0.dex.jar;annotations-13.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;billing-6.0.1.dex.jar;biometric-1.1.0.dex.jar;browser-1.4.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;concurrent-futures-1.1.0.dex.jar;core-1.10.1.dex.jar;core-common-2.2.0.dex.jar;core-ktx-1.10.1.dex.jar;core-runtime-2.2.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;error_prone_annotations-2.9.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;kotlin-stdlib-1.8.22.dex.jar;kotlin-stdlib-common-1.8.22.dex.jar;kotlin-stdlib-jdk7-1.8.22.dex.jar;kotlin-stdlib-jdk8-1.8.22.dex.jar;kotlinx-coroutines-android-1.6.4.dex.jar;kotlinx-coroutines-core-jvm-1.6.4.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.6.1.dex.jar;lifecycle-livedata-2.6.1.dex.jar;lifecycle-livedata-core-2.6.1.dex.jar;lifecycle-runtime-2.6.1.dex.jar;lifecycle-service-2.6.1.dex.jar;lifecycle-viewmodel-2.6.1.dex.jar;lifecycle-viewmodel-savedstate-2.6.1.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;okio-jvm-3.4.0.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;play-services-appset-16.0.1.dex.jar;play-services-base-18.1.0.dex.jar;play-services-basement-18.1.0.dex.jar;play-services-cloud-messaging-17.0.1.dex.jar;play-services-location-21.0.1.dex.jar;play-services-maps-18.1.0.dex.jar;play-services-measurement-base-20.1.2.dex.jar;play-services-measurement-sdk-api-20.1.2.dex.jar;play-services-stats-17.0.2.dex.jar;play-services-tasks-18.0.2.dex.jar;print-1.0.0.dex.jar;profileinstaller-1.3.0.dex.jar;room-common-2.2.5.dex.jar;room-runtime-2.2.5.dex.jar;savedstate-1.2.1.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar;startup-runtime-1.1.1.dex.jar;tracing-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.1.8.dex.jar;transport-runtime-3.1.8.dex.jar;user-messaging-platform-2.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.7.0.dex.jar</EnabledSysJars>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Android64)'!=''">
|
||||
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34</VerInfo_Keys>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<EnabledSysJars>activity-1.7.2.dex.jar;annotation-experimental-1.3.0.dex.jar;annotation-jvm-1.6.0.dex.jar;annotations-13.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;billing-6.0.1.dex.jar;biometric-1.1.0.dex.jar;browser-1.4.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;concurrent-futures-1.1.0.dex.jar;core-1.10.1.dex.jar;core-common-2.2.0.dex.jar;core-ktx-1.10.1.dex.jar;core-runtime-2.2.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;error_prone_annotations-2.9.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;kotlin-stdlib-1.8.22.dex.jar;kotlin-stdlib-common-1.8.22.dex.jar;kotlin-stdlib-jdk7-1.8.22.dex.jar;kotlin-stdlib-jdk8-1.8.22.dex.jar;kotlinx-coroutines-android-1.6.4.dex.jar;kotlinx-coroutines-core-jvm-1.6.4.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.6.1.dex.jar;lifecycle-livedata-2.6.1.dex.jar;lifecycle-livedata-core-2.6.1.dex.jar;lifecycle-runtime-2.6.1.dex.jar;lifecycle-service-2.6.1.dex.jar;lifecycle-viewmodel-2.6.1.dex.jar;lifecycle-viewmodel-savedstate-2.6.1.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;okio-jvm-3.4.0.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;play-services-appset-16.0.1.dex.jar;play-services-base-18.1.0.dex.jar;play-services-basement-18.1.0.dex.jar;play-services-cloud-messaging-17.0.1.dex.jar;play-services-location-21.0.1.dex.jar;play-services-maps-18.1.0.dex.jar;play-services-measurement-base-20.1.2.dex.jar;play-services-measurement-sdk-api-20.1.2.dex.jar;play-services-stats-17.0.2.dex.jar;play-services-tasks-18.0.2.dex.jar;print-1.0.0.dex.jar;profileinstaller-1.3.0.dex.jar;room-common-2.2.5.dex.jar;room-runtime-2.2.5.dex.jar;savedstate-1.2.1.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar;startup-runtime-1.1.1.dex.jar;tracing-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.1.8.dex.jar;transport-runtime-3.1.8.dex.jar;user-messaging-platform-2.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.7.0.dex.jar</EnabledSysJars>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Linux64)'!=''">
|
||||
<DCC_UsePackage>DataSnapServer;fmx;emshosting;DbxCommonDriver;bindengine;FireDACCommonODBC;emsclient;FireDACCommonDriver;IndyProtocols;dbxcds;RadiantShapesFmx_Design;emsedge;inetdb;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;dbexpress;Python;FireDACInfxDriver;inet;DataSnapCommon;dbrtl;FireDACOracleDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;FireDACMongoDBDriver;IndySystem;RadiantShapesFmx;FireDACTDataDriver;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;dsnapxml;DataSnapClient;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;xmlrtl;dsnap;CloudService;FireDACDb2Driver;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
</PropertyGroup>
|
||||
@ -995,6 +1015,8 @@
|
||||
<ProjectRoot Platform="Win64x" Name="$(PROJECTNAME)"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
<Platform value="Android">False</Platform>
|
||||
<Platform value="Android64">False</Platform>
|
||||
<Platform value="Linux64">False</Platform>
|
||||
<Platform value="Win32">True</Platform>
|
||||
<Platform value="Win64">False</Platform>
|
||||
|
@ -32,7 +32,7 @@ var
|
||||
lBaseSelect, lOrdering: String;
|
||||
begin
|
||||
SearchQueryText := SearchQueryText.ToLower;
|
||||
lBaseSelect := 'select id, book_name, author_name, genre from books';
|
||||
lBaseSelect := 'select id, book_name, author_name, genre, rating from books';
|
||||
lOrdering := 'order by book_name COLLATE NOCASE';
|
||||
if SearchQueryText.IsEmpty then
|
||||
begin
|
||||
|
@ -7,17 +7,18 @@
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org/dist/htmx.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<body hx-indicator="#spinner">
|
||||
<section class="section" >
|
||||
<div class="columns">
|
||||
<div class="column is-one-third is-offset-one-third">
|
||||
<input type="text" class="input" placeholder="Search" name="query" hx-get="/search"
|
||||
<input type="text" class="input" placeholder="Search" name="query" hx-get="/search"
|
||||
hx-trigger="keyup changed delay:500ms" hx-target="#results" hx-push-url="true" />
|
||||
</div>
|
||||
<div class="column is-one-third">
|
||||
<p class="subtitle is-6">⭐ DMVCFramework + HTMX :: Instant Search Demo ⭐</p>
|
||||
</div>
|
||||
</div>
|
||||
<progress id="spinner" class="htmx-indicator progress is-large is-info" max="100">ciao</progress>
|
||||
<div id="results">{{include "search_results.html"}}</div>
|
||||
</section>
|
||||
</body>
|
||||
|
@ -5,6 +5,7 @@
|
||||
<th>ID</th>
|
||||
<th>Book Title</th>
|
||||
<th>Book Author</th>
|
||||
<th>Rating</th>
|
||||
<th>Genre</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -30,9 +31,14 @@
|
||||
<td>{{:book.id|lpad,8,"0"}}</td>
|
||||
<td>{{:book.book_name}}</td>
|
||||
<td>{{:book.author_name}}</td>
|
||||
<td
|
||||
|
||||
>
|
||||
<td>
|
||||
{{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}}
|
||||
</td>
|
||||
<td>
|
||||
{{:book.genre|uppercase}}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -34,7 +34,7 @@ uses
|
||||
System.RTTI;
|
||||
|
||||
const
|
||||
TEMPLATEPRO_VERSION = '0.6';
|
||||
TEMPLATEPRO_VERSION = '0.6.1';
|
||||
|
||||
type
|
||||
ETProException = class(Exception)
|
||||
@ -59,11 +59,11 @@ type
|
||||
|
||||
TTokenType = (
|
||||
ttContent, ttInclude, ttFor, ttEndFor, ttIfThen, ttBoolExpression, ttElse, ttEndIf, ttStartTag, ttComment,
|
||||
ttLiteralString, ttEndTag, ttValue, ttFilterName, ttFilterParameter, ttLineBreak, ttSystemVersion, ttEOF);
|
||||
ttContinue, ttLiteralString, ttEndTag, ttValue, ttFilterName, ttFilterParameter, ttLineBreak, ttSystemVersion, ttExit, ttEOF);
|
||||
const
|
||||
TOKEN_TYPE_DESCR: array [Low(TTokenType)..High(TTokenType)] of string =
|
||||
('ttContent', 'ttInclude', 'ttFor', 'ttEndFor', 'ttIfThen', 'ttBoolExpression', 'ttElse', 'ttEndIf', 'ttStartTag', 'ttComment',
|
||||
'ttLiteralString', 'ttEndTag', 'ttValue', 'ttFilterName', 'ttFilterParameter', 'ttLineBreak', 'ttSystemVersion', 'ttEOF');
|
||||
'ttContinue', 'ttLiteralString', 'ttEndTag', 'ttValue', 'ttFilterName', 'ttFilterParameter', 'ttLineBreak', 'ttSystemVersion', 'ttExit', 'ttEOF');
|
||||
type
|
||||
TToken = packed record
|
||||
TokenType: TTokenType;
|
||||
@ -144,7 +144,7 @@ type
|
||||
function GetVarAsString(const Name: string): string;
|
||||
function GetTValueVarAsString(const Value: TValue; const VarName: string = ''): String;
|
||||
function GetVarAsTValue(const aName: string): TValue;
|
||||
// function EvaluateIfExpression(aIdentifier: string): Boolean;
|
||||
function GetDataSetFieldAsTValue(const aDataSet: TDataSet; const FieldName: String): TValue;
|
||||
function EvaluateIfExpressionAt(var Idx: UInt64): Boolean;
|
||||
function GetVariables: TTProVariables;
|
||||
procedure SplitVariableName(const VariableWithMember: String; out VarName, VarMembers: String);
|
||||
@ -289,16 +289,25 @@ begin
|
||||
fTemplateFunctions.Add(FunctionName.ToLower, FunctionImpl);
|
||||
end;
|
||||
|
||||
function TTProCompiledTemplate.GetDataSetFieldAsTValue(const aDataSet: TDataSet; const FieldName: String): TValue;
|
||||
var
|
||||
lField: TField;
|
||||
begin
|
||||
lField := aDataSet.FieldByName(FieldName);
|
||||
case lField.DataType of
|
||||
ftInteger: Result := lField.AsInteger;
|
||||
ftLargeint, ftAutoInc: Result := lField.AsLargeInt;
|
||||
ftString, ftWideString, ftMemo, ftWideMemo: Result := lField.AsWideString;
|
||||
else
|
||||
Error('Invalid data type for field "%s": %s', [FieldName, TRttiEnumerationType.GetName<TFieldType>(lField.DataType)]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTProCompiledTemplate.GetOnGetValue: TTProCompiledTemplateGetValueEvent;
|
||||
begin
|
||||
Result := fOnGetValue;
|
||||
end;
|
||||
|
||||
//function TTProCompiledTemplate.GetPseudoVariable(const Variable: TVarDataSource; const PseudoVarName: String): TValue;
|
||||
//begin
|
||||
// Result := GetPseudoVariable(Variable.VarIterator, PseudoVarName);
|
||||
//end;
|
||||
|
||||
function TTProCompiledTemplate.GetPseudoVariable(const VarIterator: Integer; const PseudoVarName: String): TValue;
|
||||
begin
|
||||
if PseudoVarName = '@@index' then
|
||||
@ -838,6 +847,10 @@ begin
|
||||
aTokens.Add(TToken.Create(lLastToken, '', ''));
|
||||
Dec(lForStatementCount);
|
||||
lStartVerbatim := fCharIndex;
|
||||
end else if MatchSymbol('continue') then {continue}
|
||||
begin
|
||||
lLastToken := ttContinue;
|
||||
aTokens.Add(TToken.Create(lLastToken, '', ''));
|
||||
end else if MatchSymbol('endif') then {endif}
|
||||
begin
|
||||
if lIfStatementCount = -1 then
|
||||
@ -951,6 +964,8 @@ begin
|
||||
end
|
||||
else if MatchSymbol('exit') then {exit}
|
||||
begin
|
||||
lLastToken := ttExit;
|
||||
aTokens.Add(TToken.Create(lLastToken, '', ''));
|
||||
lLastToken := ttEOF;
|
||||
aTokens.Add(TToken.Create(lLastToken, '', ''));
|
||||
Break;
|
||||
@ -1020,69 +1035,108 @@ end;
|
||||
procedure TTProCompiler.FixJumps(const aTokens: TList<TToken>);
|
||||
var
|
||||
lForInStack: TStack<UInt64>;
|
||||
lContinueStack: TStack<UInt64>;
|
||||
lIfStatementStack: TStack<TIfThenElseIndex>;
|
||||
I: UInt64;
|
||||
lToken: TToken;
|
||||
lForAddress: UInt64;
|
||||
lIfStackItem: TIfThenElseIndex;
|
||||
lCheckForUnbalancedPair: Boolean;
|
||||
lTmpContinueAddress: UInt64;
|
||||
begin
|
||||
lCheckForUnbalancedPair := True;
|
||||
lForInStack := TStack<UInt64>.Create;
|
||||
try
|
||||
lIfStatementStack := TStack<TIfThenElseIndex>.Create;
|
||||
lContinueStack := TStack<UInt64>.Create;
|
||||
try
|
||||
for I := 0 to aTokens.Count - 1 do
|
||||
begin
|
||||
case aTokens[I].TokenType of
|
||||
ttFor: begin
|
||||
lForInStack.Push(I);
|
||||
end;
|
||||
ttEndFor: begin
|
||||
{ttFor.Ref1 --> endfor}
|
||||
lForAddress := lForInStack.Pop;
|
||||
lToken := aTokens[lForAddress];
|
||||
lToken.Ref1 := I;
|
||||
aTokens[lForAddress] := lToken;
|
||||
lIfStatementStack := TStack<TIfThenElseIndex>.Create;
|
||||
try
|
||||
for I := 0 to aTokens.Count - 1 do
|
||||
begin
|
||||
case aTokens[I].TokenType of
|
||||
ttFor: begin
|
||||
if lContinueStack.Count > 0 then
|
||||
begin
|
||||
Error('Continue stack corrupted');
|
||||
end;
|
||||
lForInStack.Push(I);
|
||||
end;
|
||||
|
||||
{ttEndFor.Ref1 --> for}
|
||||
lToken := aTokens[I];
|
||||
lToken.Ref1 := lForAddress;
|
||||
aTokens[I] := lToken;
|
||||
end;
|
||||
ttEndFor: begin
|
||||
{ttFor.Ref1 --> endfor}
|
||||
lForAddress := lForInStack.Pop;
|
||||
lToken := aTokens[lForAddress];
|
||||
lToken.Ref1 := I;
|
||||
aTokens[lForAddress] := lToken;
|
||||
|
||||
{ttIfThen.Ref1 points always to relative else (if present otherwise -1)}
|
||||
{ttIfThen.Ref2 points always to relative endif}
|
||||
{ttEndFor.Ref1 --> for}
|
||||
lToken := aTokens[I];
|
||||
lToken.Ref1 := lForAddress;
|
||||
aTokens[I] := lToken;
|
||||
|
||||
ttIfThen: begin
|
||||
lIfStackItem.IfIndex := I;
|
||||
lIfStackItem.ElseIndex := -1; {-1 means: "there isn't ttElse"}
|
||||
lIfStatementStack.Push(lIfStackItem);
|
||||
end;
|
||||
ttElse: begin
|
||||
lIfStackItem := lIfStatementStack.Pop;
|
||||
lIfStackItem.ElseIndex := I;
|
||||
lIfStatementStack.Push(lIfStackItem);
|
||||
end;
|
||||
ttEndIf: begin
|
||||
lIfStackItem := lIfStatementStack.Pop;
|
||||
{if there's a ttContinue (or more than one), it must jump to endfor}
|
||||
while lContinueStack.Count > 0 do
|
||||
begin
|
||||
lTmpContinueAddress := lContinueStack.Pop;
|
||||
lToken := aTokens[lTmpContinueAddress];
|
||||
lToken.Ref1 := I;
|
||||
aTokens[lTmpContinueAddress] := lToken;
|
||||
end;
|
||||
end;
|
||||
|
||||
{fixup ifthen}
|
||||
lToken := aTokens[lIfStackItem.IfIndex];
|
||||
lToken.Ref2 := I; {ttIfThen.Ref2 points always to relative endif}
|
||||
lToken.Ref1 := lIfStackItem.ElseIndex; {ttIfThen.Ref1 points always to relative else (if present, otherwise -1)}
|
||||
aTokens[lIfStackItem.IfIndex] := lToken;
|
||||
ttContinue: begin
|
||||
lContinueStack.Push(I);
|
||||
end;
|
||||
|
||||
{fixup else}
|
||||
if lIfStackItem.ElseIndex > -1 then
|
||||
begin
|
||||
lToken := aTokens[lIfStackItem.ElseIndex];
|
||||
lToken.Ref2 := I; {ttElse.Ref2 points always to relative endif}
|
||||
aTokens[lIfStackItem.ElseIndex] := lToken;
|
||||
{ttIfThen.Ref1 points always to relative else (if present otherwise -1)}
|
||||
{ttIfThen.Ref2 points always to relative endif}
|
||||
|
||||
ttIfThen: begin
|
||||
lIfStackItem.IfIndex := I;
|
||||
lIfStackItem.ElseIndex := -1; {-1 means: "there isn't ttElse"}
|
||||
lIfStatementStack.Push(lIfStackItem);
|
||||
end;
|
||||
ttElse: begin
|
||||
lIfStackItem := lIfStatementStack.Pop;
|
||||
lIfStackItem.ElseIndex := I;
|
||||
lIfStatementStack.Push(lIfStackItem);
|
||||
end;
|
||||
ttEndIf: begin
|
||||
lIfStackItem := lIfStatementStack.Pop;
|
||||
|
||||
{fixup ifthen}
|
||||
lToken := aTokens[lIfStackItem.IfIndex];
|
||||
lToken.Ref2 := I; {ttIfThen.Ref2 points always to relative endif}
|
||||
lToken.Ref1 := lIfStackItem.ElseIndex; {ttIfThen.Ref1 points always to relative else (if present, otherwise -1)}
|
||||
aTokens[lIfStackItem.IfIndex] := lToken;
|
||||
|
||||
{fixup else}
|
||||
if lIfStackItem.ElseIndex > -1 then
|
||||
begin
|
||||
lToken := aTokens[lIfStackItem.ElseIndex];
|
||||
lToken.Ref2 := I; {ttElse.Ref2 points always to relative endif}
|
||||
aTokens[lIfStackItem.ElseIndex] := lToken;
|
||||
end;
|
||||
end;
|
||||
ttExit: begin
|
||||
lCheckForUnbalancedPair := False;
|
||||
end;
|
||||
end;
|
||||
end; // for
|
||||
|
||||
if lCheckForUnbalancedPair and (lIfStatementStack.Count > 0) then
|
||||
begin
|
||||
Error('Unbalanced "if" - expected "endif"');
|
||||
end;
|
||||
end; // for
|
||||
if lCheckForUnbalancedPair and (lForInStack.Count > 0) then
|
||||
begin
|
||||
Error('Unbalanced "for" - expected "endfor"');
|
||||
end;
|
||||
finally
|
||||
lIfStatementStack.Free;
|
||||
end;
|
||||
finally
|
||||
lIfStatementStack.Free;
|
||||
lContinueStack.Free;
|
||||
end;
|
||||
finally
|
||||
lForInStack.Free;
|
||||
@ -1163,6 +1217,18 @@ begin
|
||||
FunctionError('expected 1 parameter');
|
||||
Result := aValue.AsInt64 <= StrToInt64(aParameters[0]);
|
||||
end
|
||||
else if aFunctionName = 'contains' then
|
||||
begin
|
||||
if Length(aParameters) <> 1 then
|
||||
FunctionError('expected 1 parameter');
|
||||
Result := aValue.AsString.Contains(aParameters[0]);
|
||||
end
|
||||
else if aFunctionName = 'contains_ignore_case' then
|
||||
begin
|
||||
if Length(aParameters) <> 1 then
|
||||
FunctionError('expected 1 parameter');
|
||||
Result := aValue.AsString.ToLowerInvariant.Contains(aParameters[0].ToLowerInvariant);
|
||||
end
|
||||
else if (aFunctionName = 'eq') or (aFunctionName = 'ne') then
|
||||
begin
|
||||
if Length(aParameters) <> 1 then
|
||||
@ -1685,7 +1751,7 @@ end;
|
||||
|
||||
procedure TTProCompiledTemplate.Error(const aMessage: String);
|
||||
begin
|
||||
raise ETProRenderException.Create(aMessage);
|
||||
raise ETProRenderException.Create(aMessage) at ReturnAddress;
|
||||
end;
|
||||
|
||||
procedure TTProCompiledTemplate.ForEachToken(
|
||||
@ -1916,45 +1982,6 @@ begin
|
||||
end;
|
||||
ttValue, ttLiteralString: begin
|
||||
lVarValue := EvaluateValue(lIdx, lMustBeEncoded {must be encoded});
|
||||
|
||||
// // Ref1 contains the optional filter parameter number (-1 if there isn't any filter)
|
||||
// // Ref2 is -1 if the variable must be HTMLEncoded, while contains 1 is the value must not be HTMLEncoded
|
||||
// lRef2 := fTokens[lIdx].Ref2;
|
||||
// lCurrTokenType := fTokens[lIdx].TokenType;
|
||||
// if fTokens[lIdx].Ref1 > -1 {has a filter with Ref1 parameters} then
|
||||
// begin
|
||||
// lVarName := fTokens[lIdx].Value1;
|
||||
// Inc(lIdx);
|
||||
// lFilterName := fTokens[lIdx].Value1;
|
||||
// lFilterParCount := fTokens[lIdx].Ref1; // parameter count
|
||||
// SetLength(lFilterParameters, lFilterParCount);
|
||||
// for I := 0 to lFilterParCount - 1 do
|
||||
// begin
|
||||
// Inc(lIdx);
|
||||
// Assert(fTokens[lIdx].TokenType = ttFilterParameter);
|
||||
// lFilterParameters[I] := fTokens[lIdx].Value1;
|
||||
// end;
|
||||
// if lCurrTokenType = ttValue then
|
||||
// begin
|
||||
// lVarValue := ExecuteFilter(lFilterName, lFilterParameters, GetVarAsTValue(lVarName));
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// lVarValue := ExecuteFilter(lFilterName, lFilterParameters, lVarName);
|
||||
// end;
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// if lCurrTokenType = ttValue then
|
||||
// begin
|
||||
// lVarValue := GetVarAsString(fTokens[lIdx].Value1);
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// lVarValue := fTokens[lIdx].Value1;
|
||||
// end;
|
||||
// end;
|
||||
|
||||
if lMustBeEncoded {lRef2 = -1 // encoded} then
|
||||
lBuff.Append(HTMLEncode(lVarValue.ToString))
|
||||
else
|
||||
@ -1972,6 +1999,13 @@ begin
|
||||
begin
|
||||
Error('Compiled template has been compiled with a different version. Expected ' + TEMPLATEPRO_VERSION + ' got ' + fTokens[lIdx].Value1);
|
||||
end;
|
||||
end;
|
||||
ttContinue: begin
|
||||
lIdx := fTokens[lIdx].Ref1;
|
||||
Continue;
|
||||
end;
|
||||
ttExit: begin
|
||||
//do nothing
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -1997,7 +2031,6 @@ end;
|
||||
function TTProCompiledTemplate.GetVarAsTValue(const aName: string): TValue;
|
||||
var
|
||||
lVariable: TVarDataSource;
|
||||
lField: TField;
|
||||
lHasMember: Boolean;
|
||||
lJPath: string;
|
||||
lDataSource: string;
|
||||
@ -2040,21 +2073,16 @@ begin
|
||||
begin
|
||||
Error('Empty field name while reading from iterator "%s"', [lVarName]);
|
||||
end;
|
||||
lField := TDataSet(lVariable.VarValue.AsObject).FieldByName(lVarMembers);
|
||||
case lField.DataType of
|
||||
ftInteger: Result := lField.AsInteger;
|
||||
ftLargeint, ftAutoInc: Result := lField.AsLargeInt;
|
||||
ftString, ftWideString, ftMemo, ftWideMemo: Result := lField.AsWideString;
|
||||
else
|
||||
Error('Invalid data type for field "%s": %s', [lVarMembers, TRttiEnumerationType.GetName<TFieldType>(lField.DataType)]);
|
||||
end;
|
||||
Result := GetDataSetFieldAsTValue(TDataSet(lVariable.VarValue.AsObject), lVarMembers);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ not an interator }
|
||||
if lHasMember then
|
||||
Error(lDataSource + ' members can be read only through an iterator')
|
||||
begin
|
||||
Result := GetDataSetFieldAsTValue(TDataSet(lVariable.VarValue.AsObject), lVarMembers);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := lVariable.VarValue.AsObject;
|
||||
|
Loading…
Reference in New Issue
Block a user