Introduzione
Caratteristiche base
Questo terzo tutorial (suddiviso in tre parti) spiegherà nel dettaglio come è stato realizzato Xfile, un'applicazione sviluppata in AJAX e PHP che permette di simulare all'interno di un browser un filemanager simile all'ormai famosissimo Risorse del Computer di Microsoft, permettendo all'utente di navigare tra le cartelle remote, aprire file e eseguire funzioni di utilità generale (creare, rinominare e eliminare file e cartelle).
L'applicazione è sviluppata, rispetto alle precedenti situazioni analizzate (Xchat, Xmap), seguendo una logica distrubuita soprattutto per quanto riguarda l'aspetto server-side. Questo significa che sono presenti più componenti, ognuna per ogni caso d'uso dell'applicazione. Gli esempi sviluppati in precedenza invece prevedevano un'unica componente server che svolgeva tutte le funzioni, discriminandole a partire da un parametro inviatogli dal client.
Ho scelto di adottare questa nuova "tecnica" soprattutto perché in questa applicazione i casi d'uso sono maggiori in quantità rispetto ai precedenti progetti.
Una demo dell'applicazione è disponibile su questa pagina del mio sito. Dalla pagina di presentazione di Xfile, invece, è possibile scaricare il pacchetto zip che contiene tutti i file necessari all'implementazione e il cui codice andremo ad analizzare nel corso del tutorial.
I casi d'uso dell'applicazione
L'insieme dei casi d'uso può essere riassunto in questo piccolo schema:
1. refresh della pagina (dovuto sia al cambiamento della cartella corrente sia al refresh della pagina corrente dopo che si verifica un'azione che influenza il filesystem)
2. creazione di una nuova cartella
3. eliminazione di una cartella esistente
4. eliminazione di un file esistente
5. rinominazione di un file o di una cartella esistente
Il progetto XFile è però stato sviluppato in un ottica che prevede una facile aggiunta di funzionalità, prevedendo alcuni elementi astratti che facilitano appunto l'inserimento di nuovi "moduli" nell'applicazione.
Questi casi d'uso verranno logicamente ripresi in futuro descrivendoli in maniera più precisa e "pratica".
Le librerie utilizzate
Oltre alle "classiche" librerie che ormai ci accompagnano in questi tutorial (che ricordo sono state analizzate nei precedenti articoli):
- JSON (libreria server-side per l'encoding di variabili semplici e complesse in entità JSON facilmente integrabili nel motore JavaScript)
- net.ContentLoader (libreria client-side che facilita notevolmente la gestione della connessione con il server tramite l'oggetto XmlHttpRequest)
In questo nuovo progetto ho utilizzato una nuova libreria server-side sviluppata da me, FileManager.class, che facilita l'accesso al filesystem del server
NiftyCorner, una libreria JavaScript open source fortemente grafica che permette di rendere più morbidi gli angoli degli elementi della pagina.
Ad entrambe dedicherò il dovuto spazio successivamente.
La divisione dei compiti
L'XFile presenta notevoli differenze tra compiti assegnati alla parte client e alla parte server. A quest'ultima infatti sono delegati solamente compiti funzionali di lettura e modifica del filesystem, mentre alla componente client sono assegnati compiti di interfaccia con l'utente che, come vedremo, sono notevolmente più complessi per un'applicazione di questo tipo.
Proprio per questo motivo preferisco partire con un'analisi dei componenti server-side.
Le componenti server-side
La libreria FileManager.class
Come detto in precedenza questa libreria (sviluppata in logica object-oriented) permette di accedere in maniera totalmente trasparente al filesystem del server.
Ecco un breve schema dell'API della classe:
/* costruttore */
public FileManager(String $path)
/* ritorna un array contenente i nomi delle cartelle presenti all’interno del percorso definito */
public Array getDir(boolean $path)
/* ritorna un array contenente I nomi dei file presenti all’interno del percorso definito */
public Array getFile(Array $extensions, Boolean $path)
L'utilizzo della libreria è quasi banale: una volta costruito l'oggetto è sufficiente invocare uno dei due metodi getDir
o getFile
.
Il primo metodo presenta un parametro $path
(di default settato a true
) il quale permette di ottenere i nomi delle cartelle precedute o meno dal path iniziale.
Il secondo metodo presenta inoltre un parametro $extensions
che permette di filtrare i file, ottenendo solo quelli con determinate estensioni (di default il metodo ritornerà tutti i file).
Nell'implementazione di XFile non useremo particolari parametri utilizzando quindi i metodi con i loro valori di default (per completezza ho comunque preferito descrivere tutte le funzionalità possibili).
Caso d'uso 1: visualizzazione del contenuto di una cartella
Il primo caso d'uso analizzato è anche quello più complesso: a partire dal percorso di una cartella, il componente server ritornerà un oggetto contenente l'elenco delle cartelle e l'elenco dei file presenti all'interno del percorso passato come parametro.
Il componente (chiamato server.php
) legge il parametro passato dal client, costruisce un oggetto inline response associando agli attributi dir
e file
i risultati dei metodi chiamati sull'oggetto FileManager
e encoda l'oggetto in JSON grazie alla liberia descritta in precedenza:
class response {
var $path;
var $dir;
var $file;
function response($path) {
$this->path = $path;
$fm = new filemanager($path);
$this->dir = $fm->getDir();
$this->file = $fm->getFile();
}
}
include("ajax/filemanager.lib.php");
include("ajax/json.php");
$_POST['path'] = $_POST['path'];
$response = new response($_POST['path']);
$json = new json;
$encoded = $json->encode($response);
echo $encoded;
Caso d'uso 2: creazione di una nuova cartella
Questo secondo caso d'uso, insieme ai successivi presenta una struttura quasi banale, in quanto esegue funzioni PHP impostando come parametri quelli ricevuti dal client.
Questo componente è inserito nel file createFolder.php
.
$folder = $_POST['folder'];
mkdir("../$folder");
È facile notare che la funzione mkdir
viene invocata con "../" antecendete al parametro: questo perché i componenti server sono posizionati in una sotto cartella del progetto. Questo aspetto è presente in tutti i casi d'uso successivi, mentre non è necessario per il primo caso d'uso in quanto il file server.php si trova nella root del progetto per motivi di semplicità.
Caso d'uso 3: eliminazione di una cartella esistente
Questo componente è inserito nel file removeFolder.php
.
$folder = $_POST['folder'];
rmdir("../$folder");
Caso d'uso 4: eliminazione di un file esistente
Questo componente è inserito nel file removeFile.php
.
$file = $_POST['file'];
unlink("../$file");
Caso d'uso 5: rinominazione di un file o di una cartella esistenti
Rispetto ai casi d'uso precedente, questo non è stato ulteriormente scomposto in due componenti (uno per le cartelle e uno per i file) per il fatto che la funzione PHP invocata è la stessa sia se il parametro passato è un file sia se è una cartella.
Questo componente è inserito nel file rename.php
.
$oldname = $_POST['old'];
$newname = $_POST['new'];
rename("../$oldname", "../$newname");
Tabella riassuntiva dei casi d'uso
Il componente client-side
L'interfaccia grafica
L'HTML dell'applicazione è relativamente semplice:
<div id="window">
<div id="titlebar">XFile 2.0</div>
<div id="linkbar">
<ul>
<li id="backlink"></li>
<li id="aheadlink"></li>
<li id="uplink"></li>
</ul>
</div>
<div id="content">
<ul id="listfile"></ul>
</div>
<div id="statusbar"></div>
</div>
Al momento della creazione della pagina i contenuti sono praticamente nulli, perché vengono visualizzati grazie ad una funzione che vedremo successivamente invocata all'evento onload della pagina.
L'aspetto grafico viene completamente gestito dal foglio di stile, seguendo perfettamente il modello che prevede la suddivisione tra grafica e contenuti di una pagina web.
La gestione delle icone
Un discorso a parte deve essere fatto per la gestione delle icone dei file. Attualmente l'applicazione presenta 11 icone per estensioni, un'icona per le cartelle e un'icona per i tipi di file sconosciuti.
Ciascun elemento della lista presenta una classe uguale all'estensione del file e grazie ad un foglio di stile generato dinamicamente con PHP vengono create tutte le classi necessarie per la visualizzazione delle icone.
Ecco il file php che genera il foglio di stile:
div#content ul li {
background: url(file.bmp) center top no-repeat;
}
<?php
if ($handle = opendir('.')) {
while (false !== ($file = readdir($handle))) if($file!="." && $file!=".." && $file !="style.php") {
$ext = substr($file, 0,-4);
?>
div#content ul li.<?=$ext?> {
background: url(<?=$file?>) center top no-repeat;
}
<?php
}
closedir($handle);
}
?>
Con questo script vengono generati diversi stili, ognuno per ogni file presente nella cartella extensions. Nel momento in cui creeremo gli elementi della lista basterà associare ad essi una classe uguale all'estensione del file. Se non esiste nessuna classe associata all'estensione, l'elemento verrà visualizzato tramite un icona (file.bmp) che rappresenta un tipo sconosciuto.
Le funzioni di utilità
Prima di intrudurre le diverse funzioni specifiche per ogni caso d'uso voglio introdurre funzioni di utilità generale che verrano utilizzate a loro volta da altre funzioni che vedremo successivamente.
function getExtension(path) {
return path.substring(path.lastIndexOf(".")+1);
}
La funzione getExtension
ritorna l'estensione del file passato come parametro.
function formatId(id) {
id = id.replace("","");
return id;
}
La funzione parseId
toglie i backslash presenti nel parametro passato (poi capiremo perché si chiama proprio id).
function formatPath(path) {
var path =
path.substring(path.lastIndexOf("/")+1);
if(path.length > 12)
path = path.substring(0,9)+"...";
return path;
}
Ritorna il nome del file formattato, senza estensione e limitato a 12 caratteri se troppo lungo.
Oltre a queste funzioni esiste una variabile globale (listfile
) che presenta un riferimento all'elemento UL
che contiene gli elementi file.
Alcune variabili globali
Prima di addentrarci nei diversi casi d'uso è necessario introdurre alcune variabili globali utilizzate da più funzioni:
var homePage = "folder";
var listfile = document.getElementById("listfile");
La prima può essere considerata come una costante che rappresenta la cartella root dell'intera applicazione (l'utente potrà quindi navigare solo in questa cartella e nelle sue sotto-cartelle) mentre la seconda è semplicemente un riferimento all'oggetto che conterrà tutti i file e le directory.
Caso d'uso 1: navigazione tra le cartelle
Il caso d'uso più complesso di tutta l'applicazione è quello che permette di navigare attraverso il filesystem remoto. La complessità di questo caso d'uso deriva soprattutto dalla presenza di particolari funzioni che permettono di memorizzare lo stato dell'applicazione permettendo all'utente una navigazione veloce grazie al menu degli strumenti:
- go back (permette di tornare alla cartella precedente)
- go ahead (permette di annullare il go back)
- go up (permette di tornare alla cartella superiore)
Quindi prima di introdurre il caso d'uso vero e proprio è necessario introdurre due variabili globali che lo influenzano notevolmente.
Esistono infatti due array che vengono via via riempiti o svuotati in base alle richieste effettuate dall'utente seguendo una logica LIFO (last in – first out).
var previousPages = new Array();
var nextPages = new Array();
Quindi, per esempio, quando un utente richiederà il contenuto di una determinata cartella, prima di effettuare la richiesta, verrà aggiunto un nuovo riferimento nell'array previousPages
in modo da sapere dove si trovava l'utente prima di effettuare questa richiesta. Non è necessario avere un array per gestire il "go up". Ora è possibile passare al caso d'uso vero e proprio.
Tutto parte dalla funzione request che invia una richiesta di refresh al server (server.php
) passandogli come parametro il percorso della cartella da "aprire".
Questa funzione può essere definita come "private" in quanto non viene invocata direttamente da un evento generabile dall'utente, ma viene invocata indirettamente passando per altre funzioni che si occupano di eseguire altri compiti prima di inviare la richiesta. Entriamo nel vivo delle funzioni:
function request(path) {
var param = "path="+path;
new net.ContentLoader(
"server.php",
updateFileCallback,
param);
}
function updateFile(path) {
previousPages.push(getCurrentPage());
clearAheadPages()
request(path);
}
function goBack() {
nextPages.push(getCurrentPage());
var path = previousPages.pop();
request(path);
}
function goAhead() {
previousPages.push(getCurrentPage());
var path = nextPages.pop();
request(path);
}
function goUp() {
var current = getCurrentPage();
current = current.substring(0,current.lastIndexOf("/"));
previousPages.push(getCurrentPage());
request(current);
}
Per comprendere meglio l'invocazione della funzione request analizziamo questo schema che rappresenta gli eventi che fanno generare l'invocazione del metodo request
:
Una volta invocata la funzione e inviata al server una richiesta di aggiornamento della pagina, la palla passa in mano alla funzione updateFileCallBack
:
function updateFileCallback(txt) {
var response = eval('(' + txt + ')');
clearContent();
updateStatus(response.path);
var dirs = response.dir;
var files = response.file;
newDirectories(dirs);
newFiles(files);
setBackButton();
setAheadButton();
setUpButton();
}
Questa costruisce l'oggetto tramite eval e chiama alcune funzioni specializzate nel gestire determinata azioni.
La funzione clearContent
si occupa di svuotare il contenuto corrente della pagina:
function clearContent() {
var elt = document.getElementById("listfile");
var childs = elt.childNodes;
while (ch = elt.firstChild) elt.removeChild(ch);
}
La funzione updateStatus
si occupa di aggiornare la barra di stato della finestra con il percorso attuale passatogli come parametro:
function updateStatus(mex) {
document.getElementById("statusbar")
.innerHTML = mex;
}
Le funzioni newDirectories
e newFiles
si occupano di aggiungere alla pagina l'insieme delle directory e dei file presenti nella cartella corrente e di associargli l'evento onclick alla funzione updateFile
(come specificato prima nello schema degli eventi che invocano request).
function newDirectories(dirs) {
for(i=0;i<dirs.length;i++) {
var dd = dirs[i];
var li = document.createElement("LI");
li.className = "folder";
li.id = formatId(dd);
li.onclick =
new Function("updateFile('"+dd+"')");
var span = document.createElement("SPAN");
span.innerHTML = formatPath(dd);
li.appendChild(span);
li.oncontextmenu = function(e) {
showContext(e, this.className);
}
listfile.appendChild(li);
}
}
function newFiles(files) {
for(i=0;i<files.length;i++) {
var ff = files[i];
var li = document.createElement("LI");
var ext = getExtension(ff);
li.className = ext;
li.id = formatId(ff);
linka = new
Function("document.location='"+ff+"'");
li.onclick = linka;
var span = document.createElement("SPAN");
span.innerHTML = formatPath(ff);
li.appendChild(span);
li.oncontextmenu = function(e) {
showContext(e, this.className);
}
listfile.appendChild(li);
}
}
Queste due funzioni molto simili si occupa di creare tutti gli elementi HTML necessari alla visualizzazione del contenuto della cartella corrente. L'unica differenza riguarda la funzione associata all'evento onclick: nel caso di una cartella, verrà effettuata una richiesta al server (passando però come già ripetuto per updateFile
e non direttamente per request) con il compito di aggiornare il contenuto, mentre nel caso di un file l'evento farà scattare la sua apertura o il download (questo dipende dalle impostazioni di ciascun browser).
In entrambe le funzioni che vengono associate due particolari funzioni all'evento oncontextmenu: per il momento è meglio non approfondire l'argomento perché verrà analizzato nello specifico successivamente.
Una volta aggiornato il contenuto della pagina, non ci resta che modificare il comportamento della barra degli strumenti, modificando eventualmente le funzioni callback associate all'evento onclick.
function setBackButton() {
var d = document.getElementById("backlink");
if(previousPages.length > 0) {
d.className = "backLinkOn";
d.onclick = goBack;
} else d.className = "backLinkOff";
}
function setAheadButton() {
var d = document.getElementById("aheadlink");
if(nextPages.length > 0) {
d.className = "aheadLinkOn";
d.onclick = goAhead;
} else d.className = "aheadLinkOff";
}
function setUpButton() {
var current = getCurrentPage();
var d = document.getElementById("uplink");
if(current == homePage) {
d.className = "upLinkOff";
} else {
d.className = "upLinkOn";
d.onclick = goUp;
}
}
Le funzioni setBackButton
e setAheadButton
sono simili: entrambe controllano che ci sia qualche riferimento contenuto nei rispettivi array e in caso positivo associano le funzioni goBack
e goAhead
(viste in precedenza) all'evento onclick e adattano lo stile "on". In caso contrario non associano nessuna funzione all'onclick e adattano lo stile "off".
Un discorso a parte deve essere fatto per la funzione setUpButton
. Essa infatti non presenta nessun'array a supporto. Il controllo viene quindi effettuato grazie alla variabile homepage: se l'utente si trova nella root, il pulsante assume solamente lo stile "off", viceversa assume lo stile "on" e la funzione goUp
come callback dell'evento onclick.
Tutte le funzioni utilizzano per ottenere il path corrente la funzione getCurrentPage
che non fa altro che leggere dalla status bar (che è stata valorizzata con la funzione updateStatus):
function getCurrentPage() {
return document.getElementById("statusbar")
.innerHTML;
}
L'evento onload della pagina
La prima richiesta al server, come detto in precedenza avviene durante l'evento onload della pagina. Analizziamo meglio la funzione:
window.onload = function() {
if(!NiftyCheck()) return;
Rounded("div#window","#FFFFFF","blue","small");
listfile = document.getElementById("listfile");
request(homePage);
document.getElementById("window").oncontextmenu =
showContext;
}
Le prime due righe fanno riferimento alla libreria NiftyCorner, la terza riga associa alla variabile globale listfile un riferimento all'elemento della pagina mentre la quarta riga esegue esattamente la richiesta descritta in precedenza, invocando in modo diretto la funzione request
(che come detto prima, dopo questa volta, non verrà mai più invocata in maniera diretta).
L'ultima riga verrà descritta nel paragrafo successivo.
Il context menu
I successivi 4 casi d'uso vengono avviati grazie ad un context menu attivabile, come in tutte le applicazioni desktop, tramite la pressione del tasto destro del mouse sopra l'elemento target dell'azione che si vuole compiere.
Il context menu non è nient'altro che un elemento DIV che viene visualizzato solo nel momento in cui l'utente clicca col tasto destro su un elemento della pagina.
Per comprendere il funzionamento di questo menu partiamo dall'evento oncontextmenu visto (e rimandato) in precedenza nelle funzioni newFiles
e newDirectories
.
li.oncontextmenu = function(e) {
showContext(e, this.className);
}
Premendo col tasto destro su una cartella o su un file viene invocata la funzione showContext
passandogli come parametro l'oggetto evento (utile solo nei browser "event-oriented" – Firefox in particolare) e il className
dell'elemento target per discriminare sulla tipologia di elemento (cartella o file) e sull'eventuale estensione (permettendo quindi la scelta di diverse operazioni in base al tipo di file).
La funzione showContext
viene utilizzata come callback anche dell'evento oncontextmenu
dell'elemento window (ricordo è il div che contiene l'intera applicazione – da non confondere con l'oggetto javascript). Questa assegnazione viene effettuata all'onload della pagina.
L'intera gestione del contextMenu necessita di due variabili globali: la variabile contextSelected
che rappresenta l'elemento target sul quale è stato invocato il contextMenu (deve essere globale perchè il riferimento serve in funzioni differenti) e la variabile contextFile
che non è nient'altro che una variabile temporale che evita l'apertura di due contextMenu nel caso si prema su un'elemento del filesystem (senza questo controllo si aprirebbe il contextMenu specifico per l'elemento E il contextMenu relativo all'intera finestra).
Entriamo ora nello specifico della funzione showContext
:
function showContext(e, type) {
if(!e) {
var e = window.event;
var elem = e.srcElement;
} else var elem = e.currentTarget;
// il target è un file o cartella
if(type) {
destroyContext();
contextFile = false;
contextSelected = elem;
createContextFile(e, type);
// non esiste il target
} else if(contextFile) {
destroyContext();
createContext(e);
// evito il doppio contextMenu
} else contextFile = true;
document.getElementById("window").onclick =
destroyContext;
return false;
}
Le prime 4 righe della funzione servono solamente per armonizzare le variabili in base al browser utilizzato. Una volta ottenute le variabili che ci servono, possiamo discriminare sul fatto che l'elemento selezionato sia o meno un oggetto specifico o sia la finestra.
Nel caso esista la variabile type viene distrutto un eventuale menu già presente, viene assegnato false alla variabile contextFile
(bloccando il doppio menu) e l'elemento target alla variabile contextSelected
e viene finalmente invocata la funzione createContextFile
passandogli come parametro l'evento e e il tipo di elemento.
Nel caso non esista la variabile type e la variabile globale contextFile
sia positiva (quindi se effettivamente è stato cliccato sulla finestra) viene giustamente distrutto un eventuale menu già esistente e viene invocata la funzione createContext
passandogli come argomento l'evento e
.
Nel caso invece che la variabile contextFile
sia false
, il contextMenu non viene visualizzato.
Dopo la costruzione del contextMenu viene modificato il callback dell'evento onclick in modo da far distruggere il menu nel caso l'utente prema in un qualsiasi punto della finestra.
Per ultimo viene ritornato false
, evitando quindi di visualizzare il contextMenu standard del browser.
Scendiamo in profondità analizzando le funzioni nominate in precedenza:
function destroyContext() {
if(document.getElementById("contextMenu")) document.body.removeChild(document.
getElementById("contextMenu"));
}
La funzione destroyContext
è banale e non necessita nessuna spiegazione.
function createContext(e) {
var arr = new Array();
arr[0] = new Array("Create Folder", createFolder);
createContextPanel(e, arr);
}
function createContextFile(e, type) {
var arr = new Array();
if(type == "folder") {
arr.push(new Array("Remove Folder"
removeFolder));
arr.push(new Array("Rename Folder",
renameFolder));
} else {
arr.push(new Array("Remove File", removeFile));
arr.push(new Array("Rename File", renameFile));
}
createContextPanel(e, arr);
}
function createContextPanel(e, lis) {
var div = document.createElement("DIV");
div.oncontextmenu = function() { return false }
div.className = "contextMenu";
div.id = "contextMenu";
div.style.top = e.clientY+"px";
div.style.left = e.clientX+"px";
var ul = document.createElement("UL");
for(i=0; i<lis.length;i++) {
var li = document.createElement("LI");
var a = document.createElement("A");
a.innerHTML = lis[i][0];
a.href = "#"
a.onclick = lis[i][1];
li.appendChild(a);
ul.appendChild(li);
}
div.appendChild(ul);
document.body.appendChild(div);
}
a.onclick = lis[i][1];
li.appendChild(a);
ul.appendChild(li);
}
div.appendChild(ul);
document.body.appendChild(div);
}
Le funzioni createContext
e createContextFile
hanno l'unico compito di creare un array contenente le funzionalità che il contextMenu dovrebbe avere e passarlo alla funzione createContextPanel
che si occuperà di creare il pannello con le funzioni passategli come parametro. L'array che createContextPanel
si aspetta di ricevere è un array bidimensionale contenente per ciascuna funzionalità la label da mostrare e la funzione da chiamare in caso l'utente la selezioni.
CreateContext
assegna all'array solo un unica funzione (createFolder
) mentre createContextFile
discrimina sul fatto che il typo di target sia o meno una cartella e assegna all'array due funzioni (renameFolder/File
e removeFolder/File
).
CreateContextPanel
si occupa principalmente di creare un DIV contenente la lista delle funzioni all'interno dell'array e di posizionare assolutamente il DIV (opportunamente "colorato" secondo gli standard windows) nel punto in cui è stato premuto il tasto destro del mouse (e.clientX
e e.clientY
).
Prima ho parlato della possibilità di aggiungere ulteriori funzionalità all'applicazione. Sono proprio queste le funzioni che permettono di farlo. Basta quindi creare una nuova funzione (per esempio createTxtFile
) e associarla ad un determinato comando (per esempio crea file di testo) all'interno dell'array da passare alla funzione createContextPanel
.
I successivi paragrafi analizzaranno le funzioni presenti nell'array utilizzato per costruire il menu contestuale che rappresentano i 4 casi d'uso rimanenti.
Caso d'uso 2: creazione di una nuova cartella
La funzione si rende disponibile nel caso l'utente clicchi nella finestra senza selezionare un elemento particolare.
function createFolder() {
destroyContext();
var name = trim(
input("Inserisci il nome della cartella",""));
if(name) {
var param = "folder="+getCurrentPage()+"/"+name;
new net.ContentLoader(
"ajax/createFolder.php",
refreshPage,
param);
}
}
Caso d'uso 3: eliminazione di una cartella esistente
La funzione si rende disponibile nel caso l'utente clicchi su un elemento folder.
function removeFolder() {
destroyContext();
var yourstate = window.confirm("Sei sicuro??")
if (yourstate) {
var param = "folder="+contextSelected.id;
new net.ContentLoader(
"ajax/removeFolder.php",
refreshPage,
param);
}
}
Caso d'uso 4: eliminazione di un file esistente
La funzione si rende disponibile nel caso l'utente clicchi su un elemento file indipendentemente dalla sua estensione.
function removeFile() {
destroyContext();
var yourstate = window.confirm("Sei sicuro??")
if (yourstate) {
var param = "file="+contextSelected.id;
new net.ContentLoader(
"ajax/removeFile.php",
refreshPage,
param);
}
}
Caso d'uso 5: rinominazione di un file o di una cartella esistenti
Le funzioni si rendono disponibili se l'utente clicca su un elemento della pagina.
function renameFolder() {
destroyContext();
var folderName = contextSelected.id.substring(
contextSelected.id.lastIndexOf("/")+1);
var folderPath = contextSelected.id.substring(
0, contextSelected.id.lastIndexOf("/")+1);
var name = trim(
input("Inserisci il nuovo nome"
,folderName)
.replace(/[\:?*/"<>|]+/g, "_"));
if(name) {
var o = folderPath+folderName;
var n = folderPath+name;
var param = "old="+o+"&new="+n;
new net.ContentLoader(
"ajax/rename.php",
refreshPage,
param);
}
}
function renameFile() {
destroyContext();
var fileName = contextSelected.id.substring(
contextSelected.id.lastIndexOf("/")+1);
var filePath = contextSelected.id.substring(
0, contextSelected.id.lastIndexOf("/")+1);
name = trim(
input("Inserisci il nuovo nome del file"
,fileName)
.replace(/[\:?*/"<>|]+/g, "_"));
if(name) {
var o = filePath+fileName;
var n = filePath+name;
var param = "old="+o+"&new="+n;
new net.ContentLoader(
"ajax/rename.php",
refreshPage,
param);
}
}
Le ultime funzioni di utilità
Le ultime funzioni analizzate presentano al loro interno alcune funzioni istanziate solo per comodità. Per completezza ecco il loro listato:
function input(txt, d) {
var res = window.prompt(txt,d,"");
return res;
}
function refreshPage(){
request(getCurrentPage());
}