I tried to get this included as a standard feature of the editor, but with no luck:
http://www.telerik.com/community/forums/thread/b311D-htbgg.aspx
So, I spent a few hours heeding the advice of the Telerik guys and extended their File Browser so that my users can do bulk uploads of files in a zipped file format.
I have posted a small project in the Code Library that demonstrates this in action, here:
http://www.telerik.com/community/code-library/submission/b311D-bdcktd.aspx
And, despite the heckling I'm sure to get, I still work in VB so the code posted here is in VB. Use www.codechanger.com to convert to C# if you need.
Some notes on my own logic used here. Since the user is allowed to upload a zip file we no longer know for sure what is contained in that file - it could be any combination of any kinds of files and / or directories. I decided that I liked the feature of the user being able to upload directories of files so the code allows for that. Essentially, this is the pseudocode:
1) Is the uploaded file a zip file? If yes, then goto step 2, otherwise, proceed as normal.
2) Don't save the zip file to disk, begin extraction in-memory
3) For each entry in the zip file, determine if it's a file or a directory
4) If it's a file, delete the file if it already exists. If it's a directory, create the directory.
5) Check that the file is a non-zip file that complies with the file types specified in the search patterns. If it is a valid file, save it to disk.
6) Check that all directories and sub-directories contain image files. If the directory is empty, delete it. This is because a directory in the zip file could have contained an invalid file - but the directory would have still be created.
7) Try to return the path of the last extracted file to the File Browser Dialog - this doesn't work if the File Browser needs to change a directory but it does work in all other cases.
For those who don't want to download the whole project from the code library and just want to copy/paste the needed code for their own project, here's how it's done.
Step 1: Download and add a reference to the SharpZipLib.dll for your website / project.
Step 2: Extend the built-in FileSystemContentProvider. The only method that needs to be overridden is the StoreFile method, but you'll also need to create a New(...) method. Add the following class to your App_Code folder. Note: to make the code smaller, I've removed all comments but hopefully it makes sense:
Step 3: Add the "*.zip" extension to the SearchPatterns of the Image/Document/Media/Etc Manager; which unfortunately also means you need to manually re-input all of the default file extensions. This is what it looks like for the ImageManager (Note: I haven't brought back all of the default extensions):
Step 4: Set the ContentProviderTypeName for the Image/Document/Media/Etc Manager that you want to enable zip files for:
Step 5: Make sure you add all the other necessary stuff required by the Editor in Q1 2008 and going forward, such as the HttpHandlers in the Web.config and the RadSpell dictionary in the App_Data folder.
http://www.telerik.com/community/forums/thread/b311D-htbgg.aspx
So, I spent a few hours heeding the advice of the Telerik guys and extended their File Browser so that my users can do bulk uploads of files in a zipped file format.
I have posted a small project in the Code Library that demonstrates this in action, here:
http://www.telerik.com/community/code-library/submission/b311D-bdcktd.aspx
And, despite the heckling I'm sure to get, I still work in VB so the code posted here is in VB. Use www.codechanger.com to convert to C# if you need.
Some notes on my own logic used here. Since the user is allowed to upload a zip file we no longer know for sure what is contained in that file - it could be any combination of any kinds of files and / or directories. I decided that I liked the feature of the user being able to upload directories of files so the code allows for that. Essentially, this is the pseudocode:
1) Is the uploaded file a zip file? If yes, then goto step 2, otherwise, proceed as normal.
2) Don't save the zip file to disk, begin extraction in-memory
3) For each entry in the zip file, determine if it's a file or a directory
4) If it's a file, delete the file if it already exists. If it's a directory, create the directory.
5) Check that the file is a non-zip file that complies with the file types specified in the search patterns. If it is a valid file, save it to disk.
6) Check that all directories and sub-directories contain image files. If the directory is empty, delete it. This is because a directory in the zip file could have contained an invalid file - but the directory would have still be created.
7) Try to return the path of the last extracted file to the File Browser Dialog - this doesn't work if the File Browser needs to change a directory but it does work in all other cases.
For those who don't want to download the whole project from the code library and just want to copy/paste the needed code for their own project, here's how it's done.
Step 1: Download and add a reference to the SharpZipLib.dll for your website / project.
Step 2: Extend the built-in FileSystemContentProvider. The only method that needs to be overridden is the StoreFile method, but you'll also need to create a New(...) method. Add the following class to your App_Code folder. Note: to make the code smaller, I've removed all comments but hopefully it makes sense:
Imports ICSharpCode.SharpZipLib.Zip |
Imports System.IO |
Imports Telerik.Web.UI |
Imports Telerik.Web.UI.Widgets |
Public Class UnzipFileSystemContentProvider |
Inherits FileSystemContentProvider |
Public Sub New(ByVal context As HttpContext, ByVal searchPatterns As String(), ByVal viewPaths As String(), ByVal uploadPaths As String(), ByVal deletePaths As String(), ByVal selectedUrl As String, ByVal selectedItemTag As String) |
MyBase.New(context, searchPatterns, viewPaths, uploadPaths, deletePaths, selectedUrl, selectedItemTag) |
Me.ProcessPaths(MyBase.ViewPaths) |
Me.ProcessPaths(MyBase.UploadPaths) |
Me.ProcessPaths(MyBase.DeletePaths) |
MyBase.SelectedUrl = FileBrowserContentProvider.RemoveProtocolNameAndServerName(Me.GetAbsolutePath(MyBase.SelectedUrl)) |
End Sub |
Public Overrides Function StoreFile(ByVal file As UploadedFile, ByVal path As String, ByVal name As String, ByVal ParamArray arguments As String()) As String |
Dim relFolder As String = path |
Dim relFull = IO.Path.Combine(relFolder, name) |
Dim mapFolder As String = MyBase.Context.Server.MapPath(relFolder) |
Dim mapFull As String = MyBase.Context.Server.MapPath(relFull) |
If file.GetExtension = ".zip" Then |
Dim lastValidFile As String = "" |
Using ZIS As New ZipInputStream(file.InputStream) |
Dim ZE As ZipEntry = ZIS.GetNextEntry |
While Not IsNothing(ZE) |
Dim strDir As String = IO.Path.GetDirectoryName(ZE.Name) |
Dim strFil As String = IO.Path.GetFileName(ZE.Name) |
If strDir.Length > 0 Then |
IO.Directory.CreateDirectory(mapFolder & strDir) |
End If |
If strFil <> String.Empty Then |
If IsValidFileTypeAfterUnZip(ZE.Name) Then |
DeleteFileIfAlreadyExists(mapFolder & ZE.Name) |
lastValidFile = relFolder & ZE.Name |
Using FS As FileStream = IO.File.Create(mapFolder & ZE.Name) |
Dim i As Integer = 2048 |
Dim b As Byte() = New Byte(2048) {} |
While True |
i = ZIS.Read(b, 0, b.Length) |
If i > 0 Then |
FS.Write(b, 0, i) |
Else |
Exit While |
End If |
End While |
End Using |
End If |
End If |
ZE = ZIS.GetNextEntry |
End While |
End Using |
DeleteEmptyDirectoriesAfterZip(mapFolder) |
Return lastValidFile |
Else |
DeleteFileIfAlreadyExists(mapFull) |
file.SaveAs(mapFull) |
Return relFull |
End If |
End Function |
Private Sub DeleteFileIfAlreadyExists(ByVal mapFull As String) |
If IO.File.Exists(mapFull) Then |
IO.File.Delete(mapFull) |
End If |
End Sub |
Private Sub DeleteEmptyDirectoriesAfterZip(ByVal mapFolder As String) |
For Each Dir As String In IO.Directory.GetDirectories(mapFolder) |
DeleteEmptyDirectoriesAfterZip(Dir) |
If IO.Directory.GetFiles(Dir).Count = 0 And IO.Directory.GetDirectories(Dir).Count = 0 Then |
IO.Directory.Delete(Dir) |
End If |
Next |
End Sub |
Private Function IsValidFileTypeAfterUnZip(ByVal fileName As String) As Boolean |
Dim strExt As String = Right(fileName, fileName.Length - fileName.LastIndexOf(".")).ToLower |
If strExt = ".zip" Then |
Return False |
Else |
For Each s As String In MyBase.SearchPatterns |
s = Right(s, s.Length - s.LastIndexOf(".")).ToLower |
If s = strExt Then Return True |
Next |
End If |
Return False |
End Function |
End Class |
Step 3: Add the "*.zip" extension to the SearchPatterns of the Image/Document/Media/Etc Manager; which unfortunately also means you need to manually re-input all of the default file extensions. This is what it looks like for the ImageManager (Note: I haven't brought back all of the default extensions):
<telerik:RadEditor runat="server" ID="RadEditor1" Skin="Default"> |
<ImageManager DeletePaths="~/Images/" SearchPatterns="*.gif,*.jpg,*.jpeg,*.jpe,*.tiff,*.tif,*.bmp,*.png,*.zip" UploadPaths="~/Images/" ViewPaths="~/Images/" /> |
</telerik:RadEditor> |
Step 4: Set the ContentProviderTypeName for the Image/Document/Media/Etc Manager that you want to enable zip files for:
RadEditor1.ImageManager.ContentProviderTypeName = GetType(UnzipFileSystemContentProvider).AssemblyQualifiedName |
Step 5: Make sure you add all the other necessary stuff required by the Editor in Q1 2008 and going forward, such as the HttpHandlers in the Web.config and the RadSpell dictionary in the App_Data folder.