RkBlog

Hardware, programming and astronomy tutorials and reviews.

nicEditor in Django

nicedit is a nice WYSIWYG editor that can be embedded in your pages. It also has two interesting features - BBCode editing and image uploading directly from the editor. In this article I'll show you how to install the editor and support local file uploading as well as BBCode support.

Installing the editor

  • Download NicEdit selecting additional modules if needed. For BBCode you need "nicBBCode", and for image upload - "nicUpload"
  • Unpack the zip file and move the files to your static media folder (usually site_media/). Next you can edit nicEdit.js and edit path in "iconsPath" setting it to a correct value, like in my case:
    iconsPath : '/site_media/nic/nicEditorIcons.gif',
  • Now we can use the editor in our application. Here is an example view:
    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)))
    
    And a template:
    <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>
    
  • This example shows a Django managed form. In the template we call nicEdit to change all textarea to WYSIWYG editor. If you submit the form with some text you will see that it will send a nice XHTML content. This is a very basic usage example. It looks bit like so:
    nicedit1

Uploading images to server

  • By default Image Upload uses ImageShack backend. Sometimes we want to store files on our server. We can easily configure NicEdit to upload them locally.
  • We start at with more specific configuration of nicEdit:
    <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 defines the URL which is used to upload images. I attached a Django view under that URL. buttonList defines options that show up in the editor. panelInstance runs the editor for textarea given by ID.
  • You can find the original PHP based upload handler on the project page. For Django I've made a simple view to handle those files:
    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)
    
  • This view must return a part of JavaScript code with data about uploaded image. The original script also supports progress notification, this one is much simpler. In this example images are uploaded to /tmp/ folder in site_media.

Edycja BBCode

nicEdit can also edit HTML content but return BBCode version of it. This can be used on discussion boards and other pages. To use BBCode output you have to pass bbCode: true in the nicEdit configuration. When you submit the form - it will send the BBCode version. To edit BBCode you have to parse it to X/HTML before sending it to the editor - using some Python based parser.

You can also use a simple function that supports the basic BBCodes. For example Django template tag:
from re import findall

from django import template
from django.conf import settings

register = template.Library()

def fbc(value):
	# strip HTML at start
	# here
	# 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)
RkBlog

Django web framework tutorials, 12 December 2010, Piotr Maliński

Comment article