1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8## nofilter(TidyAll::Plugin::OTRS::Perl::LayoutObject) 9 10package Kernel::System::SysConfig::ValueType::FrontendNavigation; 11 12use strict; 13use warnings; 14 15use Kernel::System::VariableCheck qw(:all); 16 17use parent qw(Kernel::System::SysConfig::BaseValueType); 18 19our @ObjectDependencies = ( 20 'Kernel::Language', 21 'Kernel::Output::HTML::Layout', 22 'Kernel::System::Log', 23); 24 25=head1 NAME 26 27Kernel::System::SysConfig::ValueType::FrontendNavigation - System configuration frontend navigation value type backed. 28 29=head1 PUBLIC INTERFACE 30 31=head2 new() 32 33Create an object. Do not use it directly, instead use: 34 35 use Kernel::System::ObjectManager; 36 local $Kernel::OM = Kernel::System::ObjectManager->new(); 37 my $ValueTypeObject = $Kernel::OM->Get('Kernel::System::SysConfig::ValueType::FrontendNavigation'); 38 39=cut 40 41sub new { 42 my ( $Type, %Param ) = @_; 43 44 # Allocate new hash for object. 45 my $Self = {}; 46 bless( $Self, $Type ); 47 48 my @RequiredKeys = ( 49 'Name', 50 'Description', 51 'Link', 52 'NavBar', 53 ); 54 $Self->{RequiredKeys} = \@RequiredKeys; 55 56 return $Self; 57} 58 59=head2 SettingEffectiveValueCheck() 60 61Check if provided EffectiveValue matches structure defined in XMLContentParsed. 62 63 my %Result = $ValueTypeObject->SettingEffectiveValueCheck( 64 XMLContentParsed => { 65 Value => [ 66 { 67 'Item' => [ 68 { 69 ... 70 }, 71 ], 72 }, 73 ], 74 }, 75 EffectiveValue => { 76 ... 77 }, 78 ); 79 80Result: 81 %Result = ( 82 EffectiveValue => { # Note for FrontendNavigation ValueTypes EffectiveValue is not changed. 83 ... 84 }, 85 Success => 1, 86 Error => undef, 87 ); 88 89=cut 90 91sub SettingEffectiveValueCheck { 92 my ( $Self, %Param ) = @_; 93 94 for my $Needed (qw(XMLContentParsed)) { 95 if ( !$Param{$Needed} ) { 96 $Kernel::OM->Get('Kernel::System::Log')->Log( 97 Priority => 'error', 98 Message => "Need $Needed!" 99 ); 100 101 return; 102 } 103 } 104 105 my %Result = ( 106 Success => 0, 107 ); 108 109 if ( !IsHashRefWithData( $Param{EffectiveValue} ) ) { 110 $Result{Error} = "FrontendNavigation EffectiveValue must be a hash!"; 111 return %Result; 112 } 113 114 KEY: 115 for my $Key (qw(NavBar Link Name Description)) { 116 if ( !defined $Param{EffectiveValue}->{$Key} ) { 117 $Result{Error} = "FrontendNavigation must contain $Key!"; 118 last KEY; 119 } 120 } 121 122 return %Result if $Result{Error}; 123 124 $Result{Success} = 1; 125 $Result{EffectiveValue} = $Param{EffectiveValue}; 126 127 return %Result; 128} 129 130=head2 EffectiveValueGet() 131 132Extracts the effective value from a XML parsed setting. 133 134 my $EffectiveValue = $ValueTypeObject->EffectiveValueGet( 135 Value => [ 136 { 137 ValueRegex => '', # optional 138 Content => 'TheEffectiveValue', 139 ValueType => 'AValueType', # optional 140 # ... 141 } 142 ], 143 ); 144 145Returns: 146 147 $EffectiveValue = 'TheEffectiveValue'; 148 149=cut 150 151sub EffectiveValueGet { 152 my ( $Self, %Param ) = @_; 153 154 if ( !IsArrayRefWithData( $Param{Value} ) ) { 155 $Kernel::OM->Get('Kernel::System::Log')->Log( 156 Priority => 'error', 157 Message => "Value is missing or invalid!", 158 ); 159 160 return ''; 161 } 162 163 if ( scalar @{ $Param{Value} } > 1 ) { 164 $Kernel::OM->Get('Kernel::System::Log')->Log( 165 Priority => 'error', 166 Message => "Value must be a single element!", 167 ); 168 return ''; 169 } 170 171 return if ( !$Param{Value}->[0]->{Hash} ); 172 return if ( !$Param{Value}->[0]->{Hash}->[0] ); 173 return if ( !$Param{Value}->[0]->{Hash}->[0]->{Item} ); 174 175 my $EffectiveValue; 176 177 for my $Item ( @{ $Param{Value}->[0]->{Hash}->[0]->{Item} } ) { 178 179 if ( grep { $Item->{Key} eq $_ } qw(Group GroupRo) ) { 180 181 # contains array 182 183 if ( $Item->{Array} ) { 184 my @Array = (); 185 186 if ( 187 $Item->{Array} 188 && $Item->{Array}->[0]->{Item} 189 ) 190 { 191 for my $ArrayItem ( @{ $Item->{Array}->[0]->{Item} } ) { 192 push @Array, $ArrayItem->{Content} || ''; 193 } 194 } 195 $EffectiveValue->{ $Item->{Key} } = \@Array; 196 } 197 } 198 else { 199 # contains value 200 $EffectiveValue->{ $Item->{Key} } = $Item->{Content} || ''; 201 } 202 } 203 204 # Set undefined group attributes. 205 for my $Group (qw(Group GroupRo)) { 206 if ( !defined $EffectiveValue->{$Group} ) { 207 $EffectiveValue->{$Group} = []; 208 } 209 } 210 211 return $EffectiveValue; 212} 213 214=head2 SettingRender() 215 216Extracts the effective value from a XML parsed setting. 217 218 my $SettingHTML = $ValueTypeObject->SettingRender( 219 Name => 'SettingName', 220 DefaultID => 123, # (required) 221 EffectiveValue => '2016-02-02', 222 DefaultValue => 'Product 5', # (optional) 223 Class => 'My class' # (optional) 224 RW => 1, # (optional) Allow editing. Default 0. 225 Item => [ # (optional) XML parsed item 226 { 227 'ValueType' => 'FrontendNavigation', 228 'Content' => '2016-02-02', 229 'ValueRegex' => '', 230 }, 231 ], 232 IsArray => 1, # (optional) Item is part of the array 233 IsHash => 1, # (optional) Item is part of the hash 234 IDSuffix => 1, # (optional) Suffix will be added to the element ID 235 SkipEffectiveValueCheck => 1, # (optional) If enabled, system will not perform effective value check. 236 # Default: 1. 237 ); 238 239Returns: 240 241 $SettingHTML = '<div class "Field"...</div>'; 242 243=cut 244 245sub SettingRender { 246 my ( $Self, %Param ) = @_; 247 248 for my $Needed (qw(Name EffectiveValue)) { 249 if ( !defined $Param{$Needed} ) { 250 $Kernel::OM->Get('Kernel::System::Log')->Log( 251 Priority => 'error', 252 Message => "Need $Needed", 253 ); 254 return; 255 } 256 } 257 258 $Param{Class} //= ''; 259 $Param{DefaultValue} //= ''; 260 $Param{IDSuffix} //= ''; 261 262 my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); 263 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 264 265 my $EffectiveValue = $Param{EffectiveValue} // ''; 266 267 if ( !IsHashRefWithData($EffectiveValue) ) { 268 $Kernel::OM->Get('Kernel::System::Log')->Log( 269 Priority => 'error', 270 Message => "EffectiveValue must be a hash!" 271 ); 272 return ''; 273 } 274 275 # Set undefined group attributes. 276 for my $Group (qw(Group GroupRo)) { 277 if ( !defined $EffectiveValue->{$Group} ) { 278 $EffectiveValue->{$Group} = []; 279 } 280 } 281 282 my %EffectiveValueCheck = ( 283 Success => 1, 284 ); 285 286 if ( !$Param{SkipEffectiveValueCheck} ) { 287 %EffectiveValueCheck = $Self->SettingEffectiveValueCheck( 288 EffectiveValue => $EffectiveValue, 289 XMLContentParsed => { 290 Value => [ 291 { 292 Item => $Param{Item}, 293 }, 294 ], 295 }, 296 ); 297 } 298 299 my $HTML = "<div class='Hash'>\n"; 300 301 if ( !$EffectiveValueCheck{Success} ) { 302 my $Message = $LanguageObject->Translate("Value is not correct! Please, consider updating this module."); 303 304 $HTML .= $Param{IsValid} ? "<div class='BadEffectiveValue'>\n" : "<div>\n"; 305 $HTML .= "<p>* $Message</p>\n"; 306 $HTML .= "</div>\n"; 307 } 308 309 my $AddNewEntry = $LanguageObject->Translate("Add new entry"); 310 my $RemoveThisEntry = $LanguageObject->Translate("Remove this entry"); 311 my $RequiredText = $LanguageObject->Translate("This field is required."); 312 313 my $Readonly = ''; 314 if ( !$Param{RW} ) { 315 $Readonly = "readonly='readonly'"; 316 } 317 for my $Key ( sort keys %{$EffectiveValue} ) { 318 319 my $IsRequired = grep { $_ eq $Key } @{ $Self->{RequiredKeys} }; 320 321 $HTML .= "<div class='HashItem'>\n"; 322 $HTML .= "<input type='text' value='$Key' readonly='readonly' class='Key' />\n"; 323 $HTML .= "<div class='SettingContent'>\n"; 324 325 if ( grep { $Key eq $_ } qw (Group GroupRo) ) { 326 $HTML .= "<div class='Array'>\n"; 327 328 my $GroupIndex = 1; 329 for my $GroupItem ( @{ $EffectiveValue->{$Key} } ) { 330 331 my $HTMLGroupItem = $LayoutObject->Ascii2Html( 332 Text => $GroupItem, 333 Type => 'Normal', 334 ); 335 336 $HTML .= "<div class='ArrayItem'>\n"; 337 $HTML .= "<div class='SettingContent'>\n"; 338 $HTML .= "<input type=\"text\" value=\"$HTMLGroupItem\" $Readonly" 339 . "id=\"$Param{Name}$Param{IDSuffix}_Hash###$Key\_Array$GroupIndex\" />\n"; 340 $HTML .= "</div>\n"; 341 342 if ( $Param{RW} ) { 343 $HTML .= "<button class='RemoveButton' type='button' " 344 . "title='$RemoveThisEntry' value='Remove this entry'>\n" 345 . " <i class='fa fa-minus-circle'></i>\n" 346 . " <span class='InvisibleText'>$RemoveThisEntry</span>\n" 347 . "</button>\n"; 348 } 349 350 $HTML .= "</div>\n"; 351 352 $GroupIndex++; 353 } 354 355 my $ButtonClass = 'AddArrayItem'; 356 if ( !$Param{RW} ) { 357 $ButtonClass .= " Hidden"; 358 } 359 360 $HTML 361 .= " <button data-suffix='$Param{Name}$Param{IDSuffix}_Hash###$Key\_Array$GroupIndex' class='$ButtonClass' " 362 . "type='button' title='$AddNewEntry' value='Add new entry'>\n" 363 . " <i class='fa fa-plus-circle'></i>\n" 364 . " <span class='InvisibleText'>$AddNewEntry</span>\n" 365 . " </button>\n"; 366 $HTML .= "</div>\n"; 367 } 368 else { 369 my $InputClass = ''; 370 if ($IsRequired) { 371 $InputClass .= ' Validate_Required'; 372 } 373 374 my $HTMLValue = $LayoutObject->Ascii2Html( 375 Text => $EffectiveValue->{$Key}, 376 Type => 'Normal', 377 ); 378 379 $HTML .= "<input type=\"text\" value=\"$HTMLValue\" Class=\"$InputClass\" $Readonly" 380 . "id=\"$Param{Name}$Param{IDSuffix}_Hash###$Key\" />\n"; 381 382 if ($IsRequired) { 383 384 $HTML .= " 385 <div id=\"$Param{Name}$Param{IDSuffix}_Hash###${Key}Error\" class=\"TooltipErrorMessage\"> 386 <p>$RequiredText</p> 387 </div> 388 "; 389 } 390 } 391 392 $HTML .= "</div>\n"; 393 $HTML .= "</div>\n"; 394 } 395 $HTML .= "</div>\n"; 396 397 return $HTML; 398} 399 400=head2 AddItem() 401 402Generate HTML for new array/hash item. 403 404 my $HTML = $ValueTypeObject->AddItem( 405 Name => 'SettingName', (required) Name 406 DefaultItem => { (required) DefaultItem hash 407 Hash => { 408 409 }, 410 }, 411 IDSuffix => '_Array1', (optional) IDSuffix is needed for arrays and hashes. 412 ); 413 414Returns: 415 416 $HTML = '<select class="Modernize" id="SettingName" name="SettingName" title="SettingName"> 417 ... 418 </select>'; 419 420=cut 421 422sub AddItem { 423 my ( $Self, %Param ) = @_; 424 425 # Check needed stuff. 426 for my $Needed (qw(Name DefaultItem)) { 427 if ( !$Param{$Needed} ) { 428 $Kernel::OM->Get('Kernel::System::Log')->Log( 429 Priority => 'error', 430 Message => "Need $Needed!", 431 ); 432 return; 433 } 434 } 435 436 $Param{Class} //= ''; 437 $Param{DefaultValue} //= ''; 438 $Param{IDSuffix} //= ''; 439 440 my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); 441 442 my $HTML = "<div class='Hash FrontendNavigationHash'>\n"; 443 444 my @Keys; 445 446 # Check if structure is defined in the XML DefaultItem. 447 if ( $Param{DefaultItem}->{Hash}->[0]->{Item} ) { 448 for my $Item ( @{ $Param{DefaultItem}->{Hash}->[0]->{Item} } ) { 449 push @Keys, $Item->{Key}; 450 } 451 } 452 453 if (@Keys) { 454 455 # Make sure that required keys are there. 456 for my $RequiredKey ( @{ $Self->{RequiredKeys} } ) { 457 if ( !grep { $_ eq $RequiredKey } @Keys ) { 458 push @Keys, $RequiredKey; 459 } 460 } 461 } 462 else { 463 464 # Default keys. 465 @Keys = ( 466 'Group', 467 'GroupRo', 468 'Description', 469 'Name', 470 'Link', 471 'LinkOption', 472 'NavBar', 473 'Type', 474 'Block', 475 'AccessKey', 476 'Prio', 477 ); 478 } 479 my $AddNewEntry = $LanguageObject->Translate("Add new entry"); 480 my $RequiredText = $LanguageObject->Translate("This field is required."); 481 482 for my $Key ( sort @Keys ) { 483 my $IsRequired = grep { $_ eq $Key } @{ $Self->{RequiredKeys} }; 484 485 $HTML .= "<div class='HashItem'>\n"; 486 $HTML .= "<input type='text' value='$Key' readonly='readonly' class='Key' />\n"; 487 $HTML .= "<div class='SettingContent'>\n"; 488 489 if ( grep { $Key eq $_ } qw (Group GroupRo) ) { 490 $HTML .= "<div class='Array'>\n"; 491 492 # Add new item button. 493 $HTML .= " <button data-suffix='$Param{Name}$Param{IDSuffix}_Hash###$Key\_Array0' class='AddArrayItem' " 494 . "type='button' title='$AddNewEntry' value='Add new entry'>\n" 495 . " <i class='fa fa-plus-circle'></i>\n" 496 . " <span class='InvisibleText'>$AddNewEntry</span>\n" 497 . " </button>\n"; 498 499 $HTML .= "</div>\n"; 500 } 501 else { 502 my $InputClass = ''; 503 if ($IsRequired) { 504 $InputClass .= ' Validate_Required'; 505 } 506 507 $HTML .= "<input type='text' value='' " 508 . "id='$Param{Name}$Param{IDSuffix}_Hash###$Key' Class='$InputClass' />\n"; 509 510 if ($IsRequired) { 511 512 $HTML .= " 513 <div id=\"$Param{Name}$Param{IDSuffix}_Hash###${Key}Error\" class=\"TooltipErrorMessage\"> 514 <p>$RequiredText</p> 515 </div> 516 "; 517 } 518 } 519 520 $HTML .= "</div>\n"; 521 $HTML .= "</div>\n"; 522 } 523 524 $HTML .= "</div>"; 525 526 return $HTML; 527} 528 529=head2 AddSettingContent() 530 531Checks if a div with class 'SettingContent' should be added when adding new item to an array/hash in some special cases. 532 533 my $AddSettingContent = $ValueTypeObject->AddSettingContent(); 534 535Returns: 536 537 my $AddSettingContent = 0; 538 539=cut 540 541sub AddSettingContent { 542 my ( $Self, %Param ) = @_; 543 544 return 0; 545} 546 5471; 548 549=head1 TERMS AND CONDITIONS 550 551This software is part of the OTRS project (L<https://otrs.org/>). 552 553This software comes with ABSOLUTELY NO WARRANTY. For details, see 554the enclosed file COPYING for license information (GPL). If you 555did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 556 557=cut 558