mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-25 21:34:12 +01:00
poc form SDK (change dependencies implementation)
This commit is contained in:
12
js/DI/app.js
12
js/DI/app.js
@@ -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) => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
|
||||
33
sources/DI/Form/Manager/ObjectFormManager.php
Normal file
33
sources/DI/Form/Manager/ObjectFormManager.php
Normal 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){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user