poc form SDK (change dependencies implementation)

This commit is contained in:
Benjamin Dalsass
2023-09-06 15:12:51 +02:00
parent 20a663d631
commit d63b3d7265
8 changed files with 148 additions and 67 deletions

View File

@@ -1,7 +1,7 @@
/**
* Application handling.
*
* @returns {{init: init}}
* @returns {{init: init, handleTooltips: handleTooltips}}
* @constructor
*/
const App = function(){
@@ -12,24 +12,32 @@ const App = function(){
};
/**
* init.
* initialization.
*
*/
function init(){
// dark theme button
$(aSelectors.darkModeButton).on('click', function(){
$('body').attr('data-bs-theme', this.ariaPressed === 'true' ? 'dark' : 'light');
});
// dark theme button state
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
$('body').attr('data-bs-theme', 'dark');
$(aSelectors.darkModeButton).attr('aria-pressed', 'true');
$(aSelectors.darkModeButton).toggleClass('active', true);
}
// handle tooltips
handleTooltips(document);
}
/**
* Bootstrap tooltip initialization.
*
* @param oElement
*/
function handleTooltips(oElement){
const tooltips = oElement.querySelectorAll("[data-bs-toggle='tooltip']");
tooltips.forEach((el) => {

View File

@@ -9,17 +9,23 @@
*/
const Collection = function(oForm, objectFormUrl, objectSaveUrl){
// dom selectors
const aSelectors = {
addItem: '.add_item_link',
createItem: '.create_item_link',
removeItem: '.btn-remove-link',
linkSetContainer: '.link_set_widget_container',
};
/**
* Listen for add item buttons.
*
* @param oContainer
*/
function listenAddItem (oContainer) {
oContainer.querySelectorAll('.add_item_link').forEach(btn => {
btn.addEventListener("click", addFormToCollection)
oContainer.querySelectorAll(aSelectors.addItem).forEach(btn => {
btn.addEventListener('click', addFormToCollection)
});
}
/**
@@ -28,11 +34,9 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
* @param oContainer
*/
function listenCreateItem (oContainer) {
oContainer.querySelectorAll('.create_item_link').forEach(btn => {
btn.addEventListener("click", createObject)
oContainer.querySelectorAll(aSelectors.createItem).forEach(btn => {
btn.addEventListener('click', createObject)
});
}
/**
@@ -41,20 +45,9 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
* @param oContainer
*/
function listenRemoveItem(oContainer){
oContainer.querySelectorAll('.btn-remove-link').forEach(btn => {
btn.addEventListener("click", (e) => {
const oContainer = e.currentTarget.closest('.link_set_widget_container');
btn.closest('tr').remove()
if(oContainer.querySelectorAll('tbody tr').length === 1) {
oContainer.querySelector('.no_data').style.display = 'table-row';
}
})
oContainer.querySelectorAll(aSelectors.removeItem).forEach(btn => {
btn.addEventListener('click', removeItem);
});
}
/**
@@ -67,7 +60,7 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
// retrieve link set container
const oContainer = e.currentTarget.closest('.link_set_widget_container');
// retrieve collection holder
// retrieve collection holder (replace ':' character otherwise the selector is invalid)
const exp = e.currentTarget.dataset.collectionHolderClass.replaceAll(/:/g, '\\:');
const collectionHolder = oContainer.querySelector('.' + exp);
@@ -145,12 +138,33 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
handleElement(formEl);
oApp.handleTooltips(formEl);
});
listenSaveModalObject(myModalAlternative);
})
.catch(function (error) {
console.error(error);
});
}
/**
* Remove an item.
*
* @param e
*/
function removeItem(e)
{
// retrieve link set container
const oContainer = e.currentTarget.closest(aSelectors.linkSetContainer);
// remove row
e.currentTarget.closest('tr').remove();
// handle no data row visibility
if(oContainer.querySelectorAll('tbody tr').length === 1) {
oContainer.querySelector('.no_data').style.display = 'table-row';
}
}
/**
* Handle collection on the provided container element.
*
@@ -163,8 +177,11 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
listenRemoveItem(oContainer);
}
function listenSaveModalobject(){
/**
*
*/
function listenSaveModalObject(myModalAlternative)
{
const oSave = document.querySelector('[data-action="save_modal_object"]');
oSave.addEventListener('click', function(e){
@@ -194,25 +211,29 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
.then((response) => response.json())
.then((data) => {
let form = $(data.template);
if(data.succeeded){
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', {
hide: true
});
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);
//
myModalAlternative.hide();
console.log($(`[data-att-code="${oForm.dataset.attCode}"] tbody`));
console.log($(`[data-att-code="${oForm.dataset.attCode}"] tbody`));
$(`[data-att-code="${oForm.dataset.attCode}"] tbody`).append($(form.innerHTML));
$(`[data-att-code="${oForm.dataset.attCode}"] tbody`).append($(form.innerHTML));
}
else{
console.error('Error while saving object');
}
})
.catch(function (error) {
@@ -222,7 +243,6 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){
});
}
listenSaveModalobject();
return {
handleElement

View File

@@ -193,7 +193,13 @@ const Form = function(oWidget, oDynamic){
for(let sContainerId in aMapDependencies) {
// retrieve object container
const oObjectContainer = document.querySelector(`[data-container-id="${sContainerId}"]`);
let oObjectContainer = null;
if(oElement.dataset !== undefined && oElement.dataset.containerId === sContainerId){
oObjectContainer = oElement;
}
else{
oObjectContainer = oElement.querySelector(`[data-container-id="${sContainerId}"]`);
}
const aMapContainer = aMapDependencies[sContainerId];

View File

@@ -22,8 +22,8 @@ const Widget = function(){
// initialize widget
const sWidgetName = widgetField.dataset.widget;
const oWidget = eval(`$(widgetField).${sWidgetName}()`);
console.log('Init widget: ' + sWidgetName);
console.log(oWidget);
console.debug('Init widget: ' + sWidgetName);
console.debug(oWidget);
});
}

View File

@@ -2,6 +2,7 @@
namespace Combodo\iTop\DI\Controller;
use Combodo\iTop\DI\Form\Manager\ObjectFormManager;
use Combodo\iTop\DI\Form\Type\Compound\PartialObjectType;
use Combodo\iTop\DI\Form\Type\Compound\ObjectType;
use Combodo\iTop\DI\Services\ObjectService;
@@ -25,8 +26,9 @@ class ObjectController extends AbstractController
/**
* @Route ("/{class<\w+>}/{id<\d+>}/view", name="object_view")
* Return object view page with object data printed with key value representation.
*
* @Route ("/{class<\w+>}/{id<\d+>}/view", name="object_view")
*/
public function objectView(string $class, int $id) : Response
{
@@ -35,7 +37,7 @@ class ObjectController extends AbstractController
$oObject = MetaModel::GetObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
throw $this->createNotFoundException("The $class $id does not exist", $e);
}
// return object view
@@ -47,16 +49,18 @@ class ObjectController extends AbstractController
}
/**
* Return object view as JSon response.
*
* @Route ("/{class<\w+>}/{id<\d+>}/json", name="object_json")
*/
public function objectJSon(string $class, int $id) : Response
public function objectJSon(string $class, int $id) : JsonResponse
{
// retrieve object
try{
$oObject = MetaModel::GetObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
throw $this->createNotFoundException("The $class $id does not exist", $e);
}
// return object as json response
@@ -66,6 +70,11 @@ class ObjectController extends AbstractController
}
/**
* Return object edition view page.
* The form is constructed with the ObjectType form type @see ObjectType
*
* @todo perform database DbInsert, DbDelete, DbUpdate on links
*
* @Route("/{class<\w+>}/{id<\d+>}/edit", name="object_edit")
*/
public function objectEdit(Request $request, string $class, int $id, ObjectService $oObjectService) : Response
@@ -91,7 +100,7 @@ class ObjectController extends AbstractController
try {
// handle link set (apply DbInsert, DbDelete, DbUpdate) could be automatic ?
// handle link set (apply DbInsert, DbDelete, DbUpdate) should be automatic ? handle by host object ?
$oObjectService->handleLinkSetDB($oObject);
// save object
@@ -104,7 +113,7 @@ class ObjectController extends AbstractController
}
catch(Exception $e){
throw new HttpException(500, 'Error while trying to save object');
throw new HttpException(500, 'Error while trying to save object', $e);
}
// redirect to view object
@@ -125,6 +134,8 @@ class ObjectController extends AbstractController
}
/**
* Return an object form view.
*
* @Route("/{class<\w+>}/{id<\d+>}/{name<\w+>}/form", name="object_form", methods={"POST"})
*/
public function objectForm(Request $request, string $name, string $class, int $id, ObjectService $oObjectService, FormFactoryInterface $oFormFactory) : Response
@@ -134,7 +145,7 @@ class ObjectController extends AbstractController
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
throw $this->createNotFoundException("The $class $id does not exist", $e);
}
// decode data
@@ -176,16 +187,18 @@ class ObjectController extends AbstractController
}
/**
* Save object into database and return its list representation.
*
* @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
public function objectSave(Request $request, string $name, string $class, int $id, ObjectService $oObjectService, FormFactoryInterface $oFormFactory, ObjectFormManager $oObjectFormManager) : Response
{
// retrieve object
try{
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
throw $this->createNotFoundException("The $class $id does not exist", $e);
}
// create object form
@@ -196,13 +209,8 @@ class ObjectController extends AbstractController
// handle HTTP request
$oForm->handleRequest($request);
// locked attributes
$aValue = $request->get('new');
$sLockedAttributes = $aValue['locked_attributes'];
$aLockedAttributes = json_decode($sLockedAttributes);
foreach($aLockedAttributes as $sKey => $sValue){
$oObject->Set($sKey, $sValue);
}
// apply locked attributes to object
$oObjectFormManager->applyRequestLockedAttributesToObject($request, $oObject, 'new');
// submitted and valid
if ($oForm->isSubmitted() && $oForm->isValid()) {
@@ -217,7 +225,7 @@ class ObjectController extends AbstractController
}
}
catch(Exception $e){
throw new HttpException(500, 'Error while trying to save object');
throw new HttpException(500, 'Error while trying to save object', $e);
}
// create object form
@@ -229,7 +237,7 @@ class ObjectController extends AbstractController
// return object form
return new JsonResponse([
'succeeded' => true,
'template' => $this->renderView('DI/form.html.twig', [
'template' => $this->renderView('DI/form/form.html.twig', [
'id' => $id,
'class' => $class,
'form' => $oForm->createView(),
@@ -244,6 +252,10 @@ class ObjectController extends AbstractController
}
/**
* Actualize a piece of the form.
* The first form, used to apply modifications, contains all dependencies attributes and dependent attributes.
* The second form, used for new fields templates, contains only the dependent attributes.
*
* @Route("/{class<\w+>}/{id<\d+>}/reload", name="object_reload")
*/
public function objectReload(Request $request, string $class, int $id, ObjectService $oObjectService) : Response
@@ -253,7 +265,7 @@ class ObjectController extends AbstractController
$oObject = $oObjectService->getObject($class, $id);
}
catch(Exception $e){
throw $this->createNotFoundException("The $class $id does not exist");
throw $this->createNotFoundException("The $class $id does not exist", $e);
}
$aDependencyAttCodes = explode(',', $request->get('dependency_att_codes'));

View File

@@ -0,0 +1,33 @@
<?php
namespace Combodo\iTop\DI\Form\Manager;
use DBObject;
use Exception;
use Symfony\Component\HttpFoundation\Request;
class ObjectFormManager
{
/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \DBObject $oDbObject
* @param string $sFormName
*
* @return void
*/
public function applyRequestLockedAttributesToObject(Request $request, DBObject $oDbObject, string $sFormName){
try{
$aValue = $request->get($sFormName);
$sLockedAttributes = $aValue['locked_attributes'];
$aLockedAttributes = json_decode($sLockedAttributes);
foreach($aLockedAttributes as $sKey => $sValue){
$oDbObject->Set($sKey, $sValue);
}
}
catch(Exception $e){
}
}
}

View File

@@ -149,10 +149,12 @@
{% if objectId == -1 %}
{% set objectId = 0 %}
{% endif %}
{% else %}
{% set objectId = 0 %}
{% endif %}
{% if z_list == 'list' %}
<tr data-block="object_container" {% if form.vars.data is not empty %}data-container-id="{{ form.vars.id }}" data-object-id="{{ form.vars.data.id }}" data-reload-url="{{ path('object_reload', {class: form.vars.object_class, id: objectId }) }}"{% endif %}>
<tr data-block="object_container" data-container-id="{{ form.vars.id }}" data-object-id="{{ objectId }}" data-reload-url="{{ path('object_reload', {class: form.vars.object_class, id: objectId }) }}">
{% for child in form %}
<td data-block="container">
{{ form_widget(child) }}
@@ -163,7 +165,7 @@
</td>
</tr>
{% else %}
<div data-block="object_container" data-container-id="{{ form.vars.id }}" data-object-id="{{ form.vars.data.id }}" data-reload-url="{{ path('object_reload', {class: form.vars.object_class, id: objectId }) }}">
<div data-block="object_container" data-container-id="{{ form.vars.id }}" data-object-id="{{ objectId }}" data-reload-url="{{ path('object_reload', {class: form.vars.object_class, id: objectId }) }}">
{{ form_widget(form) }}
</div>
{% endif %}

View File

@@ -76,7 +76,7 @@
{% block modals %}
<!-- Full screen modal -->
<div class="modal fade" id="object_modal" tabindex="-1" aria-labelledby="object_modal1" aria-hidden="true">
<div class="modal fade" id="object_modal" tabindex="-1" aria-labelledby="object_modal" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">