Integracja NicEdit z Django

Integrujemy funkcjonalności edytora WYSIWYG NicEdit z aplikacją Django

nicedit to fajny edytor Wysiwyg posiadający kilka ciekawych możliwości. Można wykorzystywać go jako wizualny edytor BBCode stosowanego głównie na forach dyskusyjnych. Posiada też moduł przesyłania zdjęć na serwer - domyślnie zdalnie na imageshack, choć można także zintegrować własną aplikację do obsługi przesyłania plików. Niniejszy artykuł zaprezentuje integrację Nicedita z Django.

Instalacja edytora

  • Pobieramy NicEdit zaznaczając dodatkowe moduły. Do obsługi BBCode potrzeba "nicBBCode", a przesyłania grafik - "nicUpload"
  • Rozpakowujemy paczkę i przenosimy pliki do katalogu na pliki statyczne (zazwyczaj site_media). Następnie edytujemy nicEdit.js i poprawiamy ścieżkę "iconsPath", np:
    iconsPath : '/site_media/nic/nicEditorIcons.gif',
  • Teraz możemy wykorzystać edytor w naszej aplikacji. Prosty widok z formularzem wygląda tak:
    class TestForm(forms.Form):
    	txt = forms.CharField(widget=forms.Textarea)
    
    def show_nicedit(request):
    	form = TestForm()
    	if request.POST:
    		form = TestForm(request.POST)
    		if form.is_valid():
    			print form.cleaned_data['txt']
    		else:
    			print form.errors
    	return render_to_response('show_nicedit.html', {'form': form}, context_instance=RequestContext(request, userpanelContext(request)))
    
    Oraz szablon:
    <script src="/site_media/nic/nicEdit.js" type="text/javascript"></script>
    <script type="text/javascript">bkLib.onDomLoaded(nicEditors.allTextAreas);</script>
    <form method="post" action="./">{% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="Submit" />
    </form>
    
  • Powyższy przykład wyświetla prosty standardowy formularz obsługiwany przez Django. W szablonie wywołujemy nicEdit by zamienił wszystkie pola textarea na edytor. Wystarczy wpisać jakąś zawartość w formularzu i wysłać go. W konsoli (serwer deweloperski) zobaczymy kod HTML zwrócony przez edytor.
  • Nasz edytor działa i wygląda mniej więcej tak:
    nicedit1

Przesyłanie grafik na serwer

  • Nie podając żadnej konfiguracji wyświetlane są wszystkie dostępne elementy interfejsu. "Image Upload" pozwala na załadowanie fotografii do ImageShack. Czasami jednak przydaje się zapisywanie grafik na naszym serwerze.
  • Domyślnie nicEdit wysyła grafikę na własny serwer przekazujący je na ImageShack. Własny adres podajemy w konfiguracji, np:
    <script type="text/javascript">
    $(document).ready(function()
    	{
            new nicEditor({uploadURI: '/user/wysiwyg_post/', buttonList : ['bold','italic','underline', 'left', 'center', 'right', 'justify', 'fontSize', 'image', 'upload', 'link', 'unlink'], xHtml: true}).panelInstance('id_txt');
            });
    </script>
    
  • uploadURI określa adres URL ładowania grafik. W powyższym przykładzie podałem lokalny, pod który podepnę widok Django. buttonList pozwala określić dostępne opcje. panelInstance uruchamia edytor dla textarea o podanym ID.
  • Oryginalny skrypt odbierający grafiki, napisany w PHP dostępny jest na stronie projektu. W przypadku Django potrzebujemy odpowiedniego widoku. Najprostsza wersja wygląda tak:
    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def wysiwyg_post(request):
    	"""
    	Handle posting from WYSIWYG
    	"""
    	if 'nicImage' in request.FILES:
    		msg = """<script>        try {
    			top.nicUploadButton.statusCb(%s);
    		    } catch(e) { alert(e.message); }
    		    </script>"""
    		file = request.FILES['nicImage'].read()
    		# make a filename
    		fname = ''.join([choice('1234567890qwertyuiopasdfghjklzxcvbnm') for i in range(5)])
    		fname = '%s_%s' % (str(request.user), fname)
    		x = open(settings.MEDIA_ROOT + '/tmp/%s.jpg' % fname, 'wb')
    		x.write(file)
    		x.close()
    		ff = '/tmp/%s.jpg' % fname
    		
    		# return the file url, size etc.
    		ret = {"noprogress": True, "done": 1, "width": "200", "url": "/site_media/tmp/%s.jpg" % fname}
    		ret = json.dumps(ret)
    		return HttpResponse(msg % ret)
    	
    	msg = """<script>        try {
                nicUploadButton.statusCb('%s');
            } catch(e) { alert(e.message); }
    	</script>"""
    	ret = {"noprogress": True}
    	ret = json.dumps(ret)
    	return HttpResponse(msg % ret)
    
  • Ogólnie musimy zwrócić odpowiedni skrypt JS zawierający dane o przesłanym pliku. Oryginał obsługuje pasem postępu przesyłania. W powyższej wersji zostało to pominięte. Teraz ładując grafikę przez edytor - trafi ona do site_media/tmp/.

Edycja BBCode

Kolejną przydatną funkcjonalnością jest obsługa BBCode. Edytor renderuje treść HTML lecz zwaraca ją w postaci BBCode. By uruchomić tą opcję wystarczy dodać bbCode: true w konfiguracji edytora w szablonie. Wysyłając formularz z treścią zobaczymy że treść została wysłana ze znacznikami BBCode. By umożliwić edycję treści z takimi znacznikami musimy je sparsować do postaci XHTML przed przekazaniem do edytora.

Do parsowania BBCode trzeba użyć jakiegoś parsera napisanego w Pythonie, lub samemu napisać prostą funkcję, np w postaci taga szablonów Django:
from re import findall

from django import template
from django.conf import settings

register = template.Library()

def fbc(value):
	# strip HTML at start
	# then:
	value = value.replace("'", '&#39;').replace('"', '&#34;')
	
	tags = findall( r'(?xs)\[url=(.*?)\](.*?)\[/url]''', value)
	for i in tags:
		value = value.replace('[url=%s]%s[/url]' % (i[0], i[1]), '<a href="%s">%s</a>' % (i[0].replace('"', ''), i[1]))
	
	value = value.replace('[b]', '<b>')
	value = value.replace('[/b]', '</b>')
	value = value.replace('[i]', '<i>')
	value = value.replace('[/i]', '</i>')
	value = value.replace('[u]', '<u>')
	value = value.replace('[/u]', '</u>')
	value = value.replace('[quote]', '<blockquote>')
	value = value.replace('[/quote]', '</blockquote>')
	value = value.replace('[url]', '')
	value = value.replace('[/url]', '')
	value = value.replace('
', '<br />')
	
	tags = findall( r'(?xs)\[img\](.*?)\[/img]''', value)
	for i in tags:
		if not len(i) < 3:
			value = value.replace('[img]%s[/img]' % i, '<img src="%s" alt="" />' % i)
	
	return value

register.filter('fbc', fbc)
blog comments powered by Disqus

Kategorie

Strony