Browse Source

* add IfTemplate

Michaël Van Canneyt 3 years ago
parent
commit
046777532e
1 changed files with 90 additions and 10 deletions
  1. 90 10
      packages/rtl/Rtl.TemplateLoader.pas

+ 90 - 10
packages/rtl/Rtl.TemplateLoader.pas

@@ -30,24 +30,38 @@ Type
   TTemplateNotifyEvent = Reference to Procedure(Sender : TObject; Const aTemplate : String);
   TTemplateNotifyEvent = Reference to Procedure(Sender : TObject; Const aTemplate : String);
   TTemplateErrorNotifyEvent = Reference to Procedure(Sender : TObject; Const aTemplate,aError : String; aErrorcode : Integer);
   TTemplateErrorNotifyEvent = Reference to Procedure(Sender : TObject; Const aTemplate,aError : String; aErrorcode : Integer);
 
 
+  TTemplateNotification = Record
+    Name : string;
+    Event  : TTemplateNotifyEvent;
+  end;
+  TTemplateNotificationDynArray = Array of TTemplateNotification;
+
+
   { TCustomTemplateLoader }
   { TCustomTemplateLoader }
 
 
   TCustomTemplateLoader = Class(TComponent)
   TCustomTemplateLoader = Class(TComponent)
   Private
   Private
     FBaseURL: String;
     FBaseURL: String;
+    FCheckResources: Boolean;
     FOnLoad: TTemplateNotifyEvent;
     FOnLoad: TTemplateNotifyEvent;
     FOnLoadFail: TTemplateErrorNotifyEvent;
     FOnLoadFail: TTemplateErrorNotifyEvent;
     FTemplates : TJSObject;
     FTemplates : TJSObject;
-    function GetTemplate(aName : String): String;
-    procedure SetTemplate(aName : String; AValue: String);
+    FNotifications : TTemplateNotificationDynArray;
+    function IndexOfTemplateEvent(aName: String): Integer;
+    function GetTemplate(const aName : String): String;
+    procedure SetTemplate(const aName : String; const AValue: String);
   Protected
   Protected
+    function CheckTemplateResource(const aName: string): string; virtual;
+    Procedure TemplateLoaded(const aName,aTemplate : String); virtual;
     // Process an url before it is used to fetch data
     // Process an url before it is used to fetch data
-    Function ProcessURL(const aURL : String) : String;
+    Function ProcessURL(const aURL : String) : String; virtual;
   Public
   Public
     Constructor Create (aOwner : TComponent); override;
     Constructor Create (aOwner : TComponent); override;
     Destructor Destroy; override;
     Destructor Destroy; override;
+    // call aEvent when template aName is loaded.
+    Procedure IfTemplate(const aName : String; aEvent : TTemplateNotifyEvent);
     // Remove a template
     // Remove a template
-    Procedure RemoveRemplate(aName : String);
+    Procedure RemoveRemplate(const aName : String);
     // fetch a template using promise. Promise resolves to template name. On fail a TFailData record is passed on.
     // fetch a template using promise. Promise resolves to template name. On fail a TFailData record is passed on.
     // Note that the global OnLoad/OnLoadFail a
     // Note that the global OnLoad/OnLoadFail a
     Function FetchTemplate(Const aName,aURL : String) : TJSPromise;
     Function FetchTemplate(Const aName,aURL : String) : TJSPromise;
@@ -60,6 +74,9 @@ Type
     Procedure LoadTemplates(Const Templates : Array of String; aOnSuccess : TTemplateNotifyEvent = Nil; AOnFail : TTemplateErrorNotifyEvent= nil);
     Procedure LoadTemplates(Const Templates : Array of String; aOnSuccess : TTemplateNotifyEvent = Nil; AOnFail : TTemplateErrorNotifyEvent= nil);
     // URLs will be relative to this. Take care that you add a / at the end if needed !
     // URLs will be relative to this. Take care that you add a / at the end if needed !
     Property BaseURL : String Read FBaseURL Write FBaseURl;
     Property BaseURL : String Read FBaseURL Write FBaseURl;
+    // Check resources for templates when accessing Templates.
+    Property CheckResources : Boolean Read FCheckResources Write FCheckResources;
+    // Access to templates based on name
     Property Templates[aName : String] : String Read GetTemplate Write SetTemplate; default;
     Property Templates[aName : String] : String Read GetTemplate Write SetTemplate; default;
     // Called when a template was loaded.
     // Called when a template was loaded.
     Property OnLoad : TTemplateNotifyEvent Read FOnLoad Write FOnLoad;
     Property OnLoad : TTemplateNotifyEvent Read FOnLoad Write FOnLoad;
@@ -79,6 +96,8 @@ Function GlobalTemplates : TCustomTemplateLoader;
 
 
 implementation
 implementation
 
 
+uses p2jsres, rtlconsts;
+
 { TCustomTemplateLoader }
 { TCustomTemplateLoader }
 
 
 Var
 Var
@@ -138,9 +157,7 @@ procedure TURLLoader.dofetch(resolve,reject : TJSPromiseResolver);
       Res.text._then(
       Res.text._then(
         function (value : JSValue) : JSValue
         function (value : JSValue) : JSValue
           begin
           begin
-          Loader.Templates[FName]:=String(Value);
-          if Assigned(Loader.FonLoad) then
-            Loader.FOnLoad(FLoader,Name);
+          Loader.TemplateLoaded(Name,String(Value));
           Result:=Resolve(Name);
           Result:=Resolve(Name);
           end
           end
       );
       );
@@ -167,7 +184,7 @@ begin
   Result:=TJSPromise.New(@Dofetch)
   Result:=TJSPromise.New(@Dofetch)
 end;
 end;
 
 
-function TCustomTemplateLoader.GetTemplate(aName : String): String;
+function TCustomTemplateLoader.GetTemplate(const aName : String): String;
 
 
 Var
 Var
   V : jsValue;
   V : jsValue;
@@ -176,15 +193,63 @@ begin
   V:=FTemplates[LowerCase(aName)];
   V:=FTemplates[LowerCase(aName)];
   if isString(V) then
   if isString(V) then
     Result:=String(V)
     Result:=String(V)
+  else if CheckResources then
+    Result:=CheckTemplateResource(aName)
   else
   else
     Result:='';
     Result:='';
 end;
 end;
 
 
-procedure TCustomTemplateLoader.SetTemplate(aName : String; AValue: String);
+// We need a polyfill for node.js
+Function atob (s : String) : string; external name 'atob';
+
+function TCustomTemplateLoader.CheckTemplateResource(const aName: string
+  ): string;
+
+Var
+  aInfo : TResourceInfo;
+
+begin
+  Result:='';
+  If GetResourceInfo(aName,aInfo) and (aInfo.format='application/octet-stream') then
+    if aInfo.Encoding='base64' then
+      Result:=atob(aInfo.Data)
+    else if (aInfo.Encoding='text') then
+      Result:=aInfo.Data
+    else
+      Raise EConvertError.CreateFmt(SErrUnknownResourceEncoding,[aInfo.Encoding]);
+end;
+
+procedure TCustomTemplateLoader.SetTemplate(const aName : String; const AValue: String);
 begin
 begin
   FTemplates[LowerCase(aName)]:=AValue;
   FTemplates[LowerCase(aName)]:=AValue;
 end;
 end;
 
 
+Function TCustomTemplateLoader.IndexOfTemplateEvent (aName : String) : Integer;
+
+begin
+  Result:=Length(FNotifications)-1;
+  While (Result>=0) and not SameText(FNotifications[Result].Name,aName) do
+    Dec(Result);
+end;
+
+procedure TCustomTemplateLoader.TemplateLoaded(const aName, aTemplate: String);
+
+Var
+  Idx : Integer;
+
+begin
+  FTemplates[aName]:=aTemplate;
+  if Assigned(FOnLoad) then
+    FOnLoad(Self,aName);
+  Idx:=IndexOfTemplateEvent(aName);
+  While Idx<>-1 do
+    begin
+    FNotifications[Idx].Event(Self,aName);
+    Delete(FNotifications,Idx,1);
+    Idx:=IndexOfTemplateEvent(aName);
+    end;
+end;
+
 function TCustomTemplateLoader.ProcessURL(const aURL: String): String;
 function TCustomTemplateLoader.ProcessURL(const aURL: String): String;
 
 
 Var
 Var
@@ -210,7 +275,22 @@ begin
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-procedure TCustomTemplateLoader.RemoveRemplate(aName: String);
+procedure TCustomTemplateLoader.IfTemplate(const aName: String; aEvent: TTemplateNotifyEvent);
+Var
+  N : TTemplateNotification;
+
+begin
+  if Templates[aName]<>'' then
+    aEvent(Self,aName)
+  else
+     begin
+     N.Name:=aname;
+     N.Event:=aEvent;
+     FNotifications:=Concat(FNotifications,[N]);
+     end;
+end;
+
+procedure TCustomTemplateLoader.RemoveRemplate(const aName: String);
 begin
 begin
   jsDelete(FTemplates,Lowercase(aName));
   jsDelete(FTemplates,Lowercase(aName));
 end;
 end;