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.
To implement the presented functionality, we need to complete the following steps:
Like in the base article, we should add a JavaScript code for Uploader Lightbox Control.
We will start with base methods. All of them are described in this article.
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
}
}
Now we focus on custom methods for the Vault. At first, we include the following files:
<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
Then we define some configuration settings:
vault.setFilesLimit(5);
vault.setHeight(200);
vault.setWidth(610);
vault.setSkin("dhx_terrace");
Also, the following skins are available:
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:
vault.attachEvent("onFileRemove", function (file){
...
});
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) {
...
});
Finally, to destruct a Vault instance, we use the Unload method:
vault.unload();
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());
}
};
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:
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:
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"
});
...
On this step we have created a DHTMLX Vault Component. Next we'll add functionality for:
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:
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.
The Upload() method should return JSON format, which has the following structure:
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;
}
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"]};
}
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
The returned JSON should have the following fields:
To remove a file, use the following code:
public void Remove(string fname)
{
File.Delete(fname);
}
Where
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();");
For the Vault component we need the following action methods:
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.
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);
}
}
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)));
}
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");
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;
}
}
}
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;
}
}
}
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;
}
}
}
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;
}
}
}