Mobile Web Wearable Web

Task: File Manager

This task, based on the FileManager sample delivered with the Tizen SDK, demonstrates how you can use the Filesystem API (in mobile and wearable applications) to manage files in your application. For more information on the sample functionality and creating the sample with the full source code, see FileManager.

This task consists of the following parts:

This sample is a fully functional application for browsing the device storage. The user can create, copy, move, and remove folders and files.

Defining the Application Layout

The FileManager sample application layout uses the template manager based on the MVC (Model-View-Controller) architecture, and consists of 1 screen that displays the device storage folder and file structure.

Additionally, the sample application layout consists of 2 UI elements: the clipboard footer controls enable you to delete, move, or copy selected folders and files, and the More pop-up window enables you to create a new folder and to paste content to a folder.

The following figure shows the main screens of the application.

Figure: FileManager screen

FileManager screen

Using the Template Manager

The template manager enables the HTML output generation to be divided into 3 parts.

  1. app.ui.templateManager.js Source File
    1. The template manager loads the template files into the cache.

      loadToCache: function TemplateManager_loadToCache(tplNames, onSuccess)
      {
         var self = this,
         cachedTemplates = 0,
         tplName,
         tplPath;
      
         if ($.isArray(tplNames))
         {
            $.each(tplNames, function(index, fileName)
            {
               if (self.cache[fileName] === undefined)
               {
                  tplName = [fileName, app.config.get('templateExtension')].join('');
                  tplPath = [app.config.get('templateDir'), tplName].join('/');
                  $.ajax(
                  {
                     url: tplPath,
                     cache: true,
                     dataType: 'html',
                     async: true,
                     success: function(data)
                     {
                        cachedTemplates += 1;
                        self.cache[fileName] = data;
                        if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function')
                        {
                           onSuccess();
                        }
                     },
      
                     /* Error handling */
                  });
               }
               else
               {
                  cachedTemplates += 1;
                  if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function')
                  {
                     onSuccess();
                  }
               }
            });
         }
      }
      
    2. Next, the template manager returns the template HTML content from the cache.

      get: function TemplateManager_get(tplName, tplParams)
      {
         if (this.cache[tplName] !== undefined)
         {
            return this.getCompleted(this.cache[tplName], tplParams);
         }
      
         return '';
      }
      
    3. The getCompleted() method returns the completed template using the specified parameters, prepared by the passThruModifiers() method.

      getCompleted: function TemplateManager_getCompleted(tplHtml, tplParams)
      {
         var tplParam, replaceRegExp;
      
         for (tplParam in tplParams)
         {
            if (tplParams.hasOwnProperty(tplParam))
            {
      
               tplHtml = this.passThruModifiers(tplHtml, tplParam, tplParams[tplParam]);
            }
         }
      
         return tplHtml;
      }
      
      passThruModifiers: function(tplHtml, tplParam, content)
      {
         var regModOn = new RegExp('%' + tplParam + '\\|([a-zA-Z]){1,}%', 'g'),
         regModOff = new RegExp(['%', tplParam, '%'].join(''), 'g'),
         regModGet = new RegExp('%' + tplParam + '\\|(.+?)%'),
         specRegExp = new RegExp('\\$', 'g'), modifier;
      
         if (content && (typeof content === 'string'))
         {
            content = content.replace(specRegExp, '$$$$');
         }
      
         if (regModOn.test(tplHtml))
         {
            modifier = tplHtml.match(regModGet)[1];
            try
            {
               content = this.modifiers[modifier](content);
            }
      
            tplHtml = tplHtml.replace(regModOn, content);
         } 
         else
         {
            tplHtml = tplHtml.replace(regModOff, content);
         }
      
         return tplHtml;
      }

Defining the Main Screen

The main screen elements initialization and display functionality is implemented in the app.ui.js file.

  1. main.tpl Source File

    The main screen of the application displays the device storage folder and file structure. The header section of the screen is defined within a <div> element whose data-role attribute is set to header. The header section determines the title of the screen.

    If the user navigates to another child directory, the header section displays navigation buttons - Up and Home - to move 1 directory up in the file system and to move to the root directory, respectively. In a child directory, the breadcrumb navigation from the root directory to the current directory is displayed as well.

    <!--Header section-->
    <div data-role="header" data-position="fixed">
       <h1 id="mainTitle"></h1>
    
       <!--Other application code-->
    
       <a id="homeBtn">Home</a>
       <a id="levelUpBtn">Up</a>
    
       <!--Other application code-->
    
       <div id="navbar"></div>
       <div class="selectAll" style="display: none"></div>
    
       <!--Other application code-->
    
    </div>
    
  2. folderRow.tpl Source File

    The folderRow.tpl template file defines the actual content of the main screen, which is initialized in the app.ui.js source file.

    <!--Content section-->
    <li class="node folder ui-li-1line-bigicon1" id="row%id%" label="%name%" uri="%uri|escapeEncies%"
        fullUri="%fullUri|escapeEncies%">
       <form class="my-ui-checkbox hidden"><input type="checkbox" /></form>
       <img src="images/folder.png" class="ui-li-bigicon" />
       <span class="ui-li-text-main nodename">%name|escape%</span>
    </li>
    
    
  1. main.tpl Source File

    The footer section of the screen is defined within a <div> element whose data-role attribute is set to footer. The footer section contains a tab bar with a button for enabling the clipboard functionality in the application.

    The clipboard consists of buttons for deleting, moving, and copying folders and files, and also canceling the clipboard operation. In the clipboard mode, check boxes appear next to the folders and files list in the current directory on the main screen.

    <div data-role="footer" data-position="fixed">
       <div class="ui-myToolBar">
          <div data-role="tabbar" class="standardTabbar">
             <ul>
                <li><a id="editActionBtn" href="#">Edit</a></li>
    
                <!--Other application code-->
    
             </ul>
          </div>
    
          <div data-role="tabbar" class="editTabbar" style="display: none">
             <ul>
                <li><a id="deleteActionBtn" href="#">Delete</a></li>
                <li><a id="moveActionBtn" href="#">Move</a></li>
                <li><a id="copyActionBtn" href="#">Copy</a></li>
                <li><a id="cancelActionBtn" href="#">Cancel</a></li>
             </ul>
          </div>
    
       <!--Other application code-->
    
       </div>
    </div>
    

  1. main.tpl Source File

    The pop-up window consists of a jQuery pop-up menu with options for creating a new folder at the current directory location or for pasting already copied content to the current directory location.

    <div data-role="footer" data-position="fixed">
       <div class="ui-myToolBar">
          <div data-role="tabbar" class="standardTabbar">
             <ul>
    
                <!--Other application code-->
    
                <li><a id="moreActionBtn" href="#morePopup" data-rel="popup">More</a></li>
    
                <!--Other application code-->
    
             </ul>
          </div>
          <div id="morePopup" data-role="popup">
             <!--Other application code-->
    
          </div>
       </div>
    </div>
    

Managing Clipboard

This section builds upon the elements described in Managing Files and Directories.

Initializing the Clipboard

The clipboard features definition functionality is implemented in the app.clipboard.js file.

  1. Retrieving Clipboard Content

    The get() method is defined to retrieve all the filesystem paths saved currently in the clipboard.

    get: function Clipboard_get()
    {
       return this.data;
    }
  2. Adding New Content to the Clipboard

    The add() method is defined to add filesystem paths to the clipboard.

    add: function Clipboard_add(paths)
    {
       var len = paths.length, i;
    
       /* Clear clipboard */
       this.clear();
       for (i = 0; i < len; i += 1)
       {
          if (this.has(paths[i]) === false)
          {
             this.data.push(paths[i]);
          }
       }
    
       return this.data.length;
    }
  3. Checking if a Path is Present in the Clipboard

    The has() method is defined to check whether the currently copied filesystem path is already present in the clipboard.

    has: function Clipboard_has(path)
    {
       return $.inArray(path, this.data) === -1 ? false : true;
    }
    
  4. Setting the Clipboard Mode

    The setMode() method is defined to set the clipboard in 3 available modes - copy, move, and inactive (default).

    setMode: function Clipboard_setMode(mode)
    {
       if ($.inArray(mode, [this.MOVE_MODE_ID, this.COPY_MODE_ID]) === false)
       {
          /* Error handling */
       }
       this.mode = mode;
    
       return true;
    }
  5. Clearing the Clipboard

    The clear() method is defined to clear all the clipboard content and reset it to the default mode.

    clear: function Clipboard_clear()
    {
       this.data = [];
       this.mode = this.INACTIVE_MODE;
    }

Performing Clipboard Operations

The clipboard operation functionality is implemented in the app.js file.

  1. Copying Content to the Clipboard

    The saveToClipboard() method is used to add filesystem paths to the clipboard and set the appropriate clipboard mode.

    saveToClipboard: function App_saveToClipboard(paths, mode)
    {
       var clipboardLength = this.clipboard.add(paths);
    
       if (clipboardLength > 0)
       {
          this.clipboard.setMode(mode);
          app.ui.alertPopup('Data saved in clipboard');
          this.ui.clearTabbars();
       }
       else
       {
          alert('Error occurred. Data has not been saved in clipboard');
       }
    
       this.ui.refreshPasteActionBtn(this.clipboard.isEmpty());
    }
  2. Pasting Content from the Clipboard
    1. The pasteClipboard() method is used to copy filesystem paths from the clipboard or to move filesystem paths to the current directory location based on the current clipboard mode.

      pasteClipboard: function App_pasteClipboard()
      {
         var clipboardData = this.clipboard.get();
      
         if (clipboardData.length === 0)
         {
            app.ui.alertPopup('Clipboard is empty');
      
            return false;
         }
      
         if (this.clipboard.getMode() === this.clipboard.COPY_MODE_ID)
         {
            this.model.copyNodes(this.currentDirHandle, clipboardData,
                                 this.currentPath, this.onPasteClipboardSuccess.bind(this));
         }
         else
         {
            this.model.moveNodes(this.currentDirHandle, clipboardData,
                                 this.currentPath, this.onPasteClipboardSuccess.bind(this));
         }
         this.ui.refreshPasteActionBtn(this.clipboard.isEmpty());
      
         return true;
      }
    2. The onPasteClipboardSuccess() event handler responds to the success event of pasting content from the clipboard by clearing the clipboard.

      onPasteClipboardSuccess: function App_onPasteClipboardSuccess()
      {
         this.clipboard.clear();
         this.refreshCurrentPage();
      }

Managing Device Storage

This section builds upon the elements described in Managing File Storages, Creating and Deleting Files and Directories, and Retrieving Files and File Details.

Initializing the Device Storage

  1. config.xml Source File

    The required privileges are declared in the config.xml file.

    <!--Configuration file content-->
    <widget ...>
       <!--Other configuration details-->
       <tizen:privilege name="http://tizen.org/privilege/content.read"/>
       <tizen:privilege name="http://tizen.org/privilege/content.write"/>
       <tizen:privilege name="http://tizen.org/privilege/application.launch"/> 
       <tizen:privilege name="http://tizen.org/privilege/filesystem.read"/> 
       <tizen:privilege name="http://tizen.org/privilege/filesystem.write"/>
       <!--Other configuration details--> 
    </widget>

Retrieving Storages

  1. app.model.js Source File

    The loadInternalStorages() method calls the getStorages() method to get the storages of a specific storage type.

    loadInternalStorages: function Model_loadInternalStorages(onSuccess)
    {
       var self = this;
    
       this.systemIO.getStorages('INTERNAL', function(storages)
       {
          self.storages = storages;
          if (typeof onSuccess === 'function')
          {
             onSuccess();
          }
       }, 'internal0');
    }
  2. app.systemIO.js Source File

    The listStorages() method of the FileSystemManager interface (in mobile and wearable applications) is used to retrieve all the available storages.

    getStorages: function SystemIO_getStorages(type, onSuccess, excluded)
    {
       try
       {
          tizen.filesystem.listStorages(function(storages)
          {
             var tmp = [],
             len = storages.length,
             i;
    
             if (type !== undefined)
             {
                for (i = 0; i < len; i += 1)
                {
                   if (storages[i].label !== excluded)
                   {
                      if (storages[i].type === 0 || storages[i].type === type)
                         tmp.push(storages[i]);
                   }
                }
             }
             else
             {
                tmp = storages;
             }
    
             if (typeof onSuccess === 'function')
                onSuccess(tmp);
          });
       }
    }

Managing Files and Directories

The directory creation functionality is implemented in the app.js file. The file creation, file deletion, and directory deletion functionality is implemented in the app.systemIO.js file.

  1. Creating a File

    The createFile() method of the File interface (in mobile and wearable applications) is used to create a new file in the current directory.

    createFile: function SystemIO_createFile(directoryHandle, fileName)
    {
       try
       {
          return directoryHandle.createFile(fileName);
       }
    }

    Similarly, the createDirectory() method is used to create a directory at the current storage location in the application.

  2. Deleting a File

    The deleteFile() method of the File interface is used to delete a file by specifying the filesystem path of the file.

    deleteFile: function SystemIO_deleteFile(dir, filePath, onDeleteSuccess, onDeleteError)
    {
       try
       {
          dir.deleteFile(filePath, onDeleteSuccess, onDeleteError);
       }
    }

    Similarly, the deleteDirectory() method is used to delete a selected directory. You can specify if the deletion is to be performed recursively for the sub-directories as well.

Retrieving File Details

The file and file list retrieval functionality is implemented in the app.systemIO.js file. The file URI retrieval functionality is implemented in the app.ui.js file.

  1. Retrieving a File

    The resolve() method of the FileSystemManager interface is used to retrieve a file handle by specifying the location of the file.

    openDir: function SystemIO_openDir(directoryPath, onSuccess, onError, openMode)
    {
       openMode = openMode || 'rw';
       onSuccess = onSuccess || function() {};
    
       try
       {
          tizen.filesystem.resolve(directoryPath, onSuccess, onError, openMode);
       }
    }
  2. Retrieving a List of Files

    The listFiles() method of the FileSystemManager interface is used to list all the files and directories present in the current storage location in the application.

    getFilesList: function SystemIO_getFilesList(dir, onSuccess)
    {
       try
       {
          dir.listFiles(function(files)
          {
             var tmp = [],
             len = files.length,
             i;
    
             for (i = 0; i < len; i += 1)
             {
                tmp.push(files[i].name);
             }
    
             if (typeof onSuccess === 'function')
             {
                onSuccess(tmp);
             }
          }, function(e)
          {
             console.error('SystemIO_getFilesList dir.listFiles() error:', e);
          });
       }
    }
  3. Retrieving a Folder or File URI

    The toURI() method of the FileSystemManager interface is used to retrieve the folder or file URI.

    displayFolder: function Ui_displayFolder(folderName, nodes, refresh)
    {
       var len = nodes.length,
       listElements = [this.templateManager.get('levelUpRow')], nodeName, checkedRows = [], i;
    
       /* Other application code */
    
       for (i = 0; i < len; i = i + 1)
       {
          nodeName = nodes[i].name.trim();
          if (nodeName !== '')
          {
             if (nodes[i].isDirectory)
             {
                listElements.push(this.templateManager.get('folderRow',
                {
                   id: i,
                   name: nodeName,
                   uri: nodes[i].fullPath,
                   fullUri: nodes[i].toURI()
                }));
             }
             else
             {
                listElements.push(this.templateManager.get('fileRow',
                {
                   id: i,
                   name: nodeName,
                   uri: nodes[i].fullPath,
                   fullUri: nodes[i].toURI(),
                   thumbnailURI: this.helpers.getThumbnailURI(nodeName, nodes[i])
                }));
             }
          }
       }
    }
Go to top