Django Grappelli表格内联添加新行TinyMCE文本字段不可编辑

时间:2011-04-21 00:28:54

标签: django django-admin tinymce django-tinymce django-grappelli

我正在为我的项目使用django Grappelli皮肤。

我有一个带有表格内联函数的ModelAdmin。

我在页面加载时使用extra = 0来防止自动插入空白行。它工作正常。

现在,当我点击+号以插入新行时,该行已加载,但是tinymce文本字段不可编辑。

任何人都知道是什么原因以及如何解决这个问题?

阅读文件后:

http://django-grappelli.readthedocs.org/en/latest/customization.html#using-tinymce

我注意到:

由于隐藏的空格式,将TinyMCE与Inlines一起使用会有点棘手。您需要编写自定义模板并使用内联回调

onInit:从空格式中删除TinyMCE实例。

onAfterAdded:从表单初始化TinyMCE实例。

onBeforeRemoved:从表单中删除TinyMCE实例。

默认情况下不支持带Inlines的TinyMCE。

这样的样品?我注意到我需要更改它是一个TinyMCE功能。

2 个答案:

答案 0 :(得分:14)

看起来Grappelli使用的一些CSS类和HTML结构自Almflm的解决方案编写以来发生了变化。但是,我能够修改hir解决方案以使用Grappelli v2.4.7,并简化了流程中的实现。

<强>设置

  1. 通过将/PATH/TO/grappelli/templates/admin/edit_inline/stacked.html复制到/PATH/TO/YOURMOD/templates/admin/edit_inline/
  2. 来覆盖相关模板
  3. 在您网站的settings.py中,确保INSTALLED_APPS中的YOURMOD 否则,Django将继续使用模板的Grappelli版本。
  4. <强>代码

    现在您只需要对stacked.html的副本进行两处更改。找到开始的javascript块:

    $("#{{ inline_admin_formset.formset.prefix }}-group").grp_inline({
    

    ...并在该区块内进行以下更改:

    1. 像这样添加onBeforeAdded函数(或修改现有函数,如果存在,但我没有):

          onBeforeAdded:function(form) {
              // New inlines start as a hidden template with class grp-empty-form.
              // This contains a textarea, which TinyMCE converts correctly, but
              // something about the transformation from template to visible 
              // form breaks TinyMCE, so we need to remove it from the template and 
              // then re-add it after the transformation. 
              // c.f. http://stackoverflow.com/questions/5738173/
              if (tinyMCE != undefined) {
                  django.jQuery('.grp-empty-form').find('textarea').each(function() { 
                      var tid = django.jQuery(this).attr("id");
                      tinyMCE.execCommand("mceRemoveControl",false,tid); 
                  });
              }
          },
      
    2. 将以下内容添加到onAfterAdded函数中(您应该已经有一个,所以请务必修改现有函数而不是定义新函数!):

              if (tinyMCE != undefined) {
                // re-initialise tinyMCE instances
                deselector = tinyMCE.settings.editor_deselector;
                django.jQuery(form).find('textarea:not(.'+deselector+')').each(function(k,v) {
                  var tid = django.jQuery(this).attr('id');
                  tinyMCE.execCommand('mceAddControl', false, tid);
                });
              }
              // This line is optional. It just ensures that the new inline appears
              // un-collapsed, even if inlines are collapsed by default
              django.jQuery(form).removeClass("grp-closed").addClass("grp-open");
      
    3. 就是这样!

      修改onAfterLoad中添加了deselector - 确保您仍然可以在tinymce配置文件中定义一个deselector类,并且内联将符合这一点。

答案 1 :(得分:4)

我没有时间更彻底地研究这个,所以我很确定有更好的解决方案,但这似乎对我有用(用 django-grappelli 2.3.5测试 django-tinymce 1.5.1a2

我假设你正在使用堆叠内联。

您必须覆盖grappelli templates/admin/edit_inline/stacked.html的模板。 在inline_admin_formset|formsetsort:sortable_field_name的for循环迭代中,在嵌套的for循环迭代inline_admin_form之后,添加此代码段:

{% if forloop.last %}
  <script type="text/javascript">
    if (tinyMCE != undefined) {
      django.jQuery('textarea', '.empty-form').each(function() {
        tinyMCE.execCommand('mceRemoveControl', false, django.jQuery(this).attr('id'));
      });
    }
  </script>
{% endif %}

它应该为隐藏的“空格式”中的textarea元素禁用tinyMCE控件,并通过为tinyMCE小部件呈现的内联javascript进行初始化。

在原始grappelli模板中第133行的某处,您会看到grp_inline()的调用。添加/修改参数:

$("#{{ inline_admin_formset.formset.prefix }}-group").grp_inline({
  prefix: "{{ inline_admin_formset.formset.prefix }}",
  onBeforeRemoved: function(f) {
    if (tinyMCE != undefined) {
      // make sure tinyMCE instances in empty-form are inactive
      django.jQuery('textarea', '.empty-form').each(function() {
        tinyMCE.execCommand('mceRemoveControl', false, django.jQuery(this).attr('id'));
      });
    }
  },
  [...]
  onAfterAdded: function(form) {
    if (tinyMCE != undefined) {
      // re-initialise tinyMCE instances
      $('textarea', form).each(function(k,v) {
        var tid = $(this).attr('id');
        tinyMCE.execCommand('mceRemoveControl', false, tid);
        tinyMCE.execCommand('mceAddControl', false, tid);
      });
      // make sure tinyMCE instances in empty-form are inactive
      django.jQuery('textarea', '.empty-form').each(function() {
        tinyMCE.execCommand('mceRemoveControl', false, django.jQuery(this).attr('id'));
      });
    }
    [...]
  }
  [...]

如果您使用sortables,您还需要在被拖动的内联的textareas上禁用tinyMCE控件。查找sortable()初始化,并修改'start'回调:

start: function(evt, ui) {
  ui.placeholder.height(ui.item.height() + 12);
  if (tinyMCE != undefined) {
    // make sure tinyMCE instances in empty-form are inactive
    $('textarea', ui.item).each(function(k,v) {
      var tid = $(this).attr('id');
      tinyMCE.execCommand('mceRemoveControl', false, tid);
    });
  }
},
[...]

这应该可以大致了解如何解决这个棘手的问题......