0

I am trying to determine if a directory tree has been fully traversed after is was dropped on a page. That is: I would like to know when the next process can start after the full folder and sub-directories has been process by the drop event code.

As an example, in the code below I want send the M.files via json to sever. To do this I need to know when the folder is processed. The Ajax call is not shown.

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 function:

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")
    
}
Marked
  • 163
  • 2
  • 6

2 Answers2

0

I come up with a possible answer.

M.paths hold the number of active paths and is incremented for each sub-directory past the first. The handling of files and directories has also been slightly changed. A timer is used to pole the M.pathsto see if all of the paths have been completed.

There may exists a race condition in that the first sub-directory is processed and M.paths is decremented before any the other directories on that level is processed.

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 to process 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 seems to work though I have not tested it thoroughly. Also if there are many entries it will not get all of them. See https://stackoverflow.com/a/53058574/2975893 for details.

Marked
  • 163
  • 2
  • 6
0

I found a solution which seems to do the trick.

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 that processes 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 completed before their parents.

Marked
  • 163
  • 2
  • 6