Add new line functionality for vehicles/drivers

Might it have been easier to create 'dummy' models like with EventItems? Probably...
This commit is contained in:
2020-08-27 02:20:46 +01:00
parent 9cf081efc7
commit 3438489934
7 changed files with 76 additions and 52 deletions

View File

@@ -100,6 +100,7 @@ class EventChecklistEdit(generic.UpdateView):
ec = models.EventChecklist.objects.get(pk=pk) ec = models.EventChecklist.objects.get(pk=pk)
context['event'] = ec.event context['event'] = ec.event
context['edit'] = True context['edit'] = True
context['vehicles_length'] = range(len(self.object.vehicles))
return context return context
class EventChecklistCreate(generic.CreateView): class EventChecklistCreate(generic.CreateView):
@@ -131,6 +132,7 @@ class EventChecklistCreate(generic.CreateView):
epk = self.kwargs.get('pk') epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk) event = models.Event.objects.get(pk=epk)
context['event'] = event context['event'] = event
context['vehicles_length'] = range(2)
return context return context
def get_success_url(self): def get_success_url(self):

View File

@@ -646,7 +646,7 @@ class EventChecklist(models.Model, RevisionMixin):
event = models.OneToOneField('Event', on_delete=models.CASCADE) event = models.OneToOneField('Event', on_delete=models.CASCADE)
# General # General
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checklist', blank=True, null=True, power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checklist',
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?") verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
vehicles = models.JSONField(help_text="List vehicles and their drivers", default=dict, null=False) vehicles = models.JSONField(help_text="List vehicles and their drivers", default=dict, null=False)

View File

@@ -1 +1 @@
$(document).ready((function(){function e(e){targetObject=$("#"+e.attr("id")+"-update"),update_url=$("option:selected",e).data("update_url"),""==update_url?targetObject.attr("disabled",!0):(targetObject.attr("href",update_url),targetObject.attr("disabled",!1))}clearSelectionLabel="(no selection)",$(".selectpicker").each((function(){var t={ajax:{url:$(this).data("sourceurl"),type:"GET",dataType:"json",data:{term:"{{{q}}}"}},locale:{emptyTitle:""},clearOnEmpty:!1,preprocessData:function(e){var t,a=e.length,l=[];if(l.push({text:clearSelectionLabel,value:"",data:{update_url:"",subtext:""}}),a)for(t=0;t<a;t++)l.push($.extend(!0,e[t],{text:e[t].label,value:e[t].pk,data:{update_url:e[t].update,subtext:""}}));return l}};$(this).prepend($("<option></option>").attr("value","").text(clearSelectionLabel).data("update_url","")),$(this).selectpicker().ajaxSelectPicker(t),$(this).change((function(){e($(this))})),e($(this))})),$("#modal").on("hide.bs.modal",(function(e){null!=modaltarget&&""!=modalobject&&function(e,t,a,l){e.find("option").remove(),e.append($("<option></option>").attr("value",t).text(a).data("update_url",l)),e.selectpicker("render"),e.selectpicker("refresh"),e.selectpicker("val",t),e.change()}($(modaltarget),modalobject[0].pk,modalobject[0].fields.name,modalobject[0].update_url)}))})); function changeSelectedValue(e,t,a,l){e.find("option").remove(),e.append($("<option></option>").attr("value",t).text(a).data("update_url",l)),e.selectpicker("render"),e.selectpicker("refresh"),e.selectpicker("val",t),e.change()}function refreshUpdateHref(e){targetObject=$("#"+e.attr("id")+"-update"),update_url=$("option:selected",e).data("update_url"),""==update_url?targetObject.attr("disabled",!0):(targetObject.attr("href",update_url),targetObject.attr("disabled",!1))}function initPicker(e){console.log("called!");var t={ajax:{url:e.data("sourceurl"),type:"GET",dataType:"json",data:{term:"{{{q}}}"}},locale:{emptyTitle:""},clearOnEmpty:!1,preprocessData:function(e){var t,a=e.length,l=[];if(l.push({text:clearSelectionLabel,value:"",data:{update_url:"",subtext:""}}),a)for(t=0;t<a;t++)l.push($.extend(!0,e[t],{text:e[t].label,value:e[t].pk,data:{update_url:e[t].update,subtext:""}}));return l}};e.prepend($("<option></option>").attr("value","").text(clearSelectionLabel).data("update_url","")),e.selectpicker().ajaxSelectPicker(t),e.change((function(){refreshUpdateHref(e)})),refreshUpdateHref(e)}$(document).ready((function(){clearSelectionLabel="(no selection)",$(".selectpicker").each((function(){initPicker($(this))})),$("#modal").on("hide.bs.modal",(function(e){null!=modaltarget&&""!=modalobject&&changeSelectedValue($(modaltarget),modalobject[0].pk,modalobject[0].fields.name,modalobject[0].update_url)}))}));

View File

@@ -1,41 +1,37 @@
$(document).ready(function() {
clearSelectionLabel = '(no selection)';
function changeSelectedValue(obj,pk,text,update_url) { //Pass in JQuery object and new parameters function changeSelectedValue(obj,pk,text,update_url) { //Pass in JQuery object and new parameters
//console.log('Changing selected value'); //console.log('Changing selected value');
obj.find('option').remove(); //Remove all the available options obj.find('option').remove(); //Remove all the available options
obj.append( //Add the new option obj.append( //Add the new option
$("<option></option>") $("<option></option>")
.attr("value",pk) .attr("value",pk)
.text(text) .text(text)
.data('update_url',update_url) .data('update_url',update_url)
); );
obj.selectpicker('render'); //Re-render the UI obj.selectpicker('render'); //Re-render the UI
obj.selectpicker('refresh'); //Re-render the UI obj.selectpicker('refresh'); //Re-render the UI
obj.selectpicker('val', pk); //Set the new value to be selected obj.selectpicker('val', pk); //Set the new value to be selected
obj.change(); //Trigger the change function manually obj.change(); //Trigger the change function manually
} }
function refreshUpdateHref(obj) { function refreshUpdateHref(obj) {
//console.log('Refreshing Update URL'); //console.log('Refreshing Update URL');
targetObject = $('#'+obj.attr('id')+'-update'); targetObject = $('#'+obj.attr('id')+'-update');
update_url = $('option:selected', obj).data('update_url'); update_url = $('option:selected', obj).data('update_url');
if (update_url=="") { //Probably "clear selection" has been chosen if (update_url=="") { //Probably "clear selection" has been chosen
// console.log('Trying to disable'); // console.log('Trying to disable');
targetObject.attr('disabled', true); targetObject.attr('disabled', true);
} else { } else {
targetObject.attr('href', update_url); targetObject.attr('href', update_url);
targetObject.attr('disabled', false); targetObject.attr('disabled', false);
} }
} }
function initPicker(obj) {
$(".selectpicker").each(function() { console.log('called!');
var options = { var options = {
ajax: { ajax: {
url: $(this).data('sourceurl'), url: obj.data('sourceurl'),
type: 'GET', type: 'GET',
dataType: 'json', dataType: 'json',
// Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will // Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will
@@ -76,29 +72,32 @@ $(".selectpicker").each(function() {
} }
}; };
$(this).prepend($("<option></option>") obj.prepend($("<option></option>")
.attr("value",'') .attr("value",'')
.text(clearSelectionLabel) .text(clearSelectionLabel)
.data('update_url','')); //Add "clear selection" option .data('update_url','')); //Add "clear selection" option
$(this).selectpicker().ajaxSelectPicker(options); //Initiaise selectPicker obj.selectpicker().ajaxSelectPicker(options); //Initiaise selectPicker
$(this).change(function(){ //on change, update the edit button href obj.change(function(){ //on change, update the edit button href
// console.log('Selectbox Changed'); // console.log('Selectbox Changed');
refreshUpdateHref($(this)); refreshUpdateHref(obj);
}); });
refreshUpdateHref($(this)); //Ensure href is correct at the beginning refreshUpdateHref(obj); //Ensure href is correct at the beginning
}
}); $(document).ready(function() {
clearSelectionLabel = '(no selection)';
//When update/edit modal box submitted $(".selectpicker").each(function(){initPicker($(this))});
//When update/edit modal box submitted
$('#modal').on('hide.bs.modal', function (e) { $('#modal').on('hide.bs.modal', function (e) {
if (modaltarget != undefined && modalobject != "") { if (modaltarget != undefined && modalobject != "") {
//Update the selector with new values //Update the selector with new values
changeSelectedValue($(modaltarget),modalobject[0]['pk'],modalobject[0]['fields']['name'],modalobject[0]['update_url']); changeSelectedValue($(modaltarget),modalobject[0]['pk'],modalobject[0]['fields']['name'],modalobject[0]['update_url']);
} }
}); });
}); });

View File

@@ -63,12 +63,25 @@
var name = current.name.split('_')[0]; var name = current.name.split('_')[0];
result[index] = result[index] || {}; result[index] = result[index] || {};
var nested = result[index] || {}; var nested = result[index] || {};
nested[name] = current.value; if(current.value):
nested[name] = current.value;
result[index] = nested; result[index] = nested;
return result; return result;
}, {}); }, {});
$({{form.vehicles.id_for_label}}).val(JSON.stringify(post)); $({{form.vehicles.id_for_label}}).val(JSON.stringify(post));
}); });
$('#vehicle-add').on('click', function (event) {
event.preventDefault();
var newID = Number($('#vehiclest').attr('data-pk'));
$('#vehicles_new').clone().attr('style', "").attr('id', 'vehicles_' + newID).appendTo('#vehiclest');
$('#vehicles_' + newID).find('select,input').attr('name', function(){
return this.name.split('_')[0] + '_' + newID;
}).attr('data-serialize', 'true');
$('#vehicles_' + newID).find('select').addClass('selectpicker');
$('#vehicles_' + newID).find('.selectpicker').selectpicker('refresh');
$(".selectpicker").each(function(){initPicker($(this))});
$('#vehiclest').attr('data-pk', newID + 1);
});
}); });
</script> </script>
{% endblock %} {% endblock %}
@@ -111,7 +124,7 @@
</div> </div>
<label class="col-12 pt-3" for="{{ form.vehicles.id_for_label }}">{{ form.vehicles.help_text }}</label> <label class="col-12 pt-3" for="{{ form.vehicles.id_for_label }}">{{ form.vehicles.help_text }}</label>
<input name="{{ form.vehicles.name }}" id="{{ form.vehicles.id_for_label }}" <input name="{{ form.vehicles.name }}" id="{{ form.vehicles.id_for_label }}"
value="{{ form.vehicles.value }}" style="display: none"/> value="{{ form.vehicles.value }}"/>
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
@@ -119,23 +132,32 @@
<th scope="col">Driver</th> <th scope="col">Driver</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody id="vehiclest" data-pk="2">
{% for i in '012'|make_list %} <tr id="vehicles_new" style="display: none;">
<td><input name="vehicle_new" type="text" class="form-control"/></td>
<td>
<select name="driver_new" class="form-control" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
</select>
</td>
</tr>
{# TODO Add required to all fields on row when one is edited #}
{% for i in vehicles_length %}
<tr id="vehicles_{{i}}"> <tr id="vehicles_{{i}}">
<td><input name="vehicle_{{i}}" type="text" class="form-control" data-serialize="true" value="{{ form.vehicles.value|get_json_element:i|get_item:'vehicle' }}"/></td> <td><input name="vehicle_{{i}}" type="text" class="form-control" data-serialize="true" value="{{ form.vehicles.value|get_json_element:i|get_item:'vehicle'|default:'' }}"/></td>
<th scope="row"> <td>
<select name="driver_{{i}}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" data-serialize="true"> <select name="driver_{{i}}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" data-serialize="true">
{% if form.vehicles.value|get_json_element:i|get_item:'driver' is not 0 %} {% if form.vehicles.value|get_json_element:i|get_item:'driver' is not 0 %}
<option value="{{ form.vehicles.value|get_json_element:i|get_item:'driver' }}" selected="selected">{{form.vehicles.value|get_json_element:i|get_item:'driver'|profile_by_index}}</option> <option value="{{ form.vehicles.value|get_json_element:i|get_item:'driver'|default:'0' }}" selected="selected">{{form.vehicles.value|get_json_element:i|get_item:'driver'|profile_by_index}}</option>
{% endif %} {% endif %}
</select> </select>
</th> </td>
{# TODO Delete functionality <td><button class="btn btn-danger" data-id='{{i}}' data-action='delete'><span class="fas fa-times"></span></button</td>#}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<div class="text-right"> <div class="text-right">
<button class="btn btn-secondary"><span class="fas fa-plus"></span> Add Vehicle</button> <button class="btn btn-secondary" id="vehicle-add"><span class="fas fa-plus"></span> Add Vehicle</button>
</div> </div>
</div> </div>
</div> </div>
@@ -179,11 +201,6 @@
<tr> <tr>
<th scope="row"> <th scope="row">
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if object.power_mic %}
<option value="{{object.power_mic.pk}}" selected="selected">{{ object.power_mic.name }}</option>
{% endif %}
</select>
</th> </th>
<td><input type="time" class="form-control"/></td> <td><input type="time" class="form-control"/></td>
<td><input type="text" class="form-control"/></td> <td><input type="text" class="form-control"/></td>

View File

@@ -137,10 +137,15 @@ def profile_by_index(value):
else: else:
return "" return ""
#TODO More sensible returns
@register.filter @register.filter
def get_json_element(value, element): def get_json_element(value, element):
return json.loads(value)[element] try:
return json.loads(value)[str(element)]
except Exception as e:
return None
@register.filter @register.filter
def get_item(dictionary, key): def get_item(dictionary, key):
return dictionary.get(key) if(type(dictionary) is dict):
return dictionary.get(key)

View File

@@ -234,9 +234,10 @@ class ActivityTable(generic.ListView):
return context return context
# TODO Defined by the model, rather than with this list
def models_for_feed(): def models_for_feed():
return [models.Event, models.Venue, models.Person, models.Organisation, models.EventAuthorisation, models.RiskAssessment, asset_models.Asset, asset_models.Supplier] return [models.Event, models.Venue, models.Person, models.Organisation, models.EventAuthorisation, models.RiskAssessment, models.EventChecklist,
asset_models.Asset, asset_models.Supplier]
# Appears on homepage # Appears on homepage