2015-02-20 9 views
6

Come dice il titolo, ho una struttura di directory, voglio convertirla in un formato JSON compatibile per jsTree usage. Così l'uscita per una data listaFunzione efficiente per la creazione di dati JSON dalla struttura della directory dei file?

INPUT:

./Simple Root Node 
./Root Node 2 
./Root Node 2/Child 1 
./Root Node 2/Child 2 

USCITA:

treeJSON = [ 
     { "id" : "ajson1", "parent" : "#", "text" : "Simple root node" }, 
     { "id" : "ajson2", "parent" : "#", "text" : "Root node 2" }, 
     { "id" : "ajson3", "parent" : "ajson2", "text" : "Child 1" }, 
     { "id" : "ajson4", "parent" : "ajson2", "text" : "Child 2" }, 
    ] 

il mio metodo:

Attualmente, sto prendendo ogni linea dall'input. Dì ./Root Node 2/Child 1, quindi I pattern corrisponde alla prima cartella, creando un array come { "id" : "ajson2", "parent" : "#", "text" : "Root node 2" }. Quindi andare in modo ricorsivo per la prossima rimozione della prima cartella. Quindi, creando l'array di rete come { "id" : "ajson4", "parent" : "ajson2", "text" : "Child 2" }.

Faccio questo per ogni riga nell'input e quindi utilizzo la mia funzione di matrice univoca come in http://jsfiddle.net/bsw5s60j/8/ per rimuovere tutti gli array duplicati che sono stati creati. Ad esempio, { "id" : "ajson2", "parent" : "#", "text" : "Root node 2" } verrebbe creato due volte. Una volta mentre si passa attraverso la terza linea e poi la quarta.

Chiaramente, questo codice è ALTAMENTE inefficiente. Se ho circa 1.3K di directory, supponiamo che ognuna abbia 4 sottodirectory, abbiamo array 5.2K che devono essere controllati per i duplicati.

Questo sta creando un problema di hge. C'è un altro modo efficace in cui posso twittare questo codice?

Fiddle: (funziona con Chrome Solo a causa del l'attributo di file webkit)http://jsfiddle.net/bsw5s60j/8/

Javascript

var input = document.getElementById('files'); 
var narr = []; 
var fileICON = "file.png"; 

//when browse button is pressed 
input.onchange = function (e) { 
    var dummyObj = []; 
    var files = e.target.files; // FileList 
    for (var i = 0, f; f = files[i]; ++i) { 
     var fname = './' + files[i].webkitRelativePath; 
     narr = $.merge(dummyObj, (cat(fname))); 
    } 

    treeJSON = narr.getUnique(); // getting the JSON tree after processing input 
    console.log(JSON.stringify(treeJSON)); 

    //creating the tree using jstree 

    $('#tree') 
     .jstree({ 
     'core': { 
      'check_callback': true, 
       'data': function (node, cb) { 
       cb.call(this, treeJSON); 
      } 
     } 
    }); 
    var tree = $('#tree').jstree(true); 
    tree.refresh(); 
}; 

//get unqiue array function 
Array.prototype.getUnique = function() { 
    var o = {}, a = []; 
    for (var i = 0, l = this.length; i < l; ++i) { 
     if (o.hasOwnProperty(JSON.stringify(this[i]))) { 
      continue; 
     } 
     a.push(this[i]); 
     o[JSON.stringify(this[i])] = 1; 
    } 
    return a; 
}; 

// categorizing function which converts each ./Files/Root/File.jpg to a JSON 

var objArr = []; 
var folderArr = []; 

function cat(a) { 
    if (!a.match(/\/(.+?)\//)) { 
     var dummyObj = {}; 
     var fname = a.match(/\/(.*)/)[1]; 
     dummyObj.id = fname; 
     dummyObj.text = fname; 
     if (folderArr === undefined || folderArr.length == 0) { 
      dummyObj.parent = '#'; 
     } else { 
      dummyObj.parent = folderArr[(folderArr.length) - 1]; 
      dummyObj.icon = fileICON; // add extention and icon support 
     } 
     objArr.push(dummyObj); 
     return objArr; 
    } else { 
     if (a.charAt(0) == '.') { 
      var dummyObj = {}; 
      var dir1 = a.match(/^.*?\/(.*?)\//)[1]; 
      dummyObj.id = dir1; 
      dummyObj.text = dir1; 
      dummyObj.parent = '#'; 
      dummyObj.state = { 
       'opened': true, 
        'selected': true 
      }; // not working 
      folderArr.push(dir1); 
      objArr.push(dummyObj); 
      var remStr = a.replace(/^[^\/]*\/[^\/]+/, ''); 
      cat(remStr); 
      return objArr; 
     } else { 
      var dummyObj = {}; 
      var dir1 = a.match(/^.*?\/(.*?)\//)[1]; 
      dummyObj.id = dir1; 
      dummyObj.text = dir1; 
      dummyObj.parent = folderArr[(folderArr.length) - 1]; 
      folderArr.push(dir1); 
      objArr.push(dummyObj); 
      var remStr = a.replace(/^[^\/]*\/[^\/]+/, ''); 
      cat(remStr); 
      return objArr; 
     } 
    } 
} 

HTML

<input type="file" id="files" name="files[]" multiple webkitdirectory /> 
<div id="tree"></div> 

Eventuali modifiche o suggerimenti sarebbe molto utile! Grazie

+0

Si prega di inserire il codice nella domanda. – Bergi

+0

I dati di input devono essere convalidati? È ordinato, come nel tuo esempio? – Bergi

+0

@Bergi Ho aggiunto come codificato come richiesto. –

risposta

2

Ecco un semplice algoritmo che dovrebbe fare molto efficiente, utilizzando una mappa da filepaths a loro ID:

var idcount = 0; 
var treeJSON = []; 
var idmap = {}; 
function add(dirs) { 
    if (!dirs.length) return "#"; 
    var name = dirs.join("/"); 
    if (name in idmap) 
     return idmap[name]; 
    var dir = dirs.pop(); 
    var parent = add(dirs); 
    var id = "ajson" + ++idcount; 
    treeJSON.push({id: id, parent: parent, text: dir}); 
    return idmap[name] = id; 
} 

var files = e.target.files; // FileList 
for (var i=0; i<files.length; ++i) { 
    var name = files[i].webkitRelativePath; 
    add(name.split("/")); 
} 
return treeJSON; 

(updated jsfiddle demo)

Ecco come si potrebbe utilizzare per gli aggiornamenti dinamici:

// initalise JStree here 

var idcount = 0; 
var treeJSON = []; 
var idmap = {}; 
function add(dirs, isfolder) { 
    if (!dirs.length) return "#"; 
    var name = dirs.join("/"); 
    if (name in idmap) { 
     if (isfolder && idmap[name].icon) 
      delete idmap[name].icon; 
     return idmap[name]; 
    } 
    var dir = dirs.pop(); 
    var parent = add(dirs, true); 
    var id = "ajson" + ++idcount; 
    var item = {id: id, parent: parent, text: dir} 

    if (parent == "#") 
     item.state = {opened:true, selected:true}; 
    if (!isfolder && dir.indexOf(".") > 0) 
     item.icon = fileICON; 

    treeJSON.push(item); 
    return idmap[name] = id; 
} 

input.onchange = function(e) { 
    var files = e.target.files; // FileList 
    for (var i=0; i<files.length; ++i) { 
     var name = files[i].webkitRelativePath; 
     add(name.split("/"), false); 
    } 
    // refresh JStree 
}; 
+0

I file diventano cartelle in [questo script] (http://jsfiddle.net/bsw5s60j/10/). I file Think dovrebbero essere ignorati. – skobaljic

+0

@skobaljic Penso che sia un errore minore. Ci sto guardando anche io. La tua funzione sembra essere carina. Accetterò se se non ci fosse altra buona soluzione è lì. Sto ancora esaminando il codice –

+0

Penso anche che sia un problema minore, ma [Bergi] (http://stackoverflow.com/users/1048572/bergi) dovrebbe risolverlo. – skobaljic