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 markItUpvar 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 bodythis.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 itvar response = $.parseJSON(responseJSONStr);if(response.status=='success'){// if all is wellvar 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"})
 */publicfunction 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!',);}
 
    returnnew 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.