Load and Save file lazarus / 76-Pas2JS ---------------------------------------------------------------------- Okoba · 2023-08-26 09:45 Hello, Can anyone show me or point me into the direction of how can I make a sample that loads a simple text file (by dropping the file on the page or similar options), change the content and save it again, on the path or output it as downloaded file? ---------------------------------------------------------------------- lainz · 2023-08-26 10:41 Quote from: Okoba on August 26, 2023, 11:45:41 amHello, Can anyone show me or point me into the direction of how can I make a sample that loads a simple text file (by dropping the file on the page or similar options), change the content and save it again, on the path or output it as downloaded file? To load the text file (edit: seems that's using jQuery... you will need to adapt) https://css-tricks.com/drag-and-drop-file-uploading/ (edit2: seems that they also have the demo without jQuery here view- source:https://css-tricks.com/examples/DragAndDropFileUploading/) To save to file https://www.tutorialspoint.com/how-to-create-and-save-text-file-in- javascript ---------------------------------------------------------------------- Okoba · 2023-08-26 11:10 Hey lainz, I want to do this with Pas2JS and your samples are all in JS. If there is a link I should know, please tell me as I very new to Pas2JS. ---------------------------------------------------------------------- lainz · 2023-08-26 11:12 Quote from: Okoba on August 26, 2023, 01:10:40 pmHey lainz, I want to do this with Pas2JS and your samples are all in JS. If there is a link I should know, please tell me as I very new to Pas2JS. Pas2js is JS. Only typed. To code with Pas2JS you should know JS anyways... ---------------------------------------------------------------------- Okoba · 2023-08-26 11:21 I mean how the Pascal code looks? What units should I call and stuff like that. I am sure that I am missing something, hence asking. I was thinking there should be a ready sample for such simple task of reading and writing file, so I can check and learn from that. ---------------------------------------------------------------------- lainz · 2023-08-26 11:44 I don't have any links for Pas2JS. Really I don't like Pas2JS I prefer typescript or plain JS... So I don't have an example on that. ---------------------------------------------------------------------- lainz · 2023-08-26 12:51 But if you want to try it (as I did before getting that it was not for me) here is a small demo game you can try https://github.com/lainz/AllegroPas2JS-Demo-Game https://github.com/lainz/AllegroPas2JS-Demo-Game/blob/master/game.lpr Edit: here is the game published https://lainz.github.io/AllegroPas2JS-Demo-Game/index.html ---------------------------------------------------------------------- Leledumbo · 2023-08-27 07:50 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  Web; var  GInput: TJSHTMLInputElement;  GOutput: TJSHTMLDivElement;  LFile: TJSHTMLFile;  LReader: TJSFileReader;  LFileContent: String;begin  GInput := TJSHTMLInputElement(Document.GetElementByID('input'));  GOutput := TJSHTMLDivElement(Document.GetElementByID('output'));   GInput.OnChange := function (AFileInputChangeEvent: TEventListenerEvent): Boolean  begin    LFile := GInput.Files[0];     LReader := TJSFileReader.New;    LReader.OnLoad := function (AFileLoadEvent: TEventListenerEvent): Boolean    begin      LFileContent := String(TJSFileReader(AFileLoadEvent.Target).Result);    // begin edit      LFileContent := '
' + LFileContent +
'
';      // end edit      GOutput.InnerHTML := LFileContent;    end;    LReader.ReadAsText(LFile);  end;end. Code: HTML5  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i           Read file input                
        You cannot save, it's the client side (browser), there's no write access to filesystems. To make it downloadable, however, is still possible. The trick lainz showed above can be done, see TJSURL and TJSBlob from weborworker unit, basically copying what's inside that link. ---------------------------------------------------------------------- Okoba · 2023-08-27 10:18 Thank you! This is half of what I wanted and great start. For past two hours I am trying to make download work, but I can not find any sample of how blob works, and there are missing attributes and other issues. ---------------------------------------------------------------------- Leledumbo · 2023-08-27 10:59 Quote from: Okoba on August 27, 2023, 12:18:09 pmThank you! This is half of what I wanted and great start. For past two hours I am trying to make download work, but I can not find any sample of how blob works, and there are missing attributes and other issues. You're right, the TJSHTMLFile / TJSBlob is missing a constructor that accepts the content. I can make the download, but the file remains as is, no modification possible. Perhaps this is worth reporting as missing features. After all, reading the Web API standards, indeed web(orworker) unit is missing quite a lot. Even HTMLParagraphElement is missing. For reference, here's the download after upload version: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  Web; var  GInput: TJSHTMLInputElement;  Goutput: TJSHTMLAnchorElement;  LReader: TJSFileReader;  LFile: TJSHTMLFile;  LFileContent: String;begin  GInput := TJSHTMLInputElement(Document.GetElementByID('input'));  Goutput := TJSHTMLAnchorElement(Document.GetElementByID('output'));   GInput.OnChange := function (AFileInputChangeEvent: TEventListenerEvent): Boolean  begin    LFile := GInput.Files[0];     LReader := TJSFileReader.New;    LReader.OnLoad := function (AFileLoadEvent: TEventListenerEvent): Boolean    begin      LFileContent := String(TJSFileReader(AFileLoadEvent.Target).Result);    // begin edit      LFileContent := '
' + LFileContent +
'
';      // end edit       // need a way to assign back modified LFileContent to LFile or create a new TJS(HTMLFile|Blob) with LFileContent as its content      // the Web API standard provides the way as a constructor parameter, but is missing from the declaration     Goutput.HRef := TJSURL.createObjectURL(LFile);      Goutput.Download := 'result.txt';      Goutput.Click;      TJSURL.revokeObjectURL(Goutput.HRef);    end;    LReader.ReadAsText(LFile);  end;end. Code: HTML5  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i           Read file input                        ---------------------------------------------------------------------- Okoba · 2023-08-27 11:02 If that's possible to show me how to make the download, I will be glad. Honestly I don't know what is missing or not to report. I am just a beginner trying to understand how things working. But I am curious why it is not possible to change the content? ---------------------------------------------------------------------- Leledumbo · 2023-08-28 03:39 Quote from: Okoba on August 27, 2023, 01:02:23 pmHonestly I don't know what is missing or not to report. I am just a beginner trying to understand how things working. But I am curious why it is not possible to change the content? The Blob constructor accepts an iterable object, which will be the content of the blob. The corresponding TJSBlob class definition has no such a constructor defined. AFAICS, there's no way to add data to the blob later, only from the constructor. Blob is indeed designed to be immutable, so that's to be expected. Therefore, without the constructor parameter, we can't make a blob containing data that can be passed to TJSURL.createObjectURL to make a downloadable data (File is a descendant class of Blob, that's why you can pass it alternatively). Maybe I will be the one to contribute the change instead of reporting. EDIT: Done In the mean time, you can just do these little modification to web.pas and weborworker.pas units (+ symbol means add those lines): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TJSHTMLFile = class external name 'File' (TJSBlob)  private    FLastModified: NativeInt; external name 'lastModified';    FLastModifiedDate: TJSDate; external name 'lastModifiedDate';    FName: string; external name 'name';  public+   constructor New(ABits: JSValue; AName: string); overload;+   constructor New(ABits: JSValue; AName: string; AOptions: TJSObject); overload;    property lastModified: NativeInt read FLastModified;    property lastModifiedDate : TJSDate read FLastModifiedDate; deprecated;    property name: String read FName;  end;...  TJSBlob = class external name 'Blob' (TJSEventTarget)  private    FSize: NativeInt; external name 'size';    FType: string; external name  'type';  Public+   constructor New(AArray: JSValue); overload;+   constructor New(AArray: JSValue; AOptions: TJSObject); overload;    procedure close;    function slice : TJSBlob; overload;    function slice(aStart : NativeInt) : TJSBlob; overload;    function slice(aStart,aEnd : NativeInt) : TJSBlob; overload;    function slice(aStart,aEnd : NativeInt; AContentType : String) : TJSBlob; overload;    function arrayBuffer : TJSPromise;    property size : NativeInt read FSize;    property _type : string read FType; deprecated;    property type_ : string read FType;  end; Then the project code can be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program demoreadfileinput; uses  Web,JS; const  DownloadFileName = 'result.txt';var  GInput: TJSHTMLInputElement;  Goutput: TJSHTMLAnchorElement;  LReader: TJSFileReader;  LFile: TJSHTMLFile;  LFileContent: String;begin  GInput := TJSHTMLInputElement(Document.GetElementByID('input'));  Goutput := TJSHTMLAnchorElement(Document.GetElementByID('output'));   GInput.OnChange := function (AFileInputChangeEvent: TEventListenerEvent): Boolean  begin    LFile := GInput.Files[0];     LReader := TJSFileReader.New;    LReader.OnLoad := function (AFileLoadEvent: TEventListenerEvent): Boolean    begin      LFileContent := String(TJSFileReader(AFileLoadEvent.Target).Result);    // begin edit      LFileContent := '
' + LineEnding +
LFileContent + LineEnding + '
';      // end edit       LFile := TJSHTMLFile.New(TJSString.New(LFileContent), DownloadFileName);      Goutput.HRef := TJSURL.createObjectURL(LFile);      Goutput.Download := DownloadFileName;      Goutput.Click;      TJSURL.revokeObjectURL(Goutput.HRef);    end;    LReader.ReadAsText(LFile);  end;end. ---------------------------------------------------------------------- Okoba · 2023-08-28 13:43 Great demo Leledumbo! And thank you so much for updating. I checked it and it works as what I needed! ---------------------------------------------------------------------- Okoba · 2023-08-28 13:57 One note, on the commit for the demo, there is still a comment about "need a way to assign ..." and I guess it is not needed as you added it. ---------------------------------------------------------------------- Leledumbo · 2023-08-28 14:38 Quote from: Okoba on August 28, 2023, 03:57:13 pmOne note, on the commit for the demo, there is still a comment about "need a way to assign ..." and I guess it is not needed as you added it. Oops... let's see if anyone notice that before I update my commit. EDIT: Damn, Michael is quick, it's already merged. Well... it doesn't hurt, just confusing. I'll fix it later alongside other missing definitions. ---------------------------------------------------------------------- Okoba · 2023-08-29 08:37 Yes he is, and you are too. Thank you for helping me starting with this subject! I am sure this demo will help many in the future.