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