Electron, v3

Keeping Track of the Current File

Steve Kinney

Steve Kinney

Electron, v3

Check out a free preview of the full Electron, v3 course

The "Keeping Track of the Current File" Lesson is part of the full, Electron, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Steve discusses getting and setting the currently accessed file to allow the implementation of UI features for a more natural OS experience. Utilizing the current file to display the pathname and icon of the file in the window's title bar is also demonstrated in this segment.


Transcript from the "Keeping Track of the Current File" Lesson

>> So to catch up, we've got the ability to open files, we've got the ability to save files. We just wanna make sure that we've got the ability to know what file we're currently working with, right? So what I'm thinking that I'm gonna do is kind of give myself two functions called set current file and get current file, like Revel in all of your work.

When last we met our heroes, us. We had to build an open file, we have really a save a file and export the HTML. We just don't really have a great sense of knowing what file we're currently working with. So we can do the natural and normal things that we expect from a desktop application in terms of like saving if you already have a current file open.

Or if you've saved the file and all the other little like OS level, niceties that the various operating systems provide us. So I think for starters, I'm gonna do a give myself two functions, getCurrentFile and setCurrentFile. And the getCurrentFile when I might just take some of the more complicated code that I had and that's a file and be able to say like, We'd say, let's say so filePath as a string.

browserWindow is a BrowserWindow, makes this asynchronous. And we'll have to say if filePath give me that. Actually, if currentfile.filepath, we don't even really need that argument there. Make this one optional. If there is currently one that we know about, give me that, otherwise, Give me what we get back from the, From the browser window.

There's no browser window. Like, we could get back undefined. So we've got the ability to get that kind. When I might use that a little bit, and then we've got setCurrentFile with should take a filePath, which is a string, and all we're gonna build this out a little bit, but we'll just say, currentFile.filepPath equals that.

Awesome, that's gonna kind of be the initial like pieces that we build upon, because there's a whole bunch of stuff that we can do. We saw before, we can add to the title to show the current file, we could set the representative file on macOS, right? We might choose to try to like keep track of whether or not there's changes and edits and stuff along those lines.

And all of those pieces, in fact, like, I'll decide what I want to do here in a second. So there's a bunch of stuff we will do as we set the current file and build it from there. I might even just make this default current file. We'll find out as we go along.

So the first thing I wanna do is just at least get that get current file in here to just simplify my code a little bit. And so on the saveFile, we'll just say, filePath = await getCurrentFile. The browser window in there, so like ideally I'll get the one stored, if not I will get the browser window, very similar to what we had before.

We'll have that there as well. Cool, yeah, so we'll get it there's current file path, we'll get the current file path, otherwise, we will return the browser window, great. Everything moves along, and then the setCurrentFile is upon saving it. We can actually probably just do that in the save file dialog for now, which is await for that and then, setCurrentFile, and we can do file path and I can do content as well.

While I'm in here, I'll just have to adjust that one. So do filePath to do content string. So because we know the last time that we saved, it will be the content that we had in this case. Fix it right there. Cool. And then we also know that when we open a file, we have the file path and the content as well.

So now that we have this set current file abstraction, we can use it there too and which will make it a lot easier to see that everything works the way that we expect. So when we open a file, we'll have the file path, we'll have the content. So we'll also set current file to file path and content as well, right?

So we have that in place, it's just storing it in memory, it doesn't really do a lot just yet, but it gives us the ability to add on to this and handle stuff. So now whenever we save a file, or whenever we open a file, we are keeping track of what the current file is, and we can begin to put some of those pieces in there as well.

The nice part is that electron makes this very, very, very simple for us. Which is, there are a few different options that are available on the app module. So there is app.setRepresentedFile. It's actually not the one we want, so we've got it, we're keeping track of it. And then what we wanna do is, let's start with setting the title, actually.

We've got that browser window. We should probably take that as well. So we can change the browserWindow too, I think I want that to be the first argument, just to keep it. Cuz we should always have one of those as well. So we'll get browserWindow and now I have to pass that in.

Luckily, TypeScript is gonna help me here, so we'll pass the browserWindow in here. And we'll pass it over here as well. This is one of the reasons why I made it a point to pass it through. And again, if you have just one window, you could just store it in that top level scope as well.

But it is one of those things where should you decide to have multiple windows that you're storing them in, whether it be an array, whether it be a hash map or something like that, right? No longer can you rely on a global. And you can call it a premature optimization, but it's also not bothering anyone, and it makes it a little bit easier to work with.

You just have to remember to pass it through. Cool, so now we've got, we're setting the current file. We can do set title, we'll call it. We get a fun thing I'll show you in a second, which is Electron respects a few extra properties in the package.json. One of them, if we look in here that we'll see, is we have this product name, right?

So you have the repo name or the module name that you normally use in NPM. But then Electron or Electron Forge in particular respects this product name, which is like what you actually want it to show like as the actual name of the app. When you are developing right under the hood, there is like a shell of an Electron app and it's called Electron.

So that's what it shows the application menu when it has the like macOS bindings here, like Windows, you don't see this menu at all. But you can see this here when you package the app instead of Electron, it will say the name of your application, right? So you don't have to worry about like, they open your app, it just says Electron, it will show the name of the application.

As you're developing, it's kind of just using a shell Electron app to like, hold it, and that one is called Electron. But the rest of the time, you will, because you will see the actual name of your app once you package it. So that product name is then available for you wherever you need as app.name, which in this case will be firesale, or if you change it to something else, it will be something else.

So we can set that as well. So we've got that in place, and now we can also see like, browserWindow, setRepresentedFilename, right? That is the one that we saw in the menu bar up top where you can drag it, you can see exactly where it was stuff along those lines.

So that is like that's all you really need to do is just tell it where on the OS this file lives. And then again, I believe this is macOS specific and like the nice part is if you have IntelliSense like VS Code, and you hover over a method name, it says app platform is Darwin.

That means macOS only, some of them are Linux only some of them are Windows only, right? It all depends on things that one OS can do that the other one can't do. The nice part is, is you don't have to like, be like if Darwin do this If it is Windows or Linux just nothing happens, right?

And you don't necessarily need to worry about it. So now, we can set the representative file name and again this will happen when ever we either open a file or save a file. Which are right now the two ways that we could literally set a new file, like one could argue, could you drag and drop in another file?

Sure, right? The nice part is you would just as you know, you're kind of already getting the sense here. You'd send an IPC message back to the renderer, you'd update these. You probably open the file, right? You'd probably trigger open file if they dragged in a file because you won't have the contents otherwise.

So these like abstractions, you can kind of build on top of them in general. Let's just see it in action because I think like the ability to know the current file and represent that in the window, we should verify that that is all working as expected. So I'm gonna just give that another start again.

And so we see firesale and now I gotta open a file. We'll see the context bridge one again. And now you can see I see the full path. Now node has a bunch of methods on the path library if you just want the base name or something along those lines, like that's easy enough to do, we'll do it.

But now you can see I get this representative file here and if I like command, click on it, you can see exactly where it is. I can drag it, it looks, it's beginning to look more and more like a full like macOS like application. And again, you will still get the title.

If you're on Windows or Linux, you will just also get this on macOS, and both will begin to feel more and more like one of these real like kind of files as well. So we could just do like we can grab from path we can also get base name and just use that as well here, so we can do basename for the filePath.

And now we'll give another shot. Open a file. And now we see just the file name. So like whatever you're trying to go for, you can get the like appropriate effect here and show whichever one makes sense. It's still the full file path when we set the representative file.

So we can see that here as well. The other thing we might choose to do along the same time period is we can also, and this will work across all of the different, all of the different operating systems. It manifests itself differently, and you'll know best is you can add it to the recent documents list, right?

Now, the one thing I will warn you is if you're just in development, it is going to be, as you can see, my very mature file names from previous runs of this. It is like, because you're using that Electron shell application in this case, it is the same one that you use repeatedly.

When you build it up for production, obviously, then it bundles with the right identifier, and stuff along those lines. But out of the box, you will see stuff from previous iterations of this as well, but there are none of them called manifesto.md. So, let's go verify that that does what we think it does.

Right, and we'll go ahead, we open the file. And now we should see it in here as well, right? And then it'll also show up in your like recent documents where wherever recent documents are found in your OS. It registers with the OS as a document that you have opened up recently and like, you're getting that full, like file system integration at this point, or OS integration.

That like you would come to expect in an application. And again, like most of these things, they are an attention to detail, and you do need to tell electron like the specifics of how this should work, but the act of doing it is not very hard, right? You just need to know, like, okay, we're doing, you know, it's going to be a little bit different for like, if you build like an image resizing app, or something along those lines, right?

Like another great example is if you just wanted something that I can drag, drop, upload to my S3 bucket, right? You can whip something up like that incredibly quickly. The nuances of what the representative file is and how that works is gonna be different, each one. So yeah, you have to tell it.

But generally speaking, once you have a sense of how that's supposed to work, it should be relatively easy to check.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now