Identifying the conclusion of a folder being dropped in vanilla JavaScript

I am working on determining when a directory tree has been completely traversed after being dropped onto a page. My goal is to identify the point at which the next process can begin once the entire folder and its sub-directories have been processed by the drop event code.

For instance, in the following code snippet, I aim to send the files via JSON to a server after the folder has been processed. Please note that the Ajax call is not included here.

Here is the recursive directory tree traversal function:

async function processEnt(ent,n,fls){
    n = n==undefined? 0:n;
    
 
    if( ent.isFile ){
        fls.files.push(ent.name)        
    }    
    else if (ent.isDirectory){
        
        fls.dirs[ent.name]={ "files":[], "dirs":{},"done":false }                
        var r = ent.createReader()        
        
        await r.readEntries(
            async function f(ents){                                                
                if(ents.length >0){                    
                    for(var e of ents){
                       await processEnt(e,n+1,fls.dirs[ent.name])                    
                    }                                 
                    await r.readEntries(f)
                }
                
            }
        )
        
    }    
    console.log(n +" level done")    
        
}


   

The drop event handler:

async function onDrop(evt){
    evt.preventDefault()
    evt.stopPropagation()
    
    M.files = {
        "files":[],
        "dirs":{}
    }    
    for(item of evt.dataTransfer.items){                
        await processEnt( item.webkitGetAsEntry(),0,M.files )    
    }
    
    console.log("on drop done")
    
}

Answer №1

I have devised a potential solution.

The variable M.paths keeps track of the number of active paths and is incremented for each sub-directory beyond the first one. Additionally, there have been some slight modifications to how files and directories are handled. A timer is utilized to check the value of M.paths to determine if all paths have been completed.

A potential issue that may arise is a race condition where the first sub-directory is processed and M.paths is decremented before any other directories on that level are processed.

Regarding the drop event:

function onDrop(evt){
    evt.preventDefault()
    evt.stopPropagation()
   
    M.paths = 0 
    M.files = {
        "files":[],
        "dirs":[]
    }    
    
    for(item of evt.dataTransfer.items){                
        ent = item.webkitGetAsEntry()
        if(ent.isFile){
           M.files["files"].push(ent) 
        }else if(ent.isDirectory) {
            M.paths+=1
            processDirectory(ent,0,M.files )                
        }
    }
    
    window.setTimeout(function f(){
            if(M.paths==0){
                // drop envent processed 
                //run update or send info to server
                console.log("Drop event done")                    
                
            }else{
                window.setTimeout(f,500)
            }
        },500)
} 

Function for processing each directory:

function processDirectory(ent,n,fls){
    n = n==undefined? 0:n;
        
    var new_dir ={"ent":ent,"files":[],"dirs":[]}
    fls["dirs"].push(new_dir)
    var r = ent.createReader()        
    r.readEntries(
        function f(ents){                                                                
            var leaf = true
            var add_path =0
            for(let entc of ents){
                if ( entc.isDirectory ){
                    M.paths+= add_path
                    add_path = 1
                    console.log(n+":"+M.paths+":"+entc.name)
                    leaf = false
                    processDirectory(entc,n+1,new_dir)
                    
                }else if( entc.isFile){
                    new_dir["files"].push(ent)
                }     
            }
            if(leaf){ M.paths--}                
        }            
    )   
}

This implementation appears to be functional, although it has not undergone extensive testing. It should be noted that when dealing with numerous entries, not all of them may be retrieved. Refer to for more information.

Answer №2

I discovered a solution that appears to work effectively.

Here is the drop event function:

function onDrop (evt){
    
    evt.preventDefault()
    evt.stopPropagation()
    
    var promises = []
    
    for(item of evt.dataTransfer.items){
        //create new Promise that calls processItem function
        // the promise is used to track if the work is complete
        var p  = new Promise( function(res, rej){
        
                processItem(item.webkitGetAsEntry(),res,rej)
            })
            
        // record each promise
        promises.push( p )
        
    }
    
    // the drop event is complete when all of the item (child)
    // promises are completed
    Promise.all( promises ).then(function(){
        // code for after the drop event
    })
    
}

The function responsible for processing each item: function processItem (item,res,rej){

    if (ent.isFile){
        //handle file entry
        
        //complete this items promise
        res()
    }
    else if (ent.isDirectory){
    
        var promises = []
        var dirReader = ent.createReader()
        
        
        function read( entries ){
        
            if (entries.length > 0 ){                
            
                for(var e of entries){
                    var p = new Promise( function(resm,rejm) {                    
                        processItem(e,resm,rejm)
                        })
                    promises.push(p)
                }
                /*
                "readEntries" called again to ensure all entries are read as 
                "readEntries" does not read all files when there 
                is a large amount of files
                */
                dirReader.readEntries(read)
            }
        
        }
        else{
            /*
              if there are no more entries ensure all entries 
              in the directory are processed
             */
             Prmoise.all( promises ).then(function(){
                // once all promises are complete complete this items promise
                res()
            })
            
        }
        // start the read process
        dirReader.readEntries(read)
    }        


}

In testing, all processes were successfully completed before their parent processes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Assigning a value to a cell depending on a specific condition

Currently, I have a column connected to a field known as state. The possible values for this field are either S or L. My objective is to map these values as follows: S => Short, L => Long The binding is structured in the following way: $scope.gridOption ...

Exploring the properties of a file directory

As I try to access the d attribute of a path that was generated using Javascript, the output of printing the path element appears as follows: path class=​"coastline" d="M641.2565741281438,207.45837080935186L640.7046722156485,207.0278378856494L640.698 ...

The error message "element is not defined" is indicating an issue related to the cordova-plugin-google

In my current project using Ionic 3, I decided to implement map-related features by incorporating the Google Maps plugin recommended by the Ionic Team. This specific plugin serves as a wrapper around cordova-plugin-googlemaps. Following the steps outlined ...

"Clicking on the hamburger menu causes the webpage to reset its scroll

I recently integrated a mobile hamburger menu into my website, which is primarily built around a single page. However, I noticed that whenever I open the menu, it automatically scrolls to the top of the page regardless of where you were previously scrollin ...

Successful AJAX Post request functioning exclusively within the Web Console (Preview)

When a user clicks on an element on the website, I have a simple AJAX request to send the ID of that element. However, the script only works in the Web Console under the Network -> Preview section and this issue occurs across all browsers. Here is the cod ...

Issue with child prop not being updated despite changes in parent component

I'm facing a strange issue where altering a child component's prop doesn't trigger a re-render. Here's the scenario: In the parent component, I have: <child :problemProp="proplemPropValue"></child> In the child component, ...

javascript The event handler is not functioning properly for the dynamically loaded AJAX content

I am facing an issue with adding a JavaScript event listener to a dynamically loaded div via AJAX. Below is my code snippet: var QuantityMiniCart = function() { var infor = document.querySelectorAll( '.mini-cart-product-infor' ); if ( ...

Utilizing jQuery to extract the id and update its content

One of my tasks involves working with a table generated by PHP and incorporating a modal that allows users to change the text produced by the variable $l_id. I have a link with a class "eloc" that triggers the display of the modal div section. By intercept ...

What is the best way to transfer a variable from a node server to a javascript client when the page is first

My web application is mainly static, but I need to dynamically send the user's username if they are logged in and the room name they specify in the URL to the client-side JavaScript upon page load. Finding a simple solution has been challenging for me ...

Creating an easy-to-update catalog utilizing an external file: A step-by-step guide

I am looking to create a product catalog with 1-4 products in a row, each displayed in a box with details and prices. I would like to be able to generate the catalog easily using an XML/CSV file that can be updated. Can anyone provide guidance on how to ac ...

Clicking on the image does not result in a larger image being displayed

Currently working on an assignment that requires a modal pop-out to display larger versions of photos when clicked, with the option to go back using the X button. Unfortunately, I'm facing issues with the X button not functioning properly and images n ...

"Can you help me understand how to establish a character limit for the MUI autocomplete

Hey everyone, I have successfully created an auto-complete feature using Material UI and an API. Now, I am facing a challenge where I need to limit the suggestions returned by the autocomplete to only show matches when the user types at least 3 letters. Ca ...

Implementing append operations in JavaScript without relying on the id attribute

Is there a way to specify the second div without assigning it an ID or using any attributes, and then perform an append operation inside it? For instance, indicating that the p element should be appended within the second div without relying on an ID or ...

Unable to retrieve real-time data from Firestore using getStaticPaths in Next.js

While fetching data from Firebase Firestore using getStaticProps is successful, I encounter a 404 page when attempting to implement the logic for retrieving details of individual items with getStaticPaths. The current state of my [id].js code appears as fo ...

Utilize auto-suggestion feature for populating dynamically created input fields with information sourced from the

I have searched through numerous questions on stackoverflow related to my issue, but I was unable to apply any of them to solve my problem. Therefore, I am providing the files that I have been working with. I have successfully implemented autocomplete fe ...

Avoid triggering child states in ui-router

Here is the progress I have made with ui-router states: $stateProvider .state('tools', { url: '/tools/:tool', template: '<div ui-view=""></div>', abstract: true, onEnter: function ($stateParams, ...

Struggling to make a form submit work with AngularJS and a Bootstrap datetime picker

Struggling to create a post and include name and datetime using a bootstrap datetimepicker. After selecting the datetime and clicking add, nothing happens. However, if I manually type in the field and click add, it submits successfully. Despite reading up ...

Utilize Javascript to refine JSON data strings

Currently, I am tackling a small project and facing a minor JS issue. The JSON string that I have looks like this: var jsObj = { "templates": { "form0": { "ID": "MyAlertNew", "isVisible": "true", ...

What is the best way to implement a custom NgbDateParserFormatter from angular-bootstrap in Angular 8?

Currently, I am working on customizing the appearance of dates in a form using Angular-Bootstrap's datepicker with NgbDateParserFormatter. The details can be found at here. My goal is to display the date in the format of year-month-day in the form fi ...

Tips for incorporating routes in Polka.js in a way that resembles the functionality of express.Route()

One of the challenges I am facing is trying to import route logic from another file in my project. While using Express.js, this could be done easily with express.Route(). However, when attempting polka.Route(), an error occurs stating that Route doesn&apos ...