📜 ⬆️ ⬇️

A simple image loader in tinyMCE for MVC web application

The development of my project required to “tie” into the editor based on tinyMCE the ability to insert images that would be stored directly on the application server, and that it would be seamless for the end user. Googling quite a bit and finding everything useful as always on stackoverflow.com and examining everything that exists today on this topic, I realized that I would have to reinvent my own bicycle. My main motives were the following:
Almost all “ready-made” open implementations use the file storage principle when the user first uploads the file to the server, to the storage area, and then inserts it into the editor. The result is a rather complicated process, and besides this, the application server runs the risk of becoming a garbage file. The second motive is that all decisions were rather complicated and difficult. For example, some of them used silverlight components, others dragged along a bunch of external dependencies. In general, my goal is to write a simple, easy image downloader for tinyMCE that works on MVC. (I think this will be true for any MVC engine and not just ASP.NET). In this article I will tell you how easy it is to write your own bootloader and plugin for tinyMCE.



1. Boot Loader


')
As a download interface, I would like to get a dialog with a button for selecting a local file and a preview panel with two buttons, “insert” and “cancel.” The load will be asynchronous, using jquery.form. It will be automatic immediately after selecting a file.
First, write the bootloader controller.

public class ImageController : Controller { public ActionResult Index() { return View(); } [HttpPost] public JsonResult Index(HttpPostedFileBase file) { var service = new ImageService(); byte[] data = new byte[file.ContentLength]; file.InputStream.Read(data, 0, file.ContentLength); var image = service.CreateImage(file.FileName, file.ContentType, data); JsonResult res = Json(new {image.Id}); res.ContentType = "text/html"; //  ,   jquery.form (for iframe implementation) return res; } [OutputCache(Duration = 0)] public ActionResult ById(string id) { var service = new ImageService(); var image = service.GetImage(id); return new FileStreamResult(new MemoryStream(image.Data), image.ContentType); } } 


For storage, I used the service. For test purposes, it simply stores everything in a static hash:

 class ImageService { static Dictionary<string, ImageData> _images = new Dictionary<string, ImageData>(); public ImageData CreateImage(string fileName, string contentType, byte[] data) { var image = new ImageData(fileName, contentType, data); _images.Add(image.Id, image); return image; } public ImageData GetImage(string id) { return _images[id]; } internal class ImageData { private byte[] _data; public string FileName { get; set; } public string ContentType { get; set; } public string Id { get; set; } public byte[] Data { get { return _data; } } public ImageData(string fileName, string contentType, byte[] data) { FileName = fileName; ContentType = contentType; _data = data; Id = Guid.NewGuid().ToString(); } } } 


Later you can drive all the data into the database or to disk, as someone like.
Let's create a view, Index, we have one.

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript" src="@Url.Content("~/Scripts/tiny_mce/tiny_mce_popup.js")"></script> <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.form.js")" type="text/javascript"></script> <style type="text/css"> #image {height: 262px;overflow: auto;width: 440px;} #file { opacity:0;position:relative;z-index: 2;-moz-opacity:0 ; filter:alpha(opacity: 0);width:100%;height:100% } </style> </head> <body> @using (Html.BeginForm("Index", "Image", FormMethod.Post, new { id = "upload", enctype = "multipart/form-data" })) { <div> <div> <fieldset> <legend> </legend> <div id="image"><img id="preview" alt="   " src="" /></div> <input id="file" type="file" name="file" onchange="$('#upload').submit();"/> </fieldset> </div> </div> <div> <input type="button" id="insert" name="insert" value="" /> <input type="button" id="cancel" name="cancel" value="" > </div> } </body> </html> 


And the script:

 $(document).ready(function () { var options = { dataType: "json", beforeSubmit: function (data) { $('#preview').attr('src', '/Content/images/spinning.gif'); }, success: function (data) { $('#preview').attr('src', '/Image/ById/' + data.Id); } }; //   $('#upload').ajaxForm(options); //       $('#preview').click(function () { $('#file').click(); }); // Auto popup file select dialog //$('#file').click(); }); 


That's basically all, you can test our bootloader controller.



As a result, we have:



2. Plugin


Now let's create a plugin for tinyMCE. Source codes are copied from the example plugin.
I called my imagelight plugin.

editor_plugin.js

 (function() { // Load plugin specific language pack tinymce.PluginManager.requireLangPack('imagelight'); tinymce.create('tinymce.plugins.ImagelightPlugin', { init : function(ed, url) { tinyMCE.activeEditor.execCommand('mceExample'); ed.addCommand('mceImagelight', function() { ed.windowManager.open({ file : '/Image', width : 480, height : 385, inline : 1 }, { plugin_url : url // Plugin absolute URL }); }); ed.addButton('imagelight', { title : 'imagelight.desc', cmd : 'mceImagelight', image : url + '/img/imagelight.png' }); ed.onNodeChange.add(function(ed, cm, n) { cm.setActive('imagelight', n.nodeName == 'IMG'); }); }, getInfo : function() { return { longname : 'Imagelight plugin', author : 'AldeFalco', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example', version : "1.0" }; } }); tinymce.PluginManager.add('imagelight', tinymce.plugins.ImagelightPlugin); })(); 


We transfer all the code from the script to
js / dialog.js

 tinyMCEPopup.requireLangPack(); var ImagelightDialog = { init: function () { var options = { dataType: "json", beforeSubmit: function (data) { $('#preview').attr('src', '/Content/images/spinning.gif'); }, success: function (data) { $('#preview').attr('src', '/Image/ById/' + data.Id); } }; $('#upload').ajaxForm(options); $('#preview').click(function () { $('#file').click(); }); }, insert : function() { // Insert the contents from the input into the document tinyMCEPopup.editor.execCommand('mceInsertContent', false, $('#image').html()); tinyMCEPopup.close(); } }; tinyMCEPopup.onInit.add(ImagelightDialog.init, ImagelightDialog); 


By the way, if you don’t migrate, then it won’t work - jquery and tinyMCEPopup have an initialization conflict.

For resource files, write:

 tinyMCE.addI18n('en.imagelight',{ desc : 'Light Image Uploader' }); tinyMCE.addI18n('en.imagelight_dlg',{ title : 'Upload image', preview : 'Preview', alt : 'Click here to upload an image file', }); 


Modify the view.
  <title>{#imagelight_dlg.title}</title> <script type="text/javascript" src="@Url.Content("~/Scripts/tiny_mce/plugins/imagelight/js/dialog.js")"></script> ... <div class="panel_wrapper"> <div id="general_panel" class="panel current"> <fieldset> <legend>{#imagelight_dlg.preview}</legend> <div id="image"><img id="preview" alt="{#imagelight_dlg.alt}" src="" /></div> <input id="file" type="file" name="file" onchange="$('#upload').submit();"/> </fieldset> </div> </div> <div class="mceActionPanel"> <input type="button" id="insert" name="insert" value="{#insert}" onclick="ImagelightDialog.insert();" /> <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" /> </div> } 


As a result, we have a fairly simple and easy loader. It took a couple of hours. The final result:





Source: https://habr.com/ru/post/120168/


All Articles