diff --git a/components/pas2js/frmpas2jsbrowserprojectoptions.lfm b/components/pas2js/frmpas2jsbrowserprojectoptions.lfm index b083865c7b..37561d6704 100644 --- a/components/pas2js/frmpas2jsbrowserprojectoptions.lfm +++ b/components/pas2js/frmpas2jsbrowserprojectoptions.lfm @@ -16,7 +16,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm Left = 6 Height = 23 Top = 6 - Width = 173 + Width = 160 BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Create initial HTML page' @@ -32,7 +32,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm Left = 6 Height = 23 Top = 122 - Width = 213 + Width = 198 BorderSpacing.Top = 6 Caption = 'Use Browser Application object' OnChange = CBUseBrowserAppChange @@ -44,16 +44,16 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm AnchorSideTop.Side = asrBottom Left = 6 Height = 23 - Top = 213 - Width = 341 + Top = 216 + Width = 313 BorderSpacing.Top = 6 Caption = 'Use Browser Console unit to display writeln() output' TabOrder = 2 end object BPHelpOptions: TButtonPanel Left = 6 - Height = 38 - Top = 494 + Height = 40 + Top = 492 Width = 623 OKButton.Name = 'OKButton' OKButton.DefaultCaption = True @@ -67,13 +67,14 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm ShowButtons = [pbOK, pbCancel] end object SEPort: TSpinEdit - AnchorSideLeft.Control = edtWasmProgram + AnchorSideLeft.Control = RBStartServerAt AnchorSideTop.Control = RBStartServerAt AnchorSideTop.Side = asrBottom Left = 70 - Height = 27 - Top = 300 + Height = 30 + Top = 303 Width = 128 + BorderSpacing.Left = 32 BorderSpacing.Top = 6 MaxValue = 65354 MinValue = 1024 @@ -86,8 +87,8 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm AnchorSideTop.Side = asrBottom Left = 6 Height = 23 - Top = 242 - Width = 194 + Top = 245 + Width = 182 BorderSpacing.Top = 6 Caption = 'Project needs a HTTP Server' OnChange = CBUseHTTPServerChange @@ -99,8 +100,8 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm AnchorSideTop.Side = asrBottom Left = 38 Height = 23 - Top = 271 - Width = 180 + Top = 274 + Width = 168 BorderSpacing.Left = 32 BorderSpacing.Top = 6 Caption = 'Start HTTP Server on port' @@ -114,23 +115,24 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm AnchorSideTop.Side = asrBottom Left = 38 Height = 23 - Top = 329 - Width = 173 + Top = 335 + Width = 161 BorderSpacing.Top = 2 Caption = 'Use this URL to start app' TabOrder = 7 end object CBServerURL: TComboBox - AnchorSideLeft.Control = edtWasmProgram + AnchorSideLeft.Control = RBUseURL AnchorSideTop.Control = RBUseURL AnchorSideTop.Side = asrBottom AnchorSideRight.Control = edtWasmProgram AnchorSideRight.Side = asrBottom Left = 70 - Height = 27 - Top = 358 + Height = 30 + Top = 364 Width = 559 Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 32 BorderSpacing.Top = 6 BorderSpacing.Bottom = 6 ItemHeight = 0 @@ -143,7 +145,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm Left = 6 Height = 23 Top = 35 - Width = 151 + Width = 137 BorderSpacing.Top = 6 Caption = 'Maintain HTML Page' TabOrder = 9 @@ -155,7 +157,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm Left = 6 Height = 23 Top = 64 - Width = 313 + Width = 287 BorderSpacing.Top = 6 Caption = 'Run rtl when all page resources are fully loaded' TabOrder = 10 @@ -167,7 +169,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm Left = 6 Height = 23 Top = 93 - Width = 226 + Width = 209 BorderSpacing.Top = 6 Caption = 'Let rtl show uncaught exceptions' TabOrder = 11 @@ -179,7 +181,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm Left = 38 Height = 23 Top = 151 - Width = 193 + Width = 176 BorderSpacing.Left = 32 BorderSpacing.Top = 6 Caption = 'Host webassembly program' @@ -193,7 +195,7 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom Left = 70 - Height = 27 + Height = 30 Top = 180 Width = 559 Anchors = [akTop, akLeft, akRight] @@ -210,8 +212,8 @@ object WebBrowserProjectOptionsForm: TWebBrowserProjectOptionsForm AnchorSideTop.Side = asrBottom Left = 6 Height = 23 - Top = 391 - Width = 293 + Top = 400 + Width = 272 BorderSpacing.Top = 6 Caption = 'Create a javascript module instead of a script' OnChange = CBUseHTTPServerChange diff --git a/components/pas2js/frmpas2jsbrowserprojectoptions.pp b/components/pas2js/frmpas2jsbrowserprojectoptions.pp index b491485f7c..05e5b35959 100644 --- a/components/pas2js/frmpas2jsbrowserprojectoptions.pp +++ b/components/pas2js/frmpas2jsbrowserprojectoptions.pp @@ -44,6 +44,8 @@ type procedure SetURL(AValue: String); procedure SetWasmProgramURL(AValue: String); public + procedure HideWASM; virtual; + procedure HideModule; virtual; property CreateHTML : Boolean Index 0 read GetB Write SetB; property MaintainHTML : Boolean Index 1 read GetB Write SetB; property UseBrowserApp : Boolean Index 2 read GetB Write SetB; @@ -217,5 +219,16 @@ begin edtWasmProgram.Text:=aValue; end; +procedure TWebBrowserProjectOptionsForm.HideWASM; +begin + CBUseWASI.Visible:=false; + edtWasmProgram.Visible:=false; +end; + +procedure TWebBrowserProjectOptionsForm.HideModule; +begin + CBUseModule.Visible:=false; +end; + end. diff --git a/components/pas2js/pjscontroller.pp b/components/pas2js/pjscontroller.pp index 6f5c5b57bb..06e7c2f237 100644 --- a/components/pas2js/pjscontroller.pp +++ b/components/pas2js/pjscontroller.pp @@ -89,6 +89,7 @@ Const PJSIsProjectHTMLFile = 'PasJSIsProjectHTMLFile'; PJSProjectMaintainHTML = 'MaintainHTML'; PJSProjectManifestFile = 'PasJSManifestFile'; + PJSProjectCSSFile = 'PasJSCSSFile'; PJSProjectUseBrowserConsole = 'BrowserConsole'; PJSProjectRunAtReady = 'RunAtReady'; PJSProjectPort = 'PasJSPort'; diff --git a/components/pas2js/pjsdsgnregister.pas b/components/pas2js/pjsdsgnregister.pas index f3fd2db785..f43f89db9c 100644 --- a/components/pas2js/pjsdsgnregister.pas +++ b/components/pas2js/pjsdsgnregister.pas @@ -5,7 +5,7 @@ unit PJSDsgnRegister; interface uses - Classes, SysUtils, fpjson, + Classes, SysUtils, Types, fpjson, // LCL Forms, Controls, Dialogs, // LazUtils @@ -18,7 +18,7 @@ uses idehtml2class, PJSDsgnOptions, PJSDsgnOptsFrame, idedtstopas, frmpas2jswebservers, frmpas2jsnodejsprojectoptions, frmpas2jsbrowserprojectoptions, pjsprojectoptions, idehtmltools, - frmhtmltoform, pjscontroller, strpas2jsdesign; + frmhtmltoform, pjscontroller, strpas2jsdesign, CodeToolManager, CodeCache; const @@ -30,6 +30,8 @@ const FileDescNameClassFromHTMLFile = 'Class definition from HTML file'; SMessageViewHTMLToForm = 'HTML To Class conversion'; + DefaultIconSizes: array[0..7] of word = (72,96,128,144,152,192,384,512); + type { TProjectPas2JSWebApp } @@ -59,6 +61,7 @@ type function GetMainSrcFileName: string; function GetMainSrcName: string; protected + procedure AddHTMLHead(Src: TStringList); virtual; function CreateHTMLFile(AProject: TLazProject; AFileName: String ): TLazProjectFile; virtual; function CreateProjectSource: String; virtual; @@ -68,6 +71,7 @@ type function ShowModalOptions(Frm: TWebBrowserProjectOptionsForm): TModalResult; virtual; public constructor Create; override; + procedure Clear; virtual; function GetLocalizedName: string; override; function GetLocalizedDescription: string; override; function InitProject(AProject: TLazProject): TModalResult; override; @@ -97,28 +101,37 @@ type TProjectPas2JSProgressiveWebApp = class(TProjectPas2JSWebApp) private - FCSSDir: string; + FCSSStyleFilename: string; + FIconSizes: TWordDynArray; FImagesDir: string; FManifestFilename: string; FProjectDir: string; FServiceWorkerLPR: string; FWebDir: string; protected + procedure AddHTMLHead(Src: TStringList); override; function ShowModalOptions(Frm: TWebBrowserProjectOptionsForm ): TModalResult; override; function CreateManifestFile(AProject: TLazProject; AFileName: String ): TLazProjectFile; virtual; + function CreateCSSStyle(AProject: TLazProject; AFileName: String + ): TLazProjectFile; virtual; + function ForceDir(Dir: string; AutoDelete: boolean): boolean; virtual; + function SaveFile(aFilename: string): boolean; virtual; public constructor Create; override; + procedure Clear; override; function GetLocalizedName: string; override; function GetLocalizedDescription: string; override; function InitProject(AProject: TLazProject): TModalResult; override; + function CreateStartFiles(AProject: TLazProject): TModalResult; override; property ProjectDir: string read FProjectDir write FProjectDir; property ServiceWorkerLPR: string read FServiceWorkerLPR write FServiceWorkerLPR; - property CSSDir: string read FCSSDir write FCSSDir; - property ImagesDir: string read FImagesDir write FImagesDir; + property CSSStyleFilename: string read FCSSStyleFilename write FCSSStyleFilename; // without path (WebDir) + property ImagesDir: string read FImagesDir write FImagesDir; // without path (WebDir) property WebDir: string read FWebDir write FWebDir; - property ManifestFilename: string read FManifestFilename write FManifestFilename; + property ManifestFilename: string read FManifestFilename write FManifestFilename; // without path (WebDir) + property IconSizes: TWordDynArray read FIconSizes write FIconSizes; end; { TProjectPas2JSNodeJSApp } @@ -250,6 +263,7 @@ begin TPJSController.Instance.Hook; // register new-project items RegisterProjectDescriptor(TProjectPas2JSWebApp.Create); + RegisterProjectDescriptor(TProjectPas2JSProgressiveWebApp.Create); RegisterProjectDescriptor(TProjectPas2JSServiceWorker.Create); RegisterProjectDescriptor(TProjectPas2JSNodeJSApp.Create); RegisterProjectDescriptor(TProjectPas2JSModuleApp.Create); @@ -284,10 +298,28 @@ end; { TProjectPas2JSProgressiveWebApp } +procedure TProjectPas2JSProgressiveWebApp.AddHTMLHead(Src: TStringList); +var + i: Integer; + h, CurImgDir: String; +begin + inherited AddHTMLHead(Src); + Src.Add(' '); + Src.Add(' '); + Src.Add(' '); + Src.Add(' '); + CurImgDir:=ChompPathDelim(ImagesDir); + for i:=0 to high(IconSizes) do + begin + h:=IntToStr(IconSizes[i]); + Src.Add(' '); + end; +end; + function TProjectPas2JSProgressiveWebApp.ShowModalOptions( Frm: TWebBrowserProjectOptionsForm): TModalResult; var - CurProjDir, LPRFilename: String; + CurProjDir, LPRFilename, CurWebDir: String; Overwrites: TStringList; function CheckOverwriteFile(aFilename: string): string; @@ -306,6 +338,10 @@ var end; begin + // hide unsupported options + Frm.HideWASM; + Frm.HideModule; + Result:=inherited ShowModalOptions(Frm); if Result<>mrOk then exit; @@ -322,13 +358,12 @@ begin ServiceWorkerLPR:=CheckOverwriteFile(ProjectDir+ServiceWorkerLPR); CheckOverwriteFile(ChangeFileExt(ServiceWorkerLPR,'.lpi')); - WebDir:=CheckOverwriteDir(CurProjDir+WebDir); + CurWebDir:=CheckOverwriteDir(CurProjDir+WebDir); + CheckOverwriteDir(CurWebDir+ImagesDir); - HTMLFilename:=CheckOverwriteFile(WebDir+HTMLFilename); - ManifestFilename:=CheckOverwriteFile(WebDir+ManifestFilename); - - CSSDir:=CheckOverwriteDir(WebDir+CSSDir); - ImagesDir:=CheckOverwriteDir(WebDir+ImagesDir); + CheckOverwriteFile(CurWebDir+HTMLFilename); + CheckOverwriteFile(CurWebDir+ManifestFilename); + CheckOverwriteFile(CurWebDir+CSSStyleFilename); if Overwrites.Count>0 then begin @@ -348,8 +383,6 @@ end; function TProjectPas2JSProgressiveWebApp.CreateManifestFile( AProject: TLazProject; AFileName: String): TLazProjectFile; -const - IconSizes: array[1..8] of word = (72,96,128,144,152,192,384,512); var Src: TStringList; i: Integer; @@ -357,7 +390,7 @@ var begin Result:=AProject.CreateProjectFile(AFileName); Result.IsPartOfProject:=true; - AProject.CustomData.Values[PJSProjectManifestFile]:=Result.Filename; + AProject.CustomData.Values[PJSProjectManifestFile]:=CreateRelativePath(ProjectDir,Result.Filename); AProject.AddFile(Result,false); Src:=TStringList.Create; try @@ -370,12 +403,12 @@ begin Src.Add(' "theme_color": "#d04030",'); Src.Add(' "orientation": "portrait-primary",'); Src.Add(' "icons": ['); - for i:=low(IconSizes) to high(IconSizes) do + for i:=0 to high(IconSizes) do begin h:=IntToStr(IconSizes[i]); h:=h+'x'+h; Src.Add(' {'); - Src.Add(' "src": "/'+ExtractFileNameOnly(ChompPathDelim(ImagesDir))+'/icon-'+h+'.png",'); + Src.Add(' "src": "/'+ChompPathDelim(ImagesDir)+'/icon-'+h+'.png",'); Src.Add(' "type": "image/png", "sizes": "'+h+'"'); h:=' }'; if imrOk then exit; @@ -470,19 +557,26 @@ begin end; CurProjDir:=AppendPathDelim(CurProjDir); + CurWebDir:=AppendPathDelim(CurProjDir+WebDir); + CurImagesDir:=AppendPathDelim(CurWebDir+ImagesDir); - if not CheckDir(WebDir,true) then exit; - if not CheckDir(CSSDir,true) then exit; - if not CheckDir(ImagesDir,true) then exit; + if not ForceDir(WebDir,true) then exit; + if not ForceDir(ImagesDir,true) then exit; - // index.html - if LazarusIDE.DoSaveEditorFile(HTMLFilename,[sfProjectSaving])<>mrOk then exit; + // index.html (created in inherited InitProject) + CurHTMLFilename:=CurWebDir+HTMLFilename; + SaveFile(CurHTMLFilename); // manifest.json - CreateManifestFile(AProject,ManifestFilename); - if LazarusIDE.DoSaveEditorFile(ManifestFilename,[sfProjectSaving])<>mrOk then exit; + CurManifestFilename:=CurWebDir+ManifestFilename; + CreateManifestFile(AProject,CurManifestFilename); + SaveFile(CurManifestFilename); + + // style.css + CurCSSStyleFilename:=CurWebDir+CSSStyleFilename; + CreateCSSStyle(AProject,CurCSSStyleFilename); + SaveFile(CurCSSStyleFilename); - // css/style.css // favicon.ico // images/icon-.png @@ -494,6 +588,12 @@ begin Result:=mrOk; end; +function TProjectPas2JSProgressiveWebApp.CreateStartFiles(AProject: TLazProject + ): TModalResult; +begin + Result:=inherited CreateStartFiles(AProject); +end; + { TProjectPas2JSServiceWorker } function TProjectPas2JSServiceWorker.CreateProjectSource: String; @@ -1110,6 +1210,14 @@ begin FMainSrcName:='Project1'; end; +procedure TProjectPas2JSWebApp.Clear; +begin + // Reset options + FOptions:=[baoCreateHtml,baoMaintainHTML]; + ProjectPort:=0; + ProjectURL:=''; +end; + function TProjectPas2JSWebApp.GetNextPort : Word; begin @@ -1199,10 +1307,7 @@ end; function TProjectPas2JSWebApp.DoInitDescriptor: TModalResult; begin - // Reset options - FOptions:=[baoCreateHtml,baoMaintainHTML]; - ProjectPort:=0; - ProjectURL:=''; + Clear; Result:=ShowOptionsDialog; end; @@ -1237,31 +1342,20 @@ begin Result:=FMainSrcName; end; +procedure TProjectPas2JSWebApp.AddHTMLHead(Src: TStringList); +begin + if Src=nil then ; +end; + function TProjectPas2JSWebApp.CreateHTMLFile(AProject: TLazProject; AFileName: String): TLazProjectFile; Const ConsoleDiv = '
'+LineEnding; - TemplateHTMLSource = - ''+LineEnding - +''+LineEnding - +''+LineEnding - +' '+LineEnding - +' '+LineEnding - +' %s'+LineEnding - +' '+LineEnding - +''+LineEnding - +''+LineEnding - +' %s'+LineEnding - +' %s'+LineEnding - +''+LineEnding - +''+LineEnding; - - Var HTMLFile : TLazProjectFile; - HTMLSource : String; ScriptType, RunScript,Content : String; + Src: TStringList; begin HTMLFile:=AProject.CreateProjectFile(HTMLFilename); @@ -1288,11 +1382,29 @@ begin else RunScript:=Runscript+'rtl.run();'+LineEnding; RunScript:=' '+LineEnding + +' '+RunScript + +' '+LineEnding end; - HTMLSource:=Format(TemplateHTMLSource,[MainSrcName,ScriptType,aFileName,RunScript,Content]); - HTMLFile.SetSourceText(HTMLSource); + Src:=TStringList.Create; + try + Src.Add(''); + Src.Add(''); + Src.Add(''); + Src.Add(' '); + Src.Add(' '); + Src.Add(' '+MainSrcName+''); + Src.Add(' '); + AddHTMLHead(Src); + Src.Add(''); + Src.Add(''); + Src.Add(' '+RunScript); + Src.Add(' '+Content); + Src.Add(''); + Src.Add(''); + HTMLFile.SetSourceText(Src.Text); + finally + Src.Free; + end; Result:=HTMLFile; end;