Non puoi selezionare più di 25 argomenti
Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
1658 righe
65 KiB
1658 righe
65 KiB
<?php |
|
|
|
trait eFormsManager_render { |
|
use BS4FormGenerator; |
|
|
|
function printField($field) { |
|
// Field |
|
$this->printFieldHeader($field ); |
|
echo $this->{$field["type"]}($field); |
|
$this->printFieldFooter(); |
|
} |
|
|
|
/** |
|
* Stampa una sezione basandosi sul modello concettuale |
|
* |
|
* @param ?String $name nome della sezione |
|
* @param Array $section struttura della sezione |
|
* @return void |
|
*/ |
|
function printSection(?String $name, Array $section) { |
|
// WORKAROUND se un field si trova nella root |
|
if(str_starts_with($name, "eforms2")) { |
|
return $this->printField($section); |
|
} |
|
|
|
// Repeatable |
|
if(!isset($section["__meta"])) { |
|
|
|
foreach($section as $key => $member) { |
|
$this->printSection($key, $member); |
|
} |
|
return; |
|
} |
|
|
|
extract($section["__meta"]); |
|
// Extract __meta fields as variables |
|
// Clear them from the array |
|
unset($section["__meta"]); |
|
|
|
$auto_collapse = str_contains(strtolower($name), "unpublish"); |
|
$collapsed = $auto_collapse ? "collapsed" : ""; |
|
$collapse_button = $this->button( |
|
[ |
|
"name" => "button", |
|
"required" => false, |
|
"size" => "pr-2", |
|
"type" => "button", |
|
"title" => "<span class=\"fa fa-sm fa-window-minimize\"></span><span class=\"fa fa-sm fa-plus\"></span>", |
|
"attrs" => [ |
|
"data-toggle" => "collapse", |
|
"data-target" => "#collapse-{$unique_identifier}", |
|
"class" => "btn btn-sm btn-block btn-outline-secondary mr-2 {$collapsed}", |
|
] |
|
]); |
|
|
|
// Display headers |
|
if($display_type == "SECTION") { |
|
|
|
$this->printSectionHeader($this->translate($label), $id, $unique_identifier, $collapse_button); |
|
|
|
} else if($display_type == "GROUP") { |
|
|
|
|
|
$add_button = $delete_button = ""; |
|
// First iteration |
|
if($repeatable) { |
|
if($iteration == 0) { |
|
$add_button = $this->createAddButton($unique_identifier, $section_object, $this->notice, $this->info['codice'], $prefix); |
|
} elseif($preventDelete === false) { |
|
$delete_button = $this->createDeleteButton($unique_identifier); |
|
} |
|
} |
|
|
|
$this->printGroupHeader( |
|
$this->translate($label), |
|
$id, |
|
$unique_identifier, |
|
$repeatable, |
|
$iteration, |
|
$total_iterations, |
|
$add_button, |
|
$delete_button, |
|
$collapse_button, |
|
$tabNameProvider ?? $this->translate($label) . " - " . ($iteration + 1) |
|
); |
|
} |
|
|
|
// For each member |
|
foreach($section as $key => $member) { |
|
|
|
// Print iteration |
|
if($display_type == "SECTION") { |
|
|
|
} |
|
|
|
if(isset($member["name"])) { |
|
|
|
$this->printField($member); |
|
|
|
} else { |
|
|
|
// Section |
|
$this->printSection($key, $member); |
|
|
|
} |
|
|
|
} |
|
|
|
if($display_type == "SECTION") { |
|
|
|
$this->printSectionFooter(); |
|
|
|
} |
|
|
|
if($display_type == "GROUP") { |
|
|
|
$this->printGroupFooter( |
|
$this->translate($label), |
|
$id, |
|
$unique_identifier, |
|
$repeatable, |
|
$iteration, |
|
$total_iterations, |
|
$add_button, |
|
$delete_button, |
|
$collapse_button |
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
/** |
|
* Print GUUE FORM |
|
* |
|
* @param mixed $section |
|
* @return void |
|
*/ |
|
public function printForm(Array $section, Int $subsection_index) : void { |
|
|
|
|
|
|
|
$full_structure = []; |
|
$section_structure = $this->createFormStructure($section, $subsection_index, true, $full_structure); |
|
if($_SESSION["utente"]->isSupportoOrRoot()) { |
|
// Print settings toggles |
|
?> |
|
<div class="card mb-3"> |
|
<div class="card-header"> |
|
<p class="h5 mb-0 text-muted">Strumenti di debug</p> |
|
</div> |
|
<div class="card-body"> |
|
<div class="row mx-0"> |
|
<?php |
|
//$this->printNoEFXButton($this->enable_efx_evaluation); |
|
$this->printShowLabelsButton($this->hide_labels); |
|
$this->printDebugEfxButton($this->advanced_debug); |
|
$this->printForcedSuggestionsButton($this->enable_forced_suggestions); |
|
|
|
// Print debug area |
|
if($this->mode === "edit" && $this->advanced_debug) { |
|
?> <div class="col-12 mt-3"> <?php |
|
$this->printDebugArea($full_structure); |
|
?> </div> <?php |
|
} |
|
?> |
|
</div> |
|
</div> |
|
</div> |
|
<?php |
|
} |
|
|
|
|
|
|
|
|
|
// Renderizziamo le integrazioni floating |
|
$this->renderIntegrationHelpers("floating"); |
|
|
|
|
|
|
|
|
|
echo "<input type='hidden' name='section-repetition' value='{$subsection_index}'>"; |
|
|
|
$ready = empty($this->info["codice"]) ? "" : "data-ready=1"; |
|
|
|
echo "<fieldset id='master-fieldset' disabled {$ready}>"; |
|
foreach($section_structure as $key => $section) { |
|
if($key === "__meta") continue; |
|
$this->printSection($key, $section); |
|
} |
|
|
|
// Prepare autosave URL |
|
if($this->enable_efx_evaluation) { |
|
$autosave_url = "/backend/guue/save.php?"; |
|
// Check for valid section |
|
if(preg_match("/GR-([A-Za-z0-9-_])+/i", $_GET["section"] ?? "") === 1) { |
|
$autosave_url .= "section=" . $_GET["section"]; |
|
// Check for valid subsection |
|
if(is_numeric($_GET["subsection_index"] ?? "")) { |
|
$autosave_url .= "&subsection_index=" . $_GET["subsection_index"]; |
|
} |
|
} |
|
?> |
|
<script type="text/javascript"> |
|
$(document).ready(() => { |
|
eForms2.update_uri = "<?= $autosave_url ?>"; |
|
eForms2.setup(); |
|
// Popoliamo i nomi interni |
|
eForms2.makeInternalLabels(); |
|
// Popoliamo i tasti di pin |
|
eForms2.addIntegrationPinButtons(); |
|
//eForms2.onFormChange(null); |
|
|
|
}); |
|
</script> |
|
<style> |
|
|
|
button[data-toggle] svg[data-icon='window-minimize'] { |
|
display: inline-block; |
|
} |
|
button[data-toggle].collapsed svg[data-icon='window-minimize'] { |
|
display: none; |
|
} |
|
button[data-toggle] svg[data-icon='plus'] { |
|
display: none; |
|
} |
|
button[data-toggle].collapsed svg[data-icon='plus'] { |
|
display: inline-block; |
|
} |
|
code { user-select: all;} |
|
/* Workaround for grow columns */ |
|
@media (min-width: 1200px) { |
|
.col-xl-6 { |
|
flex: 1 0 50%; |
|
max-width: 100%; |
|
} |
|
} |
|
/* Workaround for excessive padding */ |
|
.form-group.col-sm-12 { |
|
padding: 0 !important; |
|
} |
|
|
|
/* Workaround for tab-pane row */ |
|
.tab-pane .row .active { |
|
display: flex !important; |
|
} |
|
.tab-content > .active.row { |
|
display: flex !important; |
|
} |
|
|
|
.btn-xs { |
|
padding: 0 0.4rem; |
|
font-size: 0.8rem; |
|
} |
|
|
|
#master-fieldset > .col-12 { |
|
padding-left: 0 !important; padding-right: 0 !important; |
|
} |
|
</style> |
|
<?php |
|
} |
|
|
|
// Prepare ADD2GUUE |
|
?> |
|
<script type="text/javascript"> |
|
$(document).ready(() => { |
|
eForms2.codice = <?= $this->info["codice"] ?>; |
|
}); |
|
</script> |
|
<?php |
|
|
|
$this->insertJavascript(); |
|
} |
|
|
|
|
|
protected function printIntegrationSectionHeader(string $label, string $unique_identifier, string $collapse_button, string $position) { |
|
?> |
|
<div class="row mb-3 <?= $position === "floating" ? "" : "col-12" ?> integration-section-header" id='<?= $unique_identifier ?>'> |
|
<div class="col-12 "> |
|
<div class="card"> |
|
<div class="card-header"> |
|
<div class="row d-flex align-items-center"> |
|
<div class="col"> |
|
<p class="h5 mb-0 text-muted"> |
|
<span class="badge bg-primary text-white"> |
|
<span class="fa fa-lightbulb fa-sm"></span> |
|
<span><?= __guue("Suggerimenti") ?></span> |
|
</span> |
|
<span><?= $label ?></span> |
|
</p> |
|
</div> |
|
<?= $collapse_button ?> |
|
</div> |
|
</div> |
|
|
|
<div class="card-body"> |
|
<div class="collapse show" id="collapse-<?= $unique_identifier ?>"> |
|
<? |
|
} |
|
protected function printSectionHeader($label, $name, $unique_identifier, $collapse_button) { |
|
?> |
|
<div class="row mb-3 section-header" id='<?= $unique_identifier ?>'> |
|
<div class="col-12 "> |
|
<div class="card"> |
|
<div class="card-header"> |
|
<div class="row d-flex align-items-center"> |
|
<div class="col"> |
|
<p class="h2 border-bottom text-primary"><?= $label ?> <?php if(!$this->hide_labels): ?> <small>(<?= $name ?>)</small> <?php endif; ?></p> |
|
</div> |
|
<?= $collapse_button ?> |
|
</div> |
|
</div> |
|
|
|
<div class="card-body px-1"> |
|
<div class="collapse show" id="collapse-<?= $unique_identifier ?>"> |
|
<? |
|
$this->renderIntegrationHelpers($name); |
|
} |
|
|
|
protected function printGroupHeader(?String $label, ?String $name, String $unique_identifier , bool $repeatable, int $iteration, int $total_iterations, string $add_button, string $delete_button, string $collapse_button, string $tabName) : void { |
|
$auto_collapse = str_contains(strtolower($name), "unpublish"); |
|
|
|
if($repeatable) { |
|
?> |
|
<?php if ($iteration === 0) : ?> |
|
<!-- Header d'iterazione --> |
|
<div class="col-12"> |
|
<div class="card repeatable-card mb-3"> |
|
<div class="card-header"> |
|
<div class="row d-flex align-items-center"> |
|
<div class="col"> |
|
<p class="h4 mb-0 text-muted"><?= $label ?> <?php if(!$this->hide_labels): ?> <small>(<?= $name ?>)</small> <?php endif; ?> </p> |
|
</div> |
|
<?= $add_button ?> |
|
<?= $collapse_button ?> |
|
</div> |
|
</div> |
|
<div class="card-body px-1"> |
|
<div class="collapse show" id="collapse-<?= $unique_identifier ?>"> |
|
<?= $this->renderIntegrationHelpers($name); ?> |
|
<div class="repeatable_container" id="repeatable_<?= $unique_identifier ?>"> |
|
|
|
<?php endif; ?> |
|
<div id='<?= $unique_identifier ?>' data-tabname="<?= $tabName ?>" class="group-header pr-0 col-12"> |
|
<?php if($iteration !== 0) : ?> |
|
<?= $delete_button ?> |
|
<?php endif; ?> |
|
<? |
|
} else { |
|
?> |
|
|
|
<div id='<?= $unique_identifier ?>' class="group-header col-12 mb-3"> |
|
<div class="card"> |
|
<div class="card-header"> |
|
<div class="row d-flex align-items-center"> |
|
<div class="col"> |
|
<p class="h4 mb-0 text-muted"><?= $label ?> <?php if(!$this->hide_labels): ?> <small>(<?= $name ?>)</small> <?php endif; ?> </p> |
|
</div> |
|
<?= $collapse_button ?> |
|
</div> |
|
</div> |
|
<div class="card-body px-1"> |
|
<div class="collapse row mx-0 <?php if(!$auto_collapse): ?>show <?php endif; ?>" id="collapse-<?= $unique_identifier ?>"> |
|
<? $this->renderIntegrationHelpers($name); |
|
|
|
} |
|
|
|
} |
|
protected function printGroupFooter(?String $label, ?String $name, String $unique_identifier = "", bool $repeatable, int $iteration, int $total_iterations, string $add_button, string $delete_button, string $collapse_button) : void { |
|
|
|
if($repeatable) { |
|
$close_repeatable_container = $repeatable && ($iteration >= ($total_iterations-1)); |
|
?> |
|
</div> <!-- group-header --> |
|
<?php if ($close_repeatable_container) : ?> |
|
</div> <!-- repeatable --> |
|
</div> <!-- collapse --> |
|
</div> <!-- card-body --> |
|
</div> <!-- card --> |
|
</div> <!-- col --> |
|
<?php endif; ?> |
|
<? |
|
} else { |
|
?> |
|
</div> <!-- collapse --> |
|
</div> <!-- card body --> |
|
</div> <!-- card --> |
|
</div> <!-- group-header --> |
|
<? |
|
} |
|
} |
|
protected function printFieldHeader($field) |
|
{ |
|
$unique_identifier = "wrapper_{$field['name']}"; |
|
$forbidden = $field["forbidden"] ?? false; |
|
$hidden = str_contains($field["type"] ?? "", "hidden"); |
|
?> |
|
<div id="<?= $unique_identifier ?>" class="field-wrapper col-12 col-xl-6 <?= $forbidden || $hidden ? "d-none" : "" ?>" > |
|
<? |
|
} |
|
protected function printFieldFooter() |
|
{ |
|
?> |
|
</div> |
|
<? |
|
} |
|
protected function printSectionFooter() |
|
{ |
|
?> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
<? |
|
} |
|
protected function printIntegrationSectionFooter() |
|
{ |
|
?> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
<? |
|
} |
|
/** |
|
* Make add2GUUE object for ajax request or div |
|
* |
|
* @param Array $settings |
|
* @return String |
|
*/ |
|
public static function makeAdd2GUUEObject(Array $settings) : String |
|
{ |
|
return base64_encode(gzdeflate(json_encode($settings))); |
|
} |
|
/** |
|
* Creates the remove repetition button |
|
* |
|
* @param string $unique_identifier |
|
* @return void |
|
*/ |
|
protected function createDeleteButton(string $unique_identifier) : string { |
|
return $this->button( |
|
[ |
|
"name" => "button", |
|
"required" => false, |
|
"size" => "pr-2", |
|
"type" => "button", |
|
"title" => "<span class=\"fa fa-sm fa-times\"></span>", |
|
"attrs" => [ |
|
"class" => "btn btn-xs btn-danger shadow-none ml-3 align-middle guue-delete-button", |
|
"style" => "float: right; margin-top: 0.2em;", |
|
"onClick" => "eForms2.deleteRepeatable('{$unique_identifier}'); return false;" |
|
] |
|
]); |
|
} |
|
|
|
|
|
protected function createAddButton($unique_identifier, $section, $notice, $codice, $prefix) { |
|
$object = $this->makeAdd2GUUEObject( |
|
[ |
|
"section" => $section, |
|
"notice" => $notice, |
|
"codice" => $codice, |
|
"prefix" => $prefix |
|
]); |
|
|
|
$button = [ |
|
"name" => "button", |
|
"required" => false, |
|
"size" => "pr-2", |
|
"type" => "button", |
|
"title" => "<span class=\"fa fa-plus\"></span> <span class='ml-1'> " . __guue("Aggiungi") . "</span>", |
|
"attrs" => [ |
|
"onClick" => "eForms2.add2GUUE('#{$unique_identifier}', '{$object}');", |
|
"class" => "btn btn-sm btn-block btn-primary guue-add-button" |
|
] |
|
]; |
|
return $this->button($button); |
|
} |
|
|
|
protected function printShowLabelsButton(bool $hide_labels) { |
|
?> |
|
<div class="col-4 custom-control custom-switch custom-switch-lg py-2 ml-3"> |
|
<input <?= !$hide_labels ? "checked" : "" ?> type="checkbox" class="custom-control-input" id="label_toggle" > |
|
<label style="transform-origin: center left; transform: scale(1.25);" class="custom-control-label" for="label_toggle"><?= __guue("Mostra nomi interni") ?></label> |
|
</div> |
|
<script> |
|
const label_toggle = document.getElementById("label_toggle"); |
|
if(label_toggle) { |
|
label_toggle.addEventListener("change", () =>{ |
|
var searchParams = new URLSearchParams(window.location.search); |
|
searchParams.set("hide_labels", <?= $hide_labels ? "0" : "1" ?>); |
|
window.location.search = searchParams.toString(); |
|
}); |
|
} |
|
</script> |
|
<? |
|
} |
|
/** |
|
* Prints the button that enables/disables EFX interpretation |
|
* |
|
* @param boolean $efx Current status |
|
* @return void |
|
*/ |
|
protected function printNoEFXButton(bool $efx) { |
|
?> |
|
<div class="col-4 custom-control custom-switch custom-switch-lg py-2 ml-3"> |
|
<input <?= $efx ? "checked" : "" ?> type="checkbox" class="custom-control-input" id="efx_toggle" > |
|
<label style="transform-origin: center left; transform: scale(1.25);" class="custom-control-label" for="efx_toggle"><?= __guue("Mostra solo rilevanti") ?></label> |
|
</div> |
|
<script> |
|
const efx_toggle = document.getElementById("efx_toggle"); |
|
if(efx_toggle) { |
|
efx_toggle.addEventListener("change", () =>{ |
|
var searchParams = new URLSearchParams(window.location.search); |
|
searchParams.set("efx_mode", <?= $efx ? "0" : "1" ?>); |
|
window.location.search = searchParams.toString(); |
|
}); |
|
} |
|
</script> |
|
<? |
|
} |
|
/** |
|
* Prints the button that enables/disables EFX debug |
|
* |
|
* @param boolean $efx Current status |
|
* @return void |
|
*/ |
|
protected function printDebugEfxButton(bool $advanced_debug) { |
|
?> |
|
<div class="col-4 custom-control custom-switch custom-switch-lg py-2 ml-3"> |
|
<input <?= $advanced_debug ? "checked" : "" ?> type="checkbox" class="custom-control-input" id="advanced_debug_toggle" > |
|
<label style="transform-origin: center left; transform: scale(1.25);" class="custom-control-label" for="advanced_debug_toggle"><?= __guue("Modalità debug") ?></label> |
|
</div> |
|
<script> |
|
const advanced_debug_toggle = document.getElementById("advanced_debug_toggle"); |
|
if(advanced_debug_toggle) { |
|
advanced_debug_toggle.addEventListener("change", () =>{ |
|
var searchParams = new URLSearchParams(window.location.search); |
|
searchParams.set("advanced_debug", <?= $advanced_debug ? "0" : "1" ?>); |
|
window.location.search = searchParams.toString(); |
|
}); |
|
} |
|
</script> |
|
<? |
|
} |
|
/** |
|
* Prints the button that enables/disables EFX debug |
|
* |
|
* @param boolean $efx Current status |
|
* @return void |
|
*/ |
|
protected function printForcedSuggestionsButton(bool $forced_suggestion) { |
|
?> |
|
<div class="custom-control custom-switch custom-switch-lg py-2 ml-3"> |
|
<input <?= $forced_suggestion ? "checked" : "" ?> type="checkbox" class="custom-control-input" id="forced_suggestion_toggle" > |
|
<label style="transform-origin: center left; transform: scale(1.25);" class="custom-control-label" for="forced_suggestion_toggle"><?= __guue("Suggerimenti forzati") ?></label> |
|
</div> |
|
<script> |
|
const forced_suggestion_toggle = document.getElementById("forced_suggestion_toggle"); |
|
if(forced_suggestion_toggle) { |
|
forced_suggestion_toggle.addEventListener("change", () =>{ |
|
var searchParams = new URLSearchParams(window.location.search); |
|
searchParams.set("forced_suggestion", <?= $forced_suggestion ? "0" : "1" ?>); |
|
window.location.search = searchParams.toString(); |
|
}); |
|
} |
|
</script> |
|
<? |
|
} |
|
protected function printDebugArea($full_structure) { |
|
?> |
|
<div class='my-2' > |
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#physical_model_collapse"> |
|
Modello fisico |
|
</button> |
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#data_source_collapse"> |
|
Sorgente dati |
|
</button> |
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#conceptual_model_collapse"> |
|
Modello concettuale |
|
</button> |
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#settings_collapse"> |
|
Impostazioni |
|
</button> |
|
<?php if(!empty($this->suggestions)): ?> |
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#suggestions_collapse"> |
|
Integrazioni |
|
</button> |
|
<?php endif; ?> |
|
<div class="collapse my-2" id="physical_model_collapse"> |
|
<a class="btn btn-primary d-block" href='#' onclick="downloadElementContents(document.getElementById('debug_physical_model'), 'bozza_modello_fisico.xml')"> |
|
Download XML (bozza) |
|
</a> |
|
<pre id='debug_physical_model' style='width:100%; max-height: 300px; overflow-y: scroll'><?= print_r(htmlspecialchars($this->xml->saveXML()), true) ?></pre> |
|
</div> |
|
<div class="collapse my-2" id="conceptual_model_collapse"> |
|
<?php dump($full_structure); ?> |
|
</div> |
|
<div class="collapse my-2" id="data_source_collapse"> |
|
<?php |
|
$data_source = $this->info["valori"]["eforms2"] ?? null; |
|
if($data_source) { |
|
dump($data_source); |
|
} |
|
?> |
|
</div> |
|
<div class="collapse my-2" id="settings_collapse"> |
|
<?php |
|
if($this->info["valori"]["settings"] ?? false ) { |
|
dump($this->info["valori"]["settings"]); |
|
} |
|
if($_SESSION["notice" . $this->notice] ?? false ) { |
|
dump($_SESSION["notice" . $this->notice]); |
|
} |
|
|
|
dump($this->completed_subsections); |
|
?> |
|
</div> |
|
<?php if(!empty($this->suggestions)): ?> |
|
<div class="collapse my-2" id="suggestions_collapse"> |
|
<?php dump($this->suggestions) ?> |
|
<?php dump($this->integrationHelperData) ?> |
|
</div> |
|
<?php endif; ?> |
|
</div> |
|
<? |
|
} |
|
|
|
// TODO Move in personal.js when everything is stable |
|
protected function insertJavascript() { |
|
?> |
|
<script type="text/javascript"> |
|
|
|
//download debug contents |
|
function downloadElementContents(element) { |
|
xmlContent = element.textContent; |
|
const blob = new Blob([xmlContent], {type: 'text/xml'}) |
|
const filename = 'debug.xml' |
|
if (window.navigator.msSaveOrOpenBlob) { |
|
window.navigator.msSaveBlob(blob,filename); |
|
} else { |
|
const elem = window.document.createElement('a'); |
|
elem.href = window.URL.createObjectURL(blob); |
|
elem.download = filename; |
|
document.body.appendChild(elem); |
|
elem.click(); |
|
document.body.removeChild(elem); |
|
} |
|
} |
|
|
|
// eForms 2 EFX Autosave Code |
|
if (typeof window.eForms2 === "undefined"){ |
|
window.eForms2 = { |
|
codice : 0, |
|
prevent_update : 0, |
|
update_uri : "", |
|
setup : function() { |
|
if(eForms2.update_uri) { |
|
$("#guue-form #master-fieldset :input").change(eForms2.onFormChange); |
|
} |
|
// Nascondi gruppi vuoti |
|
eForms2.collapseEmpty(); |
|
eForms2.expandFull(); |
|
eForms2.groupRepeatables(); |
|
// Creiamo la navigazione interna |
|
eForms2.makeNavigator(); |
|
|
|
|
|
|
|
|
|
// Inizializzazione completa |
|
var masterFieldset = document.getElementById("master-fieldset"); |
|
if(!masterFieldset.dataset.ready) { |
|
//masterFieldset.style.pointerEvents = "none"; |
|
} |
|
masterFieldset.disabled = false; |
|
}, |
|
toggleFixed : function(id, firstRun) { |
|
const stickyContainer = document.getElementById("guue-sticky-container"); |
|
if(!stickyContainer) return; |
|
const target = document.getElementById(id); |
|
let cloneTarget = document.getElementById("sticky__" + id); |
|
|
|
if(target) { |
|
let sticky = false; |
|
if(cloneTarget) { |
|
cloneTarget.remove(); |
|
target.style.pointerEvents = null; |
|
target.style.userSelect = null; |
|
target.style.opacity = 1; |
|
|
|
} else { |
|
cloneTarget = target.cloneNode(true); |
|
cloneTarget.id = "sticky__" + id; |
|
stickyContainer.appendChild(cloneTarget); |
|
target.style.pointerEvents = "none"; |
|
target.style.userSelect = "none"; |
|
target.style.opacity = "0.2"; |
|
|
|
sticky = true; |
|
} |
|
|
|
if(!firstRun) { |
|
let savedSticky = JSON.parse(localStorage.getItem("eforms2-sticky-suggestions")) || {}; |
|
savedSticky[target.id] = sticky; |
|
localStorage.setItem("eforms2-sticky-suggestions", JSON.stringify(savedSticky)); |
|
} |
|
} |
|
}, |
|
deleteRepeatable : function(id) { |
|
Swal({ |
|
title: js_dict["sei-sicuro"], |
|
text: js_dict["msg-conferma"], |
|
type: "error", |
|
showCancelButton: true, |
|
confirmButtonColor: '#3085d6', |
|
cancelButtonColor: '#d33', |
|
confirmButtonText: js_dict.conferma, |
|
cancelButtonText: js_dict.annulla, |
|
closeOnConfirm: true |
|
}).then((result) => { |
|
if (result.value) { |
|
document.getElementById(id).remove(); |
|
eForms2.onFormChange(null, function() {window.location.reload()}); |
|
} |
|
}); |
|
|
|
|
|
}, |
|
addIntegrationPinButtons : function() { |
|
const stickyContainer = document.createElement("div"); |
|
stickyContainer.id = "guue-sticky-container"; |
|
stickyContainer.style.position = "fixed"; |
|
stickyContainer.style.bottom = "2em"; |
|
stickyContainer.style.right = "1em"; |
|
stickyContainer.style.width = "80%"; |
|
stickyContainer.style.zIndex = 999; |
|
stickyContainer.style.maxWidth = "1024px"; |
|
|
|
|
|
|
|
document.body.appendChild(stickyContainer); |
|
|
|
document.querySelectorAll(".integration-section-header").forEach(function(integrationSection) { |
|
// Cerchiamo il collapse button come riferimento |
|
const collapseButton = integrationSection.querySelector(".guue-collapse-button"); |
|
if(collapseButton) { |
|
const pinButtonContainer = document.createElement("div"); |
|
pinButtonContainer.classList.add("pr-2"); |
|
const pinButton = document.createElement("button"); |
|
pinButton.classList.add("btn", "btn-sm", "btn-secondary"); |
|
// Cambiamo icona |
|
const newIcon = document.createElement("span"); |
|
newIcon.classList.add("fa", "fa-sm", "fa-thumbtack"); |
|
pinButton.appendChild(newIcon); |
|
pinButtonContainer.appendChild(pinButton); |
|
|
|
// Settiamo l'evento |
|
pinButton.onclick = null; |
|
pinButton.setAttribute("onclick", `event.preventDefault(); eForms2.toggleFixed(\"${integrationSection.id}\", false);`); |
|
// Aggiungiamo l'elemento |
|
collapseButton.parentElement.parentElement.insertBefore(pinButtonContainer, collapseButton.parentElement); |
|
|
|
} |
|
}) |
|
let savedSticky = JSON.parse(localStorage.getItem("eforms2-sticky-suggestions") ) || {}; |
|
for(let [id, value] of Object.entries(savedSticky)) { |
|
if(value) { |
|
eForms2.toggleFixed(id, true); |
|
} |
|
} |
|
|
|
|
|
}, |
|
addOrganization : function(ragione, codice, pec) { |
|
visible = function( elem ) { |
|
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); |
|
}; |
|
let found = false; |
|
if(ragione) { |
|
// Ragione sociale |
|
found = false; |
|
document.querySelectorAll('input[name*="BT-500-Organization-Company"]:not([readonly])').forEach(function(el) { |
|
if(found) return; |
|
if(visible(el)) { |
|
if(el.value) return; |
|
found = true; |
|
el.value = ragione; |
|
} |
|
}); |
|
if(!found) { |
|
Swal({ |
|
title : "Attenzione", |
|
html : "Per inserire un'orgranizzazione si prega di aggiungerne una nuova con il tasto \"Aggiungi\" e selezionarla.", |
|
confirmButtonText : "Ok", |
|
}) |
|
return; |
|
} |
|
|
|
} |
|
if(codice) { |
|
// Ragione sociale |
|
let found = false; |
|
document.querySelectorAll('input[name*="BT-501-Organization-Company"]:not([readonly])').forEach(function(el) { |
|
if(found) return; |
|
if(visible(el)) { |
|
found = true; |
|
el.value = codice; |
|
} |
|
}); |
|
} |
|
if(pec) { |
|
// Ragione sociale |
|
let found = false; |
|
document.querySelectorAll('input[name*="BT-506-Organization-Company"]:not([readonly])').forEach(function(el) { |
|
if(found) return; |
|
if(visible(el)) { |
|
found = true; |
|
el.value = pec; |
|
} |
|
}); |
|
} |
|
eForms2.onFormChange(null); |
|
}, |
|
makeInternalLabels : function() { |
|
document.querySelectorAll("[data-internalname]").forEach(function(e) { |
|
let node = e; |
|
let label = null; |
|
while(!label) { |
|
node = node.parentNode; |
|
label = node.querySelector("label"); |
|
} |
|
if(label && !label.dataset.hasInternalLabel) { |
|
const small = document.createElement("small"); |
|
const code = document.createElement("code"); |
|
label.classList.add("mr-2"); |
|
small.innerHTML = " "; |
|
small.appendChild(code); |
|
|
|
code.classList.add("text-secondary"); |
|
code.classList.add("text-nowrap"); |
|
small.classList.add("mb-2"); |
|
small.classList.add("d-inline-block"); |
|
|
|
|
|
code.innerText = `${e.dataset.internalname}`; |
|
label.dataset.hasInternalLabel = true; |
|
label.after(small); |
|
} |
|
}) |
|
}, |
|
onFormChange : function(e, callback) { |
|
if (e && (e.target.value, e.target.getAttribute("name") == null)) { |
|
return; |
|
} |
|
if(e) { |
|
// Verifichiamo la validazione del campo attuale |
|
let validation = valida($(e.target)); |
|
// Se non è valido non lanciamo il refresh inutilmente |
|
if(Array.isArray(validation) && validation.length > 0) { |
|
console.error(valida($(e.target))); |
|
if(e.target.value) { |
|
return; |
|
} |
|
} |
|
} |
|
// Preveniamo update accavallati |
|
if(eForms2.prevent_update > Date.now()) { console.error("Preventing update"); return; } |
|
eForms2.prevent_update = Date.now() + 10000; |
|
|
|
// Selezioniamo il form per farne il submit |
|
const form = document.getElementById("guue-form"); |
|
const formData = new FormData(form); |
|
formData.set("action", "autosave"); |
|
formData.set("draft", "S"); |
|
// Mostriamo l'attesa e disattiviamo tutto temporaneamente |
|
$("#wait_div").show(); |
|
$("#guue-form #master-fieldset").prop("disabled", true); |
|
|
|
// Facciamo una richiesta post all'autosave |
|
fetch( |
|
eForms2.update_uri, |
|
{ |
|
method: 'post', |
|
body: formData |
|
} |
|
) |
|
// TODO Check if response is JSON |
|
.then(response => response.json() ) |
|
.then(response => { |
|
// Se la risposta chiede un redirect, obbediamo |
|
if(response.redirect) { |
|
window.location.href = response.redirect; |
|
form.style.display = 'hidden'; |
|
return; |
|
} |
|
if(response.errors) { |
|
// Todo, magari mostrare errors solo in debug |
|
Swal({ |
|
title : "Qualcosa è andato storto", |
|
html : response.errors, |
|
confirmButtonText : "Ok", |
|
}) |
|
} |
|
// Traverse response recursively |
|
eForms2.parseResponse(response); |
|
|
|
// Settiamo la sezione attuale come draft visivamente |
|
const activeButton = document.querySelector("#guue-sections > .list-group > .active"); |
|
if(activeButton.classList.contains("list-group-item-success")) { |
|
activeButton.classList.remove("list-group-item-success"); |
|
activeButton.classList.add("list-group-item-warning"); |
|
|
|
const iconContainer = activeButton.querySelector("span"); |
|
const icon = iconContainer.querySelector("svg"); |
|
if(icon) { |
|
icon.remove(); |
|
} |
|
let newIcon = document.createElement("i"); |
|
newIcon.classList.add("fas"); |
|
newIcon.classList.add("fa-times-circle"); |
|
newIcon.classList.add("mr-2"); |
|
iconContainer.prepend(newIcon); |
|
} |
|
|
|
}) |
|
.catch(ex => { |
|
swal(js_dict["error-retry"]); |
|
console.error(ex); |
|
}) |
|
.finally(() => { |
|
if(typeof callback === "function") { |
|
callback(); |
|
} |
|
eForms2.collapseEmpty(); |
|
eForms2.makeNavigator(); |
|
$("#guue-form #master-fieldset").prop("disabled", false); |
|
$("#wait_div").slideUp('fast'); |
|
// Selezioniamo il prossimo elemento per l'utente |
|
/*if(e) { |
|
eForms2.focusNextElement(e.target); |
|
}*/ |
|
eForms2.updateTabNames(); |
|
eForms2.prevent_update = 0; |
|
}); |
|
|
|
}, |
|
focusNextElement : function(activeElement) { |
|
//add all elements we want to include in our selection |
|
var focussableElements = |
|
'input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])'; |
|
if (activeElement && activeElement.form) { |
|
var focussable = Array.prototype.filter.call( |
|
activeElement.form.querySelectorAll(focussableElements), |
|
function (element) { |
|
//check for visibility while always include the current activeElement |
|
return ( |
|
element.offsetWidth > 0 || |
|
element.offsetHeight > 0 || |
|
element === activeElement |
|
); |
|
} |
|
); |
|
var index = focussable.indexOf(activeElement); |
|
if (index > -1) { |
|
var nextElement = focussable[index + 1] || focussable[0]; |
|
nextElement.focus(); |
|
} |
|
} |
|
}, |
|
generateRandomID : function() { |
|
var S4 = function() { |
|
return (((1+Math.random())*0x10000)|0).toString(16).substring(1); |
|
}; |
|
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); |
|
}, |
|
updateTabNames : function() { |
|
// Cerchiamo il nome della tab |
|
document.querySelectorAll(".nav-link[data-bindtarget]").forEach(function(tabButton) { |
|
const child = document.querySelector(`[data-bind="${tabButton.dataset.bindtarget}"]`); |
|
const tabText = tabButton.querySelector(".nav-link-text"); |
|
if(!child || !tabText) return; |
|
if(child.dataset.tabname[0] == "#") { |
|
const candidates = child.dataset.tabname.split("|"); |
|
for(i in candidates) { |
|
const candidate = candidates[i]; |
|
const toFind = candidate.split("#")[1]; |
|
|
|
const provider = child.querySelector(`input[name*="${toFind}"]`); |
|
if(provider) { |
|
tabText.innerText = provider.value.length > 0 ? provider.value : "Nuova scheda"; |
|
break; |
|
} else { |
|
tabText.innerText = candidate; |
|
} |
|
} |
|
} else { |
|
tabText.innerText = child.dataset.tabname; |
|
} |
|
}); |
|
}, |
|
groupRepeatables : function() { |
|
document.querySelectorAll(".repeatable_container").forEach(function(el) { |
|
|
|
let i = 0; |
|
let tabs = null; |
|
let tabHeaders = null; |
|
let hasTabs = el.dataset.hasTabs; |
|
let selectedBind = ""; |
|
|
|
let toSelect = null; |
|
// Aggiunta o rimozione |
|
if(hasTabs) { |
|
// Otteniamo la tab correntemente selezionata |
|
selectedBind = el.querySelector(".nav-link.active").dataset.bindtarget; |
|
|
|
// Otteniamo, puliamo e rimuoviamo i vecchi header |
|
tabHeaders = el.removeChild(document.getElementById(el.dataset.tabHeadersId)); |
|
tabHeaders.innerHTML = ""; |
|
// Otteniamo e rimuoviamo le vechie tab |
|
tabs = el.removeChild(document.getElementById(el.dataset.tabsId)); |
|
|
|
// I vecchi elementi in tab vengono trasposti dentro il repeatable nell'ordine corretto |
|
tempContainer = []; |
|
index = 0; |
|
tabs.childNodes.forEach(function(oldChild) { |
|
if(oldChild.nodeType !== Node.ELEMENT_NODE) |
|
return; |
|
tempContainer.push(oldChild); |
|
}); |
|
|
|
// Iteriamo i figli nuovi e verifichiamo che ce ne |
|
// sia solo uno nuovo. |
|
el.childNodes.forEach(function(newChild) { |
|
if(newChild.id) { |
|
if(toSelect === null) { |
|
if(newChild.id) { |
|
toSelect = newChild; |
|
} |
|
} else { |
|
// Ne abbiamo più di uno, non selezioneremo nulla |
|
toSelect = false; |
|
} |
|
} |
|
}); |
|
tempContainer.forEach(function(oldChild){ |
|
el.insertBefore(oldChild, el.children[index++]); |
|
}); |
|
// In questo modo abbiamo vecchi figli e poi i nuovi figli e possiamo far ricreare header e tutto |
|
} else { |
|
// Creiamo l'header |
|
tabHeaders = document.createElement("ul"); |
|
tabHeaders.classList.add("nav"); |
|
tabHeaders.classList.add("nav-tabs"); |
|
tabHeaders.classList.add("px-4"); |
|
tabHeaders.setAttribute("role", "tablist"); |
|
tabHeaders.id = eForms2.generateRandomID(); |
|
// Creiamo il contenitore di tabs |
|
tabs = document.createElement("div"); |
|
tabs.classList.add("tab-content"); |
|
tabs.id = eForms2.generateRandomID(); |
|
|
|
// Assegnamo id casuali per poterli riferire dopo |
|
el.dataset.hasTabs = true; |
|
el.dataset.tabHeadersId = tabHeaders.id; |
|
el.dataset.tabsId = tabs.id; |
|
|
|
i = 0; |
|
} |
|
let straightToTabs = []; |
|
el.childNodes.forEach(function(child) { |
|
if(child.nodeType !== Node.ELEMENT_NODE) { |
|
return; |
|
} |
|
// Header della tab |
|
let tabLi = document.createElement("li"); |
|
tabLi.classList.add("nav-item"); |
|
tabLi.setAttribute("role", "presentation"); |
|
let tabButton = document.createElement("button"); |
|
tabButton.classList.add("nav-link"); |
|
|
|
tabButton.dataset.toggle="tab"; |
|
tabButton.dataset.target=`#${child.id}`; |
|
tabButton.style.minWidth = "90px"; |
|
tabButton.style.textAlign = "left"; |
|
tabLi.appendChild(tabButton); |
|
tabHeaders.appendChild(tabLi); |
|
|
|
|
|
// Creo un ID univoco per associare facilmente tab button e tab |
|
if(child.dataset.bind) { // Riportiamo quello esistente se già c'è |
|
// Nessuna azione necessaria |
|
} else { |
|
child.dataset.bind = eForms2.generateRandomID(); |
|
} |
|
tabButton.dataset.bindtarget = child.dataset.bind; |
|
|
|
|
|
tabText = document.createElement("span"); |
|
tabText.classList.add("nav-link-text"); |
|
tabButton.appendChild(tabText); |
|
tabText.innerText = i+1; |
|
// Tab in se |
|
child.classList.add("tab-pane"); |
|
child.classList.add("fade"); |
|
child.classList.add("row"); |
|
straightToTabs.push(child); |
|
|
|
// Cerchiamo di recuperare il tasto di eliminazione |
|
if( i > 0) { |
|
|
|
let deleteButton = child.querySelector(".guue-delete-button"); |
|
if(deleteButton) { |
|
deleteButton.style.display = "inline"; |
|
tabButton.appendChild(deleteButton.cloneNode(true)); |
|
deleteButton.style.display = "none"; |
|
} |
|
} |
|
i++; |
|
}); |
|
|
|
|
|
|
|
|
|
|
|
tabHeaders.style.display = "flex"; |
|
tabHeaders.classList.add("mb-3"); |
|
|
|
straightToTabs.forEach(function(child) { |
|
tabs.appendChild(child); |
|
}); |
|
el.dataset.iterations = i; |
|
el.appendChild(tabHeaders); |
|
el.appendChild(tabs); |
|
|
|
// Se abbiamo un solo elemento non mostriamo le tab |
|
if(i == 1) { |
|
tabHeaders.style.display = "none"; |
|
} |
|
// Una volta creati andiamo a caccia dell'attivo |
|
let toBeActive = el.querySelector(`.nav-link[data-bindtarget]`) |
|
// Cerchiamo di ripristinare quello che era già selezionato ove possibile |
|
if(selectedBind.length > 0) { |
|
let selectedActive = el.querySelector(`.nav-link[data-bindtarget="${selectedBind}"]`); |
|
if(selectedActive) { |
|
toBeActive = selectedActive; |
|
} |
|
} |
|
// Settiamo attive sia tab button che child |
|
if(toBeActive) { |
|
// Però se abbiamo invece da selezionare uno nuovo |
|
// perchè è quello appena selezionato |
|
if(toSelect) { |
|
// toBeActive viene deselezionato |
|
toBeActive.classList.remove("active"); |
|
// Cerchiamo la sua tab |
|
const child = document.querySelector(`[data-bind="${toBeActive.dataset.bindtarget}"]`); |
|
if(child) { |
|
child.classList.remove("show") |
|
child.classList.remove("active"); |
|
} |
|
// e quindi toSelect diventa l'effettivo toBeActive |
|
toBeActive = document.querySelector(`[data-bindtarget="${toSelect.dataset.bind}"]`); |
|
} |
|
toBeActive.classList.add("active"); |
|
// Cerchiamo la sua tab |
|
const child = document.querySelector(`[data-bind="${toBeActive.dataset.bindtarget}"]`); |
|
if(child) { |
|
child.classList.add("show") |
|
child.classList.add("active"); |
|
} |
|
|
|
} |
|
|
|
}); |
|
eForms2.updateTabNames(); |
|
}, |
|
collapseEmpty : function() { |
|
document.querySelectorAll(".group-header, .repeatable-card, .section-header").forEach(function(el) { |
|
const visible = el.querySelectorAll(".field-wrapper:not(.d-none)"); |
|
if(visible.length == 0) { |
|
el.classList.add("d-none"); |
|
} else { |
|
el.classList.remove("d-none"); |
|
} |
|
}) |
|
}, |
|
expandFull: function() { |
|
$(".collapse").not(".show").each(function(){ |
|
let empty = true; |
|
$(this).find("input").each(function(){ |
|
if ($(this).val() !== "" && $(this).val() !== undefined) { |
|
empty = false; |
|
} |
|
}) |
|
$(this).find("select").each(function(){ |
|
if ($(this).val() !== "" && $(this).val() !== undefined) { |
|
empty = false |
|
} |
|
}) |
|
if (!empty) { |
|
const id = $(this).attr("id"); |
|
$(`[data-target="#${id}"]`).click() |
|
} |
|
}) |
|
}, |
|
parseResponse : function(arr) { |
|
var k; |
|
if (arr instanceof Object) { |
|
for (k in arr){ |
|
if(k.startsWith("eforms2")) { |
|
const data = arr[k]; |
|
// Find the wrapper |
|
const wrapper = document.getElementById(`wrapper_${k}`); |
|
|
|
|
|
if(wrapper) { |
|
// Update children |
|
wrapper.querySelectorAll("input, select, label:not(.form-check-label), .valida").forEach(function(el) { |
|
eForms2.updateElement(el, data, k); |
|
}); |
|
// Show / hide |
|
if(data["forbidden"]) { |
|
wrapper.classList.add("d-none"); |
|
} else { |
|
wrapper.classList.remove("d-none"); |
|
} |
|
} |
|
} else if (arr.hasOwnProperty(k)){ |
|
//recursive call to scan property |
|
eForms2.parseResponse( arr[k] ); |
|
} |
|
} |
|
} |
|
}, |
|
// add2GUUE |
|
add2GUUE : function (target, data) { |
|
repeatable_target = "repeatable_" + target.substr(1); |
|
let container = document.getElementById(repeatable_target); |
|
let iterations = container.childElementCount; |
|
if(container.dataset.hasTabs) { |
|
iterations = container.dataset.iterations; |
|
} |
|
$.ajax({ |
|
type: "POST", |
|
url: `/backend/guue/add2GUUE.php?codice=${eForms2.codice}&iterations=${iterations}`, |
|
data: {data: data}, |
|
dataType: "html", |
|
beforeSend: function() { |
|
$("#wait_div").show(); |
|
} |
|
}) |
|
.fail(function(response) { |
|
swal(js_dict["error-retry"]); |
|
}) |
|
.done(function(response) { |
|
$("#" + repeatable_target).append(response); |
|
|
|
// Make new elements respond |
|
eForms2.setup(); |
|
eForms2.makeInternalLabels(); |
|
f_ready(); |
|
}) |
|
.always(function() { |
|
$("#wait_div").slideUp('fast'); |
|
}); |
|
}, |
|
// Update element after autosave |
|
updateElement : function(el, data, key) { |
|
nodeName = el.nodeName.toLowerCase(); |
|
// If forbidden |
|
if(data["forbidden"]) { |
|
// We disable the element |
|
el.setAttribute("disabled", ''); |
|
// We remove the rel attribute |
|
if(el.hasAttribute("rel")) { |
|
el.setAttribute("_rel", el.getAttribute("rel")); |
|
} |
|
// We clear its value |
|
|
|
// If not forbidden |
|
} else { |
|
// Aggiorniamo le options |
|
if(data["options"] && nodeName == "select") { |
|
// Marchiamo quelle da rimuovere (tutte tranne quelle vuote) |
|
el.querySelectorAll("option").forEach(function(current_option) { |
|
if(current_option.value) { |
|
current_option.dataset.todelete = true; |
|
} |
|
}); |
|
// Iteriamo le opzioni attuali |
|
for (const [value, name] of Object.entries(data["options"])) { |
|
// Cerchiamo se c'è una corrispondente |
|
current_option = el.querySelector(`option[value='${value}']`); |
|
// Se c'è, la aggiorniamo e la non marchiamo come da cancellare |
|
if(current_option) { |
|
current_option.innerText = name; |
|
delete current_option.dataset.todelete; |
|
} |
|
// Se non c'è la creiamo |
|
else { |
|
new_option = document.createElement("option"); |
|
new_option.value = value; |
|
new_option.innerText = name; |
|
el.appendChild(new_option); |
|
} |
|
} |
|
// Cancelliamo quelle non più presenti |
|
el.querySelectorAll("option[data-todelete=true]").forEach(function(to_delete) { |
|
el.removeChild(to_delete); |
|
}); |
|
} |
|
// Inseriamo le assertion |
|
if(data["assert_fail"] && (nodeName == "input" || nodeName == "select")) { |
|
|
|
input = $(el); |
|
input.addClass('is-invalid'); |
|
input.parents(".form-group").first().addClass("text-danger"); |
|
|
|
noteid = "note_" + key; |
|
const note = document.getElementById(noteid); |
|
if(note) |
|
note.innerHTML = data["assert_fail"]; |
|
else |
|
input.parents(".form-group").first().append("<div class=\"invalid-feedback\" id=\"" + noteid + "\">" + data["assert_fail"] + "</div>"); |
|
|
|
} |
|
if(el.hasAttribute("_rel")) { |
|
el.setAttribute("rel", "_rel"); |
|
el.removeAttribute("_rel"); |
|
} |
|
el.removeAttribute("disabled"); |
|
// Update data attributes |
|
for(let key in data.attrs) { |
|
if(key.toLowerCase() != "class") |
|
el.setAttribute(key, data.attrs[key]); |
|
} |
|
// Push data on readonly fields (autopopulate LOT/ORG/GLO ecc) |
|
if(el.getAttribute("readonly") && !el.dataset.dummy) { |
|
let val = data.val |
|
if(typeof val === 'object') { |
|
if(el.name && el.name.includes("[type]")) { |
|
val = val.type; |
|
} else { |
|
val = val.value; |
|
} |
|
} |
|
el.value = val; |
|
} |
|
// Update important rel parts |
|
if(el.getAttribute("rel") && data.rel) { |
|
let current_rel = el.getAttribute("rel").split(";"); |
|
current_rel[2] = data.rel[2]; |
|
current_rel[0] = data.rel[0]; |
|
el.setAttribute("rel", current_rel.join(";")); |
|
if(data.rel[0] == "S") { |
|
el.setAttribute("required", "1"); |
|
} else { |
|
el.removeAttribute("required"); |
|
} |
|
} |
|
// Update label |
|
if(el.nodeName.toLowerCase() == "label" && data.rel) { |
|
const asterisk = el.querySelector(".text-asterisk"); |
|
if(data.rel[0] == "S") { |
|
if(!asterisk) { |
|
el.innerHTML += " <?= TedEsender::MANDATORY_ASTERISK ?>"; |
|
} |
|
} else { |
|
if(asterisk) { |
|
asterisk.remove(); |
|
} |
|
} |
|
} |
|
|
|
} |
|
$(el).trigger("chosen:updated"); |
|
}, |
|
|
|
//scrollToSection |
|
scrollToSection : function(id) { |
|
|
|
document.querySelector(`#${id}`).scrollIntoView({block: 'start', behavior: 'smooth'}) |
|
}, |
|
guueFixedObserver : null, |
|
guueNaviObserver : null, |
|
navigationObservers : [], |
|
//makeNavigator |
|
makeNavigator: function() { |
|
// Inizializziamo il toggle per mostrare o meno la barra di navigazione piccola |
|
if(eForms2.guueNaviObserver == null) { |
|
const bigNav = document.getElementById("guue-big-nav"); |
|
const smallNav = document.getElementById("guue-small-nav"); |
|
eForms2.guueNaviObserver = new IntersectionObserver(function(entries) { |
|
entries.forEach((entry) => { |
|
if(entry.isIntersecting) { |
|
smallNav.style.height = "0"; |
|
smallNav.style.opacity = "0"; |
|
} else { |
|
smallNav.style.display = "flex"; |
|
smallNav.style.height = "40px"; |
|
smallNav.style.opacity = "1"; |
|
} |
|
}); |
|
}); |
|
eForms2.guueNaviObserver.observe(bigNav); |
|
|
|
} |
|
// Inizializziamo il toggle per mostrare o meno la barra di navigazione piccola |
|
if(eForms2.guueFixedObserver == null) { |
|
const commands = document.getElementById("guue-commands"); |
|
const metadata = document.getElementById("form-metadata"); |
|
eForms2.guueFixedObserver = new IntersectionObserver(function(entries) { |
|
entries.forEach((entry) => { |
|
if(entry.isIntersecting) { |
|
commands.classList.remove("fixed"); |
|
} else { |
|
commands.classList.add("fixed"); |
|
} |
|
}); |
|
}, {'threshold': 0.25 }); |
|
eForms2.guueFixedObserver.observe(metadata); |
|
|
|
} |
|
// Cancelliamo i vecchi |
|
eForms2.navigationObservers.forEach(function(observer) { |
|
observer.disconnect(); |
|
}); |
|
eForms2.navigationObservers = []; |
|
document.querySelectorAll(".guue-internal-navigation").forEach(function(oldLink) { |
|
oldLink.remove(); |
|
}) |
|
|
|
|
|
const firstLevelHeaders = document.querySelectorAll("#master-fieldset > .section-header"); |
|
const activeButton = document.querySelector("#guue-sections > .list-group > .active"); |
|
let links = []; |
|
firstLevelHeaders.forEach(function(element){ |
|
if (!element.classList.contains("d-none")) { |
|
|
|
const headerContent = element.querySelector(".col-12 > .card > .card-header .row > .col > p"); |
|
|
|
let linkContainer = document.createElement("button"); |
|
linkContainer.classList.add("list-group-item"); |
|
linkContainer.classList.add("guue-internal-navigation"); |
|
linkContainer.classList.add("text-left"); |
|
linkContainer.onclick = function(e) { window.eForms2.scrollToSection(element.id); e.preventDefault(); }; |
|
let link = document.createElement("span"); |
|
link.classList.add("ml-4"); |
|
|
|
// Creiamo un observer |
|
let observer = new IntersectionObserver(function(entries) { |
|
entries.forEach((entry) => { |
|
if(entry.isIntersecting) { |
|
linkContainer.classList.add("active"); |
|
} else { |
|
linkContainer.classList.remove("active"); |
|
} |
|
}); |
|
}, {'threshold': element.clientHeight > 1000 ? 0.05 : 0.15 }); |
|
observer.observe(element); |
|
eForms2.navigationObservers.push(observer); |
|
|
|
link.innerText = headerContent.textContent; |
|
|
|
linkContainer.append(link) |
|
|
|
links = [linkContainer].concat(links); |
|
} |
|
}) |
|
links.forEach(function(link) { |
|
activeButton.after(link); |
|
}) |
|
} |
|
} |
|
} |
|
</script> |
|
<? |
|
} |
|
|
|
public function getSectionByFieldID(array $section, string $id = "", array $return_section = [], bool $first_run = true) { |
|
// Iteriamo i contenuti |
|
foreach(($section["content"] ?? []) as $subsection) { |
|
// Se troviamo una macrosezione, popoliamo la variabile |
|
if($first_run && str_starts_with($subsection["id"], "GR-")) { |
|
$return_section = $subsection; |
|
} |
|
|
|
$subsection_id = $subsection["id"] ?? null; |
|
|
|
// Se corrisponde alla ricerca lo ritorniamo |
|
if($subsection_id === $id ) { |
|
// Conserviamo anche un riferimento ai metadata dell'elemento |
|
$return_section["field"] = $subsection; |
|
return $return_section; |
|
} |
|
// Se corrisponde il BTID invece |
|
$is_bt = substr_count($id, "-") === 1; |
|
if($is_bt && str_starts_with($subsection_id, $id)) { |
|
// Conserviamo anche un riferimento ai metadata dell'elemento |
|
$return_section["field"] = $subsection; |
|
return $return_section; |
|
} |
|
// Altrimenti cerchiamo a fondo |
|
$depth_search = $this->getSectionByFieldID($subsection, $id, $return_section, false); |
|
if($depth_search !== null) |
|
return $depth_search; |
|
} |
|
return null; |
|
} |
|
public function processErrorTagForField($field, $error) { |
|
ob_start(); |
|
// Prendiamo la sezione alla quale appartiene |
|
$section = $this->getSectionByFieldID($this->fields, $field); |
|
|
|
if($section !== null) { |
|
$repetition = 0; |
|
// Se la sezione è ripetibile, arriviamo alla ripetizione tramite un workaround |
|
if($section["_repeatable"] ?? false) { |
|
$location = $error["@location"] ?? null; |
|
if($location) { |
|
// Troviamo la prima quadra della ripetizione visto che è sempre una macrosezione |
|
$repetition_candidate = substr($location, strpos($location, "[") + 1 ); |
|
// E prendiamo fino alla chiusura della quadra |
|
$repetition_candidate = substr($repetition_candidate, 0, strpos($repetition_candidate, "]") ); |
|
if(is_numeric($repetition_candidate)) { |
|
$repetition = (int)$repetition_candidate - 1; |
|
} |
|
} |
|
} |
|
|
|
|
|
$current_section = $_GET["section"]; |
|
$current_repetition = $_GET["subsection_index"]; |
|
// Se l'errore è in una sezione diversa dalla nostra |
|
if($current_section !== $section["id"] || $repetition != $current_repetition ) { |
|
?> |
|
<a onclick="switchSection('<?= $section['id'] ?>', <?= $repetition ?>, true)" href="#"> |
|
<span class="badge badge-warning"> |
|
<span class="fa fa-sm fa-link"></span> |
|
<span><?= $this->translate($section['_label'])?> <?= $repetition > 0 ? $repetition + 1 : ""; ?> > <?= $field ?></span> |
|
</span> |
|
</a> |
|
<? |
|
} else { |
|
// Se abbiamo un riferimento completo al campo |
|
$section_field = $section["field"] ?? null; |
|
if($section_field) { |
|
?> |
|
<a onclick="scrollToField('<?= $section_field['id'] ?>')" href="#"> |
|
<span class="badge badge-info" href="#"> |
|
<span class="fa fa-sm fa-search"></span> |
|
<b><?= $field ?></b> |
|
</span> |
|
</a> |
|
<? |
|
} else { |
|
return $field; |
|
} |
|
} |
|
} else { |
|
return $field; |
|
} |
|
return ob_get_clean(); |
|
} |
|
public function processErrorForDisplay($error) { |
|
$error["label"] = $error["label"] ?? __guue("Errore sconosciuto"); |
|
|
|
// Se abbiamo il riferimento ad un field |
|
if($see = ($error["svrl:diagnostic-reference"]["@see"] ?? false)) { |
|
// field:BT-1234-Lot |
|
if(str_starts_with($see, "field:")) { |
|
|
|
// Prendiamo il campo |
|
$see = str_replace("field:" , "", $see); |
|
|
|
$processed_field = $this->processErrorTagForField($see, $error); |
|
if($processed_field != $see) { |
|
echo $processed_field; |
|
} |
|
|
|
} |
|
} |
|
|
|
// Processiamo i riferimenti ai campi nel label |
|
$matches = []; |
|
preg_match_all('/(BT|OPT|OPP)-[\d]+(\((BT|OPT|OPP)-[\d]+\))*-+[a-zA-Z0-9]+/', $error["label"], $matches); |
|
$matches = array_unique($matches[0]) ?? []; |
|
if(preg_match("/\((BT-19[5678])\)/i", $error["label"], $unpublishField) === 1) { |
|
$labelAddition = __("Il campo {$unpublishField[1]} si riferisce alle sezioni 'Pubblicato successivamente'"); |
|
$error["label"] .= "<br>Info : <strong>$labelAddition</strong>"; |
|
} |
|
foreach($matches as $match) { |
|
$replaced = $this->processErrorTagForField($match, $error); |
|
if($replaced != $match) { |
|
$error["label"] = str_replace($match, $replaced, $error["label"]); |
|
} |
|
} |
|
|
|
echo($error["label"]); |
|
if($this->advanced_debug) { |
|
unset($error["label"]); |
|
echo("<pre>"); |
|
print_r($error); |
|
echo("</pre>"); |
|
} |
|
} |
|
|
|
public function renderIntegrationHelpers(string $position) { |
|
$integrationHelperData = $this->integrationHelperData[$this->current_section_id][$this->current_subsection] ?? []; |
|
|
|
// Print integration data |
|
foreach($integrationHelperData as $integration) { |
|
|
|
if($integration["position"] !== $position) continue; |
|
|
|
// Cerchiamo il modulo di integrazione corretto |
|
global $beRoot; |
|
|
|
// Proviamo prima il path specifico |
|
$path = $beRoot."{$integration["modulo"]}/guue/render/{$integration["sottomodulo"]}.php"; |
|
// Path generico |
|
if(!file_exists($path)) { |
|
$path = $beRoot."guue/integration/{$integration["sottomodulo"]}.php"; |
|
} |
|
|
|
if (file_exists($path)) { |
|
$unique_identifier = "integration_{$integration['modulo']}_{$integration['sottomodulo']}"; |
|
$collapse_button = $this->button( |
|
[ |
|
"name" => "button", |
|
"required" => false, |
|
"size" => "pr-2", |
|
"type" => "button", |
|
"title" => "<span class=\"fa fa-sm fa-window-minimize\"></span><span class=\"fa fa-sm fa-plus\"></span>", |
|
"attrs" => [ |
|
"data-toggle" => "collapse", |
|
"data-target" => "#collapse-{$unique_identifier}", |
|
"class" => "btn btn-sm btn-block btn-outline-secondary mr-2 guue-collapse-button", |
|
] |
|
]); |
|
$this->printIntegrationSectionHeader($integration["title"], $unique_identifier, $collapse_button, $position); |
|
|
|
// Wrappo in una funzione perchè PHP è una cacca e non capisce il concetto di scope |
|
// delle variabili |
|
$callIntegration = function ($path) use ($integration) { |
|
// Se l'array è una lista, renderizziamo l'helper per ogni entry |
|
require($path); |
|
}; |
|
$callIntegration($path); |
|
$this->printIntegrationSectionFooter(); |
|
} |
|
} |
|
} |
|
}
|
|
|