File System Access API

Share your advanced knowledge/code with the community.
User avatar
Peter
Posts: 1086
Joined: Mon Feb 24, 2014 10:17 pm
Location: 127.0.0.1:9080
Contact:

File System Access API

Post by Peter »

The File System Access API allows web apps to read or save changes directly to files and folders on the user's device.
More Info: https://web.dev/file-system-access/

Code: Select all

EnableExplicit

Global FileHandle

Enumeration
  #Window
  #LoadButton
  #SaveButton
  #SaveAsButton
  #Editor
EndEnumeration

Procedure IsUndefined(Object)
  ! return typeof v_object === "undefined";
EndProcedure

Procedure IsDefined(Object)
  ! return typeof v_object !== "undefined";
EndProcedure

Procedure WriteFile(FileHandle, Content.s)
  ! (async() => {
  !   // Create a FileSystemWritableFileStream to write to.
  !   const writable = await v_filehandle.createWritable();
  !   // Write the contents of the file to the stream.
  !   await writable.write(v_content);
  !   // Close the file and write the contents to disk.
  !   await writable.close();
  ! })(v_filehandle, v_content);
EndProcedure


Procedure LoadButtonEvent()
  
  Protected FileContent.s
  
  ! (async() => {
  !   [v_filehandle] = await window.showOpenFilePicker();
  !   const file     = await v_filehandle.getFile();
  !   v_filecontent  = await file.text();
  SetGadgetText(#Editor, FileContent)
  SetActiveGadget(#Editor)
  ! })();  
  
EndProcedure

Procedure SaveAsButtonEvent()
  
  Protected FileContent.s = GetGadgetText(#Editor)
  
  ! (async() => {
  !   const options = {
  !     types: [
  !       {
  !         description: 'Text Files',
  !         accept: {
  !           'text/plain': ['.txt'],
  !         },
  !       },
  !     ],
  !   };
  !   v_filehandle = await window.showSaveFilePicker(options);
  
  If IsDefined(FileHandle)
    WriteFile(FileHandle, FileContent)
  EndIf 
  
  ! })();  
  
EndProcedure

Procedure SaveButtonEvent()
  
  If IsUndefined(FileHandle) Or FileHandle = 0
    SaveAsButtonEvent()
    ProcedureReturn
  EndIf
  
  Protected FileContent.s = GetGadgetText(#Editor)
  
  WriteFile(FileHandle, FileContent)
  
EndProcedure

OpenWindow(#Window, #PB_Ignore, #PB_Ignore, 800, 600, "Native FileSystem - Demo", #PB_Window_ScreenCentered)

ButtonGadget(#LoadButton,    10, 10, 80, 30, "Load")
ButtonGadget(#SaveButton,   100, 10, 80, 30, "Save")
ButtonGadget(#SaveAsButton, 190, 10, 80, 30, "Save as...")

EditorGadget(#Editor, 10, 50, WindowWidth(#Window) - 20, WindowHeight(#Window) - 60)

BindGadgetEvent(#LoadButton,   @LoadButtonEvent())
BindGadgetEvent(#SaveButton,   @SaveButtonEvent())
BindGadgetEvent(#SaveAsButton, @SaveAsButtonEvent())
User avatar
useful
Posts: 116
Joined: Tue Feb 25, 2014 1:15 pm

Re: File System Access API

Post by useful »

Wow! How cool. Do you have any idea how to convert this example for graphic files (jpj,png,...)?
2B or not 2B = FF
User avatar
Peter
Posts: 1086
Joined: Mon Feb 24, 2014 10:17 pm
Location: 127.0.0.1:9080
Contact:

Re: File System Access API

Post by Peter »

useful wrote: Thu Dec 02, 2021 3:49 amWow! How cool. Do you have any idea how to convert this example for graphic files (jpj,png,...)?
for loadings images try this one:

Code: Select all

EnableExplicit

Procedure LoadImageFromFilesystem(ImageGadget)
  
  If IsGadget(ImageGadget) And GadgetType(ImageGadget) = #PB_GadgetType_Image
    
    ! (async() => {
    !   const [filehandler] = await window.showOpenFilePicker();
    !   var file = await filehandler.getFile();
    !   var filereader = new FileReader();
    !   filereader.readAsDataURL(file);
    !   filereader.onload = function() {
    !     var img = new Image;
    !     img.onload = function() {
    !       var gadgetid = spider_GadgetID(v_imagegadget);
    !       var canvas = gadgetid.gadget.children[0];
    !       spider_ResizeGadget(v_imagegadget, -65535, -65535, img.width, img.height);
    !       canvas.width = spider_GadgetWidth(v_imagegadget);
    !       canvas.height = spider_GadgetHeight(v_imagegadget);
    !       var context = canvas.getContext("2d");  
    !       context.clearRect(0, 0, canvas.width, canvas.height);
    !       context.drawImage(img, 0, 0);
    !     };
    !     img.src = filereader.result;
    !   }
    ! })();
    
  EndIf
  
EndProcedure

Enumeration
  #Window
  #ButtonGadget
  #ImageGadget
EndEnumeration

Procedure ButtonEvent()
  LoadImageFromFilesystem(#ImageGadget)
EndProcedure

OpenWindow(#Window, 0, 0, 800, 800, "ImageGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ButtonGadget(#ButtonGadget, 10, 10, 100, 30, "Load image...")
ImageGadget(#ImageGadget,  10, 50, 500, 500, 0, #PB_Image_Border)

BindGadgetEvent(#ButtonGadget, @ButtonEvent())
User avatar
useful
Posts: 116
Joined: Tue Feb 25, 2014 1:15 pm

Re: File System Access API

Post by useful »

Thank you very much.
2B or not 2B = FF
jn2002dk
Posts: 1
Joined: Sat Jun 10, 2023 7:39 am

Re: File System Access API

Post by jn2002dk »

Beyond awesome

I tried using it with audio files but i am doing something wrong

Code: Select all

InitSound()
Global Song.s
Global fsong=LoadSound(0, "track_2.mp3")

Procedure LoadButtonEvent()

    ! (async() => {
    !   const [filehandler] = await window.showOpenFilePicker();
    !   var file = await filehandler.getFile();
    !   var filereader = new FileReader();
    !   filereader.readAsDataURL(file);
    !   filereader.onload = function() {
    !   g_song = file.webkitRelativePath;
Debug Song
    !   }
    ! })();
EndProcedure
In this case i want the filepath so i can load it into fsong and play it but i am missing something
tj1010
Posts: 201
Joined: Wed May 27, 2015 1:36 pm
Contact:

Re: File System Access API

Post by tj1010 »

SB already has the user-interaction file API integrated(OpenFileRequester and ReadFileCallback). To do anything without user clicks you gotta use the Cordova File plugin; I already posted SB code for it. Browsers and App engines that use CORS UI/UX based stuff will always require user prompts.

I use the SB prompt stuff for loading sqlite databases on Windows 11 and Android 13 on one tool, and then the File Cordova plugin everywhere else for no prompts. On mobile devices you're going to be restricted to certain directories without permissions that can only be set in a manifest..
Post Reply