Sfoglia il codice sorgente

* Add support for resources

michael 5 anni fa
parent
commit
2b0c7ffa88

+ 78 - 0
demo/resources/consoledemo.lpi

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="consoledemo"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="consoledemo.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="consoledemo"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="nodejs"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jminclude -Jirtl.js -JRjs"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 42 - 0
demo/resources/consoledemo.lpr

@@ -0,0 +1,42 @@
+program consoledemo;
+
+{$mode objfpc}
+
+{$R help.txt}
+
+uses
+   types, p2jsres, nodejs;
+
+
+Var
+  RL : TStringDynArray;
+  S : String;
+  aInfo : TResourceInfo;
+
+
+begin
+  Writeln('Javascript source:');
+  SetResourceSource(rsJS);
+  RL:=GetResourceNames;
+  For S in RL do
+    begin
+    Writeln('--- Found resource ',S,' : ');
+    if not GetResourceInfo(S,aInfo) then
+      Writeln('No extra information for resource ',S,' available')
+    else
+      begin
+      Writeln('Name: ',aInfo.Name);
+      Writeln('Format: ',aInfo.Format);
+      Writeln('encoding: ',aInfo.Encoding);
+      Writeln('unit: ',aInfo.resourceunit);
+      Writeln('data length: ',Length(aInfo.data));
+      end;
+    end;
+  if not GetResourceInfo('help',aInfo) then
+    Writeln('resource help not found !')
+  else
+    begin
+    Writeln('Usage:');
+    Writeln(TNJSBuffer.from(ainfo.Data,'base64').toString);
+    end;
+end.

BIN
demo/resources/down.png


+ 4 - 0
demo/resources/help.txt

@@ -0,0 +1,4 @@
+This demo is compiler with the help text embedded. 
+
+NodeJS applications do not have an associated HTML page so -JRjs is the best
+option to use till another mechanism appears.

+ 26 - 0
demo/resources/htmldemo.html

@@ -0,0 +1,26 @@
+<!doctype html>
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <title>Javascript resource demo</title>
+    <script type="application/javascript" src="htmldemo.js"></script>
+  </head>
+  <body>
+    <h1>Javascript resource demo</h1>
+    <div id="pasjsconsole"></div>
+    <script type="application/javascript">
+      window.onload= rtl.run;
+    </script>
+  <button type="button" id="doinsert">Insert HTML from resource</button> 
+  <h1 id="headertext">Press button to insert HTML below from resource data</h1>
+  <div id="playarea">
+  </div>
+  <p>
+  <div>
+    Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> &nbsp;&nbsp;Sources: &nbsp; 
+    <a target="new" href="htmldemo.lpr">Program</a>.
+  </div>
+  </p>
+  </body>
+</html>
+  

+ 91 - 0
demo/resources/htmldemo.lpi

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="htmldemo"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="3">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="PasJSWebBrowserProject" Value="1"/>
+      <Item2 Name="RunAtReady" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="htmldemo.lpr"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="consoledemo"/>
+      </Unit>
+      <Unit>
+        <Filename Value="htmldemo.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="htmldemo"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude -JRjs"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 52 - 0
demo/resources/htmldemo.lpr

@@ -0,0 +1,52 @@
+program consoledemo;
+
+{$mode objfpc}
+
+{$R testres.html}
+
+uses
+  browserconsole, JS, Classes, SysUtils, types, p2jsres, unita, unitb, web;
+
+
+
+function DoOnClick(aEvent: TJSMouseEvent): boolean;
+var
+  el : TJSHTMLElement;
+  aInfo : TResourceInfo;
+begin
+  Result:=False;
+  el:=TJSHTMLElement(document.getelementByid('playarea'));
+  if not GetResourceInfo('testres',aInfo) then
+    el.innerhtml:='resource testres not found !'
+  else
+    el.innerhtml:=window.atob(ainfo.Data);
+  el:=TJSHTMLElement(document.getelementByid('headertext'));
+  el.innertext:='Below HTML was inserted from resource data';
+end;
+
+Var
+  RL : TStringDynArray;
+  aInfo : TResourceInfo;
+  el : TJSHTMLElement;
+  S : String;
+begin
+  Writeln('Javascript embedded resources:');
+  SetResourceSource(rsJS);
+  RL:=GetResourceNames;
+  For S in RL do
+    begin
+    Writeln('--- Found resource name: ',S,' : ');
+    if not GetResourceInfo(S,aInfo) then
+      Writeln('No extra information for resource ',S,' available !')
+    else
+      begin
+      Writeln('Name: ',aInfo.Name);
+      Writeln('Format: ',aInfo.Format);
+      Writeln('encoding: ',aInfo.Encoding);
+      Writeln('unit: ',aInfo.resourceunit);
+      Writeln('data length: ',Length(aInfo.data));
+      end;
+    end;
+  el:=TJSHTMLButtonElement(document.getelementByid('doinsert'));
+  el.onclick:=@DoOnClick;
+end.

File diff suppressed because it is too large
+ 8 - 0
demo/resources/htmllinkdemo.html


+ 92 - 0
demo/resources/htmllinkdemo.lpi

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="htmllinkdemo"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="5">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="PasJSHTMLFile" Value="project1.html"/>
+      <Item2 Name="PasJSPort" Value="0"/>
+      <Item3 Name="PasJSWebBrowserProject" Value="1"/>
+      <Item4 Name="RunAtReady" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="htmllinkdemo.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="htmllinkdemo.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="htmllinkdemo"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 46 - 0
demo/resources/htmllinkdemo.lpr

@@ -0,0 +1,46 @@
+program htmllinkdemo;
+
+{$mode objfpc}
+
+uses
+  JS, Classes, SysUtils, Web, p2jsres;
+
+{$R left.png}
+{$R right.png}
+{$R up.png}
+{$R down.png}
+
+Const
+  MaxImages = 4;
+  ImageResources : Array[1..MaxImages] of string = ('up','right','down','left');
+
+Var
+  Img : TJSHTMLImageElement;
+  CurrentImage: Integer = 1;
+
+Procedure  ShowCurrentImage;
+
+Var
+  aInfo : TResourceInfo;
+
+begin
+  if not GetResourceInfo(ImageResources[CurrentImage],aInfo) then
+    Writeln('No info for image ',ImageResources[CurrentImage])
+  else
+    Img.Src:='data:'+aInfo.format+';base64,'+aInfo.Data;
+end;
+
+function RotateImage(aEvent: TJSMouseEvent): boolean;
+begin
+  Inc(CurrentImage);
+  if CurrentImage>MaxImages then
+    CurrentImage:=1;
+  ShowCurrentImage;
+end;
+
+begin
+  SetResourceSource(rsHTML);
+  Img:=TJSHTMLImageElement(Document.GetElementByID('theimage'));
+  Img.OnClick:=@RotateImage;
+  ShowCurrentImage;
+end.

+ 32 - 0
demo/resources/htmlloadlinkdemo.html

@@ -0,0 +1,32 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>Project1</title>
+  <script src="htmlloadlinkdemo.js"></script>
+</head>
+<body>
+  <h1>Dynamically loaded HTML Preload link resources</h1>
+  <p>
+    This demo demonstrates how to load resources and then load images from these resources.<br>
+    Click the below image to round-robin between the available images.
+  </p>
+  <center>
+    <img id="theimage" src="" alt="The image" width=60 height=60>
+  </center>
+  <script>
+  window.addEventListener("load", rtl.run);
+  </script>
+  <div>
+   Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> &nbsp;&nbsp;Sources: &nbsp;
+    <a target="new" href="htmlloadlinkdemo.lpr">Program</a>.
+  </div>
+  <div>
+  <a target="_blank" href="https://icons8.com/icons/set/circled-up-2">Scroll Up</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a><br>
+  <a target="_blank" href="https://icons8.com/icons/set/circled-left">Go Back</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a><br>
+  <a target="_blank" href="https://icons8.com/icons/set/circled-right">Circled Right</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a><br>
+  <a target="_blank" href="https://icons8.com/icons/set/circled-down-2">Scroll Down</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a><br>
+  </div>
+</body>
+</html>

+ 91 - 0
demo/resources/htmlloadlinkdemo.lpi

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="htmlloadlinkdemo"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="4">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="PasJSHTMLFile" Value="project1.html"/>
+      <Item2 Name="PasJSPort" Value="0"/>
+      <Item3 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="htmlloadlinkdemo.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="htmlloadlinkdemo.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="htmlloadlinkdemo"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 64 - 0
demo/resources/htmlloadlinkdemo.lpr

@@ -0,0 +1,64 @@
+program htmlloadlinkdemo;
+
+{$mode objfpc}
+
+uses
+  Classes, Web, p2jsres;
+
+{$R left.png}
+{$R right.png}
+{$R up.png}
+{$R down.png}
+
+Const
+  MaxImages = 4;
+  ImageResources : Array[1..MaxImages] of string = ('up','right','down','left');
+
+Var
+  Img : TJSHTMLImageElement;
+  CurrentImage: Integer = 1;
+
+Procedure  ShowCurrentImage;
+
+Var
+  aInfo : TResourceInfo;
+
+begin
+  if not GetResourceInfo(ImageResources[CurrentImage],aInfo) then
+    Writeln('No info for image ',ImageResources[CurrentImage])
+  else
+    Img.Src:='data:'+aInfo.format+';base64,'+aInfo.Data;
+end;
+
+function RotateImage(aEvent: TJSMouseEvent): boolean;
+begin
+  Result:=False;
+  Inc(CurrentImage);
+  if CurrentImage>MaxImages then
+    CurrentImage:=1;
+  ShowCurrentImage;
+end;
+
+procedure OnLoaded(const LoadedResources: array of String);
+
+Var
+  S : String;
+
+begin
+  // Some info
+  for S in LoadedResources do
+    Writeln('Found resource: ',S);
+  Img.OnClick:=@RotateImage;
+  ShowCurrentImage;
+end;
+
+procedure OnLoadFailed(const aError: string);
+begin
+  window.alert('Failed to load resources : '+AError)
+end;
+
+begin
+  SetResourceSource(rsHTML);
+  Img:=TJSHTMLImageElement(Document.GetElementByID('theimage'));
+  LoadHTMLLinkResources('htmlloadlinkdemo-res.html',@OnLoaded,@OnLoadFailed);
+end.

BIN
demo/resources/left.png


BIN
demo/resources/right.png


+ 5 - 0
demo/resources/testa.html

@@ -0,0 +1,5 @@
+<h3>Hello Resource World Part A</h3>
+<p>
+This message is saved in a resource file (Part A).
+</p>
+

+ 5 - 0
demo/resources/testb.html

@@ -0,0 +1,5 @@
+<h3>Hello Resource World Part B</h3>
+<p>
+This message is saved in a resource file (Part B).
+</p>
+

+ 2 - 0
demo/resources/testres.html

@@ -0,0 +1,2 @@
+<h3>Test resource in HTML</h3>
+This is a main program file resource in HTML.

+ 16 - 0
demo/resources/unita.pp

@@ -0,0 +1,16 @@
+unit unita;
+
+interface
+
+Procedure Testa;
+
+implementation
+
+{$R testa.html}
+
+Procedure Testa;
+
+begin
+end;
+
+end.

+ 16 - 0
demo/resources/unitb.pp

@@ -0,0 +1,16 @@
+unit unitb;
+
+interface
+
+Procedure Testa;
+
+implementation
+
+{$R TestB.html}
+
+Procedure Testa;
+
+begin
+end;
+
+end.

BIN
demo/resources/up.png


+ 308 - 0
packages/rtl/p2jsres.pp

@@ -0,0 +1,308 @@
+unit p2jsres;
+
+{$mode objfpc}
+{$h+}
+{$modeswitch externalclass}
+
+interface
+
+uses types;
+
+Type
+  TResourceSource = (rsJS,rsHTML);
+  TResourceInfo = record
+    name : string;
+    encoding : string;
+    resourceunit : string;
+    format : string;
+    data : string;
+  end;
+  TResourceEnumCallBack = Reference to function(const resName : string) : boolean;
+  TResourcesLoadedEnumCallBack = Reference to Procedure(const LoadedResources : Array of String);
+  TResourcesLoadErrorCallBack = Reference to Procedure(const aError : string);
+
+Function SetResourceSource(aSource : TResourceSource) : TResourceSource;
+
+Function GetResourceNames : TStringDynArray;
+Function GetResourceNames(aSource : TResourceSource) : TStringDynArray;
+
+Function EnumResources(aCallback : TResourceEnumCallBack) : Integer;
+Function EnumResources(aSource : TResourceSource; aCallback : TResourceEnumCallBack) : Integer;
+
+Function GetResourceInfo(Const aName : String; var aInfo : TResourceInfo) : Boolean;
+Function GetResourceInfo(aSource : TResourceSource; Const aName : String; var aInfo : TResourceInfo) : Boolean;
+
+Procedure LoadHTMLLinkResources(const aURL : String; OnLoad : TResourcesLoadedEnumCallBack = Nil; OnError : TResourcesLoadErrorCallBack = Nil);
+
+implementation
+
+uses sysutils, js, web;
+
+var
+  gMode: TResourceSource;
+
+{ ---------------------------------------------------------------------
+  Global entry points
+  ---------------------------------------------------------------------}
+
+Function SeTResourceSource(aSource : TResourceSource) : TResourceSource;
+begin
+  Result:=gMode;
+  gMode:=aSource;
+end;
+
+Function GetResourceNames : TStringDynArray;
+begin
+  Result:=GetResourceNames(gMode);
+end;
+
+Function EnumResources(aCallback : TResourceEnumCallBack) : Integer;
+
+begin
+  Result:=EnumResources(gMode,aCallback);
+end;
+
+Function GetResourceInfo(Const aName : String; var aInfo : TResourceInfo) : Boolean;
+
+begin
+  Result:=GetResourceInfo(gMode,aName,aInfo);
+end;
+
+{ ---------------------------------------------------------------------
+  JS resources
+  ---------------------------------------------------------------------}
+
+Type
+  TRTLResourceInfo = class external name 'Object' (TJSObject)
+    name : string;
+    encoding : string;
+    resourceunit : string; external name 'unit';
+    format : string;
+    data : string;
+  end;
+
+function rtlGetResourceList : TStringDynArray; external name 'rtl.getResourceList';
+function rtlGetResource(const aName : string) : TRTLResourceInfo; external name 'rtl.getResource';
+
+Function GetRTLResourceInfo(Const aName : String; var aInfo : TResourceInfo) : Boolean;
+
+Var
+  RTLInfo : TRTLResourceInfo;
+
+begin
+  RTLInfo:=rtlGetResource(lowercase(aName));
+  Result:=Assigned(RTLInfo);
+  if Result then
+    begin
+    aInfo.name:=RTLinfo.name;
+    aInfo.encoding:=RTLinfo.encoding;
+    aInfo.format:=RTLinfo.format;
+    aInfo.resourceunit:=RTLinfo.resourceunit;
+    aInfo.data:=RTLinfo.data;
+    end;
+end;
+
+{ ---------------------------------------------------------------------
+  HTML resources
+  ---------------------------------------------------------------------}
+
+Const
+  IDPrefix = 'resource-';
+
+Function IsResourceLink(L : TJSHTMLLinkElement) : Boolean;
+
+begin
+  Result:=(Copy(L.id,1,Length(IDPrefix))=IDPrefix) and (isDefined(L.Dataset['unit'])) and (Copy(L.href,1,4)='data')
+end;
+
+Function GetHTMLResources : TStringDynArray;
+
+
+Var
+  LC : TJSHTMLCollection;
+  L : TJSHTMLLinkElement;
+  I : Integer;
+  ID : String;
+
+begin
+  SetLength(Result,0);
+  if not isDefined(document) then // If called in Node...
+    exit;
+  // No cache, we do this dynamically: it's possible to add link nodes at runtime.
+  LC:=document.getElementsByTagName('link');
+  For I:=0 to LC.length-1 do
+    begin
+    L:=TJSHTMLLinkElement(LC[i]);
+    ID:=L.ID;
+    if IsResourceLink(L) then
+      begin
+      Delete(ID,1,Length(IDPrefix));
+      if (ID<>'') then
+        TJSArray(Result).Push(ID);
+      end;
+    end;
+end;
+
+Function GetHTMLResourceInfo(Const aName : String; var aInfo : TResourceInfo) : Boolean;
+
+Var
+  el : TJSElement;
+  L : TJSHTMLLinkElement absolute el;
+  S : String;
+  I : Integer;
+
+begin
+  Result:=False;
+  if not isDefined(document) then // If called in Node...
+    exit;
+  El:=document.getElementByID(IDPrefix+lowercase(aName));
+  Result:=assigned(el) and SameText(el.tagName,'link');
+  if not Result then
+    exit;
+  ainfo.name:=lowercase(aName);
+  ainfo.Resourceunit:=String(L.Dataset['unit']);
+  S:=L.href;
+  S:=Copy(S,6,Length(S)-5); // strip data;
+  I:=Pos(',',S);
+  aInfo.data:=Copy(S,I+1,Length(S)-1);
+  S:=copy(S,1,I-1);
+  I:=Pos(';',S);
+  if I=0 then
+    aInfo.encoding:=''
+  else
+    begin
+    aInfo.encoding:=Copy(S,I+1,Length(S)-1);
+    S:=Copy(S,1,I-1);
+    end;
+  aInfo.Format:=S;
+end;
+
+Function HasTemplate : Boolean;
+
+begin
+  asm
+   return ('content' in document.createElement('template'))
+  end;
+end;
+
+
+Procedure LoadHTMLLinkResources(const aURL : String; OnLoad : TResourcesLoadedEnumCallBack = Nil; OnError : TResourcesLoadErrorCallBack = Nil);
+
+  function FetchOK(Res : JSValue) : JSValue;
+  var
+    Response : TJSResponse absolute res;
+  begin
+    Result:=Nil;
+    if not Response.ok then
+      begin
+      if Assigned(OnError) then
+        Raise TJSError.New('HTTP Error for URL aURL, status = '+IntToStr(Response.status)+' : '+Response.statusText)
+      end
+    else
+      Result:=Response.Text();
+  end;
+
+  function BlobOK(Res : JSValue) : JSValue;
+
+  Var
+    aText : String absolute res;
+    ID : String;
+    Tmpl : TJSHTMLTemplateElement;
+    El : TJSHTMLElement;
+    L : TJSHTMLLinkElement absolute El;
+    Arr : TStringDynArray;
+    aParent : TJSHTMLElement;
+
+  begin
+    Result:=Nil;
+    aParent:=TJSHTMLElement(document.head);
+    if aParent=Nil then
+      aParent:=TJSHTMLElement(document.body);
+    SetLength(Arr,0);
+    Tmpl:=TJSHTMLTemplateElement(Document.createElement('template'));
+    Tmpl.innerhtml:=TJSString(aText).trim;
+    el:=TJSHTMLElement(Tmpl.Content.firstElementChild);
+    While El<>Nil do
+      begin
+      if SameText(El.tagName,'link') and IsResourceLink(L) then
+        begin
+        aParent.Append(TJSHTMLElement(document.importNode(l,true)));
+        ID:=L.ID;
+        Delete(ID,1,Length(IDPrefix));
+        if (ID<>'') then
+          TJSArray(Arr).Push(ID);
+        end;
+      el:=TJSHTMLElement(el.nextElementSibling);
+      end;
+    if Assigned(OnLoad) then
+      OnLoad(Arr);
+  end;
+
+  function DoError (aValue : JSValue) : JSValue;
+
+  Var
+    aErr : TJSError absolute aValue;
+
+  begin
+    Result:=Nil;
+    if Assigned(OnError) then
+      if aErr=Nil then
+        OnError('Error: ' + aErr.message)
+  end;
+
+begin
+  if not HasTemplate then
+    begin
+    if Assigned(OnError) then
+      OnError('No template support in this browser')
+    end
+  else
+    window.fetch(aURL)._then(@FetchOK)._then(@BlobOK).catch(@doError);
+end;
+
+
+{ ---------------------------------------------------------------------
+  Global entries, specifying resource mode
+  ---------------------------------------------------------------------}
+
+Function GetResourceNames(aSource : TResourceSource) : TStringDynArray;
+
+begin
+  case aSource of
+    rsJS : Result:=rtlGetResourceList;
+    rsHTML : Result:=GetHTMLResources;
+  end;
+end;
+
+Function EnumResources(aSource : TResourceSource; aCallback : TResourceEnumCallBack) : Integer;
+
+Var
+  RL : TStringDynArray;
+  I : Integer;
+  ContinueEnum : Boolean;
+
+begin
+  Result:=0;
+  RL:=GetResourceNames(aSource);
+  I:=0;
+  Result:=Length(RL);
+  ContinueEnum:=True;
+  While (I<Result) and ContinueEnum do
+    begin
+    ContinueEnum:=aCallBack(RL[i]);
+    Inc(I);
+    end;
+end;
+
+
+Function GetResourceInfo(aSource : TResourceSource; Const aName : String; var aInfo : TResourceInfo) : Boolean;
+
+begin
+  case aSource of
+    rsJS : Result:=GetRTLResourceInfo(aName,aInfo);
+    rsHTML : Result:=GetHTMLResourceInfo(aName,aInfo);
+  end;
+end;
+
+
+end.

Some files were not shown because too many files changed in this diff