Skip to content

Commit

Permalink
Forms: render sections
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienClairembault authored Feb 13, 2024
1 parent 7f4c447 commit 38a3d9c
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 13 deletions.
115 changes: 115 additions & 0 deletions js/form_renderer_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ class GlpiFormRendererController
*/
#target;

/**
* Active section index
* @type {number}
*/
#section_index;

/**
* Total number of sections
* @type {number}
*/
#number_of_sections;

/**
* Create a new GlpiFormRendererController instance for the given target.
* The target must be a valid form.
Expand All @@ -55,6 +67,12 @@ class GlpiFormRendererController
throw new Error("Target must be a valid form");
}

// Init section data
this.#section_index = 0;
this.#number_of_sections = $(this.#target)
.find("[data-glpi-form-renderer-section]")
.length;

// Init event handlers
this.#initEventHandlers();
}
Expand All @@ -70,6 +88,16 @@ class GlpiFormRendererController
$(this.#target)
.find(`[${action_attribute}=submit]`)
.on("click", () => this.#submitForm());

// Next section form action
$(this.#target)
.find(`[${action_attribute}=next-section]`)
.on("click", () => this.#goToNextSection());

// Previous section form action
$(this.#target)
.find(`[${action_attribute}=previous-section]`)
.on("click", () => this.#goToPreviousSection());
}

/**
Expand Down Expand Up @@ -97,4 +125,91 @@ class GlpiFormRendererController
$(document).trigger('glpi-form-renderer-submit-failed', e);
}
}

/**
* Go to the next section of the form.
*/
#goToNextSection() {
// Hide current section
$(this.#target)
.find(`[data-glpi-form-renderer-section=${this.#section_index}]`)
.addClass("d-none");

// Show next section
this.#section_index++;
$(this.#target)
.find(`[data-glpi-form-renderer-section=${this.#section_index}]`)
.removeClass("d-none");

// Update actions visibility
this.#updateActionsVisiblity();
}

/**
* Go to the previous section of the form.
*/
#goToPreviousSection() {
// Hide current section
$(this.#target)
.find(`[data-glpi-form-renderer-section=${this.#section_index}]`)
.addClass("d-none");

// Show preview section
this.#section_index--;
$(this.#target)
.find(`[data-glpi-form-renderer-section=${this.#section_index}]`)
.removeClass("d-none");

// Update actions visibility
this.#updateActionsVisiblity();
}

/**
* Update the visibility of the actions buttons depending on the active
* section of the form.
*/
#updateActionsVisiblity() {
if (this.#section_index == 0) {
// First section, show next button
$(this.#target)
.find("[data-glpi-form-renderer-action=submit]")
.addClass("d-none");

$(this.#target)
.find("[data-glpi-form-renderer-action=next-section]")
.removeClass("d-none");

$(this.#target)
.find("[data-glpi-form-renderer-action=previous-section]")
.addClass("d-none");

} else if (this.#section_index == (this.#number_of_sections - 1)) { // Minus 1 because section_index is 0-based
// Last section, show submit and previous button
$(this.#target)
.find("[data-glpi-form-renderer-action=submit]")
.removeClass("d-none");

$(this.#target)
.find("[data-glpi-form-renderer-action=next-section]")
.addClass("d-none");

$(this.#target)
.find("[data-glpi-form-renderer-action=previous-section]")
.removeClass("d-none");

} else {
// Any middle section, show next and previous button
$(this.#target)
.find("[data-glpi-form-renderer-action=submit]")
.addClass("d-none");

$(this.#target)
.find("[data-glpi-form-renderer-action=next-section]")
.removeClass("d-none");

$(this.#target)
.find("[data-glpi-form-renderer-action=previous-section]")
.removeClass("d-none");
}
}
}
1 change: 0 additions & 1 deletion src/Form/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
use Glpi\Application\View\TemplateRenderer;
use Html;
use Glpi\DBAL\QuerySubQuery;
use Glpi\Form\QuestionType\QuestionTypeShortAnswerText;
use Glpi\Form\QuestionType\QuestionTypesManager;
use Log;

Expand Down
8 changes: 8 additions & 0 deletions src/Form/Renderer/FormRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ final class FormRenderer
*/
public function render(Form $form): string
{
// Note: the "form_renderer_controller" must not be loaded here as this code
// may be called multiple times using AJAX requests, thus trying to load the
// javascript "GlpiFormRendererController" class multiple times and causing an
// error.
// Each pages that call this method through AJAX must instead include the
// JS controller themselves.

// Load template
$twig = TemplateRenderer::getInstance();
return $twig->render('pages/form_renderer.html.twig', [
'form' => $form,
Expand Down
57 changes: 45 additions & 12 deletions templates/pages/form_renderer.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,41 @@
# ---------------------------------------------------------------------
#}

{# TODO: Maybe it will also be possible to render form outside of modal #}
{# In this case, the modal specific structure and classes references could be conditioned with a parameter #}
{# Is this a single or multi sections forms ? #}
{% set is_single_section_form = form.getSections()|length == 1 %}

<form id="forms_form_answers" method="POST" action="{{ path("ajax/form/answer.php") }}">
<div class="modal-header">
<h5 class="modal-title">
{{ form.fields.name }}
</h5>
<div class="mt-3">
<h5 class="modal-title mb-3" id="display_form_modal_label">
{{ form.fields.name }}
</h5>

<div class="text-muted">
{{ form.fields.header|safe_html }}
</div>
</div>

<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ _x("button", "Close") }}"></button>
</div>

<div class="modal-body">
<div class="text-muted mb-4">
{{ form.fields.header|safe_html }}
</div>

{% for section in form.getSections() %}
{% for section in form.getSections() %}
{# Is this the first section of a form ? #}
{% set is_first_section = loop.index0 == 0 %}

{# Show only the first section of a multi section forms #}
<div
data-glpi-form-renderer-section="{{ loop.index0 }}"
class="{{ not is_single_section_form and not is_first_section ? "d-none" : "" }}"
>
<h2 class="mb-3">{{ section.fields.name }}</h2>

{% for question in section.getQuestions() %}
{# Compute question type #}
{% set question_type = question.getQuestionType() %}

{# Skip unknown types (may be a disabled plugin) #}
{% if question_type is not null %}
<div class="mb-3">
Expand All @@ -64,16 +80,33 @@
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endfor %}

<input type="hidden" name="forms_id" value="{{ form.fields.id }}">
<input type="hidden" name="forms_id" value="{{ form.fields.id }}">
</div>

<div class="modal-footer">
<button
type="button"
data-glpi-form-renderer-action="previous-section"
class="btn btn-ghost-secondary d-none"
>
{{ __("Back") }}
</button>

<button
type="button"
data-glpi-form-renderer-action="next-section"
class="btn btn-primary {{ is_single_section_form ? "d-none" : "" }}"
>
{{ __("Continue") }}
</button>

<button
type="button"
data-glpi-form-renderer-action="submit"
class="btn btn-primary"
class="btn btn-primary {{ not is_single_section_form ? "d-none" : "" }}"
>
{{ __("Send form") }}
</button>
Expand Down

0 comments on commit 38a3d9c

Please sign in to comment.