Download Free Demos

File Uploader for Lightbox

Introduction

In this article we demonstrate how to add DHTMLX components in the Lightbox of Scheduler .NET. You are assumed to be an experienced Microsoft .NET web application developer and DHTMLX Scheduler .NET user. To proceed with this tutorial, you should first get familiar with the following articles:

They will give you some basics on adding simple components to the Lightbox.

Let's extend the Lightbox component of Scheduler .NET with the uploading functionality.

 Uploader component

To implement the presented functionality, we need to complete the following steps:

Step 1. Define a Component on the Client Side

Like in the base article, we should add a JavaScript code for Uploader Lightbox Control.

Using Base Methods

We will start with base methods. All of them are described in this article.

  • render() is used to define a container of the Vault component
  • set_value() - initializes DHTMLX Vault and all the logic
scheduler.form_blocks["vault"] = {
    render: function (sns) { // sns - section configuration object
        return "<div id='" + sns.type + "' style='height:" + (sns.height || 40) + "px;' ></div>";
    },
    set_value: function (node, value, ev, config) {
        // node - HTML object related to HTML defined above
        // value - value defined by the "map_to" property
        // ev - event object
        scheduler.form_blocks.vault.upload(config.name, ev.id);
 
    },
    get_value: function (node, ev) {
        // node - HTML object related to HTML defined above
        // event object
        return;
    },
    focus: function (node) {
        // node - HTML object related to HTML defined above
 
    },
    /*for initialization of Vault*/
    upload: function (name, event_id) {
    // name - container name
    // event_id - id of event
    }
}

Initializing Vault

Now we focus on custom methods for the Vault. At first, we include the following files:

  • dhtmlxvault.css
  • dhtmlxvault.js
<link rel="stylesheet" type="text/css" href="dhtmlxvault.css"/>
<script src="dhtmlxvault.js"></script>

In the code below we initialize the Vault component:

if (!scheduler._vaultInst) {
    scheduler._vaultInst = new dhtmlXVaultObject({
        container: "vault",
        uploadUrl: scheduler._vaultConfig.uploadUrl
    });
    scheduler._vaultInst.setAutoStart(true);
}
return scheduler._vaultInst;

where

  • container - id of HTML container element for DHTMLX Vault component
  • uploadUrl - this URL will be called for uploading a file

Specifying Vault Configuration

Then we define some configuration settings:

  • the number of files allowed to be added list. In this example only 5 files are allowed:
vault.setFilesLimit(5);
  • the initial height of DHTMLX Vault component. In this example it is 200 px:
vault.setHeight(200);
  • the initial width of DHTMLX Vault component. In this example it is 610 px:
vault.setWidth(610);
  • the skin of the component. For this example, we chose the "terrace" skin:
vault.setSkin("dhx_terrace");

Also, the following skins are available:

  • dhx_skyblue (default)
  • dhx_web

Using dhtmlxVault Events

To use some events of DHTMLX Vault Component, you need to use the attachEvent() method, as in the following code:

vault.attachEvent(string name,function handler);

For upload example, we use the following events:

  • onFileRemove - fires when a user removes a single file from the file list
vault.attachEvent("onFileRemove", function (file){
    ...
});
  • onBeforeFileAdd - fires before the user adds a file or files to the upload queue.

The number of calls in this method is equal to the amount of files. This method is used for validation in our example:

vault.attachEvent("onBeforeFileAdd", function (file) {
    ...
});

Unloading Vault

Finally, to destruct a Vault instance, we use the Unload method:

vault.unload();

Full Client-Side Code

The full code of this chapter is the following:

scheduler.form_blocks["vault"] = {
    render: function (sns) { // sns - section configuration object
        return "<div id='" + sns.type + "' style='height:" + (sns.height || 40) + "px;' ></div>";
    },
 
    set_value: function (node, value, ev, config) {
        // node - HTML object related to HTML defined above
        // value - value defined by the "map_to" property
        // ev - event object
        scheduler.form_blocks.vault.setConfig(config.name);
        scheduler.form_blocks.vault.upload(config.name, ev.id);
    },
 
    get_value: function (node, ev) {
        // node - HTML object related to the HTML defined above
        // event object
        return;
    },
 
    focus: function (node) {
        // node - HTML object related to the HTML defined above
    },
 
    getVault: function () {
        if (!scheduler._vaultInst) {
            scheduler._vaultInst = new dhtmlXVaultObject({
                container: "vault",
                uploadUrl: scheduler._vaultConfig.uploadUrl
            });
            scheduler._vaultInst.setAutoStart(true);
        }
        return scheduler._vaultInst;
    },
 
    setConfig: function (name) {
        var scs = scheduler.config.lightbox.sections;
        for (var i = 0; i < scs.length; i++) {
            if (scs[i].name == name)
                scheduler._vaultConfig = scs[i];
        }
    },
 
    getConfig: function () {
        return scheduler._vaultConfig;
    },
 
    initUploader: function (config) {
        var obj = scheduler.form_blocks["vault"];
 
        var vault = obj.getVault();
 
        /*allows uploading only of 5 files*/
        vault.setFilesLimit(config.filesLimit);
        vault.setHeight(config.Height);
        vault.setWidth(config.Width);
        vault.setSkin(config.skin);
 
        /*fires when the user removes a single file from the list of files*/
        vault.attachEvent("onFileRemove", function (file) {
            window.dhx4.ajax.get(config.removeUrl + file.serverName.toString());
        });
 
        scheduler.attachEvent("onAfterLightbox", function () {
            var obj = scheduler.form_blocks["vault"];
            var vault = obj.getVault();
            if (vault) {
                if (vault.unload != null) {
                    vault.unload();
                    scheduler._vaultInst = null;
                }
            }
        });
 
        /*fires before the user adds a file to the upload queue*/
        vault.attachEvent("onBeforeFileAdd", function (file) {
            var obj = scheduler.form_blocks["vault"];
            config = obj.getConfig();
            var ext = this.getFileExtension(file.name);
            return config.ext.indexOf(ext) >= 0 || file.size > config.sizeLimit;
        });
 
    },
 
    upload: function (name, event_id) {
        var obj = scheduler.form_blocks["vault"];
        var config = obj.getConfig();
 
        obj.initUploader(config);
        obj.changeSession(event_id);
        var vault = obj.getVault();
 
        if (!scheduler.getState().new_event) {
            if (!vault.v_container) {
                vault.v_container = document.getElementById('vault');
            } else {
                var cont = document.getElementById('vault');
                cont.parentNode.replaceChild(vault.v_container, cont);
            }
            vault.setDownloadURL(config.dwnUrl);
            /*load list of files from server*/
            vault.load(config.fileList + event_id.toString(), function () {
 
            });
        }
    },
 
    changeSession: function (event_id) {
        var obj = scheduler.form_blocks["vault"];
        var config = obj.getConfig();
        window.dhx4.ajax.get(config.session + event_id.toString());
    }
};

Step 2. Define a Component on the Server Side

At this step we will add a wrapper for the LightboxVault panel to add this component to the Scheduler.NET. Vault is one of the components for which basic properties are not enough. But it's not a problem for Scheduler.NET, as far as it is extensible.

Everything you need is to add some property to your wrapper and the component will render this property in JavaScript.

For example, for the Vault component in this example the following custom properties are needed:

  • removeUrl - functionality for removing a file
  • uploadUrl - functionality for uploading a file
  • dwnUrl - functionality for showing a document in a browser
  • fileList - functionality for loading a list of files to the DHTMLX Component
  • changeSession - functionality for changing a session
  • filesLimit - amount of files which can be downloaded
  • width - width of the Vault component
  • sizeLimit - max size of a downloaded file
  • ext - file extensions which can be downloaded
public class LightboxVault : LightboxField
{
    /// <summary>
    /// Define Vault skins
    /// </summary>
    public enum Skins
    {
       dhx_skyblue,
       dhx_web,
       dhx_terrace
    };
 
    /// <summary>
    /// Vault skin
    /// </summary>
    public Skins Skin
    {
      get
       {
         var skin = Skins.dhx_web;
         if (Enum.IsDefined(typeof(Skins), Get("skin")))
            skin = (Skins)Enum.Parse(typeof(Skins), Get("skin"));
         return skin;
       }
      set
       {
         Set("skin", value.ToString());
       }
    }
    /// <summary>
    /// URL for upload file
    /// </summary>
    public string UploadUrl
    {
       get { return Get("uploadUrl"); }
       set { Set("uploadUrl", value); }
    }
    /// <summary>
    /// URL for removing file
    /// </summary>
    public string RemoveUrl
    {
       get { return Get("removeUrl"); }
       set { Set("removeUrl", value); }
    }
    /// <summary>
    /// URL for opening file in a browser
    /// </summary>
    public string DwnUrl
    {
       get { return Get("dwnUrl"); }
       set { Set("dwnUrl", value); }
    }
    /// <summary>
    /// URL for getting list of files
    /// </summary>
    public string FileList
    {
       get { return Get("fileList"); }
       set { Set("fileList", value); }
    }
    /// <summary>
    /// SVault session
    /// </summary>
    public string ChangeSession
    {
       get { return Get("session"); }
       set { Set("session", value); }
    }
    /// <summary>
    /// Amount of files which can be downloaded
    /// </summary>
    public int FilesLimit
    {
       get { return Convert.ToInt32(Get("filesLimit")); }
       set { Set("filesLimit", value); }
    }
    /// <summary>
    /// Width of the component
    /// </summary>
    public int Width
    {
       get { return Convert.ToInt32(Get("width")); }
       set { Set("width", value); }
    }
    /// <summary>
    /// Max size of file which can be downloaded
    /// </summary>
    public int FileSizeLimit
    {
       get { return Convert.ToInt32(Get("sizeLimit")); }
       set { Set("sizeLimit", value); }
    }
    /// <summary>
    /// Allow extensions
    /// </summary>
    public string AllowsExt
    {
       get { return Get("ext"); }
       set { Set("ext", value); }
    }
 
    public LightboxVault(string name, string label = null)
       : base(name, label)
    {
       Height = 150;
       Type = "vault";
    }
 
    /// <summary>
    /// Determines skin and returns necessary files for this
    /// </summary>
    /// <returns>List of styles for vault component</returns>
    public override Dictionary<string, FileType> GetCSS()
    {
        string styles;
        switch (Skin)
        {
           case Skins.dhx_skyblue:
              styles = "dhtmlxVault/skins/skyblue/dhtmlxvault.css";
              break;
           case Skins.dhx_terrace:
              styles = "dhtmlxVault/skins/terrace/dhtmlxvault.css";
              break;
           default:
              styles = "dhtmlxVault/skins/web/dhtmlxvault.css";
              break;
        }
        Dictionary<string, FileType> files = new Dictionary<string, FileType>();
            files.Add("dhtmlxVault/dhtmlxvault.css", FileType.Local);
            files.Add(styles, FileType.Local);
            return files;
        }
    /// <summary>
    /// Returns necessary js file for the component
    /// </summary>
    /// <returns>List of js files for vault component</returns>
    public override Dictionary<string, FileType> GetJS()
    {
      return new Dictionary<string, FileType>()"dhtmlxVault/dhtmlxvault.js", FileType.Local;
    }
}

As you can see, in this code we overrode the GetJS() and GetCSS() methods for the Vault component. It means that all we need is to define the skin and needed files will be loaded.

In our example the Vault folder is inside of the dhtmlxScheduler folder:

 File structure

Finally, we should add this component to the Scheduler.NET:

...
var calendar = new DHXScheduler();
...
calendar.Lightbox.Add(new LightboxVault("vault", "")
{
    ThemeCss = "SKIN_FOLDER",
    uploadUrl = "UPLOAD_FILE",
    removeUrl = "REMOVE_FILE",
    dwnUrl = "DOWNLOAD_URL",
    fileList = "GET_FILES",
    changeSession = "CHANGE_SESSION",
    Width = 610,
    FilesLimit = 5,
    FileSizeLimit = 20000,
    AllowsExt = "EXTENSIONS"
});
...

 Lightbox with vault component

On this step we have created a DHTMLX Vault Component. Next we'll add functionality for:

  • loading a list to the Vault control
  • removing files from Vault
  • ability to open files in a browser

Step 2.1 Define Logic for Vault

Before defining logic for the Vault component, we initialize an auxiliary class for the file manager:

public static class FileManager
{
    public static void CreateDirectory(string path)
    {
        var exists = Directory.Exists(path);
        if (!exists)
        {
            Directory.CreateDirectory(path);
        }
    }
 
    public static void RemoveFile(string name)
    {
        File.Delete(name);
    }
 
    public static string GetVPath(string param)
    {
        return string.Format("{0}{1}",
            System.Configuration.ConfigurationManager.AppSettings["UploadPath"],
            param);
    }
 
    public static string GetVPath(string p1, string p2)
    {
        return string.Format("{0}{1}/{2}",
            System.Configuration.ConfigurationManager.AppSettings["UploadPath"],
            p1, p2);
    }
 
    public static void MoveFile(string from, string to)
    {
        Directory.Move(from, to);
    }
}

Here are the methods for:

  • creating a directory, if it doesn't exist
  • removing a file
  • returning the path of file or folders.

Also, we need some classes for JSON responses:

public class VaultFile
{
    public bool state;
    public string name;
    public Extra extra;
}
 
public class Extra
{
    public string info;
    public string param;
}
 
public class vFileInfo
{
    public string name;
    public string serverName;
    public long size;
}

Finally, we need to initialize methods for: reading the list of files, uploading and removing files. In our example this code is in the LightboxUploader.Control library.

Uploading a File

The Upload() method should return JSON format, which has the following structure:

  • state - true/false - status of downloading
  • name - name of the downloaded file
  • extra - optional. It has the following field : info - message of the download process
public VaultFile Upload(string name, HttpPostedFile file)
{
    VaultFile vFile = null;
    try
    {
        byte[] bytes;
        using (var br = new BinaryReader(file.InputStream))
        {
            bytes = br.ReadBytes(file.ContentLength);
        }
        using (var stream = File.Open(name + "/" + file.FileName, FileMode.OpenOrCreate))
        {
            stream.Write(bytes, 0, bytes.Length);
        }
 
        vFile = new VaultFile
        {
            state = true,
            name = file.FileName,
            extra = new Extra
            {
                info = string.Format("{0} has been downloaded.", file.FileName)
            }
        };
    }
    catch (Exception exception)
    {
 
        vFile = new VaultFile
        {
            state = false,
            name = file.FileName,
            extra = new Extra
            {
                info = exception.Message
            }
        };
 
        return vFile;
    }
    return vFile;
}

Setting Maximum File Size

While DHTMLX Vault component is initializing, Vault tries to set maxFileSize from the server:

public object SetMaxFize()
{
  return new {maxFileSize = System.Configuration.ConfigurationManager.AppSettings["maxSize"]};
}

Getting Files List from Server

To get files for the event, follow this code:

public List<vFileInfo> GetAll(string id, string folder)
{
    FileManager.CreateDirectory(folder);
    var pathFiles = Directory.GetFiles(folder);
 
    var fileInfos = new List<vFileInfo>();
 
    foreach (var path in pathFiles)
    {
        var fi = new FileInfo(path);
        fileInfos.Add(new vFileInfo()
        {
            name = fi.Name,
            serverName = fi.Name,
            size = fi.Length
        });
    }
 
    return fileInfos;
}

Where

  • id - id of the event
  • folder - path of the folder

The returned JSON should have the following fields:

  • name - name of the file which will be displayed
  • serverName - name of the file on the server
  • size - size of the file

Removing Files

To remove a file, use the following code:

public void Remove(string fname)
{
   File.Delete(fname);
}

Where

  • name - file path

Step 2.1.1 MVC

In web configurations we define the upload path for downloaded files:

<configuration>
    <appSettings>
        <add key="UploadPath" value="~/upload/" />
        <add key="extensions" value="pdf, jpg, jpeg, png, zip, txt" />
     </appSettings>
</configuration>

Also we need to specify in the function, what new name the folder will have after the event id is changed. The view will be contain the following code:

<script type="text/javascript">
    function beforeInit() {
        scheduler.attachEvent("onEventIdChange", function (old_id, new_id) {
            var params = "cur_id=" + old_id + "&new_id=" + new_id;
            window.dhx4.ajax.get("Home/ChangeFolderName?"+params);
        });
    }
</script>   <div style="height: 600px;"> @Html.Raw(Model.Render()) </div>

Then we should add the client side as an extension, and connect the Vault Component to the scheduler calendar:

calendar.Lightbox.Add(
    new LightboxVault("vault", "")
    {
        Skin = LightboxVault.Skins.dhx_terrace,
        UploadUrl = "Vault/UploadFile/",
        RemoveUrl = "Vault/RemoveFile?filename=",
        DwnUrl = "Vault/GetFile?fileName={serverName}",
        FileList = "Vault/GetFiles?id=",
        ChangeSession = "Home/ChangeSession?id=",
        Width = 610,
        FilesLimit = 5,
        FileSizeLimit = 20000000,
        AllowsExt = ConfigurationManager.AppSettings["extensions"]
     }
);
 
calendar.Extensions.Add("../dhtmlxscheduler_vault.js");
calendar.BeforeInit.Add("beforeInit();");

Adding Action Methods for Vault

For the Vault component we need the following action methods:

  • UploadFile() - uploads a file to the server
  • GetFiles() - returns the list of files inside the Vault component
  • GetFile() - returns data file for displaying it in the browser

For this purpose we use the setDownloadURL method of the DHTMLX Vault component. This method allows setting a link for the file inside of the component.

  • RemoveFile() - removes a file by id

Full DHTMLX Vault Controller Code

The full code of the DHTMLX Vault Controller should be as follows:

public class VaultController : Controller
{
   /*
   * UploadFile file
   */
   public JsonResult UploadFile()
   {
      var context = System.Web.HttpContext.Current;
      var vm = new VaultManager();
 
      if (context.Request.QueryString["mode"] == "conf")
      {
         return Json(vm.SetMaxFize(), JsonRequestBehavior.AllowGet);
      }
      var file = context.Request.Files["file"];
      var eventid = Session["sessionId"].ToString();
      var path = Server.MapPath(FileManager.GetVPath(eventid));
 
      FileManager.CreateDirectory(path);
 
      if (file != null)
      {
         var result = vm.Upload(path, file);
         return Json(result, JsonRequestBehavior.AllowGet);
      }
      return Json(new VaultFile()
      {
         state = false,
         extra = new Extra()
           {
              info = "File is null"
           }
       }, JsonRequestBehavior.AllowGet);
   }
 
   /*
   * Get list of files by event_id
   */
   public JsonResult GetFiles(string id)
   {
      var folder = FileManager.GetVPath(id);
      folder = Server.MapPath(folder);
 
      var vm = new VaultManager();
      var result = vm.GetAll(id, folder);
 
      return Json(result, JsonRequestBehavior.AllowGet);
    }
 
    /*
     * Open file in a browser
     */
     public void GetFile()
     {
        var context = System.Web.HttpContext.Current;
        var filename = context.Request.Params["fileName"];
        var id = Session["sessionId"].ToString();
        var folder = FileManager.GetVPath(id, filename);
        folder = VirtualPathUtility.ToAbsolute(folder);
        Response.Write("<script>");
        Response.Write("window.open('" + Request.UrlReferrer.ToString().TrimEnd('/') + folder + "', '_newtab');");
        Response.Write("</script>");
 
   }
 
   /*
    * Remove file
    */
    public void RemoveFile(string filename)
    {
       var eventId = Session["sessionId"].ToString();
       var folder = FileManager.GetVPath(eventId);
       folder = Server.MapPath(folder);
       VaultManager vm = new VaultManager();
       vm.Remove(folder + "/" + filename);
     }
}

Renaming a Folder

To change the folder name after saving an event, use the following code:

public void ChangeFolderName(string cur_id, string new_id)
{
    FileManager.MoveFile(Server.MapPath(FileManager.GetVPath(cur_id)),
      Server.MapPath(FileManager.GetVPath(new_id)));
}

Step 2.1.2 Web Forms

In web configurations we define the upload path for downloaded files:

<configuration>
    <appSettings>
        <add key="UploadPath" value="~/upload/" />
        <add key="extensions" value="pdf, jpg, jpeg, png, zip, txt" />
     </appSettings>
</configuration>

We need to define a function for renaming the folder of event after changing id. The page will contain the following code:

<script type="text/javascript">
    function beforeInit() {
        scheduler.attachEvent("onEventIdChange", function (old_id, new_id) {
            var params = "cur_id=" + old_id + "&new_id=" + new_id;
            window.dhx4.ajax.get("RenameFolder.ashx?" + params);
        });
    }
</script>
<div style="height: 600px">
   <%= this.scheduler.Render() %>
</div>

Then we connect our Vault Component to the scheduler calendar:

calendar.Lightbox.Add(new LightboxVault("vault", "")
    {
        Skin = LightboxVault.Skins.dhx_terrace,
        UploadUrl = "Upload.ashx",
        RemoveUrl = "RemoveFile.ashx?fname=",
        DwnUrl = "GetFile.ashx?fileName={serverName}",
        FileList = "GetFiles.ashx?id=",
        ChangeSession = "ChangeSession.ashx?id=",
        Width = 610,
        FilesLimit = 5,
        FileSizeLimit = 20000000,
        AllowsExt = ConfigurationManager.AppSettings["extensions"].ToString()
    }
);
 
calendar.BeforeInit.Add("beforeInit();");
calendar.Extensions.Add("../dhtmlxscheduler_vault.js");

Uploading a File

For uploading files, use the following code:

public class Upload : IRequiresSessionState, IHttpHandler
{
 
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "application/json";
 
        var js = new JavaScriptSerializer();
        var vm = new VaultManager();
 
        if (context.Request.QueryString["mode"] == "conf")
        {
            context.Response.Write(js.Serialize(vm.SetMaxFize()));
        }
        else
        {
            var file = context.Request.Files["file"];
            var eventid = context.Session["sessionId"].ToString();
            var path = context.Server.MapPath(FileManager.GetVPath(eventid));
 
            FileManager.DirectoryCreate(path);
 
            if (file != null)
            {
                var result = vm.Upload(path, file);
                    context.Response.Write(js.Serialize(result));
            }
        }
 
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Removing a File

The following code removes a file by id:

public class RemoveFile : IRequiresSessionState, IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        var filename = context.Request.Params["fname"];
        var eventId = context.Session["sessionId"].ToString();
        var folder = FileManager.GetVPath(eventId);
        folder = context.Server.MapPath(folder);
        VaultManager vm = new VaultManager();
        vm.Remove(folder + "/" + filename);
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Loading File List

The following code loads a list of files inside Vault component:

public class GetFiles : IRequiresSessionState, IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string id = context.Request.Params["id"];
        var js = new JavaScriptSerializer();
 
        var folder = FileManager.GetVPath(id);
        folder =context.Server.MapPath(folder);
 
        var vm = new VaultManager();
        var result = vm.GetAll(id, folder);
 
        context.Response.ContentType = "application/json";
        context.Response.Write(js.Serialize(result));
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Renaming a Folder

The following code renames the directory after id is changed:

public class RenameFolder : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        var cur_id = context.Request.Params["cur_id"];
        var new_id = context.Request.Params["new_id"];
 
        FileManager.MoveFile(context.Server.MapPath(FileManager.GetVPath(cur_id)),
            context.Server.MapPath(FileManager.GetVPath(new_id)));
        }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Was this article helpful?

Yes No