# -- # Copyright (C) 2001-2019 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::Output::HTML::SysConfig; use strict; use warnings; use Kernel::System::VariableCheck qw( :all ); use parent qw(Kernel::System::SysConfig::Base::Framework); our @ObjectDependencies = ( 'Kernel::Config', 'Kernel::Language', 'Kernel::Output::HTML::Layout', 'Kernel::System::SysConfig', 'Kernel::System::Log', 'Kernel::System::Main', ); =head1 NAME Kernel::Output::HTML::SysConfig - Manage HTML representation of SysConfig settings. =head1 PUBLIC INTERFACE =head2 new() Create an object. Do not use it directly, instead use: use Kernel::System::ObjectManager; local $Kernel::OM = Kernel::System::ObjectManager->new(); my $SysConfigHTMLObject = $Kernel::OM->Get('Kernel::Output::HTML::SysConfig'); =cut sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); return $Self; } =head2 SettingRender() Returns the specific HTML for the setting. my $HTMLStr = $SysConfigHTMLObject->SettingRender( Setting => { Name => 'Setting Name', XMLContentParsed => $XMLParsedToPerl, EffectiveValue => "Product 6", # or a complex structure DefaultValue => "Product 5", # or a complex structure IsAjax => 1, # (optional) is ajax request. Default 0. # ... }, RW => 1, # (optional) Allow editing. Default 0. UserID => 1, # (required) UserID ); Returns: $HTMLStr = '
' # or false in case of an error =cut sub SettingRender { my ( $Self, %Param ) = @_; # Check needed stuff. for my $Needed (qw(Setting UserID)) { if ( !$Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $Needed!", ); return; } } if ( !IsHashRefWithData( $Param{Setting} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Setting is invalid!", ); } my %Setting = %{ $Param{Setting} }; my $RW = $Param{RW}; if ( $Setting{OverriddenFileName} ) { $RW = 0; } my $Result = $Self->_SettingRender( %Setting, Value => $Setting{XMLContentParsed}->{Value}, RW => $RW, IsAjax => $Param{IsAjax}, SkipEffectiveValueCheck => $Param{SkipEffectiveValueCheck}, EffectiveValue => $Setting{EffectiveValue}, UserID => $Param{UserID}, ); my $HTML = <<"EOF";
$Result
EOF if ($RW) { my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); my $SaveText = $LanguageObject->Translate('Save this setting'); my $CancelText = $LanguageObject->Translate('Cancel editing and unlock this setting'); my $ResetText = $LanguageObject->Translate('Reset this setting to its default value.'); $HTML .= "
\n"; } return $HTML; } =head2 SettingAddItem() Returns response that is sent when user adds new array/hash item. my %Result = $SysConfigHTMLObject->SettingAddItem( SettingStructure => [], # (required) array that contains structure # where a new item should be inserted (can be empty) Setting => { # (required) Setting hash (from SettingGet()) 'DefaultID' => '8905', 'DefaultValue' => [ 'Item 1', 'Item 2' ], 'Description' => 'Simple array item(Min 1, Max 3).', 'Name' => 'TestArray', ... }, Key => 'HashKey', # (optional) hash key IDSuffix => '_Array3, # (optional) suffix that will be added to all input/select fields # (it is used in the JS on Update, during EffectiveValue calculation) Value => [ # (optional) Perl structure { 'Array' => [ 'Item' => [ { 'Content' => 'Item 1', }, ... ], ], }, ], AddSettingContent => 0, # (optional) if enabled, result will be inside of div with class "SettingContent" UserID => 1, # (required) UserID ); Returns: %Result = ( 'Item' => '
', ); or %Result = ( 'Error' => 'Error description', ); =cut sub SettingAddItem { my ( $Self, %Param ) = @_; for my $Needed (qw(SettingStructure Setting UserID)) { if ( !$Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $Needed!", ); return; } } $Param{Key} //= ''; my @SettingStructure = @{ $Param{SettingStructure} }; $Param{IDSuffix} //= ''; my %Setting = %{ $Param{Setting} }; my $DefaultItem; my %Result; my $Value = $Param{Value}; if ( $Value->{Item} && $Value->{Item}->[0]->{ValueType} ) { my $ValueType = $Value->{Item}->[0]->{ValueType}; my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); if ( !$Loaded ) { $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( "Unable to load %s!", "Kernel::System::SysConfig::ValueType::$ValueType" ); return %Result; } my $BackendObject = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); $DefaultItem = $BackendObject->DefaultItemAdd(); } elsif ( $Value->{Item} && $Value->{Item}->[0]->{ValueType} eq 'VacationDaysOneTime' ) { $DefaultItem = { Item => { Content => '', }, ValueType => 'VacationDaysOneTime', }; } elsif ( $Value->{Array} && $Value->{Array}->[0]->{DefaultItem} ) { $DefaultItem = $Value->{Array}->[0]->{DefaultItem}->[0]; } elsif ( $Value->{Hash} && $Value->{Hash}->[0]->{DefaultItem} ) { $DefaultItem = $Value->{Hash}->[0]->{DefaultItem}->[0]; } if ( !$DefaultItem && $Value->{Array} ) { my $DedicatedDefaultItem = $Value->{Array}->[0]; my @Structure = split m{_Array|_Hash\#\#\#}smx, $Param{IDSuffix}; shift @Structure; my $Index = 0; for my $StructureItem (@SettingStructure) { if ( $StructureItem eq 'Hash' ) { my $HashKey = $Structure[$Index]; my ($Item) = grep { $HashKey eq $_->{Key} } @{ $DedicatedDefaultItem->{Item} }; last STRUCTURE if !$Item; $DedicatedDefaultItem = $Item->{Hash}->[0]; } else { my $ArrayIndex = $Structure[$Index]; last STRUCTURE if !$DedicatedDefaultItem->{Item}->{$ArrayIndex}; $DedicatedDefaultItem = $DedicatedDefaultItem->{Item}->[$ArrayIndex]->{Array}->[0]; } $Index++; } if ( $DedicatedDefaultItem->{DefaultItem} ) { $DefaultItem = $DedicatedDefaultItem->{DefaultItem}->[0]; @SettingStructure = (); } else { # Simple item $DefaultItem = { Item => { Content => '', }, }; } } elsif ( !$DefaultItem && $Value->{Hash} ) { my $DedicatedDefaultItem = $Value->{Hash}->[0]; my @Structure = split m{_Array|_Hash\#\#\#}smx, $Param{IDSuffix}; shift @Structure; my $Index = 0; STRUCTURE: for my $StructureItem (@SettingStructure) { # NOTE: Array elements must contain same structure. if ( $StructureItem eq 'Hash' ) { # Check original XML structure and search for the element with the same key. # If found, system will use this structure. my $HashKey = $Structure[$Index]; my ($Item) = grep { $HashKey eq $_->{Key} } @{ $DedicatedDefaultItem->{Item} }; last STRUCTURE if !$Item; $DedicatedDefaultItem = $Item->{Hash}->[0]; } $Index++; } if ( $DedicatedDefaultItem->{DefaultItem} ) { $DefaultItem = $DedicatedDefaultItem->{DefaultItem}->[0]; @SettingStructure = (); } else { # Simple item $DefaultItem = { Item => { Content => '', }, }; } } for my $StructureItem ( reverse @SettingStructure ) { if ( $StructureItem eq 'Array' ) { $DefaultItem = $DefaultItem->{Array}->[0]->{DefaultItem}->[0]; if ( !$DefaultItem ) { $DefaultItem = { Item => { Content => '', }, }; } } else { $DefaultItem = $DefaultItem->{Hash}->[0]->{DefaultItem}->[0]; if ( !$DefaultItem ) { $DefaultItem = { Item => { Content => '', }, }; } } } # Default fallback if ( !$DefaultItem ) { $DefaultItem = { Item => { Content => '', }, }; } if ( $DefaultItem->{Item} || $DefaultItem->{ValueType} ) { my $ValueType = $DefaultItem->{ValueType} || 'String'; my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); if ( !$Loaded ) { $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( "Unable to load %s!", "Kernel::System::SysConfig::ValueType::$ValueType" ); return %Result; } my $BackendObject = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); # Check if ValueType should add SettingContent. my $AddSettingContent = $BackendObject->AddSettingContent(); if ($AddSettingContent) { $Result{Item} = "
\n"; } $Result{Item} .= $BackendObject->AddItem( Name => $Setting{Name}, DefaultItem => $DefaultItem, IDSuffix => $Param{IDSuffix}, UserID => $Param{UserID}, ); if ($AddSettingContent) { $Result{Item} .= '
'; } } else { $Result{Item} //= ''; if ( $DefaultItem->{Array} ) { pop @SettingStructure; $Param{SettingStructure} = \@SettingStructure; # new array item my %SubResult = $Self->SettingAddItem( %Param, Value => $DefaultItem, IDSuffix => $Param{IDSuffix} . '_Array1', AddSettingContent => 0, UserID => $Param{UserID}, ); return %SubResult if $SubResult{Error}; if ( $Param{AddSettingContent} ) { $Result{Item} .= "
\n"; } $Result{Item} .= '
'; $Result{Item} .= '
'; $Result{Item} .= $SubResult{Item}; $Result{Item} .= "
\n"; $Result{Item} .= "
\n"; if ( $Param{AddSettingContent} ) { $Result{Item} .= "
\n"; } } elsif ( $DefaultItem->{Hash} ) { my $AddKey = $Kernel::OM->Get('Kernel::Language')->Translate("Add key"); pop @SettingStructure; $Param{SettingStructure} = \@SettingStructure; # new hash item my %SubResult = $Self->SettingAddItem( %Param, Value => $DefaultItem, IDSuffix => $Param{IDSuffix} . "_Hash###$Param{Key}", AddSettingContent => 0, UserID => $Param{UserID}, ); return %SubResult if $SubResult{Error}; if ( $Param{AddSettingContent} ) { $Result{Item} .= "
\n"; } $Result{Item} .= "
"; if ( $Param{AddSettingContent} ) { $Result{Item} .= "
\n"; } } } return %Result; } =head1 PRIVATE INTERFACE =head2 _SettingRender() Recursive helper for SettingRender(). my $HTMLStr = $SysConfigObject->_SettingRender( Name => 'Setting Name', Value => $XMLParsedToPerlValue, # (required) EffectiveValue => "Product 6", # (required) or a complex structure DefaultValue => "Product 5", # (optional) or a complex structure ValueType => "String", # (optional) IsAjax => 1, # (optional) Default 0. # ... RW => 1, # (optional) Allow editing. Default 0. IsArray => 1, # (optional) Item is part of the array IsHash => 1, # (optional) Item is part of the hash Key => 'Key', # (optional) Hash key (if available) SkipEffectiveValueCheck => 1, # (optional) If enabled, system will not perform effective value check. # Default: 1. UserID => 1, # (required) UserID ); Returns: $HTMLStr = '
' # or false in case of an error =cut sub _SettingRender { my ( $Self, %Param ) = @_; for my $Needed (qw(Value EffectiveValue UserID)) { if ( !defined $Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $Needed!", ); return; } } $Param{IDSuffix} //= ''; $Param{EffectiveValue} //= ''; my $Result = $Param{Result} || ''; my %Objects; if ( $Param{Objects} ) { %Objects = %{ $Param{Objects} }; } my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); # Make sure structure is correct. return $Result if !IsArrayRefWithData( $Param{Value} ); return $Result if !IsHashRefWithData( $Param{Value}->[0] ); if ( $Param{Value}->[0]->{Item} ) { # Make sure structure is correct. return $Result if !IsArrayRefWithData( $Param{Value}->[0]->{Item} ); return $Result if !IsHashRefWithData( $Param{Value}->[0]->{Item}->[0] ); # Set default ValueType. my $ValueType = "String"; if ( $Param{Value}->[0]->{Item}->[0]->{ValueType} ) { $ValueType = $Param{Value}->[0]->{Item}->[0]->{ValueType}; } if ( !$Objects{$ValueType} ) { # Load required class. my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); return $Result if !$Loaded; # Create object instance. $Objects{$ValueType} = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); } $Result = $Objects{$ValueType}->SettingRender( %Param, Item => $Param{Value}->[0]->{Item}, ); } elsif ( $Param{Value}->[0]->{Hash} ) { # Make sure structure is correct. return {} if !IsArrayRefWithData( $Param{Value}->[0]->{Hash} ); return {} if ref $Param{Value}->[0]->{Hash}->[0] ne 'HASH'; if ( !$Param{Value}->[0]->{Hash}->[0]->{Item} ) { $Param{Value}->[0]->{Hash}->[0]->{Item} = []; delete $Param{Value}->[0]->{Content}; } return {} if ref $Param{Value}->[0]->{Hash}->[0]->{Item} ne 'ARRAY'; my $ModifiedXMLParsed = $Self->SettingModifiedXMLContentParsedGet( ModifiedSetting => { EffectiveValue => $Param{EffectiveValue}, }, DefaultSetting => { XMLContentParsed => { Value => $Param{Value}, }, }, ); my @Items; my $RemoveThisEntry = $LanguageObject->Translate("Remove this entry"); $Result .= "
[0]->{Hash}->[0]->{MinItems} ) { $Result .= "data-min-items='" . $ModifiedXMLParsed->[0]->{Hash}->[0]->{MinItems} . "' "; } if ( $ModifiedXMLParsed->[0]->{Hash}->[0]->{MaxItems} ) { $Result .= "data-max-items='" . $ModifiedXMLParsed->[0]->{Hash}->[0]->{MaxItems} . "' "; } $Result .= ">"; my $Index = 0; ITEM: for my $Item ( @{ $ModifiedXMLParsed->[0]->{Hash}->[0]->{Item} } ) { next ITEM if !IsHashRefWithData($Item); $Index++; # Add attributes that are defined in the XML file to the corresponding ModifiedXMLParsed items. if ( $Param{Value}->[0]->{Hash}->[0]->{Item} ) { my ($HashItem) = grep { defined $_->{Key} && $_->{Key} eq $Item->{Key} } @{ $Param{Value}->[0]->{Hash}->[0]->{Item} }; if ($HashItem) { ATTRIBUTE: for my $Attribute ( sort keys %{$HashItem} ) { # Do not override core attributes. next ATTRIBUTE if grep { $Attribute eq $_ } qw(Content DefaultItem Hash Array Key SelectedID); if ( $Attribute eq 'Item' ) { if ( !$HashItem->{Item}->[0]->{ValueType} || $HashItem->{Item}->[0]->{ValueType} ne 'Option' ) { # Skip Items that contain Options (they can't be modified). next ATTRIBUTE; } } $Item->{$Attribute} = $HashItem->{$Attribute}; } } } my $DefaultValueType; if ( $Param{Value}->[0]->{Hash}->[0]->{DefaultItem} ) { $DefaultValueType = $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{ValueType}; } if ( $Item->{Hash} || $Item->{Array} ) { # Complex structure - HoA or HoH my $Key = $Item->{Hash} ? 'Hash' : 'Array'; $Result .= "
\n"; # Gather the value type from the default item, from a previous call # or string as default. my $ValueType = $DefaultValueType || $Param{ValueType} || 'String'; my $HTMLKey = ''; # Check if complex structure has a key element. if ( defined $Item->{Key} ) { $HTMLKey = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Ascii2Html( Text => $Item->{Key}, Type => 'Normal', ); $Result .= " "; } $Result .= "
\n"; my $IDSuffix = $Param{IDSuffix} . "_Hash###$HTMLKey"; if ( $Param{Value}->[0]->{Hash}->[0]->{DefaultItem} ) { if ( $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{Array} ) { my $DefaultItem = $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{Array}->[0]->{DefaultItem}; if ($DefaultItem) { # Append default item parameters. $Item->{Array}->[0] = { %{ $Item->{Array}->[0] }, DefaultItem => $DefaultItem, }; } } elsif ( $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{Hash} ) { my $DefaultItem = $Param{Value}->[0]->{Hash}->[0]->{DefaultItem}->[0]->{Hash}->[0]->{DefaultItem}; if ($DefaultItem) { # Append default item parameters. $Item->{Hash}->[0] = { %{ $Item->{Hash}->[0] }, DefaultItem => $DefaultItem, }; } } } # Start recursion. $Result .= $Self->_SettingRender( %Param, EffectiveValue => $Param{EffectiveValue}->{ $Item->{Key} }, Value => [$Item], Objects => \%Objects, ValueType => $ValueType, IDSuffix => $IDSuffix, ); $Result .= "
\n"; if ( $Param{RW} ) { $Result .= ""; } $Result .= "
\n"; } else { my $HashItem = "
\n"; # Gather the Value type from parent, from item, from previous call # or use string as default. my $ValueType = $Item->{ValueType} || $DefaultValueType || $Param{ValueType} || 'String'; # Output key element. $HashItem .= "{Key}\" "; if ( !$Param{RW} ) { $HashItem .= "disabled=\"disabled\" "; } $HashItem .= "readonly=\"readonly\" "; $HashItem .= "/>\n"; if ( !$Objects{$ValueType} ) { # Make sure the ValueType backed is present and is syntactically correct. my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); return $Result if !$Loaded; # Create object instance $Objects{$ValueType} = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); } my $IDSuffix = $Param{IDSuffix} || ''; $IDSuffix .= "_Hash###$Item->{Key}"; my $ValueAttribute = $Objects{$ValueType}->ValueAttributeGet(); # Output item. $HashItem .= $Objects{$ValueType}->SettingRender( %Param, Name => $Param{Name}, EffectiveValue => $Item->{$ValueAttribute} // '', Class => 'Content', Item => [$Item], IsAjax => $Param{IsAjax}, IsHash => 1, Key => $Item->{Key}, IDSuffix => $IDSuffix, ); if ( $Param{RW} ) { # Check if item is removable if ( $ValueType eq ( $DefaultValueType || 'String' ) ) { $HashItem .= " "; } } $HashItem .= "
\n"; $Result .= $HashItem; } } my $KeyTranslation = $LanguageObject->Translate('Key'); my $ContentTranslation = $LanguageObject->Translate('Content'); my $AddNewEntry = $LanguageObject->Translate("Add new entry"); $Result .= " "; $Result .= "
"; } elsif ( $Param{Value}->[0]->{Array} ) { # Make sure structure is correct. return [] if !IsArrayRefWithData( $Param{Value}->[0]->{Array} ); return [] if ref $Param{Value}->[0]->{Array}->[0] ne 'HASH'; if ( !$Param{Value}->[0]->{Array}->[0]->{Item} ) { $Param{Value}->[0]->{Array}->[0]->{Item} = []; } return [] if ref $Param{Value}->[0]->{Array}->[0]->{Item} ne 'ARRAY'; my $ModifiedXMLParsed = $Self->SettingModifiedXMLContentParsedGet( ModifiedSetting => { EffectiveValue => $Param{EffectiveValue}, }, DefaultSetting => { XMLContentParsed => { Value => $Param{Value}, }, }, ); my @Items; my $RemoveThisEntry = $LanguageObject->Translate("Remove this entry"); $Result .= "
[0]->{Array}->[0]->{MinItems} ) { $Result .= "data-min-items='" . $ModifiedXMLParsed->[0]->{Array}->[0]->{MinItems} . "' "; } if ( $ModifiedXMLParsed->[0]->{Array}->[0]->{MaxItems} ) { $Result .= "data-max-items='" . $ModifiedXMLParsed->[0]->{Array}->[0]->{MaxItems} . "' "; } $Result .= ">"; my $Index = 0; ITEM: for my $Item ( @{ $ModifiedXMLParsed->[0]->{Array}->[0]->{Item} } ) { next ITEM if !IsHashRefWithData($Item); $Index++; # check attributes if ( $Param{Value}->[0]->{Array}->[0]->{Item} ) { ATTRIBUTE: for my $Attribute ( sort keys %{ $Param{Value}->[0]->{Array}->[0]->{Item}->[0] } ) { next ATTRIBUTE if grep { $Attribute eq $_ } qw(Content Item DefaultItem Hash Array); $Item->{$Attribute} = $Param{Value}->[0]->{Array}->[0]->{Item}->[0]->{$Attribute}; } } my $DefaultValueType; if ( $Param{Value}->[0]->{Array}->[0]->{DefaultItem} ) { $DefaultValueType = $Param{Value}->[0]->{Array}->[0]->{DefaultItem}->[0]->{ValueType}; } if ( $Item->{Hash} || $Item->{Array} ) { # Complex structure - AoA or AoH my $Key = $Item->{Hash} ? 'Hash' : 'Array'; $Result .= "
"; my $IDSuffix = $Param{IDSuffix} || ''; $IDSuffix .= "_Array$Index"; if ( $Param{Value}->[0]->{Array}->[0]->{DefaultItem} ) { if ( $Param{Value}->[0]->{Array}->[0]->{DefaultItem}->[0]->{Array} ) { my $DefaultItem = $Param{Value}->[0]->{Array}->[0]->{DefaultItem}->[0]->{Array}->[0]->{DefaultItem}; if ($DefaultItem) { # Append default item parameters. $Item->{Array}->[0] = { %{ $Item->{Array}->[0] }, DefaultItem => $DefaultItem, }; } } elsif ( $Param{Value}->[0]->{Array}->[0]->{DefaultItem}->[0]->{Hash} ) { my $DefaultItem = $Param{Value}->[0]->{Array}->[0]->{DefaultItem}->[0]->{Hash}->[0]->{DefaultItem}; if ($DefaultItem) { # Append default item parameters. $Item->{Hash}->[0] = { %{ $Item->{Hash}->[0] }, DefaultItem => $DefaultItem, }; } } } # Start recursion. $Result .= $Self->_SettingRender( %Param, Value => [$Item], EffectiveValue => $Param{EffectiveValue}->[ $Index - 1 ], IDSuffix => $IDSuffix, ); if ( $Param{RW} ) { $Result .= " "; } $Result .= "
"; } else { # Gather the value type from the default item, from the item, from a previous call # or string as default. my $ValueType = $DefaultValueType || $Item->{ValueType} || $Param{ValueType} || 'String'; if ( !$Objects{$ValueType} ) { # Make sure the ValueType backed is present and is syntactically correct. my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require( "Kernel::System::SysConfig::ValueType::$ValueType", ); return $Result if !$Loaded; # Create object instance $Objects{$ValueType} = $Kernel::OM->Get( "Kernel::System::SysConfig::ValueType::$ValueType", ); } my $RenderItem; if ( $Item->{Content} ) { $RenderItem = [$Item]; } else { $RenderItem = $Item->{Item}; } my $ValueAttribute = $Objects{$ValueType}->ValueAttributeGet(); my $EffectiveValue = $RenderItem->[0]->{$ValueAttribute} || ''; my $IDSuffix = $Param{IDSuffix} || ''; $IDSuffix .= "_Array$Index"; my $ArrayItem = "
"; $ArrayItem .= $Objects{$ValueType}->SettingRender( %Param, Name => $Param{Name}, EffectiveValue => $EffectiveValue || '', Class => 'Entry', Item => $RenderItem, IsAjax => $Param{IsAjax}, IsArray => 1, IDSuffix => $IDSuffix, ); if ( $Param{RW} ) { $ArrayItem .= " "; } $ArrayItem .= "
\n"; $Result .= $ArrayItem; } } my $Size = @{ $ModifiedXMLParsed->[0]->{Array}->[0]->{Item} } + 1; $Param{IDSuffix} //= ''; my $AddNewEntry = $LanguageObject->Translate("Add new entry"); $Result .= " \n"; $Result .= "
"; } return $Result; } 1; =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). This software comes with ABSOLUTELY NO WARRANTY. For details, see the enclosed file COPYING for license information (GPL). If you did not receive this file, see L. =cut