Sfoglia il codice sorgente

wasmjob: added demo to create a button with a click event

mattias 3 anni fa
parent
commit
211f4021eb

+ 1 - 0
demo/wasienv/button/.gitignore

@@ -0,0 +1 @@
+lib

+ 103 - 0
demo/wasienv/button/BrowserButton1.lpi

@@ -0,0 +1,103 @@
+<?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="BrowserButton1"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="4">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="Pas2JSProject" Value="1"/>
+      <Item2 Name="PasJSLocation" Value="BrowserButton1"/>
+      <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="BrowserButton1.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../button/index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+      <Unit>
+        <Filename Value="../dom/job_browser.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_Browser"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="BrowserButton1"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../dom"/>
+      <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>

+ 127 - 0
demo/wasienv/button/BrowserButton1.lpr

@@ -0,0 +1,127 @@
+program BrowserButton1;
+
+{$mode objfpc}
+
+uses
+  BrowserConsole, BrowserApp, JS, Classes, SysUtils, Web, WebAssembly, Types,
+  WasiEnv, JOB_Browser, JOB_Shared;
+
+Type
+
+  { TMyApplication }
+
+  TMyApplication = class(TBrowserApplication)
+  // todo: most of this code should be moved a TBrowserJOBApplication
+  Private
+    FWasiEnv: TPas2JSWASIEnvironment;
+    FMemory : TJSWebAssemblyMemory; // Memory of webassembly
+    FTable : TJSWebAssemblyTable; // Table of exported functions
+    FWADomBridge : TJSObjectBridge;
+    function CreateWebAssembly(Path: string; ImportObject: TJSObject
+      ): TJSPromise;
+    procedure DoWrite(Sender: TObject; const aOutput: String);
+    function InitEnv(aValue: JSValue): JSValue;
+    procedure InitWebAssembly;
+  Public
+    Constructor Create(aOwner : TComponent); override;
+    Destructor Destroy; override;
+    procedure DoRun; override;
+  end;
+
+function TMyApplication.InitEnv(aValue: JSValue): JSValue;
+Var
+  Module : TJSInstantiateResult absolute aValue;
+  Exps : TWASIExports;
+  InitFunc: TProc;
+begin
+  Result:=True;
+  FWasiEnv.Instance:=Module.Instance;
+  Exps := TWASIExports(TJSObject(Module.Instance.exports_));
+  //writeln('TMyApplication.InitEnv wasm exports=',TJSObject.keys(Exps));
+  FWADomBridge.WasiExports:=Exps;
+
+  // init the library
+  InitFunc:=TProc(Exps.functions['_initialize']);
+  writeln('TMyApplication.InitEnv ');
+  InitFunc();
+end;
+
+{ TMyApplication }
+
+procedure TMyApplication.DoWrite(Sender: TObject; const aOutput: String);
+begin
+  Writeln(aOutput);
+end;
+
+constructor TMyApplication.Create(aOwner: TComponent);
+begin
+  inherited Create(aOwner);
+  FWasiEnv:=TPas2JSWASIEnvironment.Create;
+  FWasiEnv.OnStdErrorWrite:=@DoWrite;
+  FWasiEnv.OnStdOutputWrite:=@DoWrite;
+  FWADomBridge:=TJSObjectBridge.Create(FWasiEnv);
+end;
+
+function TMyApplication.CreateWebAssembly(Path: string; ImportObject: TJSObject): TJSPromise;
+begin
+  Result:=window.fetch(Path)._then(Function (res : jsValue) : JSValue
+    begin
+      Result:=TJSResponse(Res).arrayBuffer._then(Function (res2 : jsValue) : JSValue
+        begin
+          Result:=TJSWebAssembly.instantiate(TJSArrayBuffer(res2),ImportObject);
+        end,Nil)
+    end,Nil
+  );
+end;
+
+procedure TMyApplication.InitWebAssembly;
+
+Var
+  mDesc: TJSWebAssemblyMemoryDescriptor;
+  tDesc: TJSWebAssemblyTableDescriptor;
+  ImportObj : TJSObject;
+
+begin
+  //  Setup memory
+  mDesc.initial:=256;
+  mDesc.maximum:=256;
+  FMemory:=TJSWebAssemblyMemory.New(mDesc);
+  // Setup table
+  tDesc.initial:=0;
+  tDesc.maximum:=0;
+  tDesc.element:='anyfunc';
+  FTable:=TJSWebAssemblyTable.New(tDesc);
+  // Setup ImportObject
+  ImportObj:=new([
+    'js', new([
+      'mem', FMemory,
+      'tbl', FTable
+    ])
+ ]);
+  FWasiEnv.AddImports(ImportObj);
+  CreateWebAssembly('WasiButton1.wasm',ImportObj)._then(@InitEnv);
+end;
+
+destructor TMyApplication.Destroy;
+begin
+  FreeAndNil(FWasiEnv);
+  inherited Destroy;
+end;
+
+procedure TMyApplication.DoRun;
+
+begin
+  // Your code here
+  Terminate;
+  InitWebAssembly;
+end;
+
+var
+  Application : TMyApplication;
+
+begin
+  Application:=TMyApplication.Create(nil);
+  Application.Initialize;
+  Application.Run;
+end.
+

+ 7 - 0
demo/wasienv/button/README.txt

@@ -0,0 +1,7 @@
+Demo showing how to create a button from Wasi using JOB (JavaScript Object Bridge).
+
+It contains the two projects
+
+WasiButton1.lpi - Wasi
+BrowserButton1.lpi - JavaScript/Pas2js
+

+ 90 - 0
demo/wasienv/button/WasiButton1.lpi

@@ -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="WasiButton1"/>
+      <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="WasiButton1.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../dom/job_wasm.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JOB_WAsm"/>
+      </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>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="WasiButton1.wasm" ApplyConventions="False"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../dom"/>
+      <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>

+ 73 - 0
demo/wasienv/button/WasiButton1.lpr

@@ -0,0 +1,73 @@
+library WasiButton1;
+
+{$mode objfpc}
+{$h+}
+{$codepage UTF8}
+
+uses
+  SysUtils, JOB_WAsm, JOB_Shared, JOB_Web, JOB_JS;
+
+type
+
+  { TWasmApp }
+
+  TWasmApp = class
+  private
+    function OnButtonClick(Event: IJSEventListenerEvent): boolean;
+  public
+    procedure Run;
+  end;
+
+{ TApplication }
+
+function TWasmApp.OnButtonClick(Event: IJSEventListenerEvent): boolean;
+begin
+  writeln('TWasmApp.OnButtonClick ');
+  if Event=nil then ;
+
+  JSWindow.Alert('You triggered TWasmApp.OnButtonClick');
+  Result:=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_WAsm.JOBCallback(Func,Data,Code,Args);
+end;
+
+exports
+  JOBCallback;
+
+var
+  Application: TWasmApp;
+begin
+  Application:=TWasmApp.Create;
+  Application.Run;
+end.
+

File diff suppressed because it is too large
+ 0 - 0
demo/wasienv/button/bulma.min.css


+ 52 - 0
demo/wasienv/button/index.html

@@ -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</title>
+  <link href="bulma.min.css" rel="stylesheet">
+  <script src="BrowserButton1.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="BrowserButton1.lpr">Pas2JS Program</a></p>
+          <p>Webassembly Sources: &nbsp; <a target="new" href="WasiButton1.lpr">FPC Program</a></p>
+        </div>
+      </div>
+    </div>
+  </div>
+  <script>
+    rtl.showUncaughtExceptions=true;
+    rtl.run();
+  </script>
+</body>
+</html>

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