7

Why would you want to show a file/folder dialog on the server-side?

I'm building a project that is intended to be ran locally (both the Node server-side part and client-side in the browser), where I'd like to be able to select a path, add it to some list or JSON file, and then maintain some projects in it (webpack'ing, read files, serve via express, etc).

Mostly just for personal use, for now anyways.

The reason I ask to do this via Node instead of the browser is so I can somehow get around the security implications in modern browsers that prevents, upon selecting a folder, from revealing the full local folder paths on the client-side (from an <input> tag).

Not only that, but I also:

  • DON'T need to upload any files, or
  • DON'T need the list of files contained in the selected folder.

I just need:

  • a way to pick a folder in a user-friendly manner, and...
  • submit it's path to the server
  • (or have the server prompt for it, and store it somewhere).

Take this input tag for example:

<input id="open-project" type="file" />

This will result this type of popup, which is great for digging into folders, pasting portions of paths to quickly navigate where you need, go to your Quick Access / Favorites, etc...

Shows the Open file dialog

But it's intended for selecting files, with no paths exposed, nothing useful to pass on to the server.

However...

If you switch it to this...

<input id="open-project" type="file" webkitdirectory directory />

You end up with this dreadful dialog box, which assumes you want to upload ALL THE FILES contained in the folder.

enter image description here

enter image description here


So it doesn't really look like <input> is the way to go.

Maybe there's an existing module that does this on the server-side? That way I could:

  • 'Invoke' it from the client-side, via AJAX for example
  • which would then trigger it on the server
  • and then show me the folder-select prompt

Or...

Make, a... tree-view in the browser... that communicates back-and-forth with the node side to dig down the local filesystem...

Any suggestions?

Community
  • 1
  • 1
chamberlainpi
  • 4,854
  • 8
  • 32
  • 63
  • 1
    Did you finally solve this?....I am in the very same situation....:) – ÁngelBlanco Mar 31 '20 at 11:56
  • @ÁngelBlanco I ended up building a custom browser-based file explorer with VueJS + “express” module. I defined a POST route that explores a list of available volumes/drives and also allows to dig through them (except some system directories). A little HTML, CSS and JS later, much later... got myself a folder selector! – chamberlainpi Apr 01 '20 at 00:32
  • @bigp - would you be willing to share that custom browser based file explorer? Or if not, any inspiration you used to create it? It would help me a lot with a current project. Thanks! – Alex L Nov 13 '20 at 22:13

1 Answers1

8

I've accomplished this by spawning a child powershell process, and passing that value back up to the parent. This would only work on a Windows server, but something like this should work:

let psScript = `
Function Select-FolderDialog
{
    param([string]$Description="Select Folder",[string]$RootFolder="Desktop")

 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
     Out-Null     

   $objForm = New-Object System.Windows.Forms.FolderBrowserDialog
        $objForm.Rootfolder = $RootFolder
        $objForm.Description = $Description
        $Show = $objForm.ShowDialog()
        If ($Show -eq "OK")
        {
            Return $objForm.SelectedPath
        }
        Else
        {
            Write-Error "Operation cancelled by user."
        }
    }

$folder = Select-FolderDialog # the variable contains user folder selection
write-host $folder
`

That's essentially the script that you need to prompt for folder location, then write it to the host (similar to a console.log)

then you'd need to execute this script and handle the output:

var spawn = require("child_process").spawn,child;
child = spawn("powershell.exe",psScript);
child.stdout.on("data",function(data){
    console.log("Powershell Data: " + data);
});
child.stderr.on("data",function(data){
    //this script block will get the output of the PS script
    console.log("Powershell Errors: " + data);
});
child.on("exit",function(){
    console.log("Powershell Script finished");
});
child.stdin.end(); //end input
  • Great answer that I used on a few different little projects. However now, for a reason I cannot yet determine, it no longer pops up in the foreground, but pops up in the background... I've tried to use all sorts of scripts to make it go to the foreground with no luck. Any ideas? (I've tried things like ``foreach($p in (Get-Process powershell)){(New-Object -ComObject WScript.Shell).AppActivate(($p).MainWindowTitle)}``) – Alex L Nov 13 '20 at 22:09
  • 3
    You need to call spawn like spawn('powershell.exe', [psScript]); otherwise there will be an error in your code. Node 12.18.3 – Mansur Nov 25 '20 at 17:31
  • 1
    If you want to use a better folder browser dialog, I've grappled with the issue of displaying a more user friendly, fully featured dialog using your example [here](https://stackoverflow.com/questions/66823581/use-the-upgraded-folderbrowserdialog-vista-style-in-powershell/66823582#66823582) – Ben Philipp Mar 26 '21 at 20:11
  • @BenPhilipp Thank you so much! Combining this answer with the one you linked gave me exactly what I came here for – aggregate1166877 Oct 30 '22 at 02:18
  • @RogerHernandez I'm developing an MIT-licensed terminal utils package. May I please use your code in that project under the MIT license? – aggregate1166877 Nov 25 '22 at 04:29