diff --git a/2017.pycon-au.org.conf b/2017.pycon-au.org.conf index f3240105eae8292e6cd9195d28bb1c0811599803..89f51e39b5bf78f4054d8b4eb14150eb65a25b27 100644 --- a/2017.pycon-au.org.conf +++ b/2017.pycon-au.org.conf @@ -1,4 +1,4 @@ -WSGIPythonPath /srv/http/2017.pycon-au.org/symposion/website:/srv/http/2017.pycon-au.org/symposion/lib/python2.7/site-packages +WSGIPythonPath /srv/http/2017.pycon-au.org/symposion/website:/srv/http/2017.pycon-au.org/symposion/lib/python2.7/site-packages:/srv/http/2017.pycon-au.org/symposion/lib/python2.7 ServerAdmin webmaster@pycon-au.org @@ -9,6 +9,7 @@ WSGIPythonPath /srv/http/2017.pycon-au.org/symposion/website:/srv/http/2017.pyco Alias /site_media/static/pyconau2017/ /srv/http/2017.pycon-au.org/symposion/website/static/dist/pyconau2017/ Alias /site_media/static/admin/ /srv/http/2017.pycon-au.org/symposion/lib/python2.7/site-packages/django/contrib/admin/static/admin/ + Alias /site_media/static/wagtailadmin/ /srv/http/2017.pycon-au.org/symposion/lib/python2.7/site-packages/wagtail/wagtailadmin/static/wagtailadmin/ @@ -17,7 +18,7 @@ WSGIPythonPath /srv/http/2017.pycon-au.org/symposion/website:/srv/http/2017.pyco # Require all granted - WSGIDaemonProcess 2017.pycon-au.org python-path="/srv/http/2017.pycon-au.org/symposion/website:/srv/http/2017.pycon-au.org/symposion/lib/python2.7/site-packages" home=/srv/http/2017.pycon-au.org/symposion/website user=nicks group=www-data + WSGIDaemonProcess 2017.pycon-au.org python-path="/srv/http/2017.pycon-au.org/symposion/website:/srv/http/2017.pycon-au.org/symposion/lib/python2.7/site-packages:/srv/http/2017.pycon-au.org/symposion/lib/python2.7" home=/srv/http/2017.pycon-au.org/symposion/website user=nicks group=www-data WSGIProcessGroup 2017.pycon-au.org diff --git a/static/dist/js/jquery.formset.js b/static/dist/js/jquery.formset.js new file mode 100644 index 0000000000000000000000000000000000000000..5e8d8b547e07242125d1fba7dca96bb39ee388ba --- /dev/null +++ b/static/dist/js/jquery.formset.js @@ -0,0 +1,210 @@ +/** +* Django formset helper +*/ +(function($) { + "use strict"; + + var pluginName = 'formset'; + + /** + * Wraps up a formset, allowing adding, and removing forms + */ + var Formset = function(el, options) { + var _this = this; + + //Defaults: + this.opts = $.extend({}, Formset.defaults, options); + + this.$formset = $(el); + this.$emptyForm = this.$formset.find(this.opts.emptyForm); + this.$body = this.$formset.find(this.opts.body); + this.$add = this.$formset.find(this.opts.add); + + this.formsetPrefix = $(el).data('formset-prefix'); + + // Bind to the `Add form` button + this.addForm = $.proxy(this, 'addForm'); + this.$add.click(this.addForm); + + // Bind receiver to `formAdded` and `formDeleted` events + this.$formset.on('formAdded formDeleted', this.opts.form, $.proxy(this, 'checkMaxForms')); + + // Set up the existing forms + this.$forms().each(function(i, form) { + var $form = $(form); + _this.bindForm($(this), i); + }); + + // Store a reference to this in the formset element + this.$formset.data(pluginName, this); + + var extras = ['animateForms']; + $.each(extras, function(i, extra) { + if ((extra in _this.opts) && (_this.opts[extra])) { + _this[extra](); + } + }); + }; + + Formset.defaults = { + form: '[data-formset-form]', + emptyForm: 'script[type=form-template][data-formset-empty-form]', + body: '[data-formset-body]', + add: '[data-formset-add]', + deleteButton: '[data-formset-delete-button]', + hasMaxFormsClass: 'has-max-forms', + animateForms: false + }; + + Formset.prototype.addForm = function() { + // Don't proceed if the number of maximum forms has been reached + if (this.hasMaxForms()) { + throw new Error("MAX_NUM_FORMS reached"); + } + + var newIndex = this.totalFormCount(); + this.$managementForm('TOTAL_FORMS').val(newIndex + 1); + + var newFormHtml = this.$emptyForm.html() + .replace(new RegExp('__prefix__', 'g'), newIndex) + .replace(new RegExp('<\\\\/script>', 'g'), ''); + + var $newFormFragment = $($.parseHTML(newFormHtml, this.$body.document, true)); + this.$body.append($newFormFragment); + + var $newForm = $newFormFragment.filter(this.opts.form); + this.bindForm($newForm, newIndex); + + return $newForm; + }; + + /** + * Attach any events needed to a new form + */ + Formset.prototype.bindForm = function($form, index) { + var prefix = this.formsetPrefix + '-' + index; + $form.data(pluginName + '__formPrefix', prefix); + + var $delete = $form.find('[name=' + prefix + '-DELETE]'); + + var onChangeDelete = function() { + if ($delete.is(':checked')) { + $form.attr('data-formset-form-deleted', ''); + // Remove required property and pattern attribute to allow submit, back it up to data field + $form.find(':required').data(pluginName + '-required-field', true).prop('required', false); + $form.find('input[pattern]').each(function() { + var pattern = $(this).attr('pattern'); + $(this).data(pluginName + '-field-pattern', pattern).removeAttr('pattern'); + }); + $form.trigger('formDeleted'); + } else { + $form.removeAttr('data-formset-form-deleted'); + // Restore required property and pattern attributes from data field + $form.find('*').filter(function() { + return $(this).data(pluginName + '-required-field') === true; + }).prop('required', true); + $form.find('input').each(function() { + var pattern = $(this).data(pluginName + '-field-pattern'); + if (pattern) { + $(this).attr('pattern', pattern); + } + }); + $form.trigger('formAdded'); + } + } + + // Trigger `formAdded` / `formDeleted` events when delete checkbox value changes + $delete.change(onChangeDelete); + + // This will trigger `formAdded` for newly created forms. + // It will also trigger `formAdded` or `formDeleted` for all forms when + // the Formset is first created. + // setTimeout so the caller can register events before the events are + // triggered, during initialisation. + window.setTimeout(onChangeDelete); + + // Delete the form if the delete button is pressed + var $deleteButton = $form.find(this.opts.deleteButton); + $deleteButton.bind('click', function() { + $delete.attr('checked', true).change(); + }); + }; + + Formset.prototype.$forms = function() { + return this.$body.find(this.opts.form); + }; + Formset.prototype.$managementForm = function(name) { + return this.$formset.find('[name=' + this.formsetPrefix + '-' + name + ']'); + }; + + Formset.prototype.totalFormCount = function() { + return this.$forms().length; + }; + + Formset.prototype.deletedFormCount = function() { + return this.$forms().filter('[data-formset-form-deleted]').length; + }; + + Formset.prototype.activeFormCount = function() { + return this.totalFormCount() - this.deletedFormCount(); + }; + + Formset.prototype.hasMaxForms = function() { + var maxForms = parseInt(this.$managementForm('MAX_NUM_FORMS').val(), 10) || 1000; + return this.activeFormCount() >= maxForms; + }; + + Formset.prototype.checkMaxForms = function() { + if (this.hasMaxForms()) { + this.$formset.addClass(this.opts.hasMaxFormsClass); + this.$add.attr('disabled', 'disabled'); + } else { + this.$formset.removeClass(this.opts.hasMaxFormsClass); + this.$add.removeAttr('disabled'); + } + }; + + Formset.prototype.animateForms = function() { + this.$formset.on('formAdded', this.opts.form, function() { + var $form = $(this); + $form.slideUp(0); + $form.slideDown(); + }).on('formDeleted', this.opts.form, function() { + var $form = $(this); + $form.slideUp(); + }); + this.$forms().filter('[data-formset-form-deleted]').slideUp(0); + }; + + Formset.getOrCreate = function(el, options) { + var rev = $(el).data(pluginName); + if (!rev) { + rev = new Formset(el, options); + } + + return rev; + }; + + $.fn[pluginName] = function() { + var options, fn, args; + // Create a new Formset for each element + if (arguments.length === 0 || (arguments.length === 1 && $.type(arguments[0]) != 'string')) { + options = arguments[0]; + return this.each(function() { + return Formset.getOrCreate(this, options); + }); + } + + // Call a function on each Formset in the selector + fn = arguments[0]; + args = $.makeArray(arguments).slice(1); + + if (fn in Formset) { + // Call the Formset class method if it exists + args.unshift(this); + return Formset[fn].apply(Formset, args); + } else { + throw new Error("Unknown function call " + fn + " for $.fn.formset"); + } + }; +})(jQuery);