Skip to content

March 13, 2012

2

Mobile File Explorer with PhoneGap/Cordova and jQuery Mobile Part 2

by nady

In the first part of this tutorial we’ve learned how to browse the file system. Now we’ll learn how to deal with files and folders actions, like open, copy, move and delete.

Final result:





Download Sources

First of all, let’s finish the navigation within the file system, when we click the back button to go up one level and when we click the home button to go back to root.

Open js/script.js and invoke into onDeviceReady() the clickItemAction() function and create it:

[js]
/* click actions */
function clickItemAction(){
var backBtn = $(‘#backBtn’);
var homeBtn = $(‘#homeBtn’);

backBtn.click(function(){ // go one level up
if( parentDir != null ) listDir(parentDir);
});

homeBtn.click(function(){ // go to root
if( root != null ) listDir(root);
});
}
[/js]

Add more global variables that we need to determine what is the actual item and his type that we’ve clicked on, what is the item and his type that can be copied or moved.

[js]
var activeItem = null; // The clicked item
var activeItemType = null; // d-directory, f-file
var clipboardItem = null; // file or directory for copy or move
var clipboardAction = null; // c-copy, m-move
[/js]

When an folder or an file is clicked an dialog box with actions to choose from should open. Go to index.html and add into #home content under the grid: [html]<a id="menu" href="#menuOptions" data-rel="dialog">file details</a>[/html]
data-rel="dialog" asures that this will be opened as a dialog box.
Add the page #menuOptions that contains the choosing options.

[html]
<div id="menuOptions" data-role="page">
<div data-role="header">
<h1>Choose</h1>
</div>
<div data-role="content">
<input type="button" id="openBtn" data-theme="e" value="Open">
<input type="button" id="copyBtn" value="Copy">
<input type="button" id="moveBtn" value="Move">
<input type="button" id="pasteBtn" value="Paste" disabled>
<input type="button" id="deleteBtn" value="Delete">
</div>
</div>
[/html]

The paste button is enabled only after there is an item set into the clipboardItem variable.
Also add another dialog that we’ll use later on, to display some file details. Under #menu link add: [html]<a id="get_file_details" href="#fileDetails" data-rel="dialog">file details</a>[/html]
Create another page that will be opened in an dialog box:

[html]
<div id="fileDetails" data-role="page">
<div data-role="header">
<h1>File</h1>
</div>
<div id="file_details" data-role="content"></div>
</div>
[/html]

Go to css/style.css and hide those two links because we’ll trigger them from javascript:

[css]
#menu, #get_file_details{
display: none;
}
[/css]

Return to js/script.js to clickItemAction() function and add click action for folders and files.

[js]
var folders = $(‘.folder’);
var files = $(‘.file’);

folders.live(‘click’, function(){
var name = $(this).text();
getActiveItem(name, ‘d’);
$(‘#menu’).trigger(‘click’); // menu dialog box
});

files.live(‘click’, function(){
var name = $(this).text();
getActiveItem(name, ‘f’);
$(‘#menu’).trigger(‘click’); // menu dialog box
// paste button always disabled for files
pasteBtn.button(‘disable’);
pasteBtn.button(‘refresh’);
});
[/js]

Create the getActiveItem() function that gets the item we’ve clicked on by using getDirectory() method from the DirectoryEntry object for type ‘d’ and the getFile() method from the FileEntry object for type ‘f’.

[js]
/* get active item */
function getActiveItem(name, type){
if( type == ‘d’ && currentDir != null ){
currentDir.getDirectory(name, {create:false},
function(dir){ // success find directory
activeItem = dir;
activeItemType = type;
},
function(error){ // error find directory
console.log(‘Unable to find directory: ‘+error.code);
}
);
} else if(type == ‘f’ && currentDir != null){
currentDir.getFile(name, {create:false},
function(file){ // success find file
activeItem = file;
activeItemType = type;
},
function(error){ // error find file
console.log(‘Unable to find file: ‘+error.code);
}
);
}
}
[/js]

To read a file create a function readFile() that from an FileEntry gets a File object by calling file() method. Using this File object add some details of the file to the #file_details dialog box, also by using a File Reader object, output the content of a file to the console log as a Data URL, you can also output the content as plain text using method readAsText(file).

[js]
/* read from file */
function readFile(fileEntry){
if( !fileEntry.isFile ) console.log(‘readFile incorrect type’);
$.mobile.showPageLoadingMsg(); // show loading message

fileEntry.file(function(file){
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("Read as data URL");
console.log(evt.target.result); // show data from file into console
};
reader.readAsDataURL(file);

$.mobile.hidePageLoadingMsg(); // hide loading message

// dialog with file details
$(‘#file_details’).html(‘<p><strong>Name:</strong> ‘+file.name+
‘</p><p><strong>Type:</strong> ‘+file.type+
‘</p><p><strong>Last Modified:</strong> ‘+new Date(file.lastModifiedDate)+
‘</p><p><strong>Size:</strong> ‘+file.size);
$(‘#get_file_details’).trigger(‘click’);
}, function(error){
console.log(evt.target.error.code);
});
}
[/js]

When you open a folder use the listDir() function and when you open a file use the readFile() function.

[js]
/* open item */
function openItem(type){
if( type == ‘d’ ){
listDir(activeItem);
} else if(type == ‘f’){
readFile(activeItem);
}
}
[/js]

Go back to clickItemAction() function and add vars for the menu actions:

[js]
/* menu buttons */
var menuDialog = $(‘#menuOptions’);
var openBtn = $(‘#openBtn’);
var copyBtn = $(‘#copyBtn’);
var moveBtn = $(‘#moveBtn’);
var pasteBtn = $(‘#pasteBtn’);
var deleteBtn = $(‘#deleteBtn’);
[/js]

Add click actions for openBtn, copyBtn and moveBtn:

[js]
openBtn.click(function(){
openItem(activeItemType);
menuDialog.dialog(‘close’);
});

copyBtn.click(function(){
getClipboardItem(‘c’);
menuDialog.dialog(‘close’);
pasteBtn.button(‘enable’);
pasteBtn.button(‘refresh’);
});

moveBtn.click(function(){
getClipboardItem(‘m’);
menuDialog.dialog(‘close’);
pasteBtn.button(‘enable’);
pasteBtn.button(‘refresh’);
});
[/js]

The getClipboardItem() function sets the global variables clipboardItem and clipboardAction

[js]
/* get clipboard item for copy or move */
function getClipboardItem(action){
if( activeItem != null) {
clipboardItem = activeItem;
clipboardAction = action;
}
}
[/js]

Back to the clickItemAction() function, when the paste button is clicked, according to the clipboardAction ( c-copy, m-move) the methods copyTo() or moveTo() from the DirectoryEntry and FileEntry are used.

[js]
pasteBtn.click(function(){
if( clipboardItem != null && clipboardAction != null ){
if(clipboardAction == ‘c’){ // copy item
console.log(‘copy: ‘+clipboardItem.name + ‘ to: ‘+activeItem.name);
clipboardItem.copyTo(activeItem,clipboardItem.name,
function(fileCopy){
console.log(‘copy success! ‘+fileCopy.name);
openBtn.trigger(‘click’);
}, function(error){
console.log(‘copy error: ‘+error.code);
}
);
} else if(clipboardAction == ‘m’){ // move item
console.log(‘move: ‘+clipboardItem.name + ‘ to: ‘+activeItem.name);
clipboardItem.moveTo(activeItem,clipboardItem.name,
function(fileCopy){
console.log(‘move success! ‘+fileCopy.name);
openBtn.trigger(‘click’);
}, function(error){
console.log(‘move error: ‘+error.code);
}
);
}
}
});
[/js]

For the delete button click use the removeRecursively() method from DirectoryEntry for directories that will delete a directory with all his content, or remove() method from FileEntry for files.

[js]
deleteBtn.click(function(){
if( activeItem != null && activeItemType != null){
if(activeItemType==’d’){
activeItem.removeRecursively(function(){
console.log(‘removed recursively with success’);
menuDialog.dialog(‘close’);
listDir(currentDir);
}, function(error){
console.log(‘remove recursively error: ‘+error.code);
});
} else if(activeItemType==’f’){
activeItem.remove(function(){
console.log(‘removed recursively with success’);
menuDialog.dialog(‘close’);
listDir(currentDir);
}, function(error){
console.log(‘remove recursively error: ‘+error.code);
});
}
}
});
[/js]

This is it! Feel free to discuss this topic in the comment area below.

Read more from Android, Mobile
2 Comments Post a comment
  1. venkatesh
    Jun 30 2012

    When I download source code to test, that time it asks authentication. What is the username and password to download.

    Reply
    • noise
      Jun 30 2012

      Now it should work. Please test if you can download the archive (without any authentication).

      Reply

Leave a Reply

required
required

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments