2

I'm trying to create a single HTML page with multiple instances of TinyMCE editors. The number of editors varies by the request; so I can't enumerate them and initialize them individually. Here is my code:

views.py:

from tinymce.widgets import TinyMCE
class ThreadForm(forms.Form):
    subject = forms.CharField(max_length=300, widget=forms.TextInput(attrs={'size':'100'}))
    body = forms.CharField(widget=TinyMCE())
class MessageForm(forms.Form):
    thread_pk = forms.IntegerField()
    body = forms.CharField(widget=TinyMCE())

urls.py:

urlpatterns = patterns('',
    ...
    url(r'^tinymce/', include('tinymce.urls')),
)

settings.py:

INSTALLED_APPS = (
    ...
    'tinymce',
)
...
TINYMCE_DEFAULT_CONFIG = {
    'selector': 'textarea',
    'theme': 'advanced',
    'width': 600,
    'height': 300,
    'theme_advanced_toolbar_location': 'top',
    'theme_advanced_buttons1': 'bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,hr,|,undo,redo',
    'theme_advanced_buttons2': 'cut,copy,paste,pastetext,pasteword,|,search,replace,|,link,unlink,charmap,|,visualaid,table,|,blockquote,sub,sup,|,preview,code,emotions,image',
    'theme_advanced_buttons3': '',
    'plugins': 'paste,table,spellchecker,searchreplace,emotions',
    'theme_advanced_resizing': True,
}

member_forums.html:

...
{% block headers %}
{{ thread_form.media }}
{% endblock %}
...
<table id="new_thread_table">
    {{ thread_form.as_table }}
</table>
...
{% for message_form in message_forms %}
    <table class="new_message_table">
        {{ message_form.as_table }}
    </table>
    ...
{% endfor %}

There is one ThreadForm in the template and multiple MessageForms.

When I comment out the MessageForms in the HTML, the ThreadForm seems to work, but when I uncomment them, the ThreadForm loads with a TinyMCE skin that doesn't update (adding text doesn't make the undo button appear enabled even though it is), and when I submit the form, the body entry for the form is missing, resulting in form.is_valid failing.

I only have {{ thread_form.media }} in my template header and nothing for the MessageForms. Iterating through:

{% for message_form in message_forms %}
    {{ message_form.media }}
{% endfor %}

didn't do any good, either.

After doing some research, it appears TinyMCE is being initialized too many times when the MessageForms are loaded, causing the data to be lost during form submitting (EDIT in top answer to: TinyMCE with Django: "This field is required")

I'm lost on how to get this to work. Any help or pointers would be appreciated.

Community
  • 1
  • 1
Nagra
  • 466
  • 3
  • 8
  • Commenting out the thread_form makes the first message_form appear with the TinyMCE skin with no functionality and the same error when trying to submit data. – Nagra Apr 01 '14 at 06:55
  • Added a script at the top that simply calls tinyMCE.init({ theme: "advanced", }); Didn't make a difference when other forms are commented out. So maybe problem isn't that init is being called too many times? Seems the problem is just having more than one TinyMCE field. – Nagra Apr 01 '14 at 07:50

3 Answers3

1

Removed Django-TinyMCE and started using TinyMCE 4.0.21. It's working splendidly now.

views.py:

...
class ThreadForm(forms.Form):
    subject = forms.CharField(max_length=300, widget=forms.TextInput(attrs={'size':'100'}))
    body = forms.CharField(widget=forms.Textarea(attrs={'class':'thread'}))
...

member_forums.html:

...
{% block headers %}
<script type="text/javascript" src="{% static 'tinymce/tinymce.min.js' %}"></script>
<script type="text/javascript" src="{% static 'tinymce/threads.js' %}"></script>
{% endblock %}

{% block content %}
    ...
    <form id="new_thread_form" method="post" action="">
        {% csrf_token %}
        <table id="new_thread_table">
            {{ thread_form.as_table }}
        </table>
    </form>
    ...
    <form class="new_message_form" method="post" action="">
    {% csrf_token %}
    {% for message_form in message_forms %}
        {{ message_form.thread_pk }}
        <textarea class="message" name="body"></textarea>
    {% endfor %}
    ...
{% endblock %}

threads.js:

tinyMCE.init({
    selector: "textarea.thread",
    theme: "modern",
    ...
});

tinyMCE.init({
    selector: "textarea.message",
    theme: "modern",
    ...
});
Nagra
  • 466
  • 3
  • 8
0

TinyMCE uses id to assign which textarea should be TinyMCE, and ids are supposed to be unique in HTML. Since my bodies were both called body, Django's form.as_table was rendering them with the same id. When TinyMCE tried to assign the editor to the id, it failed when it reached the second field with the same id. Similar issue:

TinyMCE not working when loading two textareas

I changed the MessageForm.body to MessageForm.body1 and that made the ThreadForm TinyMCE work like a charm. Now I need to iterate through and change the id of each MessageForm. But there should be a better solution. TinyMCE should be able to render all textareas. Maybe removing ids altogether?

Community
  • 1
  • 1
Nagra
  • 466
  • 3
  • 8
  • 1
    No, you can change that by using `selector: textarea` in your TinyMCE configuration file. – xyres Apr 01 '14 at 09:15
  • I'll try setting 'selector': 'textarea' in my default TinyMCE config variable in settings.py and see if that makes a difference before trying my own solution. – Nagra Apr 01 '14 at 22:17
  • selector: textarea didn't change anything. The problem was that the ids were the same. ids are supposed to be unique. Dynamically assigning id fixed it. – Nagra Apr 02 '14 at 02:50
0

The solution below works for me. Apparently there is something wrong with the default javascript code of TinyCME.

With the current setting of your django and tinycme-django, you just need to add a js function to overwrite the default tinycme script.

Go to a .js file that is being loaded on your HTML page and add the function below:

(function ($) {
    function tinymce4_init(selector) {
        var tinymce4_config = { setup: function (editor) { editor.on('change', function () { editor.save(); }); }, "language": "en", "directionality": "ltr", "cleanup_on_startup": true, "custom_undo_redo_levels": 20, "selector": "textarea.tinymce4-editor", "theme": "modern", "plugins": "\n            textcolor save link image media preview codesample contextmenu\n            table code lists fullscreen  insertdatetime  nonbreaking\n            contextmenu directionality searchreplace wordcount visualblocks\n            visualchars code fullscreen autolink lists  charmap print  hr\n            anchor pagebreak\n            ", "toolbar1": "\n            fullscreen preview bold italic underline | fontselect,\n            fontsizeselect  | forecolor backcolor | alignleft alignright |\n            aligncenter alignjustify | indent outdent | bullist numlist table |\n            | link image media | codesample |\n            ", "toolbar2": "\n            visualblocks visualchars |\n            charmap hr pagebreak nonbreaking anchor |  code |\n            ", "contextmenu": "formats | link image", "menubar": true, "statusbar": true }; if (typeof selector != 'undefined') { tinymce4_config['selector'] = selector; }
        tinymce.init(tinymce4_config);
    }
    tinymce4_init();
})();

In the script above change the "selector": "textarea.tinymce4-editor" to match your own class/id/tag. This is a complete snippet with all the plugins etc.

for a simplified version you can use:

 tinyMCE.init({
     selector: "#id_blog-content",
     theme: "modern"
 });

Where the selector refers to the id/class/tag of your form.

@Nagra: In order to use unique ids for different forms on the same html page you can use a prefix for your form. this way each field of your form gets a unique id in this format:
id_{prefix}-{field name}.

I have unique ids for each form and selector: textarea. Yet it is not solving the issue.