
Поговоримо про написання плагіна для WYSIWYG-редактора markItUp. Завдання плагіна повинно полягати в швидкому та легкому завантаженні зображень на сервер, щоб їх можна було вставити в текст пізніше (у формі тегу img).
Все почалося з запиту «Завантаження зображень у markItUp». Пошук звичайних готових рішень майже ні до чого не призвів. Єдине рішення, яке спрацювало – це плагін https://gist.github.com/783934, але у нього є кілька недоліків:
- Багато залежностей від «додаткових» плагінів jQuery.
- Занадто громіздкі JS та CSS.
Отже, ми могли або змінити (або спростити) цей плагін, або написати свій. Після початку роботи в перший спосіб, я майже непомітно перейшов до другого і в результаті з'явився цей JS-код:
var InlineUpload ={ dialog:null, options:{ form_class:'inline_upload_form',// клас форми action:'/posts/upload',// URL, на який буде надіслано POST із завантаженим файлом iframe:'inline_upload_iframe'// ім'я iframe}, display:function(hash){// метод, який передбачає клік на кнопку в markItUpvar self =this; this.dialog= $(document).find(".inline_upload_container"); if(!this.dialog.size()){// в нашому прихованому div немає DOM, давайте створимо його// форма з iframe всередині невидимого div та прикріпимо її до тіла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);} // Виконуємо клік на input [type = file] у прихованому div// щоб показати системний діалог вибору файлу $("input[name='form[inlineUploadFile]']").focus();// Хак для chrome та інших $("input[name='form[inlineUploadFile]']").trigger('click'); // Після вибору файлу, ми надсилаємо нашу приховану форму на сервер $("input[name='form[inlineUploadFile]']").live('change',function(){if($(this).val()!=''){// якщо файл не було вибрано, нічого страшного не станеться $('.'+ self.options.form_class).submit();}}); // Відповідь буде надана у прихованому iframe $('.'+this.options.iframe).bind('load',function(){var responseJSONStr = $(this).contents().find('body').html();if(responseJSONStr !=''){// сервер повернув нам відповідь, отже, ми повинні її розпарситиvar response = $.parseJSON(responseJSONStr);if(response.status=='success'){// якщо все гараздvar block =['<img src="'%20+%20response.src%20+%20'" width="'+ response.width+'" height="'+ response.height+'" alt="" class="">']; $.markItUp({replaceWith: block.join('')});// Додаємо тег img до тексту}else{ alert(response.msg);// отримали повідомлення про помилку} self.cleanUp();// cleanUp() видаляє прихований div з формою та iframe з DOM}});}, cleanUp:function(){ $("input[name='form[inlineUploadFile]']").die('change');this.dialog.remove();}};
Щоб підключити наш плагін, вам потрібно додати нову кнопку до налаштувань панелей markItUp:
{ name:'PictureUpload', key:'P', beforeInsert:function(markItUp){ InlineUpload.display(markItUp)}},
А на стороні бекенду нам потрібно додати обробник для завантаження файлів (приклад дії для Symfony2):
/** * Завантажити фото * * @return string * @Route("/posts/upload", name="blog_post_upload_image") * @Method({"POST"}) */publicfunction uploadImageAction(){// Створити валідатор$collectionConstraint=new Collection(array('inlineUploadFile'=>new Image(array('mimeTypes'=>array("image/png","image/jpeg","image/gif"))),)); // Створити "на льоту" форму з нашим валідатором$form=$this->createFormBuilder(null,array('csrf_protection'=>false,'validation_constraint'=>$collectionConstraint))->add('inlineUploadFile','file')->getForm(); $form->bindRequest($this->get('request'));if($form->isValid()){// Обробка файлу$file=$form->get('inlineUploadFile')->getData();$ext=$file->guessExtension(); if($ext==''){$response=array('msg'=>'Файл виглядає трохи підозріло! Я не хочу його приймати.',);}else{// Зберегти файл$uploadDir=realpath($this->get('kernel')->getRootDir().'/../web/uploads/images');$newName=uniqid().'.'.$ext;$file->move($uploadDir,$newName);$info=getImageSize($uploadDir.'/'.$newName); // Повернути таку відповідь, якщо все добре$response=array('status'=>'успіх','src'=>'/uploads/images/'.$newName,'width'=>$info[0],'height'=>$info[1],);}}else{// Повернути таку відповідь, якщо все погано$response=array('msg'=>'Ваш файл недійсний!',);} returnnew Response(json_encode($response));}
Таким чином, ми отримали найпростіший у використанні плагін. Користувач, натискаючи на іконку зображення, одразу отримує діалог вибору файлу, а після вибору має готовий рядок в редакторі.
Цей приклад дуже простий. Якщо бажаєте, його можна ускладнити, наприклад, замість прихованих форм - показати їх у діалозі, надіславши серверу кілька зображень тощо.