123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- 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.
|