By default, the Insert Image tool opens a simple dialog that allows you to type in or paste the URL of an image and, optionally, specify a tooltip.
The Editor also supports another way of picking an image by browsing a list of predefined files and directories. Uploading new images is also supported. For a runnable example, refer to the demo on file and image browser in the Editor.
To retrieve and upload the files and directories, the image browser needs a server-side implementation. To configure the image browser tool, use the ImageBrowser()
method.
@(Html.Kendo().Editor()
.Name("editor")
.ImageBrowser(imageBrowser => imageBrowser
.Image("~/Content/UserFiles/Images/{0}")
.Read("Read", "ImageBrowser")
.Create("Create", "ImageBrowser")
.Destroy("Destroy", "ImageBrowser")
.Upload("Upload", "ImageBrowser")
.Thumbnail("Thumbnail", "ImageBrowser")
)
)
public class ImageBrowserController : EditorImageBrowserController
{
private const string contentFolderRoot = "~/Content/";
private const string prettyName = "Images/";
private static readonly string[] foldersToCopy = new[] { "~/Content/shared/" };
public override string ContentPath
{
get
{
return CreateUserFolder();
}
}
private string CreateUserFolder()
{
var virtualPath = Path.Combine(contentFolderRoot, "UserFiles", prettyName);
var path = Server.MapPath(virtualPath);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
foreach (var sourceFolder in foldersToCopy)
{
CopyFolder(Server.MapPath(sourceFolder), path);
}
}
return virtualPath;
}
private void CopyFolder(string source, string destination)
{
if (!Directory.Exists(destination))
{
Directory.CreateDirectory(destination);
}
foreach (var file in Directory.EnumerateFiles(source))
{
var dest = Path.Combine(destination, Path.GetFileName(file));
System.IO.File.Copy(file, dest);
}
foreach (var folder in Directory.EnumerateDirectories(source))
{
var dest = Path.Combine(destination, Path.GetFileName(folder));
CopyFolder(folder, dest);
}
}
}
public abstract class EditorImageBrowserController : BaseFileBrowserController, IImageBrowserController
{
private readonly IThumbnailCreator thumbnailCreator;
private const int ThumbnailHeight = 80;
private const int ThumbnailWidth = 80;
protected EditorImageBrowserController()
: this(DI.Current.Resolve<IDirectoryBrowser>(),
DI.Current.Resolve<IDirectoryPermission>(),
DI.Current.Resolve<IVirtualPathProvider>(),
DI.Current.Resolve<IThumbnailCreator>())
{
}
protected EditorImageBrowserController(IDirectoryBrowser directoryBrowser,
IDirectoryPermission permission,
IVirtualPathProvider pathProvider,
IThumbnailCreator thumbnailCreator)
: base(directoryBrowser, permission, pathProvider)
{
this.thumbnailCreator = thumbnailCreator;
}
public override string Filter
{
get
{
return EditorImageBrowserSettings.DefaultFileTypes;
}
}
public virtual bool AuthorizeThumbnail(string path)
{
return CanAccess(path);
}
[OutputCache(Duration = 3600, VaryByParam = "path")]
public virtual ActionResult Thumbnail(string path)
{
path = NormalizePath(path);
if (AuthorizeThumbnail(path))
{
var physicalPath = Server.MapPath(path);
if (System.IO.File.Exists(physicalPath))
{
Response.AddFileDependency(physicalPath);
return CreateThumbnail(physicalPath);
}
else
{
throw new HttpException(404, "File Not Found");
}
}
else
{
throw new HttpException(403, "Forbidden");
}
}
private FileContentResult CreateThumbnail(string physicalPath)
{
using (var fileStream = System.IO.File.OpenRead(physicalPath))
{
var desiredSize = new ImageSize
{
Width = ThumbnailWidth,
Height = ThumbnailHeight
};
const string contentType = "image/png";
return File(thumbnailCreator.Create(fileStream, desiredSize, contentType), contentType);
}
}
}
public abstract class BaseFileBrowserController : Controller, IFileBrowserController
{
private readonly IDirectoryBrowser directoryBrowser;
private readonly IDirectoryPermission permission;
private readonly IVirtualPathProvider pathProvider;
protected BaseFileBrowserController()
: this(DI.Current.Resolve<IDirectoryBrowser>(),
DI.Current.Resolve<IDirectoryPermission>(),
DI.Current.Resolve<IVirtualPathProvider>())
{
}
protected BaseFileBrowserController(IDirectoryBrowser directoryBrowser,
IDirectoryPermission permission,
IVirtualPathProvider pathProvider)
{
this.directoryBrowser = directoryBrowser;
this.permission = permission;
this.pathProvider = pathProvider;
}
public abstract string ContentPath
{
get;
}
public virtual string Filter
{
get
{
return "*.*";
}
}
public virtual bool AuthorizeRead(string path)
{
return CanAccess(path);
}
protected virtual bool CanAccess(string path)
{
return permission.CanAccess(pathProvider.ToAbsolute(ContentPath), path);
}
protected string NormalizePath(string path)
{
if (string.IsNullOrEmpty(path))
{
return pathProvider.ToAbsolute(ContentPath);
}
return pathProvider.CombinePaths(pathProvider.ToAbsolute(ContentPath), path);
}
public virtual JsonResult Read(string path)
{
path = NormalizePath(path);
if (AuthorizeRead(path))
{
try
{
directoryBrowser.Server = Server;
var result = directoryBrowser.GetFiles(path, Filter)
.Concat(directoryBrowser.GetDirectories(path));
return Json(result);
}
catch (DirectoryNotFoundException)
{
throw new HttpException(404, "File Not Found");
}
}
throw new HttpException(403, "Forbidden");
}
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Destroy(string path, FileBrowserEntry entry)
{
path = NormalizePath(path);
if (entry != null)
{
path = pathProvider.CombinePaths(path, entry.Name);
if (entry.EntryType == FileBrowserEntryType.File)
{
DeleteFile(path);
}
else
{
DeleteDirectory(path);
}
return Json(new object[0]);
}
throw new HttpException(404, "File Not Found");
}
public virtual bool AuthorizeDeleteFile(string path)
{
return CanAccess(path);
}
public virtual bool AuthorizeDeleteDirectory(string path)
{
return CanAccess(path);
}
protected virtual void DeleteFile(string path)
{
if (!AuthorizeDeleteFile(path))
{
throw new HttpException(403, "Forbidden");
}
var physicalPath = Server.MapPath(path);
if (System.IO.File.Exists(physicalPath))
{
System.IO.File.Delete(physicalPath);
}
}
protected virtual void DeleteDirectory(string path)
{
if (!AuthorizeDeleteDirectory(path))
{
throw new HttpException(403, "Forbidden");
}
var physicalPath = Server.MapPath(path);
if (Directory.Exists(physicalPath))
{
Directory.Delete(physicalPath, true);
}
}
public virtual bool AuthorizeCreateDirectory(string path, string name)
{
return CanAccess(path);
}
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Create(string path, FileBrowserEntry entry)
{
path = NormalizePath(path);
var name = entry.Name;
if (name.HasValue() && AuthorizeCreateDirectory(path, name))
{
var physicalPath = Path.Combine(Server.MapPath(path), name);
if (!Directory.Exists(physicalPath))
{
Directory.CreateDirectory(physicalPath);
}
return Json(entry);
}
throw new HttpException(403, "Forbidden");
}
public virtual bool AuthorizeUpload(string path, HttpPostedFileBase file)
{
return CanAccess(path) && IsValidFile(file.FileName);
}
private bool IsValidFile(string fileName)
{
var extension = Path.GetExtension(fileName);
var allowedExtensions = Filter.Split(',');
return allowedExtensions.Any(e => e.Equals("*.*") || e.EndsWith(extension, StringComparison.InvariantCultureIgnoreCase));
}
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Upload(string path, HttpPostedFileBase file)
{
path = NormalizePath(path);
var fileName = Path.GetFileName(file.FileName);
if (AuthorizeUpload(path, file))
{
file.SaveAs(Path.Combine(Server.MapPath(path), fileName));
return Json(new FileBrowserEntry
{
Size = file.ContentLength,
Name = fileName
}, "text/plain");
}
throw new HttpException(403, "Forbidden");
}
}
public interface IImageBrowserController : IFileBrowserController
{
IActionResult Thumbnail(string path);
}
public interface IFileBrowserController
{
JsonResult Read(string path);
ActionResult Destroy(string path, FileBrowserEntry entry);
ActionResult Create(string path, FileBrowserEntry entry);
ActionResult Upload(string path, IFormFile file);
}
The following list provides information about the default requests and responses for the Create()
, Read()
, Destroy()
, and Upload()
operations.
Create()
—Makes a POST
request for the creation of a directory with the following parameters and does not expect a response.
{ "name": "New folder name", "type": "d", "path": "foo/" }
Read()
—Makes a POST
request that contains the path
parameter which specifies the path that is browsed and expects a file listing in the following format.
[
{ "name": "foo.png", "type": "f", "size": 73289 },
{ "name": "bar.jpg", "type": "f", "size": 15289 },
...
]
name
from the previous example is the name of the file or directory, type
is either an f
for a file or a d
for a directory, and size
is the file size (optional).
Destroy()
—Makes a POST
request with the following parameters and expects an empty ContentResult as a response:
name
The file or the directory that will be deleted. path
The directory in which the file or the directory resides. type
The file or the directory that will be deleted (an f
or a d
). size
(Optional) The file size, as provided by the Read()
response.Upload()
—Makes a POST
request. The request includes FormData
which contains the upload path and the file name and type. Its payload consists of the uploaded file. The expected response is a file
object in the following format:
{ "name": "foo.png", "type": "f", "size": 12345 }
Thumbnail()
—Makes a GET
request for each individual image to display its thumbnail in the explorer window. The single request parameter is the path
to the image. The service is expected to respond with the image file for the thumbnail.
Image()
—Used by the Editor to generate the src
attribute of the original image when the image is inserted. It results in a GET
request generated by the browser for each inserted image. The URL can point to a file system or to a service and is parameterized—the {0}
placeholder denotes the path
and fileName
as received from the Read()
service.
You can update all of these requests and responses through the ImageBrowser()
configuration. Each of them exposes more options that you can tweak.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4