A plug-in for fast image loading in MarkItUp

Let's talk about writing a plug-in for the markItUp WYSIWYG editor. The task of the plug-in should be quick and easy loading of images to the server to be inserted into a text afterwards (in the form of img tag).
t all started with the ticket «Upload images in markItUp». Search of ordinary turnkey solutions led almost to nothing. The only solution that worked – was the plug-in https://gist.github.com/783934, but it does have a few drawbacks:
- Many dependencies from «extra» jQuery plugins.
- Too bulky JS and CSS.
Well, we could either alter (or simplify) this plug-in or write our own. After starting to go the first way, I almost insensibly moved to the second one and eventually this JS code appeared:
var InlineUpload = { dialog: null, options: { form_class: 'inline_upload_form', // class form action: '/posts/upload', // URL to which the POST with downloaded file will be send iframe: 'inline_upload_iframe' // name of the iframe }, display: function(hash) { // method that assumes a click on the button in markItUp var self = this; this.dialog = $(document).find(".inline_upload_container"); if (!this.dialog.size()) { // there is no DOM in our hidden div, let’s create it // the form with iframe inside an invisible div and attach it to the body this.dialog = $([ '<div style="opacity:0;position:absolute;" class="inline_upload_container"><form class="',this.options.form_class,'" action="',this.options.action,'" target="',this.options.iframe,'" method="post" enctype="multipart/form-data">', '<input name="form[inlineUploadFile]" type="file" /></form>' + '<iframe id="',this.options.iframe,'" name="',this.options.iframe,'" class="',this.options.iframe,'" src="about:blank" width="0" height="0"></iframe></div>', ].join('')); this.dialog.appendTo(document.body); } // Do click on the input [type = file]in the hidden div'e // to show the system dialog of the file selection $("input[name='form[inlineUploadFile]']").focus(); // Hack for chrome and others $("input[name='form[inlineUploadFile]']").trigger('click'); // After the file has been selected, we send our hidden form to the server $("input[name='form[inlineUploadFile]']").live('change', function(){ if ($(this).val() != '') { // if the file was not selected, nothing terrible would happen $('.' + self.options.form_class).submit(); } }); // The answer will be given in a hidden iframe $('.' + this.options.iframe).bind('load', function() { var responseJSONStr = $(this).contents().find('body').html(); if (responseJSONStr != '') { // server returned us the answer, so we are to parse it var response = $.parseJSON(responseJSONStr); if (response.status == 'success') { // if all is well var block = ['<img src="' + response.src + '" width="' + response.width + '" height="' + response.height + '" alt="" class=""/>']; $.markItUp({replaceWith: block.join('')} ); // Add the img tag to the text } else { alert(response.msg); // got an error message } self.cleanUp(); // cleanUp() removes a hidden div with the form and iframe out of the DOM } }); }, cleanUp: function() { $("input[name='form[inlineUploadFile]']").die('change'); this.dialog.remove(); } };
To connect our plug-in, you need to add a new button to setup of markItUp panels:
{ name:'PictureUpload', key:'P', beforeInsert: function(markItUp) { InlineUpload.display(markItUp) } },
And on the side of the backend we need to add a handler for files uploading (an example of action for Symfony2):
/** * Upload photo * * @return string * @Route("/posts/upload", name="blog_post_upload_image") * @Method({"POST"}) */ public function uploadImageAction() { // Create a validator $collectionConstraint = new Collection(array( 'inlineUploadFile' => new Image(array('mimeTypes' => array("image/png", "image/jpeg", "image/gif"))), )); // Create "on the fly" the form with our validator $form = $this->createFormBuilder(null, array( 'csrf_protection' => false, 'validation_constraint' => $collectionConstraint )) ->add('inlineUploadFile', 'file') ->getForm(); $form->bindRequest($this->get('request')); if ($form->isValid()) { // File processing $file = $form->get('inlineUploadFile')->getData(); $ext = $file->guessExtension(); if ($ext == '') { $response = array( 'msg' => 'A file seems a bit suspicious! I do not want to accept it.', ); } else { //Save the file $uploadDir = realpath($this->get('kernel')->getRootDir() . '/../web/uploads/images'); $newName = uniqid() . '.' . $ext; $file->move($uploadDir, $newName); $info = getImageSize($uploadDir . '/' . $newName); //Return such an answer, if all is well $response = array( 'status' => 'success', 'src' => '/uploads/images/' . $newName, 'width' => $info[0], 'height' => $info[1], ); } } else { // Return such an answer if everything is bad $response = array( 'msg' => 'Your file is not valid!', ); } return new Response(json_encode($response)); }
This way we got the easiest to use plug-in. A user by clicking the icon of the picture immediately receives a file selection dialog, and after selecting has a ready line in the editor.
This example is very simple. If you wish, it can be more difficult, for example, instead of hidden forms - to show it in the dialogue, sending the server a few pictures, etc.