Files
scripts/Perl OTRS/Kernel/Output/HTML/SysConfig.pm
2024-10-14 00:08:40 +02:00

1029 lines
35 KiB
Perl

# --
# 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 = '<div class="Setting"><div class "Field"...</div></div>' # 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";
<div class="Setting" data-change-time="$Param{Setting}->{ChangeTime}">
$Result
</div>
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 .= "
<div class='SettingUpdateBox'>
<button class='CallForAction Update' aria-controls='fieldset$Param{Setting}->{DefaultID}' type='button' value='$SaveText' title='$SaveText'>
<span><i class='fa fa-check'></i></span>
</button>
<button class='CallForAction Cancel' aria-controls='fieldset$Param{Setting}->{DefaultID}' type='button' value='$CancelText' title='$CancelText'>
<span><i class='fa fa-times'></i></span>
</button>
</div>\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' => '<div class=\'SettingContent\'>
<input type=\'text\' id=\'TestArray_Array4\'
value=\'Default value\' name=\'TestArray\' class=\' Entry\'/></div>',
);
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} = "<div class='SettingContent'>\n";
}
$Result{Item} .= $BackendObject->AddItem(
Name => $Setting{Name},
DefaultItem => $DefaultItem,
IDSuffix => $Param{IDSuffix},
UserID => $Param{UserID},
);
if ($AddSettingContent) {
$Result{Item} .= '</div>';
}
}
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} .= "<div class=\"SettingContent\">\n";
}
$Result{Item} .= '<div class="Array">';
$Result{Item} .= '<div class="ArrayItem">';
$Result{Item} .= $SubResult{Item};
$Result{Item} .= "</div>\n";
$Result{Item} .= "</div>\n";
if ( $Param{AddSettingContent} ) {
$Result{Item} .= "</div>\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} .= "<div class=\"SettingContent\">\n";
}
$Result{Item} .= "
<div class=\"Hash\">
<div class=\"HashItem\">
<input type=\"text\" class=\"Key\" data-suffix=\"$Param{IDSuffix}_Hash###\">
<button class=\"AddKey\" value=\"$AddKey\" type=\"button\" title=\"$AddKey\">
<i class=\"fa fa-plus-circle\"></i>
<span class=\"InvisibleText\">$AddKey</span>
</button>
</div>
</div>";
if ( $Param{AddSettingContent} ) {
$Result{Item} .= "</div>\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 = '<div class "Field"...</div>' # 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 .= "<div class='Hash' ";
if ( $ModifiedXMLParsed->[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 .= "<div class='HashItem'>\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 .= "
<input class=\"Key\" type=\"text\" name=\"$Param{Name}Key\" value=\"$HTMLKey\"/>";
}
$Result .= "<div class=\"SettingContent\">\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 .= "</div>\n";
if ( $Param{RW} ) {
$Result
.= "<button value=\"$RemoveThisEntry\" title=\"$RemoveThisEntry\" type=\"button\" class=\"RemoveButton\">
<i class=\"fa fa-minus-circle\"></i>
<span class=\"InvisibleText\">$RemoveThisEntry</span>
</button>";
}
$Result .= "</div>\n";
}
else {
my $HashItem = "<div class='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 .= "<input class=\"Key\" type=\"text\" name=\"$Param{Name}Key\" value=\"$Item->{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 .= "
<button value=\"$RemoveThisEntry\" title=\"$RemoveThisEntry\" type=\"button\" class=\"RemoveButton\">
<i class=\"fa fa-minus-circle\"></i>
<span class=\"InvisibleText\">$RemoveThisEntry</span>
</button>";
}
}
$HashItem .= "</div>\n";
$Result .= $HashItem;
}
}
my $KeyTranslation = $LanguageObject->Translate('Key');
my $ContentTranslation = $LanguageObject->Translate('Content');
my $AddNewEntry = $LanguageObject->Translate("Add new entry");
$Result .= "
<button data-suffix=\"$Param{IDSuffix}_Hash###\" value=\"$AddNewEntry\" title=\"$AddNewEntry\" type=\"button\" class=\"AddHashKey";
if ( !$Param{RW} ) {
$Result .= " Hidden";
}
$Result .= "\">
<i class=\"fa fa-plus-circle\"></i>
<span class=\"InvisibleText\">$AddNewEntry</span>
</button>";
$Result .= "</div>";
}
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 .= "<div class='Array' ";
if ( $ModifiedXMLParsed->[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 .= "<div class='ArrayItem'>";
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 .= "
<button value=\"$RemoveThisEntry\" title=\"$RemoveThisEntry\" type=\"button\" class=\"RemoveButton\">
<i class=\"fa fa-minus-circle\"></i>
<span class=\"InvisibleText\">$RemoveThisEntry</span>
</button>";
}
$Result .= "</div>";
}
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 = "<div class='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 .= "
<button value=\"$RemoveThisEntry\" title=\"$RemoveThisEntry\" type=\"button\" class=\"RemoveButton\">
<i class=\"fa fa-minus-circle\"></i>
<span class=\"InvisibleText\">$RemoveThisEntry</span>
</button>";
}
$ArrayItem .= "</div>\n";
$Result .= $ArrayItem;
}
}
my $Size = @{ $ModifiedXMLParsed->[0]->{Array}->[0]->{Item} } + 1;
$Param{IDSuffix} //= '';
my $AddNewEntry = $LanguageObject->Translate("Add new entry");
$Result .= "
<button value=\"$AddNewEntry\" title=\"$AddNewEntry\" type=\"button\" data-suffix=\"$Param{IDSuffix}_Array$Size\" class=\"AddArrayItem";
if ( !$Param{RW} ) {
$Result .= " Hidden";
}
$Result .= "\">
<i class=\"fa fa-plus-circle\"></i>
<span class=\"InvisibleText\">$AddNewEntry</span>
</button>\n";
$Result .= "</div>";
}
return $Result;
}
1;
=head1 TERMS AND CONDITIONS
This software is part of the OTRS project (L<https://otrs.org/>).
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<https://www.gnu.org/licenses/gpl-3.0.txt>.
=cut