RichTextField
An attempt at integrating TinyMCE completely as its own field that has the capability to save a copy as UTF-8 in another field for searchability.
Adding the field type
project_dir/local_models.py
from django.utils.html import escape
from django.forms import LargeTextField
from django.db.models.fields import Field
from django.dispatch import dispatcher
from django.db.models import signals
from django.conf import settings
class TextFieldWithClass(LargeTextField):
def __init__(self, css_class='', plaintext_field=None, *args, **kwargs):
self.css_class, self.plaintext_field = css_class, plaintext_field
LargeTextField.__init__(self, *args, **kwargs)
def render(self, data):
if data is None:
data = ''
if isinstance(data, unicode):
data = data.encode(settings.DEFAULT_CHARSET)
css_class = ''
if self.css_class != '':
css_class = ' ' + self.css_class
return '<textarea id="%s" class="v%s%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \
(self.get_id(), self.__class__.__name__, self.is_required and ' required' or '',
css_class, self.field_name, self.rows, self.cols, escape(data))
class RichTextFieldWithClass(Field):
def __init__(self, css_class='', plaintext_field=None, *args, **kwargs):
self.css_class, self.plaintext_field = css_class, plaintext_field
Field.__init__(self, *args, **kwargs)
def set_plaintext_field(self, instance=None):
from genshi.core import Markup
plain = Markup(getattr(instance, self.attname)).striptags().stripentities().encode('utf-8')
setattr(instance, self.plaintext_field, plain)
def contribute_to_class(self, cls, name):
super(RichTextFieldWithClass, self).contribute_to_class(cls, name)
if self.plaintext_field:
dispatcher.connect(self.set_plaintext_field, signals.pre_save, sender=cls)
def prepare_field_objs_and_params(self, manipulator, name_prefix):
field_objs, params = super(RichTextFieldWithClass, self).prepare_field_objs_and_params(manipulator, name_prefix)
params['css_class'], params['plaintext_field'] = self.css_class, self.plaintext_field
return (field_objs, params)
def get_manipulator_field_objs(self):
return [TextFieldWithClass]
def get_internal_type(self):
return 'TextField'
Adding the necessary javascript
Download and unpack TinyMCE so tiny_mce.js ends up here: /media/js/tinymce/jscripts/tiny_mce/tiny_mce.js
Remember this javascript must be on the same domain as the admin or it won't work.
/media/js/tmce.js
tinyMCE.init({
mode : "specific_textareas", // only specific textareas
editor_selector : "mceEditor", // specified by the mceEditor class
theme : "advanced",
plugins : "table,save,advhr,advimage,advlink",
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,sub,sup,removeformat,charmap,separator,justifyleft,justifycenter,justifyright,bullist,numlist,outdent,indent,separator,formatselect,styleselect,code",
theme_advanced_buttons2 : "cut,copy,paste,separator,search,replace,image,link,anchor,separator,tablecontrols",
theme_advanced_buttons3 : "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_path_location : "bottom",
theme_advanced_styles : "Left=left;Right=right;", // possible classes
content_css : "/media/js/tmce.css", // add css styles
plugin_insertdate_dateFormat : "%Y-%m-%d",
plugin_insertdate_timeFormat : "%H:%M:%S",
extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
width : "640", height : "350" // set size of field
});
Using the field in the model
project_dir/appdir/models.py
from django.db import models
from local_models import RichTextFieldWithClass
class Page(models.Model):
label = models.CharField(maxlength=255)
text = RichTextFieldWithClass(css_class='mceEditor', plaintext_field='plaintext')
plaintext = models.TextField() # optional optional argument, requires genshi from edgewall
def __repr__(self):
return self.label
class Admin:
js=['../js/tinymce/jscripts/tiny_mce/tiny_mce.js', '../js/tmce.js']
