Commit 1335aa2f authored by ramez's avatar ramez Committed by Tim Graham
Browse files

Fixed #15760 -- Added JavaScript events for admin inline forms.

parent 65a1055a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -588,6 +588,7 @@ answer newbie questions, and generally made Django that much better:
    Rachel Willmer <http://www.willmer.com/kb/>
    Radek Švarz <http://www.svarz.cz/translate/>
    Rajesh Dhawan <rajesh.dhawan@gmail.com>
    Ramez Ashraf <ramezashraf@gmail.com>
    Ramiro Morales <ramiro@rmorales.net>
    Ram Rachum <ram@rachum.com>
    Randy Barlow <randy@electronsweatshop.com>
+2 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@
                    if (options.removed) {
                        options.removed(row);
                    }
                    $(document).trigger('formset:removed', [row, options.prefix]);
                    // Update the TOTAL_FORMS form count.
                    var forms = $("." + options.formCssClass);
                    $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
@@ -120,6 +121,7 @@
                if (options.added) {
                    options.added(row);
                }
                $(document).trigger('formset:added', [row, options.prefix]);
            });
        }
        return this;
+9 −9
Original line number Diff line number Diff line
(function(b){b.fn.formset=function(c){var a=b.extend({},b.fn.formset.defaults,c),f=b(this);c=f.parent();var k=function(a,e,l){var d=new RegExp("("+e+"-(\\d+|__prefix__))");e=e+"-"+l;b(a).prop("for")&&b(a).prop("for",b(a).prop("for").replace(d,e));a.id&&(a.id=a.id.replace(d,e));a.name&&(a.name=a.name.replace(d,e))},h=b("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(h.val(),10),e=b("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),d=""===e.val()||0<e.val()-h.val();
f.each(function(e){b(this).not("."+a.emptyCssClass).addClass(a.formCssClass)});if(f.length&&d){var m;"TR"===f.prop("tagName")?(f=this.eq(-1).children().length,c.append('<tr class="'+a.addCssClass+'"><td colspan="'+f+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),m=c.find("tr:last a")):(f.filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),m=f.filter(":last").next().find("a"));m.click(function(d){d.preventDefault();d=b("#"+a.prefix+
"-empty");var g=d.clone(!0);g.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);g.is("tr")?g.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):g.is("ul")||g.is("ol")?g.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):g.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></span>");g.find("*").each(function(){k(this,
a.prefix,h.val())});g.insertBefore(b(d));b(h).val(parseInt(h.val(),10)+1);l+=1;""!==e.val()&&0>=e.val()-h.val()&&m.parent().hide();g.find("a."+a.deleteCssClass).click(function(d){d.preventDefault();g.remove();--l;a.removed&&a.removed(g);d=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(d.length);(""===e.val()||0<e.val()-d.length)&&m.parent().show();var c,f,h=function(){k(this,a.prefix,c)};c=0;for(f=d.length;c<f;c++)k(b(d).get(c),a.prefix,c),b(d.get(c)).find("*").each(h)});a.added&&a.added(g)})}return this};
b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null};b.fn.tabularFormset=function(c){var a=b(this),f=function(l){b(a.selector).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")},k=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,e){var b=e.name.split("-");
SelectFilter.init(e.id,b[b.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){var d=b.name.split("-");SelectFilter.init(b.id,d[d.length-1],!0)}))},h=function(a){a.find(".prepopulated_field").each(function(){var e=b(this).find("input, select, textarea"),d=e.data("dependency_list")||[],c=[];b.each(d,function(b,e){c.push("#"+a.find(".field-"+e).find("input, select, textarea").attr("id"))});c.length&&e.prepopulate(c,e.attr("maxlength"))})};a.formset({prefix:c.prefix,addText:c.addText,formCssClass:"dynamic-"+
c.prefix,deleteCssClass:"inline-deletelink",deleteText:c.deleteText,emptyCssClass:"empty-form",removed:f,added:function(a){h(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();f(a)}});return a};b.fn.stackedFormset=function(c){var a=b(this),f=function(c){b(a.selector).find(".inline_label").each(function(a){a+=1;b(this).html(b(this).html().replace(/(#\d+)/g,"#"+a))})},k=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,
b){var d=b.name.split("-");SelectFilter.init(b.id,d[d.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){var d=b.name.split("-");SelectFilter.init(b.id,d[d.length-1],!0)}))},h=function(a){a.find(".prepopulated_field").each(function(){var c=b(this).find("input, select, textarea"),d=c.data("dependency_list")||[],f=[];b.each(d,function(b,c){f.push("#"+a.find(".form-row .field-"+c).find("input, select, textarea").attr("id"))});f.length&&c.prepopulate(f,c.attr("maxlength"))})};a.formset({prefix:c.prefix,
addText:c.addText,formCssClass:"dynamic-"+c.prefix,deleteCssClass:"inline-deletelink",deleteText:c.deleteText,emptyCssClass:"empty-form",removed:f,added:function(a){h(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();f(a)}});return a}})(django.jQuery);
(function(b){b.fn.formset=function(d){var a=b.extend({},b.fn.formset.defaults,d),e=b(this);d=e.parent();var k=function(a,f,l){var c=new RegExp("("+f+"-(\\d+|__prefix__))");f=f+"-"+l;b(a).prop("for")&&b(a).prop("for",b(a).prop("for").replace(c,f));a.id&&(a.id=a.id.replace(c,f));a.name&&(a.name=a.name.replace(c,f))},h=b("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(h.val(),10),f=b("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),c=""===f.val()||0<f.val()-h.val();
e.each(function(f){b(this).not("."+a.emptyCssClass).addClass(a.formCssClass)});if(e.length&&c){var m;"TR"===e.prop("tagName")?(e=this.eq(-1).children().length,d.append('<tr class="'+a.addCssClass+'"><td colspan="'+e+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),m=d.find("tr:last a")):(e.filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),m=e.filter(":last").next().find("a"));m.click(function(c){c.preventDefault();c=b("#"+a.prefix+
"-empty");var g=c.clone(!0);g.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);g.is("tr")?g.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):g.is("ul")||g.is("ol")?g.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):g.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></span>");g.find("*").each(function(){k(this,
a.prefix,h.val())});g.insertBefore(b(c));b(h).val(parseInt(h.val(),10)+1);l+=1;""!==f.val()&&0>=f.val()-h.val()&&m.parent().hide();g.find("a."+a.deleteCssClass).click(function(c){c.preventDefault();g.remove();--l;a.removed&&a.removed(g);b(document).trigger("formset:removed",[g,a.prefix]);c=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(c.length);(""===f.val()||0<f.val()-c.length)&&m.parent().show();var d,e,h=function(){k(this,a.prefix,d)};d=0;for(e=c.length;d<e;d++)k(b(c).get(d),a.prefix,
d),b(c.get(d)).find("*").each(h)});a.added&&a.added(g);b(document).trigger("formset:added",[g,a.prefix])})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null};b.fn.tabularFormset=function(d){var a=b(this),e=function(l){b(a.selector).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")},
k=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],!0)}))},h=function(a){a.find(".prepopulated_field").each(function(){var f=b(this).find("input, select, textarea"),c=f.data("dependency_list")||[],d=[];b.each(c,function(b,c){d.push("#"+a.find(".field-"+c).find("input, select, textarea").attr("id"))});
d.length&&f.prepopulate(d,f.attr("maxlength"))})};a.formset({prefix:d.prefix,addText:d.addText,formCssClass:"dynamic-"+d.prefix,deleteCssClass:"inline-deletelink",deleteText:d.deleteText,emptyCssClass:"empty-form",removed:e,added:function(a){h(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();e(a)}});return a};b.fn.stackedFormset=function(d){var a=b(this),e=function(d){b(a.selector).find(".inline_label").each(function(a){a+=1;b(this).html(b(this).html().replace(/(#\d+)/g,
"#"+a))})},k=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){var c=b.name.split("-");SelectFilter.init(b.id,c[c.length-1],!0)}))},h=function(a){a.find(".prepopulated_field").each(function(){var d=b(this).find("input, select, textarea"),c=d.data("dependency_list")||[],e=[];b.each(c,function(b,c){e.push("#"+a.find(".form-row .field-"+c).find("input, select, textarea").attr("id"))});
e.length&&d.prepopulate(e,d.attr("maxlength"))})};a.formset({prefix:d.prefix,addText:d.addText,formCssClass:"dynamic-"+d.prefix,deleteCssClass:"inline-deletelink",deleteText:d.deleteText,emptyCssClass:"empty-form",removed:e,added:function(a){h(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();e(a)}});return a}})(django.jQuery);
+3 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ Other topics

   actions
   admindocs
   javascript

.. seealso::

@@ -1882,6 +1883,8 @@ The :doc:`staticfiles app </ref/contrib/staticfiles>` prepends
``None``) to any asset paths. The same rules apply as :ref:`regular asset
definitions on forms <form-asset-paths>`.

.. _contrib-admin-jquery:

jQuery
~~~~~~

+75 −0
Original line number Diff line number Diff line
======================================
JavaScript customizations in the admin
======================================

.. _admin-javascript-inline-form-events:

Inline form events
==================

.. versionadded:: 1.9

You may want to execute some JavaScript when an inline form is added or removed
in the admin change form. The ``formset:added`` and ``formset:removed`` jQuery
events allow this. The event handler is passed three arguments:

* ``event`` is the ``jQuery`` event.
* ``$row`` is the newly added (or removed) row.
* ``formsetName`` is the formset the row belongs to.

The event is fired using the :ref:`django.jQuery namespace
<contrib-admin-jquery>`.

In your custom ``change_form.html`` template, extend the
``admin_change_form_document_ready`` block and add the event listener code:

.. code-block:: html+django

    {% extends 'admin/change_form.html' %}

    {% block admin_change_form_document_ready %}
    {{ block.super }}
    <script type="text/javascript">
    (function($) {
        $(document).on('formset:added', function(event, $row, formsetName) {
            if (formsetName == 'author_set') {
                // Do something
            }
        });

        $(document).on('formset:removed', function(event, $row, formsetName) {
            // Row removed
        });
    })(django.jQuery);
    </script>
    {% endblock %}

Two points to keep in mind:

* The JavaScript code must go in a template block if you are inheriting
  ``admin/change_form.html`` or it won't be rendered in the final HTML.
* ``{{ block.super }}`` is added because Django's
  ``admin_change_form_document_ready`` block contains JavaScript code to handle
  various operations in the change form and we need that to be rendered too.

Sometimes you'll need to work with ``jQuery`` plugins that are not registered
in the ``django.jQuery`` namespace. To do that, simply change how the code
listens for events. Instead of wrapping the listener in the ``django.jQuery``
namespace, just listen to the event triggered from there. For example:

.. code-block:: html+django

    {% extends 'admin/change_form.html' %}

    {% block admin_change_form_document_ready %}
    {{ block.super }}
    <script type="text/javascript">
        django.jQuery(document).on('formset:added', function(event, $row, formsetName) {
            // Row added
        });

        django.jQuery(document).on('formset:removed', function(event, $row, formsetName) {
            // Row removed
        });
    </script>
    {% endblock %}
Loading