mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
WebStencils support in IDE Wizard and code generator
This commit is contained in:
parent
92c4bf9f0c
commit
787daee3b2
@ -176,6 +176,19 @@ type
|
||||
); override;
|
||||
end;
|
||||
|
||||
TUnitWebStencilsHelpersDeclarationCommand = class(TCustomCommand)
|
||||
public
|
||||
procedure ExecuteInterface(
|
||||
Section: TStringBuilder;
|
||||
Model: TJSONObject
|
||||
); override;
|
||||
procedure ExecuteImplementation(
|
||||
Section: TStringBuilder;
|
||||
Model: TJsonObject
|
||||
); override;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
TUnitFooterCommand = class(TCustomCommand)
|
||||
@ -319,21 +332,18 @@ begin
|
||||
.AppendLine(' MVCFramework.Commons,')
|
||||
.AppendLine(' MVCFramework.Serializer.Commons,');
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_templatepro] then
|
||||
begin
|
||||
Section
|
||||
.AppendLine(' MVCFramework.View.Renderers.TemplatePro,');
|
||||
end;
|
||||
if Model.B[TConfigKey.program_ssv_mustache] then
|
||||
begin
|
||||
{The Mustache units are required in the "program" because the mustache helpers are declared there.
|
||||
Should we create an external unit as we do in templatepro and webstencils }
|
||||
Section
|
||||
.AppendLine(' MVCFramework.View.Renderers.Mustache,')
|
||||
.AppendLine(' mormot.core.mustache,');
|
||||
.AppendLine(' MVCFramework.View.Renderers.Mustache,')
|
||||
.AppendLine(' mormot.core.mustache,');
|
||||
end;
|
||||
if Model.B[TConfigKey.program_service_container_generate] then
|
||||
begin
|
||||
Section
|
||||
.AppendLine(' MVCFramework.Container,')
|
||||
.AppendLine(' MVCFramework.Container,')
|
||||
end;
|
||||
Section
|
||||
.AppendLine(' MVCFramework.Signal;')
|
||||
@ -786,6 +796,13 @@ begin
|
||||
.AppendLine(' MVCFramework.View.Renderers.TemplatePro,')
|
||||
end;
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_webstencils] then
|
||||
begin
|
||||
Section
|
||||
.AppendLine(' MVCFramework.View.Renderers.WebStencils,')
|
||||
end;
|
||||
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_mustache] then
|
||||
begin
|
||||
Section
|
||||
@ -846,6 +863,15 @@ begin
|
||||
.AppendLine;
|
||||
end;
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_webstencils] then
|
||||
begin
|
||||
Section
|
||||
.AppendLine(' // Server Side View')
|
||||
.AppendLine(' FMVC.SetViewEngine(TMVCWebStencilsViewEngine);')
|
||||
.AppendLine(' // Server Side View - END')
|
||||
.AppendLine;
|
||||
end;
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_mustache] then
|
||||
begin
|
||||
Section
|
||||
@ -1097,6 +1123,18 @@ begin
|
||||
.AppendLine('{$ENDIF}')
|
||||
.AppendLine;
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_templatepro] then
|
||||
begin
|
||||
Section
|
||||
.AppendLine(' TemplateProContextConfigure;');
|
||||
end;
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_webstencils] then
|
||||
begin
|
||||
Section
|
||||
.AppendLine(' WebStencilsProcessorConfigure;');
|
||||
end;
|
||||
|
||||
if Model.B[TConfigKey.program_ssv_mustache] then
|
||||
begin
|
||||
Section
|
||||
@ -1175,7 +1213,7 @@ begin
|
||||
.AppendLine(' LServer.MaxConnections := dotEnv.Env(''dmvc.webbroker.max_connections'', 0);')
|
||||
.AppendLine(' LServer.ListenQueue := dotEnv.Env(''dmvc.indy.listen_queue'', 500);')
|
||||
.AppendLine(' LServer.Active := True;')
|
||||
.AppendLine(' LogI(''Listening on port '' + APort.ToString);')
|
||||
.AppendLine(' LogI(''Listening on http://localhost:'' + APort.ToString);')
|
||||
.AppendLine(' LogI(''Application started. Press Ctrl+C to shut down.'');')
|
||||
.AppendLine(' WaitForTerminationSignal;')
|
||||
.AppendLine(' EnterInShutdownState;')
|
||||
@ -1442,7 +1480,7 @@ procedure TUnitTemplateProHelpersDeclarationCommand.ExecuteInterface(
|
||||
Section: TStringBuilder; Model: TJSONObject);
|
||||
begin
|
||||
inherited;
|
||||
CheckFor(TConfigKey.program_ssv_mustache, Model);
|
||||
CheckFor(TConfigKey.program_ssv_templatepro, Model);
|
||||
CheckFor(TConfigKey.templatepro_helpers_unit_name, Model);
|
||||
Section
|
||||
.AppendLine('unit ' + Model[TConfigKey.templatepro_helpers_unit_name] + ';')
|
||||
@ -1460,4 +1498,77 @@ begin
|
||||
.AppendLine;
|
||||
end;
|
||||
|
||||
{ TUnitWebStencilsHelpersDeclarationCommand }
|
||||
|
||||
procedure TUnitWebStencilsHelpersDeclarationCommand.ExecuteImplementation(Section: TStringBuilder; Model: TJsonObject);
|
||||
begin
|
||||
inherited;
|
||||
Section
|
||||
.AppendLine('implementation')
|
||||
.AppendLine('')
|
||||
.AppendLine('uses')
|
||||
.AppendLine(' System.SysUtils, MVCFramework.View.Renderers.WebStencils, System.Bindings.Methods, Web.Stencils;')
|
||||
.AppendLine('')
|
||||
.AppendLine('')
|
||||
.AppendLine('function MyHelper1(const Parameters: TArray<IValue>): TValue;')
|
||||
.AppendLine('begin')
|
||||
.AppendLine(' Result := Parameters[0].GetValue.ToString + '' (I''''m The MyHelper1)'';')
|
||||
.AppendLine('end;')
|
||||
.AppendLine('')
|
||||
.AppendLine('function MyHelper2(const Parameters: TArray<IValue>): TValue;')
|
||||
.AppendLine('begin')
|
||||
.AppendLine(' Result := Parameters[0].GetValue.ToString + '' (I''''m The MyHelper2)'';')
|
||||
.AppendLine('end;')
|
||||
.AppendLine('')
|
||||
.AppendLine('procedure WebStencilsProcessorConfigure;')
|
||||
.AppendLine('begin')
|
||||
.AppendLine(' TBindingMethodsFactory.RegisterMethod(')
|
||||
.AppendLine(' TMethodDescription.Create(')
|
||||
.AppendLine(' MakeInvokable(function(Args: TArray<IValue>): IValue')
|
||||
.AppendLine(' begin')
|
||||
.AppendLine(' Result := TValueWrapper.Create(MyHelper1(Args));')
|
||||
.AppendLine(' end),')
|
||||
.AppendLine(' ''MyHelper1'', ''MyHelper1'', '''', True, ''MyHelper1 is just a sample'', nil));')
|
||||
.AppendLine('')
|
||||
.AppendLine('')
|
||||
.AppendLine(' TBindingMethodsFactory.RegisterMethod(')
|
||||
.AppendLine(' TMethodDescription.Create(')
|
||||
.AppendLine(' MakeInvokable(function(Args: TArray<IValue>): IValue')
|
||||
.AppendLine(' begin')
|
||||
.AppendLine(' Result := TValueWrapper.Create(MyHelper2(Args));')
|
||||
.AppendLine(' end),')
|
||||
.AppendLine(' ''MyHelper2'', ''MyHelper2'', '''', True, ''MyHelper2 is just a sample'', nil));')
|
||||
.AppendLine('')
|
||||
.AppendLine(' TMVCWebStencilsConfiguration.OnProcessorConfiguration :=')
|
||||
.AppendLine(' procedure(const WebStencilsProcessor: TWebStencilsProcessor)')
|
||||
.AppendLine(' begin')
|
||||
.AppendLine(' //custom configuration for TWebStencilsProcessor (executed for each view)')
|
||||
.AppendLine(' end;')
|
||||
.AppendLine('')
|
||||
.AppendLine('end;')
|
||||
.AppendLine('')
|
||||
.AppendLine('end.')
|
||||
end;
|
||||
|
||||
procedure TUnitWebStencilsHelpersDeclarationCommand.ExecuteInterface(Section: TStringBuilder; Model: TJSONObject);
|
||||
begin
|
||||
inherited;
|
||||
CheckFor(TConfigKey.program_ssv_webstencils, Model);
|
||||
CheckFor(TConfigKey.webstencils_helpers_unit_name, Model);
|
||||
Section
|
||||
.AppendLine('unit ' + Model[TConfigKey.webstencils_helpers_unit_name] + ';')
|
||||
.AppendLine
|
||||
.AppendLine('interface')
|
||||
.AppendLine
|
||||
.AppendLine('uses')
|
||||
.AppendLine(' System.Rtti, System.Bindings.EvalProtocol;')
|
||||
.AppendLine
|
||||
.AppendLine('function MyHelper1(const Parameters: TArray<IValue>): TValue;')
|
||||
.AppendLine('function MyHelper2(const Parameters: TArray<IValue>): TValue;')
|
||||
.AppendLine
|
||||
.AppendLine
|
||||
.AppendLine('procedure WebStencilsProcessorConfigure;')
|
||||
.AppendLine;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -35,6 +35,7 @@ procedure FillWebModuleTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillWebModuleDFMTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillJSONRPCTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillTemplateProTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillWebStencilsTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillMustacheTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillEntitiesTemplates(Gen: TMVCCodeGenerator);
|
||||
procedure FillServicesTemplates(Gen: TMVCCodeGenerator);
|
||||
@ -98,6 +99,14 @@ begin
|
||||
]);
|
||||
end;
|
||||
|
||||
procedure FillWebStencilsTemplates(Gen: TMVCCodeGenerator);
|
||||
begin
|
||||
Gen.Commands.AddRange([
|
||||
TUnitWebStencilsHelpersDeclarationCommand.Create
|
||||
]);
|
||||
end;
|
||||
|
||||
|
||||
procedure FillServicesTemplates(Gen: TMVCCodeGenerator);
|
||||
begin
|
||||
Gen.Commands.AddRange([
|
||||
|
@ -59,11 +59,13 @@ type
|
||||
program_sqids='program.sqids';
|
||||
program_dotenv='program.dotenv';
|
||||
program_ssv_templatepro='program.ssv.templatepro';
|
||||
program_ssv_webstencils='program.ssv.webstencils';
|
||||
program_ssv_mustache='program.ssv.mustache';
|
||||
program_service_container_generate = 'program.service.container.generate';
|
||||
program_service_container_unit_name = 'program.service.container.unit_name';
|
||||
mustache_helpers_unit_name = 'mustache.helpers_unit_name';
|
||||
templatepro_helpers_unit_name = 'templatepro.helpers_unit_name';
|
||||
webstencils_helpers_unit_name = 'webstencils.helpers_unit_name';
|
||||
controller_unit_name='controller.unit_name';
|
||||
controller_classname= 'controller.classname';
|
||||
controller_index_methods_generate= 'controller.index_methods.generate';
|
||||
|
@ -3,7 +3,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
Top = 0
|
||||
BorderStyle = bsDialog
|
||||
Caption = 'DelphiMVCFramework :: New Project Wizard'
|
||||
ClientHeight = 615
|
||||
ClientHeight = 631
|
||||
ClientWidth = 729
|
||||
Color = clBtnFace
|
||||
Constraints.MinHeight = 145
|
||||
@ -18,7 +18,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
OnDestroy = FormDestroy
|
||||
DesignSize = (
|
||||
729
|
||||
615)
|
||||
631)
|
||||
TextHeight = 13
|
||||
object Shape1: TShape
|
||||
Left = 0
|
||||
@ -400,7 +400,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
object lblBook: TLabel
|
||||
AlignWithMargins = True
|
||||
Left = 10
|
||||
Top = 590
|
||||
Top = 606
|
||||
Width = 259
|
||||
Height = 16
|
||||
Cursor = crHandPoint
|
||||
@ -419,6 +419,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
OnClick = lblBookClick
|
||||
OnMouseEnter = lblBookMouseEnter
|
||||
OnMouseLeave = lblBookMouseLeave
|
||||
ExplicitTop = 590
|
||||
end
|
||||
object lblCopyRight: TLabel
|
||||
Left = 24
|
||||
@ -434,12 +435,13 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
ParentFont = False
|
||||
end
|
||||
object lblPATREON: TLabel
|
||||
Left = 452
|
||||
Top = 549
|
||||
Left = 461
|
||||
Top = 572
|
||||
Width = 257
|
||||
Height = 16
|
||||
Cursor = crHandPoint
|
||||
Alignment = taRightJustify
|
||||
Anchors = [akRight, akBottom]
|
||||
AutoSize = False
|
||||
Caption = 'Support DMVCFramework on PATREON'
|
||||
Color = clBtnFace
|
||||
@ -453,10 +455,11 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
OnClick = lblPATREONClick
|
||||
OnMouseEnter = lblPATREONMouseEnter
|
||||
OnMouseLeave = lblPATREONMouseLeave
|
||||
ExplicitTop = 549
|
||||
end
|
||||
object btnOK: TButton
|
||||
Left = 561
|
||||
Top = 580
|
||||
Top = 596
|
||||
Width = 77
|
||||
Height = 27
|
||||
Anchors = [akRight, akBottom]
|
||||
@ -468,7 +471,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object btnCancel: TButton
|
||||
Left = 644
|
||||
Top = 580
|
||||
Top = 596
|
||||
Width = 77
|
||||
Height = 27
|
||||
Anchors = [akRight, akBottom]
|
||||
@ -504,9 +507,9 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object Panel2: TPanel
|
||||
Left = 0
|
||||
Top = 400
|
||||
Top = 423
|
||||
Width = 308
|
||||
Height = 189
|
||||
Height = 182
|
||||
Anchors = [akLeft, akBottom]
|
||||
BevelOuter = bvNone
|
||||
Caption = 'Panel2'
|
||||
@ -516,21 +519,21 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
TabOrder = 5
|
||||
DesignSize = (
|
||||
308
|
||||
189)
|
||||
182)
|
||||
object gbControllerUnitOptions: TGroupBox
|
||||
Left = 12
|
||||
Top = 0
|
||||
Top = 13
|
||||
Width = 296
|
||||
Height = 184
|
||||
Height = 165
|
||||
Anchors = [akLeft, akTop, akRight, akBottom]
|
||||
Caption = 'Controller Unit Options'
|
||||
TabOrder = 0
|
||||
DesignSize = (
|
||||
296
|
||||
184)
|
||||
165)
|
||||
object lblClassName: TLabel
|
||||
Left = 16
|
||||
Top = 126
|
||||
Top = 115
|
||||
Width = 105
|
||||
Height = 13
|
||||
Caption = 'Controller Class Name'
|
||||
@ -555,7 +558,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object edtControllerClassName: TEdit
|
||||
Left = 16
|
||||
Top = 146
|
||||
Top = 135
|
||||
Width = 264
|
||||
Height = 19
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
@ -597,29 +600,29 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
Left = 314
|
||||
Top = 135
|
||||
Width = 407
|
||||
Height = 210
|
||||
Height = 221
|
||||
Caption = 'Middlewares'
|
||||
TabOrder = 6
|
||||
DesignSize = (
|
||||
407
|
||||
210)
|
||||
221)
|
||||
object Label4: TLabel
|
||||
Left = 161
|
||||
Top = 112
|
||||
Top = 125
|
||||
Width = 144
|
||||
Height = 13
|
||||
Caption = 'FireDAC Connections filename'
|
||||
end
|
||||
object Bevel1: TBevel
|
||||
Left = 11
|
||||
Top = 102
|
||||
Top = 115
|
||||
Width = 383
|
||||
Height = 3
|
||||
Shape = bsTopLine
|
||||
end
|
||||
object Label5: TLabel
|
||||
Left = 161
|
||||
Top = 156
|
||||
Top = 169
|
||||
Width = 101
|
||||
Height = 13
|
||||
Caption = 'ConnectionDef Name'
|
||||
@ -681,7 +684,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object chkActiveRecord: TCheckBox
|
||||
Left = 27
|
||||
Top = 111
|
||||
Top = 124
|
||||
Width = 135
|
||||
Height = 17
|
||||
Anchors = [akTop]
|
||||
@ -690,7 +693,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object EdtFDConnDefFileName: TEdit
|
||||
Left = 161
|
||||
Top = 129
|
||||
Top = 142
|
||||
Width = 230
|
||||
Height = 21
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
@ -699,7 +702,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object EdtConnDefName: TEdit
|
||||
Left = 161
|
||||
Top = 175
|
||||
Top = 188
|
||||
Width = 230
|
||||
Height = 21
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
@ -709,7 +712,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object GroupBoxJSONRPC: TGroupBox
|
||||
Left = 314
|
||||
Top = 438
|
||||
Top = 436
|
||||
Width = 407
|
||||
Height = 105
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
@ -748,7 +751,7 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object chkMSHeap: TCheckBox
|
||||
Left = 24
|
||||
Top = 292
|
||||
Top = 283
|
||||
Width = 225
|
||||
Height = 17
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
@ -757,50 +760,40 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
end
|
||||
object chkCustomConfigDotEnv: TCheckBox
|
||||
Left = 24
|
||||
Top = 273
|
||||
Top = 264
|
||||
Width = 225
|
||||
Height = 17
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
Caption = 'Generate custom .env configuration'
|
||||
TabOrder = 9
|
||||
end
|
||||
object chkMustache: TCheckBox
|
||||
Left = 24
|
||||
Top = 331
|
||||
Width = 225
|
||||
Height = 17
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
Caption = 'Use Mustache as Server Side View engine'
|
||||
TabOrder = 10
|
||||
OnClick = chkMustacheClick
|
||||
end
|
||||
object chkServicesContainer: TCheckBox
|
||||
Left = 24
|
||||
Top = 351
|
||||
Top = 303
|
||||
Width = 225
|
||||
Height = 17
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
Caption = 'Use Services Container'
|
||||
Checked = True
|
||||
State = cbChecked
|
||||
TabOrder = 11
|
||||
TabOrder = 10
|
||||
end
|
||||
object chkSqids: TCheckBox
|
||||
Left = 24
|
||||
Top = 371
|
||||
Top = 323
|
||||
Width = 225
|
||||
Height = 17
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
Caption = 'Use Sqids'
|
||||
Checked = True
|
||||
State = cbChecked
|
||||
TabOrder = 12
|
||||
TabOrder = 11
|
||||
end
|
||||
object rgNameCase: TRadioGroup
|
||||
Left = 314
|
||||
Top = 351
|
||||
Top = 362
|
||||
Width = 407
|
||||
Height = 81
|
||||
Height = 63
|
||||
Caption = 'Default style for serialized property names (MVCNameCaseDefault)'
|
||||
Columns = 3
|
||||
ItemIndex = 2
|
||||
@ -811,17 +804,23 @@ object frmDMVCNewProject: TfrmDMVCNewProject
|
||||
'CamelCase (fooBar)'
|
||||
'PascalCase (FooBar)'
|
||||
'SnakeCase (foo_bar)')
|
||||
TabOrder = 13
|
||||
TabOrder = 12
|
||||
end
|
||||
object chkTemplatePro: TCheckBox
|
||||
Left = 24
|
||||
Top = 312
|
||||
Width = 245
|
||||
Height = 17
|
||||
Anchors = [akLeft, akRight, akBottom]
|
||||
Caption = 'Use TemplatePro as Server Side View engine'
|
||||
TabOrder = 14
|
||||
OnClick = chkTemplateProClick
|
||||
object rgSSV: TRadioGroup
|
||||
Left = 12
|
||||
Top = 362
|
||||
Width = 296
|
||||
Height = 63
|
||||
Caption = 'Server Side Views Template Engine'
|
||||
Columns = 2
|
||||
ItemIndex = 0
|
||||
Items.Strings = (
|
||||
'None'
|
||||
'TemplatePro'
|
||||
'WebStencils'
|
||||
'Mustache')
|
||||
TabOrder = 13
|
||||
OnClick = rgSSVClick
|
||||
end
|
||||
object ApplicationEvents: TApplicationEvents
|
||||
OnIdle = ApplicationEventsIdle
|
||||
|
@ -32,6 +32,8 @@
|
||||
|
||||
unit DMVC.Expert.Forms.NewProjectWizard;
|
||||
|
||||
{$I dmvcframework.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
@ -97,11 +99,10 @@ type
|
||||
chkCustomConfigDotEnv: TCheckBox;
|
||||
chkProfileActions: TCheckBox;
|
||||
lblPATREON: TLabel;
|
||||
chkMustache: TCheckBox;
|
||||
chkServicesContainer: TCheckBox;
|
||||
chkSqids: TCheckBox;
|
||||
rgNameCase: TRadioGroup;
|
||||
chkTemplatePro: TCheckBox;
|
||||
rgSSV: TRadioGroup;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure Image1Click(Sender: TObject);
|
||||
procedure lblBookMouseEnter(Sender: TObject);
|
||||
@ -116,8 +117,7 @@ type
|
||||
procedure lblPATREONClick(Sender: TObject);
|
||||
procedure lblPATREONMouseEnter(Sender: TObject);
|
||||
procedure lblPATREONMouseLeave(Sender: TObject);
|
||||
procedure chkMustacheClick(Sender: TObject);
|
||||
procedure chkTemplateProClick(Sender: TObject);
|
||||
procedure rgSSVClick(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
fModel: TJsonObject;
|
||||
@ -177,18 +177,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TfrmDMVCNewProject.chkMustacheClick(Sender: TObject);
|
||||
begin
|
||||
if chkMustache.Checked then
|
||||
chkTemplatePro.Checked := False;
|
||||
end;
|
||||
|
||||
procedure TfrmDMVCNewProject.chkTemplateProClick(Sender: TObject);
|
||||
begin
|
||||
if chkTemplatePro.Checked then
|
||||
chkMustache.Checked := False;
|
||||
end;
|
||||
|
||||
procedure TfrmDMVCNewProject.FormCreate(Sender: TObject);
|
||||
begin
|
||||
edtControllerClassName.TextHint := TDefaultValues.sDefaultControllerName;
|
||||
@ -287,6 +275,18 @@ begin
|
||||
lblPATREON.Font.Style := lblPATREON.Font.Style - [fsUnderline];
|
||||
end;
|
||||
|
||||
procedure TfrmDMVCNewProject.rgSSVClick(Sender: TObject);
|
||||
begin
|
||||
{$if not Defined(WEBSTENCILS)}
|
||||
if SameText(rgSSV.Items[rgSSV.ItemIndex], 'webstencils') then
|
||||
begin
|
||||
ShowMessage('This Delphi version doesn''t support WebStencils, so DMVCFramework cannot use it.' +
|
||||
sLineBreak + 'Consider to use TemplatePro.');
|
||||
rgSSV.ItemIndex := 1;
|
||||
end;
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
procedure TfrmDMVCNewProject.lblBookClick(Sender: TObject);
|
||||
begin
|
||||
ShellExecute(0, PChar('open'),
|
||||
@ -348,8 +348,9 @@ begin
|
||||
fModel.B[TConfigKey.program_msheap] := chkMSHeap.Checked;
|
||||
fModel.B[TConfigKey.program_sqids] := chkSqids.Checked;
|
||||
fModel.B[TConfigKey.program_dotenv] := chkCustomConfigDotEnv.Checked;
|
||||
fModel.B[TConfigKey.program_ssv_mustache] := chkMustache.Checked;
|
||||
fModel.B[TConfigKey.program_ssv_templatepro] := chkTemplatePro.Checked;
|
||||
fModel.B[TConfigKey.program_ssv_templatepro] := SameText(rgSSV.Items[rgSSV.ItemIndex], 'templatepro');
|
||||
fModel.B[TConfigKey.program_ssv_webstencils] := SameText(rgSSV.Items[rgSSV.ItemIndex], 'webstencils');
|
||||
fModel.B[TConfigKey.program_ssv_mustache] := SameText(rgSSV.Items[rgSSV.ItemIndex], 'mustache');
|
||||
fModel.B[TConfigKey.program_service_container_generate] := chkServicesContainer.Checked;
|
||||
fModel.S[TConfigKey.program_service_container_unit_name] := 'TBA';
|
||||
fModel.S[TConfigKey.controller_unit_name] := 'TBA';
|
||||
|
@ -110,6 +110,8 @@ begin
|
||||
lTemplateProHelpersUnitName: string;
|
||||
lEntityUnitName: string;
|
||||
EntityUnit: IOTAModule;
|
||||
lWebStencilsHelpersUnitName: string;
|
||||
WebStencilsHelperUnit: IOTAModule;
|
||||
begin
|
||||
WizardForm := TfrmDMVCNewProject.Create(Application);
|
||||
try
|
||||
@ -203,7 +205,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{********** SERVER SIDE VIEWS TEMPLATE ENGINE CONFIGURATION **************}
|
||||
|
||||
lMustacheHelpersUnitName := '';
|
||||
// Create Mustache Helpers Unit
|
||||
@ -243,6 +245,26 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
lWebStencilsHelpersUnitName := '';
|
||||
// Create WebStencils Helpers Unit
|
||||
if lJSON.B[TConfigKey.program_ssv_webstencils] then
|
||||
begin
|
||||
HelpersUnitCreator := TNewGenericUnitFromTemplate.Create(
|
||||
lJSON,
|
||||
FillWebStencilsTemplates,
|
||||
TConfigKey.webstencils_helpers_unit_name,
|
||||
APersonality);
|
||||
WebStencilsHelperUnit := ModuleServices.CreateModule(HelpersUnitCreator);
|
||||
ChangeIOTAModuleFileNamePrefix(WebStencilsHelperUnit, 'WebStencilsHelpers');
|
||||
lWebStencilsHelpersUnitName := GetUnitName(WebStencilsHelperUnit.FileName);
|
||||
lJSON.S[TConfigKey.webstencils_helpers_unit_name] := lWebStencilsHelpersUnitName;
|
||||
if Project <> nil then
|
||||
begin
|
||||
Project.AddFile(WebStencilsHelperUnit.FileName, True);
|
||||
end;
|
||||
end;
|
||||
|
||||
{******** END - SERVER SIDE VIEWS TEMPLATE ENGINE CONFIGURATION ************}
|
||||
|
||||
// Create Webmodule Unit
|
||||
WebModuleCreator := TNewWebModuleUnitEx.Create(
|
||||
|
@ -33,7 +33,8 @@ type
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.StrUtils, System.SysUtils, MVCFramework.Logger, MVCFramework.HTMX, RandomUtilsU;
|
||||
System.StrUtils, System.SysUtils, MVCFramework.Logger, MVCFramework.HTMX, RandomUtilsU,
|
||||
TemplatePro;
|
||||
|
||||
function TMyController.Customers: String;
|
||||
begin
|
||||
@ -63,7 +64,7 @@ begin
|
||||
var lPosts := GetPosts(20);
|
||||
try
|
||||
ViewData['posts'] := lPosts;
|
||||
Result := Page(['pages/posts']);
|
||||
Result := Page('pages/posts');
|
||||
finally
|
||||
lPosts.Free;
|
||||
end;
|
||||
@ -74,7 +75,11 @@ begin
|
||||
var lUsers := GetUsers();
|
||||
try
|
||||
ViewData['users'] := lUsers;
|
||||
Result := Page(['pages/users']);
|
||||
Result := Page('pages/users', False,
|
||||
procedure (const Tmpl: TObject)
|
||||
begin
|
||||
(Tmpl as TTProCompiledTemplate).SetData('var1', 1234);
|
||||
end);
|
||||
finally
|
||||
lUsers.Free;
|
||||
end;
|
||||
|
@ -2,30 +2,59 @@ unit HelpersU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.Rtti;
|
||||
|
||||
type
|
||||
TMyMustacheHelpers = class sealed
|
||||
public
|
||||
class procedure MyHelper1(const Value: variant; out Result: variant);
|
||||
class procedure MyHelper2(const Value: variant; out Result: variant);
|
||||
end;
|
||||
function MyHelper1(const Value: TValue; const Parameters: TArray<string>): TValue;
|
||||
function MyHelper2(const Value: TValue; const Parameters: TArray<string>): TValue;
|
||||
|
||||
|
||||
procedure TemplateProContextConfigure;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
MVCFramework.View.Renderers.Mustache, System.SysUtils;
|
||||
TemplatePro, System.SysUtils;
|
||||
|
||||
{ TMyMustacheHelpers }
|
||||
|
||||
class procedure TMyMustacheHelpers.MyHelper1(const Value: variant; out Result: variant);
|
||||
function MyHelper1(const Value: TValue; const Parameters: TArray<string>): TValue;
|
||||
begin
|
||||
Result := Value + ' (I''m The MyHelper1)';
|
||||
Result := Value.ToString + ' (I''m The MyHelper1)';
|
||||
end;
|
||||
|
||||
class procedure TMyMustacheHelpers.MyHelper2(const Value: variant; out Result: variant);
|
||||
function MyHelper2(const Value: TValue; const Parameters: TArray<string>): TValue;
|
||||
begin
|
||||
Result := Value + ' (I''m The MyHelper2)';
|
||||
Result := Value.ToString + ' (I''m The MyHelper2)';
|
||||
end;
|
||||
|
||||
|
||||
procedure TemplateProContextConfigure;
|
||||
begin
|
||||
TTProConfiguration.OnContextConfiguration := procedure(const CompiledTemplate: ITProCompiledTemplate)
|
||||
begin
|
||||
// These filters will be available to the TemplatePro views as if they were the standard ones
|
||||
CompiledTemplate.AddFilter('MyHelper1', MyHelper1);
|
||||
CompiledTemplate.AddFilter('MyHelper2', MyHelper2);
|
||||
|
||||
CompiledTemplate.OnGetValue :=
|
||||
procedure(const DataSource, Members: string; var Value: TValue; var Handled: Boolean)
|
||||
begin
|
||||
if SameText(DataSource, 'ext1') then
|
||||
begin
|
||||
if Members.IsEmpty then
|
||||
begin
|
||||
Value := 'External Value Ext1'
|
||||
end
|
||||
else
|
||||
begin
|
||||
Value := 'Reading ext1.' + Members;
|
||||
end;
|
||||
Handled := True;
|
||||
end;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
@ -56,7 +56,7 @@ begin
|
||||
//view path
|
||||
Config[TMVCConfigKey.ViewPath] := dotEnv.Env('dmvc.view_path', 'templates');
|
||||
//use cache for server side views (use "false" in debug and "true" in production for faster performances
|
||||
Config[TMVCConfigKey.ViewCache] := dotEnv.Env('dmvc.view_cache', 'false');
|
||||
Config[TMVCConfigKey.ViewCache] := dotEnv.Env('dmvc.view_cache', 'true');
|
||||
//Max Record Count for automatic Entities CRUD
|
||||
Config[TMVCConfigKey.MaxEntitiesRecordCount] := dotEnv.Env('dmvc.max_entities_record_count', IntToStr(TMVCConstants.MAX_RECORD_COUNT));
|
||||
//Enable Server Signature in response
|
||||
|
@ -1,4 +1,4 @@
|
||||
program htmx_website;
|
||||
program htmx_website_with_templatepro;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
@ -17,7 +17,8 @@ uses
|
||||
ControllerU in 'ControllerU.pas',
|
||||
WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule},
|
||||
RandomUtilsU in '..\commons\RandomUtilsU.pas',
|
||||
TemplatePro in '..\..\sources\TemplatePro.pas';
|
||||
TemplatePro in '..\..\sources\TemplatePro.pas',
|
||||
HelpersU in 'HelpersU.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
@ -68,7 +69,7 @@ begin
|
||||
Profiler.WarningThreshold := dotEnv.Env('dmvc.profiler.warning_threshold', 2000);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
TemplateProContextConfigure;
|
||||
RunServer(dotEnv.Env('dmvc.server.port', 8080));
|
||||
except
|
||||
on E: Exception do
|
@ -6,10 +6,10 @@
|
||||
<Base>True</Base>
|
||||
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||
<ProjectName Condition="'$(ProjectName)'==''">htmx_website</ProjectName>
|
||||
<ProjectName Condition="'$(ProjectName)'==''">htmx_website_with_templatepro</ProjectName>
|
||||
<TargetedPlatforms>1</TargetedPlatforms>
|
||||
<AppType>Console</AppType>
|
||||
<MainSource>htmx_website.dpr</MainSource>
|
||||
<MainSource>htmx_website_with_templatepro.dpr</MainSource>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
@ -69,7 +69,7 @@
|
||||
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
|
||||
<DCC_UnitSearchPath>$(DMVC);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
|
||||
<DCC_Framework>FMX;$(DCC_Framework)</DCC_Framework>
|
||||
<SanitizedProjectName>htmx_website</SanitizedProjectName>
|
||||
<SanitizedProjectName>htmx_website_with_templatepro</SanitizedProjectName>
|
||||
<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>
|
||||
@ -128,6 +128,7 @@
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\commons\RandomUtilsU.pas"/>
|
||||
<DCCReference Include="..\..\sources\TemplatePro.pas"/>
|
||||
<DCCReference Include="HelpersU.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
@ -146,7 +147,7 @@
|
||||
<BorlandProject>
|
||||
<Delphi.Personality>
|
||||
<Source>
|
||||
<Source Name="MainSource">htmx_website.dpr</Source>
|
||||
<Source Name="MainSource">htmx_website_with_templatepro.dpr</Source>
|
||||
</Source>
|
||||
<Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
@ -172,9 +173,9 @@
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="bin\htmx_website.exe" Configuration="Debug" Class="ProjectOutput"/>
|
||||
<DeployFile LocalName="bin\htmx_website.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<DeployFile LocalName="bin\htmx_website_with_templatepro.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>htmx_website.exe</RemoteName>
|
||||
<RemoteName>htmx_website_with_templatepro.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
@ -4,7 +4,7 @@ interface
|
||||
|
||||
uses
|
||||
MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons,
|
||||
System.Generics.Collections;
|
||||
System.Generics.Collections, Web.Stencils;
|
||||
|
||||
type
|
||||
[MVCPath]
|
||||
@ -53,7 +53,7 @@ begin
|
||||
var lPosts := GetPosts(20);
|
||||
try
|
||||
ViewData['posts'] := lPosts;
|
||||
Result := Page('posts' + IfThen(Context.Request.IsHTMX, '_body'))
|
||||
Result := Page('posts' + IfThen(Context.Request.IsHTMX, '_body'));
|
||||
finally
|
||||
lPosts.Free;
|
||||
end;
|
||||
|
@ -2,30 +2,57 @@ unit HelpersU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.Rtti, System.Bindings.EvalProtocol;
|
||||
|
||||
type
|
||||
TMyMustacheHelpers = class sealed
|
||||
public
|
||||
class procedure MyHelper1(const Value: variant; out Result: variant);
|
||||
class procedure MyHelper2(const Value: variant; out Result: variant);
|
||||
end;
|
||||
function MyHelper1(const Parameters: TArray<IValue>): TValue;
|
||||
function MyHelper2(const Parameters: TArray<IValue>): TValue;
|
||||
|
||||
|
||||
procedure WebStencilsProcessorConfigure;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
MVCFramework.View.Renderers.Mustache, System.SysUtils;
|
||||
System.SysUtils, MVCFramework.View.Renderers.WebStencils, System.Bindings.Methods, Web.Stencils;
|
||||
|
||||
{ TMyMustacheHelpers }
|
||||
|
||||
class procedure TMyMustacheHelpers.MyHelper1(const Value: variant; out Result: variant);
|
||||
function MyHelper1(const Parameters: TArray<IValue>): TValue;
|
||||
begin
|
||||
Result := Value + ' (I''m The MyHelper1)';
|
||||
Result := Parameters[0].GetValue.ToString + ' (I''m The MyHelper1)';
|
||||
end;
|
||||
|
||||
class procedure TMyMustacheHelpers.MyHelper2(const Value: variant; out Result: variant);
|
||||
function MyHelper2(const Parameters: TArray<IValue>): TValue;
|
||||
begin
|
||||
Result := Value + ' (I''m The MyHelper2)';
|
||||
Result := Parameters[0].GetValue.ToString + ' (I''m The MyHelper2)';
|
||||
end;
|
||||
|
||||
procedure WebStencilsProcessorConfigure;
|
||||
begin
|
||||
TBindingMethodsFactory.RegisterMethod(
|
||||
TMethodDescription.Create(
|
||||
MakeInvokable(function(Args: TArray<IValue>): IValue
|
||||
begin
|
||||
Result := TValueWrapper.Create(MyHelper1(Args));
|
||||
end),
|
||||
'MyHelper1', 'MyHelper1', '', True, 'MyHelper1 is just a sample', nil));
|
||||
|
||||
|
||||
TBindingMethodsFactory.RegisterMethod(
|
||||
TMethodDescription.Create(
|
||||
MakeInvokable(function(Args: TArray<IValue>): IValue
|
||||
begin
|
||||
Result := TValueWrapper.Create(MyHelper2(Args));
|
||||
end),
|
||||
'MyHelper2', 'MyHelper2', '', True, 'MyHelper2 is just a sample', nil));
|
||||
|
||||
TMVCWebStencilsConfiguration.OnProcessorConfiguration :=
|
||||
procedure(const WebStencilsProcessor: TWebStencilsProcessor)
|
||||
begin
|
||||
//custom configuration for TWebStencilsProcessor (executed for each view)
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<p>
|
||||
<article style="padding: 0.6rem">
|
||||
<header style="font-size: 140%">
|
||||
@(MyHelper2("ciao mondo"))
|
||||
@(uppercase(p.title))
|
||||
</header>
|
||||
@p.abstract
|
||||
|
@ -17,7 +17,8 @@ uses
|
||||
MVCFramework.View.Renderers.WebStencils,
|
||||
ControllerU in 'ControllerU.pas',
|
||||
WebModuleU in 'WebModuleU.pas' {MyWebModule: TWebModule},
|
||||
RandomUtilsU in '..\commons\RandomUtilsU.pas';
|
||||
RandomUtilsU in '..\commons\RandomUtilsU.pas',
|
||||
HelpersU in 'HelpersU.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
@ -68,7 +69,7 @@ begin
|
||||
Profiler.WarningThreshold := dotEnv.Env('dmvc.profiler.warning_threshold', 2000);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
WebStencilsProcessorConfigure;
|
||||
RunServer(dotEnv.Env('dmvc.server.port', 8080));
|
||||
except
|
||||
on E: Exception do
|
||||
|
@ -126,6 +126,7 @@
|
||||
<DesignClass>TWebModule</DesignClass>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\commons\RandomUtilsU.pas"/>
|
||||
<DCCReference Include="HelpersU.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
|
@ -419,7 +419,7 @@ type
|
||||
{ public declarations }
|
||||
end;
|
||||
|
||||
EMVCFrameworkViewException = class(EMVCException)
|
||||
EMVCSSVException = class(EMVCException)
|
||||
private
|
||||
{ private declarations }
|
||||
protected
|
||||
|
@ -54,6 +54,7 @@ type
|
||||
public
|
||||
procedure Execute(const ViewName: string; const Builder: TStringBuilder); override;
|
||||
constructor Create(const AEngine: TMVCEngine; const AWebContext: TWebContext;
|
||||
const AController: TMVCController;
|
||||
const AViewModel: TMVCViewDataObject;
|
||||
const AContentType: string); override;
|
||||
class destructor Destroy;
|
||||
@ -98,8 +99,8 @@ var
|
||||
gHelpersLoaded : Boolean = False;
|
||||
|
||||
constructor TMVCMustacheViewEngine.Create(const AEngine: TMVCEngine;
|
||||
const AWebContext: TWebContext; const AViewModel: TMVCViewDataObject;
|
||||
const AContentType: string);
|
||||
const AWebContext: TWebContext; const AController: TMVCController;
|
||||
const AViewModel: TMVCViewDataObject; const AContentType: string);
|
||||
begin
|
||||
inherited;
|
||||
fModelPrepared := False;
|
||||
@ -137,7 +138,7 @@ begin
|
||||
PrepareModels;
|
||||
lViewFileName := GetRealFileName(ViewName);
|
||||
if lViewFileName.IsEmpty then
|
||||
raise EMVCFrameworkViewException.CreateFmt('View [%s] not found', [ViewName]);
|
||||
raise EMVCSSVException.CreateFmt('View [%s] not found', [ViewName]);
|
||||
lViewTemplate := StringToUTF8(TFile.ReadAllText(lViewFileName, TEncoding.UTF8));
|
||||
lViewEngine := TSynMustache.Parse(lViewTemplate);
|
||||
Builder.Append(UTF8Tostring(RenderJSON(lViewEngine, FJSONModelAsString, fPartials, fHelpers, nil, false)));
|
||||
|
@ -128,7 +128,7 @@ begin
|
||||
lUseCompiledVersion := False;
|
||||
lViewFileName := GetRealFileName(ViewName);
|
||||
if lViewFileName.IsEmpty then
|
||||
raise EMVCFrameworkViewException.CreateFmt('View [%s] not found', [ViewName]);
|
||||
raise EMVCSSVException.CreateFmt('View [%s] not found', [ViewName]);
|
||||
if FUseViewCache then
|
||||
begin
|
||||
lCacheDir := TPath.Combine(TPath.GetDirectoryName(lViewFileName), '__cache__');
|
||||
@ -137,7 +137,7 @@ begin
|
||||
|
||||
if not FileAge(lViewFileName, lActualFileTimeStamp) then
|
||||
begin
|
||||
raise EMVCFrameworkViewException.CreateFmt('View [%s] not found',
|
||||
raise EMVCSSVException.CreateFmt('View [%s] not found',
|
||||
[ViewName]);
|
||||
end;
|
||||
|
||||
@ -188,6 +188,10 @@ begin
|
||||
Result := '(Error: Expected 1 param, got ' + Length(aParameters).ToString + ')';
|
||||
end;
|
||||
end);
|
||||
if Assigned(FBeforeRenderCallback) then
|
||||
begin
|
||||
FBeforeRenderCallback(TObject(lCompiledTemplate));
|
||||
end;
|
||||
Builder.Append(lCompiledTemplate.Render);
|
||||
except
|
||||
on E: ETProException do
|
||||
|
@ -24,30 +24,48 @@
|
||||
|
||||
unit MVCFramework.View.Renderers.WebStencils;
|
||||
|
||||
{$I dmvcframework.inc}
|
||||
|
||||
interface
|
||||
|
||||
{$if Defined(WEBSTENCILS)}
|
||||
|
||||
//This unit is usable from Delphi 12.2+
|
||||
|
||||
uses
|
||||
MVCFramework, System.Generics.Collections, System.SysUtils,
|
||||
MVCFramework.Commons, System.IOUtils, System.Classes;
|
||||
MVCFramework.Commons, System.IOUtils, System.Classes, Web.Stencils;
|
||||
|
||||
type
|
||||
TMVCWebStencilsEvent = reference to procedure(const WebStencilsProcessor: TWebStencilsProcessor);
|
||||
|
||||
{ This class implements the WebStencils view engine for server side views }
|
||||
TMVCWebStencilsViewEngine = class(TMVCBaseViewEngine)
|
||||
protected
|
||||
procedure OnFile(Sender: TObject; const AFilename: string; var AText: string; var AHandled: Boolean);
|
||||
public
|
||||
procedure Execute(const ViewName: string; const Builder: TStringBuilder); override;
|
||||
end;
|
||||
|
||||
TMVCWebStencilsConfiguration = class sealed
|
||||
private
|
||||
class var fOnProcessorConfiguration: TMVCWebStencilsEvent;
|
||||
public
|
||||
class property OnProcessorConfiguration: TMVCWebStencilsEvent
|
||||
read fOnProcessorConfiguration
|
||||
write fOnProcessorConfiguration;
|
||||
end;
|
||||
|
||||
{$endif}
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
{$if Defined(WEBSTENCILS)}
|
||||
uses
|
||||
MVCFramework.Serializer.Defaults,
|
||||
MVCFramework.Serializer.Intf,
|
||||
MVCFramework.DuckTyping,
|
||||
System.Bindings.EvalProtocol,
|
||||
System.Bindings.Methods,
|
||||
Web.Stencils,
|
||||
MVCFramework.Cache,
|
||||
Data.DB,
|
||||
System.Rtti,
|
||||
@ -121,6 +139,14 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function MakeMethodJSON: IInvokable;
|
||||
begin
|
||||
Result := MakeInvokable(function(Args: TArray<IValue>): IValue
|
||||
begin
|
||||
Result := TValueWrapper.Create(DumpAsJSONString(Args[0].GetValue.AsObject, []));
|
||||
end)
|
||||
end;
|
||||
|
||||
procedure RegisterWSFunctions(WSProcessor: TWebStencilsProcessor);
|
||||
begin
|
||||
if gFunctionInitialized then Exit;
|
||||
@ -128,13 +154,20 @@ begin
|
||||
try
|
||||
if gFunctionInitialized then Exit;
|
||||
gFunctionInitialized := True;
|
||||
|
||||
|
||||
TBindingMethodsFactory.RegisterMethod(
|
||||
TMethodDescription.Create(
|
||||
MakeInvokable(function(Args: TArray<IValue>): IValue
|
||||
begin
|
||||
if Length(Args) <> 1 then
|
||||
begin
|
||||
raise EMVCSSVException.Create(500, 'Expected 1 parameter in "JSON" function, got ' + Length(Args).ToString);
|
||||
end;
|
||||
Result := TValueWrapper.Create(DumpAsJSONString(Args[0].GetValue.AsObject, []));
|
||||
end),
|
||||
end) as IInvokable,
|
||||
'json', 'json', '', True, 'Serialize an object to JSON', nil));
|
||||
|
||||
finally
|
||||
TMonitor.Exit(gWSLock);
|
||||
end;
|
||||
@ -143,45 +176,24 @@ end;
|
||||
procedure TMVCWebStencilsViewEngine.Execute(const ViewName: string; const Builder: TStringBuilder);
|
||||
var
|
||||
lViewFileName: string;
|
||||
lViewTemplate: String;
|
||||
lWebStencilsProcessor: TWebStencilsProcessor;
|
||||
lPair: TPair<String, TValue>;
|
||||
lActualFileTimeStamp: TDateTime;
|
||||
lCompiledViewFileName: string;
|
||||
lActualCompiledFileTimeStamp: TDateTime;
|
||||
lUseCompiledVersion: Boolean;
|
||||
lCacheDir: string;
|
||||
begin
|
||||
lUseCompiledVersion := False;
|
||||
lViewFileName := GetRealFileName(ViewName);
|
||||
if lViewFileName.IsEmpty then
|
||||
raise EMVCFrameworkViewException.CreateFmt('View [%s] not found', [ViewName]);
|
||||
|
||||
// if FUseViewCache then
|
||||
// begin
|
||||
// lCacheDir := TPath.Combine(TPath.GetDirectoryName(lViewFileName), '__cache__');
|
||||
// TDirectory.CreateDirectory(lCacheDir);
|
||||
// lCompiledViewFileName := TPath.Combine(lCacheDir, TPath.ChangeExtension(TPath.GetFileName(lViewFileName), '.' + WebStencils_VERSION + '.tpcu'));
|
||||
//
|
||||
// if not FileAge(lViewFileName, lActualFileTimeStamp) then
|
||||
// begin
|
||||
// raise EMVCFrameworkViewException.CreateFmt('View [%s] not found',
|
||||
// [ViewName]);
|
||||
// end;
|
||||
//
|
||||
// if FileAge(lCompiledViewFileName, lActualCompiledFileTimeStamp) then
|
||||
// begin
|
||||
// lUseCompiledVersion := lActualFileTimeStamp < lActualCompiledFileTimeStamp;
|
||||
// end;
|
||||
// end;
|
||||
raise EMVCSSVException.CreateFmt('View [%s] not found', [ViewName]);
|
||||
|
||||
lWebStencilsProcessor := TWebStencilsProcessor.Create(nil);
|
||||
try
|
||||
RegisterWSFunctions(lWebStencilsProcessor);
|
||||
try
|
||||
//lWebStencilsProcessor.OnFile := Self.OnFile;
|
||||
if Assigned(TMVCWebStencilsConfiguration.fOnProcessorConfiguration) then
|
||||
begin
|
||||
TMVCWebStencilsConfiguration.OnProcessorConfiguration(lWebStencilsProcessor);
|
||||
end;
|
||||
//lWebStencilsProcessor.OnFile := Self.OnFile; {12.2, any filename starting with ..\ is not read correctly by the parser. Is it a feature? }
|
||||
lWebStencilsProcessor.InputFileName := lViewFileName;
|
||||
lWebStencilsProcessor.PathTemplate := TPath.GetDirectoryName(lViewFileName);
|
||||
lWebStencilsProcessor.PathTemplate := Config[TMVCConfigKey.ViewPath];
|
||||
if Assigned(ViewModel) then
|
||||
begin
|
||||
for lPair in ViewModel do
|
||||
@ -190,6 +202,10 @@ begin
|
||||
lWebStencilsProcessor.AddVar(lPair.Key, ViewModel[lPair.Key].AsObject, False);
|
||||
end;
|
||||
end;
|
||||
if Assigned(FBeforeRenderCallback) then
|
||||
begin
|
||||
FBeforeRenderCallback(lWebStencilsProcessor);
|
||||
end;
|
||||
Builder.Append(lWebStencilsProcessor.Content);
|
||||
except
|
||||
on E: EWebStencilsException do
|
||||
@ -203,28 +219,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCWebStencilsViewEngine.OnFile(Sender: TObject; const AFilename: string; var AText: string;
|
||||
var AHandled: Boolean);
|
||||
var
|
||||
lFName: String;
|
||||
begin
|
||||
lFName := AFilename;
|
||||
if TPath.GetExtension(lFName).IsEmpty then
|
||||
begin
|
||||
lFName := lFName + '.' + Config[TMVCConfigKey.DefaultViewFileExtension];
|
||||
end;
|
||||
if not TFile.Exists(lFName) then
|
||||
begin
|
||||
lFName := TPath.Combine(Config[TMVCConfigKey.ViewPath], lFName);
|
||||
if not TFile.Exists(lFName) then
|
||||
begin
|
||||
lFName := TPath.Combine(AppPath, lFName);
|
||||
end;
|
||||
end;
|
||||
AText := TFile.ReadAllText(lFName);
|
||||
AHandled := True;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
gWSLock := TObject.Create;
|
||||
@ -233,5 +227,6 @@ finalization
|
||||
|
||||
FreeAndNil(gWSLock);
|
||||
|
||||
{$endif}
|
||||
|
||||
end.
|
||||
|
@ -883,6 +883,8 @@ type
|
||||
const Retry: Integer = TMVCConstants.SSE_RETRY_DEFAULT);
|
||||
end;
|
||||
|
||||
TMVCSSVBeforeRenderCallback = reference to procedure(const TemplateRenderInstance: TObject);
|
||||
|
||||
TMVCController = class(TMVCRenderer)
|
||||
private
|
||||
FViewModel: TMVCViewDataObject;
|
||||
@ -904,8 +906,8 @@ type
|
||||
function GetClientId: string;
|
||||
function GetCurrentWebModule: TWebModule;
|
||||
function GetViewModel: TMVCViewDataObject;
|
||||
function GetRenderedView(const AViewNames: TArray<string>): string; overload; virtual;
|
||||
function GetRenderedView(const AViewNames: TArray<string>; const JSONModel: TJSONObject): string; overload; virtual;
|
||||
function GetRenderedView(const AViewNames: TArray<string>; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; virtual;
|
||||
function GetRenderedView(const AViewNames: TArray<string>; const JSONModel: TJSONObject; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; virtual;
|
||||
|
||||
/// <summary>
|
||||
/// Normally used in OnBeforeControllerAction to define view headers automatically used by the Page method.
|
||||
@ -922,27 +924,28 @@ type
|
||||
/// Page method just concatenate -> commonheader_header_views + views + commonfooter_views
|
||||
/// PageFragment ignore header and footer views
|
||||
/// </summary>
|
||||
function Page(const AViewNames: TArray<string>; const UseCommonHeadersAndFooters: Boolean = True): string; overload; inline;
|
||||
function Page(const AViewName: string; const UseCommonHeadersAndFooters: Boolean = True): string; overload; inline;
|
||||
function Page(const AViewNames: TArray<string>; const UseCommonHeadersAndFooters: Boolean = True; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; inline;
|
||||
function Page(const AViewName: string; const UseCommonHeadersAndFooters: Boolean = True; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; inline;
|
||||
|
||||
/// <summary>
|
||||
/// Page calls GetRenderedView with sensible defaults.
|
||||
/// Page method with UseCommonHeadersAndFooters = True (default) concatenates
|
||||
// commonheader_header_views + views + commonfooter_views
|
||||
/// </summary>
|
||||
function Page(const AViewNames: TArray<string>; const JSONModel: TJSONObject; const UseCommonHeadersAndFooters: Boolean = True): string; overload; inline;
|
||||
function Page(const AViewNames: TArray<string>; const JSONModel: TJSONObject;
|
||||
const UseCommonHeadersAndFooters: Boolean = True; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; inline;
|
||||
|
||||
/// <summary>
|
||||
/// PageFragment calls GetRenderedView.
|
||||
/// PageFragment ignore header and footer views.
|
||||
/// </summary>
|
||||
function PageFragment(const AViewNames: TArray<string>): string; overload; inline;
|
||||
function PageFragment(const AViewNames: TArray<string>; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; inline;
|
||||
|
||||
/// <summary>
|
||||
/// PageFragment calls GetRenderedView.
|
||||
/// PageFragment ignore header and footer views.
|
||||
/// </summary>
|
||||
function PageFragment(const AViewNames: TArray<string>; const JSONModel: TJSONObject): string; overload; inline;
|
||||
function PageFragment(const AViewNames: TArray<string>; const JSONModel: TJSONObject; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback = nil): string; overload; inline;
|
||||
|
||||
/// <summary>
|
||||
/// Load mustache view located in TMVCConfigKey.ViewsPath
|
||||
@ -1277,18 +1280,24 @@ type
|
||||
FViewModel: TMVCViewDataObject;
|
||||
FContentType: string;
|
||||
FOutput: string;
|
||||
FController: TMVCController;
|
||||
protected
|
||||
FUseViewCache: Boolean;
|
||||
FJSONModel: TJSONObject;
|
||||
FBeforeRenderCallback: TMVCSSVBeforeRenderCallback;
|
||||
function GetRealFileName(const AViewName: string): string; virtual;
|
||||
function IsCompiledVersionUpToDate(const AFileName, ACompiledFileName: string): Boolean; virtual; abstract;
|
||||
public
|
||||
constructor Create(const AEngine: TMVCEngine; const AWebContext: TWebContext;
|
||||
constructor Create(
|
||||
const AEngine: TMVCEngine;
|
||||
const AWebContext: TWebContext;
|
||||
const AController: TMVCController;
|
||||
const AViewModel: TMVCViewDataObject;
|
||||
const AContentType: string); overload; virtual;
|
||||
constructor Create(
|
||||
const AEngine: TMVCEngine;
|
||||
const AWebContext: TWebContext;
|
||||
const AController: TMVCController;
|
||||
const AViewModel: TMVCViewDataObject;
|
||||
const AJSONModel: TJSONObject;
|
||||
const AContentType: string); overload; virtual;
|
||||
@ -4188,14 +4197,15 @@ begin
|
||||
Result := Context.Request.GetHeader('If-None-Match');
|
||||
end;
|
||||
|
||||
function TMVCController.GetRenderedView(const AViewNames: TArray<string>; const JSONModel: TJSONObject): string;
|
||||
function TMVCController.GetRenderedView(const AViewNames: TArray<string>; const JSONModel: TJSONObject; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
var
|
||||
lView: TMVCBaseViewEngine; lViewName: string; lStrStream: TStringBuilder;
|
||||
begin
|
||||
lStrStream := TStringBuilder.Create;
|
||||
try
|
||||
lView := FEngine.ViewEngineClass.Create(Engine, Context, FViewModel, JSONModel, ContentType);
|
||||
lView := FEngine.ViewEngineClass.Create(Engine, Context, Self, FViewModel, JSONModel, ContentType);
|
||||
try
|
||||
lView.FBeforeRenderCallback := OnBeforeRenderCallback;
|
||||
for lViewName in AViewNames do
|
||||
begin
|
||||
lView.Execute(lViewName, lStrStream);
|
||||
@ -4385,36 +4395,36 @@ begin
|
||||
end;
|
||||
|
||||
function TMVCController.Page(const AViewNames: TArray<string>;
|
||||
const JSONModel: TJSONObject; const UseCommonHeadersAndFooters: Boolean): string;
|
||||
const JSONModel: TJSONObject; const UseCommonHeadersAndFooters: Boolean; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
begin
|
||||
if UseCommonHeadersAndFooters then
|
||||
Result := GetRenderedView(fPageHeaders + AViewNames + fPageFooters, JSONModel)
|
||||
Result := GetRenderedView(fPageHeaders + AViewNames + fPageFooters, JSONModel, OnBeforeRenderCallback)
|
||||
else
|
||||
Result := GetRenderedView(AViewNames, JSONModel)
|
||||
Result := GetRenderedView(AViewNames, JSONModel, OnBeforeRenderCallback)
|
||||
end;
|
||||
|
||||
function TMVCController.Page(const AViewName: string; const UseCommonHeadersAndFooters: Boolean): string;
|
||||
function TMVCController.Page(const AViewName: string; const UseCommonHeadersAndFooters: Boolean; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
begin
|
||||
Result := Page([AViewName], UseCommonHeadersAndFooters);
|
||||
Result := Page([AViewName], UseCommonHeadersAndFooters, OnBeforeRenderCallback);
|
||||
end;
|
||||
|
||||
function TMVCController.PageFragment(const AViewNames: TArray<string>;
|
||||
const JSONModel: TJSONObject): string;
|
||||
const JSONModel: TJSONObject; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
begin
|
||||
Result := Page(AViewNames, JSONModel, False);
|
||||
Result := Page(AViewNames, JSONModel, False, OnBeforeRenderCallback);
|
||||
end;
|
||||
|
||||
function TMVCController.PageFragment(const AViewNames: TArray<string>): string;
|
||||
function TMVCController.PageFragment(const AViewNames: TArray<string>; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
begin
|
||||
Result := Page(AViewNames, nil, False);
|
||||
end;
|
||||
|
||||
function TMVCController.Page(const AViewNames: TArray<string>; const UseCommonHeadersAndFooters: Boolean): string;
|
||||
function TMVCController.Page(const AViewNames: TArray<string>; const UseCommonHeadersAndFooters: Boolean; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
begin
|
||||
if UseCommonHeadersAndFooters then
|
||||
Result := GetRenderedView(fPageHeaders + AViewNames + fPageFooters)
|
||||
Result := GetRenderedView(fPageHeaders + AViewNames + fPageFooters, OnBeforeRenderCallback)
|
||||
else
|
||||
Result := GetRenderedView(AViewNames);
|
||||
Result := GetRenderedView(AViewNames, OnBeforeRenderCallback);
|
||||
end;
|
||||
|
||||
procedure TMVCController.PushObjectToView(const aModelName: string; const AModel: TObject);
|
||||
@ -4835,7 +4845,7 @@ begin
|
||||
Render<T>(ACollection, AOwns, ASerializationAction);
|
||||
end;
|
||||
|
||||
function TMVCController.GetRenderedView(const AViewNames: TArray<string>): string;
|
||||
function TMVCController.GetRenderedView(const AViewNames: TArray<string>; const OnBeforeRenderCallback: TMVCSSVBeforeRenderCallback): string;
|
||||
var
|
||||
lView: TMVCBaseViewEngine;
|
||||
lViewName: string;
|
||||
@ -4844,10 +4854,13 @@ begin
|
||||
lStrStream := TStringBuilder.Create;
|
||||
try
|
||||
lView := FEngine.ViewEngineClass.Create(
|
||||
Engine, Context,
|
||||
Engine,
|
||||
Context,
|
||||
Self,
|
||||
FViewModel,
|
||||
ContentType);
|
||||
try
|
||||
lView.FBeforeRenderCallback := OnBeforeRenderCallback;
|
||||
for lViewName in AViewNames do
|
||||
begin
|
||||
lView.Execute(lViewName, lStrStream);
|
||||
@ -5224,12 +5237,14 @@ end;
|
||||
constructor TMVCBaseViewEngine.Create(
|
||||
const AEngine: TMVCEngine;
|
||||
const AWebContext: TWebContext;
|
||||
const AController: TMVCController;
|
||||
const AViewModel: TMVCViewDataObject;
|
||||
const AContentType: string);
|
||||
begin
|
||||
inherited Create;
|
||||
Engine := AEngine;
|
||||
FWebContext := AWebContext;
|
||||
FController := AController;
|
||||
FViewModel := AViewModel;
|
||||
FContentType := AContentType;
|
||||
FOutput := EmptyStr;
|
||||
@ -5239,11 +5254,12 @@ end;
|
||||
constructor TMVCBaseViewEngine.Create(
|
||||
const AEngine: TMVCEngine;
|
||||
const AWebContext: TWebContext;
|
||||
const AController: TMVCController;
|
||||
const AViewModel: TMVCViewDataObject;
|
||||
const AJSONModel: TJSONObject;
|
||||
const AContentType: string);
|
||||
begin
|
||||
Create(AEngine, AWebContext, AViewModel, AContentType);
|
||||
Create(AEngine, AWebContext, AController, AViewModel, AContentType);
|
||||
fJSONModel := AJSONModel;
|
||||
end;
|
||||
|
||||
|
@ -104,3 +104,9 @@ DelphiMVCFramework is compatible with Delphi version XE7 or better
|
||||
{$DEFINE CUSTOM_MANAGED_RECORDS}
|
||||
{$ENDIF}
|
||||
|
||||
{$UNDEF WEBSTENCILS}
|
||||
{$IF Defined(ATHENSORBETTER)}
|
||||
{$IF declared(RTLVersion122) or (RTLVersion >= 37)}
|
||||
{$DEFINE WEBSTENCILS}
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
Loading…
Reference in New Issue
Block a user