diff --git a/css/DI/app.css b/css/DI/app.css index fc1a499cd..2494e7d50 100644 --- a/css/DI/app.css +++ b/css/DI/app.css @@ -1,3 +1,4 @@ +/* body */ body{ font-family: 'Montserrat', serif; padding-top: 64px; @@ -26,26 +27,36 @@ body[data-bs-theme="dark"] .app_icon{ [data-block="row_container"] > div{ display: flex; } -.combodo-row fieldset{ + +/* column */ +[data-block="column_container"]{ + padding: 10px; + flex-grow: 1; + width: 0; +} + +/* fieldset */ +[data-block="fieldset_container"]{ flex-grow: 1; } -.combodo-column{ - padding: 10px; -} -.combodo-field-set{ - border: #b7b7b7 dashed 1px; - padding: 10px; - border-radius: 10px; -} -.combodo-field-set-label{ +[data-block="fieldset_container"] > legend{ font-weight: bold; border-bottom: 2px solid #b7b7b7; margin-bottom: 10px; } -.loading{ +[data-block="fieldset_container"] > div{ + border: #b7b7b7 dashed 1px; + padding: 10px; + border-radius: 10px; +} + +/* ATTRIBUTES */ + +/* attribute */ +[data-block="attribute_container"].loading{ position: relative; } -.loading:after{ +[data-block="attribute_container"].loading:after{ content: 'loading...'; position: absolute; top: 0; @@ -58,11 +69,21 @@ body[data-bs-theme="dark"] .app_icon{ justify-content: center; border-radius: 10px; } -label.required:after{ + +/* FORM */ + +/* form */ +form{ + border-radius: 10px; + padding: 5px; +} + +/* label */ +form label.required:after{ content: ' *'; color: red; } -label.locked:after{ +form label.locked:after{ content: "\f023"; font-family: "Font Awesome 5 Free", serif; font-weight: 600; @@ -70,40 +91,6 @@ label.locked:after{ color: #ffcc00; font-size: .7rem; } -label.dependent{ +form label.dependent{ color: #2757af; } -form{ - /*background-color: #f8f8f8;*/ - border-radius: 10px; - padding: 5px; -} -form.actions button,a{ - margin: 0 3px; -} -[data-block="container"]:has(.test:empty) { - display: none; -} -.z_list_list{ - display: flex; -} -body[data-bs-theme="dark"] .app_icon{ - filter: invert(1); -} -.combodo-field-set-label.is_indirect_1:after{ - content: 'indirect'; - margin-left: 5px; - font-size: .8rem; - color: #0C63E4; -} -.combodo-field-set-label.is_abstract_1:after{ - content: 'abstract'; - margin-left: 5px; - font-size: .8rem; - color: #0C63E4; -} -.dropdown_scroll_300{ - max-height: 300px; - overflow-y: auto; - overflow-x: clip; -} diff --git a/js/DI/app.js b/js/DI/app.js index cad1fe004..1893ca82d 100644 --- a/js/DI/app.js +++ b/js/DI/app.js @@ -45,9 +45,20 @@ const App = function(){ }); } + /** + * ckeditor save editors. + * + */ + function saveCkEditors(){ + for(let instanceName in CKEDITOR.instances) { + CKEDITOR.instances[instanceName].updateElement(); + } + } + return { init, - handleTooltips + handleTooltips, + saveCkEditors } }; diff --git a/js/DI/collection.js b/js/DI/collection.js index 244ea096a..eea70ec09 100644 --- a/js/DI/collection.js +++ b/js/DI/collection.js @@ -9,12 +9,17 @@ */ const Collection = function(oForm, objectFormUrl, objectSaveUrl){ + const MODAL_LOADING_HTML = 'loading...'; + // dom selectors const aSelectors = { addItem: '.add_item_link', createItem: '.create_item_link', removeItem: '.btn-remove-link', - linkSetContainer: '.link_set_widget_container', + dataAttributeContainer: '[data-block="attribute_container"]', + dataObjectContainer: '[data-block="object_container"]', + dataAttCode: '[data-att-code]', + dataAttCodeSpecific: '[data-att-code="{0}"]', }; /** @@ -57,12 +62,12 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){ */ function addFormToCollection(e){ - // retrieve link set container - const oContainer = e.currentTarget.closest('.link_set_widget_container'); + // retrieve attribute container + const oAttributeContainer = e.currentTarget.closest(aSelectors.dataAttributeContainer); // retrieve collection holder (replace ':' character otherwise the selector is invalid) const exp = e.currentTarget.dataset.collectionHolderClass.replaceAll(/:/g, '\\:'); - const collectionHolder = oContainer.querySelector('.' + exp); + const collectionHolder = oAttributeContainer.querySelector('.' + exp); // compute template const text = collectionHolder @@ -85,8 +90,8 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){ // store new index collectionHolder.dataset.index++; - // remove no data row - oContainer.querySelector('.no_data').style.display = 'none'; + // hide no data row + oAttributeContainer.querySelector('.no_data').style.display = 'none'; } /** @@ -96,32 +101,40 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){ */ function createObject(e){ - let objectId = e.currentTarget.closest('form').dataset.objectId; + // retrieve attribute container + const oAttributeContainer = e.currentTarget.closest(aSelectors.dataAttributeContainer); - // set modal loading state - $('#object_modal .modal-body').html('loading...'); + // retrieve attribute field + const oAttributeField = oAttributeContainer.querySelector(aSelectors.dataAttCode); - const cont = e.currentTarget.closest('.link_set_widget_container'); + // retrieve attribute object container + const oObjectContainer = e.currentTarget.closest(aSelectors.dataObjectContainer); // open modal - const myModalAlternative = new bootstrap.Modal('#object_modal', {}); - myModalAlternative.show(); + const oModalBody= document.querySelector('#object_modal .modal-body'); + oModalBody.innerHTML = MODAL_LOADING_HTML; + const oModal = new bootstrap.Modal('#object_modal', {}); + oModal.show(); // compute object form url - const url = objectFormUrl + const sUrl = objectFormUrl .replaceAll('object_class', e.currentTarget.dataset.objectClass) .replaceAll('form_name', 'new'); // prepare request data const aLockedAttributes = {}; - aLockedAttributes[e.currentTarget.dataset.extKeyToMe] = objectId; + if(!e.currentTarget.dataset.isIndirect) { + aLockedAttributes[e.currentTarget.dataset.extKeyToMe] = oObjectContainer.dataset.objectId; + } const aData = { locked_attributes: aLockedAttributes, - att_code: cont.dataset.attCode + att_code: oAttributeField.dataset.attCode } + const sExtKeyToMe = e.currentTarget.dataset.extKeyToMe; + // fetch url - fetch(url, { + fetch(sUrl, { method: 'POST', headers: { 'Accept': 'application/json', @@ -131,21 +144,81 @@ const Collection = function(oForm, objectFormUrl, objectSaveUrl){ }) .then((response) => response.json()) .then((data) => { - const oModalBody = $('#object_modal .modal-body'); - oModalBody.html(data.template); - oModalBody[0].querySelectorAll('form').forEach((formEl) => { - oForm.handleElement(formEl); - handleElement(formEl); - oApp.handleTooltips(formEl); - }); - - listenSaveModalObject(myModalAlternative); + oModalBody.innerHTML = data.template; + oForm.handleElement(oModalBody); + handleElement(oModalBody); + oApp.handleTooltips(oModalBody); + listenSaveModalObject(oModal, oModalBody, oObjectContainer, oAttributeField.dataset.attCode, sExtKeyToMe, oAttributeContainer.dataset.objectClass); }) .catch(function (error) { console.error(error); }); } + /** + * + */ + function listenSaveModalObject(oModal, oModalBody, oObjectContainer, sAttCode, sExtKeyToMe, sObjectClass) + { + const oSave = document.querySelector('[data-action="save_modal_object"]'); + + oSave.addEventListener('click', function(e){ + + const oForm = document.querySelector('form[name="new"]'); + + // set loading state + oModalBody.innerHTML = MODAL_LOADING_HTML; + + // save CK editors + oApp.saveCkEditors(); + + // prepare data + const data = new URLSearchParams(); + for (const pair of new FormData(oForm)) { + data.append(pair[0], pair[1]); + } + data.append('ext_key_to_me', sExtKeyToMe); + data.append('object_class', sObjectClass); + + // compute object form url + const url = objectSaveUrl + .replaceAll('object_class', oForm.dataset.objectClass) + .replaceAll('form_name', 'new'); + + // fetch url + fetch(url, { + method: 'POST', + body: data, + }) + .then((response) => response.json()) + .then((data) => { + + // on success + if(data.succeeded){ + + // extract form content + const reg = new RegExp(/