Recent

Author Topic: Load and Save file  (Read 3285 times)

Okoba

  • Hero Member
  • *****
  • Posts: 533
Load and Save file
« on: August 26, 2023, 11:45:41 am »
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

  • Hero Member
  • *****
  • Posts: 4515
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Load and Save file
« Reply #1 on: August 26, 2023, 12:41:47 pm »
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?

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
« Last Edit: August 26, 2023, 12:48:03 pm by lainz »

Okoba

  • Hero Member
  • *****
  • Posts: 533
Re: Load and Save file
« Reply #2 on: August 26, 2023, 01:10:40 pm »
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

  • Hero Member
  • *****
  • Posts: 4515
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Load and Save file
« Reply #3 on: August 26, 2023, 01:12:16 pm »
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.

Pas2js is JS. Only typed. To code with Pas2JS you should know JS anyways...

Okoba

  • Hero Member
  • *****
  • Posts: 533
Re: Load and Save file
« Reply #4 on: August 26, 2023, 01:21:10 pm »
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

  • Hero Member
  • *****
  • Posts: 4515
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Load and Save file
« Reply #5 on: August 26, 2023, 01:44:35 pm »
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

  • Hero Member
  • *****
  • Posts: 4515
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Load and Save file
« Reply #6 on: August 26, 2023, 02:51:47 pm »
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
« Last Edit: August 26, 2023, 03:22:00 pm by lainz »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8760
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Load and Save file
« Reply #7 on: August 27, 2023, 09:50:56 am »
Code: Pascal  [Select][+][-]
  1. uses
  2.   Web;
  3.  
  4. var
  5.   GInput: TJSHTMLInputElement;
  6.   GOutput: TJSHTMLDivElement;
  7.   LFile: TJSHTMLFile;
  8.   LReader: TJSFileReader;
  9.   LFileContent: String;
  10. begin
  11.   GInput := TJSHTMLInputElement(Document.GetElementByID('input'));
  12.   GOutput := TJSHTMLDivElement(Document.GetElementByID('output'));
  13.  
  14.   GInput.OnChange := function (AFileInputChangeEvent: TEventListenerEvent): Boolean
  15.   begin
  16.     LFile := GInput.Files[0];
  17.  
  18.     LReader := TJSFileReader.New;
  19.     LReader.OnLoad := function (AFileLoadEvent: TEventListenerEvent): Boolean
  20.     begin
  21.       LFileContent := String(TJSFileReader(AFileLoadEvent.Target).Result);
  22.       // begin edit
  23.       LFileContent := '<pre>' + LFileContent + '</pre>';
  24.       // end edit
  25.       GOutput.InnerHTML := LFileContent;
  26.     end;
  27.     LReader.ReadAsText(LFile);
  28.   end;
  29. end.
  30.  
Code: HTML5  [Select][+][-]
  1. <!DOCTYPE html>
  2.   <head id="head">
  3.     <meta charset="utf-8"/>
  4.     <title>Read file input</title>
  5.     <script type="application/javascript" src="demoreadfileinput.js"></script>
  6.   </head>
  7.   <body>
  8.     <input type="file" id="input">
  9.     <div id="output"></div>
  10.  
  11.     <script type="application/javascript">
  12.       rtl.run();
  13.     </script>
  14.   </body>
  15. </html>
  16.  
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.
« Last Edit: August 27, 2023, 01:10:09 pm by Leledumbo »

Okoba

  • Hero Member
  • *****
  • Posts: 533
Re: Load and Save file
« Reply #8 on: August 27, 2023, 12:18:09 pm »
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

  • Hero Member
  • *****
  • Posts: 8760
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Load and Save file
« Reply #9 on: August 27, 2023, 12:59:06 pm »
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.
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][+][-]
  1. uses
  2.   Web;
  3.  
  4. var
  5.   GInput: TJSHTMLInputElement;
  6.   Goutput: TJSHTMLAnchorElement;
  7.   LReader: TJSFileReader;
  8.   LFile: TJSHTMLFile;
  9.   LFileContent: String;
  10. begin
  11.   GInput := TJSHTMLInputElement(Document.GetElementByID('input'));
  12.   Goutput := TJSHTMLAnchorElement(Document.GetElementByID('output'));
  13.  
  14.   GInput.OnChange := function (AFileInputChangeEvent: TEventListenerEvent): Boolean
  15.   begin
  16.     LFile := GInput.Files[0];
  17.  
  18.     LReader := TJSFileReader.New;
  19.     LReader.OnLoad := function (AFileLoadEvent: TEventListenerEvent): Boolean
  20.     begin
  21.       LFileContent := String(TJSFileReader(AFileLoadEvent.Target).Result);
  22.       // begin edit
  23.       LFileContent := '<pre>' + LFileContent + '</pre>';
  24.       // end edit
  25.  
  26.       // need a way to assign back modified LFileContent to LFile or create a new TJS(HTMLFile|Blob) with LFileContent as its content
  27.       // the Web API standard provides the way as a constructor parameter, but is missing from the declaration
  28.  
  29.       Goutput.HRef := TJSURL.createObjectURL(LFile);
  30.       Goutput.Download := 'result.txt';
  31.       Goutput.Click;
  32.       TJSURL.revokeObjectURL(Goutput.HRef);
  33.     end;
  34.     LReader.ReadAsText(LFile);
  35.   end;
  36. end.
  37.  
Code: HTML5  [Select][+][-]
  1. <!DOCTYPE html>
  2.   <head id="head">
  3.     <meta charset="utf-8"/>
  4.     <title>Read file input</title>
  5.     <script type="application/javascript" src="demoreadfileinput.js"></script>
  6.   </head>
  7.   <body>
  8.     <input type="file" id="input">
  9.     <a id="output" style="visibility:none"></div>
  10.  
  11.     <script type="application/javascript">
  12.       rtl.run();
  13.     </script>
  14.   </body>
  15. </html>
  16.  
« Last Edit: August 27, 2023, 01:09:58 pm by Leledumbo »

Okoba

  • Hero Member
  • *****
  • Posts: 533
Re: Load and Save file
« Reply #10 on: August 27, 2023, 01:02:23 pm »
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

  • Hero Member
  • *****
  • Posts: 8760
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Load and Save file
« Reply #11 on: August 28, 2023, 05:39:12 am »
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?
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][+][-]
  1.   TJSHTMLFile = class external name 'File' (TJSBlob)
  2.   private
  3.     FLastModified: NativeInt; external name 'lastModified';
  4.     FLastModifiedDate: TJSDate; external name 'lastModifiedDate';
  5.     FName: string; external name 'name';
  6.   public
  7. +   constructor New(ABits: JSValue; AName: string); overload;
  8. +   constructor New(ABits: JSValue; AName: string; AOptions: TJSObject); overload;
  9.     property lastModified: NativeInt read FLastModified;
  10.     property lastModifiedDate : TJSDate read FLastModifiedDate; deprecated;
  11.     property name: String read FName;
  12.   end;
  13. ...
  14.   TJSBlob = class external name 'Blob' (TJSEventTarget)
  15.   private
  16.     FSize: NativeInt; external name 'size';
  17.     FType: string; external name  'type';
  18.   Public
  19. +   constructor New(AArray: JSValue); overload;
  20. +   constructor New(AArray: JSValue; AOptions: TJSObject); overload;
  21.     procedure close;
  22.     function slice : TJSBlob; overload;
  23.     function slice(aStart : NativeInt) : TJSBlob; overload;
  24.     function slice(aStart,aEnd : NativeInt) : TJSBlob; overload;
  25.     function slice(aStart,aEnd : NativeInt; AContentType : String) : TJSBlob; overload;
  26.     function arrayBuffer : TJSPromise;
  27.     property size : NativeInt read FSize;
  28.     property _type : string read FType; deprecated;
  29.     property type_ : string read FType;
  30.   end;
  31.  
Then the project code can be:
Code: Pascal  [Select][+][-]
  1. program demoreadfileinput;
  2.  
  3. uses
  4.   Web,JS;
  5.  
  6. const
  7.   DownloadFileName = 'result.txt';
  8. var
  9.   GInput: TJSHTMLInputElement;
  10.   Goutput: TJSHTMLAnchorElement;
  11.   LReader: TJSFileReader;
  12.   LFile: TJSHTMLFile;
  13.   LFileContent: String;
  14. begin
  15.   GInput := TJSHTMLInputElement(Document.GetElementByID('input'));
  16.   Goutput := TJSHTMLAnchorElement(Document.GetElementByID('output'));
  17.  
  18.   GInput.OnChange := function (AFileInputChangeEvent: TEventListenerEvent): Boolean
  19.   begin
  20.     LFile := GInput.Files[0];
  21.  
  22.     LReader := TJSFileReader.New;
  23.     LReader.OnLoad := function (AFileLoadEvent: TEventListenerEvent): Boolean
  24.     begin
  25.       LFileContent := String(TJSFileReader(AFileLoadEvent.Target).Result);
  26.       // begin edit
  27.       LFileContent := '<pre>' + LineEnding + LFileContent + LineEnding + '</pre>';
  28.       // end edit
  29.  
  30.       LFile := TJSHTMLFile.New(TJSString.New(LFileContent), DownloadFileName);
  31.       Goutput.HRef := TJSURL.createObjectURL(LFile);
  32.       Goutput.Download := DownloadFileName;
  33.       Goutput.Click;
  34.       TJSURL.revokeObjectURL(Goutput.HRef);
  35.     end;
  36.     LReader.ReadAsText(LFile);
  37.   end;
  38. end.
  39.  
« Last Edit: August 28, 2023, 06:06:28 am by Leledumbo »

Okoba

  • Hero Member
  • *****
  • Posts: 533
Re: Load and Save file
« Reply #12 on: August 28, 2023, 03:43:56 pm »
Great demo Leledumbo!
And thank you so much for updating.
I checked it and it works as what I needed!

Okoba

  • Hero Member
  • *****
  • Posts: 533
Re: Load and Save file
« Reply #13 on: August 28, 2023, 03:57:13 pm »
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

  • Hero Member
  • *****
  • Posts: 8760
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Load and Save file
« Reply #14 on: August 28, 2023, 04:38:41 pm »
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.
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.
« Last Edit: August 29, 2023, 06:18:16 am by Leledumbo »

 

TinyPortal © 2005-2018