Copy link to clipboard
Copied
Hi guys. I want to make a file tree menu GUI for my script, and I found window.cep.fs.readDir strange in that it returns undefined for directories, so I decided to do this through JSX:
recurseChildren(rootFolder)
function recurseChildren(path) {
var subFolders = getChildren(path, 'Folders');
var subFiles = getChildren(path, 'Files');
var children = [];
if (subFolders) {
for (var i = 0; i < subFolders.length; i++) {
children.push(subFolders)
children.push(recurseChildren(subFolders));
}
}
if (subFiles) {
for (var i = 0; i < subFiles.length; i++) {
children.push(subFiles);
}
}
if (!children.length) {
return false;
} else {
return children;
}
}
function getChildren(path, type){
var thisFolder = Folder(path);
var children = thisFolder.getFiles();
var subs = [];
if (!children.length) {
return false;
} else {
for (var i = 0; i < children.length; i++) {
switch (type) {
case 'Folders':
if ((/\/(\w|\-|\d)*$/g.test(children)) && !(/LICENSE/.test(children)))
subs.push(children);
break;
case 'Files':
if ((/\/(\w|\d|\-)*\.(\w)*$/g.test(children)) || (/LICENSE/.test(children)))
subs.push(children);
break;
default:
subs.push(children);
break;
}
}
return subs;
}
}
So I have access to all the files in all the folders of a single root directory, including ones that are excluded from getFiles() typically (like '.git', 'LICENSE', '.debug' and more), and my plan was to use this as a basis for constructing a tree view menu itself, but now I'm confused as to the best way to organize the data. I tried appending each new directory as a property of an object with each filename as another property within that, but found that traversing a 'nesting level' within an object without knowing it's name or what nesting level it is (to know what the parent would be) was really obfuscatory and pretty hard to do. Initially I thought I should use arrays within arrays, but then I tied myself up in a lot of corners trying to go that route too, because I need to know the name of the subfolder, the subfolder's parent, and the subfolder's contents.
How would you best organize this, or rewrite the above to give a better result? I feel like dropping the file reading and returning only directories, then using window.cep.readFile on all the directories contents back in vanilla JS would be far easier than anything I'm doing here, am I wrong? Are there better ways to do this?
Hey, I don't have any spare minutes at the moment to create a test of what I feel I'd use for such a purpose, but perhaps what you could use in your toolset is:
var f = Folder("~/Desktop");
var allFiles = f.getFiles();
var thisFile;
for(var i = 0; i < allFiles.length; i++){
thisFile = allFiles;
$.writeln(decodeURI(thisFile.name) + " | Is Folder: " + (thisFile instanceof Folder) + ", Is File: " + (thisFile instanceof File));
}
Copy link to clipboard
Copied
Hey, I don't have any spare minutes at the moment to create a test of what I feel I'd use for such a purpose, but perhaps what you could use in your toolset is:
var f = Folder("~/Desktop");
var allFiles = f.getFiles();
var thisFile;
for(var i = 0; i < allFiles.length; i++){
thisFile = allFiles;
$.writeln(decodeURI(thisFile.name) + " | Is Folder: " + (thisFile instanceof Folder) + ", Is File: " + (thisFile instanceof File));
}
Copy link to clipboard
Copied
Thanks! Using instanceof is giving perfect results, refactored all my code and ended up with an object result:
JSX:
function readFullDirectory(path){
var mirror = {}
var f = Folder(path);
var allFiles = f.getFiles();
var thisFile;
for (var i = 0; i < allFiles.length; i++) {
thisFile = allFiles;
if (thisFile instanceof Folder) {
mirror[thisFile.name] = readFullDirectory(thisFile);
} else {
mirror[thisFile.name] = thisFile;
}
}
return JSON.stringify(mirror);
}
JS:
csInterface.evalScript(`readFullDirectory('${sysPath}')`, function(mirror){
var root = parseAll(mirror);
console.log(result);
});
function parseAll(str){
var result = JSON.parse(str);
for (let [key, value] of Object.entries(result)) {
if (typeof value !== 'object') {
result[key] = parseAll(value);
}
}
return result;
}
Before recursively JSON parsing my console looked like a warzone, but I did get it to correctly display a hierarchy of folders/files this way:
This solves my problem and replaces a shameful amount of past code, lol. I'm still not sure if this is a dumb way to structure a hierarchy for folders and files, but I can iterate through and dynamically generate the tree menu from it, assign the file path as the value or even the corresponding HTML element, so it might work. It's a bit wonky in the sense that I have file extensions within property names, so I can only access via root.client['index.html'] but not directly as root.client.index.html, I'm sure this is very offensive to somebody out there.
Is it bad form to prod? If not, how would you detect any external changes to this folder outside the scope of this script -- any new, deleted, or renamed file, etc.? I figure that I could run the above scan with SetTimer every 500ms or so and discriminate the new result from the previous result, if no change return nothing and assign new to old, but if change then rebuild this tree object and trigger a redraw of the UI, but I keep having to window.reload() my scripts when using SetTimer this way and it seems to bring a few other glitches. Any ideas? How would you do it if you needed to?
Copy link to clipboard
Copied
This is all great stuff - but I have not yet done anything like it! Looking forward to all your progress.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Hey, how do you get such a styled treeview with perfect colors matching that UI and all?
Copy link to clipboard
Copied
I've made a JS and CSS library that automatically styles to mimic native UI, updates with theme changes, adds fonts, changes all scrollbars and other things too:
I haven't updated the repo in a while, but I add to and modify it all the time (latest is in this tree menu) and I'd update it if others are interested. It returns an appUI object that has a ton of information in it, including all of the hex values above, and everything is based in CSS variables so restyling affects all elements and hovering/toggling and certain things are handled automatically. You can snatch all the native UI colors for AI, AE, and PS, and I base it off Bootstrap-esque classes, so using it is as simple as:
<div class="adobe adobe-btn">
<!-- Place an icon inside button -->
<span class="fa fa-adjust fa-lg"></span>
</div>
That's the code for the button in the SkinColor panel between eyedropper and wand. Just adding a prefix class, 'adobe', then sub-classes like 'adobe-btn-switch' (toolbar button), 'adobe-inputGroup', 'adobe-input-md', etc, and the JS and CSS (adobeStyle.css and magicMirror.js) take care of all the styling and eventListeners.
Copy link to clipboard
Copied
I tried this code but keeps returning the path of Photoshop or Illustrator. I used a dialog to get folderPath and send that to your script. I dont quite understand why it pushes back the app path. I did alter you code a tiny bit. I did not used JSON.stringify, but toSource(). But that doesnt seem to matter.
({undefined:[new File ("/Applications/Adobe%20Photoshop%20CC%202018/.DS_Store"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/Adobe%20Photoshop%20CC%202018.app"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/cefclient_cep8.app"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/Configuration"), new File ("/Applications/Adobe%20Photoshop%20CC%202018/Icon%0D"), new File ("/Applications/Adobe%20Photoshop%20CC%202018/icon.txt"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/Legal"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/Locales"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/Plug-ins"), new Folder ("/Applications/Adobe%20Photoshop%20CC%202018/Presets"), new File ("/Applications/Adobe%20Photoshop%20CC%202018/Uninstall%20Adobe%20Photoshop%20CC%202018")]})
EDIT
i noticed [i] was missing, that cause this weird return. But when i added that to allFiles[i] the app hangs.
function readFullDirectory(path){
var files = {}
var f = Folder(path);
var allFiles = f.getFiles();
var thisFile;
for (var i = 0; i < allFiles.length; i++) {
thisFile = allFiles[i];
if (thisFile instanceof Folder) {
files[thisFile.name] = readFullDirectory(thisFile);
} else {
files[thisFile.name] = thisFile;
}
}
// return JSON.stringify(files);
// alert(files)
// return files;
return files.toSource();
}
var path = Folder.selectDialog('Please select the source folder');
alert(readFullDirectory(path))
EDIT 2
okay issue found, you used path, that is something which can be app aswell. i changed it to dialogPath or folderPath and now it works properly. It wasnt actually hanging. it was getting all files and folders of photoshop. Since path in the app returns program path and everything inside
Copy link to clipboard
Copied
To be perfectly honest this project was early into my foray into code and I wouldn't recommend using any of it personally. I'm fairly sure the way I'd posted code back in the day was altered when the forums were redone as there seems to be consistent missing [i] or other characters in the code, unless you were looking at the github repo. If so, I made several versions after this named Redwood and Hyperion that would be much better, but ultimately I'd do things a lot differently nowadays and use NodeJS utils instead of any scripting.
Copy link to clipboard
Copied
Well i was interested to get a folder and files structure. Just tinkering about a doodle for someone. They'd like a method to replicate a folder structure from source to a destination folder. It i used to read PDF files and creates different kinds of files when exporting.