wasmjob: started fetch demo

This commit is contained in:
mattias 2022-08-01 14:04:41 +02:00
parent b588ff243d
commit c5aab46aa4
10 changed files with 959 additions and 13 deletions

View File

@ -341,6 +341,10 @@ Type
TJSWindowOrWorkerGlobalScope = class;
IJSCacheStorage = interface;
TJSCacheStorage = class;
IJSResponse = interface;
TJSResponse = class;
IJSHeaders = interface;
TJSHeaders = class;
TJSEventListenerOptions = TJOB_Dictionary;
TJSAddEventListenerOptions = TJOB_Dictionary;
TJSGetRootNodeOptions = TJOB_Dictionary;
@ -379,6 +383,7 @@ Type
TJSChannelPixelLayout = TJOB_Dictionary;
TJSImageBitmapOptions = TJOB_Dictionary;
TJSMultiCacheQueryOptions = TJOB_Dictionary;
TJSResponseInit = TJOB_Dictionary;
TVisibilityState = UnicodeString;
TDocumentAutoplayPolicy = UnicodeString;
TFlashClassification = UnicodeString;
@ -404,6 +409,8 @@ Type
TColorSpaceConversion = UnicodeString;
TServiceWorkerState = UnicodeString;
TCacheStorageNamespace = UnicodeString;
TResponseType = UnicodeString;
THeadersGuardEnum = UnicodeString;
TEventListener = function (event: IJSEvent): Boolean of object;
TEventHandlerNonNull = function (event: IJSEvent): TJOB_JSValue of object;
TEventHandler = TEventHandlerNonNull;
@ -438,6 +445,8 @@ Type
TImagePixelLayout = IJSArray; // array of TJSChannelPixelLayout
// Union of Blob, Directory, USVString
TFormDataEntryValue = TJOB_JSValue;
// Union of sequence, record
THeadersInit = TJOB_JSValue;
{ --------------------------------------------------------------------
TJSEventListenerOptions
@ -842,6 +851,16 @@ Type
cacheName: UnicodeString;
end;
{ --------------------------------------------------------------------
TJSResponseInit
--------------------------------------------------------------------}
TJSResponseInitRec = record
status: Word;
statusText: UnicodeString;
headers: THeadersInit;
end;
{ --------------------------------------------------------------------
TJSEventTarget
--------------------------------------------------------------------}
@ -2590,7 +2609,7 @@ Type
TJSRangeDynArray = IJSArray; // array of TJSRange
IJSSelection = interface(IJSObject)
['{A4886FB0-977D-3F5E-AEF5-E54883662A9A}']
['{522D4098-FC2A-35AF-A806-57B88516481A}']
function _GetanchorNode: IJSNode;
function _GetanchorOffset: LongWord;
function _GetfocusNode: IJSNode;
@ -2621,7 +2640,6 @@ Type
procedure deleteFromDocument;
function containsNode(aNode: IJSNode; allowPartialContainment: Boolean): Boolean; overload;
function containsNode(aNode: IJSNode): Boolean; overload;
function toString: UnicodeString;
procedure modify(const alter: UnicodeString; const aDirection: UnicodeString; const aGranularity: UnicodeString);
function toStringWithFormat(const aFormatType: UnicodeString; aFlags: LongWord; aWrapColumn: Integer): UnicodeString;
procedure addSelectionListener(aNewListener: IJSnsISelectionListener);
@ -2675,7 +2693,6 @@ Type
procedure deleteFromDocument;
function containsNode(aNode: IJSNode; allowPartialContainment: Boolean): Boolean; overload;
function containsNode(aNode: IJSNode): Boolean; overload;
function toString: UnicodeString;
procedure modify(const alter: UnicodeString; const aDirection: UnicodeString; const aGranularity: UnicodeString);
function toStringWithFormat(const aFormatType: UnicodeString; aFlags: LongWord; aWrapColumn: Integer): UnicodeString;
procedure addSelectionListener(aNewListener: IJSnsISelectionListener);
@ -4585,6 +4602,98 @@ Type
class function Cast(Intf: IJSObject): IJSCacheStorage;
end;
{ --------------------------------------------------------------------
TJSResponse
--------------------------------------------------------------------}
IJSResponse = interface(IJSObject)
['{1C2F3A3B-95B8-328C-AF98-F7FD8DBAB69C}']
function _Gettype_: TResponseType;
function _Geturl: UnicodeString;
function _Getredirected: Boolean;
function _Getstatus: Word;
function _Getok: Boolean;
function _GetstatusText: UnicodeString;
function _Getheaders: IJSHeaders;
function _GethasCacheInfoChannel: Boolean;
function error: IJSResponse;
function redirect(const aUrl: UnicodeString; aStatus: Word): IJSResponse; overload;
function redirect(const aUrl: UnicodeString): IJSResponse; overload;
function clone: IJSResponse;
function cloneUnfiltered: IJSResponse;
function json: IJSPromise; overload;
property type_: TResponseType read _Gettype_;
property url: UnicodeString read _Geturl;
property redirected: Boolean read _Getredirected;
property status: Word read _Getstatus;
property ok: Boolean read _Getok;
property statusText: UnicodeString read _GetstatusText;
property headers: IJSHeaders read _Getheaders;
property hasCacheInfoChannel: Boolean read _GethasCacheInfoChannel;
end;
{ TJSResponse }
TJSResponse = class(TJSObject,IJSResponse)
Private
function _Gettype_: TResponseType;
function _Geturl: UnicodeString;
function _Getredirected: Boolean;
function _Getstatus: Word;
function _Getok: Boolean;
function _GetstatusText: UnicodeString;
function _Getheaders: IJSHeaders;
function _GethasCacheInfoChannel: Boolean;
Public
function error: IJSResponse;
function redirect(const aUrl: UnicodeString; aStatus: Word): IJSResponse; overload;
function redirect(const aUrl: UnicodeString): IJSResponse; overload;
function clone: IJSResponse;
function cloneUnfiltered: IJSResponse;
function json: IJSPromise; overload;
class function Cast(Intf: IJSObject): IJSResponse;
property type_: TResponseType read _Gettype_;
property url: UnicodeString read _Geturl;
property redirected: Boolean read _Getredirected;
property status: Word read _Getstatus;
property ok: Boolean read _Getok;
property statusText: UnicodeString read _GetstatusText;
property headers: IJSHeaders read _Getheaders;
property hasCacheInfoChannel: Boolean read _GethasCacheInfoChannel;
end;
{ --------------------------------------------------------------------
TJSHeaders
--------------------------------------------------------------------}
TUnicodeStringDynArrayDynArray = IJSArray; // array of TUnicodeStringDynArray
IJSHeaders = interface(IJSObject)
['{C0BCC7DF-3747-3F31-83C9-BDEB874234DC}']
function _Getguard: THeadersGuardEnum;
procedure _Setguard(const aValue: THeadersGuardEnum);
procedure append(const aName: UnicodeString; const aValue: UnicodeString);
procedure delete(const aName: UnicodeString);
function get(const aName: UnicodeString): UnicodeString;
function has(const aName: UnicodeString): Boolean;
procedure set_(const aName: UnicodeString; const aValue: UnicodeString);
property guard: THeadersGuardEnum read _Getguard write _Setguard;
end;
TJSHeaders = class(TJSObject,IJSHeaders)
Private
function _Getguard: THeadersGuardEnum;
procedure _Setguard(const aValue: THeadersGuardEnum);
Public
procedure append(const aName: UnicodeString; const aValue: UnicodeString);
procedure delete(const aName: UnicodeString);
function get(const aName: UnicodeString): UnicodeString;
function has(const aName: UnicodeString): Boolean;
procedure set_(const aName: UnicodeString; const aValue: UnicodeString);
class function Cast(Intf: IJSObject): IJSHeaders;
property guard: THeadersGuardEnum read _Getguard write _Setguard;
end;
{ --------------------------------------------------------------------
TJSNode
--------------------------------------------------------------------}
@ -4865,6 +4974,7 @@ Type
procedure cancelIdleCallback(aHandle: LongWord);
function getRegionalPrefsLocales: TUnicodeStringDynArray;
function getWebExposedLocales: TUnicodeStringDynArray;
function fetch(const URL: UnicodeString): IJSPromise;
property window: IJSWindowProxy read _Getwindow;
property self_: IJSWindowProxy read _Getself_;
property document: IJSDocument read _Getdocument;
@ -5044,6 +5154,8 @@ Type
property localStorage: IJSStorage read _GetlocalStorage;
end;
{ TJSWindow }
TJSWindow = class(TJSEventTarget,IJSWindow)
Private
function _Getwindow: IJSWindowProxy;
@ -5199,6 +5311,7 @@ Type
procedure cancelIdleCallback(aHandle: LongWord);
function getRegionalPrefsLocales: TUnicodeStringDynArray;
function getWebExposedLocales: TUnicodeStringDynArray;
function fetch(const URL: UnicodeString): IJSPromise;
class function Cast(Intf: IJSObject): IJSWindow;
property window: IJSWindowProxy read _Getwindow;
property self_: IJSWindowProxy read _Getself_;
@ -11807,11 +11920,6 @@ begin
Result:=InvokeJSBooleanResult('containsNode',[aNode]);
end;
function TJSSelection.toString: UnicodeString;
begin
Result:=InvokeJSUnicodeStringResult('toString',[]);
end;
procedure TJSSelection.modify(const alter: UnicodeString; const aDirection: UnicodeString; const aGranularity: UnicodeString);
begin
InvokeJSNoResult('modify',[alter,aDirection,aGranularity]);
@ -13902,6 +14010,121 @@ begin
Result:=TJSCacheStorage.JOBCast(Intf);
end;
function TJSResponse._Gettype_: TResponseType;
begin
Result:=ReadJSPropertyUnicodeString('type');
end;
function TJSResponse._Geturl: UnicodeString;
begin
Result:=ReadJSPropertyUnicodeString('url');
end;
function TJSResponse._Getredirected: Boolean;
begin
Result:=ReadJSPropertyBoolean('redirected');
end;
function TJSResponse._Getstatus: Word;
begin
Result:=ReadJSPropertyLongInt('status');
end;
function TJSResponse._Getok: Boolean;
begin
Result:=ReadJSPropertyBoolean('ok');
end;
function TJSResponse._GetstatusText: UnicodeString;
begin
Result:=ReadJSPropertyUnicodeString('statusText');
end;
function TJSResponse._Getheaders: IJSHeaders;
begin
Result:=ReadJSPropertyObject('headers',TJSHeaders) as IJSHeaders;
end;
function TJSResponse._GethasCacheInfoChannel: Boolean;
begin
Result:=ReadJSPropertyBoolean('hasCacheInfoChannel');
end;
function TJSResponse.error: IJSResponse;
begin
Result:=InvokeJSObjectResult('error',[],TJSResponse) as IJSResponse;
end;
function TJSResponse.redirect(const aUrl: UnicodeString; aStatus: Word): IJSResponse; overload;
begin
Result:=InvokeJSObjectResult('redirect',[aUrl,aStatus],TJSResponse) as IJSResponse;
end;
function TJSResponse.redirect(const aUrl: UnicodeString): IJSResponse; overload;
begin
Result:=InvokeJSObjectResult('redirect',[aUrl],TJSResponse) as IJSResponse;
end;
function TJSResponse.clone: IJSResponse;
begin
Result:=InvokeJSObjectResult('clone',[],TJSResponse) as IJSResponse;
end;
function TJSResponse.cloneUnfiltered: IJSResponse;
begin
Result:=InvokeJSObjectResult('cloneUnfiltered',[],TJSResponse) as IJSResponse;
end;
function TJSResponse.json: IJSPromise;
begin
Result:=InvokeJSObjectResult('json',[],TJSPromise) as IJSPromise;
end;
class function TJSResponse.Cast(Intf: IJSObject): IJSResponse;
begin
Result:=TJSResponse.JOBCast(Intf);
end;
function TJSHeaders._Getguard: THeadersGuardEnum;
begin
Result:=ReadJSPropertyUnicodeString('guard');
end;
procedure TJSHeaders._Setguard(const aValue: THeadersGuardEnum);
begin
WriteJSPropertyUnicodeString('guard',aValue);
end;
procedure TJSHeaders.append(const aName: UnicodeString; const aValue: UnicodeString);
begin
InvokeJSNoResult('append',[aName,aValue]);
end;
procedure TJSHeaders.delete(const aName: UnicodeString);
begin
InvokeJSNoResult('delete',[aName]);
end;
function TJSHeaders.get(const aName: UnicodeString): UnicodeString;
begin
Result:=InvokeJSUnicodeStringResult('get',[aName]);
end;
function TJSHeaders.has(const aName: UnicodeString): Boolean;
begin
Result:=InvokeJSBooleanResult('has',[aName]);
end;
procedure TJSHeaders.set_(const aName: UnicodeString; const aValue: UnicodeString);
begin
InvokeJSNoResult('set',[aName,aValue]);
end;
class function TJSHeaders.Cast(Intf: IJSObject): IJSHeaders;
begin
Result:=TJSHeaders.JOBCast(Intf);
end;
function TJSNode._GetnodeType: Word;
begin
Result:=ReadJSPropertyLongInt('nodeType');
@ -14802,6 +15025,11 @@ begin
Result:=InvokeJSObjectResult('getWebExposedLocales',[],TJSArray) as TUnicodeStringDynArray;
end;
function TJSWindow.fetch(const URL: UnicodeString): IJSPromise;
begin
Result:=InvokeJSObjectResult('fetch',[URL],TJSPromise) as IJSPromise;
end;
class function TJSWindow.Cast(Intf: IJSObject): IJSWindow;
begin
Result:=TJSWindow.JOBCast(Intf);

View File

@ -3768,8 +3768,7 @@ interface Selection {
[Throws]
boolean containsNode(Node node,
optional boolean allowPartialContainment = false);
/* Mattias: added toString */
stringifier DOMString toString ();
// Mattias: stringifier DOMString toString ();
};
// Additional methods not currently in the spec
@ -4079,8 +4078,8 @@ interface Range : AbstractRange {
[Throws]
boolean intersectsNode(Node node);
[Throws, BinaryName="ToString"]
stringifier;
// Mattias: [Throws, BinaryName="ToString"]
// stringifier;
};
// http://domparsing.spec.whatwg.org/#dom-range-createcontextualfragment
@ -7431,3 +7430,267 @@ interface FormData {
void set(USVString name, USVString value);
iterable<USVString, FormDataEntryValue>;
};
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-obj
*
*/
// Still unclear what should be subclassed.
// https://github.com/slightlyoff/ServiceWorker/issues/189
[Func="ServiceWorkerVisible",
// FIXME(nsm): Bug 1113522. This is exposed to satisfy webidl constraints, but it won't actually work.
Exposed=(Window,Worker)]
interface ServiceWorker : EventTarget {
readonly attribute USVString scriptURL;
readonly attribute ServiceWorkerState state;
attribute EventHandler onstatechange;
// Mattias: [Throws]
// void postMessage(any message, sequence<object> transferable);
// Mattias: [Throws]
// void postMessage(any message, optional StructuredSerializeOptions options = {});
};
ServiceWorker includes AbstractWorker;
enum ServiceWorkerState {
// https://github.com/w3c/ServiceWorker/issues/1162
"parsed",
"installing",
"installed",
"activating",
"activated",
"redundant"
};
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Exposed=(Window,Worker)]
interface mixin AbstractWorker {
attribute EventHandler onerror;
};
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is:
* https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin
* https://fetch.spec.whatwg.org/#fetch-method
* https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
* https://w3c.github.io/ServiceWorker/#self-caches
*/
// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin
[Exposed=(Window,Worker)]
interface mixin WindowOrWorkerGlobalScope {
[Replaceable] readonly attribute USVString origin;
readonly attribute boolean crossOriginIsolated;
[Throws, NeedsCallerType]
void reportError(any e);
// base64 utility methods
[Throws]
DOMString btoa(DOMString btoa);
[Throws]
DOMString atob(DOMString atob);
// timers
// NOTE: We're using overloads where the spec uses a union. Should
// be black-box the same.
[Throws]
long setTimeout(Function handler, optional long timeout = 0, any... arguments);
[Throws]
long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
void clearTimeout(optional long handle = 0);
[Throws]
long setInterval(Function handler, optional long timeout = 0, any... arguments);
[Throws]
long setInterval(DOMString handler, optional long timeout = 0, any... unused);
void clearInterval(optional long handle = 0);
// Mattias: // microtask queuing
// void queueMicrotask(VoidFunction callback);
// ImageBitmap
// Mattias: [Throws]
// Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage,
// optional ImageBitmapOptions aOptions = {});
// Mattias: [Throws]
// Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage,
// long aSx, long aSy, long aSw, long aSh,
// optional ImageBitmapOptions aOptions = {});
// structured cloning
// Mattias: [Throws]
// any structuredClone(any value, optional StructuredSerializeOptions options = {});
};
// https://fetch.spec.whatwg.org/#fetch-method
partial interface mixin WindowOrWorkerGlobalScope {
// Mattias: [NewObject, NeedsCallerType]
// Promise<Response> fetch(RequestInfo input, optional RequestInit init = {});
};
// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
partial interface mixin WindowOrWorkerGlobalScope {
readonly attribute boolean isSecureContext;
};
// http://w3c.github.io/IndexedDB/#factory-interface
partial interface mixin WindowOrWorkerGlobalScope {
// readonly attribute IDBFactory indexedDB;
// Mattias: [Throws]
// readonly attribute IDBFactory? indexedDB;
};
// https://w3c.github.io/ServiceWorker/#self-caches
partial interface mixin WindowOrWorkerGlobalScope {
[Throws, Func="nsGlobalWindowInner::CachesEnabled", SameObject]
readonly attribute CacheStorage caches;
};
// https://wicg.github.io/scheduling-apis/#ref-for-windoworworkerglobalscope-scheduler
partial interface mixin WindowOrWorkerGlobalScope {
// Mattias: [Replaceable, Pref="dom.enable_web_task_scheduling", SameObject]
// readonly attribute Scheduler scheduler;
};
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/ServiceWorker/#cachestorage-interface
*/
interface Principal;
[Exposed=(Window,Worker),
Func="nsGlobalWindowInner::CachesEnabled"]
interface CacheStorage {
[Throws, ChromeOnly]
constructor(CacheStorageNamespace namespace, Principal principal);
// Mattias: [NewObject]
// Promise<Response> match(RequestInfo request, optional MultiCacheQueryOptions options = {});
// Mattias: [NewObject]
// Promise<boolean> has(DOMString cacheName);
// Mattias: [NewObject]
// Promise<Cache> open(DOMString cacheName);
// Mattias: [NewObject]
// Promise<boolean> delete(DOMString cacheName);
// Mattias: [NewObject]
// Promise<sequence<DOMString>> keys();
};
dictionary MultiCacheQueryOptions : CacheQueryOptions {
DOMString cacheName;
};
// chrome-only, gecko specific extension
enum CacheStorageNamespace {
"content", "chrome"
};
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://fetch.spec.whatwg.org/#response-class
*/
[Exposed=(Window,Worker)]
interface Response {
// This should be constructor(optional BodyInit... but BodyInit doesn't
// include ReadableStream yet because we don't want to expose Streams API to
// Request.
[Throws]
constructor(optional (Blob or BufferSource or FormData or URLSearchParams or ReadableStream or USVString)? body = null,
optional ResponseInit init = {});
[NewObject] static Response error();
[Throws,
NewObject] static Response redirect(USVString url, optional unsigned short status = 302);
readonly attribute ResponseType type;
readonly attribute USVString url;
readonly attribute boolean redirected;
readonly attribute unsigned short status;
readonly attribute boolean ok;
readonly attribute ByteString statusText;
[SameObject, BinaryName="headers_"] readonly attribute Headers headers;
[Throws,
NewObject] Response clone();
[ChromeOnly, NewObject, Throws] Response cloneUnfiltered();
// For testing only.
[ChromeOnly] readonly attribute boolean hasCacheInfoChannel;
};
// Mattias: Response includes Body;
// This should be part of Body but we don't want to expose body to request yet.
// See bug 1387483.
partial interface Response {
// Mattias: [GetterThrows]
// readonly attribute ReadableStream? body;
};
dictionary ResponseInit {
unsigned short status = 200;
ByteString statusText = "";
HeadersInit headers;
};
enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredirect" };
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://fetch.spec.whatwg.org/#headers-class
*/
typedef (sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit;
enum HeadersGuardEnum {
"none",
"request",
"request-no-cors",
"response",
"immutable"
};
[Exposed=(Window,Worker)]
interface Headers {
[Throws]
constructor(optional HeadersInit init);
[Throws] void append(ByteString name, ByteString value);
[Throws] void delete(ByteString name);
[Throws] ByteString? get(ByteString name);
[Throws] boolean has(ByteString name);
[Throws] void set(ByteString name, ByteString value);
iterable<ByteString, ByteString>;
// Used to test different guard states from mochitest.
// Note: Must be set prior to populating headers or will throw.
[ChromeOnly, SetterThrows] attribute HeadersGuardEnum guard;
};

View File

@ -0,0 +1,108 @@
<?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="BrowserFetch1"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<CustomData Count="4">
<Item0 Name="MaintainHTML" Value="1"/>
<Item1 Name="Pas2JSProject" Value="1"/>
<Item2 Name="PasJSLocation" Value="BrowserFetch1"/>
<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"/>
</RunParams>
<Units>
<Unit>
<Filename Value="BrowserFetch1.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="index.html"/>
<IsPartOfProject Value="True"/>
<CustomData Count="1">
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
</CustomData>
</Unit>
<Unit>
<Filename Value="../../../packages/job/job_browser.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="JOB_Browser"/>
</Unit>
<Unit>
<Filename Value="../../../packages/job/job_shared.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="JOB_Shared"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target FileExt=".js">
<Filename Value="BrowserFetch1"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="../../../packages/job"/>
<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
-dVerboseJOB"/>
<OtherDefines Count="1">
<Define0 Value="VerboseJOB"/>
</OtherDefines>
<CompilerPath Value="$(pas2js)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,50 @@
program BrowserFetch1;
{$mode objfpc}
uses
BrowserConsole, JS, Classes, SysUtils, Web, WasiEnv, WasiHostApp, JOB_Browser;
Type
{ TMyApplication }
TMyApplication = class(TBrowserWASIHostApplication)
Private
FWADomBridge : TJSObjectBridge;
function OnBeforeStart(Sender: TObject;
aDescriptor: TWebAssemblyStartDescriptor): Boolean;
Public
constructor Create(aOwner : TComponent); override;
procedure DoRun; override;
end;
function TMyApplication.OnBeforeStart(Sender: TObject;
aDescriptor: TWebAssemblyStartDescriptor): Boolean;
begin
FWADomBridge.WasiExports:=aDescriptor.Exported;
Result:=true;
end;
constructor TMyApplication.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FWADomBridge:=TJSObjectBridge.Create(WasiEnvironment);
RunEntryFunction:='_initialize';
end;
procedure TMyApplication.DoRun;
begin
// Your code here
StartWebAssembly('WasiFetch1.wasm',true,@OnBeforeStart);
end;
var
Application : TMyApplication;
begin
Application:=TMyApplication.Create(nil);
Application.Initialize;
Application.Run;
end.

View File

@ -0,0 +1,4 @@
{
"name":"Example",
"value":3
}

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="WasiFetch1"/>
<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"/>
</RunParams>
<Units>
<Unit>
<Filename Value="WasiFetch1.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="../dom/job_web.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="JOB_Web"/>
</Unit>
<Unit>
<Filename Value="../dom/job_js.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="JOB_JS"/>
</Unit>
<Unit>
<Filename Value="../../../packages/job/job_shared.pp"/>
<IsPartOfProject Value="True"/>
<UnitName Value="JOB_Shared"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="WasiFetch1.wasm" ApplyConventions="False"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="../dom;../../../packages/job"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="wasm32"/>
<TargetOS Value="wasi"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<ExecutableType Value="Library"/>
</Options>
</Linking>
<Other>
<OtherDefines Count="1">
<Define0 Value="VerboseInvokeJSArgs"/>
</OtherDefines>
<CompilerPath Value="/usr/lib/fpc/3.3.1/ppcrosswasm32"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,149 @@
library WasiFetch1;
{$mode objfpc}
{$h+}
{$codepage UTF8}
uses
SysUtils, JOB_Shared, JOB_Web, JOB_JS;
type
{ TWasmApp }
TWasmApp = class
private
function OnAccepted(const aValue: TJOB_JSValue): TJOB_JSValue;
function OnButtonClick(Event: IJSEvent): boolean;
function OnJSONFailed(const aValue: TJOB_JSValue): TJOB_JSValue;
function OnJSONReceived(const aValue: TJOB_JSValue): TJOB_JSValue;
function OnRejected(const aValue: TJOB_JSValue): TJOB_JSValue;
public
procedure Run;
end;
{ TApplication }
function TWasmApp.OnAccepted(const aValue: TJOB_JSValue): TJOB_JSValue;
var
Obj: IJSObject;
Response: IJSResponse;
p: IJSPromise;
begin
Result:=TJOB_Boolean.Create(false);
writeln('TWasmApp.OnAccepted ',aValue.AsString);
if aValue.Kind<>jjvkObject then
begin
writeln('TWasmApp.OnAccepted Expected object, but got '+JOB_JSValueKindNames[aValue.Kind]);
exit;
end;
Obj:=TJOB_Object(aValue).Value;
if Obj=nil then
begin
writeln('TWasmApp.OnAccepted Expected object, but got nil');
exit;
end;
Response:=TJSResponse.Cast(Obj);
writeln('TWasmApp.OnAccepted Response: ok=',Response.ok);
writeln('TWasmApp.OnAccepted Response: status=',Response.status);
writeln('TWasmApp.OnAccepted Response: statusText="',Response.statusText,'"');
writeln('TWasmApp.OnAccepted Response: redirected=',Response.redirected);
writeln('TWasmApp.OnAccepted Response: URL="',Response.url,'"');
p:=Response.InvokeJSObjectResult('json',[],TJSPromise) as IJSPromise;
p._then(@OnJSONReceived,@OnJSONFailed);
TJOB_Boolean(Result).Value:=true;
end;
function TWasmApp.OnButtonClick(Event: IJSEvent): boolean;
var
p: IJSPromise;
begin
writeln('TWasmApp.OnButtonClick ');
if Event=nil then ;
JSWindow.Alert('You triggered TWasmApp.OnButtonClick');
p:=JSWindow.InvokeJSObjectResult('fetch',['Example.json'],TJSPromise) as IJSPromise;
p._then(@OnAccepted,@OnRejected);
//JSWindow.fetch('Example.json')._then(@OnAccepted,@OnRejected);
Result:=true;
end;
function TWasmApp.OnJSONFailed(const aValue: TJOB_JSValue): TJOB_JSValue;
begin
Result:=TJOB_Boolean.Create(true);
end;
function TWasmApp.OnJSONReceived(const aValue: TJOB_JSValue): TJOB_JSValue;
var
Obj: IJSObject;
begin
Result:=TJOB_Boolean.Create(true);
if aValue.Kind<>jjvkObject then
begin
writeln('TWasmApp.OnJSONReceived Expected object, but got '+JOB_JSValueKindNames[aValue.Kind]);
exit;
end;
Obj:=TJOB_Object(aValue).Value;
if Obj=nil then
begin
writeln('TWasmApp.OnJSONReceived Expected object, but got nil');
exit;
end;
writeln('TWasmApp.OnJSONReceived Obj.name=',Obj.Properties['name'].AsString);
writeln('TWasmApp.OnJSONReceived Obj.value=',Obj.Properties['value'].AsString);
end;
function TWasmApp.OnRejected(const aValue: TJOB_JSValue): TJOB_JSValue;
begin
writeln('TWasmApp.OnRejected ',aValue.AsString);
Result:=TJOB_Boolean.Create(true);
end;
procedure TWasmApp.Run;
var
JSDiv: IJSHTMLDivElement;
JSButton: IJSHTMLButtonElement;
begin
writeln('TWasmApp.Run getElementById "playground" ...');
// get reference of HTML element "playground" and type cast it to Div
JSDiv:=TJSHTMLDivElement.Cast(JSDocument.getElementById('playground'));
// create button
writeln('TWasmApp.Run create button ...');
JSButton:=TJSHTMLButtonElement.Cast(JSDocument.createElement('button'));
writeln('TWasmApp.Run set button caption ...');
JSButton.InnerHTML:='Click me!';
// add button to div
writeln('TWasmApp.Run add button to div ...');
JSDiv.append(JSButton);
// add event listener OnButtonClick
writeln('TWasmApp.Run addEventListener OnButtonClick ...');
JSButton.addEventListener('click',@OnButtonClick);
writeln('TWasmApp.Run END');
end;
// workaround: fpc wasm does not yet support exporting functions from units
function JOBCallback(const Func: TJOBCallback; Data, Code: Pointer; Args: PByte): PByte;
begin
Result:=JOB_JS.JOBCallback(Func,Data,Code,Args);
end;
exports
JOBCallback;
var
Application: TWasmApp;
begin
Application:=TWasmApp.Create;
Application.Run;
end.

1
demo/wasienv/fetch/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,52 @@
<!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>FPC-Webassembly Demo creating a button via JOB and fetch Example.json</title>
<link href="bulma.min.css" rel="stylesheet">
<script src="BrowserFetch1.js"></script>
<style>
.source {
/* width: 730px; */
margin: -45px auto;
font-size: 0.9em;
}
.source-inner {
display: flex;
justify-content: space-between;
align-items: center;
/* width: 482px; */
}
</style>
</head>
<body>
<div class="section py-4">
<h1 class="title is-3">Test Area</h1>
<div class="box" id="playground">Playground</div>
</div>
<div class="section py-4">
<h1 class="title is-3">Console output</h1>
<div class="box" id="pasjsconsole"></div>
</div>
<!-- <hr> -->
<div class="section">
<div class="source">
<div class="source-inner">
<div>
<p>Created using &nbsp; <a target="_blank" href="https://wiki.freepascal.org/pas2js">pas2js.</a> </p>
<p>Pas2JS Sources: &nbsp; <a target="new" href="BrowserFetch1.lpr">Pas2JS Program</a></p>
<p>Webassembly Sources: &nbsp; <a target="new" href="WasiFetch1.lpr">FPC Program</a></p>
</div>
</div>
</div>
</div>
<script>
rtl.showUncaughtExceptions=true;
rtl.run();
</script>
</body>
</html>

View File

@ -505,7 +505,8 @@ var
begin
//writeln('TJSObjectBridge called JS Method Call=',aCall,' Data=',aData,' Code=',aCode,' Args=',JSArguments.length);
Args:=CreateCallbackArgs(View,JSArguments);
ResultP:=CallbackHandler(aCall,aData,aCode,Args); // this frees Args
ResultP:=CallbackHandler(aCall,aData,aCode,Args); // this frees Args, and may detach View
View:=getModuleMemoryDataView();
//writeln('TJSObjectBridge called Wasm Call=',aCall,' Data=',aData,' Code=',aCode,' ResultP=',ResultP);
Result:=EatCallbackResult(View,ResultP); // this frees ResultP
//writeln('TJSObjectBridge Result=',Result);