N°6154 N°6219 - Relations Read - tooltip, confirmation title and message (#486)

N°6154 - n:n Read - tooltip, confirmation title and message on Add-Edit-Remove
N°6219 - 1:n Read: tooltip, modal title and message on Add-Edit-Remove-Delete
This commit is contained in:
bdalsass
2023-04-28 14:43:53 +02:00
committed by GitHub
parent 269c1bf005
commit de35d941c1
28 changed files with 461 additions and 254 deletions

View File

@@ -2974,7 +2974,12 @@ EOF
$oObjectDetails = ObjectFactory::MakeDetails($this, $this->GetDisplayMode());
$oToolbarButtons->AddCSSClass('ibo-toolbar-top');
$oObjectDetails->AddToolbarBlock($oToolbarButtons);
// Allow form title customization
if (array_key_exists('form_title', $aExtraParams)) {
$oObjectDetails->SetTitle($aExtraParams['form_title']);
}
}
$oForm->AddSubBlock($oObjectDetails);
if (isset($aExtraParams['nbBulkObj'])) {
// if bulk modify buttons must be after object display

View File

@@ -1844,7 +1844,12 @@ class MenuBlock extends DisplayBlock
$iSetCount = $oSet->Count();
/** @var string $sRefreshAction JS snippet to run when clicking on the refresh button of the menu */
$sRefreshAction = $aExtraParams['refresh_action'] ?? '';
$bIsCreationInModalAllowed = isset($aExtraParams['creation_in_modal_is_allowed']) && $aExtraParams['creation_in_modal_is_allowed'] === true;
$bIsCreationInModal = isset($aExtraParams['creation_in_modal']) && $aExtraParams['creation_in_modal'] === true;
$bIsCreationDisallowed = isset($aExtraParams['creation_disallowed']) && $aExtraParams['creation_disallowed'] === true;
// Check rights
$oReflectionClass = new ReflectionClass($sClass);
$bIsCreationAllowed = (!$bIsCreationDisallowed && UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) === UR_ALLOWED_YES) && ($oReflectionClass->IsSubclassOf('cmdbAbstractObject'));
/** @var array $aRegularActions Any action other than a transition */
$aRegularActions = [];
@@ -1860,7 +1865,7 @@ class MenuBlock extends DisplayBlock
$sContext = '&'.$sContext;
}
$oReflectionClass = new ReflectionClass($sClass);
$sFilter = $this->GetFilter()->serialize();
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
@@ -1880,10 +1885,6 @@ class MenuBlock extends DisplayBlock
}
}
// Check rights
$bIsCreationAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) === UR_ALLOWED_YES) && ($oReflectionClass->IsSubclassOf('cmdbAbstractObject'));
$bIsModifyAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) === UR_ALLOWED_YES) && ($oReflectionClass->IsSubclassOf('cmdbAbstractObject'));
// Check concurrent lock (can only be lock if we are handling a single object
$bLocked = false;
if ($iSetCount === 1) {
@@ -1905,7 +1906,7 @@ class MenuBlock extends DisplayBlock
//--------------------------------------------
// Create in new tab
if ($bIsCreationAllowed && !$bIsCreationInModalAllowed) {
if ($bIsCreationAllowed && !$bIsCreationInModal) {
$this->AddNewObjectMenuAction($aRegularActions, $sClass, $sDefaultValuesAsUrlParams);
}
@@ -2308,9 +2309,12 @@ class MenuBlock extends DisplayBlock
}
// - Creation in modal
if ($bIsCreationInModalAllowed === true) {
if ($bIsCreationAllowed && $bIsCreationInModal) {
$oAddLinkActionButton = ButtonUIBlockFactory::MakeIconAction(
'fas fa-plus',
// Allow button tooltip customization
array_key_exists('creation_in_modal_tooltip', $aExtraParams) ?
$aExtraParams['creation_in_modal_tooltip'] :
Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($sClass)),
'UI:Links:New',
'',

View File

@@ -2386,12 +2386,9 @@ class AttributeLinkedSet extends AttributeDefinition
}
// Setting target class
if (!$this->IsIndirect())
{
if (!$this->IsIndirect()) {
$sTargetClass = $this->GetLinkedClass();
}
else
{
} else {
/** @var \AttributeExternalKey $oRemoteAttDef */
/** @var \AttributeLinkedSetIndirect $this */
$oRemoteAttDef = MetaModel::GetAttributeDef($this->GetLinkedClass(), $this->GetExtKeyToRemote());
@@ -2406,14 +2403,12 @@ class AttributeLinkedSet extends AttributeDefinition
$aAttCodesToDisplay = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetClass, 'list'));
// - Adding friendlyname attribute to the list is not already in it
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetClass);
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay))
{
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay)) {
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
}
// - Adding attribute labels
$aAttributesToDisplay = array();
foreach($aAttCodesToDisplay as $sAttCodeToDisplay)
{
foreach ($aAttCodesToDisplay as $sAttCodeToDisplay) {
$oAttDefToDisplay = MetaModel::GetAttributeDef($sTargetClass, $sAttCodeToDisplay);
$aAttributesToDisplay[$sAttCodeToDisplay] = $oAttDefToDisplay->GetLabel();
}
@@ -2436,14 +2431,47 @@ class AttributeLinkedSet extends AttributeDefinition
public function HasAValue($proposedValue): bool
{
// Protection against wrong value type
if (false === ($proposedValue instanceof ormLinkSet))
{
if (false === ($proposedValue instanceof ormLinkSet)) {
return parent::HasAValue($proposedValue);
}
// We test if there is at least 1 item in the linkset (new or existing), not if an item is being added to it.
return $proposedValue->Count() > 0;
}
/**
* SearchSpecificLabel.
*
* @param string $sDictEntrySuffix
* @param string $sDefault
* @param bool $bUserLanguageOnly
* @param ...$aArgs
* @return string
* @since 3.1.0
*/
public function SearchSpecificLabel(string $sDictEntrySuffix, string $sDefault, bool $bUserLanguageOnly, ...$aArgs): string
{
try {
$sNextClass = $this->m_sHostClass;
do {
$sKey = "class:{$sNextClass}/Attribute:{$this->m_sCode}/{$sDictEntrySuffix}";
if (Dict::S($sKey, null, $bUserLanguageOnly) !== $sKey) {
return Dict::Format($sKey, ...$aArgs);
}
$sNextClass = MetaModel::GetParentClass($sNextClass);
} while ($sNextClass !== null);
if (Dict::S($sDictEntrySuffix, null, $bUserLanguageOnly) !== $sKey) {
return Dict::Format($sDictEntrySuffix, ...$aArgs);
} else {
return $sDefault;
}
} catch (Exception $e) {
ExceptionLog::LogException($e);
return $sDefault;
}
}
}
/**

View File

@@ -19,19 +19,46 @@
Dict::Add('EN US', 'English', 'English', array(
// Action row
'UI:Links:ActionRow:Detach' => 'Remove',
'UI:Links:ActionRow:Detach+' => 'Remove this object',
'UI:Links:ActionRow:Detach:Confirmation' => 'Do you really want to remove <b>{item}</b> from current object ?',
'UI:Links:ActionRow:Delete' => 'Delete',
'UI:Links:ActionRow:Delete+' => 'Delete this object',
'UI:Links:ActionRow:Delete:Confirmation' => 'Do you really want to delete <b>{item}</b> from current object ?',
'UI:Links:ActionRow:Modify' => 'Modify',
'UI:Links:ActionRow:Modify+' => 'Modify this object',
'UI:Links:ActionRow:Modify:Modal:Title' => 'Modify an object',
// Placeholders
// $%1s : host object class name
// $%2s : host object firendlyname
// $%3s : current tab name
// $%4s : remote object class name
// $%5s : remote object friendlyname
// Action
'UI:Links:New:Modal:Title' => 'Create an object',
'UI:Links:Object:New:Modal:Title' => 'Create an object',
// Create
'UI:Links:Create:Button' => 'Create',
'UI:Links:Create:Button+' => 'Create a %4$s',
'UI:Links:Create:Modal:Title' => 'Create a %4$s in %2$s',
// Add
'UI:Links:Add:Button' => 'Add',
'UI:Links:Add:Button+' => 'Add a %4$s',
'UI:Links:Add:Modal:Title' => 'Add a %4$s to %2$s',
// Modify link
'UI:Links:ModifyLink:Button' => 'Modify',
'UI:Links:ModifyLink:Button+' => 'Modify this link',
'UI:Links:ModifyLink:Modal:Title' => 'Modify the link between %2$s and %5$s',
// Modify object
'UI:Links:ModifyObject:Button' => 'Modify',
'UI:Links:ModifyObject:Button+' => 'Modify this object',
'UI:Links:ModifyObject:Modal:Title' => '%5$s',
// Remove
'UI:Links:Remove:Button' => 'Remove',
'UI:Links:Remove:Button+' => 'Remove this %4$s',
'UI:Links:Remove:Modal:Title' => 'Remove a %4$s',
'UI:Links:Remove:Modal:Message' => 'Do you really want to remove %5$s from %2$s?',
// Delete
'UI:Links:Delete:Button' => 'Delete',
'UI:Links:Delete:Button+' => 'Delete this %4$s',
'UI:Links:Delete:Modal:Title' => 'Delete a %4$s',
'UI:Links:Delete:Modal:Message' => 'Do you really want to delete %5$s?',
// Bulk
'UI:Links:Bulk:LinkWillBeCreatedForAllObjects' => 'Add to all objects',

View File

@@ -19,19 +19,47 @@
Dict::Add('FR FR', 'French', 'Français', array(
// Action row
'UI:Links:ActionRow:Detach' => 'Enlever',
'UI:Links:ActionRow:Detach+' => 'Enlever cet objet',
'UI:Links:ActionRow:Detach:Confirmation' => 'Voulez-vous Enlever <b>{item}</b> de l\'objet courant ?',
'UI:Links:ActionRow:Delete' => 'Supprimer',
'UI:Links:ActionRow:Delete+' => 'Supprimer cet objet',
'UI:Links:ActionRow:Delete:Confirmation' => 'Voulez-vous supprimer <b>{item}</b> de l\'objet courant ?',
'UI:Links:ActionRow:Modify' => 'Modifier',
'UI:Links:ActionRow:Modify+' => 'Modifier cet objet',
'UI:Links:ActionRow:Modify:Modal:Title' => 'Modifier un objet',
// Action
'UI:Links:New:Modal:Title' => 'Créer un objet',
// Placeholders
// $%1s : host object class name
// $%2s : host object firendlyname
// $%3s : current tab name
// $%4s : remote object class name
// $%5s : remote object friendlyname
'UI:Links:Object:New:Modal:Title' => 'Créer un objet',
// Create
'UI:Links:Create:Button' => 'Créer',
'UI:Links:Create:Button+' => 'Créer un(e) %4$s',
'UI:Links:Create:Modal:Title' => 'Ajouter un(e) %4$s à %2$s',
// Add
'UI:Links:Add:Button' => 'Ajouter',
'UI:Links:Add:Button+' => 'Ajouter un(e) %4$s',
'UI:Links:Add:Modal:Title' => 'Ajouter un(e) %4$s à %2$s',
// Modify link
'UI:Links:ModifyLink:Button' => 'Modifier',
'UI:Links:ModifyLink:Button+' => 'Modifier cette relation',
'UI:Links:ModifyLink:Modal:Title' => 'Modifier la relation entre %2$s et %5$s',
// Modify object
'UI:Links:ModifyObject:Button' => 'Modifier',
'UI:Links:ModifyObject:Button+' => 'Modifier cet objet',
'UI:Links:ModifyObject:Modal:Title' => '%5$s',
// Remove
'UI:Links:Remove:Button' => 'Retirer',
'UI:Links:Remove:Button+' => 'Retirer cet(te) %4$s',
'UI:Links:Remove:Modal:Title' => 'Retirer un(e) %4$s de %1$s',
'UI:Links:Remove:Modal:Message' => 'Voulez-vous vraiment retirer %5$s de %2$s ?',
// Delete
'UI:Links:Delete:Button' => 'Supprimer',
'UI:Links:Delete:Button+' => 'Supprimer cet(te) %4$s',
'UI:Links:Delete:Modal:Title' => 'Supprimer un(e) %4$s',
'UI:Links:Delete:Modal:Message' => 'Voulez-vous vraiment supprimer %5$s ?',
// Bulk
'UI:Links:Bulk:LinkWillBeCreatedForAllObjects' => 'Ajouter à tous les objets',

View File

@@ -75,6 +75,10 @@ $(function()
// retrieve table
const $Table = $('table', this.element);
// retrieve new button
const $NewButton = $('[name="UI:Links:New"]', this.element);
const sButtonTooltipContent = $NewButton.attr('data-tooltip-content');
// 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');
@@ -82,7 +86,7 @@ $(function()
const sHostObjectId = $Table.closest('[data-role="ibo-object-details"]').attr('data-object-id');
// link object creation
iTopLinkSetWorker.CreateLinkedObject(sClass, sAttCode, sHostObjectClass, sHostObjectId, function(){
iTopLinkSetWorker.CreateLinkedObject(sButtonTooltipContent, sClass, sAttCode, sHostObjectClass, sHostObjectId, function(){
$(this).find("form").remove();
$(this).dialog('destroy');
},function (event, data) {
@@ -96,20 +100,29 @@ $(function()
* ModifyLinkedObject.
*
* @param {string} sLinkedObjectKey
* @param {Element} $TRElement
* @param {string} sRemoteFriendlyname
*/
ModifyLinkedObject: function (sLinkedObjectKey) {
ModifyLinkedObject: function (sLinkedObjectKey, $TRElement, sRemoteFriendlyname) {
const me = this;
// retrieve modify button and extract modal title
const $ModifyButton = $('[name="ModifyButton"]', $TRElement);
const sButtonTooltipContent = $ModifyButton.attr('data-tooltip-content');
let sButtonTitleContent = $ModifyButton.attr('data-modal-title');
sButtonTitleContent = sButtonTitleContent.replaceAll('{item}', sRemoteFriendlyname);
// Specify that external key to host object will be readonly
let aReadOnlyParams = {
'readonly': {
}
}
aReadOnlyParams['readonly'][this.options.external_key_to_me] = 1;
aReadOnlyParams['form_title'] = sButtonTitleContent;
// link object modification
iTopObjectWorker.ModifyObject(this.options.link_class, sLinkedObjectKey, function () {
iTopObjectWorker.ModifyObject(sButtonTooltipContent, this.options.link_class, sLinkedObjectKey, function () {
$(this).find("form").remove();
$(this).dialog('destroy');
}, function(event, data){

View File

@@ -46,6 +46,7 @@ const iTopLinkSetWorker = new function(){
/**
* CallAjaxCreateLinkedObject.
*
* @param {string} sModalTitle
* @param {string} sClass
* @param {string} sAttCode
* @param {string} sHostObjectClass
@@ -53,10 +54,10 @@ const iTopLinkSetWorker = new function(){
* @param oOnModalCloseCallback
* @param oOnFormSubmittedCallback
*/
const CallAjaxCreateLinkedObject = function(sClass, sAttCode, sHostObjectClass, sHostObjectId, oOnModalCloseCallback = null, oOnFormSubmittedCallback = null){
const CallAjaxCreateLinkedObject = function(sModalTitle, sClass, sAttCode, sHostObjectClass, sHostObjectId, oOnModalCloseCallback = null, oOnFormSubmittedCallback = null){
let oOptions = {
title: Dict.S('UI:Links:New:Modal:Title'),
title: sModalTitle,
content: {
endpoint: `${ROUTER_BASE_URL}?route=${ROUTE_LINK_SET_CREATE_OBJECT}`,
data: {

View File

@@ -15,7 +15,7 @@ const iTopLinkSet = new function () {
const CallCreateLinkedObject = function(sLinkedClass, oWidget)
{
// Create link object
iTopObjectWorker.CreateObject(sLinkedClass, function(){
iTopObjectWorker.CreateObject(Dict.S('UI:Links:Object:New:Modal:Title'), sLinkedClass, function(){
$(this).find("form").remove();
$(this).dialog('destroy');
},

View File

@@ -9,13 +9,14 @@ const iTopObjectWorker = new function(){
/**
* CallAjaxCreateObject.
*
* @param {string} sTitle
* @param {string} sClass
* @param oOnModalCloseCallback
* @param oOnFormSubmittedCallback
* @param {Object} aAdditionalData
* @constructor
*/
const CallAjaxCreateObject = function(sClass, oOnModalCloseCallback = null, oOnFormSubmittedCallback = null, aAdditionalData = []){
const CallAjaxCreateObject = function(sTitle, sClass, oOnModalCloseCallback = null, oOnFormSubmittedCallback = null, aAdditionalData = []){
let aData = $.extend(
{
class: sClass,
@@ -24,7 +25,7 @@ const iTopObjectWorker = new function(){
);
let oOptions = {
title: Dict.S('UI:Object:Modal:Title'),
title: sTitle,
content: {
endpoint: `${ROUTER_BASE_URL}?route=${ROUTE_CREATE_OBJECT}`,
data: aData
@@ -43,6 +44,7 @@ const iTopObjectWorker = new function(){
/**
* CallAjaxModifyObject.
*
* @param {string} sTitle
* @param {string} sObjectClass
* @param {string} sObjectKey
* @param oOnModalCloseCallback
@@ -50,7 +52,7 @@ const iTopObjectWorker = new function(){
* @param {Object} aAdditionalData
* @constructor
*/
const CallAjaxModifyObject = function(sObjectClass, sObjectKey, oOnModalCloseCallback, oOnFormSubmittedCallback, aAdditionalData = []){
const CallAjaxModifyObject = function(sTitle, sObjectClass, sObjectKey, oOnModalCloseCallback, oOnFormSubmittedCallback, aAdditionalData = []){
let aData = $.extend(
{
class: sObjectClass,
@@ -60,7 +62,7 @@ const iTopObjectWorker = new function(){
);
let oOptions = {
title: Dict.S('UI:Links:ActionRow:Modify:Modal:Title'),
title: sTitle,
content: {
endpoint: `${ROUTER_BASE_URL}?route=${ROUTE_MODIFY_OBJECT}`,
data: aData,

View File

@@ -325,10 +325,12 @@ CombodoModal._ConvertButtonDefinition = function (aButtonsDefinitions) {
if(aButtonsDefinitions === null) {
return aConverted
}
aButtonsDefinitions.forEach(element => {
Object.keys(aButtonsDefinitions).forEach(key => {
const element = aButtonsDefinitions[key];
console.log(element);
const aButton = {
text: element.text,
class: element.class,
class: typeof(element.classes) !== 'undefined' ? element.classes.join(' ') : '',
click: element.callback_on_click
}
aConverted.push(aButton);
@@ -366,43 +368,40 @@ CombodoModal.OpenConfirmationModal = function(oOptions, aData) {
}
}
// Merge external options with confirmation modal default options
oOptions = $.extend({
oOptions = $.extend(true, {
title: Dict.S('UI:Modal:DefaultConfirmationTitle'),
content: '',
confirm_button_label: null,
do_not_show_again_pref_key: null,
callback_on_confirm: null,
callback_on_cancel: null,
extra_options: {
callback_on_modal_close: function () {
$(this).dialog( "destroy" ); // destroy dialog object
}
},
buttons: [
{
buttons: {
cancel: {
text: Dict.S('UI:Button:Cancel'),
class: 'ibo-is-alternative',
classes: ['ibo-is-alternative'],
callback_on_click: function () {
// call confirm handler and close dialog
let bCanClose = true;
if(oOptions.callback_on_cancel != null){
if (oOptions.callback_on_cancel != null) {
bCanClose = oOptions.callback_on_cancel(...aData) !== false;
}
if(bCanClose){
if (bCanClose) {
$(this).dialog('close'); // close dialog
}
}
},
{
text: oOptions.confirm_button_label ?? Dict.S('UI:Button:Confirm'),
class: 'ibo-is-primary',
confirm: {
text: Dict.S('UI:Button:Confirm'),
classes: ['ibo-is-primary'],
callback_on_click: function () {
// Call confirm handler and close dialog
let bCanClose = true;
if(oOptions.callback_on_confirm != null){
if (oOptions.callback_on_confirm != null) {
bCanClose = oOptions.callback_on_confirm(...aData) !== false;
}
if(bCanClose){
if (bCanClose) {
$(this).dialog('close'); // close dialog
// Handle "do not show again" user preference
let bDoNotShowAgain = oOptions.do_not_show_again_pref_key !== null ?
@@ -414,7 +413,7 @@ CombodoModal.OpenConfirmationModal = function(oOptions, aData) {
}
}
}
],
},
callback_on_content_loaded: function(oModalContentElement){
// Add option do not show again from template
if(oOptions.do_not_show_again_pref_key !== null) {
@@ -444,15 +443,15 @@ CombodoModal.OpenInformativeModal = function(sMessage, sSeverity, oOptions) {
$(this).dialog( "destroy" );
}
},
buttons: [
{
buttons: {
ok: {
text: Dict.S('UI:Button:Ok'),
class: 'ibo-is-regular ibo-is-neutral',
// classes: ['ibo-is-regular', 'ibo-is-neutral'],
callback_on_click: function () {
$(this).dialog('close');
}
},
],
},
}, oOptions);
// Open modal

View File

@@ -2,24 +2,6 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f::getLoader();

View File

@@ -42,9 +42,6 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var ?string */
private $vendorDir;
@@ -109,7 +106,6 @@ class ClassLoader
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
@@ -153,7 +149,7 @@ class ClassLoader
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
* @psalm-var array<string, string>
*/
public function getClassMap()
{
@@ -429,8 +425,7 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
includeFile($file);
return true;
}
@@ -560,26 +555,18 @@ class ClassLoader
return false;
}
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
self::$includeFile = \Closure::bind(static function($file) {
function includeFile($file)
{
include $file;
}, null, null);
}
}

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
@@ -449,6 +449,7 @@ return array(
'Combodo\\iTop\\Service\\Events\\EventServiceLog' => $baseDir . '/sources/Service/Events/EventServiceLog.php',
'Combodo\\iTop\\Service\\Events\\iEventServiceSetup' => $baseDir . '/sources/Service/Events/iEventServiceSetup.php',
'Combodo\\iTop\\Service\\Links\\LinkSetDataTransformer' => $baseDir . '/sources/Service/Links/LinkSetDataTransformer.php',
'Combodo\\iTop\\Service\\Links\\LinkSetHelper' => $baseDir . '/sources/Service/Links/LinkSetHelper.php',
'Combodo\\iTop\\Service\\Links\\LinkSetModel' => $baseDir . '/sources/Service/Links/LinkSetModel.php',
'Combodo\\iTop\\Service\\Links\\LinkSetRepository' => $baseDir . '/sources/Service/Links/LinkSetRepository.php',
'Combodo\\iTop\\Service\\Links\\LinksBulkDataPostProcessor' => $baseDir . '/sources/Service/Links/LinksBulkDataPostProcessor.php',

View File

@@ -2,24 +2,24 @@
// autoload_files.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'c9d07b32a2e02bc0fc582d4f0c1b56cc' => $vendorDir . '/laminas/laminas-servicemanager/src/autoload.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
);

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -25,31 +25,46 @@ class ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f', 'loadClassLoader'));
$includePaths = require __DIR__ . '/include_paths.php';
$includePaths[] = get_include_path();
set_include_path(implode(PATH_SEPARATOR, $includePaths));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire7f81b4a2a468a061c306af5e447a9a9f($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire7f81b4a2a468a061c306af5e447a9a9f($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@@ -7,22 +7,22 @@ namespace Composer\Autoload;
class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
{
public static $files = array (
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'c9d07b32a2e02bc0fc582d4f0c1b56cc' => __DIR__ . '/..' . '/laminas/laminas-servicemanager/src/autoload.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
);
public static $prefixLengthsPsr4 = array (
@@ -814,6 +814,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Service\\Events\\EventServiceLog' => __DIR__ . '/../..' . '/sources/Service/Events/EventServiceLog.php',
'Combodo\\iTop\\Service\\Events\\iEventServiceSetup' => __DIR__ . '/../..' . '/sources/Service/Events/iEventServiceSetup.php',
'Combodo\\iTop\\Service\\Links\\LinkSetDataTransformer' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetDataTransformer.php',
'Combodo\\iTop\\Service\\Links\\LinkSetHelper' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetHelper.php',
'Combodo\\iTop\\Service\\Links\\LinkSetModel' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetModel.php',
'Combodo\\iTop\\Service\\Links\\LinkSetRepository' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetRepository.php',
'Combodo\\iTop\\Service\\Links\\LinksBulkDataPostProcessor' => __DIR__ . '/../..' . '/sources/Service/Links/LinksBulkDataPostProcessor.php',

View File

@@ -2,7 +2,7 @@
// include_paths.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'e645e9b00625680af30db024d4f2ef652179407c',
'reference' => 'd0e6572fd0f88f05aa45e840a0311c2a0595d51a',
'name' => 'combodo/itop',
'dev' => true,
),
@@ -25,7 +25,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => 'e645e9b00625680af30db024d4f2ef652179407c',
'reference' => 'd0e6572fd0f88f05aa45e840a0311c2a0595d51a',
'dev_requirement' => false,
),
'combodo/tcpdf' => array(

View File

@@ -249,6 +249,15 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory
$oButton->SetColor($aAction['color']);
}
$oButton->SetDataAttributes(['label' => Dict::S($aAction['label']), 'action-id' => $iKey, 'table-id' => $oTable->GetId()]);
if (array_key_exists('metadata', $aAction)) {
$aMetadata = $aAction['metadata'];
if (is_array($aMetadata)) {
foreach ($aMetadata as $key => $value) {
$oButton->AddDataAttribute($key, $value);
}
}
}
$oToolbar->AddSubBlock($oButton);
}
@@ -922,10 +931,14 @@ JS;
/**give definition of id for select checkbox*/
'row_actions',
/** array of blocks displayed on every row */
'creation_in_modal_is_allowed',
/** bool to allow a creation of a new object of this type in a modal */
'creation_in_modal',
/** bool to perform a creation of a new object of this type in a modal */
'creation_in_modal_tooltip',
/** creation in modal button tooltip */
'creation_in_modal_js_handler',
/** Handler to call when trying to create a new object in modal */
'creation_disallowed',
/** Don't provide the standard object creation feature */
];
}
}

View File

@@ -9,7 +9,6 @@ namespace Combodo\iTop\Application\UI\Links;
use ApplicationException;
use ArchivedObjectException;
use AttributeLinkedSet;
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use CoreException;
use CoreWarning;
@@ -17,7 +16,6 @@ use DBObject;
use DictExceptionMissingString;
use DisplayBlock;
use Exception;
use MetaModel;
use MySQLException;
use Utils;
use WebPage;
@@ -41,6 +39,20 @@ abstract class AbstractBlockLinkSetViewTable extends UIContentBlock
'js/wizardhelper.js',
];
// Dictionnary entries
public const BUTTON_TOOLTIP = 'UI:Links:Add:Button+';
public const DICT_CREATE_BUTTON_TOOLTIP = 'UI:Links:Create:Button+';
public const DICT_MODIFY_LINK_BUTTON_TOOLTIP = 'UI:Links:ModifyLink:Button+';
public const DICT_MODIFY_LINK_MODAL_TITLE = 'UI:Links:ModifyLink:Modal:Title';
public const DICT_MODIFY_OBJECT_BUTTON_TOOLTIP = 'UI:Links:ModifyObject:Button+';
public const DICT_MODIFY_OBJECT_MODAL_TITLE = 'UI:Links:ModifyObject:Modal:Title';
public const DICT_REMOVE_BUTTON_TOOLTIP = 'UI:Links:Remove:Button+';
public const DICT_REMOVE_MODAL_TITLE = 'UI:Links:Remove:Modal:Title';
public const DICT_REMOVE_MODAL_MESSAGE = 'UI:Links:Remove:Modal:Message';
public const DICT_DELETE_BUTTON_TOOLTIP = 'UI:Links:Delete:Button+';
public const DICT_DELETE_MODAL_TITLE = 'UI:Links:Delete:Modal:Title';
public const DICT_DELETE_MODAL_MESSAGE = 'UI:Links:Delete:Modal:Message';
/** @var DBObject $oDbObject db object witch link set belongs to */
protected DBObject $oDbObject;
@@ -99,6 +111,25 @@ abstract class AbstractBlockLinkSetViewTable extends UIContentBlock
$this->sTargetClass = $this->GetTargetClass();
}
/**
* @param string $sKey
* @param \DBObject|null $oDBObject
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function GetDictionaryEntry(string $sKey, DBObject $oDBObject = null)
{
return $this->oAttDef->SearchSpecificLabel($sKey, '', true,
$this->sObjectClass,
$this->oDbObject->Get('friendlyname'),
$this->oAttDef->GetLabel(),
$this->sTargetClass,
$oDBObject !== null ? $oDBObject->Get('friendlyname') : '{item}');
}
/**
* Initialize UI.
*

View File

@@ -49,9 +49,12 @@ class BlockDirectLinkSetViewTable extends AbstractBlockLinkSetViewTable
}
// Add creation in modal if the linkset is not readonly
if ($this->oAttDef->GetEditMode() != LINKSET_EDITMODE_NONE) {
$aExtraParams['creation_in_modal_is_allowed'] = true;
if (!$this->oAttDef->GetReadOnly() && $this->oAttDef->GetEditMode() != LINKSET_EDITMODE_NONE) {
$aExtraParams['creation_in_modal'] = true;
$aExtraParams['creation_in_modal_tooltip'] = $this->GetDictionaryEntry(static::DICT_CREATE_BUTTON_TOOLTIP);
$aExtraParams['creation_in_modal_js_handler'] = "{$this->GetWidgetName()}.links_view_table('CreateLinkedObject');";
} else {
$aExtraParams['creation_disallowed'] = true;
}
return $aExtraParams;
@@ -69,30 +72,42 @@ class BlockDirectLinkSetViewTable extends AbstractBlockLinkSetViewTable
case LINKSET_EDITMODE_ADDONLY: // The only possible action is to open (in a new window) the form to create a new object
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Modify',
'tooltip' => 'UI:Links:ActionRow:Modify+',
'label' => 'UI:Links:ModifyObject:Button',
'name' => 'ModifyButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_MODIFY_OBJECT_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-pen',
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw']);",
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw'], oTrElement, aRowData['{$this->sTargetClass}/friendlyname']);",
'metadata' => [
'modal-title' => $this->GetDictionaryEntry(static::DICT_MODIFY_OBJECT_MODAL_TITLE),
],
);
break;
case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
case LINKSET_EDITMODE_ACTIONS: // Show the usual 'Actions' popup menu
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Modify',
'tooltip' => 'UI:Links:ActionRow:Modify+',
'label' => 'UI:Links:ModifyObject:Button',
'name' => 'ModifyButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_MODIFY_OBJECT_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-pen',
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw']);",
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw'], oTrElement, aRowData['{$this->sTargetClass}/friendlyname']);",
'metadata' => [
'modal-title' => $this->GetDictionaryEntry(static::DICT_MODIFY_OBJECT_MODAL_TITLE),
],
);
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Delete',
'tooltip' => 'UI:Links:ActionRow:Delete+',
'label' => 'UI:Links:Delete:Button',
'name' => 'DeleteButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_DELETE_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-trash',
'color' => Button::ENUM_COLOR_SCHEME_DESTRUCTIVE,
'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",
'title' => $this->GetDictionaryEntry(static::DICT_DELETE_MODAL_TITLE),
'message' => $this->GetDictionaryEntry(static::DICT_DELETE_MODAL_MESSAGE),
'confirm_button_class' => 'ibo-is-danger',
'row_data' => "{$this->sTargetClass}/hyperlink",
'do_not_show_again_pref_key' => $this->GetDoNotShowAgainPreferenceKey(),
],
);
@@ -100,19 +115,25 @@ class BlockDirectLinkSetViewTable extends AbstractBlockLinkSetViewTable
case LINKSET_EDITMODE_ADDREMOVE: // The whole linkset can be edited 'in-place'
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Modify',
'tooltip' => 'UI:Links:ActionRow:Modify+',
'label' => 'UI:Links:ModifyObject:Button',
'name' => 'ModifyButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_MODIFY_OBJECT_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-pen',
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw']);",
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['{$this->oAttDef->GetLinkedClass()}/_key_/raw'], oTrElement, aRowData['{$this->sTargetClass}/friendlyname']);",
'metadata' => [
'modal-title' => $this->GetDictionaryEntry(static::DICT_MODIFY_OBJECT_MODAL_TITLE),
],
);
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Detach',
'tooltip' => 'UI:Links:ActionRow:Detach+',
'label' => 'UI:Links:Remove:Button',
'name' => 'RemoveButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_REMOVE_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-minus',
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('DetachLinkedObject', aRowData['{$this->sTargetClass}/_key_/raw'], oTrElement);",
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('DetachLinkedObject', aRowData['{$this->sTargetClass}/_key_/raw'], oTrElement, oTrElement);",
'confirmation' => [
'message' => 'UI:Links:ActionRow:Detach:Confirmation',
'message_row_data' => "{$this->sTargetClass}/hyperlink",
'title' => $this->GetDictionaryEntry(static::DICT_REMOVE_MODAL_TITLE),
'message' => $this->GetDictionaryEntry(static::DICT_REMOVE_MODAL_MESSAGE),
'row_data' => "{$this->sTargetClass}/hyperlink",
'do_not_show_again_pref_key' => $this->GetDoNotShowAgainPreferenceKey(),
],
);

View File

@@ -7,7 +7,6 @@
namespace Combodo\iTop\Application\UI\Links\Indirect;
use Combodo\iTop\Application\UI\Links\AbstractBlockLinkSetViewTable;
use Combodo\iTop\Service\Links\LinkSetModel;
use MetaModel;
use PHPUnit\Exception;
@@ -62,9 +61,11 @@ class BlockIndirectLinkSetViewTable extends AbstractBlockLinkSetViewTable
// 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'] = true;
$aExtraParams['creation_in_modal_tooltip'] = $this->GetDictionaryEntry(static::BUTTON_TOOLTIP);
$aExtraParams['creation_in_modal_js_handler'] = "{$this->GetWidgetName()}.links_view_table('CreateLinkedObject');";
} else {
$aExtraParams['creation_disallowed'] = true;
}
return $aExtraParams;
@@ -76,20 +77,26 @@ class BlockIndirectLinkSetViewTable extends AbstractBlockLinkSetViewTable
$aRowActions = array();
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Modify',
'tooltip' => 'UI:Links:ActionRow:Modify+',
'label' => 'UI:Links:ModifyLink:Button',
'name' => 'ModifyButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_MODIFY_LINK_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-pen',
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['Link/_key_/raw']);",
'js_row_action' => "{$this->GetWidgetName()}.links_view_table('ModifyLinkedObject', aRowData['Link/_key_/raw'], oTrElement, aRowData['Remote/friendlyname']);",
'metadata' => [
'modal-title' => $this->GetDictionaryEntry(static::DICT_MODIFY_LINK_MODAL_TITLE),
],
);
$aRowActions[] = array(
'label' => 'UI:Links:ActionRow:Detach',
'tooltip' => 'UI:Links:ActionRow:Detach+',
'label' => 'UI:Links:Remove:Button',
'name' => 'RemoveButton',
'tooltip' => $this->GetDictionaryEntry(static::DICT_REMOVE_BUTTON_TOOLTIP),
'icon_classes' => 'fas fa-minus',
'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",
'title' => $this->GetDictionaryEntry(static::DICT_REMOVE_MODAL_TITLE),
'message' => $this->GetDictionaryEntry(static::DICT_REMOVE_MODAL_MESSAGE),
'row_data' => "Remote/hyperlink",
'do_not_show_again_pref_key' => $this->GetDoNotShowAgainPreferenceKey(),
],
);

View File

@@ -81,6 +81,7 @@ class AjaxRenderController
$aObj[$sAlias."/_key_"] = $aObject[$sAlias]->GetKey();
$aObj[$sAlias."/_key_/raw"] = $aObject[$sAlias]->GetKey();
$aObj[$sAlias."/hyperlink"] = $aObject[$sAlias]->GetHyperlink();
$aObj[$sAlias."/friendlyname"] = $aObject[$sAlias]->Get('friendlyname');
// N°5943 Protection against $aColumnsLoad having less class aliases than $aClassAliases, this is in case the method's consumer isn't passing data correctly
if (false === array_key_exists($sAlias, $aColumnsLoad)) {

View File

@@ -219,6 +219,7 @@ JS
$bPrintable = utils::ReadParam('printable', '0') === '1';
$sClass = utils::ReadParam('class', '', false, 'class');
$sId = utils::ReadParam('id', '');
$sFormTitle = utils::ReadPostedParam('form_title', null, utils::ENUM_SANITIZATION_FILTER_STRING);
// Check parameters
if (utils::IsNullOrEmptyString($sClass) || utils::IsNullOrEmptyString($sId))
@@ -243,6 +244,11 @@ JS
$aFormExtraParams = array('wizard_container' => 1);
FormHelper::UpdateFlagsFromContext($oObj, $aFormExtraParams);
// Allow form title customization
if (!utils::IsNullOrEmptyString($sFormTitle)) {
$aFormExtraParams['form_title'] = $sFormTitle;
}
if ($this->IsHandlingXmlHttpRequest()) {
$oPage = new AjaxPage('');
$aFormExtraParams['js_handlers'] = [];

View File

@@ -11,6 +11,7 @@ use cmdbAbstractObject;
use Combodo\iTop\Application\Helper\FormHelper;
use Combodo\iTop\Application\UI\Base\Component\Form\FormUIBlockFactory;
use Combodo\iTop\Controller\AbstractController;
use Combodo\iTop\Service\Links\LinkSetModel;
use Combodo\iTop\Service\Router\Router;
use Combodo\iTop\Service\Base\ObjectRepository;
use Exception;
@@ -198,16 +199,29 @@ class LinkSetController extends AbstractController
}
});
}
JS
;
JS;
// Form title
/** @var \AttributeLinkedSet $oLinksetDef */
$oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$oHostObj = MetaModel::GetObject($sClass, $sId);
$sFormTitle = $oLinksetDef->SearchSpecificLabel('UI:Links:Add:Modal:Title', '', true,
$sClass,
$oHostObj->Get('friendlyname'),
$oLinksetDef->GetLabel(),
LinkSetModel::GetTargetClass($oLinksetDef));
$aExtraParams = [
'noRelations' => true,
'hide_transitions' => true,
'formPrefix' => $sAttCode,
'fieldsFlags' => $aFieldFlags,
'forceFieldsSubmission' => [
$sExtKeyToMe
$sExtKeyToMe,
],
'form_title' => $sFormTitle,
'custom_button' => \Dict::S('UI:Button:Add'),
'js_handlers' => [
'form_on_submit' => $sFormOnSubmitJsCode,
'cancel_button_on_click' =>

View File

@@ -4,6 +4,7 @@
// for each row action...
{% for aAction in oUIBlock.GetRowActions() %}
// register action buttons click
$('body').on('click', 'button[data-table-id="{{ oUIBlock.GetId() }}"][data-action-id="{{ loop.index0 }}"]', function() {
@@ -13,21 +14,41 @@
let sLabel = $(this).data('label');
let iActionId = $(this).data('action-id');
let aRowData = oDatatable.row(oTrElement).data();
let sConfirmButtonClass = 'ibo-is-primary';
{% if aAction.confirmation.confirm_button_class is not empty %}
sConfirmButtonClass = '{{ aAction.confirmation.confirm_button_class }}';
{% endif %}
{% if aAction.confirmation is defined %}
// Prepare confirmation title
let sTitle = `{{ 'UI:Datatables:RowActions:ConfirmationDialog'|dict_s|raw }}`;
{% if aAction.confirmation.title is defined %}
sTitle = `{{ aAction.confirmation.title|dict_s|raw }}`;
{% endif %}
sTitle = sTitle.replaceAll('{item}', aRowData['{{ aAction.confirmation.row_data }}']);
// Prepare confirmation message
let sMessage = `{{ 'UI:Datatables:RowActions:ConfirmationMessage'|dict_s|raw }}`;
{% if aAction.confirmation.message is defined %}
sMessage = `{{ aAction.confirmation.message|dict_s|raw }}`;
{% endif %}
sMessage = sMessage.replaceAll('{item}', aRowData['{{ aAction.confirmation.row_data }}']);
// Handle action row with confirmation modal
CombodoModal.OpenConfirmationModal({
title: '{{ 'UI:Datatables:RowActions:ConfirmationDialog'|dict_s }}',
content: sMessage.replaceAll('{item}', aRowData['{{ aAction.confirmation.message_row_data }}']),
confirm_button_label: sLabel,
callback_on_confirm: ActionRowFunction{{ oUIBlock.GetId() }}{{ loop.index0 }},
title: sTitle,
content: sMessage,
buttons: {
confirm: {
text: sLabel,
classes: [sConfirmButtonClass],
callback_on_click:{
ActionRowFunction{{ oUIBlock.GetId() }}{{ loop.index0 }}
}
}
},
{% if aAction.confirmation.do_not_show_again_pref_key is defined %}
do_not_show_again_pref_key: '{{ aAction.confirmation.do_not_show_again_pref_key }}',
{% endif %}