poc form SDK (extends to form)

This commit is contained in:
Benjamin Dalsass
2023-09-05 15:12:48 +02:00
parent 253c61e241
commit 8126233553
12 changed files with 171 additions and 42 deletions

View File

@@ -3,10 +3,11 @@
*
* @param oForm
* @param objectFormUrl
* @param objectSaveUrl
* @returns {{handleElement: handleElement}}
* @constructor
*/
const Collection = function(oForm, objectFormUrl){
const Collection = function(oForm, objectFormUrl, objectSaveUrl){
/**
* Listen for add item buttons.
@@ -101,9 +102,13 @@ const Collection = function(oForm, objectFormUrl){
*/
function createObject(e){
let objectId = e.currentTarget.closest('form').dataset.objectId;
// set modal loading state
$('#object_modal .modal-body').html('loading...');
const cont = e.currentTarget.closest('.link_set_widget_container');
// open modal
const myModalAlternative = new bootstrap.Modal('#object_modal', []);
myModalAlternative.show();
@@ -115,14 +120,15 @@ const Collection = function(oForm, objectFormUrl){
// prepare request data
const aLockedAttributes = {};
aLockedAttributes[e.currentTarget.dataset.extKeyToMe] = 0;
aLockedAttributes[e.currentTarget.dataset.extKeyToMe] = objectId;
const aData = {
locked_attributes: aLockedAttributes
locked_attributes: aLockedAttributes,
att_code: cont.dataset.attCode
}
// fetch url
fetch(url, {
method: 'post',
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
@@ -154,6 +160,70 @@ const Collection = function(oForm, objectFormUrl){
listenRemoveItem(oContainer);
}
function listenSaveModalobject(){
const oSave = document.querySelector('[data-action="save_modal_object"]');
oSave.addEventListener('click', function(e){
const oForm = document.querySelector('form[name="new"]');
for(let instanceName in CKEDITOR.instances) {
CKEDITOR.instances[instanceName].updateElement();
}
const data = new URLSearchParams();
for (const pair of new FormData(oForm)) {
console.log(pair[0] + ' = ' + pair[1]);
data.append(pair[0], pair[1]);
}
data.append('locked_attributes', '');
// compute object form url
const url = objectSaveUrl
.replaceAll('object_class', oForm.dataset.objectClass)
.replaceAll('form_name', 'new');
// fetch url
fetch(url, {
method: 'POST',
body: new URLSearchParams(new FormData(oForm))
})
.then((response) => response.json())
.then((data) => {
let form = $(data.template);
console.log(form);
//
// console.log(oForm.dataset.attCode);
//
// const fragment = oToolkit.createElementFromHtml(data.template);
// const inner = fragment.querySelector('form').innerHTML;
// const el = oToolkit.createElementFromHtml(inner);
// console.log(el);
//
// const myModalAlternative = new bootstrap.Modal('#object_modal', []);
// myModalAlternative.hide();
console.log($(`[data-att-code="${oForm.dataset.attCode}"] tbody`));
$(`[data-att-code="${oForm.dataset.attCode}"] tbody`).append($(form.innerHTML));
})
.catch(function (error) {
console.error(error);
});
});
}
listenSaveModalobject();
return {
handleElement
}

View File

@@ -91,6 +91,8 @@ const Form = function(oWidget, oDynamic){
});
});
const aAllAttCodes = aDependentAttCodes.concat(aDependenciesAttCodes);
/////////////////////////////////
// II - PREPARE RELOAD REQUEST
@@ -99,7 +101,7 @@ const Form = function(oWidget, oDynamic){
let $bFirst = true;
// iterate throw dependencies...
aDependenciesAttCodes.forEach(function(sAtt) {
aAllAttCodes.forEach(function(sAtt) {
const oDependsOnElement = oElement.querySelector(String.format(aSelectors.dataAttCode, sAtt));
if(!$bFirst){
@@ -110,7 +112,7 @@ const Form = function(oWidget, oDynamic){
});
sRequestBody += '&att_codes=' + aDependentAttCodes.join(',');
sRequestBody += '&dependency_att_codes=' + aDependenciesAttCodes.join(',');
sRequestBody += '&dependency_att_codes=' + aAllAttCodes.join(',');
/////////////////////////////////
// III - UPDATE THE FORM

View File

@@ -142,6 +142,11 @@ class ObjectController extends AbstractController
// decode data
$aData = json_decode($request->getContent(), true);
// locked attributes
foreach($aData['locked_attributes'] as $sKey => $sValue){
$oObject->Set($sKey, $sValue);
}
// create object form
$oForm = $oFormFactory->createNamed($name, ObjectType::class, $oObject, [
'object_class' => $class,
@@ -150,10 +155,40 @@ class ObjectController extends AbstractController
'data-reload-url' => $this->generateUrl('object_reload', [
'class' => $class,
'id' => $id
])
]),
'data-object-class' => $class,
'data-att-code' => $aData['att_code']
]
]);
// return object form
return new JsonResponse([
'template' => $this->renderView('DI/form.html.twig', [
'id' => $id,
'class' => $class,
'form' => $oForm->createView(),
])
]);
}
/**
* @Route("/{class<\w+>}/{id<\d+>}/{name<\w+>}/save", name="object_save", methods={"POST"})
*/
public function objectSave(Request $request, string $name, string $class, int $id, ObjectService $oObjectService, FormFactoryInterface $oFormFactory) : Response
{
// retrieve object
try{
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
}
// create object form
$oForm = $oFormFactory->createNamed($name, ObjectType::class, $oObject, [
'object_class' => $class,
]);
// handle HTTP request
$oForm->handleRequest($request);
@@ -161,18 +196,32 @@ class ObjectController extends AbstractController
if ($oForm->isSubmitted() && $oForm->isValid()) {
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');
}
// redirect to view object
return new JsonResponse();
// create object form
$oForm = $oFormFactory->createNamed($name, ObjectType::class, $oObject, [
'object_class' => $class,
'z_list' => 'list'
]);
// return object form
return new JsonResponse([
'template' => $this->renderView('DI/form.html.twig', [
'id' => $id,
'class' => $class,
'form' => $oForm->createView(),
])
]);
}
// return object form
@@ -198,10 +247,13 @@ class ObjectController extends AbstractController
throw $this->createNotFoundException("The $class $id does not exist");
}
$aDependencyAttCodes = explode(',', $request->get('dependency_att_codes'));
$aAttCodes = explode(',', $request->get('att_codes'));
// create form with request data (dependent field)
$oForm = $this->createForm(PartialObjectType::class, $oObject, [
'object_class' => $class,
'att_codes' => explode(',', $request->get('dependency_att_codes'))
'att_codes' => array_merge($aDependencyAttCodes, $aAttCodes)
]);
// handle form data
@@ -213,7 +265,7 @@ class ObjectController extends AbstractController
// create a new form for affected field with updated (but not persist) data
$oForm = $this->createForm(PartialObjectType::class, $oObject, [
'object_class' => $class,
'att_codes' => explode(',', $request->get('att_codes'))
'att_codes' => $aAttCodes
]);
// return object form

View File

@@ -79,7 +79,7 @@ class AttributeBuilder
'required' => !$oAttributeDefinition->IsNullAllowed(),
'disabled' => !$oAttributeDefinition->IsWritable() || $bIsLocked,
'attr' => [
'data-att-code' => $sCode
'data-att-code' => $sCode,
],
'row_attr' => [
'data-block' => 'container'
@@ -87,7 +87,8 @@ class AttributeBuilder
'label_attr' => [
'class' => $bIsLocked ? 'locked' : ''
]
]
],
'create_hidden' => $bIsLocked
];
// register dependencies

View File

@@ -191,9 +191,10 @@ class ObjectFormListener implements EventSubscriberInterface
$aOptions['disabled'] = true;
}
// ignore fields hidden
// ignore fields hidden ISSUE WITH LINKSET PRESENTATION
if ($iFlags & (OPT_ATT_HIDDEN)) {
return null;
// $aOptions['attr']['class'] = 'd-none';
// return null;
}
return $aOptions;

View File

@@ -63,8 +63,11 @@ class ExternalKeyType extends AbstractType implements IFormTypeOptionModifier
}
// !!! ensure current value is part of result
$object = MetaModel::GetObject($aInitialOptions['object_class'], $iVal);
$aInitialOptions['choices'][$object->GetName()] = $iVal;
if($iVal > 0){
$object = MetaModel::GetObject($aInitialOptions['object_class'], $iVal);
$aInitialOptions['choices'][$object->GetName()] = $iVal;
}
}
catch(Exception $e){

View File

@@ -57,6 +57,7 @@ class LinkSetType extends AbstractType
$view->vars['labels'] = $this->oObjectService->getFormPresentationLabels($options['entry_options']['object_class'], 'list', $options['entry_options']['ext_key_to_me']);
$view->vars['object_class'] = $options['entry_options']['object_class'];
$view->vars['ext_key_to_me'] = $options['entry_options']['ext_key_to_me'];
$view->vars['att_code'] = $options['attr']['data-att-code'];
$view->vars['target_class'] = $options['target_class'];
$view->vars['is_indirect'] = $options['is_indirect'];
$view->vars['is_abstract'] = $options['is_abstract'];

View File

@@ -27,12 +27,6 @@ class ObjectType extends AbstractType
/** @var ObjectPresentationService object presentation service */
private ObjectPresentationService $objectPresentationService;
/** @var \Combodo\iTop\DI\Form\Builder\AttributeBuilder attribute builder */
private AttributeBuilder $oAttributeBuilder;
/** @var \Combodo\iTop\DI\Form\Builder\LayoutBuilder layout builder */
private LayoutBuilder $oLayoutBuilder;
/**
* Constructor.
*
@@ -41,12 +35,10 @@ class ObjectType extends AbstractType
* @param \Combodo\iTop\DI\Form\Builder\AttributeBuilder $oAttributeBuilder
* @param \Combodo\iTop\DI\Form\Builder\LayoutBuilder $oLayoutBuilder
*/
public function __construct(ObjectFormListener $oObjectFormModifier, ObjectPresentationService $objectPresentationService, AttributeBuilder $oAttributeBuilder, LayoutBuilder $oLayoutBuilder)
public function __construct(ObjectFormListener $oObjectFormModifier, ObjectPresentationService $objectPresentationService)
{
$this->oObjectFormModifier = $oObjectFormModifier;
$this->objectPresentationService = $objectPresentationService;
$this->oAttributeBuilder = $oAttributeBuilder;
$this->oLayoutBuilder = $oLayoutBuilder;
}
/** @inheritdoc */

View File

@@ -6,6 +6,7 @@ use Combodo\iTop\DI\Form\Builder\AttributeBuilder;
use Combodo\iTop\DI\Form\Builder\LayoutBuilder;
use Dict;
use MetaModel;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
/**
@@ -57,6 +58,10 @@ class ObjectPresentationService
$level = $this->handleLevel($aPresentation, $class, $lockedAttributes);
foreach ($level as $key => $value) {
$builder->add($key, $value['type'], $value['options']);
// if(array_key_exists('create_hidden', $value) && $value['create_hidden'] === true){
// $builder->add($key,HiddenType::class);
// }
}
}
@@ -107,7 +112,7 @@ class ObjectPresentationService
$aPresentation = MetaModel::GetZListItems($class, $zList);
$aPresentation = $this->filterLinkSetpresentation($aPresentation, $class, $sExtKeyToMe);
$level = $this->handleLevel($aPresentation, $class, null, null);
$level = $this->handleLevel($aPresentation, $class, null);
$aLabels = [];
foreach ($level as $key => $value) {
$value['options']['attr']['data-att-code'] = $key;

View File

@@ -32,7 +32,7 @@
<body data-bs-theme="light">
<!-- nav -->
<!-- navbar -->
<nav class="navbar navbar-expand-lg fixed-top bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#"><img class="app_icon" src="{{ asset_image('DI/flask-solid.svg') }}" width="24px"> Forms SDK</a>
@@ -80,18 +80,15 @@
</div>
</nav>
{# - BLOCK BODY - #}
<div class="m-3">
{# - BLOCK BODY - #}
{% block body %}{% endblock %}
</div>
{# - BLOCK TOASTS - #}
<div class="toast-container position-fixed bottom-0 start-50 translate-middle-x p-3">
{# - BLOCK TOASTS - #}
{% block toasts %}{% endblock %}
</div>
<!-- Full screen modal -->
@@ -102,7 +99,7 @@
<h1 class="modal-title fs-4" id="exampleModalFullscreenLabel">Create object</h1>
<div>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" aria-label="Close">Cancel</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" aria-label="Confirm">Confirm</button>
<button type="button" class="btn btn-primary" data-action="save_modal_object" aria-label="Confirm">Confirm</button>
</div>
</div>
<div class="modal-body">
@@ -112,10 +109,15 @@
</div>
<div id="test">
</div>
<script>
// Toolkit
var oToolkit = new Toolkit();
const oToolkit = new Toolkit();
oToolkit.init();
// App initialization

View File

@@ -76,7 +76,7 @@
{% endif %}
{# container #}
<div class="link_set_widget_container">
<div class="link_set_widget_container" data-att-code="{{ att_code }}">
{# table #}
<table class="table link_set_widget" >

View File

@@ -39,7 +39,7 @@
{# inject form #}
<div>
{{ form(form, {'attr': {'id' : 'object_form'}}) }}
{{ form(form, {'attr': {'id' : 'object_form', 'data-object-id' : id}}) }}
</div>
{% endblock %}
@@ -59,7 +59,7 @@
});
{# Collection #}
const oCollection = new Collection(oForm, '{{ path('object_form', {'class': 'object_class', 'id' : 0, 'name': 'form_name'}) }}');
const oCollection = new Collection(oForm, '{{ path('object_form', {'class': 'object_class', 'id' : 0, 'name': 'form_name'}) }}', '{{ path('object_save', {'class': 'object_class', 'id' : 0, 'name': 'form_name'}) }}');
oCollection.handleElement(document);
{# toast database information #}