');
oParams = this.options.submit_parameters;
oParams.operation = 'createObject';
@@ -225,14 +187,14 @@ $(function()
}
});
me.indicator.html('');
- // me.oButtons['create'].prop('disabled', false);
+ $('[data-role="ibo-button"][data-action="create"]', this.element).prop('disabled', false);
me._updateDlgPosition();
});
},
_selectToAdd: function()
{
- // this.oButtons['add'].prop('disabled', true);
+ $('[data-role="ibo-button"][data-action="add"]', this.element).prop('disabled', true);
this.indicator.html('
');
oParams = this.options.submit_parameters;
oParams.operation = 'selectObjectsToAdd';
@@ -298,7 +260,7 @@ $(function()
});
me.indicator.html('');
- // me.oButtons['add'].prop('disabled', false);
+ $('[data-role="ibo-button"][data-action="add"]', this.element).prop('disabled', false);
if (me.options.do_search)
{
me._onSearchToAdd();
@@ -468,7 +430,7 @@ $(function()
me._updateTable();
me.indicator.html('');
- // me.oButtons['add'].prop('disabled', false);
+ $('[data-role="ibo-button"][data-action="add"]', this.element).prop('disabled', false);
me._updateTableInformation();
});
@@ -535,7 +497,7 @@ $(function()
oParams.tempId = nextIdx;
var me = this;
- // this.oButtons['create'].prop('disabled', true);
+ $('[data-role="ibo-button"][data-action="create"]', this.element).prop('disabled', true);
this.indicator.html('
');
$.post(this.options.submit_to, oParams, function (data) {
@@ -545,7 +507,7 @@ $(function()
me._updateTable();
me.indicator.html('');
- // me.oButtons['create'].prop('disabled', false);
+ $('[data-role="ibo-button"][data-action="create"]', this.element).prop('disabled', false);
});
}
},
@@ -656,6 +618,18 @@ $(function()
Remove: function(oCheckbox) // for public access
{
this._removeRow(oCheckbox);
+ },
+ selectToAdd: function(){
+ this._selectToAdd();
+ },
+ removeSelection: function(){
+ this._removeSelection();
+ },
+ createRow: function(){
+ this._createRow();
+ },
+ deleteSelection: function(){
+ this._deleteSelection();
}
});
});
\ No newline at end of file
diff --git a/js/links/links_set.js b/js/links/links_set.js
new file mode 100644
index 000000000..383c2f66e
--- /dev/null
+++ b/js/links/links_set.js
@@ -0,0 +1,46 @@
+let CombodoLinkSet = new function () {
+
+ /**
+ * Create a new link object and add it to set widget.
+ *
+ * @param sLinkedClass
+ * @param sCode
+ * @param sHostObjectClass
+ * @param sHostObjectKey
+ * @param sRemoteExtKey
+ * @param sRemoteClass
+ * @param oWidget
+ * @constructor
+ */
+ const CallCreateLinkedObject = function(sLinkedClass, sCode, sHostObjectClass, sHostObjectKey, sRemoteExtKey, sRemoteClass, oWidget)
+ {
+ // Create link object
+ CombodoLinkSetWorker.CreateLinkedObject(sLinkedClass, sCode, sHostObjectClass, sHostObjectKey,
+ function(){
+ $(this).find("form").remove();
+ $(this).dialog('destroy');
+ },
+ function(event, data){
+
+ // We have just create a link object, now request the remote object
+ CombodoLinkSetWorker.GetRemoteObject(data.data.object.class_name, data.data.object.key, sRemoteExtKey, sRemoteClass, function(data){
+
+ // Add the new remote object in widget set options list
+ const selectize = oWidget[0].selectize;
+ selectize.addOption(data.data.object);
+ selectize.refreshOptions(false);
+
+ // Select the new remote object
+ selectize.addItem(data.data.object.key);
+
+ // Add to initial values, to handle remove action
+ selectize.addInitialValue(data.data.object.key);
+ });
+ });
+ }
+
+
+ return {
+ CreateLinkedObject: CallCreateLinkedObject,
+ }
+};
\ No newline at end of file
diff --git a/js/links/links_set_worker.js b/js/links/links_set_worker.js
new file mode 100644
index 000000000..abfa8200a
--- /dev/null
+++ b/js/links/links_set_worker.js
@@ -0,0 +1,106 @@
+let CombodoLinkSetWorker = new function(){
+
+ // defines
+ const ROUTER_BASE_URL = '../pages/ajax.render.php';
+ const ROUTE_LINK_SET_DELETE_OBJECT = 'linkset.delete_linked_object';
+ const ROUTE_LINK_SET_DETACH_OBJECT = 'linkset.detach_linked_object';
+ const ROUTE_LINK_SET_CREATE_OBJECT = 'linkset.create_linked_object';
+ const ROUTE_LINK_GET_REMOTE_OBJECT = 'linkset.get_remote_object';
+
+ /**
+ * CallAjaxDeleteLinkedObject.
+ *
+ * @param {string} sLinkedObjectClass
+ * @param {string} sLinkedObjectKey
+ * @param oOnResponseCallback
+ * @constructor
+ */
+ const CallAjaxDeleteLinkedObject = function(sLinkedObjectClass, sLinkedObjectKey, oOnResponseCallback){
+
+ $.post(`${ROUTER_BASE_URL}?route=${ROUTE_LINK_SET_DELETE_OBJECT}`, {
+ linked_object_class: sLinkedObjectClass,
+ linked_object_key: sLinkedObjectKey,
+ transaction_id: $('#linkset_transactions_id').val()
+ }, oOnResponseCallback);
+ };
+
+ /**
+ * CallAjaxDetachLinkedObject.
+ *
+ * @param {string} sLinkedObjectClass
+ * @param {string} sLinkedObjectKey
+ * @param {string} sExternalKeyAttCode
+ * @param oOnResponseCallback
+ * @constructor
+ */
+ const CallAjaxDetachLinkedObject = function(sLinkedObjectClass, sLinkedObjectKey, sExternalKeyAttCode, oOnResponseCallback){
+
+ $.post(`${ROUTER_BASE_URL}?route=${ROUTE_LINK_SET_DETACH_OBJECT}`, {
+ linked_object_class: sLinkedObjectClass,
+ linked_object_key: sLinkedObjectKey,
+ external_key_att_code: sExternalKeyAttCode,
+ transaction_id: $('#linkset_transactions_id').val()
+ }, oOnResponseCallback);
+ };
+
+ /**
+ * CallAjaxCreateLinkedObject.
+ *
+ * @param {string} sClass
+ * @param {string} sAttCode
+ * @param {string} sHostObjectClass
+ * @param {string} sHostObjectId
+ * @param oOnModalCloseCallback
+ * @param oOnFormSubmittedCallback
+ */
+ const CallAjaxCreateLinkedObject = function(sClass, sAttCode, sHostObjectClass, sHostObjectId, oOnModalCloseCallback = null, oOnFormSubmittedCallback = null){
+
+ let oOptions = {
+ title: Dict.S('UI:Links:New:Modal:Title'),
+ content: {
+ endpoint: `${ROUTER_BASE_URL}?route=${ROUTE_LINK_SET_CREATE_OBJECT}`,
+ data: {
+ class: sClass,
+ att_code: sAttCode,
+ host_class: sHostObjectClass,
+ host_id: sHostObjectId
+ }
+ },
+ extra_options: {
+ callback_on_modal_close: oOnModalCloseCallback
+ },
+ }
+
+ const oModal = CombodoModal.OpenModal(oOptions);
+ if(oOnFormSubmittedCallback !== null){
+ oModal.on('itop.form.submitted', 'form', oOnFormSubmittedCallback);
+ }
+ };
+
+ /**
+ * CallGetRemoteObject.
+ *
+ * @param sLinkedObjectClass
+ * @param sLinkedObjectKey
+ * @param sExternalKeyAttCode
+ * @param sRemoteClass
+ * @param oOnResponseCallback
+ * @constructor
+ */
+ const CallGetRemoteObject = function(sLinkedObjectClass, sLinkedObjectKey, sExternalKeyAttCode, sRemoteClass, oOnResponseCallback){
+
+ $.post(`${ROUTER_BASE_URL}?route=${ROUTE_LINK_GET_REMOTE_OBJECT}`, {
+ linked_object_class: sLinkedObjectClass,
+ linked_object_key: sLinkedObjectKey,
+ external_key_att_code: sExternalKeyAttCode,
+ remote_class: sRemoteClass
+ }, oOnResponseCallback);
+ };
+
+ return {
+ DeleteLinkedObject: CallAjaxDeleteLinkedObject,
+ DetachLinkedObject: CallAjaxDetachLinkedObject,
+ CreateLinkedObject: CallAjaxCreateLinkedObject,
+ GetRemoteObject: CallGetRemoteObject
+ }
+};
\ No newline at end of file
diff --git a/js/links/links_view_table_widget.js b/js/links/links_view_table_widget.js
new file mode 100644
index 000000000..576ed395f
--- /dev/null
+++ b/js/links/links_view_table_widget.js
@@ -0,0 +1,116 @@
+$(function()
+{
+ // the widget definition, where "itop" is the namespace,
+ // "links_view_table" the widget name
+ $.widget( "itop.links_view_table",
+ {
+
+ // default options
+ options:
+ {
+ link_class: null,
+ external_key_to_me: null
+ },
+
+ // the constructor
+ _create: function () {
+ $Table = $('table', this.element);
+ this.$tableSettingsDialog = $('#datatable_dlg_' + $Table.attr('id'));
+ },
+
+ // the destructor
+ _destroy: function () {
+ },
+
+ /**
+ * DeleteLinkedObject.
+ *
+ * @param sLinkedObjectKey
+ * @param oTrElement
+ * @constructor
+ */
+ DeleteLinkedObject: function (sLinkedObjectKey, oTrElement) {
+
+ const me = this;
+
+ // link object deletion
+ CombodoLinkSetWorker.DeleteLinkedObject(this.options.link_class, sLinkedObjectKey, function (data) {
+ if (data.data.success === true) {
+ oTrElement.remove();
+ } else {
+ CombodoModal.OpenInformativeModal(data.data.error_message, 'error');
+ }
+ });
+ },
+
+ /**
+ * DetachLinkedObject.
+ *
+ * @param sLinkedObjectKey
+ * @param oTrElement
+ * @constructor
+ */
+ DetachLinkedObject: function (sLinkedObjectKey, oTrElement) {
+
+ const me = this;
+
+ // link object unlink
+ CombodoLinkSetWorker.DetachLinkedObject(this.options.link_class, sLinkedObjectKey, this.options.external_key_to_me, function (data) {
+ if (data.data.success === true) {
+ oTrElement.remove();
+ } else {
+ CombodoModal.OpenInformativeModal(data.data.error_message, 'error');
+ }
+ });
+ },
+
+ /**
+ * CreateLinkedObject.
+ *
+ */
+ CreateLinkedObject: function () {
+
+ const me = this;
+
+ // retrieve table
+ const $Table = $('table', this.element);
+
+ // retrieve context parameters
+ const sClass = $Table.closest('[data-role="ibo-block-links-table"]').attr('data-link-class');
+ const sAttCode = $Table.closest('[data-role="ibo-block-links-table"]').attr('data-link-attcode');
+ const sHostObjectClass = $Table.closest('[data-role="ibo-object-details"]').attr('data-object-class');
+ const sHostObjectId = $Table.closest('[data-role="ibo-object-details"]').attr('data-object-id');
+
+ // link object creation
+ CombodoLinkSetWorker.CreateLinkedObject(sClass, sAttCode, sHostObjectClass, sHostObjectId, function(){
+ $(this).find("form").remove();
+ $(this).dialog('destroy');
+ },function (event, data) {
+ if(data.success){
+ me.$tableSettingsDialog.DataTableSettings('DoRefresh');
+ }
+ });
+ },
+
+ /**
+ * ModifyLinkedObject.
+ *
+ * @param {string} sLinkedObjectKey
+ */
+ ModifyLinkedObject: function (sLinkedObjectKey) {
+
+ const me = this;
+
+ // link object modification
+ ObjectWorker.ModifyObject(this.options.link_class, sLinkedObjectKey, function () {
+ $(this).find("form").remove();
+ $(this).dialog('destroy');
+ }, function(event, data){
+ if(data.success) {
+ me.$tableSettingsDialog.DataTableSettings('DoRefresh');
+ }
+ });
+ },
+
+ });
+});
\ No newline at end of file
diff --git a/js/linkswidget.js b/js/links/links_widget.js
similarity index 100%
rename from js/linkswidget.js
rename to js/links/links_widget.js
diff --git a/js/objects/objects_worker.js b/js/objects/objects_worker.js
new file mode 100644
index 000000000..216562ef7
--- /dev/null
+++ b/js/objects/objects_worker.js
@@ -0,0 +1,60 @@
+let ObjectWorker = new function(){
+
+ // defines
+ const ROUTER_BASE_URL = '../pages/ajax.render.php';
+ const ROUTE_MODIFY_OBJECT = 'object.modify';
+ const ROUTE_GET_OBJECT = 'object.get';
+
+ /**
+ * CallAjaxModifyObject.
+ *
+ * @param {string} sObjectClass
+ * @param {string} sObjectKey
+ * @param oOnModalCloseCallback
+ * @param oOnFormSubmittedCallback
+ * @constructor
+ */
+ const CallAjaxModifyObject = function(sObjectClass, sObjectKey, oOnModalCloseCallback, oOnFormSubmittedCallback){
+
+ let oOptions = {
+ title: Dict.S('UI:Links:ActionRow:Modify:Modal:Title'),
+ content: {
+ endpoint: `${ROUTER_BASE_URL}?route=${ROUTE_MODIFY_OBJECT}`,
+ data: {
+ class: sObjectClass,
+ id: sObjectKey,
+ },
+ },
+ extra_options: {
+ callback_on_modal_close: oOnModalCloseCallback
+ },
+ }
+
+ const oModal = CombodoModal.OpenModal(oOptions);
+ if(oOnFormSubmittedCallback !== null){
+ oModal.on('itop.form.submitted', 'form', oOnFormSubmittedCallback);
+ }
+ };
+
+ /**
+ * CallAjaxGetObject.
+ *
+ * @param {string} sObjectClass
+ * @param {string} sObjectKey
+ * @param oOnResponseCallback
+ * @constructor
+ */
+ const CallAjaxGetObject = function(sObjectClass, sObjectId, oOnResponseCallback){
+
+ $.post(`${ROUTER_BASE_URL}?route=${ROUTE_GET_OBJECT}`, {
+ object_class: sObjectClass,
+ object_key: sObjectId,
+ }, oOnResponseCallback);
+ };
+
+
+ return {
+ ModifyObject: CallAjaxModifyObject,
+ GetObject: CallAjaxGetObject
+ }
+};
\ No newline at end of file
diff --git a/js/selectize/plugin_combodo_multi_values_synthesis.js b/js/selectize/plugin_combodo_multi_values_synthesis.js
index 6ffe9d612..7ea5b0cac 100644
--- a/js/selectize/plugin_combodo_multi_values_synthesis.js
+++ b/js/selectize/plugin_combodo_multi_values_synthesis.js
@@ -78,14 +78,14 @@ Selectize.define("combodo_multi_values_synthesis", function (aOptions) {
}
// Element exist in default selection,
// click allow user to switch between add or ignore states
- if(oSelf.settings.initial.includes(sItemValue)) {
+ if(oSelf.plugins.settings.combodo_update_operations.initial.includes(sItemValue)) {
oSelf.listenClick($Item, sItemValue);
}
return;
}
// If no operation to restore
- if(!oSelf.settings.initial.includes(sItemValue)) {
+ if(!oSelf.plugins.settings.combodo_update_operations.initial.includes(sItemValue)) {
// Element doesn't exist in initial value, we mark it as added
oSelf.Add($Item, sItemValue);
@@ -112,7 +112,7 @@ Selectize.define("combodo_multi_values_synthesis", function (aOptions) {
const $Item = oSelf.getItem(sItem);
// Element doesn't exist in default selection,
- if(!oSelf.settings.initial.includes(sItem)) {
+ if(!oSelf.plugins.settings.combodo_update_operations.initial.includes(sItem)) {
// Remove operation
delete aOperations[sItem];
diff --git a/js/selectize/plugin_combodo_update_operations.js b/js/selectize/plugin_combodo_update_operations.js
index a129f3969..51edd8252 100644
--- a/js/selectize/plugin_combodo_update_operations.js
+++ b/js/selectize/plugin_combodo_update_operations.js
@@ -15,11 +15,18 @@
*
* You should have received a copy of the GNU Affero General Public License
*/
-Selectize.define("combodo_update_operations", function () {
+Selectize.define("combodo_update_operations", function (aOptions) {
// Selectize instance
let oSelf = this;
+ // Plugin options
+ aOptions = $.extend({
+ initial: [],
+ },
+ aOptions
+ );
+
// Plugin variables
oSelf.bIsInitialized = false;
oSelf.operations = {};
@@ -88,7 +95,7 @@ Selectize.define("combodo_update_operations", function () {
// Scan items in current value and not in initial value
aCurrentItems.forEach(function(e){
- if(!oSelf.settings.initial.includes(e)){
+ if(!aOptions.initial.includes(e)){
oSelf.operations[e] = {
operation: 'add',
data: CombodoGlobalToolbox.ExtractArrayItemsContainingThisKeyAndValue(aCurrentOptions, oSelf.settings.valueField, e)
@@ -97,7 +104,7 @@ Selectize.define("combodo_update_operations", function () {
});
// scan items in initial value and not in current value
- oSelf.settings.initial.forEach(function(e){
+ aOptions.initial.forEach(function(e){
if(!aCurrentItems.includes(e)){
oSelf.operations[e] = {
operation: 'remove',
@@ -109,4 +116,12 @@ Selectize.define("combodo_update_operations", function () {
};
})();
+ // Declare addInitialValue function
+ oSelf.addInitialValue = (function () {
+ return function (value) {
+ aOptions.initial.push(value);
+ oSelf.updateOperationsInput();
+ };
+ })();
+
});
\ No newline at end of file
diff --git a/lib/composer/installed.php b/lib/composer/installed.php
index a06e2ae12..08f2006c5 100644
--- a/lib/composer/installed.php
+++ b/lib/composer/installed.php
@@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
- 'reference' => '9482139b5aec9978f05b1cbb0542b24c18681819',
+ 'reference' => 'f25f91ad79b38d9dcbe2a175bdb2fd2635255968',
'name' => 'combodo/itop',
'dev' => true,
),
@@ -25,7 +25,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
- 'reference' => '9482139b5aec9978f05b1cbb0542b24c18681819',
+ 'reference' => 'f25f91ad79b38d9dcbe2a175bdb2fd2635255968',
'dev_requirement' => false,
),
'combodo/tcpdf' => array(
diff --git a/pages/UniversalSearch.php b/pages/UniversalSearch.php
index e4649b57e..3b829cc78 100644
--- a/pages/UniversalSearch.php
+++ b/pages/UniversalSearch.php
@@ -34,7 +34,6 @@ $oP->add_linked_script("../js/json.js");
$oP->add_linked_script("../js/forms-json-utils.js");
$oP->add_linked_script("../js/wizardhelper.js");
$oP->add_linked_script("../js/wizard.utils.js");
-$oP->add_linked_script("../js/linkswidget.js");
$oP->add_linked_script("../js/extkeywidget.js");
$oP->add_linked_script("../js/jquery.blockUI.js");
diff --git a/pages/tagadmin.php b/pages/tagadmin.php
index a6a6fede6..8263c2104 100644
--- a/pages/tagadmin.php
+++ b/pages/tagadmin.php
@@ -37,7 +37,6 @@ try
$oP->add_linked_script("../js/forms-json-utils.js");
$oP->add_linked_script("../js/wizardhelper.js");
$oP->add_linked_script("../js/wizard.utils.js");
- $oP->add_linked_script("../js/linkswidget.js");
$oP->add_linked_script("../js/extkeywidget.js");
$oP->add_linked_script("../js/jquery.blockUI.js");
diff --git a/sources/Application/UI/Base/Component/Input/Set/Set.php b/sources/Application/UI/Base/Component/Input/Set/Set.php
index 058873562..fbad58c5d 100644
--- a/sources/Application/UI/Base/Component/Input/Set/Set.php
+++ b/sources/Application/UI/Base/Component/Input/Set/Set.php
@@ -37,6 +37,7 @@ class Set extends AbstractInput
public const DEFAULT_JS_ON_READY_TEMPLATE_REL_PATH = 'base/components/input/set/layout';
public const DEFAULT_JS_FILES_REL_PATH = [
+ 'js/links/links_set_worker.js',
'js/selectize/plugin_combodo_add_button.js',
'js/selectize/plugin_combodo_auto_position.js',
'js/selectize/plugin_combodo_update_operations.js',
@@ -55,6 +56,9 @@ class Set extends AbstractInput
/** @var bool $bHasAddOptionButton Enable add option button */
private bool $bHasAddOptionButton;
+ /** @var string|null $sAddOptionButtonJsOnClick JS code to execute on button click */
+ private ?string $sAddOptionButtonJsOnClick;
+
/** @var string $sAddButtonTitle Add button title */
private string $sAddButtonTitle;
@@ -103,6 +107,7 @@ class Set extends AbstractInput
$this->iMaxOptions = null;
$this->bHasRemoveItemButton = true;
$this->bHasAddOptionButton = false;
+ $this->sAddOptionButtonJsOnClick = null;
$this->sAddButtonTitle = Dict::S('UI:Button:Create');
$this->bIsPreloadEnabled = false;
$this->sTemplateOptions = null;
@@ -183,6 +188,30 @@ class Set extends AbstractInput
return $this->bHasRemoveItemButton;
}
+ /**
+ * SetAddOptionButtonJsOnClick.
+ *
+ * @param string $sJsOnClick
+ *
+ * @return $this
+ */
+ public function SetAddOptionButtonJsOnClick(string $sJsOnClick): Set
+ {
+ $this->sAddOptionButtonJsOnClick = $sJsOnClick;
+
+ return $this;
+ }
+
+ /**
+ * GetAddOptionButtonJsOnClick.
+ *
+ * @return string
+ */
+ public function GetAddOptionButtonJsOnClick(): string
+ {
+ return $this->sAddOptionButtonJsOnClick;
+ }
+
/**
* SetHasAddOptionButton.
*
diff --git a/sources/Application/UI/Links/AbstractBlockLinksViewTable.php b/sources/Application/UI/Links/AbstractBlockLinksViewTable.php
index d8b4da691..459e56272 100644
--- a/sources/Application/UI/Links/AbstractBlockLinksViewTable.php
+++ b/sources/Application/UI/Links/AbstractBlockLinksViewTable.php
@@ -32,10 +32,12 @@ use WebPage;
abstract class AbstractBlockLinksViewTable extends UIContentBlock
{
// Overloaded constants
- public const BLOCK_CODE = 'ibo-abstract-block-links-view-table';
- public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/layout';
- public const DEFAULT_JS_FILES_REL_PATH = [
- 'js/links/link_set_worker.js',
+ public const BLOCK_CODE = 'ibo-abstract-block-links-view-table';
+ public const DEFAULT_JS_ON_READY_TEMPLATE_REL_PATH = 'application/links/layout';
+ public const DEFAULT_JS_FILES_REL_PATH = [
+ 'js/links/links_view_table_widget.js',
+ 'js/links/links_set_worker.js',
+ 'js/objects/objects_worker.js',
'js/wizardhelper.js',
];
@@ -70,7 +72,7 @@ abstract class AbstractBlockLinksViewTable extends UIContentBlock
*/
public function __construct(WebPage $oPage, DBObject $oDbObject, string $sObjectClass, string $sAttCode, AttributeLinkedSet $oAttDef)
{
- parent::__construct('', ["ibo-block-links-table"]);
+ parent::__construct("links_view_table_$sAttCode", ["ibo-block-links-table"]);
// retrieve parameters
$this->oAttDef = $oAttDef;
@@ -204,6 +206,8 @@ abstract class AbstractBlockLinksViewTable extends UIContentBlock
/**
+ * GetAttCode.
+ *
* @return string
*/
public function GetAttCode(): string
@@ -211,4 +215,33 @@ abstract class AbstractBlockLinksViewTable extends UIContentBlock
return $this->sAttCode;
}
+ /**
+ * GetLinkedClass.
+ *
+ * @return mixed
+ */
+ public function GetLinkedClass()
+ {
+ return $this->oAttDef->GetLinkedClass();
+ }
+
+ /**
+ * GetExternalKeyToMe.
+ *
+ * @return mixed
+ */
+ public function GetExternalKeyToMe()
+ {
+ return $this->oAttDef->GetExtKeyToMe();
+ }
+
+ /**
+ * GetWidgetName.
+ *
+ * @return string
+ */
+ public function GetWidgetName(): string
+ {
+ return "oWidget{$this->GetId()}";
+ }
}
\ No newline at end of file
diff --git a/sources/Application/UI/Links/Direct/BlockDirectLinksEditTable.php b/sources/Application/UI/Links/Direct/BlockDirectLinksEditTable.php
index da8ae25d8..f99e289aa 100644
--- a/sources/Application/UI/Links/Direct/BlockDirectLinksEditTable.php
+++ b/sources/Application/UI/Links/Direct/BlockDirectLinksEditTable.php
@@ -6,18 +6,28 @@
namespace Combodo\iTop\Application\UI\Links\Direct;
+use ApplicationContext;
+use ArchivedObjectException;
+use AttributeLinkedSet;
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\Component\Html\Html;
-use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
+use Combodo\iTop\Application\UI\Base\Component\Toolbar\Toolbar;
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
+use ConfigException;
+use CoreException;
+use CoreUnexpectedValue;
+use DBObjectSet;
use Dict;
+use DictExceptionMissingString;
+use Exception;
use MetaModel;
+use MySQLException;
+use UILinksWidgetDirect;
use utils;
+use WebPage;
/**
* Class BlockDirectLinksEditTable
@@ -31,40 +41,43 @@ class BlockDirectLinksEditTable extends UIContentBlock
// Overloaded constants
public const BLOCK_CODE = 'ibo-block-direct-links-edit-table';
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/direct/block-direct-links-edit-table/layout';
+ public const DEFAULT_JS_FILES_REL_PATH = [
+ 'js/links/links_direct_widget.js',
+ ];
- /** @var \UILinksWidgetDirect */
- public \UILinksWidgetDirect $oUILinksDirectWidget;
+ /** @var UILinksWidgetDirect $oUILinksDirectWidget */
+ public UILinksWidgetDirect $oUILinksDirectWidget;
- /** @var \AttributeLinkedSet */
- private \AttributeLinkedSet $oAttributeLinkedSet;
+ /** @var AttributeLinkedSet $oAttributeLinkedSet */
+ private AttributeLinkedSet $oAttributeLinkedSet;
- /** @var string */
+ /** @var string $sInputName */
public string $sInputName;
- /** @var array */
+ /** @var array $aLabels */
public array $aLabels;
- /** @var string */
+ /** @var string $sSubmitUrl */
public string $sSubmitUrl;
- /** @var string */
+ /** @var string $sWizHelper */
public string $sWizHelper;
- /** @var string */
+ /** @var string $sJSDoSearch */
public string $sJSDoSearch;
/**
* Constructor.
*
- * @param \UILinksWidgetDirect $oUILinksDirectWidget
+ * @param UILinksWidgetDirect $oUILinksDirectWidget
* @param string $sId
*
- * @throws \ConfigException
- * @throws \CoreException
- * @throws \DictExceptionMissingString
- * @throws \Exception
+ * @throws ConfigException
+ * @throws CoreException
+ * @throws DictExceptionMissingString
+ * @throws Exception
*/
- public function __construct(\UILinksWidgetDirect $oUILinksDirectWidget, string $sId)
+ public function __construct(UILinksWidgetDirect $oUILinksDirectWidget, string $sId)
{
parent::__construct($sId, ["ibo-block-direct-links--edit-in-place"]);
@@ -73,18 +86,14 @@ class BlockDirectLinksEditTable extends UIContentBlock
// compute
$this->aLabels = array(
- 'delete' => Dict::S('UI:Button:Delete'),
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
- 'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
- 'remove' => Dict::S('UI:Button:Remove'),
- 'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->oUILinksDirectWidget->GetLinkedClass())),
);
- $oContext = new \ApplicationContext();
- $this->sSubmitUrl = \utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
+ $oContext = new ApplicationContext();
+ $this->sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
// Don't automatically launch the search if the table is huge
- $bDoSearch = !\utils::IsHighCardinality($this->oUILinksDirectWidget->GetLinkedClass());
+ $bDoSearch = !utils::IsHighCardinality($this->oUILinksDirectWidget->GetLinkedClass());
$this->sJSDoSearch = $bDoSearch ? 'true' : 'false';
// Initialization
@@ -98,7 +107,7 @@ class BlockDirectLinksEditTable extends UIContentBlock
* Initialisation.
*
* @return void
- * @throws \Exception
+ * @throws Exception
*/
private function Init()
{
@@ -109,8 +118,8 @@ class BlockDirectLinksEditTable extends UIContentBlock
* Initialize UI.
*
* @return void
- * @throws \CoreException
- * @throws \Exception
+ * @throws CoreException
+ * @throws Exception
*/
private function InitUI()
{
@@ -118,15 +127,14 @@ class BlockDirectLinksEditTable extends UIContentBlock
}
/**
- * @param \WebPage $oPage
- * @param \DBObjectSet $oValue
+ * @param WebPage $oPage
+ * @param DBObjectSet $oValue
* @param string $sFormPrefix
*
* @return void
*/
- public function InitTable(\WebPage $oPage, $oValue, string $sFormPrefix)
+ public function InitTable(WebPage $oPage, DBObjectSet $oValue, string $sFormPrefix)
{
- /** @todo fields initialization */
$this->sInputName = $sFormPrefix.'attr_'.$this->oUILinksDirectWidget->GetAttCode();
$this->sWizHelper = 'oWizardHelper'.$sFormPrefix;
@@ -138,7 +146,7 @@ class BlockDirectLinksEditTable extends UIContentBlock
$oDatatable->SetOptions(['select_mode' => 'custom', 'disable_hyperlinks' => true]);
// Panel
- $aTablePanel = PanelUIBlockFactory::MakeForClass($this->oUILinksDirectWidget->GetLinkedClass(), $this->oAttributeLinkedSet->GetLabel())
+ $oTablePanel = PanelUIBlockFactory::MakeForClass($this->oUILinksDirectWidget->GetLinkedClass(), $this->oAttributeLinkedSet->GetLabel())
->SetSubTitle(Dict::Format('UI:Pagination:HeaderNoSelection', count($aRows)))
->SetIcon(MetaModel::GetClassIcon($this->oUILinksDirectWidget->GetLinkedClass(), false))
->AddCSSClass('ibo-datatable-panel');
@@ -146,30 +154,17 @@ class BlockDirectLinksEditTable extends UIContentBlock
// - Panel description
$sDescription = $this->oAttributeLinkedSet->GetDescription();
if (utils::IsNotNullOrEmptyString($sDescription)) {
- $oTitleBlock = $aTablePanel->GetTitleBlock()
+ $oTitleBlock = $oTablePanel->GetTitleBlock()
->AddDataAttribute('tooltip-content', $sDescription)
->AddDataAttribute('tooltip-max-width', 'min(600px, 90vw)') // Allow big description to be wide enough while shrinking on small screens
->AddCSSClass('ibo-has-description');
}
// Toolbar and actions
- $oToolbar = ToolbarUIBlockFactory::MakeForButton();
- $oActionButtonUnlink = ButtonUIBlockFactory::MakeNeutral('Unlink');
- $oActionButtonUnlink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._removeSelection();");
- $oToolbar->AddSubBlock($oActionButtonUnlink);
- $oActionButtonLink = ButtonUIBlockFactory::MakeNeutral('Link');
- $oActionButtonLink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._selectToAdd();");
- $oToolbar->AddSubBlock($oActionButtonLink);
- $oActionButtonCreate = ButtonUIBlockFactory::MakeNeutral('Create');
- $oActionButtonCreate->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._createRow();");
- $oToolbar->AddSubBlock($oActionButtonCreate);
- $oActionButtonDelete = ButtonUIBlockFactory::MakeNeutral('Delete');
- $oActionButtonDelete->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('instance')._deleteSelection();");
-
- $oToolbar->AddSubBlock($oActionButtonDelete);
- $aTablePanel->AddToolbarBlock($oToolbar);
- $aTablePanel->AddSubBlock($oDatatable);
- $this->AddSubBlock($aTablePanel);
+ $oToolbar = $this->InitToolBar();
+ $oTablePanel->AddToolbarBlock($oToolbar);
+ $oTablePanel->AddSubBlock($oDatatable);
+ $this->AddSubBlock($oTablePanel);
}
catch (\Exception $e) {
$oAlert = AlertUIBlockFactory::MakeForDanger('error', Dict::S('UI:Datatables:Language:Error'));
@@ -179,18 +174,70 @@ class BlockDirectLinksEditTable extends UIContentBlock
}
}
+ /**
+ * InitToolBar.
+ *
+ * @return \Combodo\iTop\Application\UI\Base\Component\Toolbar\Toolbar
+ */
+ private function InitToolBar(): Toolbar
+ {
+ $oToolbar = ToolbarUIBlockFactory::MakeForButton();
+
+ // until a full link set refactoring (continue using edit_mode property)
+ switch ($this->oAttributeLinkedSet->GetEditMode()) {
+ case LINKSET_EDITMODE_NONE: // The linkset is read-only
+ break;
+
+ case LINKSET_EDITMODE_ADDONLY: // The only possible action is to open (in a new window) the form to create a new object
+ $oActionButtonLink = ButtonUIBlockFactory::MakeNeutral('Link', 'link');
+ $oActionButtonLink->AddDataAttribute('action', 'add');
+ $oActionButtonLink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('selectToAdd');");
+ $oToolbar->AddSubBlock($oActionButtonLink);
+ break;
+
+ case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
+ $oActionButtonCreate = ButtonUIBlockFactory::MakeNeutral('Create', 'create');
+ $oActionButtonCreate->AddDataAttribute('action', 'create');
+ $oActionButtonCreate->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('createRow');");
+ $oToolbar->AddSubBlock($oActionButtonCreate);
+ $oActionButtonDelete = ButtonUIBlockFactory::MakeNeutral('Delete', 'delete');
+ $oActionButtonDelete->AddDataAttribute('action', 'delete');
+ $oActionButtonDelete->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('deleteSelection');");
+ $oToolbar->AddSubBlock($oActionButtonDelete);
+ break;
+
+ case LINKSET_EDITMODE_ADDREMOVE: // The whole linkset can be edited 'in-place'
+ $oActionButtonUnlink = ButtonUIBlockFactory::MakeNeutral('Unlink', 'unlink');
+ $oActionButtonUnlink->AddDataAttribute('action', 'detach');
+ $oActionButtonUnlink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('removeSelection');");
+ $oToolbar->AddSubBlock($oActionButtonUnlink);
+ $oActionButtonLink = ButtonUIBlockFactory::MakeNeutral('Link', 'link');
+ $oActionButtonLink->AddDataAttribute('action', 'add');
+ $oActionButtonLink->SetOnClickJsCode("$('#{$this->oUILinksDirectWidget->GetInputId()}').directlinks('selectToAdd');");
+ $oToolbar->AddSubBlock($oActionButtonLink);
+ break;
+
+ case LINKSET_EDITMODE_ACTIONS: // Show the usual 'Actions' popup menu
+ default:
+
+ }
+
+ return $oToolbar;
+ }
+
+
/**
* Return table rows.
*
- * @param \DBObjectSet $oValue
+ * @param DBObjectSet $oValue
*
* @return array
- * @throws \ArchivedObjectException
- * @throws \CoreException
- * @throws \CoreUnexpectedValue
- * @throws \DictExceptionMissingString
- * @throws \MySQLException
- * @throws \Exception
+ * @throws ArchivedObjectException
+ * @throws CoreException
+ * @throws CoreUnexpectedValue
+ * @throws DictExceptionMissingString
+ * @throws MySQLException
+ * @throws Exception
*/
private function GetTableRows(\WebPage $oPage, \DBObjectSet $oValue): array
{
@@ -220,6 +267,41 @@ class BlockDirectLinksEditTable extends UIContentBlock
return ($bSafe) ? \utils::GetSafeId($sFieldId) : $sFieldId;
}
+ /**
+ * Convert edit_mode to relation type.
+ *
+ * @return string|null
+ */
+ private function ConvertEditModeToRelationType(): ?string
+ {
+ switch ($this->oAttributeLinkedSet->GetEditMode()) {
+ case LINKSET_EDITMODE_INPLACE:
+ return LINKSET_RELATIONTYPE_PROPERTY;
+ case LINKSET_EDITMODE_ADDREMOVE:
+ return LINKSET_RELATIONTYPE_LINK;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Convert edit_mode to read only.
+ *
+ * @return bool
+ */
+ private function ConvertEditModeToReadOnly(): bool
+ {
+ switch ($this->oAttributeLinkedSet->GetEditMode()) {
+ case LINKSET_EDITMODE_NONE:
+ case LINKSET_EDITMODE_ADDONLY:
+ case LINKSET_EDITMODE_ACTIONS:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
/**
* Return row actions.
*
@@ -229,9 +311,9 @@ class BlockDirectLinksEditTable extends UIContentBlock
{
$aRowActions = array();
- if (!$this->oAttributeLinkedSet->GetReadOnly()) {
+ if (!$this->ConvertEditModeToReadOnly()) {
- switch ($this->oAttributeLinkedSet->GetRelationType()) {
+ switch ($this->ConvertEditModeToRelationType()) {
case LINKSET_RELATIONTYPE_LINK:
$aRowActions[] = array(
diff --git a/sources/Application/UI/Links/Direct/BlockDirectLinksViewTable.php b/sources/Application/UI/Links/Direct/BlockDirectLinksViewTable.php
index 52c5c7554..fc180eb78 100644
--- a/sources/Application/UI/Links/Direct/BlockDirectLinksViewTable.php
+++ b/sources/Application/UI/Links/Direct/BlockDirectLinksViewTable.php
@@ -37,9 +37,9 @@ class BlockDirectLinksViewTable extends AbstractBlockLinksViewTable
'default' => $this->GetDefault(),
'table_id' => $this->GetTableId(),
'row_actions' => $this->GetRowActions(),
- 'currentId' => $this->GetTableId(),
+ 'currentId' => $this->GetTableId(),
'panel_title' => $this->oAttDef->GetLabel(),
- 'panel_icon' => MetaModel::GetClassIcon($this->GetTargetClass(), false),
+ 'panel_icon' => MetaModel::GetClassIcon($this->GetTargetClass(), false),
);
// Description
@@ -50,9 +50,9 @@ class BlockDirectLinksViewTable extends AbstractBlockLinksViewTable
// Add creation in modal if the linkset is not readonly
if (!$this->oAttDef->GetReadOnly()) {
$aExtraParams['creation_in_modal_is_allowed'] = true;
- $aExtraParams['creation_in_modal_js_handler'] = 'LinkSetWorker.CreateLinkedObject("'.$this->GetTableId().'");';
+ $aExtraParams['creation_in_modal_js_handler'] = "{$this->GetWidgetName()}.links_view_table('CreateLinkedObject');";
}
-
+
return $aExtraParams;
}
@@ -70,7 +70,7 @@ class BlockDirectLinksViewTable extends AbstractBlockLinksViewTable
'label' => 'UI:Links:ActionRow:Detach',
'tooltip' => 'UI:Links:ActionRow:Detach+',
'icon_classes' => 'fas fa-minus',
- 'js_row_action' => "LinkSetWorker.DetachLinkedObject('{$this->sTargetClass}', aRowData['{$this->sTargetClass}/_key_/raw'], '{$this->oAttDef->GetExtKeyToMe()}', '{$this->GetTableId()}');",
+ 'js_row_action' => "{$this->GetWidgetName()}.links_view_table('DetachLinkedObject', aRowData['{$this->sTargetClass}/_key_/raw'], oTrElement);",
'confirmation' => [
'message' => 'UI:Links:ActionRow:Detach:Confirmation',
'message_row_data' => "{$this->sTargetClass}/hyperlink",
@@ -84,7 +84,7 @@ class BlockDirectLinksViewTable extends AbstractBlockLinksViewTable
'label' => 'UI:Links:ActionRow:Delete',
'tooltip' => 'UI:Links:ActionRow:Delete+',
'icon_classes' => 'fas fa-trash',
- 'js_row_action' => "LinkSetWorker.DeleteLinkedObject('{$this->oAttDef->GetLinkedClass()}', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw'], '{$this->GetTableId()}');",
+ 'js_row_action' => "{$this->GetWidgetName()}.links_view_table('DeleteLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw'], oTrElement);",
'confirmation' => [
'message' => 'UI:Links:ActionRow:Delete:Confirmation',
'message_row_data' => "{$this->sTargetClass}/hyperlink",
@@ -97,7 +97,7 @@ class BlockDirectLinksViewTable extends AbstractBlockLinksViewTable
'label' => 'UI:Links:ActionRow:Modify',
'tooltip' => 'UI:Links:ActionRow:Modify+',
'icon_classes' => 'fas fa-pen',
- 'js_row_action' => "LinkSetWorker.ModifyLinkedObject('{$this->sTargetClass}', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw'], '{$this->GetTableId()}');",
+ 'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw']);",
);
}
diff --git a/sources/Application/UI/Links/Indirect/BlockIndirectLinksEditTable.php b/sources/Application/UI/Links/Indirect/BlockIndirectLinksEditTable.php
index d512abe7a..b53a81e2c 100644
--- a/sources/Application/UI/Links/Indirect/BlockIndirectLinksEditTable.php
+++ b/sources/Application/UI/Links/Indirect/BlockIndirectLinksEditTable.php
@@ -6,19 +6,23 @@
namespace Combodo\iTop\Application\UI\Links\Indirect;
+use AttributeLinkedSetIndirect;
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
-use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
+use ConfigException;
+use CoreException;
+use DBObject;
+use Exception;
use Dict;
use MetaModel;
+use UILinksWidget;
use utils;
+use WebPage;
/**
* Class BlockIndirectLinksEditTable
@@ -32,12 +36,15 @@ class BlockIndirectLinksEditTable extends UIContentBlock
// Overloaded constants
public const BLOCK_CODE = 'ibo-block-indirect-links-edit-table';
public const DEFAULT_JS_TEMPLATE_REL_PATH = 'application/links/indirect/block-indirect-links-edit-table/layout';
+ public const DEFAULT_JS_FILES_REL_PATH = [
+ 'js/links/links_widget.js',
+ ];
- /** @var \UILinksWidget */
- public \UILinksWidget $oUILinksWidget;
+ /** @var UILinksWidget $oUILinksWidget */
+ public UILinksWidget $oUILinksWidget;
- /** @var \AttributeLinkedSetIndirect */
- private \AttributeLinkedSetIndirect $oAttributeLinkedSetIndirect;
+ /** @var AttributeLinkedSetIndirect $oAttributeLinkedSetIndirect */
+ private AttributeLinkedSetIndirect $oAttributeLinkedSetIndirect;
/** @var string */
public string $sDuplicates;
@@ -60,13 +67,13 @@ class BlockIndirectLinksEditTable extends UIContentBlock
/**
* Constructor.
*
- * @param \UILinksWidget $oUILinksWidget
+ * @param UILinksWidget $oUILinksWidget
*
- * @throws \ConfigException
- * @throws \CoreException
- * @throws \Exception
+ * @throws ConfigException
+ * @throws CoreException
+ * @throws Exception
*/
- public function __construct(\UILinksWidget $oUILinksWidget)
+ public function __construct(UILinksWidget $oUILinksWidget)
{
parent::__construct("linkedset_{$oUILinksWidget->GetLinkedSetId()}", ["ibo-block-indirect-links--edit"]);
@@ -88,7 +95,7 @@ class BlockIndirectLinksEditTable extends UIContentBlock
* Initialization.
*
* @return void
- * @throws \Exception
+ * @throws Exception
*/
private function Init()
{
@@ -99,8 +106,8 @@ class BlockIndirectLinksEditTable extends UIContentBlock
* Initialize UI.
*
* @return void
- * @throws \CoreException
- * @throws \Exception
+ * @throws CoreException
+ * @throws Exception
*/
private function InitUI()
{
@@ -109,37 +116,6 @@ class BlockIndirectLinksEditTable extends UIContentBlock
$this->AddDeferredBlock($oDeferredBlock);
}
- /**
- * CreateTableInformationAlert.
- *
- * @return iUIBlock
- */
- private function CreateTableInformationAlert(): iUIBlock
- {
- // Selection alert
- $oAlert = AlertUIBlockFactory::MakeNeutral('', '', "linkedset_{$this->oUILinksWidget->GetInputId()}_alert_information");
- $oAlert->AddCSSClasses([
- 'ibo-table--alert-information',
- ]);
- $oAlert->SetIsClosable(false);
- $oAlert->SetIsCollapsible(false);
- $oAlert->AddSubBlock(new Html(''));
-
- // Delete button
- $oUIButton = ButtonUIBlockFactory::MakeForDestructiveAction("Détacher les {$this->oUILinksWidget->GetRemoteClass()}", 'table-selection');
- $oUIButton->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.RemoveSelected();");
- $oUIButton->AddCSSClass('ibo-table--alert-information--delete-button');
- $oAlert->AddSubBlock($oUIButton);
-
- // Add button
- $oUIAddButton = ButtonUIBlockFactory::MakeForPrimaryAction("Attacher des {$this->oUILinksWidget->GetRemoteClass()}", 'table-selection');
- $oUIAddButton->AddCSSClass('ibo-table--alert-information--add-button');
- $oUIAddButton->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.AddObjects();");
- $oAlert->AddSubBlock($oUIAddButton);
-
- return $oAlert;
- }
-
/**
* @param \WebPage $oPage
* @param $oValue
@@ -149,6 +125,9 @@ class BlockIndirectLinksEditTable extends UIContentBlock
* @param $aTableConfig
*
* @return void
+ * @throws \ArchivedObjectException
+ * @throws \CoreException
+ * @throws \CoreUnexpectedValue
*/
public function InitTable(\WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aTableConfig)
{
@@ -192,7 +171,7 @@ class BlockIndirectLinksEditTable extends UIContentBlock
]);
// Panel
- $aTablePanel = PanelUIBlockFactory::MakeForClass($this->oUILinksWidget->GetRemoteClass(), $this->oAttributeLinkedSetIndirect->GetLabel())
+ $oTablePanel = PanelUIBlockFactory::MakeForClass($this->oUILinksWidget->GetRemoteClass(), $this->oAttributeLinkedSetIndirect->GetLabel())
->SetSubTitle(Dict::Format('UI:Pagination:HeaderNoSelection', count($aForm)))
->SetIcon(MetaModel::GetClassIcon($this->oUILinksWidget->GetRemoteClass(), false))
->AddCSSClass('ibo-datatable-panel');
@@ -200,7 +179,7 @@ class BlockIndirectLinksEditTable extends UIContentBlock
// - Panel description
$sDescription = $this->oAttributeLinkedSetIndirect->GetDescription();
if (utils::IsNotNullOrEmptyString($sDescription)) {
- $oTitleBlock = $aTablePanel->GetTitleBlock()
+ $oTitleBlock = $oTablePanel->GetTitleBlock()
->AddDataAttribute('tooltip-content', $sDescription)
->AddDataAttribute('tooltip-max-width', 'min(600px, 90vw)') // Allow big description to be wide enough while shrinking on small screens
->AddCSSClass('ibo-has-description');
@@ -214,10 +193,10 @@ class BlockIndirectLinksEditTable extends UIContentBlock
$oActionButtonLink = ButtonUIBlockFactory::MakeNeutral('Link');
$oActionButtonLink->SetOnClickJsCode("oWidget{$this->oUILinksWidget->GetInputId()}.AddObjects();");
$oToolbar->AddSubBlock($oActionButtonLink);
- $aTablePanel->AddToolbarBlock($oToolbar);
- $aTablePanel->AddSubBlock($oDataTable);
+ $oTablePanel->AddToolbarBlock($oToolbar);
+ $oTablePanel->AddSubBlock($oDataTable);
- $this->AddSubBlock($aTablePanel);
+ $this->AddSubBlock($oTablePanel);
$this->AddSubBlock(InputUIBlockFactory::MakeForHidden("{$sFormPrefix}{$this->oUILinksWidget->GetInputId()}", '', "{$sFormPrefix}{$this->oUILinksWidget->GetInputId()}"));
}
@@ -238,7 +217,7 @@ class BlockIndirectLinksEditTable extends UIContentBlock
* @throws \CoreUnexpectedValue
* @throws \Exception
*/
- public function GetFormRow(\WebPage $oP, \DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false)
+ public function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false)
{
$sPrefix = "{$this->oUILinksWidget->GetAttCode()}{$this->oUILinksWidget->GetNameSuffix()}";
$aRow = array();
diff --git a/sources/Application/UI/Links/Indirect/BlockIndirectLinksViewTable.php b/sources/Application/UI/Links/Indirect/BlockIndirectLinksViewTable.php
index f7e2848d4..1b0db3de0 100644
--- a/sources/Application/UI/Links/Indirect/BlockIndirectLinksViewTable.php
+++ b/sources/Application/UI/Links/Indirect/BlockIndirectLinksViewTable.php
@@ -58,11 +58,12 @@ class BlockIndirectLinksViewTable extends AbstractBlockLinksViewTable
if ($this->oAttDef->HasDescription()) {
$aExtraParams['panel_title_tooltip'] = $this->oAttDef->GetDescription();
}
-
+
// Add creation in modal if the linkset is not readonly
if (!$this->oAttDef->GetReadOnly()) {
+ $sHostClass = get_class($this->oDbObject);
$aExtraParams['creation_in_modal_is_allowed'] = true;
- $aExtraParams['creation_in_modal_js_handler'] = 'LinkSetWorker.CreateLinkedObject("'.$this->GetTableId().'");';
+ $aExtraParams['creation_in_modal_js_handler'] = "{$this->GetWidgetName()}.links_view_table('CreateLinkedObject');";
}
return $aExtraParams;
@@ -79,7 +80,7 @@ class BlockIndirectLinksViewTable extends AbstractBlockLinksViewTable
'label' => 'UI:Links:ActionRow:Detach',
'tooltip' => 'UI:Links:ActionRow:Detach+',
'icon_classes' => 'fas fa-minus',
- 'js_row_action' => "LinkSetWorker.DeleteLinkedObject('{$this->oAttDef->GetLinkedClass()}', aRowData['Link/_key_/raw'], '{$this->GetTableId()}');",
+ 'js_row_action' => "{$this->GetWidgetName()}.links_view_table('DeleteLinkedObject', aRowData['Link/_key_/raw'], oTrElement);",
'confirmation' => [
'message' => 'UI:Links:ActionRow:Detach:Confirmation',
'message_row_data' => "Remote/hyperlink",
@@ -91,7 +92,7 @@ class BlockIndirectLinksViewTable extends AbstractBlockLinksViewTable
'label' => 'UI:Links:ActionRow:Modify',
'tooltip' => 'UI:Links:ActionRow:Modify+',
'icon_classes' => 'fas fa-pen',
- 'js_row_action' => "LinkSetWorker.ModifyLinkedObject('{$this->oAttDef->GetLinkedClass()}', aRowData['Link/_key_/raw'], '{$this->GetTableId()}');",
+ 'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['Link/_key_/raw']);",
);
}
diff --git a/sources/Application/UI/Links/Set/LinksSetUIBlockFactory.php b/sources/Application/UI/Links/Set/LinksSetUIBlockFactory.php
index dd1f284f0..fce739900 100644
--- a/sources/Application/UI/Links/Set/LinksSetUIBlockFactory.php
+++ b/sources/Application/UI/Links/Set/LinksSetUIBlockFactory.php
@@ -26,6 +26,7 @@ use Combodo\iTop\Service\Links\LinksBulkDataPostProcessor;
use Combodo\iTop\Service\Links\LinkSetDataTransformer;
use Combodo\iTop\Service\Links\LinkSetModel;
use Combodo\iTop\Service\Links\LinkSetRepository;
+use DBObject;
use iDBObjectSetIterator;
/**
@@ -46,10 +47,11 @@ class LinksSetUIBlockFactory extends SetUIBlockFactory
* @param AttributeLinkedSet $oAttDef Link set attribute definition
* @param iDBObjectSetIterator $oDbObjectSet Link set value
* @param string $sWizardHelperJsVarName Wizard helper name
+ * @param DBObject|null $oHostDbObject Host DB object
*
* @return \Combodo\iTop\Application\UI\Base\Component\Input\Set\Set
*/
- public static function MakeForLinkSet(string $sId, AttributeLinkedSet $oAttDef, iDBObjectSetIterator $oDbObjectSet, string $sWizardHelperJsVarName): Set
+ public static function MakeForLinkSet(string $sId, AttributeLinkedSet $oAttDef, iDBObjectSetIterator $oDbObjectSet, string $sWizardHelperJsVarName, DBObject $oHostDbObject = null): Set
{
$sTargetClass = LinkSetModel::GetTargetClass($oAttDef);
$sTargetField = LinkSetModel::GetTargetField($oAttDef);
@@ -57,6 +59,16 @@ class LinksSetUIBlockFactory extends SetUIBlockFactory
// Set UI block for OQL
$oSetUIBlock = SetUIBlockFactory::MakeForOQL($sId, $sTargetClass, $oAttDef->GetValuesDef()->GetFilterExpression(), $sWizardHelperJsVarName);
+ $oSetUIBlock->AddJsFileRelPath('js/links/links_set.js');
+
+ // Add button behaviour
+ if (in_array($oAttDef->GetEditMode(), [LINKSET_EDITMODE_ADDREMOVE, LINKSET_EDITMODE_ADDONLY, LINKSET_EDITMODE_INPLACE, LINKSET_EDITMODE_ACTIONS])
+ && $oHostDbObject !== null) {
+ $sHostClass = get_class($oHostDbObject);
+ $oSetUIBlock->SetHasAddOptionButton(true);
+ $oSetUIBlock->SetAddOptionButtonJsOnClick("CombodoLinkSet.CreateLinkedObject('{$oAttDef->GetLinkedClass()}', '{$oAttDef->GetCode()}', '{$sHostClass}', '{$oHostDbObject->GetKey()}', '{$sTargetField}', '{$sTargetClass}', oWidget{$oSetUIBlock->GetId()} );");
+ }
+
// Current value
$aCurrentValues = LinkSetDataTransformer::Decode($oDbObjectSet, $sTargetClass, $sTargetField);
diff --git a/sources/Application/WebPage/iTopWebPage.php b/sources/Application/WebPage/iTopWebPage.php
index 4750349a2..7f5854a30 100644
--- a/sources/Application/WebPage/iTopWebPage.php
+++ b/sources/Application/WebPage/iTopWebPage.php
@@ -47,6 +47,9 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
// - DisplayableGraph, impact analysis
'js/raphael-min.js',
'js/jquery.mousewheel.js',
+ /** - links widgets moved in links folder @since 3.1.0 * */
+ 'js/links/links_direct_widget.js',
+ 'js/links/links_widget.js',
];
/** @inheritDoc */
protected const COMPATIBILITY_DEPRECATED_LINKED_SCRIPTS_REL_PATH = [
diff --git a/sources/Controller/Base/Layout/ObjectController.php b/sources/Controller/Base/Layout/ObjectController.php
index b16e8d522..b3d5e34a8 100644
--- a/sources/Controller/Base/Layout/ObjectController.php
+++ b/sources/Controller/Base/Layout/ObjectController.php
@@ -18,6 +18,7 @@ use Combodo\iTop\Service\Base\ObjectRepository;
use CoreCannotSaveObjectException;
use DeleteException;
use Dict;
+use Exception;
use IssueLog;
use iTopOwnershipLock;
use iTopWebPage;
@@ -90,6 +91,8 @@ class ObjectController extends AbstractController
/* Alerts the results */
sPosting.done(function(data) {
+ // fire event
+ oForm.trigger('itop.form.submitted', [data]);
if(data.success !== undefined && data.success === true) {
oForm.closest('[data-role="ibo-modal"]').dialog('close');
}
@@ -151,6 +154,7 @@ JS;
$sClass = utils::ReadPostedParam('class', '', 'class');
$sClassLabel = MetaModel::GetName($sClass);
+ $sFormPrefix = utils::ReadPostedParam('formPrefix', '', FILTER_SANITIZE_STRING);
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
$aErrors = array();
$aWarnings = array();
@@ -203,7 +207,7 @@ JS;
$oObj->Set($sStateAttCode, $sTargetState);
}
}
- $aErrors = $oObj->UpdateObjectFromPostedForm();
+ $aErrors = $oObj->UpdateObjectFromPostedForm($sFormPrefix);
}
if (isset($oObj) && is_object($oObj))
{
@@ -260,6 +264,7 @@ JS;
// Nothing more to do
if ($this->IsHandlingXmlHttpRequest()) {
$aResult['success'] = true;
+ $aResult['data'] = ['object' => ObjectRepository::ConvertObjectToArray($oObj, $sClass)];
} else {
ReloadAndDisplay($oPage, $oObj, 'create', $sMessage, 'ok');
}
@@ -543,8 +548,6 @@ JS;
'js/forms-json-utils.js',
'js/wizardhelper.js',
'js/wizard.utils.js',
- 'js/linkswidget.js',
- 'js/linksdirectwidget.js',
'js/extkeywidget.js',
'js/jquery.blockUI.js',
];
@@ -589,4 +592,33 @@ JS;
]);
}
+ /**
+ * OperationGet.
+ *
+ * @return JsonPage
+ */
+ public function OperationGet(): JsonPage
+ {
+ $oPage = new JsonPage();
+ $bSuccess = true;
+ $aObjectData = null;
+
+ // Retrieve query params
+ $sObjectClass = utils::ReadParam('object_class', '', false, utils::ENUM_SANITIZATION_FILTER_STRING);
+ $sObjectKey = utils::ReadParam('object_key', '', false, utils::ENUM_SANITIZATION_FILTER_STRING);
+
+ // Retrieve object
+ try {
+ $oObject = MetaModel::GetObject($sObjectClass, $sObjectKey);
+ $aObjectData = ObjectRepository::ConvertObjectToArray($oObject, $sObjectClass);
+ }
+ catch (Exception $e) {
+ $bSuccess = false;
+ }
+
+ return $oPage->SetData([
+ 'object' => $aObjectData,
+ 'success' => $bSuccess,
+ ]);
+ }
}
\ No newline at end of file
diff --git a/sources/Controller/Links/LinksetController.php b/sources/Controller/Links/LinksetController.php
index 62ff2150a..b9c4cde96 100644
--- a/sources/Controller/Links/LinksetController.php
+++ b/sources/Controller/Links/LinksetController.php
@@ -10,6 +10,7 @@ use AjaxPage;
use cmdbAbstractObject;
use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
use Combodo\iTop\Controller\AbstractController;
+use Combodo\iTop\Service\Base\ObjectRepository;
use Exception;
use JsonPage;
use CoreException;
@@ -169,8 +170,8 @@ class LinkSetController extends AbstractController
$aPrefillParam = array('source_obj' => $oSourceObj);
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
// We display this form in a modal, once we submit (in ajax) we probably want to only close the modal
- $sFormOnSubmitJsCode =
- <<