poc form SDK (extends to form)

This commit is contained in:
Benjamin Dalsass
2023-09-01 16:15:34 +02:00
parent 664aa3949d
commit 253c61e241
8 changed files with 229 additions and 59 deletions

View File

@@ -79,10 +79,13 @@ const Collection = function(oForm, objectFormUrl){
);
// create item element
const item = oToolkit.createElementFromHtml(text);
const fragment = oToolkit.createElementFromHtml(text);
collectionHolder.appendChild(fragment);
// form handling
const item = collectionHolder.querySelector('tr:last-child');
listenRemoveItem(item);
oForm.handleElement(item);
collectionHolder.appendChild(item);
// store new index
collectionHolder.dataset.index++;

116
js/DI/dynamic.js Normal file
View File

@@ -0,0 +1,116 @@
/**
* Dynamics handling.
*
* @returns {{handleElement: handleElement}}
* @constructor
*/
const Dynamic = function(){
const aSelectors = {
dataHideWhen: '[data-hide-when]',
dataDisableWhen: '[data-disable-when]',
dataAttCode: '[data-att-code="{0}"]',
dataBlockContainer: '[data-block="container"]',
};
/**
* hideEmptyContainers.
*
* The purpose of this function is to hide empty containers.
* Ex: FieldSetType with no children
*
*/
function hideEmptyContainers(oElement){
$('.combodo-field-set', oElement).each(function(){
$(this).parent().toggle($(this).children().length !== 0);
});
}
/**
* initDynamicsInvisible.
*
* @param oElement
*/
function initDynamicsInvisible(oElement){
// get all dynamic hide fields
const aInvisibleFields = oElement.querySelectorAll(aSelectors.dataHideWhen);
// iterate throw fields...
aInvisibleFields.forEach(function (oInvisibleField) {
// retrieve condition
const aHideWhenCondition = JSON.parse(oInvisibleField.dataset.hideWhen);
// retrieve condition data
const oHideWhenElement = oElement.querySelector(String.format(aSelectors.dataAttCode, aHideWhenCondition.att_code));
// initial hidden state
oInvisibleField.closest(aSelectors.dataBlockContainer).hidden = (oHideWhenElement.value === aHideWhenCondition.value);
// listen for changes
oHideWhenElement.addEventListener('change', (e) => {
oInvisibleField.closest(aSelectors.dataBlockContainer).hidden = (e.target.value === aHideWhenCondition.value);
oInvisibleField.closest(aSelectors.dataBlockContainer).style.visibility = (e.target.value === aHideWhenCondition.value) ? 'hidden' : '';
});
});
}
/**
* initDynamicsDisable.
*
* @param oElement
*/
function initDynamicsDisable(oElement){
// get all dynamic hide fields
const aDisabledFields = oElement.querySelectorAll(aSelectors.dataDisableWhen);
// iterate throw fields...
aDisabledFields.forEach(function (oDisabledField) {
// retrieve condition
const aDisableWhenCondition = JSON.parse(oDisabledField.dataset.disableWhen);
// retrieve condition data
const oDisableWhenElement = oElement.querySelector(`[data-att-code="${aDisableWhenCondition.att_code}"]`);
// initial disabled state
oDisabledField.closest(aSelectors.dataBlockContainer).disabled = (oDisableWhenElement.value === aDisableWhenCondition.value);
// listen for changes
oDisableWhenElement.addEventListener('change', (e) => {
oDisabledField.closest(aSelectors.dataBlockContainer).disabled = (e.target.value === aDisableWhenCondition.value);
});
});
}
/**
* handleElement.
*
* @param element
*/
function handleElement(element){
hideEmptyContainers(element);
initDynamicsInvisible(element);
initDynamicsDisable(element);
}
return {
handleElement,
}
};

View File

@@ -2,17 +2,16 @@
* Forms handling.
*
* @param oWidget
* @param oDynamic
* @returns {{handleElement: handleElement}}
* @constructor
*/
const Form = function(oWidget){
const Form = function(oWidget, oDynamic){
const DEPENDS_ON_SEPARATOR = ' ';
const aSelectors = {
dataDependsOn: '[data-depends-on]',
dataHideWhen: '[data-hide-when]',
dataDisableWhen: '[data-disable-when]',
dataBlockContainer: '[data-block="container"]',
dataAttCode: '[data-att-code="{0}"]'
};
@@ -261,11 +260,9 @@ const Form = function(oWidget){
* @param element
*/
function handleElement(element){
hideEmptyContainers(element);
initDependencies(element);
initDynamicsInvisible(element);
initDynamicsDisable(element);
oWidget.handleElement(element);
oDynamic.handleElement(element);
}
return {

View File

@@ -0,0 +1,34 @@
<?php
namespace Combodo\iTop\DI\Controller;
use Combodo\iTop\DI\Form\Type\Compound\ConfigurationType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Configuration controller.
*
*/
class ConfigurationController extends AbstractController
{
/**
* @Route("/configuration/edit", name="configuration_edit")
*/
public function configurationEdit(Request $request) : Response
{
// create object form
$oForm = $this->createForm(ConfigurationType::class, []);
// handle HTTP request
$oForm->handleRequest($request);
// return object form
return $this->renderForm('DI/configuration/edit.html.twig', [
'form' => $oForm
]);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Combodo\iTop\DI\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Default controller.
*
*/
class DefaultController extends AbstractController
{
/**
* @Route ("/", name="root")
*/
public function root(): Response
{
return $this->redirectToRoute('home');
}
/**
* @Route ("/home", name="home")
*/
public function home(): Response
{
return $this->render('DI/home.html.twig');
}
}

View File

@@ -2,7 +2,6 @@
namespace Combodo\iTop\DI\Controller;
use Combodo\iTop\DI\Form\Type\Compound\ConfigurationType;
use Combodo\iTop\DI\Form\Type\Compound\PartialObjectType;
use Combodo\iTop\DI\Form\Type\Compound\ObjectType;
use Combodo\iTop\DI\Services\ObjectService;
@@ -15,25 +14,14 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Stopwatch\Stopwatch;
class Controller extends AbstractController
/**
* Object controller.
*
*/
class ObjectController extends AbstractController
{
/**
* @Route ("/", name="root")
*/
public function root(): Response
{
return $this->redirectToRoute('home');
}
/**
* @Route ("/home", name="home")
*/
public function home(): Response
{
return $this->render('DI/home.html.twig');
}
/**
* @Route ("/{class<\w+>}/{id<\d+>}/view", name="object_view")
@@ -83,7 +71,7 @@ class Controller extends AbstractController
{
// retrieve object
try{
$oObject= $oObjectService->getObject($class, $id);
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
@@ -103,15 +91,19 @@ class Controller extends AbstractController
// submitted and valid
if ($oForm->isSubmitted() && $oForm->isValid()) {
// retrieve object
$oObject = $oForm->getData();
try {
// handle link set (apply DbInsert, DbDelete, DbUpdate) could be automatic ?
$oObjectService->handleLinkSetDB($oObject);
// save object
$oObject->DBUpdate();
if($id === 0){
$id = $oObject->DBInsert();
}
else{
$oObject->DBUpdate();
}
}
catch(Exception $e){
throw new HttpException(500, 'Error while trying to save object');
@@ -141,7 +133,7 @@ class Controller extends AbstractController
{
// retrieve object
try{
$oObject= $oObjectService->getObject($class, $id);
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
@@ -168,9 +160,6 @@ class Controller extends AbstractController
// submitted and valid
if ($oForm->isSubmitted() && $oForm->isValid()) {
// retrieve object
$oObject = $oForm->getData();
try {
// handle link set (apply DbInsert, DbDelete, DbUpdate) could be automatic ?
$oObjectService->handleLinkSetDB($oObject);
@@ -203,7 +192,7 @@ class Controller extends AbstractController
{
// retrieve object
try{
$oObject= $oObjectService->getObject($class, $id);
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
@@ -233,20 +222,4 @@ class Controller extends AbstractController
]);
}
/**
* @Route("/configuration/edit", name="configuration_edit")
*/
public function configurationEdit(Request $request) : Response
{
// create object form
$oForm = $this->createForm(ConfigurationType::class, []);
// handle HTTP request
$oForm->handleRequest($request);
// return object form
return $this->renderForm('DI/configuration/edit.html.twig', [
'form' => $oForm
]);
}
}

View File

@@ -24,9 +24,6 @@
{# JS #}
<script src="{{ asset_js('DI/toolkit.js') }}"></script>
<script src="{{ asset_js('DI/app.js') }}"></script>
<script src="{{ asset_js('DI/collection.js') }}"></script>
<script src="{{ asset_js('DI/form.js') }}"></script>
<script src="{{ asset_js('DI/widget.js') }}"></script>
{# - BLOCK HEAD - #}
{% block head %}{% endblock %}
@@ -58,6 +55,17 @@
<li><a class="dropdown-item" href="{{ path('object_edit', {'class': 'UserRequest', 'id': 1}) }}">UserRequest</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
New Object
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ path('object_edit', {'class': 'Organization', 'id': 0}) }}">Organization</a></li>
<li><a class="dropdown-item" href="{{ path('object_edit', {'class': 'Person', 'id': 0}) }}">Person</a></li>
<li><a class="dropdown-item" href="{{ path('object_edit', {'class': 'User', 'id': 0}) }}">User</a></li>
<li><a class="dropdown-item" href="{{ path('object_edit', {'class': 'UserRequest', 'id': 0}) }}">UserRequest</a></li>
</ul>
</li>
<li class="nav-item">
<a href="{{ path('configuration_edit') }}" class="nav-link">Edit Configuration</a>
</li>
@@ -107,7 +115,7 @@
<script>
// Toolkit
const oToolkit = new Toolkit();
var oToolkit = new Toolkit();
oToolkit.init();
// App initialization

View File

@@ -6,13 +6,19 @@
{% block head %}
<script src="{{ asset_js('DI/widget.js') }}"></script>
<script src="{{ asset_js('DI/dynamic.js') }}"></script>
<script src="{{ asset_js('DI/form.js') }}"></script>
<script src="{{ asset_js('DI/collection.js') }}"></script>
<script src="{{ asset_js('DI/widget/text_widget.js') }}"></script>
{% endblock %}
{% block actions %}
<a href="{{ path('object_edit', {'class': class, 'id': id - 1}) }}" class="btn btn-secondary btn {% if id <= 1 %} disabled {% endif %}"><i class="fa-solid fa-arrow-left"></i></a>
<a href="{{ path('object_edit', {'class': class, 'id': id + 1}) }}" class="btn btn-secondary btn"><i class="fa-solid fa-arrow-right"></i></a>
{% if id != 0 %}
<a href="{{ path('object_edit', {'class': class, 'id': id - 1}) }}" class="btn btn-secondary btn {% if id <= 1 %} disabled {% endif %}"><i class="fa-solid fa-arrow-left"></i></a>
<a href="{{ path('object_edit', {'class': class, 'id': id + 1}) }}" class="btn btn-secondary btn"><i class="fa-solid fa-arrow-right"></i></a>
{% endif %}
<button type="reset" class="btn-secondary btn" form="object_form">Reset</button>
<button type="submit" class="btn-primary btn" form="object_form">Save</button>
{% endblock %}
@@ -42,10 +48,12 @@
{# Widget #}
const oWidget = new Widget();
oWidget.handleElement(document);
{# Dynamic #}
const oDynamic = new Dynamic();
{# Form #}
const oForm = new Form(oWidget);
const oForm = new Form(oWidget, oDynamic);
document.querySelectorAll('form').forEach((formEl) => {
oForm.handleElement(formEl);
});