PageRenderTime 61ms CodeModel.GetById 48ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/admin/media/js/inlines.js

https://code.google.com/p/mango-py/
JavaScript | 136 lines | 97 code | 0 blank | 39 comment | 24 complexity | cf876c9232ad1ea579bb021c8d8a9b36 MD5 | raw file
  1/**
  2 * Django admin inlines
  3 *
  4 * Based on jQuery Formset 1.1
  5 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
  6 * @requires jQuery 1.2.6 or later
  7 *
  8 * Copyright (c) 2009, Stanislaus Madueke
  9 * All rights reserved.
 10 *
 11 * Spiced up with Code from Zain Memon's GSoC project 2009
 12 * and modified for Django by Jannis Leidel
 13 *
 14 * Licensed under the New BSD License
 15 * See: http://www.opensource.org/licenses/bsd-license.php
 16 */
 17(function($) {
 18	$.fn.formset = function(opts) {
 19		var options = $.extend({}, $.fn.formset.defaults, opts);
 20		var updateElementIndex = function(el, prefix, ndx) {
 21			var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
 22			var replacement = prefix + "-" + ndx;
 23			if ($(el).attr("for")) {
 24				$(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
 25			}
 26			if (el.id) {
 27				el.id = el.id.replace(id_regex, replacement);
 28			}
 29			if (el.name) {
 30				el.name = el.name.replace(id_regex, replacement);
 31			}
 32		};
 33		var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
 34		var nextIndex = parseInt(totalForms.val());
 35		var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off");
 36		// only show the add button if we are allowed to add more items,
 37        // note that max_num = None translates to a blank string.
 38		var showAddButton = maxForms.val() == '' || (maxForms.val()-totalForms.val()) > 0;
 39		$(this).each(function(i) {
 40			$(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
 41		});
 42		if ($(this).length && showAddButton) {
 43			var addButton;
 44			if ($(this).attr("tagName") == "TR") {
 45				// If forms are laid out as table rows, insert the
 46				// "add" button in a new table row:
 47				var numCols = this.eq(0).children().length;
 48				$(this).parent().append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="javascript:void(0)">' + options.addText + "</a></tr>");
 49				addButton = $(this).parent().find("tr:last a");
 50			} else {
 51				// Otherwise, insert it immediately after the last form:
 52				$(this).filter(":last").after('<div class="' + options.addCssClass + '"><a href="javascript:void(0)">' + options.addText + "</a></div>");
 53				addButton = $(this).filter(":last").next().find("a");
 54			}
 55			addButton.click(function() {
 56				var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
 57				var template = $("#" + options.prefix + "-empty");
 58				var row = template.clone(true);
 59				row.removeClass(options.emptyCssClass)
 60				    .addClass(options.formCssClass)
 61				    .attr("id", options.prefix + "-" + nextIndex);
 62				if (row.is("tr")) {
 63					// If the forms are laid out in table rows, insert
 64					// the remove button into the last table cell:
 65					row.children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
 66				} else if (row.is("ul") || row.is("ol")) {
 67					// If they're laid out as an ordered/unordered list,
 68					// insert an <li> after the last list item:
 69					row.append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
 70				} else {
 71					// Otherwise, just insert the remove button as the
 72					// last child element of the form's container:
 73					row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
 74				}
 75				row.find("*").each(function() {
 76					updateElementIndex(this, options.prefix, totalForms.val());
 77				});
 78				// Insert the new form when it has been fully edited
 79				row.insertBefore($(template));
 80				// Update number of total forms
 81				$(totalForms).val(parseInt(totalForms.val()) + 1);
 82				nextIndex += 1;
 83				// Hide add button in case we've hit the max, except we want to add infinitely
 84				if ((maxForms.val() != '') && (maxForms.val()-totalForms.val()) <= 0) {
 85					addButton.parent().hide();
 86				}
 87				// The delete button of each row triggers a bunch of other things
 88				row.find("a." + options.deleteCssClass).click(function() {
 89					// Remove the parent form containing this button:
 90					var row = $(this).parents("." + options.formCssClass);
 91					row.remove();
 92					nextIndex -= 1;
 93					// If a post-delete callback was provided, call it with the deleted form:
 94					if (options.removed) {
 95						options.removed(row);
 96					}
 97					// Update the TOTAL_FORMS form count.
 98					var forms = $("." + options.formCssClass);
 99					$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
100					// Show add button again once we drop below max
101					if ((maxForms.val() == '') || (maxForms.val()-forms.length) > 0) {
102						addButton.parent().show();
103					}
104					// Also, update names and ids for all remaining form controls
105					// so they remain in sequence:
106					for (var i=0, formCount=forms.length; i<formCount; i++)
107					{
108						updateElementIndex($(forms).get(i), options.prefix, i);
109						$(forms.get(i)).find("*").each(function() {
110							updateElementIndex(this, options.prefix, i);
111						});
112					}
113					return false;
114				});
115				// If a post-add callback was supplied, call it with the added form:
116				if (options.added) {
117					options.added(row);
118				}
119				return false;
120			});
121		}
122		return this;
123	}
124	/* Setup plugin defaults */
125	$.fn.formset.defaults = {
126		prefix: "form",					// The form prefix for your django formset
127		addText: "add another",			// Text for the add link
128		deleteText: "remove",			// Text for the delete link
129		addCssClass: "add-row",			// CSS class applied to the add link
130		deleteCssClass: "delete-row",	// CSS class applied to the delete link
131		emptyCssClass: "empty-row",		// CSS class applied to the empty row
132		formCssClass: "dynamic-form",	// CSS class applied to each form in a formset
133		added: null,					// Function called each time a new form is added
134		removed: null					// Function called each time a form is deleted
135	}
136})(django.jQuery);