From 29f974a2575959cb6a7301d32c6ef1075236d728 Mon Sep 17 00:00:00 2001 From: serge Date: Wed, 12 Oct 2016 17:19:03 +0800 Subject: [PATCH 01/17] WIP: most done for application. TODO: init the action log on every views --- .../migrations/0011_applicationuseraction.py | 31 +++++ wildlifelicensing/apps/applications/models.py | 32 ++++- .../conditions/assessor_enter_conditions.html | 11 +- .../wl/conditions/enter_conditions.html | 27 +++-- .../templates/wl/process/process_app.html | 22 ++-- .../wl/view/view_readonly_officer.html | 9 +- wildlifelicensing/apps/applications/urls.py | 5 +- .../apps/applications/views/issue.py | 7 +- .../apps/applications/views/process.py | 61 +++++++++- .../apps/applications/views/view.py | 51 ++++++-- wildlifelicensing/apps/main/models.py | 22 +++- .../apps/main/static/wl/js/actions_log.js | 112 ++++++++++++++++++ .../main/static/wl/js/communications_log.js | 2 +- .../templates/wl/communications_panel.html | 28 ++++- wildlifelicensing/static/wl/css/base.css | 8 ++ 15 files changed, 380 insertions(+), 48 deletions(-) create mode 100644 wildlifelicensing/apps/applications/migrations/0011_applicationuseraction.py create mode 100644 wildlifelicensing/apps/main/static/wl/js/actions_log.js diff --git a/wildlifelicensing/apps/applications/migrations/0011_applicationuseraction.py b/wildlifelicensing/apps/applications/migrations/0011_applicationuseraction.py new file mode 100644 index 0000000000..0a3ba8763c --- /dev/null +++ b/wildlifelicensing/apps/applications/migrations/0011_applicationuseraction.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.10 on 2016-10-12 02:42 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wl_applications', '0010_auto_20160901_1436'), + ] + + operations = [ + migrations.CreateModel( + name='ApplicationUserAction', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('when', models.DateTimeField(auto_now_add=True)), + ('what', models.TextField()), + ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wl_applications.Application')), + ('who', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/wildlifelicensing/apps/applications/models.py b/wildlifelicensing/apps/applications/models.py index 5ae30b592d..c2cbf8d807 100755 --- a/wildlifelicensing/apps/applications/models.py +++ b/wildlifelicensing/apps/applications/models.py @@ -8,7 +8,7 @@ from ledger.accounts.models import EmailUser, Profile, Document, RevisionedMixin from wildlifelicensing.apps.main.models import WildlifeLicence, WildlifeLicenceType, Condition, \ - CommunicationsLogEntry, AssessorGroup, Variant + CommunicationsLogEntry, AssessorGroup, Variant, UserAction @python_2_unicode_compatible @@ -130,6 +130,9 @@ def is_senior_offer_applicable(self): self.applicant.is_senior and \ bool(self.applicant.senior_card) + def log_user_action(self, action, request): + return ApplicationUserAction.log_action(self, action, request.user) + class ApplicationVariantLink(models.Model): application = models.ForeignKey(Application) @@ -210,6 +213,33 @@ class Meta: unique_together = ('condition', 'assessment', 'order') +class ApplicationUserAction(UserAction): + ACTION_ASSIGN_TO_ = "Assign to {}" + ACTION_UNASSIGN = "Unassign" + ACTION_ACCEPT_ID = "Accept ID" + ACTION_RESET_ID = "Reset ID" + ACTION_ID_REQUEST_UPDATE = 'Request ID update' + ACTION_ACCEPT_CHARACTER = 'Accept character' + ACTION_RESET_CHARACTER = "Reset character" + ACTION_ACCEPT_REVIEW = 'Accept review' + ACTION_RESET_REVIEW = "Reset review" + ACTION_ID_REQUEST_AMENDMENTS = "Request amendments" + SEND_FOR_ASSESSMENT_TO_ = "Send for assessment to {}" + SEND_ASSESSMENT_REMINDER_TO_ = "Send assessment reminder to {}" + ACTION_DECLINE_APPLICATION = "Decline application" + ACTION_ISSUE_LICENCE_ = "Issue Licence {}" + + @classmethod + def log_action(cls, application, action, user): + return cls.objects.create( + application=application, + who=user, + what=str(action) + ) + + application = models.ForeignKey(Application) + + @receiver(pre_delete, sender=Application) def delete_documents(sender, instance, *args, **kwargs): for document in instance.documents.all(): diff --git a/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html b/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html index a5e1debfa5..304d16cad6 100755 --- a/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html +++ b/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html @@ -14,7 +14,11 @@ {% endblock %} {% block requirements %} - require(['js/conditions/assessor_enter_conditions', 'js/communications_log'], function (enter_conditions, commsLog) { + require([ + 'js/conditions/assessor_enter_conditions', + 'js/communications_log', + 'js/actions_log + ], function (enter_conditions, commsLog, actionsLog) { $(function () { enter_conditions.init({{ assessment|jsonify }}, {{ application|jsonify }}, {{ form_structure|jsonify }}, {{ other_assessments|jsonify }}); @@ -27,6 +31,11 @@ logListURL: "{% url 'wl_applications:log_list' application.id %}", addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" }); + actionsLog.init({ + showLogPopoverSelector: '#showActionLog', + logListURL: "{% url 'wl_applications:action_list' application.id %}", + }); + }); }); {% endblock %} diff --git a/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html b/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html index 67ca49cce7..3b1084ad72 100755 --- a/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html +++ b/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html @@ -15,17 +15,26 @@ {% endblock %} {% block requirements %} - require(['js/conditions/enter_conditions', 'js/communications_log'], function (enterConditions, commLog) { - enterConditions.init({{ application|jsonify }}, {{ assessments|jsonify }}, {{form_structure|jsonify}}, '{{ csrf_token }}'); + require([ + 'js/conditions/enter_conditions', + 'js/communications_log', + 'js/actions_log' + ], function (enterConditions, commLog, actionsLog) { + enterConditions.init({{ application|jsonify }}, {{ assessments|jsonify }}, {{form_structure|jsonify}}, '{{ csrf_token }}'); - commLog.initCommunicationLog({ - showLogPopoverSelector: '#showLog', - showLogEntryModalSelector: '#addLogEntry', - logEntryModalSelector: '#logEntryModal', - logEntryFormSelector: '#addLogEntryForm', - logListURL: "{% url 'wl_applications:log_list' application.id %}", - addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" + commLog.initCommunicationLog({ + showLogPopoverSelector: '#showLog', + showLogEntryModalSelector: '#addLogEntry', + logEntryModalSelector: '#logEntryModal', + logEntryFormSelector: '#addLogEntryForm', + logListURL: "{% url 'wl_applications:log_list' application.id %}", + addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" + }); + actionsLog.init({ + showLogPopoverSelector: '#showActionLog', + logListURL: "{% url 'wl_applications:action_list' application.id %}", }); + }); {% endblock %} diff --git a/wildlifelicensing/apps/applications/templates/wl/process/process_app.html b/wildlifelicensing/apps/applications/templates/wl/process/process_app.html index a8be8c51d1..f5f61572e8 100755 --- a/wildlifelicensing/apps/applications/templates/wl/process/process_app.html +++ b/wildlifelicensing/apps/applications/templates/wl/process/process_app.html @@ -15,12 +15,13 @@ {% endblock %} {% block requirements %} - require(['js/process/process_app', 'js/communications_log'], function (app, commsLog) { - $(function () { - data = {{ data|jsonify }}; - app.initialiseApplicationProcesssing(data); + require(['js/process/process_app', 'js/communications_log', 'js/actions_log'], + function (app, commsLog, actionsLog) { + $(function () { + data = {{ data|jsonify }}; + app.initialiseApplicationProcesssing(data); - commsLog.initCommunicationLog({ + commsLog.initCommunicationLog({ showLogPopoverSelector: '#showLog', showLogEntryModalSelector: '#addLogEntry', logEntryModalSelector: '#logEntryModal', @@ -29,9 +30,14 @@ addLogEntryURL: "{% url 'wl_applications:add_log_entry' data.application.id %}" }); + actionsLog.init({ + showLogPopoverSelector: '#showActionLog', + logListURL: "{% url 'wl_applications:action_list' data.application.id %}", + }); + $('#mainContainer').removeClass('hidden'); + }); }); - }); {% endblock %} {% block breadcrumbs %} @@ -119,9 +125,7 @@

{{ data.application.licence_type.name }}

- {% with disable_collapse=True add_text='Add application log entry' %} - {% include 'wl/communications_panel.html' %} - {% endwith %} + {% include 'wl/communications_panel.html' %}
diff --git a/wildlifelicensing/apps/applications/templates/wl/view/view_readonly_officer.html b/wildlifelicensing/apps/applications/templates/wl/view/view_readonly_officer.html index 026ad6fd1f..4c80fcfb53 100755 --- a/wildlifelicensing/apps/applications/templates/wl/view/view_readonly_officer.html +++ b/wildlifelicensing/apps/applications/templates/wl/view/view_readonly_officer.html @@ -17,8 +17,9 @@ require(['jQuery', 'js/view/view_readonly_officer', 'js/entry/application_preview', - 'js/communications_log'], - function($, viewReadonlyOfficer, applicationPreview, commsLog) { + 'js/communications_log', + 'js/actions_log'], + function($, viewReadonlyOfficer, applicationPreview, commsLog, actionsLog) { viewReadonlyOfficer.init({{ application|jsonify }}, {{ assessments|jsonify }}, {{form_structure|jsonify}}); $('#mainContainer').removeClass('hidden'); @@ -31,6 +32,10 @@ logListURL: "{% url 'wl_applications:log_list' application.id %}", addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" }); + actionsLog.init({ + showLogPopoverSelector: '#showActionLog', + logListURL: "{% url 'wl_applications:action_list' application.id %}", + }); // need to initialise sidebar menu after showing main container otherwise affix height will be wrong applicationPreview.initialiseSidebarMenu('#sectionList'); diff --git a/wildlifelicensing/apps/applications/urls.py b/wildlifelicensing/apps/applications/urls.py index 3005c7e7c9..7e4bf93158 100755 --- a/wildlifelicensing/apps/applications/urls.py +++ b/wildlifelicensing/apps/applications/urls.py @@ -15,7 +15,7 @@ from wildlifelicensing.apps.applications.views.issue import IssueLicenceView, ReissueLicenceView, PreviewLicenceView from wildlifelicensing.apps.applications.views.view import ViewReadonlyView, ViewReadonlyOfficerView, \ - ViewReadonlyAssessorView, AddApplicationLogEntryView, ApplicationLogListView + ViewReadonlyAssessorView, AddApplicationLogEntryView, ApplicationLogListView, ApplicationUserActionListView urlpatterns = [ @@ -52,6 +52,9 @@ url('^add-log-entry/([0-9]+)/$', AddApplicationLogEntryView.as_view(), name='add_log_entry'), url('^log-list/([0-9]+)/$', ApplicationLogListView.as_view(), name='log_list'), + # action log + url('^action-list/([0-9]+)/$', ApplicationUserActionListView.as_view(), name='action_list'), + # conditions url('^enter-conditions/([0-9]+)/$', EnterConditionsView.as_view(), name='enter_conditions'), url('^enter-conditions/([0-9]+)/assessment/([0-9]+)/?$', EnterConditionsAssessorView.as_view(), diff --git a/wildlifelicensing/apps/applications/views/issue.py b/wildlifelicensing/apps/applications/views/issue.py index e7806c03bc..66c2d975b0 100755 --- a/wildlifelicensing/apps/applications/views/issue.py +++ b/wildlifelicensing/apps/applications/views/issue.py @@ -16,7 +16,7 @@ from wildlifelicensing.apps.main.pdf import create_licence_pdf_document, create_licence_pdf_bytes,\ create_cover_letter_pdf_document from wildlifelicensing.apps.main.signals import licence_issued -from wildlifelicensing.apps.applications.models import Application, Assessment +from wildlifelicensing.apps.applications.models import Application, Assessment, ApplicationUserAction from wildlifelicensing.apps.applications.utils import get_log_entry_to, format_application from wildlifelicensing.apps.applications.emails import send_licence_issued_email from wildlifelicensing.apps.applications.forms import ApplicationLogEntryForm @@ -141,6 +141,11 @@ def post(self, request, *args, **kwargs): application.save() + application.log_user_action( + ApplicationUserAction.ACTION_ISSUE_LICENCE_.format(licence), + request + ) + # The licence should be emailed to the customer if they applied for it online. If an officer entered # the application on their behalf, the licence needs to be posted to the user. diff --git a/wildlifelicensing/apps/applications/views/process.py b/wildlifelicensing/apps/applications/views/process.py index 84921ef949..b7d51536c6 100755 --- a/wildlifelicensing/apps/applications/views/process.py +++ b/wildlifelicensing/apps/applications/views/process.py @@ -15,7 +15,7 @@ from wildlifelicensing.apps.main.mixins import OfficerRequiredMixin, OfficerOrAssessorRequiredMixin from wildlifelicensing.apps.main.helpers import get_all_officers, render_user_name from wildlifelicensing.apps.main.serializers import WildlifeLicensingJSONEncoder -from wildlifelicensing.apps.applications.models import Application, AmendmentRequest, Assessment +from wildlifelicensing.apps.applications.models import Application, AmendmentRequest, Assessment, ApplicationUserAction from wildlifelicensing.apps.applications.forms import IDRequestForm, ReturnsRequestForm, AmendmentRequestForm, \ ApplicationLogEntryForm from wildlifelicensing.apps.applications.emails import send_amendment_requested_email, send_assessment_requested_email, \ @@ -119,6 +119,10 @@ def post(self, request, *args, **kwargs): elif 'decline' in request.POST: application.processing_status = 'declined' application.save() + application.log_user_action( + ApplicationUserAction.ACTION_DECLINE_APPLICATION, + request + ) messages.warning(request, 'The application was declined.') @@ -140,11 +144,16 @@ def post(self, request, *args, **kwargs): application.save() if application.assigned_officer is not None: - assigned_officer = {'id': application.assigned_officer.id, 'text': '%s %s' % - (application.assigned_officer.first_name, - application.assigned_officer.last_name)} + name = render_user_name(application.assigned_officer) + assigned_officer = {'id': application.assigned_officer.id, 'text': name} + application.log_user_action( + ApplicationUserAction.ACTION_ASSIGN_TO_.format(name), + request) else: assigned_officer = {'id': 0, 'text': 'Unassigned'} + application.log_user_action( + ApplicationUserAction.ACTION_UNASSIGN, + request) return JsonResponse({'assigned_officer': assigned_officer, 'processing_status': PROCESSING_STATUSES[application.processing_status]}, @@ -154,12 +163,23 @@ def post(self, request, *args, **kwargs): class SetIDCheckStatusView(OfficerRequiredMixin, View): def post(self, request, *args, **kwargs): application = get_object_or_404(Application, pk=request.POST['applicationID']) + previous_status = application.id_check_status application.id_check_status = request.POST['status'] application.customer_status = determine_customer_status(application) application.processing_status = determine_processing_status(application) application.save() + if application.id_check_status != previous_status: + # log action + status = application.id_check_status + user_action = "ID check:" + status # default action + if status == 'accepted': + user_action = ApplicationUserAction.ACTION_ACCEPT_ID + elif status == 'not_checked': + user_action = ApplicationUserAction.ACTION_RESET_ID + application.log_user_action(user_action, request) + return JsonResponse({'id_check_status': ID_CHECK_STATUSES[application.id_check_status], 'processing_status': PROCESSING_STATUSES[application.processing_status]}, safe=False, encoder=WildlifeLicensingJSONEncoder) @@ -176,6 +196,7 @@ def post(self, request, *args, **kwargs): application.customer_status = determine_customer_status(application) application.processing_status = determine_processing_status(application) application.save() + application.log_user_action(ApplicationUserAction.ACTION_ID_REQUEST_UPDATE, request) send_id_update_request_email(id_request, request) response = {'id_check_status': ID_CHECK_STATUSES[application.id_check_status], @@ -224,11 +245,22 @@ def post(self, request, *args, **kwargs): class SetCharacterCheckStatusView(OfficerRequiredMixin, View): def post(self, request, *args, **kwargs): application = get_object_or_404(Application, pk=request.POST['applicationID']) + previous_status = application.character_check_status application.character_check_status = request.POST['status'] application.processing_status = determine_processing_status(application) application.save() + if application.character_check_status != previous_status: + # log action + status = application.character_check_status + user_action = "Character check:" + status # default action + if status == 'accepted': + user_action = ApplicationUserAction.ACTION_ACCEPT_CHARACTER + elif status == 'not_checked': + user_action = ApplicationUserAction.ACTION_RESET_CHARACTER + application.log_user_action(user_action, request) + return JsonResponse({'character_check_status': CHARACTER_CHECK_STATUSES[application.character_check_status], 'processing_status': PROCESSING_STATUSES[application.processing_status]}, safe=False, encoder=WildlifeLicensingJSONEncoder) @@ -237,12 +269,23 @@ def post(self, request, *args, **kwargs): class SetReviewStatusView(OfficerRequiredMixin, View): def post(self, request, *args, **kwargs): application = get_object_or_404(Application, pk=request.POST['applicationID']) + previous_status = application.review_status application.review_status = request.POST['status'] application.customer_status = determine_customer_status(application) application.processing_status = determine_processing_status(application) application.save() + if application.review_status != previous_status: + # log action + status = application.review_status + user_action = "Character check:" + status # default action + if status == 'accepted': + user_action = ApplicationUserAction.ACTION_ACCEPT_REVIEW + elif status == 'not_reviewed': + user_action = ApplicationUserAction.ACTION_RESET_REVIEW + application.log_user_action(user_action, request) + response = {'review_status': REVIEW_STATUSES[application.review_status], 'processing_status': PROCESSING_STATUSES[application.processing_status]} @@ -260,7 +303,7 @@ def post(self, request, *args, **kwargs): application.customer_status = determine_customer_status(application) application.processing_status = determine_processing_status(application) application.save() - + application.log_user_action(ApplicationUserAction.ACTION_ID_REQUEST_AMENDMENTS, request) send_amendment_requested_email(amendment_request, request=request) response = {'review_status': REVIEW_STATUSES[application.review_status], @@ -285,6 +328,9 @@ def post(self, request, *args, **kwargs): application.processing_status = determine_processing_status(application) application.save() + application.log_user_action( + ApplicationUserAction.SEND_FOR_ASSESSMENT_TO_.format(ass_group), + request) send_assessment_requested_email(assessment, request) @@ -302,6 +348,11 @@ class RemindAssessmentView(OfficerRequiredMixin, View): def post(self, request, *args, **kwargs): assessment = get_object_or_404(Assessment, pk=request.POST['assessmentID']) + assessment.application.log_user_action( + ApplicationUserAction.SEND_ASSESSMENT_REMINDER_TO_.format(assessment.assessor_group), + request + ) + send_assessment_reminder_email(assessment, request) assessment.date_last_reminded = date.today() diff --git a/wildlifelicensing/apps/applications/views/view.py b/wildlifelicensing/apps/applications/views/view.py index 5674b2f642..80e4006333 100755 --- a/wildlifelicensing/apps/applications/views/view.py +++ b/wildlifelicensing/apps/applications/views/view.py @@ -5,13 +5,14 @@ from preserialize.serialize import serialize from wildlifelicensing.apps.payments import utils as payment_utils -from wildlifelicensing.apps.applications.models import Application, Assessment, ApplicationLogEntry +from wildlifelicensing.apps.applications.models import Application, Assessment, ApplicationLogEntry, \ + ApplicationUserAction from wildlifelicensing.apps.applications.mixins import UserCanViewApplicationMixin, CanPerformAssessmentMixin from wildlifelicensing.apps.applications.utils import convert_documents_to_url, append_app_document_to_schema_data, \ get_log_entry_to, format_application, format_assessment from wildlifelicensing.apps.applications.forms import ApplicationLogEntryForm from wildlifelicensing.apps.main.models import Document -from wildlifelicensing.apps.main.helpers import is_officer +from wildlifelicensing.apps.main.helpers import is_officer, render_user_name from wildlifelicensing.apps.main.utils import format_communications_log_entry from wildlifelicensing.apps.main.mixins import OfficerOrAssessorRequiredMixin from wildlifelicensing.apps.main.serializers import WildlifeLicensingJSONEncoder @@ -35,7 +36,8 @@ def get_context_data(self, **kwargs): if is_officer(self.request.user): kwargs['customer'] = application.applicant - kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), fromm=self.request.user.get_full_name()) + kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), + fromm=self.request.user.get_full_name()) else: kwargs['payment_status'] = payment_utils.PAYMENT_STATUSES.get(payment_utils. get_application_payment_status(application)) @@ -58,12 +60,14 @@ def get_context_data(self, **kwargs): kwargs['application'] = serialize(application, posthook=format_application) - kwargs['assessments'] = serialize(Assessment.objects.filter(application=application), posthook=format_assessment) + kwargs['assessments'] = serialize(Assessment.objects.filter(application=application), + posthook=format_assessment) kwargs['payment_status'] = payment_utils.PAYMENT_STATUSES.get(payment_utils. get_application_payment_status(application)) - kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), fromm=self.request.user.get_full_name()) + kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), + fromm=self.request.user.get_full_name()) return super(ViewReadonlyOfficerView, self).get_context_data(**kwargs) @@ -91,19 +95,25 @@ def get_context_data(self, **kwargs): kwargs['other_assessments'] = serialize(Assessment.objects.filter(application=application). exclude(id=assessment.id).order_by('id'), posthook=format_assessment) - kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), fromm=self.request.user.get_full_name()) + kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), + fromm=self.request.user.get_full_name()) return super(ViewReadonlyAssessorView, self).get_context_data(**kwargs) class ApplicationLogListView(OfficerOrAssessorRequiredMixin, View): + serial_template = { + 'exclude': ['application', 'communicationslogentry_ptr', 'customer', 'staff'], + 'posthook': format_communications_log_entry + } + def get(self, request, *args, **kwargs): application = get_object_or_404(Application, pk=args[0]) - data = serialize(ApplicationLogEntry.objects.filter(application=application), - posthook=format_communications_log_entry, - exclude=['application', 'communicationslogentry_ptr', 'customer', 'officer']), - - return JsonResponse({'data': data[0]}, safe=False, encoder=WildlifeLicensingJSONEncoder) + data = serialize( + ApplicationLogEntry.objects.filter(application=application), + **self.serial_template + ) + return JsonResponse({'data': data}, safe=False, encoder=WildlifeLicensingJSONEncoder) class AddApplicationLogEntryView(OfficerOrAssessorRequiredMixin, View): @@ -145,3 +155,22 @@ def post(self, request, *args, **kwargs): ] }, safe=False, encoder=WildlifeLicensingJSONEncoder, status_code=422) + + +class ApplicationUserActionListView(OfficerOrAssessorRequiredMixin, View): + serial_template = { + 'fields': ['who', 'when', 'what'], + 'related': { + 'who': { + 'posthook': render_user_name + } + } + } + + def get(self, request, *args, **kwargs): + application = get_object_or_404(Application, pk=args[0]) + data = serialize( + ApplicationUserAction.objects.filter(application=application), + **self.serial_template + ) + return JsonResponse({'data': data}, safe=False, encoder=WildlifeLicensingJSONEncoder) diff --git a/wildlifelicensing/apps/main/models.py b/wildlifelicensing/apps/main/models.py index 92fa86a182..c33a1691a2 100755 --- a/wildlifelicensing/apps/main/models.py +++ b/wildlifelicensing/apps/main/models.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function, absolute_import, division from django.db import models from django.utils.encoding import python_2_unicode_compatible @@ -109,7 +109,8 @@ def __str__(self): def get_title_with_variants(self): if self.pk is not None and self.variants.exists(): - return '{} ({})'.format(self.licence_type.name, ' / '.join(self.variants.all().values_list('name', flat=True))) + return '{} ({})'.format(self.licence_type.name, + ' / '.join(self.variants.all().values_list('name', flat=True))) else: return self.licence_type.name @@ -192,3 +193,20 @@ class AssessorGroup(models.Model): def __str__(self): return self.name + + +@python_2_unicode_compatible +class UserAction(models.Model): + who = models.ForeignKey(EmailUser, null=False, blank=False) + when = models.DateTimeField(null=False, blank=False, auto_now_add=True) + what = models.TextField(blank=False) + + def __str__(self): + return "{what} ({who} at {when})".format( + what=self.what, + who=self.who, + when=self.when + ) + + class Meta: + abstract = True diff --git a/wildlifelicensing/apps/main/static/wl/js/actions_log.js b/wildlifelicensing/apps/main/static/wl/js/actions_log.js new file mode 100644 index 0000000000..11ee7a12c2 --- /dev/null +++ b/wildlifelicensing/apps/main/static/wl/js/actions_log.js @@ -0,0 +1,112 @@ +define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment, dataTable) { + "use strict"; + + // constants + var DATE_TIME_FORMAT = 'DD/MM/YYYY HH:mm:ss'; + + function initActionsLog(options) { + // multi-used selectors + var $logListContent, logDataTable; + + // default options + options = _.defaults(options || {}, { + showLogPopoverSelector: '#showActionLog', + logTableSelector: $(''), + logListURL: 'insert-default-url-here' + }); + + // if log table is in a popover, need to prepare log table container before initializing table or + // search/paging/etc won't show + if (options.showLogPopoverSelector) { + $logListContent = $('
').append($(options.logTableSelector)); + } + + // init log table + logDataTable = initLogTable(options.logListURL, options.logTableSelector); + + // init log table popover if provided + if (options.showLogPopoverSelector) { + $(options.showLogPopoverSelector).popover({ + container: 'body', + title: 'Action log', + content: $logListContent, + placement: 'right', + trigger: "manual", + html: true + }).click(function () { + var isVisible = $(this).data()['bs.popover'].tip().hasClass('in'); + if (!isVisible) { + logDataTable.ajax.reload(); + $(this).popover('show'); + $('[data-toggle="tooltip"]').tooltip(); + } else { + $(this).popover('hide'); + } + }); + } + } + + function initLogTable(logListURL, tableSelector) { + var $table = $(tableSelector), + tableOptions = { + paging: true, + info: true, + searching: true, + processing: true, + deferRender: true, + serverSide: false, + autowidth: true, + order: [[2, 'desc']], + // TODO: next one is to avoid the 'search' field to go out of the popover (table width is small). + // see https://datatables.net/reference/option/dom + dom: + "<'row'<'col-sm-5'l><'col-sm-6'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + ajax: { + url: logListURL + } + }, + colDefinitions = [ + { + title: 'Who', + data: 'who' + }, + { + title: 'What', + data: 'what' + }, + { + title: 'When', + data: 'when', + render: function (date) { + return moment(date).format(DATE_TIME_FORMAT); + } + } + ]; + + // set DT date format sorting + dataTable.setDateTimeFormat(DATE_TIME_FORMAT); + + // activate popover when table is drawn. + $table.on('draw.dt', function () { + var $tablePopover = $table.find('[data-toggle="popover"]'); + if ($tablePopover.length > 0) { + $tablePopover.popover(); + // the next line prevents from scrolling up to the top after clicking on the popover. + $($tablePopover).on('click', function (e) { + e.preventDefault(); + return true; + }); + } + }); + + return dataTable.initTable($table, tableOptions, colDefinitions); + } + + return { + init: function(options) { + return initActionsLog(options); + } + }; +}); \ No newline at end of file diff --git a/wildlifelicensing/apps/main/static/wl/js/communications_log.js b/wildlifelicensing/apps/main/static/wl/js/communications_log.js index 3901885a89..0454e9fa91 100644 --- a/wildlifelicensing/apps/main/static/wl/js/communications_log.js +++ b/wildlifelicensing/apps/main/static/wl/js/communications_log.js @@ -2,7 +2,7 @@ define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment "use strict"; // constants - var DATE_TIME_FORMAT = 'DD/MM/YYYY HH:mm A'; + var DATE_TIME_FORMAT = 'DD/MM/YYYY HH:mm:ss'; function initCommunicationLog(options) { // default options diff --git a/wildlifelicensing/apps/main/templates/wl/communications_panel.html b/wildlifelicensing/apps/main/templates/wl/communications_panel.html index c87ca5bbb9..249e8ab49c 100644 --- a/wildlifelicensing/apps/main/templates/wl/communications_panel.html +++ b/wildlifelicensing/apps/main/templates/wl/communications_panel.html @@ -2,16 +2,34 @@
- Communications Log + Logs {% if not disable_collapse %} - + {% endif %}
-
diff --git a/wildlifelicensing/static/wl/css/base.css b/wildlifelicensing/static/wl/css/base.css index 7ec3c57509..9fc563c36b 100755 --- a/wildlifelicensing/static/wl/css/base.css +++ b/wildlifelicensing/static/wl/css/base.css @@ -34,6 +34,14 @@ margin-top: 20px; } +.top-buffer-s { + margin-top: 10px; +} + +.top-buffer-xs { + margin-top: 5px; +} + .bottom-buffer { margin-bottom: 20px; } From f6eed2c32f95dbf8d19a352338c0b04284189fca Mon Sep 17 00:00:00 2001 From: serge Date: Thu, 13 Oct 2016 13:45:07 +0800 Subject: [PATCH 02/17] Refactor log stuff. Added more action log. --- wildlifelicensing/apps/applications/models.py | 9 +- .../conditions/assessor_enter_conditions.html | 20 +-- .../wl/conditions/enter_conditions.html | 33 ++--- .../templates/wl/issue/issue_licence.html | 30 +++-- .../templates/wl/process/process_app.html | 30 ++--- .../templates/wl/view/view_readonly.html | 23 ++-- .../wl/view/view_readonly_assessor.html | 18 ++- .../wl/view/view_readonly_officer.html | 28 ++--- .../apps/applications/views/conditions.py | 10 +- .../apps/applications/views/entry.py | 18 ++- .../apps/applications/views/process.py | 4 +- .../templates/wl/customer_lookup.html | 2 +- .../apps/main/static/wl/js/actions_log.js | 112 ----------------- .../wl/js/{communications_log.js => logs.js} | 117 ++++++++++++++++-- ..._modal.html => logs_comm_entry_modal.html} | 4 +- ...munications_panel.html => logs_panel.html} | 22 ++-- .../returns/templates/wl/curate_return.html | 28 ++--- 17 files changed, 246 insertions(+), 262 deletions(-) delete mode 100644 wildlifelicensing/apps/main/static/wl/js/actions_log.js rename wildlifelicensing/apps/main/static/wl/js/{communications_log.js => logs.js} (67%) rename wildlifelicensing/apps/main/templates/wl/{communications_modal.html => logs_comm_entry_modal.html} (82%) rename wildlifelicensing/apps/main/templates/wl/{communications_panel.html => logs_panel.html} (54%) diff --git a/wildlifelicensing/apps/applications/models.py b/wildlifelicensing/apps/applications/models.py index c2cbf8d807..5316e02bb2 100755 --- a/wildlifelicensing/apps/applications/models.py +++ b/wildlifelicensing/apps/applications/models.py @@ -214,6 +214,9 @@ class Meta: class ApplicationUserAction(UserAction): + ACTION_CREATE_CUSTOMER_ = "Create customer {}" + ACTION_CREATE_PROFILE_ = "Create profile {}" + ACTION_LODGE_APPLICATION = "Lodge application {}" ACTION_ASSIGN_TO_ = "Assign to {}" ACTION_UNASSIGN = "Unassign" ACTION_ACCEPT_ID = "Accept ID" @@ -224,10 +227,12 @@ class ApplicationUserAction(UserAction): ACTION_ACCEPT_REVIEW = 'Accept review' ACTION_RESET_REVIEW = "Reset review" ACTION_ID_REQUEST_AMENDMENTS = "Request amendments" - SEND_FOR_ASSESSMENT_TO_ = "Send for assessment to {}" - SEND_ASSESSMENT_REMINDER_TO_ = "Send assessment reminder to {}" + ACTION_SEND_FOR_ASSESSMENT_TO_ = "Send for assessment to {}" + ACTION_SEND_ASSESSMENT_REMINDER_TO_ = "Send assessment reminder to {}" ACTION_DECLINE_APPLICATION = "Decline application" ACTION_ISSUE_LICENCE_ = "Issue Licence {}" + ACTION_OPEN_ASSESSMENT_ = "Open assessment {}" + ACTION_CONCLUDE_ASSESSMENT_ = "Conclude assessment {}" @classmethod def log_action(cls, application, action, user): diff --git a/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html b/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html index 304d16cad6..615f7a8b64 100755 --- a/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html +++ b/wildlifelicensing/apps/applications/templates/wl/conditions/assessor_enter_conditions.html @@ -16,23 +16,17 @@ {% block requirements %} require([ 'js/conditions/assessor_enter_conditions', - 'js/communications_log', - 'js/actions_log - ], function (enter_conditions, commsLog, actionsLog) { + 'js/logs' + ], function (enter_conditions, logs) { $(function () { enter_conditions.init({{ assessment|jsonify }}, {{ application|jsonify }}, {{ form_structure|jsonify }}, {{ other_assessments|jsonify }}); - commsLog.initCommunicationLog({ - showLogPopoverSelector: '#showLog', - showLogEntryModalSelector: '#addLogEntry', - logEntryModalSelector: '#logEntryModal', - logEntryFormSelector: '#addLogEntryForm', + logs.initCommunicationLog({ logListURL: "{% url 'wl_applications:log_list' application.id %}", addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" }); - actionsLog.init({ - showLogPopoverSelector: '#showActionLog', + logs.initActionLog({ logListURL: "{% url 'wl_applications:action_list' application.id %}", }); @@ -112,9 +106,7 @@

{{ application.licence_type.name }}

- {% with disable_collapse=True add_text='Add application log entry' %} - {% include 'wl/communications_panel.html' %} - {% endwith %} + {% include 'wl/logs_panel.html' %}
@@ -185,5 +177,5 @@

Current Conditions

{% endblock %} {% block modals %} - {% include 'wl/communications_modal.html' %} + {% include 'wl/logs_comm_entry_modal.html' %} {% endblock %} \ No newline at end of file diff --git a/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html b/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html index 3b1084ad72..de224f896c 100755 --- a/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html +++ b/wildlifelicensing/apps/applications/templates/wl/conditions/enter_conditions.html @@ -14,27 +14,22 @@ {% endblock %} + {% block requirements %} require([ 'js/conditions/enter_conditions', - 'js/communications_log', - 'js/actions_log' - ], function (enterConditions, commLog, actionsLog) { - enterConditions.init({{ application|jsonify }}, {{ assessments|jsonify }}, {{form_structure|jsonify}}, '{{ csrf_token }}'); + 'js/logs' + ], + function (enterConditions, logs) { + enterConditions.init({{ application|jsonify }}, {{ assessments|jsonify }}, {{form_structure|jsonify}}, '{{ csrf_token }}'); - commLog.initCommunicationLog({ - showLogPopoverSelector: '#showLog', - showLogEntryModalSelector: '#addLogEntry', - logEntryModalSelector: '#logEntryModal', - logEntryFormSelector: '#addLogEntryForm', - logListURL: "{% url 'wl_applications:log_list' application.id %}", - addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" - }); - actionsLog.init({ - showLogPopoverSelector: '#showActionLog', - logListURL: "{% url 'wl_applications:action_list' application.id %}", + logs.initCommunicationLog({ + logListURL: "{% url 'wl_applications:log_list' application.id %}", + addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" + }); + logs.initActionLog({ + logListURL: "{% url 'wl_applications:action_list' application.id %}", }); - }); {% endblock %} @@ -117,9 +112,7 @@

{{ application.licence_type.name }}

- {% with disable_collapse=True add_text='Add application log entry' %} - {% include 'wl/communications_panel.html' %} - {% endwith %} + {% include 'wl/logs_panel.html' %}
@@ -250,5 +243,5 @@
- {% include 'wl/communications_modal.html' %} + {% include 'wl/logs_comm_entry_modal.html' %} {% endblock %} diff --git a/wildlifelicensing/apps/applications/templates/wl/issue/issue_licence.html b/wildlifelicensing/apps/applications/templates/wl/issue/issue_licence.html index 20e8f5c07a..9a94145e4b 100755 --- a/wildlifelicensing/apps/applications/templates/wl/issue/issue_licence.html +++ b/wildlifelicensing/apps/applications/templates/wl/issue/issue_licence.html @@ -16,18 +16,18 @@ {% endblock %} {% block requirements %} - require(['js/issue/issue_licence', 'js/communications_log'], function(issueLicence, commsLog) { - $(function () { - issueLicence.initialise(); - - commsLog.initCommunicationLog({ - showLogPopoverSelector: '#showLog', - showLogEntryModalSelector: '#addLogEntry', - logEntryModalSelector: '#logEntryModal', - logEntryFormSelector: '#addLogEntryForm', - logListURL: "{% url 'wl_applications:log_list' application.id %}", - addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" - }); + require([ + 'js/issue/issue_licence', + 'js/logs' + ], + function(issueLicence, logs) { + issueLicence.initialise(); + logs.initCommunicationLog({ + logListURL: "{% url 'wl_applications:log_list' application.id %}", + addLogEntryURL: "{% url 'wl_applications:add_log_entry' application.id %}" + }); + logs.initActionLog({ + logListURL: "{% url 'wl_applications:action_list' application.id %}", }); }); {% endblock %} @@ -116,9 +116,7 @@

{{ application.licence_type.name }}

- {% with add_text='Add application log entry' %} - {% include 'wl/communications_panel.html' %} - {% endwith %} + {% include 'wl/logs_panel.html' %} {% if payment_status == 'Awaiting Payment' %}
'), - logListURL: 'insert-default-url-here' - }); - - // if log table is in a popover, need to prepare log table container before initializing table or - // search/paging/etc won't show - if (options.showLogPopoverSelector) { - $logListContent = $('
').append($(options.logTableSelector)); - } - - // init log table - logDataTable = initLogTable(options.logListURL, options.logTableSelector); - - // init log table popover if provided - if (options.showLogPopoverSelector) { - $(options.showLogPopoverSelector).popover({ - container: 'body', - title: 'Action log', - content: $logListContent, - placement: 'right', - trigger: "manual", - html: true - }).click(function () { - var isVisible = $(this).data()['bs.popover'].tip().hasClass('in'); - if (!isVisible) { - logDataTable.ajax.reload(); - $(this).popover('show'); - $('[data-toggle="tooltip"]').tooltip(); - } else { - $(this).popover('hide'); - } - }); - } - } - - function initLogTable(logListURL, tableSelector) { - var $table = $(tableSelector), - tableOptions = { - paging: true, - info: true, - searching: true, - processing: true, - deferRender: true, - serverSide: false, - autowidth: true, - order: [[2, 'desc']], - // TODO: next one is to avoid the 'search' field to go out of the popover (table width is small). - // see https://datatables.net/reference/option/dom - dom: - "<'row'<'col-sm-5'l><'col-sm-6'f>>" + - "<'row'<'col-sm-12'tr>>" + - "<'row'<'col-sm-5'i><'col-sm-7'p>>", - ajax: { - url: logListURL - } - }, - colDefinitions = [ - { - title: 'Who', - data: 'who' - }, - { - title: 'What', - data: 'what' - }, - { - title: 'When', - data: 'when', - render: function (date) { - return moment(date).format(DATE_TIME_FORMAT); - } - } - ]; - - // set DT date format sorting - dataTable.setDateTimeFormat(DATE_TIME_FORMAT); - - // activate popover when table is drawn. - $table.on('draw.dt', function () { - var $tablePopover = $table.find('[data-toggle="popover"]'); - if ($tablePopover.length > 0) { - $tablePopover.popover(); - // the next line prevents from scrolling up to the top after clicking on the popover. - $($tablePopover).on('click', function (e) { - e.preventDefault(); - return true; - }); - } - }); - - return dataTable.initTable($table, tableOptions, colDefinitions); - } - - return { - init: function(options) { - return initActionsLog(options); - } - }; -}); \ No newline at end of file diff --git a/wildlifelicensing/apps/main/static/wl/js/communications_log.js b/wildlifelicensing/apps/main/static/wl/js/logs.js similarity index 67% rename from wildlifelicensing/apps/main/static/wl/js/communications_log.js rename to wildlifelicensing/apps/main/static/wl/js/logs.js index 0454e9fa91..852da2d2e7 100644 --- a/wildlifelicensing/apps/main/static/wl/js/communications_log.js +++ b/wildlifelicensing/apps/main/static/wl/js/logs.js @@ -7,10 +7,10 @@ define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment function initCommunicationLog(options) { // default options options = _.defaults(options || {}, { - showLogPopoverSelector: null, - showLogEntryModalSelector: null, - logEntryModalSelector: null, - logEntryFormSelector: null, + showLogPopoverSelector: '#showCommunicationLog', + showLogEntryModalSelector: '#addCommunicationLogEntry', + logEntryModalSelector: '#logCommEntryModal', + logEntryFormSelector: '#addLogCommEntryForm', logTableSelector: $('
'), logListURL: 'insert-default-url-here', addLogEntryURL: 'insert-default-url-here' @@ -35,7 +35,7 @@ define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment } // init log table - logDataTable = initLogTable(options.logListURL, options.logTableSelector); + logDataTable = initCommunicationTable(options.logListURL, options.logTableSelector); // init log table popover if provided if (options.showLogPopoverSelector) { @@ -87,7 +87,7 @@ define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment $logEntryModal.modal('hide'); // clear/reset form fields - $(this).find('#id_type').val($('#id_type option:first').val()); + $(this).find('#id_type').val($('#id_type').find('option:first').val()); $(this).find('#id_subject').val(''); $(this).find('#id_text').val(''); $(this).find('#id_attachment').val(''); @@ -99,7 +99,7 @@ define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment } } - function initLogTable(logListURL, tableSelector) { + function initCommunicationTable(logListURL, tableSelector) { function commaToNewline(s){ return s.replace(/[,;]/g, '\n'); } @@ -236,7 +236,108 @@ define(['jQuery', 'lodash', 'moment', 'js/wl.dataTable'], function ($, _, moment return dataTable.initTable($table, tableOptions, colDefinitions); } + function initActionLog(options) { + // multi-used selectors + var $logListContent, logDataTable; + + // default options + options = _.defaults(options || {}, { + showLogPopoverSelector: '#showActionLog', + logTableSelector: $('
'), + logListURL: 'insert-default-url-here' + }); + + // if log table is in a popover, need to prepare log table container before initializing table or + // search/paging/etc won't show + if (options.showLogPopoverSelector) { + $logListContent = $('
').append($(options.logTableSelector)); + } + + // init log table + logDataTable = initActionTable(options.logListURL, options.logTableSelector); + + // init log table popover if provided + if (options.showLogPopoverSelector) { + $(options.showLogPopoverSelector).popover({ + container: 'body', + title: 'Action log', + content: $logListContent, + placement: 'right', + trigger: "manual", + html: true + }).click(function () { + var isVisible = $(this).data()['bs.popover'].tip().hasClass('in'); + if (!isVisible) { + logDataTable.ajax.reload(); + $(this).popover('show'); + $('[data-toggle="tooltip"]').tooltip(); + } else { + $(this).popover('hide'); + } + }); + } + } + + function initActionTable(logListURL, tableSelector) { + var $table = $(tableSelector), + tableOptions = { + paging: true, + info: true, + searching: true, + processing: true, + deferRender: true, + serverSide: false, + autowidth: true, + order: [[2, 'desc']], + // TODO: next one is to avoid the 'search' field to go out of the popover (table width is small). + // see https://datatables.net/reference/option/dom + dom: + "<'row'<'col-sm-5'l><'col-sm-6'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + ajax: { + url: logListURL + } + }, + colDefinitions = [ + { + title: 'Who', + data: 'who' + }, + { + title: 'What', + data: 'what' + }, + { + title: 'When', + data: 'when', + render: function (date) { + return moment(date).format(DATE_TIME_FORMAT); + } + } + ]; + + // set DT date format sorting + dataTable.setDateTimeFormat(DATE_TIME_FORMAT); + + // activate popover when table is drawn. + $table.on('draw.dt', function () { + var $tablePopover = $table.find('[data-toggle="popover"]'); + if ($tablePopover.length > 0) { + $tablePopover.popover(); + // the next line prevents from scrolling up to the top after clicking on the popover. + $($tablePopover).on('click', function (e) { + e.preventDefault(); + return true; + }); + } + }); + + return dataTable.initTable($table, tableOptions, colDefinitions); + } + return { - initCommunicationLog: initCommunicationLog + initCommunicationLog: initCommunicationLog, + initActionLog: initActionLog }; }); \ No newline at end of file diff --git a/wildlifelicensing/apps/main/templates/wl/communications_modal.html b/wildlifelicensing/apps/main/templates/wl/logs_comm_entry_modal.html similarity index 82% rename from wildlifelicensing/apps/main/templates/wl/communications_modal.html rename to wildlifelicensing/apps/main/templates/wl/logs_comm_entry_modal.html index be37ba5792..5643d96c5f 100644 --- a/wildlifelicensing/apps/main/templates/wl/communications_modal.html +++ b/wildlifelicensing/apps/main/templates/wl/logs_comm_entry_modal.html @@ -1,13 +1,13 @@ {% load bootstrap3 %} - diff --git a/wildlifelicensing/apps/applications/urls.py b/wildlifelicensing/apps/applications/urls.py index 7e4bf93158..e9492478cc 100755 --- a/wildlifelicensing/apps/applications/urls.py +++ b/wildlifelicensing/apps/applications/urls.py @@ -60,7 +60,7 @@ url('^enter-conditions/([0-9]+)/assessment/([0-9]+)/?$', EnterConditionsAssessorView.as_view(), name='enter_conditions_assessor'), url('^search-conditions/$', SearchConditionsView.as_view(), name='search_conditions'), - url('^create-condition/$', CreateConditionView.as_view(), name='create_condition'), + url('^create-condition/([0-9]+)/$', CreateConditionView.as_view(), name='create_condition'), url('^set-assessment-condition-state/$', SetAssessmentConditionState.as_view(), name='set_assessment_condition_state'), # issue diff --git a/wildlifelicensing/apps/applications/views/conditions.py b/wildlifelicensing/apps/applications/views/conditions.py index c6737dd88f..9a28974074 100755 --- a/wildlifelicensing/apps/applications/views/conditions.py +++ b/wildlifelicensing/apps/applications/views/conditions.py @@ -55,6 +55,9 @@ def post(self, request, *args, **kwargs): application.conditions.clear() application.save() + application.log_user_action( + ApplicationUserAction.ACTION_ENTER_CONDITIONS, + request) for order, condition_id in enumerate(request.POST.getlist('conditionID')): ApplicationCondition.objects.create(condition=Condition.objects.get(pk=condition_id), @@ -167,8 +170,15 @@ def get(self, request, *args, **kwargs): class CreateConditionView(OfficerRequiredMixin, View): def post(self, request, *args, **kwargs): try: - response = serialize(Condition.objects.create(code=request.POST.get('code'), text=request.POST.get('text'), - one_off=not request.POST.get('addToGeneralList', False))) + condition = Condition.objects.create(code=request.POST.get('code'), text=request.POST.get('text'), + one_off=not request.POST.get('addToGeneralList', False)) + if len(self.args) > 0: + application = get_object_or_404(Application, pk=self.args[0]) + application.log_user_action( + ApplicationUserAction.ACTION_CREATE_CONDITION_.format(condition), + request + ) + response = serialize(condition) except IntegrityError: response = 'This code has already been used. Please enter a unique code.' From 2fa8cb0fc154ba690efab0dac2183efc48b76548 Mon Sep 17 00:00:00 2001 From: serge Date: Thu, 13 Oct 2016 14:27:03 +0800 Subject: [PATCH 04/17] Added action log for assessor 'save' assessment Removed the 'open' assessment log. --- wildlifelicensing/apps/applications/models.py | 3 ++- .../apps/applications/views/conditions.py | 12 +++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/wildlifelicensing/apps/applications/models.py b/wildlifelicensing/apps/applications/models.py index c2cc8ee463..25be6dbb8a 100755 --- a/wildlifelicensing/apps/applications/models.py +++ b/wildlifelicensing/apps/applications/models.py @@ -233,7 +233,8 @@ class ApplicationUserAction(UserAction): ACTION_ENTER_CONDITIONS = "Enter Conditions" ACTION_CREATE_CONDITION_ = "Create condition {}" ACTION_ISSUE_LICENCE_ = "Issue Licence {}" - ACTION_OPEN_ASSESSMENT_ = "Open assessment {}" + # Assessors + ACTION_SAVE_ASSESSMENT_ = "Save assessment {}" ACTION_CONCLUDE_ASSESSMENT_ = "Conclude assessment {}" @classmethod diff --git a/wildlifelicensing/apps/applications/views/conditions.py b/wildlifelicensing/apps/applications/views/conditions.py index 9a28974074..078ef9bdff 100755 --- a/wildlifelicensing/apps/applications/views/conditions.py +++ b/wildlifelicensing/apps/applications/views/conditions.py @@ -100,10 +100,6 @@ def get_context_data(self, **kwargs): def get(self, request, *args, **kwargs): assessment = get_object_or_404(Assessment, pk=args[1]) - assessment.application.log_user_action( - ApplicationUserAction.ACTION_OPEN_ASSESSMENT_.format(assessment.assessor_group), - request) - if assessment.status == 'assessed': messages.warning(request, 'This assessment has already been concluded and may only be viewed in read-only mode.') return redirect('wl_applications:view_assessment', *args) @@ -120,11 +116,13 @@ def post(self, request, *args, **kwargs): assessment=assessment, order=order) # set the assessment request status to be 'assessed' if concluding + user_action = ApplicationUserAction.ACTION_SAVE_ASSESSMENT_ if 'conclude' in request.POST: assessment.status = 'assessed' - application.log_user_action( - ApplicationUserAction.ACTION_CONCLUDE_ASSESSMENT_.format(assessment.assessor_group), - request) + user_action = ApplicationUserAction.ACTION_CONCLUDE_ASSESSMENT_ + application.log_user_action( + user_action.format(assessment.assessor_group), + request) comment = request.POST.get('comment', '') if len(comment.strip()) > 0: From 9baf380c858202b398cab80dac965f23c4ff968e Mon Sep 17 00:00:00 2001 From: serge Date: Thu, 13 Oct 2016 14:58:38 +0800 Subject: [PATCH 05/17] Fixed tests to accommodate an update in the 'create_condition' url (added application pk) --- .../apps/applications/tests/test_conditions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wildlifelicensing/apps/applications/tests/test_conditions.py b/wildlifelicensing/apps/applications/tests/test_conditions.py index ca9052cb3f..827a5e22b3 100755 --- a/wildlifelicensing/apps/applications/tests/test_conditions.py +++ b/wildlifelicensing/apps/applications/tests/test_conditions.py @@ -31,7 +31,7 @@ def setUp(self): self.urls_post = [ { - 'url': reverse('wl_applications:create_condition'), + 'url': reverse('wl_applications:create_condition', args=[self.application.pk]), 'data': { 'code': '123488374', 'text': 'condition text' @@ -111,7 +111,7 @@ def test_assessor_access_limited(self): ] urls_post_forbidden = [ { - 'url': reverse('wl_applications:create_condition'), + 'url': reverse('wl_applications:create_condition', args=[self.application.pk]), 'data': { 'code': '123488374', 'text': 'condition text' @@ -181,7 +181,7 @@ def test_assessor_access_normal(self): ] urls_post_forbidden = [ { - 'url': reverse('wl_applications:create_condition'), + 'url': reverse('wl_applications:create_condition', args=[self.application.pk]), 'data': { 'code': '123488374', 'text': 'condition text' From cf0281332fd2c5b22714cd846c82704b419d975b Mon Sep 17 00:00:00 2001 From: serge Date: Thu, 13 Oct 2016 16:18:49 +0800 Subject: [PATCH 06/17] Customer template: Fixed loading of log.js (was using the old one) Fixed customer get log list: was using the olf field 'officer' now renamed 'staff' --- .../customer_management/templates/wl/customer_lookup.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wildlifelicensing/apps/customer_management/templates/wl/customer_lookup.html b/wildlifelicensing/apps/customer_management/templates/wl/customer_lookup.html index dc64f8eb76..cc3a940486 100755 --- a/wildlifelicensing/apps/customer_management/templates/wl/customer_lookup.html +++ b/wildlifelicensing/apps/customer_management/templates/wl/customer_lookup.html @@ -12,13 +12,14 @@ {% endblock %} {% block requirements %} - require(['js/customer_search', 'js/dash_tables', 'js/communications_log'], function (customerSearch, dashTables, commLog) { + require(['js/customer_search', 'js/dash_tables', 'js/logs'], function (customerSearch, dashTables, logs) { customerSearch.init(); {% if customer %} dashTables({data: {% if dataJSON %} {{ dataJSON|safe }} {% else %} {} {% endif %}}); - commLog.initCommunicationLog({ + logs.initCommunicationLog({ + showLogPopoverSelector: null, showLogEntryModalSelector: '#addLogEntry', logEntryModalSelector: '#logEntryModal', logEntryFormSelector: '#addLogEntryForm', From 6a792df07db27a2b47c2d040e3f3c09a7b2aee80 Mon Sep 17 00:00:00 2001 From: serge Date: Thu, 13 Oct 2016 16:19:03 +0800 Subject: [PATCH 07/17] Fixed customer get log list: was using the olf field 'officer' now renamed 'staff' --- wildlifelicensing/apps/main/views.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/wildlifelicensing/apps/main/views.py b/wildlifelicensing/apps/main/views.py index 0525f73948..3f4ec4ad40 100755 --- a/wildlifelicensing/apps/main/views.py +++ b/wildlifelicensing/apps/main/views.py @@ -251,14 +251,20 @@ def post(self, request, *args, **kwargs): class CommunicationsLogListView(OfficerRequiredMixin, View): + serial_template = { + 'exclude': ['communicationslogentry_ptr', 'customer', 'staff'], + 'posthook': format_communications_log_entry + } + def get(self, request, *args, **kwargs): - q = Q(officer=args[0]) | Q(customer=args[0]) + q = Q(staff=args[0]) | Q(customer=args[0]) - data = serialize(CommunicationsLogEntry.objects.filter(q).order_by('created'), - posthook=format_communications_log_entry, - exclude=['communicationslogentry_ptr', 'customer', 'officer']), + data = serialize( + CommunicationsLogEntry.objects.filter(q).order_by('created'), + **self.serial_template + ) - return JsonResponse({'data': data[0]}, safe=False, encoder=WildlifeLicensingJSONEncoder) + return JsonResponse({'data': data}, safe=False, encoder=WildlifeLicensingJSONEncoder) class AddCommunicationsLogEntryView(OfficerRequiredMixin, View): From 9038801636ed10ceafb20a41a5f9c06dcef5d022 Mon Sep 17 00:00:00 2001 From: serge Date: Fri, 14 Oct 2016 16:04:20 +0800 Subject: [PATCH 08/17] Code reformat --- .../apps/applications/views/conditions.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/wildlifelicensing/apps/applications/views/conditions.py b/wildlifelicensing/apps/applications/views/conditions.py index 078ef9bdff..94c57ce8a4 100755 --- a/wildlifelicensing/apps/applications/views/conditions.py +++ b/wildlifelicensing/apps/applications/views/conditions.py @@ -12,7 +12,7 @@ from wildlifelicensing.apps.main.models import Condition from wildlifelicensing.apps.main.mixins import OfficerRequiredMixin, OfficerOrAssessorRequiredMixin from wildlifelicensing.apps.main.serializers import WildlifeLicensingJSONEncoder -from wildlifelicensing.apps.applications.models import Application, ApplicationCondition, Assessment,\ +from wildlifelicensing.apps.applications.models import Application, ApplicationCondition, Assessment, \ AssessmentCondition, ApplicationUserAction from wildlifelicensing.apps.applications.utils import append_app_document_to_schema_data, convert_documents_to_url, \ get_log_entry_to, format_application, format_assessment, ASSESSMENT_CONDITION_ACCEPTANCE_STATUSES @@ -37,9 +37,11 @@ def get_context_data(self, **kwargs): kwargs['application'] = serialize(application, posthook=format_application) kwargs['form_structure'] = application.licence_type.application_schema - kwargs['assessments'] = serialize(Assessment.objects.filter(application=application), posthook=format_assessment) + kwargs['assessments'] = serialize(Assessment.objects.filter(application=application), + posthook=format_assessment) - kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), fromm=self.request.user.get_full_name()) + kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), + fromm=self.request.user.get_full_name()) kwargs['payment_status'] = payment_utils.PAYMENT_STATUSES.get(payment_utils. get_application_payment_status(application)) @@ -73,7 +75,6 @@ class EnterConditionsAssessorView(CanPerformAssessmentMixin, TemplateView): template_name = 'wl/conditions/assessor_enter_conditions.html' success_url = reverse_lazy('wl_dashboard:home') - def get_context_data(self, **kwargs): application = get_object_or_404(Application, pk=self.args[0]) assessment = get_object_or_404(Assessment, pk=self.args[1]) @@ -93,7 +94,8 @@ def get_context_data(self, **kwargs): kwargs['other_assessments'] = serialize(Assessment.objects.filter(application=application). exclude(id=assessment.id).order_by('id'), posthook=format_assessment) - kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), fromm=self.request.user.get_full_name()) + kwargs['log_entry_form'] = ApplicationLogEntryForm(to=get_log_entry_to(application), + fromm=self.request.user.get_full_name()) return super(EnterConditionsAssessorView, self).get_context_data(**kwargs) @@ -101,7 +103,8 @@ def get(self, request, *args, **kwargs): assessment = get_object_or_404(Assessment, pk=args[1]) if assessment.status == 'assessed': - messages.warning(request, 'This assessment has already been concluded and may only be viewed in read-only mode.') + messages.warning(request, + 'This assessment has already been concluded and may only be viewed in read-only mode.') return redirect('wl_applications:view_assessment', *args) return super(EnterConditionsAssessorView, self).get(*args, **kwargs) @@ -142,7 +145,7 @@ def post(self, request, *args, **kwargs): send_assessment_done_email(assessment, request) messages.success(request, 'The application assessment has been forwarded back to the Wildlife Licensing ' - 'office for review.') + 'office for review.') return redirect(self.success_url) else: @@ -169,7 +172,7 @@ class CreateConditionView(OfficerRequiredMixin, View): def post(self, request, *args, **kwargs): try: condition = Condition.objects.create(code=request.POST.get('code'), text=request.POST.get('text'), - one_off=not request.POST.get('addToGeneralList', False)) + one_off=not request.POST.get('addToGeneralList', False)) if len(self.args) > 0: application = get_object_or_404(Application, pk=self.args[0]) application.log_user_action( From 89f7380cf306dfd7e7ec440ef094e16be3d3bb43 Mon Sep 17 00:00:00 2001 From: tony Date: Tue, 18 Oct 2016 11:37:21 +0800 Subject: [PATCH 09/17] W.I.P. Have basic expanding collapsing working for sections and groups. --- .../handlebars_templates/group.handlebars | 13 +++++---- .../handlebars_templates/section.handlebars | 6 ++-- .../static/wl/js/entry/application_entry.js | 28 ++++++++++++++++++- .../wl/js/precompiled_handlebars_templates.js | 2 +- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars b/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars index 43dd21eca0..2148b32ec1 100755 --- a/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars +++ b/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars @@ -1,5 +1,5 @@
-

{{label}}

+

{{label}}

{{#unless isRemovable}} {{#if help_text}}

{{{help_text}}}

@@ -7,16 +7,19 @@ {{/unless}}
-
+ +
{{#unless isPreviewMode }} {{#if isRepeatable }} Copy {{label}} {{/if}} -
- Remove -
+ +   |   + Remove {{label}} + {{/unless}} +
\ No newline at end of file diff --git a/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars b/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars index 5d9c98ba56..d09ca66bd4 100755 --- a/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars +++ b/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars @@ -1,2 +1,4 @@ -

{{label}}

-
\ No newline at end of file +

{{label}}

+
+
+
\ No newline at end of file diff --git a/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js b/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js index 4b042ec551..db5c1093ab 100755 --- a/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js +++ b/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js @@ -241,7 +241,7 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet $(this).replaceWith(speciesClone); }); - itemCopy.find('[id^="remove_' + item.name + '"]').removeClass('hidden'); + itemCopy.find('[id^="remove_' + item.name + '"]').parent().removeClass('hidden'); itemCopy.find('[id^="description_' + item.name + '"]').addClass('hidden'); itemSelector.after(itemCopy); groupInput.val(groupCount + 1); @@ -275,6 +275,32 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet formContainer.append(_layoutItem(formStructure[i], 0, '', itemData)); } + $('.collapse-link').each(function() { + var $link = $(this), + $linkSpan = $(this).find('span'), + $collapsible = $link.siblings('.children-anchor-point'); + + $link.click(function() { + $collapsible.collapse('toggle'); + }) + + $collapsible.on('hide.bs.collapse', function () { + if($link.hasClass('collapse-link-top')) { + $linkSpan.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); + } else if($link.hasClass('collapse-link-bottom')) { + $link.hide(); + } + }).on('show.bs.collapse', function() { + if($link.hasClass('collapse-link-top')) { + $linkSpan.removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); + } + }).on('shown.bs.collapse', function() { + if($link.hasClass('collapse-link-bottom')) { + $link.show(); + }; + }); + }); + // initialise parsley form validation $('form').parsley({ successClass: "has-success", diff --git a/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js b/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js index d20949bda4..267f0c52b6 100644 --- a/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js +++ b/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js @@ -1 +1 @@ -define(["handlebars.runtime"],function(l){l=l.default;var n=l.template,e=l.templates=l.templates||{};return e.species=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.radiobuttons=n({1:function(l,n,e,a,r,u,t){var s,i=l.lambda,o=l.escapeExpression,p=null!=n?n:{};return'
\n \n
\n"},2:function(l,n,e,a,r){return"required"},4:function(l,n,e,a,r){return"checked"},6:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,t){var s,i,o=null!=n?n:{};return'
\n \n"+(null!=(s=e.each.call(o,null!=n?n.options:n,{name:"each",hash:{},fn:l.program(1,r,0,u,t),inverse:l.noop,data:r}))?s:"")+(null!=(s=e.if.call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(6,r,0,u,t),inverse:l.noop,data:r}))?s:"")+"
"},useData:!0,useDepths:!0}),e.group=n({1:function(l,n,e,a,r){var u;return null!=(u=e.if.call(null!=n?n:{},null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(2,r,0),inverse:l.noop,data:r}))?u:""},2:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function";return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:i,u=typeof t===o?t.call(s,{name:"help_text",hash:{},data:r}):t)?u:"")+"

\n"},4:function(l,n,e,a,r){var u,t,s=null!=n?n:{};return(null!=(u=e.if.call(s,null!=n?n.isRepeatable:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+'
\n Remove\n
\n'},5:function(l,n,e,a,r){var u,t=null!=n?n:{},s=e.helperMissing,i="function",o=l.escapeExpression;return' Copy '+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:s,typeof u===i?u.call(t,{name:"label",hash:{},data:r}):u))+"\n"},7:function(l,n,e,a,r){return"hidden"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{};return'
\n

'+l.escapeExpression((t=null!=(t=e.label||(null!=n?n.label:n))?t:e.helperMissing,"function"==typeof t?t.call(s,{name:"label",hash:{},data:r}):t))+"

\n"+(null!=(u=e.unless.call(s,null!=n?n.isRemovable:n,{name:"unless",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+'
\n
\n
\n
\n'+(null!=(u=e.unless.call(s,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(4,r,0),inverse:l.noop,data:r}))?u:"")+"
\n
\n
"},useData:!0}),e.checkbox=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n "+p((t=null!=(t=e.label||(null!=n?n.label:n))?t:i,typeof t===o?t.call(s,{name:"label",hash:{},data:r}):t))+"\n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.declaration=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.section=n({compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t=null!=n?n:{},s=e.helperMissing,i="function",o=l.escapeExpression;return'

'+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:s,typeof u===i?u.call(t,{name:"label",hash:{},data:r}):u))+"

\r\n
"},useData:!0}),e.label=n({1:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{};return'
\r\n \r\n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.date=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n
\n \n \n \n \n
\n'+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.table=n({1:function(l,n,e,a,r){return"
\n"},3:function(l,n,e,a,r){return" \n"},5:function(l,n,e,a,r){return'
\n Add Row\n
\n'},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{};return"

"+l.escapeExpression((t=null!=(t=e.label||(null!=n?n.label:n))?t:e.helperMissing,"function"==typeof t?t.call(s,{name:"label",hash:{},data:r}):t))+'

\n
\n \n \n'+(null!=(u=e.each.call(s,null!=n?n.children:n,{name:"each",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e.unless.call(s,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(3,r,0),inverse:l.noop,data:r}))?u:"")+" \n \n \n \n \n
\n"+(null!=(u=e.unless.call(s,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")},useData:!0}),e.text_area=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))},5:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\r\n"},7:function(l,n,e,a,r){var u;return" \r\n "+l.escapeExpression((u=null!=(u=e.errors||(null!=n?n.errors:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"errors",hash:{},data:r}):u))+"\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e.if.call(s,null!=n?n.errors:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.number=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.file=n({1:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'

\n Currently: '+(null!=(u=(e.getURLFilename||n&&n.getURLFilename||i).call(s,null!=n?n.value:n,{name:"getURLFilename",hash:{},data:r}))?u:"")+'\n

\n \n'},3:function(l,n,e,a,r){var u;return'accept="'+l.escapeExpression((u=null!=(u=e.fileTypes||(null!=n?n.fileTypes:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"fileTypes",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){return"required"},7:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e.if.call(s,null!=n?n.value:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+' \n'+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,t,s=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e.if.call(s,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.select=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){return' \r\n'},5:function(l,n,e,a,r,u,t){var s,i=l.lambda,o=l.escapeExpression;return' \r\n"},6:function(l,n,e,a,r){return"selected"},8:function(l,n,e,a,r){var u,t;return'

'+(null!=(t=null!=(t=e.help_text||(null!=n?n.help_text:n))?t:e.helperMissing,u="function"==typeof t?t.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):t)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,t){var s,i,o=null!=n?n:{},p=e.helperMissing,c="function",h=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(s=e.if.call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(8,r,0,u,t),inverse:l.noop,data:r}))?s:"")+"
"},useData:!0,useDepths:!0}),e}); \ No newline at end of file +define(["handlebars.runtime"],function(l){l=l["default"];var n=l.template,e=l.templates=l.templates||{};return e.section=n({compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s=null!=n?n:{},t=e.helperMissing,i="function",o=l.escapeExpression;return'

'+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:t,typeof u===i?u.call(s,{name:"label",hash:{},data:r}):u))+'

\r\n
\r\n
\r\n
'},useData:!0}),e.checkbox=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n "+p((s=null!=(s=e.label||(null!=n?n.label:n))?s:i,typeof s===o?s.call(t,{name:"label",hash:{},data:r}):s))+"\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.radiobuttons=n({1:function(l,n,e,a,r,u,s){var t,i=l.lambda,o=l.escapeExpression,p=null!=n?n:{};return'
\n \n
\n"},2:function(l,n,e,a,r){return"required"},4:function(l,n,e,a,r){return"checked"},6:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,s){var t,i,o=null!=n?n:{};return'
\n \n"+(null!=(t=e.each.call(o,null!=n?n.options:n,{name:"each",hash:{},fn:l.program(1,r,0,u,s),inverse:l.noop,data:r}))?t:"")+(null!=(t=e["if"].call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(6,r,0,u,s),inverse:l.noop,data:r}))?t:"")+"
"},useData:!0,useDepths:!0}),e.table=n({1:function(l,n,e,a,r){return" \n"},3:function(l,n,e,a,r){return" \n"},5:function(l,n,e,a,r){return'
\n Add Row\n
\n'},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return"

"+l.escapeExpression((s=null!=(s=e.label||(null!=n?n.label:n))?s:e.helperMissing,"function"==typeof s?s.call(t,{name:"label",hash:{},data:r}):s))+'

\n\n \n \n'+(null!=(u=e.each.call(t,null!=n?n.children:n,{name:"each",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(3,r,0),inverse:l.noop,data:r}))?u:"")+" \n \n \n \n \n
\n"+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")},useData:!0}),e.select=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){return' \r\n'},5:function(l,n,e,a,r,u,s){var t,i=l.lambda,o=l.escapeExpression;return' \r\n"},6:function(l,n,e,a,r){return"selected"},8:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,s){var t,i,o=null!=n?n:{},p=e.helperMissing,c="function",h=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(t=e["if"].call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(8,r,0,u,s),inverse:l.noop,data:r}))?t:"")+"
"},useData:!0,useDepths:!0}),e.label=n({1:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return'
\r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.declaration=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.number=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.group=n({1:function(l,n,e,a,r){var u;return null!=(u=e["if"].call(null!=n?n:{},null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(2,r,0),inverse:l.noop,data:r}))?u:""},2:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function";return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:i,u=typeof s===o?s.call(t,{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},4:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return(null!=(u=e["if"].call(t,null!=n?n.isRepeatable:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+' \n   |  \n Remove '+p((s=null!=(s=e.label||(null!=n?n.label:n))?s:i,typeof s===o?s.call(t,{name:"label",hash:{},data:r}):s))+"\n \n"},5:function(l,n,e,a,r){var u,s=null!=n?n:{},t=e.helperMissing,i="function",o=l.escapeExpression;return' Copy '+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:t,typeof u===i?u.call(s,{name:"label",hash:{},data:r}):u))+"\n"},7:function(l,n,e,a,r){return"hidden"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return'
\n

'+l.escapeExpression((s=null!=(s=e.label||(null!=n?n.label:n))?s:e.helperMissing,"function"==typeof s?s.call(t,{name:"label",hash:{},data:r}):s))+"

\n"+(null!=(u=e.unless.call(t,null!=n?n.isRemovable:n,{name:"unless",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+'
\n
\n \n
\n
\n'+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(4,r,0),inverse:l.noop,data:r}))?u:"")+' \n
\n
\n
'},useData:!0}),e.species=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text_area=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},7:function(l,n,e,a,r){var u;return" \r\n "+l.escapeExpression((u=null!=(u=e.errors||(null!=n?n.errors:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"errors",hash:{},data:r}):u))+"\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e["if"].call(t,null!=n?n.errors:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.file=n({1:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'

\n Currently: '+(null!=(u=(e.getURLFilename||n&&n.getURLFilename||i).call(t,null!=n?n.value:n,{name:"getURLFilename",hash:{},data:r}))?u:"")+'\n

\n \n'},3:function(l,n,e,a,r){var u;return'accept="'+l.escapeExpression((u=null!=(u=e.fileTypes||(null!=n?n.fileTypes:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"fileTypes",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){return"required"},7:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e["if"].call(t,null!=n?n.value:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+' \n'+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.date=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n
\n \n \n \n \n
\n'+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e}); \ No newline at end of file From ee813fdb019553135a417f1d4cd578d7f28ebceb Mon Sep 17 00:00:00 2001 From: Tony Prior Date: Tue, 18 Oct 2016 15:40:17 +0800 Subject: [PATCH 10/17] Fixed collapsers for group copies. Made collapsibles work for application previews. Fixed bug with groups copying twice when clicking the copy link of a copy. --- .../handlebars_templates/group.handlebars | 4 +- .../handlebars_templates/section.handlebars | 2 +- .../static/wl/js/entry/application_entry.js | 73 ++++++++++++------- .../static/wl/js/entry/application_preview.js | 32 +++++++- .../static/wl/js/process/preview_versions.js | 32 ++++++++ .../wl/js/precompiled_handlebars_templates.js | 2 +- 6 files changed, 114 insertions(+), 31 deletions(-) diff --git a/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars b/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars index 2148b32ec1..aae0cceadd 100755 --- a/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars +++ b/wildlifelicensing/apps/applications/handlebars_templates/group.handlebars @@ -7,7 +7,7 @@ {{/unless}}
- +
{{#unless isPreviewMode }} @@ -19,7 +19,7 @@ Remove {{label}} {{/unless}} - +
\ No newline at end of file diff --git a/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars b/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars index d09ca66bd4..87b6f94202 100755 --- a/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars +++ b/wildlifelicensing/apps/applications/handlebars_templates/section.handlebars @@ -1,4 +1,4 @@ -

{{label}}

+

{{label}}


\ No newline at end of file diff --git a/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js b/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js index db5c1093ab..30e5551df7 100755 --- a/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js +++ b/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js @@ -16,6 +16,10 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet _initInputField(item, $itemContainer); + if(item.type === 'section' || item.type === 'group') { + _initCollapsible($itemContainer); + } + // unset item name and value if they were set otherwise there may be unintended consequences if extra form fields are created dynamically item.name = item.name.slice(0, item.name.indexOf(suffix)); item.value = undefined; @@ -190,6 +194,44 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet } } + function _initCollapsible($itemContainer, removeExistingEvents) { + var $collapsible = $itemContainer.find('.children-anchor-point').first(), + $topLink = $collapsible.siblings('.collapse-link-top'), + $topLinkSpan = $topLink.find('span'), + $bottomLink = $collapsible.siblings('.collapse-link-bottom').first(); + + if(removeExistingEvents) { + $collapsible.off('hide.bs.collapse').off('show.bs.collapse').off('shown.bs.collapse'); + $topLink.off('click'); + if($bottomLink.length) { + $bottomLink.off('click'); + } + } + + $collapsible.on('hide.bs.collapse', function () { + $topLinkSpan.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); + if($bottomLink.length > 0) { + $bottomLink.hide(); + } + }).on('show.bs.collapse', function() { + $topLinkSpan.removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); + }).on('shown.bs.collapse', function() { + if($bottomLink.length) { + $bottomLink.show(); + }; + }); + + $topLink.click(function() { + $collapsible.collapse('toggle'); + }); + + if($bottomLink.length) { + $bottomLink.click(function() { + $collapsible.collapse('toggle'); + }); + } + } + function _setupCopyRemoveEvents(item, itemSelector, suffix) { itemSelector.find('[id^="copy_' + item.name + '"]').first().click(function(e) { var itemCopy = itemSelector.clone(true, true), @@ -241,9 +283,14 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet $(this).replaceWith(speciesClone); }); + itemCopy.find('[id^="copy_' + item.name + '"]').off('click'); itemCopy.find('[id^="remove_' + item.name + '"]').parent().removeClass('hidden'); itemCopy.find('[id^="description_' + item.name + '"]').addClass('hidden'); + itemSelector.after(itemCopy); + + _initCollapsible(itemCopy, true); + groupInput.val(groupCount + 1); _setupCopyRemoveEvents(item, itemCopy, suffix); }); @@ -275,32 +322,6 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet formContainer.append(_layoutItem(formStructure[i], 0, '', itemData)); } - $('.collapse-link').each(function() { - var $link = $(this), - $linkSpan = $(this).find('span'), - $collapsible = $link.siblings('.children-anchor-point'); - - $link.click(function() { - $collapsible.collapse('toggle'); - }) - - $collapsible.on('hide.bs.collapse', function () { - if($link.hasClass('collapse-link-top')) { - $linkSpan.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); - } else if($link.hasClass('collapse-link-bottom')) { - $link.hide(); - } - }).on('show.bs.collapse', function() { - if($link.hasClass('collapse-link-top')) { - $linkSpan.removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); - } - }).on('shown.bs.collapse', function() { - if($link.hasClass('collapse-link-bottom')) { - $link.show(); - }; - }); - }); - // initialise parsley form validation $('form').parsley({ successClass: "has-success", diff --git a/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js b/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js index 141608087d..c1aac6dd2d 100755 --- a/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js +++ b/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js @@ -17,6 +17,7 @@ define(['jQuery', 'handlebars.runtime', 'bootstrap', 'js/handlebars_helpers', 'j if(item.type === 'section' || item.type === 'group') { item.isPreviewMode = true; itemContainer.append(Handlebars.templates[item.type](item)); + _initCollapsible(itemContainer); } else if (item.type === 'radiobuttons' || item.type === 'select') { var isSpecified = false; itemContainer.append($('
diff --git a/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js b/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js index 265c6264d4..a3f2eb5c8e 100644 --- a/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js +++ b/wildlifelicensing/static/wl/js/precompiled_handlebars_templates.js @@ -1 +1 @@ -define(["handlebars.runtime"],function(l){l=l["default"];var n=l.template,e=l.templates=l.templates||{};return e.label=n({1:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return'
\r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.table=n({1:function(l,n,e,a,r){return" \n"},3:function(l,n,e,a,r){return" \n"},5:function(l,n,e,a,r){return'
\n Add Row\n
\n'},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return"

"+l.escapeExpression((s=null!=(s=e.label||(null!=n?n.label:n))?s:e.helperMissing,"function"==typeof s?s.call(t,{name:"label",hash:{},data:r}):s))+'

\n\n \n \n'+(null!=(u=e.each.call(t,null!=n?n.children:n,{name:"each",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(3,r,0),inverse:l.noop,data:r}))?u:"")+" \n \n \n \n \n
\n"+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")},useData:!0}),e.species=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.group=n({1:function(l,n,e,a,r){var u;return null!=(u=e["if"].call(null!=n?n:{},null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(2,r,0),inverse:l.noop,data:r}))?u:""},2:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function";return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:i,u=typeof s===o?s.call(t,{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},4:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return(null!=(u=e["if"].call(t,null!=n?n.isRepeatable:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+' \n   |  \n Remove '+p((s=null!=(s=e.label||(null!=n?n.label:n))?s:i,typeof s===o?s.call(t,{name:"label",hash:{},data:r}):s))+"\n \n"},5:function(l,n,e,a,r){var u,s=null!=n?n:{},t=e.helperMissing,i="function",o=l.escapeExpression;return' Copy '+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:t,typeof u===i?u.call(s,{name:"label",hash:{},data:r}):u))+"\n"},7:function(l,n,e,a,r){return"hidden"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return'
\n

'+l.escapeExpression((s=null!=(s=e.label||(null!=n?n.label:n))?s:e.helperMissing,"function"==typeof s?s.call(t,{name:"label",hash:{},data:r}):s))+"

\n"+(null!=(u=e.unless.call(t,null!=n?n.isRemovable:n,{name:"unless",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+'
\n
\n \n
\n
\n'+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(4,r,0),inverse:l.noop,data:r}))?u:"")+' \n
\n
\n
'},useData:!0}),e.date=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n
\n \n \n \n \n
\n'+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text_area=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},7:function(l,n,e,a,r){var u;return" \r\n "+l.escapeExpression((u=null!=(u=e.errors||(null!=n?n.errors:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"errors",hash:{},data:r}):u))+"\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e["if"].call(t,null!=n?n.errors:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.declaration=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.file=n({1:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'

\n Currently: '+(null!=(u=(e.getURLFilename||n&&n.getURLFilename||i).call(t,null!=n?n.value:n,{name:"getURLFilename",hash:{},data:r}))?u:"")+'\n

\n \n'},3:function(l,n,e,a,r){var u;return'accept="'+l.escapeExpression((u=null!=(u=e.fileTypes||(null!=n?n.fileTypes:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"fileTypes",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){return"required"},7:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e["if"].call(t,null!=n?n.value:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+' \n'+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.radiobuttons=n({1:function(l,n,e,a,r,u,s){var t,i=l.lambda,o=l.escapeExpression,p=null!=n?n:{};return'
\n \n
\n"},2:function(l,n,e,a,r){return"required"},4:function(l,n,e,a,r){return"checked"},6:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,s){var t,i,o=null!=n?n:{};return'
\n \n"+(null!=(t=e.each.call(o,null!=n?n.options:n,{name:"each",hash:{},fn:l.program(1,r,0,u,s),inverse:l.noop,data:r}))?t:"")+(null!=(t=e["if"].call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(6,r,0,u,s),inverse:l.noop,data:r}))?t:"")+"
"},useData:!0,useDepths:!0}),e.number=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.checkbox=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n "+p((s=null!=(s=e.label||(null!=n?n.label:n))?s:i,typeof s===o?s.call(t,{name:"label",hash:{},data:r}):s))+"\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.section=n({compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s=null!=n?n:{},t=e.helperMissing,i="function",o=l.escapeExpression;return'

'+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:t,typeof u===i?u.call(s,{name:"label",hash:{},data:r}):u))+'

\r\n
\r\n
\r\n
'},useData:!0}),e.select=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){return' \r\n'},5:function(l,n,e,a,r,u,s){var t,i=l.lambda,o=l.escapeExpression;return' \r\n"},6:function(l,n,e,a,r){return"selected"},8:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,s){var t,i,o=null!=n?n:{},p=e.helperMissing,c="function",h=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(t=e["if"].call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(8,r,0,u,s),inverse:l.noop,data:r}))?t:"")+"
"},useData:!0,useDepths:!0}),e}); \ No newline at end of file +define(["handlebars.runtime"],function(l){l=l["default"];var n=l.template,e=l.templates=l.templates||{};return e.label=n({1:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return'
\r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.table=n({1:function(l,n,e,a,r){return" \n"},3:function(l,n,e,a,r){return" \n"},5:function(l,n,e,a,r){return'
\n Add Row\n
\n'},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return"

"+l.escapeExpression((s=null!=(s=e.label||(null!=n?n.label:n))?s:e.helperMissing,"function"==typeof s?s.call(t,{name:"label",hash:{},data:r}):s))+'

\n\n \n \n'+(null!=(u=e.each.call(t,null!=n?n.children:n,{name:"each",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(3,r,0),inverse:l.noop,data:r}))?u:"")+" \n \n \n \n \n
\n"+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")},useData:!0}),e.species=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.group=n({1:function(l,n,e,a,r){var u;return null!=(u=e["if"].call(null!=n?n:{},null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(2,r,0),inverse:l.noop,data:r}))?u:""},2:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function";return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:i,u=typeof s===o?s.call(t,{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},4:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return(null!=(u=e["if"].call(t,null!=n?n.isRepeatable:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+' \n |\n Remove '+p((s=null!=(s=e.label||(null!=n?n.label:n))?s:i,typeof s===o?s.call(t,{name:"label",hash:{},data:r}):s))+"\n \n"},5:function(l,n,e,a,r){var u,s=null!=n?n:{},t=e.helperMissing,i="function",o=l.escapeExpression;return' Copy '+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:t,typeof u===i?u.call(s,{name:"label",hash:{},data:r}):u))+"\n"},7:function(l,n,e,a,r){return"hidden"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{};return'
\n

'+l.escapeExpression((s=null!=(s=e.label||(null!=n?n.label:n))?s:e.helperMissing,"function"==typeof s?s.call(t,{name:"label",hash:{},data:r}):s))+"

\n"+(null!=(u=e.unless.call(t,null!=n?n.isRemovable:n,{name:"unless",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+'
\n
\n \n
\n
\n'+(null!=(u=e.unless.call(t,null!=n?n.isPreviewMode:n,{name:"unless",hash:{},fn:l.program(4,r,0),inverse:l.noop,data:r}))?u:"")+' \n
\n
\n
'},useData:!0}),e.date=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n
\n \n \n \n \n
\n'+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.text_area=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},7:function(l,n,e,a,r){var u;return" \r\n "+l.escapeExpression((u=null!=(u=e.errors||(null!=n?n.errors:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"errors",hash:{},data:r}):u))+"\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+(null!=(u=e["if"].call(t,null!=n?n.errors:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.declaration=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.file=n({1:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'

\n Currently: '+(null!=(u=(e.getURLFilename||n&&n.getURLFilename||i).call(t,null!=n?n.value:n,{name:"getURLFilename",hash:{},data:r}))?u:"")+'\n

\n \n'},3:function(l,n,e,a,r){var u;return'accept="'+l.escapeExpression((u=null!=(u=e.fileTypes||(null!=n?n.fileTypes:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"fileTypes",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){return"required"},7:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n \n"+(null!=(u=e["if"].call(t,null!=n?n.value:n,{name:"if",hash:{},fn:l.program(1,r,0),inverse:l.noop,data:r}))?u:"")+' \n'+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(7,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.radiobuttons=n({1:function(l,n,e,a,r,u,s){var t,i=l.lambda,o=l.escapeExpression,p=null!=n?n:{};return'
\n \n
\n"},2:function(l,n,e,a,r){return"required"},4:function(l,n,e,a,r){return"checked"},6:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,s){var t,i,o=null!=n?n:{};return'
\n \n"+(null!=(t=e.each.call(o,null!=n?n.options:n,{name:"each",hash:{},fn:l.program(1,r,0,u,s),inverse:l.noop,data:r}))?t:"")+(null!=(t=e["if"].call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(6,r,0,u,s),inverse:l.noop,data:r}))?t:"")+"
"},useData:!0,useDepths:!0}),e.number=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){var u;return'value="'+l.escapeExpression((u=null!=(u=e.value||(null!=n?n.value:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"value",hash:{},data:r}):u))+'"'},5:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.checkbox=n({1:function(l,n,e,a,r){return"data-parsley-required"},3:function(l,n,e,a,r){return"checked"},5:function(l,n,e,a,r){var u;return'

'+l.escapeExpression((u=null!=(u=e.help_text||(null!=n?n.help_text:n))?u:e.helperMissing,"function"==typeof u?u.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):u))+"

\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s,t=null!=n?n:{},i=e.helperMissing,o="function",p=l.escapeExpression;return'
\n "+p((s=null!=(s=e.label||(null!=n?n.label:n))?s:i,typeof s===o?s.call(t,{name:"label",hash:{},data:r}):s))+"\n"+(null!=(u=e["if"].call(t,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(5,r,0),inverse:l.noop,data:r}))?u:"")+"
"},useData:!0}),e.section=n({compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r){var u,s=null!=n?n:{},t=e.helperMissing,i="function",o=l.escapeExpression;return'

'+o((u=null!=(u=e.label||(null!=n?n.label:n))?u:t,typeof u===i?u.call(s,{name:"label",hash:{},data:r}):u))+'

\r\n
\r\n
\r\n
'},useData:!0}),e.select=n({1:function(l,n,e,a,r){return"required"},3:function(l,n,e,a,r){return' \r\n'},5:function(l,n,e,a,r,u,s){var t,i=l.lambda,o=l.escapeExpression;return' \r\n"},6:function(l,n,e,a,r){return"selected"},8:function(l,n,e,a,r){var u,s;return'

'+(null!=(s=null!=(s=e.help_text||(null!=n?n.help_text:n))?s:e.helperMissing,u="function"==typeof s?s.call(null!=n?n:{},{name:"help_text",hash:{},data:r}):s)?u:"")+"

\r\n"},compiler:[7,">= 4.0.0"],main:function(l,n,e,a,r,u,s){var t,i,o=null!=n?n:{},p=e.helperMissing,c="function",h=l.escapeExpression;return'
\r\n \r\n \r\n"+(null!=(t=e["if"].call(o,null!=n?n.help_text:n,{name:"if",hash:{},fn:l.program(8,r,0,u,s),inverse:l.noop,data:r}))?t:"")+"
"},useData:!0,useDepths:!0}),e}); \ No newline at end of file From bc38da4336c9d6f599050ecdf34e48cc5f4b9f55 Mon Sep 17 00:00:00 2001 From: tony Date: Thu, 20 Oct 2016 14:34:21 +0800 Subject: [PATCH 13/17] Put licensing text in wl.bootstrap-treeview, refactor of EntryView get function. --- .../apps/applications/views/entry.py | 37 +++++++------------ .../static/wl/js/wl.bootstrap-treeview.js | 26 +++++++++++++ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/wildlifelicensing/apps/applications/views/entry.py b/wildlifelicensing/apps/applications/views/entry.py index e4fc988d79..ae9ff995d5 100755 --- a/wildlifelicensing/apps/applications/views/entry.py +++ b/wildlifelicensing/apps/applications/views/entry.py @@ -212,34 +212,32 @@ def get(self, request, *args, **kwargs): categories = [] - def _get_variants(variant_group, licence_type, current_params): + def __get_variants(variant_group, licence_type, current_params): variants = [] for variant in variant_group.variants.all(): variant_dict = {'text': variant.name} if variant_group.child is not None: - variant_dict['nodes'] = _get_variants(variant_group.child, licence_type, current_params + [variant.id]) + variant_dict['nodes'] = __get_variants(variant_group.child, licence_type, current_params + [variant.id]) else: params = urlencode({'variants': current_params + [variant.id]}, doseq=True) variant_dict['href'] = '{}?{}'.format(reverse('wl_applications:select_licence_type', args=(licence_type.id,)), params) - variant_dict['help_text'] = variant.help_text + variant_dict['help_text'] = variant.help_text variants.append(variant_dict) return variants - for category in WildlifeLicenceCategory.objects.all(): - category_dict = {'name': category.name, 'licence_types': []} - - for licence_type in WildlifeLicenceType.objects.filter(category=category, replaced_by__isnull=True): + def __populate_category_dict(category_dict, licence_type_queryset, categories): + for licence_type in licence_type_queryset: licence_type_dict = {'text': licence_type.name} if licence_type.variant_group is not None: - licence_type_dict['nodes'] = _get_variants(licence_type.variant_group, licence_type, []) + licence_type_dict['nodes'] = __get_variants(licence_type.variant_group, licence_type, []) else: licence_type_dict['href'] = reverse('wl_applications:select_licence_type', args=(licence_type.id,)) @@ -250,23 +248,14 @@ def _get_variants(variant_group, licence_type, current_params): categories.append(category_dict) - if WildlifeLicenceType.objects.filter(category__isnull=True, replaced_by__isnull=True).exists(): - category_dict = {'name': 'Other', 'licence_types': []} - - for licence_type in WildlifeLicenceType.objects.filter(category__isnull=True, replaced_by__isnull=True): - licence_type_dict = {'text': licence_type.name} - - if licence_type.variant_group is not None: - licence_type_dict['nodes'] = _get_variants(licence_type.variant_group, licence_type, []) - else: - licence_type_dict['href'] = reverse('wl_applications:select_licence_type', - args=(licence_type.id,)) - - licence_type_dict['help_text'] = licence_type.help_text - - category_dict['licence_types'].append(licence_type_dict) + for category in WildlifeLicenceCategory.objects.all(): + __populate_category_dict({'name': category.name, 'licence_types': []}, + WildlifeLicenceType.objects.filter(category=category, replaced_by__isnull=True), + categories) - categories.append(category_dict) + uncategorised_queryset = WildlifeLicenceType.objects.filter(category__isnull=True, replaced_by__isnull=True) + if uncategorised_queryset.exists(): + __populate_category_dict({'name': 'Other', 'licence_types': []}, uncategorised_queryset, categories) return render(request, self.template_name, {'categories': categories}) diff --git a/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js b/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js index 5a5f69be03..7fbb4186b7 100755 --- a/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js +++ b/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js @@ -1,3 +1,29 @@ +/* ========================================================= + * bootstrap-treeview.js v1.2.0 + * ========================================================= + * Copyright 2013 Jonathan Miles + * Project URL : http://www.jondmiles.com/bootstrap-treeview + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This version has been modified to allow rendering of help text for each + * node. This is done in the buildTree function. It was not possible to override + * this one function in another module because the Tree function is not accessible + * externally. + * + * ========================================================= */ + + define(['jQuery'], function ($) { /*global jQuery, console*/ From f99df982b4765163decf265e0cbd01a19366e894 Mon Sep 17 00:00:00 2001 From: tony Date: Thu, 20 Oct 2016 14:35:41 +0800 Subject: [PATCH 14/17] Made help text italic. --- wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js b/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js index 7fbb4186b7..2ad56a5839 100755 --- a/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js +++ b/wildlifelicensing/static/wl/js/wl.bootstrap-treeview.js @@ -618,7 +618,7 @@ define(['jQuery'], function ($) { if (node.help_text) { var width = level * HELP_TEXT_INDENT + HELP_TEXT_INDENT_BUFFER; treeItem.append($('
').text(node.help_text).css('color', 'black').css('margin-left', width). - css('cursor', 'default')); + css('font-style', 'italic').css('cursor', 'default')); } // Add item to the tree From d7495cb27bd0519e414d706bff4062bdc5bf2479 Mon Sep 17 00:00:00 2001 From: Serge Le Breton Date: Thu, 20 Oct 2016 14:56:25 +0800 Subject: [PATCH 15/17] Update application_preview.js --- .../applications/static/wl/js/entry/application_preview.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js b/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js index c1aac6dd2d..45800e0ea0 100755 --- a/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js +++ b/wildlifelicensing/apps/applications/static/wl/js/entry/application_preview.js @@ -130,7 +130,7 @@ define(['jQuery', 'handlebars.runtime', 'bootstrap', 'js/handlebars_helpers', 'j $collapsible.on('hide.bs.collapse', function () { $topLinkSpan.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); - if($bottomLink.length > 0) { + if($bottomLink.length) { $bottomLink.hide(); } }).on('show.bs.collapse', function() { @@ -187,4 +187,4 @@ define(['jQuery', 'handlebars.runtime', 'bootstrap', 'js/handlebars_helpers', 'j }); } }; -}); \ No newline at end of file +}); From 1f072cca6d08e31a1f5883c9feb355d7d8ccb948 Mon Sep 17 00:00:00 2001 From: Serge Le Breton Date: Thu, 20 Oct 2016 14:57:04 +0800 Subject: [PATCH 16/17] Update preview_versions.js --- .../applications/static/wl/js/process/preview_versions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wildlifelicensing/apps/applications/static/wl/js/process/preview_versions.js b/wildlifelicensing/apps/applications/static/wl/js/process/preview_versions.js index af5a898a2d..8e25d31607 100755 --- a/wildlifelicensing/apps/applications/static/wl/js/process/preview_versions.js +++ b/wildlifelicensing/apps/applications/static/wl/js/process/preview_versions.js @@ -229,7 +229,7 @@ define(['jQuery', 'handlebars.runtime', 'bootstrap', 'js/handlebars_helpers', 'j $collapsible.on('hide.bs.collapse', function () { $topLinkSpan.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); - if($bottomLink.length > 0) { + if($bottomLink.length) { $bottomLink.hide(); } }).on('show.bs.collapse', function() { @@ -272,4 +272,4 @@ define(['jQuery', 'handlebars.runtime', 'bootstrap', 'js/handlebars_helpers', 'j } } }; -}); \ No newline at end of file +}); From 809af3b40e722078a8e7b98649e8752e98f1951c Mon Sep 17 00:00:00 2001 From: Serge Le Breton Date: Thu, 20 Oct 2016 14:57:40 +0800 Subject: [PATCH 17/17] Update application_entry.js --- .../apps/applications/static/wl/js/entry/application_entry.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js b/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js index 30e5551df7..c598cfbf11 100755 --- a/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js +++ b/wildlifelicensing/apps/applications/static/wl/js/entry/application_entry.js @@ -210,7 +210,7 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet $collapsible.on('hide.bs.collapse', function () { $topLinkSpan.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); - if($bottomLink.length > 0) { + if($bottomLink.length) { $bottomLink.hide(); } }).on('show.bs.collapse', function() { @@ -355,4 +355,4 @@ define(['jQuery', 'handlebars.runtime', 'parsley', 'bootstrap', 'bootstrap-datet sectionList.affix({ offset: { top: sectionList.offset().top }}); } }; -}); \ No newline at end of file +});