Merge branch 'modal-forms'

This commit is contained in:
Oliver committed 2018-04-26 09:26:52 +10:00
commit 3c17777114
10 files changed
+295 -25

No files matched your search

+102
View File
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.template.loader import render_to_string
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.generic import UpdateView, CreateView, DeleteView
class AjaxView(object):
ajax_form_action = ''
ajax_form_title = ''
ajax_submit_text = 'Submit'
def getAjaxTemplate(self):
if hasattr(self, 'ajax_template_name'):
return self.ajax_template_name
else:
return self.template_name
def renderJsonResponse(self, request, form, data={}):
context = {'form': form,
'form_action': self.ajax_form_action,
'form_title': self.ajax_form_title,
'submit_text': self.ajax_submit_text,
}
data['html_form'] = render_to_string(
self.getAjaxTemplate(),
context,
request=request
)
return JsonResponse(data)
class AjaxCreateView(AjaxView, CreateView):
def post(self, request, *args, **kwargs):
if request.is_ajax():
form = self.form_class(request.POST)
data = {'form_valid': form.is_valid()}
if form.is_valid():
obj = form.save()
# Return the PK of the newly-created object
data['pk'] = obj.pk
return self.renderJsonResponse(request, form, data)
else:
return super(CreateView, self).post(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
response = super(CreateView, self).get(request, *args, **kwargs)
if request.is_ajax():
form = self.form_class(initial=self.get_initial())
return self.renderJsonResponse(request, form)
else:
return response
class AjaxUpdateView(AjaxView, UpdateView):
def post(self, request, *args, **kwargs):
if request.is_ajax():
form = self.form_class(request.POST, instance=self.get_object())
data = {'form_valid': form.is_valid()}
if form.is_valid():
obj = form.save()
return self.renderJsonResponse(request, form, data)
else:
response = super(UpdateView, self).post(request, *args, **kwargs)
return response
def get(self, request, *args, **kwargs):
response = super(UpdateView, self).get(request, *args, **kwargs)
if request.is_ajax():
form = self.form_class(instance = self.get_object())
return self.renderJsonResponse(request, form)
else:
return response
+7 -5
View File
@@ -42,10 +42,11 @@ class EditCategoryForm(forms.ModelForm):
super(EditCategoryForm, self).__init__(*args, **kwargs) super(EditCategoryForm, self).__init__(*args, **kwargs)
self.helper = FormHelper() self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form' #self.helper.form_id = 'id-edit-part-form'
self.helper.form_method = 'post' #self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Submit')) self.helper.form_tag = False
#self.helper.add_input(Submit('submit', 'Submit'))
class Meta: class Meta:
model = PartCategory model = PartCategory
@@ -62,10 +63,11 @@ class EditBomItemForm(forms.ModelForm):
super(EditBomItemForm, self).__init__(*args, **kwargs) super(EditBomItemForm, self).__init__(*args, **kwargs)
self.helper = FormHelper() self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form' #self.helper.form_id = 'id-edit-part-form'
self.helper.form_method = 'post' self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Submit')) self.helper.form_tag = False
#self.helper.add_input(Submit('submit', 'Submit'))
class Meta: class Meta:
model = BomItem model = BomItem
+34 -6
View File
@@ -1,9 +1,16 @@
{% extends "part/part_base.html" %} {% extends "part/part_base.html" %}
{% load static %}
{% block details %} {% block details %}
{% include 'part/tabs.html' with tab='bom' %} {% include 'part/tabs.html' with tab='bom' %}
<div class='modal fade' id='modal-form'>
<div class='modal-dialog'>
<div class='modal-content'>
</div>
</div>
</div>
<h3>Bill of Materials</h3> <h3>Bill of Materials</h3>
<table class="table table-striped"> <table class="table table-striped">
@@ -18,17 +25,38 @@
<tr> <tr>
<td><a href="{% url 'part-detail' sub_part.id %}">{{ sub_part.name }}</a></td> <td><a href="{% url 'part-detail' sub_part.id %}">{{ sub_part.name }}</a></td>
<td>{{ sub_part.description }}</td> <td>{{ sub_part.description }}</td>
<td>{{ bom_item.quantity }}</span></td> <td>{{ bom_item.quantity }}</td>
<td><a href="{% url 'bom-item-detail' bom_item.id %}">Edit</a></td> <td>
<button type='button' url="{% url 'bom-item-edit' bom_item.id %}" class='btn btn-success edit-row-button'>Edit</button>
</td>
</tr> </tr>
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
</table> </table>
<div class='container-fluid'> <div class='container-fluid'>
<a href="{% url 'bom-item-create' %}?parent={{ part.id }}"> <button type='button' class='btn btn-success' id='new-bom-item'>Add BOM Item</button>
<button class='btn btn-success'>Add BOM Item</button>
</a>
</div> </div>
{% endblock %} {% endblock %}
{% block javascript %}
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
<script type='text/javascript'>
$(".edit-row-button").click(function () {
var button = $(this);
launchModalForm("#modal-form",
button.attr('url'));
});
$("#new-bom-item").click(function () {
launchModalForm("#modal-form",
"{% url 'bom-item-create' %}/?parent={{ part.id }}");
});
</script>
{% endblock %}
@@ -22,9 +22,9 @@
{% endif %} {% endif %}
<div class='container-fluid'> <div class='container-fluid'>
<a href="{% url 'category-create' %}?category={{ category.id }}"> <button type='button' class='btn btn-primary js-create-cat'>
<button class="btn btn-success">New Category</button> New Category
</a> </button>
<a href="{% url 'part-create' %}?category={{ category.id }}"> <a href="{% url 'part-create' %}?category={{ category.id }}">
<button class="btn btn-success">New Part</button> <button class="btn btn-success">New Part</button>
</a> </a>
@@ -39,4 +39,28 @@
</div> </div>
<div class='modal fade' id='modal-cat'>
<div class='modal-dialog'>
<div class='modal-content'>
</div>
</div>
</div>
{% endblock %}
{% block javascript %}
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
<script type='text/javascript'>
$(".js-create-cat").click(function() {
launchModalForm("#modal-cat",
"{% url 'category-create' %}",
{category: {{ category.id }} });
});
</script>
{% endblock %} {% endblock %}
+24 -3
View File
@@ -5,6 +5,13 @@
{% include "part/cat_link.html" with category=category %} {% include "part/cat_link.html" with category=category %}
<div class='modal fade' id='modal-cat'>
<div class='modal-dialog'>
<div class='modal-content'>
</div>
</div>
</div>
{% if children.all|length > 0 %} {% if children.all|length > 0 %}
<h4>Part Categories</h4> <h4>Part Categories</h4>
{% include "part/category_subcategories.html" with children=children %} {% include "part/category_subcategories.html" with children=children %}
@@ -14,12 +21,26 @@
{% include "part/category_parts.html" with parts=parts %} {% include "part/category_parts.html" with parts=parts %}
<div class='container-fluid'> <div class='container-fluid'>
<a href="{% url 'category-create' %}"> <button type='button' class='btn btn-primary js-create-cat'>
<button class="btn btn-success">New Category</button> New Category
</a> </button>
<a href="{% url 'part-create' %}"> <a href="{% url 'part-create' %}">
<button class="btn btn-success">New Part</button> <button class="btn btn-success">New Part</button>
</a> </a>
</div> </div>
{% endblock %} {% endblock %}
{% block javascript %}
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
<script type="text/javascript">
$(document).ready(function () {
$(".js-create-cat").click(function() {
launchModalForm("#modal-cat", "{% url 'category-create' %}");
});
});
</script>
{% endblock %}
+13 -3
View File
@@ -4,6 +4,8 @@ from __future__ import unicode_literals
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.views.generic import DetailView, ListView from django.views.generic import DetailView, ListView
from django.views.generic.edit import UpdateView, DeleteView, CreateView from django.views.generic.edit import UpdateView, DeleteView, CreateView
@@ -17,6 +19,7 @@ from .forms import EditBomItemForm
from .forms import EditSupplierPartForm from .forms import EditSupplierPartForm
from InvenTree.views import AjaxCreateView, AjaxUpdateView
class PartIndex(ListView): class PartIndex(ListView):
model = Part model = Part
@@ -130,8 +133,11 @@ class CategoryDelete(DeleteView):
return HttpResponseRedirect(self.get_object().get_absolute_url()) return HttpResponseRedirect(self.get_object().get_absolute_url())
class CategoryCreate(CreateView): class CategoryCreate(AjaxCreateView):
model = PartCategory model = PartCategory
ajax_form_action = reverse_lazy('category-create')
ajax_form_title = 'Create new part category'
ajax_template_name = 'modal_form.html'
template_name = 'part/category_new.html' template_name = 'part/category_new.html'
form_class = EditCategoryForm form_class = EditCategoryForm
@@ -162,10 +168,12 @@ class BomItemDetail(DetailView):
template_name = 'part/bom-detail.html' template_name = 'part/bom-detail.html'
class BomItemCreate(CreateView): class BomItemCreate(AjaxCreateView):
model = BomItem model = BomItem
form_class = EditBomItemForm form_class = EditBomItemForm
template_name = 'part/bom-create.html' template_name = 'part/bom-create.html'
ajax_template_name = 'modal_form.html'
ajax_form_title = 'Create BOM item'
def get_initial(self): def get_initial(self):
# Look for initial values # Look for initial values
@@ -180,10 +188,12 @@ class BomItemCreate(CreateView):
return initials return initials
class BomItemEdit(UpdateView): class BomItemEdit(AjaxUpdateView):
model = BomItem model = BomItem
form_class = EditBomItemForm form_class = EditBomItemForm
template_name = 'part/bom-edit.html' template_name = 'part/bom-edit.html'
ajax_template_name = 'modal_form.html'
ajax_form_title = 'Edit BOM item'
class BomItemDelete(DeleteView): class BomItemDelete(DeleteView):
+7
View File
@@ -0,0 +1,7 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under the MIT license
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:tLine truncated
this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e<c&&"top";if("bottom"==this.affixed)return null!=c?!(e+this.unpin<=f.top)&&"bottom":!(e+g<=a-d)&&"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&e<=c?"top":null!=d&&i+j>=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
+56
View File
@@ -0,0 +1,56 @@
function launchModalForm(modal, url, data) {
$.ajax({
url: url, // Where to request the data from
type: 'get', // GET request
data: data, // Any additional context data (e.g. initial values)
dataType: 'json',
beforeSend: function() {
$(modal).modal('show');
},
success: function(response) {
if (response.html_form) {
var target = modal + ' .modal-content';
$(target).html(response.html_form);
} else {
alert('JSON response missing form data');
$(modal).modal('hide');
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert('Error requesting form data:\n' + thrownError);
$(modal).modal('hide');
}
});
$(modal).on('submit', '.js-modal-form', function() {
var form = $(this);
$.ajax({
url: url,
data: form.serialize(),
type: form.attr('method'),
dataType: 'json',
success: function (response) {
if (response.form_valid) {
alert("Success!");
$(modal).modal('hide');
}
else if (response.html_form) {
var target = modal + ' .modal-content';
$(target).html(response.html_form);
}
else {
alert('JSON response missing form data');
$(modal).modal('hide');
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Error posting form data:\n" + thrownError);
$(modal).modal('hide');
}
});
// Override the default form submit functionality
return false;
});
}
+8 -5
View File
@@ -13,11 +13,6 @@
<link rel='stylesheet' href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}"> <link rel='stylesheet' href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}"> <link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<!-- Scripts -->
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
{% block head %} {% block head %}
{% endblock %} {% endblock %}
@@ -39,5 +34,13 @@ InvenTree
{% endblock %} {% endblock %}
</div> </div>
<!-- Scripts -->
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'script/bootstrap.min.js' %}"></script>
{% block javascript %}
{% endblock %}
</body> </body>
</html> </html>
+17
View File
@@ -0,0 +1,17 @@
<form method="post" action='{{ form_action }}' class='js-modal-form'>
{% csrf_token %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">{{ form_title }}</h4>
</div>
<div class="modal-body">
{% load crispy_forms_tags %}
{% crispy form %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">{{ submit_text }}</button>
</div>
</form>