init III
This commit is contained in:
157
Perl OTRS/Kernel/Output/HTML/Layout/AJAX.pm
Normal file
157
Perl OTRS/Kernel/Output/HTML/Layout/AJAX.pm
Normal file
@@ -0,0 +1,157 @@
|
||||
# --
|
||||
# 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::Layout::AJAX;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::System::JSON ();
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::AJAX - all AJAX-related HTML functions
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All AJAX-related HTML functions
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 BuildSelectionJSON()
|
||||
|
||||
build a JSON output which can be used for e. g. data for pull downs
|
||||
|
||||
my $JSON = $LayoutObject->BuildSelectionJSON(
|
||||
[
|
||||
Data => $ArrayRef, # use $HashRef, $ArrayRef or $ArrayHashRef (see below)
|
||||
Name => 'TheName', # name of element
|
||||
SelectedID => [1, 5, 3], # (optional) use integer or arrayref (unable to use with ArrayHashRef)
|
||||
SelectedValue => 'test', # (optional) use string or arrayref (unable to use with ArrayHashRef)
|
||||
Sort => 'NumericValue', # (optional) (AlphanumericValue|NumericValue|AlphanumericKey|NumericKey|TreeView) unable to use with ArrayHashRef
|
||||
SortReverse => 0, # (optional) reverse the list
|
||||
Translation => 1, # (optional) default 1 (0|1) translate value
|
||||
PossibleNone => 0, # (optional) default 0 (0|1) add a leading empty selection
|
||||
Max => 100, # (optional) default 100 max size of the shown value
|
||||
],
|
||||
[
|
||||
# ...
|
||||
]
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub BuildSelectionJSON {
|
||||
my ( $Self, $Array ) = @_;
|
||||
my %DataHash;
|
||||
|
||||
for my $Data ( @{$Array} ) {
|
||||
my %Param = %{$Data};
|
||||
|
||||
# log object
|
||||
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
|
||||
|
||||
# check needed stuff
|
||||
for (qw(Name)) {
|
||||
if ( !defined $Param{$_} ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $_!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !defined( $Param{Data} ) ) {
|
||||
if ( !$Param{PossibleNone} ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need Data!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
$DataHash{''} = '-';
|
||||
}
|
||||
elsif ( ref $Param{Data} eq '' ) {
|
||||
$DataHash{ $Param{Name} } = $Param{Data};
|
||||
}
|
||||
elsif ( defined $Param{KeepData} && $Param{KeepData} ) {
|
||||
$DataHash{ $Param{Name} } = $Param{Data};
|
||||
}
|
||||
else {
|
||||
|
||||
# create OptionRef
|
||||
my $OptionRef = $Self->_BuildSelectionOptionRefCreate(
|
||||
%Param,
|
||||
HTMLQuote => 0,
|
||||
);
|
||||
|
||||
# create AttributeRef
|
||||
my $AttributeRef = $Self->_BuildSelectionAttributeRefCreate(%Param);
|
||||
|
||||
# create DataRef
|
||||
my $DataRef = $Self->_BuildSelectionDataRefCreate(
|
||||
Data => $Param{Data},
|
||||
AttributeRef => $AttributeRef,
|
||||
OptionRef => $OptionRef,
|
||||
);
|
||||
|
||||
# create data structure
|
||||
if ( $AttributeRef && $DataRef ) {
|
||||
my @DataArray;
|
||||
for my $Row ( @{$DataRef} ) {
|
||||
my $Key = '';
|
||||
if ( defined $Row->{Key} ) {
|
||||
$Key = $Row->{Key};
|
||||
}
|
||||
my $Value = '';
|
||||
if ( defined $Row->{Value} ) {
|
||||
$Value = $Row->{Value};
|
||||
}
|
||||
|
||||
# DefaultSelected parameter for JavaScript New Option
|
||||
my $DefaultSelected = Kernel::System::JSON::False();
|
||||
|
||||
# to set a disabled option (Disabled is not included in JavaScript New Option)
|
||||
my $Disabled = Kernel::System::JSON::False();
|
||||
|
||||
if ( $Row->{Selected} ) {
|
||||
$DefaultSelected = Kernel::System::JSON::True();
|
||||
}
|
||||
elsif ( $Row->{Disabled} ) {
|
||||
$DefaultSelected = Kernel::System::JSON::False();
|
||||
$Disabled = Kernel::System::JSON::True();
|
||||
}
|
||||
|
||||
# Selected parameter for JavaScript NewOption
|
||||
my $Selected = $DefaultSelected;
|
||||
push @DataArray, [ $Key, $Value, $DefaultSelected, $Selected, $Disabled ];
|
||||
}
|
||||
$DataHash{ $AttributeRef->{name} } = \@DataArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $Self->JSONEncode(
|
||||
Data => \%DataHash,
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
572
Perl OTRS/Kernel/Output/HTML/Layout/Article.pm
Normal file
572
Perl OTRS/Kernel/Output/HTML/Layout/Article.pm
Normal file
@@ -0,0 +1,572 @@
|
||||
# --
|
||||
# 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::Layout::Article;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::Article - Helper functions for article rendering.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 ArticleFields()
|
||||
|
||||
Get article fields as returned by specific article backend.
|
||||
|
||||
my %ArticleFields = $LayoutObject->ArticleFields(
|
||||
TicketID => 123, # (required)
|
||||
ArticleID => 123, # (required)
|
||||
);
|
||||
|
||||
Returns article fields hash:
|
||||
|
||||
%ArticleFields = (
|
||||
Sender => { # mandatory
|
||||
Label => 'Sender',
|
||||
Value => 'John Smith',
|
||||
Prio => 100,
|
||||
},
|
||||
Subject => { # mandatory
|
||||
Label => 'Subject',
|
||||
Value => 'Message',
|
||||
Prio => 200,
|
||||
},
|
||||
...
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ArticleFields {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Check needed stuff.
|
||||
for my $Needed (qw(TicketID ArticleID)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $BackendObject = $Self->_BackendGet(%Param);
|
||||
|
||||
# Return backend response.
|
||||
return $BackendObject->ArticleFields(
|
||||
%Param,
|
||||
);
|
||||
}
|
||||
|
||||
=head2 ArticlePreview()
|
||||
|
||||
Get article content preview as returned by specific article backend.
|
||||
|
||||
my $ArticlePreview = $LayoutObject->ArticlePreview(
|
||||
TicketID => 123, # (required)
|
||||
ArticleID => 123, # (required)
|
||||
ResultType => 'plain', # (optional) plain|HTML, default: HTML
|
||||
MaxLength => 50, # (optional) performs trimming (for plain result only)
|
||||
);
|
||||
|
||||
Returns article preview in scalar form:
|
||||
|
||||
$ArticlePreview = 'Hello, world!';
|
||||
|
||||
=cut
|
||||
|
||||
sub ArticlePreview {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Check needed stuff.
|
||||
for my $Needed (qw(TicketID ArticleID)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $BackendObject = $Self->_BackendGet(%Param);
|
||||
|
||||
# Return backend response.
|
||||
return $BackendObject->ArticlePreview(
|
||||
%Param,
|
||||
);
|
||||
}
|
||||
|
||||
=head2 ArticleActions()
|
||||
|
||||
Get available article actions as returned by specific article backend.
|
||||
|
||||
my @Actions = $LayoutObject->ArticleActions(
|
||||
TicketID => 123, # (required)
|
||||
ArticleID => 123, # (required)
|
||||
);
|
||||
|
||||
Returns article action array:
|
||||
|
||||
@Actions = (
|
||||
{
|
||||
ItemType => 'Dropdown',
|
||||
DropdownType => 'Reply',
|
||||
StandardResponsesStrg => $StandardResponsesStrg,
|
||||
Name => 'Reply',
|
||||
Class => 'AsPopup PopupType_TicketAction',
|
||||
Action => 'AgentTicketCompose',
|
||||
FormID => 'Reply' . $Article{ArticleID},
|
||||
ResponseElementID => 'ResponseID',
|
||||
Type => $Param{Type},
|
||||
},
|
||||
{
|
||||
ItemType => 'Link',
|
||||
Description => 'Forward article via mail',
|
||||
Name => 'Forward',
|
||||
Class => 'AsPopup PopupType_TicketAction',
|
||||
Link =>
|
||||
"Action=AgentTicketForward;TicketID=$Ticket{TicketID};ArticleID=$Article{ArticleID}"
|
||||
},
|
||||
...
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ArticleActions {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Check needed stuff.
|
||||
for my $Needed (qw(TicketID ArticleID)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $BackendObject = $Self->_BackendGet(%Param);
|
||||
|
||||
# Return backend response.
|
||||
return $BackendObject->ArticleActions(
|
||||
%Param,
|
||||
UserID => $Self->{UserID},
|
||||
);
|
||||
}
|
||||
|
||||
=head2 ArticleCustomerRecipientsGet()
|
||||
|
||||
Get customer users from an article to use as recipients.
|
||||
|
||||
my @CustomerUserIDs = $LayoutObject->ArticleCustomerRecipientsGet(
|
||||
TicketID => 123, # (required)
|
||||
ArticleID => 123, # (required)
|
||||
);
|
||||
|
||||
Returns array of customer user IDs who should receive a message:
|
||||
|
||||
@CustomerUserIDs = (
|
||||
'customer-1',
|
||||
'customer-2',
|
||||
...
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ArticleCustomerRecipientsGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
for my $Needed (qw(TicketID ArticleID)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $BackendObject = $Self->_BackendGet(%Param);
|
||||
|
||||
# Return backend response.
|
||||
return $BackendObject->ArticleCustomerRecipientsGet(
|
||||
%Param,
|
||||
UserID => $Self->{UserID},
|
||||
);
|
||||
}
|
||||
|
||||
=head2 ArticleQuote()
|
||||
|
||||
get body and attach e. g. inline documents and/or attach all attachments to
|
||||
upload cache
|
||||
|
||||
for forward or split, get body and attach all attachments
|
||||
|
||||
my $HTMLBody = $LayoutObject->ArticleQuote(
|
||||
TicketID => 123,
|
||||
ArticleID => 123,
|
||||
FormID => $Self->{FormID},
|
||||
UploadCacheObject => $Self->{UploadCacheObject},
|
||||
AttachmentsInclude => 1,
|
||||
);
|
||||
|
||||
or just for including inline documents to upload cache
|
||||
|
||||
my $HTMLBody = $LayoutObject->ArticleQuote(
|
||||
TicketID => 123,
|
||||
ArticleID => 123,
|
||||
FormID => $Self->{FormID},
|
||||
UploadCacheObject => $Self->{UploadCacheObject},
|
||||
AttachmentsInclude => 0,
|
||||
);
|
||||
|
||||
Both will also work without rich text (if $ConfigObject->Get('Frontend::RichText')
|
||||
is false), return param will be text/plain instead.
|
||||
|
||||
=cut
|
||||
|
||||
sub ArticleQuote {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
for my $Needed (qw(TicketID ArticleID FormID UploadCacheObject)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Self->FatalError( Message => "Need $Needed!" );
|
||||
}
|
||||
}
|
||||
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
|
||||
my $ArticleBackendObject = $ArticleObject->BackendForArticle(
|
||||
ArticleID => $Param{ArticleID},
|
||||
TicketID => $Param{TicketID}
|
||||
);
|
||||
|
||||
# body preparation for plain text processing
|
||||
if ( $ConfigObject->Get('Frontend::RichText') ) {
|
||||
|
||||
my $Body = '';
|
||||
|
||||
my %NotInlineAttachments;
|
||||
|
||||
my %QuoteArticle = $ArticleBackendObject->ArticleGet(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
DynamicFields => 0,
|
||||
);
|
||||
|
||||
# Get the attachments without message bodies.
|
||||
$QuoteArticle{Atms} = {
|
||||
$ArticleBackendObject->ArticleAttachmentIndex(
|
||||
ArticleID => $Param{ArticleID},
|
||||
ExcludePlainText => 1,
|
||||
ExcludeHTMLBody => 1,
|
||||
)
|
||||
};
|
||||
|
||||
# Check if there is HTML body attachment.
|
||||
my %AttachmentIndexHTMLBody = $ArticleBackendObject->ArticleAttachmentIndex(
|
||||
ArticleID => $Param{ArticleID},
|
||||
OnlyHTMLBody => 1,
|
||||
);
|
||||
my ($HTMLBodyAttachmentID) = sort keys %AttachmentIndexHTMLBody;
|
||||
|
||||
if ($HTMLBodyAttachmentID) {
|
||||
my %AttachmentHTML = $ArticleBackendObject->ArticleAttachment(
|
||||
TicketID => $QuoteArticle{TicketID},
|
||||
ArticleID => $QuoteArticle{ArticleID},
|
||||
FileID => $HTMLBodyAttachmentID,
|
||||
);
|
||||
my $Charset = $AttachmentHTML{ContentType} || '';
|
||||
$Charset =~ s/.+?charset=("|'|)(\w+)/$2/gi;
|
||||
$Charset =~ s/"|'//g;
|
||||
$Charset =~ s/(.+?);.*/$1/g;
|
||||
|
||||
# convert html body to correct charset
|
||||
$Body = $Kernel::OM->Get('Kernel::System::Encode')->Convert(
|
||||
Text => $AttachmentHTML{Content},
|
||||
From => $Charset,
|
||||
To => $Self->{UserCharset},
|
||||
Check => 1,
|
||||
);
|
||||
|
||||
# get HTML utils object
|
||||
my $HTMLUtilsObject = $Kernel::OM->Get('Kernel::System::HTMLUtils');
|
||||
|
||||
# add url quoting
|
||||
$Body = $HTMLUtilsObject->LinkQuote(
|
||||
String => $Body,
|
||||
);
|
||||
|
||||
# strip head, body and meta elements
|
||||
$Body = $HTMLUtilsObject->DocumentStrip(
|
||||
String => $Body,
|
||||
);
|
||||
|
||||
# display inline images if exists
|
||||
my $SessionID = '';
|
||||
if ( $Self->{SessionID} && !$Self->{SessionIDCookie} ) {
|
||||
$SessionID = ';' . $Self->{SessionName} . '=' . $Self->{SessionID};
|
||||
}
|
||||
my $AttachmentLink = $Self->{Baselink}
|
||||
. 'Action=PictureUpload'
|
||||
. ';FormID='
|
||||
. $Param{FormID}
|
||||
. $SessionID
|
||||
. ';ContentID=';
|
||||
|
||||
# search inline documents in body and add it to upload cache
|
||||
my %Attachments = %{ $QuoteArticle{Atms} };
|
||||
my %AttachmentAlreadyUsed;
|
||||
$Body =~ s{
|
||||
(=|"|')cid:(.*?)("|'|>|\/>|\s)
|
||||
}
|
||||
{
|
||||
my $Start= $1;
|
||||
my $ContentID = $2;
|
||||
my $End = $3;
|
||||
|
||||
# improve html quality
|
||||
if ( $Start ne '"' && $Start ne '\'' ) {
|
||||
$Start .= '"';
|
||||
}
|
||||
if ( $End ne '"' && $End ne '\'' ) {
|
||||
$End = '"' . $End;
|
||||
}
|
||||
|
||||
# find attachment to include
|
||||
ATMCOUNT:
|
||||
for my $AttachmentID ( sort keys %Attachments ) {
|
||||
|
||||
if ( lc $Attachments{$AttachmentID}->{ContentID} ne lc "<$ContentID>" ) {
|
||||
next ATMCOUNT;
|
||||
}
|
||||
|
||||
# get whole attachment
|
||||
my %AttachmentPicture = $ArticleBackendObject->ArticleAttachment(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
FileID => $AttachmentID,
|
||||
);
|
||||
|
||||
# content id cleanup
|
||||
$AttachmentPicture{ContentID} =~ s/^<//;
|
||||
$AttachmentPicture{ContentID} =~ s/>$//;
|
||||
|
||||
# find cid, add attachment URL and remember, file is already uploaded
|
||||
$ContentID = $AttachmentLink . $Self->LinkEncode( $AttachmentPicture{ContentID} );
|
||||
|
||||
# add to upload cache if not uploaded and remember
|
||||
if (!$AttachmentAlreadyUsed{$AttachmentID}) {
|
||||
|
||||
# remember
|
||||
$AttachmentAlreadyUsed{$AttachmentID} = 1;
|
||||
|
||||
# write attachment to upload cache
|
||||
$Param{UploadCacheObject}->FormIDAddFile(
|
||||
FormID => $Param{FormID},
|
||||
Disposition => 'inline',
|
||||
%{ $Attachments{$AttachmentID} },
|
||||
%AttachmentPicture,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# return link
|
||||
$Start . $ContentID . $End;
|
||||
}egxi;
|
||||
|
||||
# find inline images using Content-Location instead of Content-ID
|
||||
ATTACHMENT:
|
||||
for my $AttachmentID ( sort keys %Attachments ) {
|
||||
|
||||
next ATTACHMENT if !$Attachments{$AttachmentID}->{ContentID};
|
||||
|
||||
# get whole attachment
|
||||
my %AttachmentPicture = $ArticleBackendObject->ArticleAttachment(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
FileID => $AttachmentID,
|
||||
);
|
||||
|
||||
# content id cleanup
|
||||
$AttachmentPicture{ContentID} =~ s/^<//;
|
||||
$AttachmentPicture{ContentID} =~ s/>$//;
|
||||
|
||||
$Body =~ s{
|
||||
("|')(\Q$AttachmentPicture{ContentID}\E)("|'|>|\/>|\s)
|
||||
}
|
||||
{
|
||||
my $Start= $1;
|
||||
my $ContentID = $2;
|
||||
my $End = $3;
|
||||
|
||||
# find cid, add attachment URL and remember, file is already uploaded
|
||||
$ContentID = $AttachmentLink . $Self->LinkEncode( $AttachmentPicture{ContentID} );
|
||||
|
||||
# add to upload cache if not uploaded and remember
|
||||
if (!$AttachmentAlreadyUsed{$AttachmentID}) {
|
||||
|
||||
# remember
|
||||
$AttachmentAlreadyUsed{$AttachmentID} = 1;
|
||||
|
||||
# write attachment to upload cache
|
||||
$Param{UploadCacheObject}->FormIDAddFile(
|
||||
FormID => $Param{FormID},
|
||||
Disposition => 'inline',
|
||||
%{ $Attachments{$AttachmentID} },
|
||||
%AttachmentPicture,
|
||||
);
|
||||
}
|
||||
|
||||
# return link
|
||||
$Start . $ContentID . $End;
|
||||
}egxi;
|
||||
}
|
||||
|
||||
# find not inline images
|
||||
ATTACHMENT:
|
||||
for my $AttachmentID ( sort keys %Attachments ) {
|
||||
next ATTACHMENT if $AttachmentAlreadyUsed{$AttachmentID};
|
||||
$NotInlineAttachments{$AttachmentID} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# attach also other attachments on article forward
|
||||
if ( $Body && $Param{AttachmentsInclude} ) {
|
||||
for my $AttachmentID ( sort keys %NotInlineAttachments ) {
|
||||
my %Attachment = $ArticleBackendObject->ArticleAttachment(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
FileID => $AttachmentID,
|
||||
);
|
||||
|
||||
# add attachment
|
||||
$Param{UploadCacheObject}->FormIDAddFile(
|
||||
FormID => $Param{FormID},
|
||||
%Attachment,
|
||||
Disposition => 'attachment',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# Fallback for non-MIMEBase articles: get article HTML content if it exists.
|
||||
if ( !$Body ) {
|
||||
$Body = $Self->ArticlePreview(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
);
|
||||
}
|
||||
|
||||
return $Body if $Body;
|
||||
}
|
||||
|
||||
# as fallback use text body for quote
|
||||
my %Article = $ArticleBackendObject->ArticleGet(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
DynamicFields => 0,
|
||||
);
|
||||
|
||||
# check if original content isn't text/plain or text/html, don't use it
|
||||
if ( !$Article{ContentType} ) {
|
||||
$Article{ContentType} = 'text/plain';
|
||||
}
|
||||
|
||||
if ( $Article{ContentType} !~ /text\/(plain|html)/i ) {
|
||||
$Article{Body} = '-> no quotable message <-';
|
||||
$Article{ContentType} = 'text/plain';
|
||||
}
|
||||
else {
|
||||
$Article{Body} = $Self->WrapPlainText(
|
||||
MaxCharacters => $ConfigObject->Get('Ticket::Frontend::TextAreaEmail') || 82,
|
||||
PlainText => $Article{Body},
|
||||
);
|
||||
}
|
||||
|
||||
# attach attachments
|
||||
if ( $Param{AttachmentsInclude} ) {
|
||||
my %ArticleIndex = $ArticleBackendObject->ArticleAttachmentIndex(
|
||||
ArticleID => $Param{ArticleID},
|
||||
ExcludePlainText => 1,
|
||||
ExcludeHTMLBody => 1,
|
||||
);
|
||||
for my $Index ( sort keys %ArticleIndex ) {
|
||||
my %Attachment = $ArticleBackendObject->ArticleAttachment(
|
||||
TicketID => $Param{TicketID},
|
||||
ArticleID => $Param{ArticleID},
|
||||
FileID => $Index,
|
||||
);
|
||||
|
||||
# add attachment
|
||||
$Param{UploadCacheObject}->FormIDAddFile(
|
||||
FormID => $Param{FormID},
|
||||
%Attachment,
|
||||
Disposition => 'attachment',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# return body as html
|
||||
if ( $ConfigObject->Get('Frontend::RichText') ) {
|
||||
|
||||
$Article{Body} = $Self->Ascii2Html(
|
||||
Text => $Article{Body},
|
||||
HTMLResultMode => 1,
|
||||
LinkFeature => 1,
|
||||
);
|
||||
}
|
||||
|
||||
# return body as plain text
|
||||
return $Article{Body};
|
||||
}
|
||||
|
||||
sub _BackendGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Check needed stuff.
|
||||
for my $Needed (qw(TicketID ArticleID)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $ArticleBackendObject = $Kernel::OM->Get('Kernel::System::Ticket::Article')->BackendForArticle(%Param);
|
||||
|
||||
# Determine channel name for this article.
|
||||
my $ChannelName = $ArticleBackendObject->ChannelNameGet();
|
||||
|
||||
my $Loaded = $Kernel::OM->Get('Kernel::System::Main')->Require(
|
||||
"Kernel::Output::HTML::Article::$ChannelName",
|
||||
);
|
||||
return if !$Loaded;
|
||||
|
||||
return $Kernel::OM->Get("Kernel::Output::HTML::Article::$ChannelName");
|
||||
}
|
||||
|
||||
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
|
||||
209
Perl OTRS/Kernel/Output/HTML/Layout/CustomerUser.pm
Normal file
209
Perl OTRS/Kernel/Output/HTML/Layout/CustomerUser.pm
Normal file
@@ -0,0 +1,209 @@
|
||||
# --
|
||||
# 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::Layout::CustomerUser;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::System::VariableCheck qw(:all);
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::CustomerUser - all CustomerUser related HTML functions
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 CustomerUserAddressBookListShow()
|
||||
|
||||
Returns a list of customer user as sort-able list with pagination.
|
||||
|
||||
This function is similar to L<Kernel::Output::HTML::Layout::CustomerUser::CustomerUserAddressBookListShow()>
|
||||
in F<Kernel/Output/HTML/Layout/CustomerUser.pm>.
|
||||
|
||||
my $Output = $LayoutObject->CustomerUserAddressBookListShow(
|
||||
CustomerUserIDs => $CustomerUserIDsRef, # total list of customer user ids, that can be listed
|
||||
Total => scalar @{ $CustomerUserIDsRef }, # total number of customer user ids
|
||||
View => $Self->{View}, # optional, the default value is 'AddressBook'
|
||||
Filter => 'All',
|
||||
Filters => \%NavBarFilter,
|
||||
LinkFilter => $LinkFilter,
|
||||
TitleName => 'Overview: CustomerUsers',
|
||||
TitleValue => $Self->{Filter},
|
||||
Env => $Self,
|
||||
LinkPage => $LinkPage,
|
||||
LinkSort => $LinkSort,
|
||||
Frontend => 'Agent', # optional (Agent|Customer), default: Agent, indicates from which frontend this function was called
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub CustomerUserAddressBookListShow {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# Take object ref to local, remove it from %Param (prevent memory leak).
|
||||
my $Env = delete $Param{Env};
|
||||
|
||||
my $Frontend = $Param{Frontend} || 'Agent';
|
||||
|
||||
# Set defaut view mode to 'AddressBook'.
|
||||
my $View = $Param{View} || 'AddressBook';
|
||||
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# get backend from config
|
||||
my $Backends = $ConfigObject->Get('CustomerUser::Frontend::Overview');
|
||||
if ( !$Backends ) {
|
||||
return $Self->FatalError(
|
||||
Message => 'Need config option CustomerUser::Frontend::Overview',
|
||||
);
|
||||
}
|
||||
|
||||
# check for hash-ref
|
||||
if ( ref $Backends ne 'HASH' ) {
|
||||
return $Self->FatalError(
|
||||
Message => 'Config option CustomerUser::Frontend::Overview needs to be a HASH ref!',
|
||||
);
|
||||
}
|
||||
|
||||
# check for config key
|
||||
if ( !$Backends->{$View} ) {
|
||||
return $Self->FatalError(
|
||||
Message => "No config option found for the view '$View'!",
|
||||
);
|
||||
}
|
||||
|
||||
# nav bar
|
||||
my $StartHit = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam(
|
||||
Param => 'StartHit',
|
||||
) || 1;
|
||||
|
||||
# get personal page shown count
|
||||
my $PageShown = $ConfigObject->Get("CustomerUser::Frontend::$Self->{Action}")->{PageShown} || 100;
|
||||
|
||||
# check start option, if higher then elements available, set
|
||||
# it to the last overview page (Thanks to Stefan Schmidt!)
|
||||
if ( $StartHit > $Param{Total} ) {
|
||||
my $Pages = int( ( $Param{Total} / $PageShown ) + 0.99999 );
|
||||
$StartHit = ( ( $Pages - 1 ) * $PageShown ) + 1;
|
||||
}
|
||||
|
||||
# set page limit and build page nav
|
||||
my $Limit = $Param{Limit} || 20_000;
|
||||
my %PageNav = $Self->PageNavBar(
|
||||
Limit => $Limit,
|
||||
StartHit => $StartHit,
|
||||
PageShown => $PageShown,
|
||||
AllHits => $Param{Total} || 0,
|
||||
Action => 'Action=' . $Self->{Action},
|
||||
Link => $Param{LinkPage},
|
||||
);
|
||||
|
||||
# build navbar content
|
||||
$Self->Block(
|
||||
Name => 'OverviewNavBar',
|
||||
Data => \%Param,
|
||||
);
|
||||
|
||||
# back link
|
||||
if ( $Param{LinkBack} ) {
|
||||
$Self->Block(
|
||||
Name => 'OverviewNavBarPageBack',
|
||||
Data => \%Param,
|
||||
);
|
||||
}
|
||||
|
||||
# check if page nav is available
|
||||
if (%PageNav) {
|
||||
$Self->Block(
|
||||
Name => 'OverviewNavBarPageNavBar',
|
||||
Data => \%PageNav,
|
||||
);
|
||||
|
||||
# don't show context settings in AJAX case (e. g. in customer ticket history),
|
||||
# because the submit with page reload will not work there
|
||||
if ( !$Param{AJAX} ) {
|
||||
$Self->Block(
|
||||
Name => 'ContextSettings',
|
||||
Data => {
|
||||
%PageNav,
|
||||
%Param,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# build html content
|
||||
my $OutputNavBar = $Self->Output(
|
||||
TemplateFile => 'AgentCustomerUserAddressBookOverviewNavBar',
|
||||
Data => {%Param},
|
||||
);
|
||||
|
||||
# create output
|
||||
my $OutputRaw = '';
|
||||
if ( !$Param{Output} ) {
|
||||
$Self->Print(
|
||||
Output => \$OutputNavBar,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$OutputRaw .= $OutputNavBar;
|
||||
}
|
||||
|
||||
# load module
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require( $Backends->{$View}->{Module} ) ) {
|
||||
return $Self->FatalError();
|
||||
}
|
||||
|
||||
# check for backend object
|
||||
my $Object = $Backends->{$View}->{Module}->new( %{$Env} );
|
||||
return if !$Object;
|
||||
|
||||
# run module
|
||||
my $Output = $Object->Run(
|
||||
%Param,
|
||||
Limit => $Limit,
|
||||
StartHit => $StartHit,
|
||||
PageShown => $PageShown,
|
||||
AllHits => $Param{Total} || 0,
|
||||
Frontend => $Frontend,
|
||||
);
|
||||
|
||||
# create output
|
||||
if ( !$Param{Output} ) {
|
||||
$Self->Print(
|
||||
Output => \$Output,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$OutputRaw .= $Output;
|
||||
}
|
||||
|
||||
# create overview nav bar
|
||||
$Self->Block(
|
||||
Name => 'OverviewNavBar',
|
||||
Data => {%Param},
|
||||
);
|
||||
|
||||
# return content if available
|
||||
return $OutputRaw;
|
||||
}
|
||||
|
||||
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
|
||||
85
Perl OTRS/Kernel/Output/HTML/Layout/Datepicker.pm
Normal file
85
Perl OTRS/Kernel/Output/HTML/Layout/Datepicker.pm
Normal file
@@ -0,0 +1,85 @@
|
||||
# --
|
||||
# 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::Layout::Datepicker;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::Datepicker - Datepicker data
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All valid functions.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 DatepickerGetVacationDays()
|
||||
|
||||
Returns a hash of all vacation days defined in the system.
|
||||
|
||||
$LayoutObject->DatepickerGetVacationDays();
|
||||
|
||||
=cut
|
||||
|
||||
sub DatepickerGetVacationDays {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# get the defined vacation days
|
||||
my $TimeVacationDays = $ConfigObject->Get('TimeVacationDays');
|
||||
my $TimeVacationDaysOneTime = $ConfigObject->Get('TimeVacationDaysOneTime');
|
||||
if ( $Param{Calendar} ) {
|
||||
if ( $ConfigObject->Get( "TimeZone::Calendar" . $Param{Calendar} . "Name" ) ) {
|
||||
$TimeVacationDays = $ConfigObject->Get( "TimeVacationDays::Calendar" . $Param{Calendar} );
|
||||
$TimeVacationDaysOneTime = $ConfigObject->Get(
|
||||
"TimeVacationDaysOneTime::Calendar" . $Param{Calendar}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# translate the vacation description if possible
|
||||
for my $Month ( sort keys %{$TimeVacationDays} ) {
|
||||
for my $Day ( sort keys %{ $TimeVacationDays->{$Month} } ) {
|
||||
$TimeVacationDays->{$Month}->{$Day}
|
||||
= $Self->{LanguageObject}->Translate( $TimeVacationDays->{$Month}->{$Day} );
|
||||
}
|
||||
}
|
||||
|
||||
for my $Year ( sort keys %{$TimeVacationDaysOneTime} ) {
|
||||
for my $Month ( sort keys %{ $TimeVacationDaysOneTime->{$Year} } ) {
|
||||
for my $Day ( sort keys %{ $TimeVacationDaysOneTime->{$Year}->{$Month} } ) {
|
||||
$TimeVacationDaysOneTime->{$Year}->{$Month}->{$Day} = $Self->{LanguageObject}->Translate(
|
||||
$TimeVacationDaysOneTime->{$Year}->{$Month}->{$Day}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
'TimeVacationDays' => $TimeVacationDays,
|
||||
'TimeVacationDaysOneTime' => $TimeVacationDaysOneTime,
|
||||
};
|
||||
}
|
||||
|
||||
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
|
||||
1151
Perl OTRS/Kernel/Output/HTML/Layout/FAQ.pm
Normal file
1151
Perl OTRS/Kernel/Output/HTML/Layout/FAQ.pm
Normal file
File diff suppressed because it is too large
Load Diff
1107
Perl OTRS/Kernel/Output/HTML/Layout/ITSMChange.pm
Normal file
1107
Perl OTRS/Kernel/Output/HTML/Layout/ITSMChange.pm
Normal file
File diff suppressed because it is too large
Load Diff
737
Perl OTRS/Kernel/Output/HTML/Layout/ITSMConfigItem.pm
Normal file
737
Perl OTRS/Kernel/Output/HTML/Layout/ITSMConfigItem.pm
Normal file
@@ -0,0 +1,737 @@
|
||||
# --
|
||||
# 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::Layout::ITSMConfigItem;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::ITSMConfigItem - all ConfigItem-related HTML functions
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All ITSM Configuration Management-related HTML functions
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 ITSMConfigItemOutputStringCreate()
|
||||
|
||||
returns an output string
|
||||
|
||||
my $String = $LayoutObject->ITSMConfigItemOutputStringCreate(
|
||||
Value => 11, # (optional)
|
||||
Item => $ItemRef,
|
||||
Print => 1, # (optional, default 0)
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMConfigItemOutputStringCreate {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
if ( !$Param{Item} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Item!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ITSMLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return '' if !$BackendObject;
|
||||
|
||||
# generate output string
|
||||
my $String = $BackendObject->OutputStringCreate(%Param);
|
||||
|
||||
return $String;
|
||||
}
|
||||
|
||||
=head2 ITSMConfigItemFormDataGet()
|
||||
|
||||
returns the values from the html form as hash reference
|
||||
|
||||
my $FormDataRef = $LayoutObject->ITSMConfigItemFormDataGet(
|
||||
Key => 'Item::1::Node::3',
|
||||
Item => $ItemRef,
|
||||
ConfigItemID => 123,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMConfigItemFormDataGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for my $Argument (qw(Key Item ConfigItemID)) {
|
||||
if ( !$Param{$Argument} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Argument!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ITSMLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return {} if !$BackendObject;
|
||||
|
||||
# get form data
|
||||
my $FormData = $BackendObject->FormDataGet(%Param);
|
||||
|
||||
return $FormData;
|
||||
}
|
||||
|
||||
=head2 ITSMConfigItemInputCreate()
|
||||
|
||||
returns a input field html string
|
||||
|
||||
my $String = $LayoutObject->ITSMConfigItemInputCreate(
|
||||
Key => 'Item::1::Node::3',
|
||||
Value => 11, # (optional)
|
||||
Item => $ItemRef,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMConfigItemInputCreate {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for my $Argument (qw(Key Item)) {
|
||||
if ( !$Param{$Argument} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Argument!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ITSMLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return '' if !$BackendObject;
|
||||
|
||||
# lookup item value
|
||||
my $String = $BackendObject->InputCreate(%Param);
|
||||
|
||||
return $String;
|
||||
}
|
||||
|
||||
=head2 ITSMConfigItemSearchFormDataGet()
|
||||
|
||||
returns the values from the search html form
|
||||
|
||||
my $ArrayRef = $LayoutObject->ITSMConfigItemSearchFormDataGet(
|
||||
Key => 'Item::1::Node::3',
|
||||
Item => $ItemRef,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMConfigItemSearchFormDataGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for my $Argument (qw(Key Item)) {
|
||||
if ( !$Param{$Argument} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Argument!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ITSMLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return [] if !$BackendObject;
|
||||
|
||||
# get form data
|
||||
my $Values = $BackendObject->SearchFormDataGet(%Param);
|
||||
|
||||
return $Values;
|
||||
}
|
||||
|
||||
=head2 ITSMConfigItemSearchInputCreate()
|
||||
|
||||
returns a search input field html string
|
||||
|
||||
my $String = $LayoutObject->ITSMConfigItemSearchInputCreate(
|
||||
Key => 'Item::1::Node::3',
|
||||
Item => $ItemRef,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMConfigItemSearchInputCreate {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for my $Argument (qw(Key Item)) {
|
||||
if ( !$Param{$Argument} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Argument!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ITSMLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return '' if !$BackendObject;
|
||||
|
||||
# lookup item value
|
||||
my $String = $BackendObject->SearchInputCreate(%Param);
|
||||
|
||||
return $String;
|
||||
}
|
||||
|
||||
=head2 _ITSMLoadLayoutBackend()
|
||||
|
||||
load a input type backend module
|
||||
|
||||
$BackendObject = $LayoutObject->_ITSMLoadLayoutBackend(
|
||||
Type => 'GeneralCatalog',
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub _ITSMLoadLayoutBackend {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get log object
|
||||
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
|
||||
|
||||
if ( !$Param{Type} ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Type!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
my $GenericModule = "Kernel::Output::HTML::ITSMConfigItem::Layout$Param{Type}";
|
||||
|
||||
# load the backend module
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require($GenericModule) ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Can't load backend module $Param{Type}!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# create new instance
|
||||
my $BackendObject = $GenericModule->new(
|
||||
%{$Self},
|
||||
%Param,
|
||||
LayoutObject => $Self,
|
||||
);
|
||||
|
||||
if ( !$BackendObject ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Can't create a new instance of backend module $Param{Type}!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return $BackendObject;
|
||||
}
|
||||
|
||||
=head2 ITSMConfigItemListShow()
|
||||
|
||||
Returns a list of configuration items with sort and pagination capabilities.
|
||||
|
||||
This function is similar to L<Kernel::Output::HTML::LayoutTicket::TicketListShow()>
|
||||
in F<Kernel/Output/HTML/LayoutTicket.pm>.
|
||||
|
||||
my $Output = $LayoutObject->ITSMConfigItemListShow(
|
||||
ConfigItemIDs => $ConfigItemIDsRef, # total list of config item ids, that can be listed
|
||||
Total => scalar @{ $ConfigItemIDsRef }, # total number of list items, config items in this case
|
||||
View => $Self->{View}, # optional, the default value is 'Small'
|
||||
Filter => 'All',
|
||||
Filters => \%NavBarFilter,
|
||||
FilterLink => $LinkFilter,
|
||||
TitleName => 'Overview: Config Item: Computer',
|
||||
TitleValue => $Self->{Filter},
|
||||
Env => $Self,
|
||||
LinkPage => $LinkPage,
|
||||
LinkSort => $LinkSort,
|
||||
Frontend => 'Agent', # optional (Agent|Customer), default: Agent, indicates from which frontend this function was called
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMConfigItemListShow {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# take object ref to local, remove it from %Param (prevent memory leak)
|
||||
my $Env = delete $Param{Env};
|
||||
|
||||
# lookup latest used view mode
|
||||
if ( !$Param{View} && $Self->{ 'UserITSMConfigItemOverview' . $Env->{Action} } ) {
|
||||
$Param{View} = $Self->{ 'UserITSMConfigItemOverview' . $Env->{Action} };
|
||||
}
|
||||
|
||||
# set frontend
|
||||
my $Frontend = $Param{Frontend} || 'Agent';
|
||||
|
||||
# set defaut view mode to 'small'
|
||||
my $View = $Param{View} || 'Small';
|
||||
|
||||
# store latest view mode
|
||||
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
|
||||
SessionID => $Self->{SessionID},
|
||||
Key => 'UserITSMConfigItemOverview' . $Env->{Action},
|
||||
Value => $View,
|
||||
);
|
||||
|
||||
# get needed objects
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
|
||||
|
||||
# get backend from config
|
||||
my $Backends = $ConfigObject->Get('ITSMConfigItem::Frontend::Overview');
|
||||
if ( !$Backends ) {
|
||||
return $LayoutObject->FatalError(
|
||||
Message => 'Need config option ITSMConfigItem::Frontend::Overview',
|
||||
);
|
||||
}
|
||||
|
||||
# check for hash-ref
|
||||
if ( ref $Backends ne 'HASH' ) {
|
||||
return $LayoutObject->FatalError(
|
||||
Message => 'Config option ITSMConfigItem::Frontend::Overview needs to be a HASH ref!',
|
||||
);
|
||||
}
|
||||
|
||||
# check for config key
|
||||
if ( !$Backends->{$View} ) {
|
||||
return $LayoutObject->FatalError(
|
||||
Message => "No config option found for the view '$View'!",
|
||||
);
|
||||
}
|
||||
|
||||
# nav bar
|
||||
my $StartHit = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam(
|
||||
Param => 'StartHit',
|
||||
) || 1;
|
||||
|
||||
# get personal page shown count
|
||||
my $PageShownPreferencesKey = 'UserConfigItemOverview' . $View . 'PageShown';
|
||||
my $PageShown = $Self->{$PageShownPreferencesKey} || 10;
|
||||
my $Group = 'ConfigItemOverview' . $View . 'PageShown';
|
||||
|
||||
# check start option, if higher then elements available, set
|
||||
# it to the last overview page (Thanks to Stefan Schmidt!)
|
||||
if ( $StartHit > $Param{Total} ) {
|
||||
my $Pages = int( ( $Param{Total} / $PageShown ) + 0.99999 );
|
||||
$StartHit = ( ( $Pages - 1 ) * $PageShown ) + 1;
|
||||
}
|
||||
|
||||
# get data selection
|
||||
my %Data;
|
||||
my $Config = $ConfigObject->Get('PreferencesGroups');
|
||||
if ( $Config && $Config->{$Group} && $Config->{$Group}->{Data} ) {
|
||||
%Data = %{ $Config->{$Group}->{Data} };
|
||||
}
|
||||
|
||||
# set page limit and build page nav
|
||||
my $Limit = $Param{Limit} || 20_000;
|
||||
my %PageNav = $LayoutObject->PageNavBar(
|
||||
Limit => $Limit,
|
||||
StartHit => $StartHit,
|
||||
PageShown => $PageShown,
|
||||
AllHits => $Param{Total} || 0,
|
||||
Action => 'Action=' . $Env->{Action},
|
||||
Link => $Param{LinkPage},
|
||||
);
|
||||
|
||||
# build shown ticket a page
|
||||
$Param{RequestedURL} = $Param{RequestedURL} || "Action=$Self->{Action};$Param{LinkPage}";
|
||||
$Param{Group} = $Group;
|
||||
$Param{PreferencesKey} = $PageShownPreferencesKey;
|
||||
$Param{PageShownString} = $Self->BuildSelection(
|
||||
Name => $PageShownPreferencesKey,
|
||||
SelectedID => $PageShown,
|
||||
Data => \%Data,
|
||||
Translation => 0,
|
||||
Sort => 'NumericValue',
|
||||
Class => 'Modernize',
|
||||
);
|
||||
|
||||
# build navbar content
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBar',
|
||||
Data => \%Param,
|
||||
);
|
||||
|
||||
# back link
|
||||
if ( $Param{LinkBack} ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarPageBack',
|
||||
Data => \%Param,
|
||||
);
|
||||
|
||||
$LayoutObject->AddJSData(
|
||||
Key => 'ITSMConfigItemSearch',
|
||||
Value => {
|
||||
Profile => $Param{Profile},
|
||||
ClassID => $Param{ClassID},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
# get filters
|
||||
if ( $Param{Filters} ) {
|
||||
|
||||
# get given filters
|
||||
my @NavBarFilters;
|
||||
for my $Prio ( sort keys %{ $Param{Filters} } ) {
|
||||
push @NavBarFilters, $Param{Filters}->{$Prio};
|
||||
}
|
||||
|
||||
# build filter content
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilter',
|
||||
Data => {
|
||||
%Param,
|
||||
},
|
||||
);
|
||||
|
||||
# loop over filters
|
||||
my $Count = 0;
|
||||
for my $Filter (@NavBarFilters) {
|
||||
|
||||
# increment filter count and build filter item
|
||||
$Count++;
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilterItem',
|
||||
Data => {
|
||||
%Param,
|
||||
%{$Filter},
|
||||
},
|
||||
);
|
||||
|
||||
# filter is selected
|
||||
if ( $Filter->{Filter} eq $Param{Filter} ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilterItemSelected',
|
||||
Data => {
|
||||
%Param,
|
||||
%{$Filter},
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilterItemSelectedNot',
|
||||
Data => {
|
||||
%Param,
|
||||
%{$Filter},
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# loop over configured backends
|
||||
for my $Backend ( sort keys %{$Backends} ) {
|
||||
|
||||
# build navbar view mode
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarViewMode',
|
||||
Data => {
|
||||
%Param,
|
||||
%{ $Backends->{$Backend} },
|
||||
Filter => $Param{Filter},
|
||||
View => $Backend,
|
||||
},
|
||||
);
|
||||
|
||||
# current view is configured in backend
|
||||
if ( $View eq $Backend ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarViewModeSelected',
|
||||
Data => {
|
||||
%Param,
|
||||
%{ $Backends->{$Backend} },
|
||||
Filter => $Param{Filter},
|
||||
View => $Backend,
|
||||
},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarViewModeNotSelected',
|
||||
Data => {
|
||||
%Param,
|
||||
%{ $Backends->{$Backend} },
|
||||
Filter => $Param{Filter},
|
||||
View => $Backend,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# check if page nav is available
|
||||
if (%PageNav) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarPageNavBar',
|
||||
Data => \%PageNav,
|
||||
);
|
||||
|
||||
# don't show context settings in AJAX case (e. g. in customer ticket history),
|
||||
# because the submit with page reload will not work there
|
||||
if ( !$Param{AJAX} ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'ContextSettings',
|
||||
Data => {
|
||||
%PageNav,
|
||||
%Param,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# check if bulk feature is enabled
|
||||
my $BulkFeature = 0;
|
||||
if ( $ConfigObject->Get('ITSMConfigItem::Frontend::BulkFeature') ) {
|
||||
my @Groups;
|
||||
if ( $ConfigObject->Get('ITSMConfigItem::Frontend::BulkFeatureGroup') ) {
|
||||
@Groups = @{ $ConfigObject->Get('ITSMConfigItem::Frontend::BulkFeatureGroup') };
|
||||
}
|
||||
if ( !@Groups ) {
|
||||
$BulkFeature = 1;
|
||||
}
|
||||
else {
|
||||
GROUP:
|
||||
for my $Group (@Groups) {
|
||||
next GROUP if !$Kernel::OM->Get('Kernel::System::Group')->PermissionCheck(
|
||||
UserID => $Self->{UserID},
|
||||
GroupName => $Group,
|
||||
Type => 'rw',
|
||||
);
|
||||
|
||||
$BulkFeature = 1;
|
||||
last GROUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# show the bulk action button if feature is enabled
|
||||
if ($BulkFeature) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'BulkAction',
|
||||
Data => {
|
||||
%PageNav,
|
||||
%Param,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
# build html content
|
||||
my $OutputNavBar = $LayoutObject->Output(
|
||||
TemplateFile => 'AgentITSMConfigItemOverviewNavBar',
|
||||
Data => {%Param},
|
||||
);
|
||||
|
||||
# create output
|
||||
my $OutputRaw = '';
|
||||
if ( !$Param{Output} ) {
|
||||
$LayoutObject->Print(
|
||||
Output => \$OutputNavBar,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$OutputRaw .= $OutputNavBar;
|
||||
}
|
||||
|
||||
# load module
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require( $Backends->{$View}->{Module} ) ) {
|
||||
return $LayoutObject->FatalError();
|
||||
}
|
||||
|
||||
# check for backend object
|
||||
my $Object = $Backends->{$View}->{Module}->new( %{$Env} );
|
||||
return if !$Object;
|
||||
|
||||
# run module
|
||||
my $Output = $Object->Run(
|
||||
%Param,
|
||||
Limit => $Limit,
|
||||
StartHit => $StartHit,
|
||||
PageShown => $PageShown,
|
||||
AllHits => $Param{Total} || 0,
|
||||
Frontend => $Frontend,
|
||||
);
|
||||
|
||||
# create output
|
||||
if ( !$Param{Output} ) {
|
||||
$LayoutObject->Print(
|
||||
Output => \$Output,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$OutputRaw .= $Output;
|
||||
}
|
||||
|
||||
# create overview nav bar
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBar',
|
||||
Data => {%Param},
|
||||
);
|
||||
|
||||
# return content if available
|
||||
return $OutputRaw;
|
||||
}
|
||||
|
||||
=head2 XMLData2Hash()
|
||||
|
||||
returns a hash reference with the requested attributes data for a config item
|
||||
|
||||
Return
|
||||
|
||||
$Data = {
|
||||
'HardDisk::2' => {
|
||||
Value => 'HD2',
|
||||
Name => 'Hard Disk',
|
||||
},
|
||||
'CPU::1' => {
|
||||
Value => '',
|
||||
Name => 'CPU',
|
||||
},
|
||||
'HardDisk::2::Capacity::1' => {
|
||||
Value => '780 GB',
|
||||
Name => 'Capacity',
|
||||
},
|
||||
};
|
||||
|
||||
my $Data = $LayoutObject->XMLData2Hash(
|
||||
XMLDefinition => $Version->{XMLDefinition},
|
||||
XMLData => $Version->{XMLData}->[1]->{Version}->[1],
|
||||
Attributes => ['CPU::1', 'HardDrive::2::Capacity::1', ...],
|
||||
Data => \%DataHashRef, # optional
|
||||
Prefix => 'HardDisk::1', # optional
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub XMLData2Hash {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
return if !$Param{XMLData};
|
||||
return if !$Param{XMLDefinition};
|
||||
return if !$Param{Attributes};
|
||||
return if ref $Param{XMLData} ne 'HASH';
|
||||
return if ref $Param{XMLDefinition} ne 'ARRAY';
|
||||
return if ref $Param{Attributes} ne 'ARRAY';
|
||||
|
||||
# to store the return data
|
||||
my $Data = $Param{Data} || {};
|
||||
|
||||
# create a lookup structure
|
||||
my %RelevantAttributes = map { $_ => 1 } @{ $Param{Attributes} };
|
||||
|
||||
ITEM:
|
||||
for my $Item ( @{ $Param{XMLDefinition} } ) {
|
||||
|
||||
my $CountMax = $Item->{CountMax} || 1;
|
||||
|
||||
COUNTER:
|
||||
for my $Counter ( 1 .. $CountMax ) {
|
||||
|
||||
# add prefix
|
||||
my $Prefix = $Item->{Key} . '::' . $Counter;
|
||||
if ( $Param{Prefix} ) {
|
||||
$Prefix = $Param{Prefix} . '::' . $Prefix;
|
||||
}
|
||||
|
||||
# skip not needed elements and sub elements
|
||||
next COUNTER if !grep { $_ =~ m{\A$Prefix} } @{ $Param{Attributes} };
|
||||
|
||||
# lookup value
|
||||
my $Value = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->XMLValueLookup(
|
||||
Item => $Item,
|
||||
Value => $Param{XMLData}->{ $Item->{Key} }->[$Counter]->{Content} // '',
|
||||
);
|
||||
|
||||
# only if value is defined
|
||||
if ( defined $Value ) {
|
||||
|
||||
# create output string
|
||||
$Value = $Self->ITSMConfigItemOutputStringCreate(
|
||||
Value => $Value,
|
||||
Item => $Item,
|
||||
Print => $Param{Print},
|
||||
);
|
||||
}
|
||||
|
||||
if ( $RelevantAttributes{$Prefix} ) {
|
||||
|
||||
# store the item in hash
|
||||
$Data->{$Prefix} = {
|
||||
Name => $Item->{Name},
|
||||
Value => $Value // '',
|
||||
};
|
||||
}
|
||||
|
||||
# start recursion, if "Sub" was found
|
||||
if ( $Item->{Sub} ) {
|
||||
$Data = $Self->XMLData2Hash(
|
||||
XMLDefinition => $Item->{Sub},
|
||||
XMLData => $Param{XMLData}->{ $Item->{Key} }->[$Counter],
|
||||
Prefix => $Prefix,
|
||||
Data => $Data,
|
||||
Attributes => $Param{Attributes},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $Data;
|
||||
}
|
||||
|
||||
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
|
||||
285
Perl OTRS/Kernel/Output/HTML/Layout/ITSMTemplate.pm
Normal file
285
Perl OTRS/Kernel/Output/HTML/Layout/ITSMTemplate.pm
Normal file
@@ -0,0 +1,285 @@
|
||||
# --
|
||||
# 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::Layout::ITSMTemplate;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::Language qw(Translatable);
|
||||
use POSIX qw(ceil);
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head2 ITSMTemplateListShow()
|
||||
|
||||
Returns a list of templates as C<sortable> list with pagination.
|
||||
|
||||
This function is similar to L<Kernel::Output::HTML::Layout::ITSMChange::ITMChangeListShow()>
|
||||
in F<Kernel/Output/HTML/LayoutITSMChange.pm>.
|
||||
|
||||
my $Output = $LayoutObject->ITSMTemplateListShow(
|
||||
TemplateIDs => $TemplateIDsRef, # total list of template ids, that can be listed
|
||||
Total => scalar @{ $TemplateIDsRef }, # total number of list items, templates in this case
|
||||
Filter => 'All',
|
||||
Filters => \%NavBarFilter,
|
||||
FilterLink => $LinkFilter,
|
||||
TitleName => 'Overview: Template',
|
||||
TitleValue => $Self->{Filter},
|
||||
Env => $Self,
|
||||
LinkPage => $LinkPage,
|
||||
LinkSort => $LinkSort,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ITSMTemplateListShow {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# take object ref to local, remove it from %Param (prevent memory leak)
|
||||
my $Env = delete $Param{Env};
|
||||
|
||||
# for now there is only the 'Small' view
|
||||
my $View = 'Small';
|
||||
|
||||
# get layout object
|
||||
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
|
||||
|
||||
# get backend from config
|
||||
my $Backends = $Kernel::OM->Get('Kernel::Config')->Get('ITSMChange::Frontend::TemplateOverview');
|
||||
if ( !$Backends ) {
|
||||
return $LayoutObject->FatalError(
|
||||
Message => $LayoutObject->{LanguageObject}->Translate(
|
||||
'Need config option %s!',
|
||||
'ITSMChange::Frontend::TemplateOverview',
|
||||
),
|
||||
Comment => Translatable('Please contact the administrator.'),
|
||||
);
|
||||
}
|
||||
|
||||
# check for hash-ref
|
||||
if ( ref $Backends ne 'HASH' ) {
|
||||
return $LayoutObject->FatalError(
|
||||
Message => $LayoutObject->{LanguageObject}->Translate(
|
||||
'Config option %s needs to be a HASH ref!',
|
||||
'ITSMChange::Frontend::TemplateOverview',
|
||||
),
|
||||
Comment => Translatable('Please contact the administrator.'),
|
||||
);
|
||||
}
|
||||
|
||||
# check for config key
|
||||
if ( !$Backends->{$View} ) {
|
||||
return $LayoutObject->FatalError(
|
||||
Message => $LayoutObject->{LanguageObject}->Translate( 'No config option found for the view "%s"!', $View ),
|
||||
Comment => Translatable('Please contact the administrator.'),
|
||||
);
|
||||
}
|
||||
|
||||
# nav bar
|
||||
my $StartHit = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'StartHit' ) || 1;
|
||||
|
||||
# check start option, if higher then elements available, set
|
||||
# it to the last overview page (Thanks to Stefan Schmidt!)
|
||||
my $PageShown = $Backends->{$View}->{PageShown};
|
||||
if ( $StartHit > $Param{Total} ) {
|
||||
my $Pages = int( ( $Param{Total} / $PageShown ) + 0.99999 );
|
||||
$StartHit = ( ( $Pages - 1 ) * $PageShown ) + 1;
|
||||
}
|
||||
|
||||
# set page limit and build page nav
|
||||
my $Limit = $Param{Limit} || 20_000;
|
||||
my %PageNav = $LayoutObject->PageNavBar(
|
||||
Limit => $Limit,
|
||||
StartHit => $StartHit,
|
||||
PageShown => $PageShown,
|
||||
AllHits => $Param{Total} || 0,
|
||||
Action => 'Action=' . $LayoutObject->{Action},
|
||||
Link => $Param{LinkPage},
|
||||
);
|
||||
|
||||
# build navbar content
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBar',
|
||||
Data => \%Param,
|
||||
);
|
||||
|
||||
# back link
|
||||
if ( $Param{LinkBack} ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarPageBack',
|
||||
Data => \%Param,
|
||||
);
|
||||
}
|
||||
|
||||
# get filters
|
||||
if ( $Param{Filters} ) {
|
||||
|
||||
# get given filters
|
||||
my @NavBarFilters;
|
||||
for my $Prio ( sort keys %{ $Param{Filters} } ) {
|
||||
push @NavBarFilters, $Param{Filters}->{$Prio};
|
||||
}
|
||||
|
||||
# build filter content
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilter',
|
||||
Data => {
|
||||
%Param,
|
||||
},
|
||||
);
|
||||
|
||||
# loop over filters
|
||||
my $Count = 0;
|
||||
for my $Filter (@NavBarFilters) {
|
||||
|
||||
# increment filter count and build filter item
|
||||
$Count++;
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilterItem',
|
||||
Data => {
|
||||
%Param,
|
||||
%{$Filter},
|
||||
},
|
||||
);
|
||||
|
||||
# filter is selected
|
||||
if ( $Filter->{Filter} eq $Param{Filter} ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilterItemSelected',
|
||||
Data => {
|
||||
%Param,
|
||||
%{$Filter},
|
||||
},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarFilterItemSelectedNot',
|
||||
Data => {
|
||||
%Param,
|
||||
%{$Filter},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# loop over configured backends, when there is more than a single backend
|
||||
for my $Backend ( sort keys %{$Backends} ) {
|
||||
|
||||
# build navbar view mode
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarViewMode',
|
||||
Data => {
|
||||
%Param,
|
||||
%{ $Backends->{$Backend} },
|
||||
Filter => $Param{Filter},
|
||||
View => $Backend,
|
||||
},
|
||||
);
|
||||
|
||||
# current view is configured in backend
|
||||
if ( $View eq $Backend ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarViewModeSelected',
|
||||
Data => {
|
||||
%Param,
|
||||
%{ $Backends->{$Backend} },
|
||||
Filter => $Param{Filter},
|
||||
View => $Backend,
|
||||
},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarViewModeNotSelected',
|
||||
Data => {
|
||||
%Param,
|
||||
%{ $Backends->{$Backend} },
|
||||
Filter => $Param{Filter},
|
||||
View => $Backend,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# check if page nav is available
|
||||
if (%PageNav) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarPageNavBar',
|
||||
Data => \%PageNav,
|
||||
);
|
||||
}
|
||||
|
||||
# check if nav bar is available
|
||||
if ( $Param{NavBar} ) {
|
||||
if ( $Param{NavBar}->{MainName} ) {
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBarMain',
|
||||
Data => $Param{NavBar},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# build html content
|
||||
my $OutputNavBar = $LayoutObject->Output(
|
||||
TemplateFile => 'AgentITSMTemplateOverviewNavBar',
|
||||
Data => {%Param},
|
||||
);
|
||||
|
||||
# create output
|
||||
my $OutputRaw = '';
|
||||
if ( !$Param{Output} ) {
|
||||
$LayoutObject->Print(
|
||||
Output => \$OutputNavBar,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$OutputRaw .= $OutputNavBar;
|
||||
}
|
||||
|
||||
# load module
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require( $Backends->{$View}->{Module} ) ) {
|
||||
return $LayoutObject->FatalError();
|
||||
}
|
||||
|
||||
# check for backend object
|
||||
my $Object = $Backends->{$View}->{Module}->new( %{$Env} );
|
||||
return if !$Object;
|
||||
|
||||
# run module
|
||||
my $Output = $Object->Run(
|
||||
%Param,
|
||||
Limit => $Limit,
|
||||
StartHit => $StartHit,
|
||||
PageShown => $PageShown,
|
||||
AllHits => $Param{Total} || 0,
|
||||
);
|
||||
|
||||
# create output
|
||||
if ( !$Param{Output} ) {
|
||||
$LayoutObject->Print(
|
||||
Output => \$Output,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$OutputRaw .= $Output;
|
||||
}
|
||||
|
||||
# create overview nav bar
|
||||
$LayoutObject->Block(
|
||||
Name => 'OverviewNavBar',
|
||||
Data => {%Param},
|
||||
);
|
||||
|
||||
# return content if available
|
||||
return $OutputRaw;
|
||||
}
|
||||
|
||||
1;
|
||||
158
Perl OTRS/Kernel/Output/HTML/Layout/ImportExport.pm
Normal file
158
Perl OTRS/Kernel/Output/HTML/Layout/ImportExport.pm
Normal file
@@ -0,0 +1,158 @@
|
||||
# --
|
||||
# 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::Layout::ImportExport;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::ImportExport
|
||||
|
||||
=cut
|
||||
|
||||
=head2 ImportExportFormInputCreate()
|
||||
|
||||
Returns a input field html string
|
||||
|
||||
my $String = $LayoutObject->ImportExportFormInputCreate(
|
||||
Item => $ItemRef,
|
||||
Value => 'Value', # (optional)
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ImportExportFormInputCreate {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
if ( !$Param{Item} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Item!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ImportExportLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return '' if !$BackendObject;
|
||||
|
||||
# lookup item value
|
||||
my $String = $BackendObject->FormInputCreate(%Param);
|
||||
|
||||
return $String;
|
||||
}
|
||||
|
||||
=head2 ImportExportFormDataGet()
|
||||
|
||||
Returns the values from the html form as hash reference
|
||||
|
||||
my $FormData = $LayoutObject->ImportExportFormDataGet(
|
||||
Item => $ItemRef,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub ImportExportFormDataGet {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
if ( !$Param{Item} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Item!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# load backend
|
||||
my $BackendObject = $Self->_ImportExportLoadLayoutBackend(
|
||||
Type => $Param{Item}->{Input}->{Type},
|
||||
);
|
||||
|
||||
return if !$BackendObject;
|
||||
|
||||
# get form data
|
||||
my $FormData = $BackendObject->FormDataGet(%Param);
|
||||
|
||||
return $FormData;
|
||||
}
|
||||
|
||||
=head2 _ImportExportLoadLayoutBackend()
|
||||
|
||||
To load a import/export layout backend module
|
||||
|
||||
my $Backend = $LayoutObject->_ImportExportLoadLayoutBackend(
|
||||
Type => 'Selection',
|
||||
);
|
||||
|
||||
An instance of the loaded backend module is returned.
|
||||
|
||||
=cut
|
||||
|
||||
sub _ImportExportLoadLayoutBackend {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get log object
|
||||
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
|
||||
|
||||
if ( !$Param{Type} ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Type!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
my $GenericModule = "Kernel::Output::HTML::ImportExport::Layout$Param{Type}";
|
||||
|
||||
# load the backend module
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require($GenericModule) ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Can't load backend module $Param{Type}!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# create new instance
|
||||
my $BackendObject = $GenericModule->new(
|
||||
%{$Self},
|
||||
%Param,
|
||||
LayoutObject => $Self,
|
||||
);
|
||||
|
||||
if ( !$BackendObject ) {
|
||||
$LogObject->Log(
|
||||
Priority => 'error',
|
||||
Message => "Can't create a new instance of backend module $Param{Type}!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return $BackendObject;
|
||||
}
|
||||
|
||||
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
|
||||
1318
Perl OTRS/Kernel/Output/HTML/Layout/LinkObject.pm
Normal file
1318
Perl OTRS/Kernel/Output/HTML/Layout/LinkObject.pm
Normal file
File diff suppressed because it is too large
Load Diff
924
Perl OTRS/Kernel/Output/HTML/Layout/Loader.pm
Normal file
924
Perl OTRS/Kernel/Output/HTML/Layout/Loader.pm
Normal file
@@ -0,0 +1,924 @@
|
||||
# --
|
||||
# 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::Layout::Loader;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::stat;
|
||||
use Digest::MD5;
|
||||
|
||||
use Kernel::Language qw(Translatable);
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::Loader - CSS/JavaScript
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All valid functions.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 LoaderCreateAgentCSSCalls()
|
||||
|
||||
Generate the minified CSS files and the tags referencing them,
|
||||
taking a list from the Loader::Agent::CommonCSS config item.
|
||||
|
||||
$LayoutObject->LoaderCreateAgentCSSCalls(
|
||||
Skin => 'MySkin', # optional, if not provided skin is the configured by default
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub LoaderCreateAgentCSSCalls {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# get host based default skin configuration
|
||||
my $SkinSelectedHostBased;
|
||||
my $DefaultSkinHostBased = $ConfigObject->Get('Loader::Agent::DefaultSelectedSkin::HostBased');
|
||||
if ( $DefaultSkinHostBased && $ENV{HTTP_HOST} ) {
|
||||
REGEXP:
|
||||
for my $RegExp ( sort keys %{$DefaultSkinHostBased} ) {
|
||||
|
||||
# do not use empty regexp or skin directories
|
||||
next REGEXP if !$RegExp;
|
||||
next REGEXP if !$DefaultSkinHostBased->{$RegExp};
|
||||
|
||||
# check if regexp is matching
|
||||
if ( $ENV{HTTP_HOST} =~ /$RegExp/i ) {
|
||||
$SkinSelectedHostBased = $DefaultSkinHostBased->{$RegExp};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# determine skin
|
||||
# 1. use UserSkin setting from Agent preferences, if available
|
||||
# 2. use HostBased skin setting, if available
|
||||
# 3. use default skin from configuration
|
||||
|
||||
my $SkinSelected = $Self->{'UserSkin'};
|
||||
|
||||
# check if the skin is valid
|
||||
my $SkinValid = 0;
|
||||
if ($SkinSelected) {
|
||||
$SkinValid = $Self->SkinValidate(
|
||||
SkinType => 'Agent',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
if ( !$SkinValid ) {
|
||||
$SkinSelected = $SkinSelectedHostBased
|
||||
|| $ConfigObject->Get('Loader::Agent::DefaultSelectedSkin')
|
||||
|| 'default';
|
||||
}
|
||||
|
||||
# save selected skin
|
||||
$Self->{SkinSelected} = $SkinSelected;
|
||||
|
||||
my $SkinHome = $ConfigObject->Get('Home') . '/var/httpd/htdocs/skins';
|
||||
my $DoMinify = $ConfigObject->Get('Loader::Enabled::CSS');
|
||||
|
||||
my $ToolbarModuleSettings = $ConfigObject->Get('Frontend::ToolBarModule');
|
||||
my $CustomerUserItemSettings = $ConfigObject->Get('Frontend::CustomerUser::Item');
|
||||
|
||||
{
|
||||
my @FileList;
|
||||
|
||||
# get global css
|
||||
my $CommonCSSList = $ConfigObject->Get('Loader::Agent::CommonCSS');
|
||||
for my $Key ( sort keys %{$CommonCSSList} ) {
|
||||
push @FileList, @{ $CommonCSSList->{$Key} };
|
||||
}
|
||||
|
||||
# get toolbar module css
|
||||
for my $Key ( sort keys %{$ToolbarModuleSettings} ) {
|
||||
if ( $ToolbarModuleSettings->{$Key}->{CSS} ) {
|
||||
push @FileList, $ToolbarModuleSettings->{$Key}->{CSS};
|
||||
}
|
||||
}
|
||||
|
||||
# get customer user item css
|
||||
for my $Key ( sort keys %{$CustomerUserItemSettings} ) {
|
||||
if ( $CustomerUserItemSettings->{$Key}->{CSS} ) {
|
||||
push @FileList, $CustomerUserItemSettings->{$Key}->{CSS};
|
||||
}
|
||||
}
|
||||
|
||||
$Self->_HandleCSSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'CommonCSS',
|
||||
SkinHome => $SkinHome,
|
||||
SkinType => 'Agent',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
# now handle module specific CSS
|
||||
my $LoaderAction = $Self->{Action} || 'Login';
|
||||
$LoaderAction = 'Login' if ( $LoaderAction eq 'Logout' );
|
||||
|
||||
{
|
||||
my $Setting = $ConfigObject->Get("Loader::Module::$LoaderAction") || {};
|
||||
|
||||
my @FileList;
|
||||
|
||||
MODULE:
|
||||
for my $Module ( sort keys %{$Setting} ) {
|
||||
next MODULE if ref $Setting->{$Module}->{CSS} ne 'ARRAY';
|
||||
@FileList = ( @FileList, @{ $Setting->{$Module}->{CSS} || [] } );
|
||||
}
|
||||
|
||||
$Self->_HandleCSSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'ModuleCSS',
|
||||
SkinHome => $SkinHome,
|
||||
SkinType => 'Agent',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
# handle the responsive CSS
|
||||
{
|
||||
my @FileList;
|
||||
my $ResponsiveCSSList = $ConfigObject->Get('Loader::Agent::ResponsiveCSS');
|
||||
|
||||
for my $Key ( sort keys %{$ResponsiveCSSList} ) {
|
||||
push @FileList, @{ $ResponsiveCSSList->{$Key} };
|
||||
}
|
||||
|
||||
$Self->_HandleCSSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'ResponsiveCSS',
|
||||
SkinHome => $SkinHome,
|
||||
SkinType => 'Agent',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
#print STDERR "Time: " . Time::HiRes::tv_interval([$t0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 LoaderCreateAgentJSCalls()
|
||||
|
||||
Generate the minified JavaScript files and the tags referencing them,
|
||||
taking a list from the Loader::Agent::CommonJS config item.
|
||||
|
||||
$LayoutObject->LoaderCreateAgentJSCalls();
|
||||
|
||||
=cut
|
||||
|
||||
sub LoaderCreateAgentJSCalls {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
#use Time::HiRes;
|
||||
#my $t0 = Time::HiRes::gettimeofday();
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
my $JSHome = $ConfigObject->Get('Home') . '/var/httpd/htdocs/js';
|
||||
my $DoMinify = $ConfigObject->Get('Loader::Enabled::JS');
|
||||
|
||||
{
|
||||
my @FileList;
|
||||
|
||||
# get global js
|
||||
my $CommonJSList = $ConfigObject->Get('Loader::Agent::CommonJS');
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{$CommonJSList} ) {
|
||||
next KEY if $Key eq '100-CKEditor' && !$ConfigObject->Get('Frontend::RichText');
|
||||
push @FileList, @{ $CommonJSList->{$Key} };
|
||||
}
|
||||
|
||||
# get toolbar module js
|
||||
my $ToolbarModuleSettings = $ConfigObject->Get('Frontend::ToolBarModule');
|
||||
for my $Key ( sort keys %{$ToolbarModuleSettings} ) {
|
||||
if ( $ToolbarModuleSettings->{$Key}->{JavaScript} ) {
|
||||
push @FileList, $ToolbarModuleSettings->{$Key}->{JavaScript};
|
||||
}
|
||||
}
|
||||
|
||||
$Self->_HandleJSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'CommonJS',
|
||||
JSHome => $JSHome,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
# now handle module specific JavaScript
|
||||
{
|
||||
my $LoaderAction = $Self->{Action} || 'Login';
|
||||
$LoaderAction = 'Login' if ( $LoaderAction eq 'Logout' );
|
||||
|
||||
my $Setting = $ConfigObject->Get("Loader::Module::$LoaderAction") || {};
|
||||
|
||||
my @FileList;
|
||||
|
||||
MODULE:
|
||||
for my $Module ( sort keys %{$Setting} ) {
|
||||
next MODULE if ref $Setting->{$Module}->{JavaScript} ne 'ARRAY';
|
||||
@FileList = ( @FileList, @{ $Setting->{$Module}->{JavaScript} || [] } );
|
||||
}
|
||||
|
||||
$Self->_HandleJSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'ModuleJS',
|
||||
JSHome => $JSHome,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 LoaderCreateJavaScriptTemplateData()
|
||||
|
||||
Generate a minified file for the template data that
|
||||
needs to be present on the client side for JavaScript based templates.
|
||||
|
||||
$LayoutObject->LoaderCreateJavaScriptTemplateData();
|
||||
|
||||
=cut
|
||||
|
||||
sub LoaderCreateJavaScriptTemplateData {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# load theme
|
||||
my $Theme = $Self->{UserTheme} || $ConfigObject->Get('DefaultTheme') || Translatable('Standard');
|
||||
|
||||
# force a theme based on host name
|
||||
my $DefaultThemeHostBased = $ConfigObject->Get('DefaultTheme::HostBased');
|
||||
if ( $DefaultThemeHostBased && $ENV{HTTP_HOST} ) {
|
||||
|
||||
THEME:
|
||||
for my $RegExp ( sort keys %{$DefaultThemeHostBased} ) {
|
||||
|
||||
# do not use empty regexp or theme directories
|
||||
next THEME if !$RegExp;
|
||||
next THEME if $RegExp eq '';
|
||||
next THEME if !$DefaultThemeHostBased->{$RegExp};
|
||||
|
||||
# check if regexp is matching
|
||||
if ( $ENV{HTTP_HOST} =~ /$RegExp/i ) {
|
||||
$Theme = $DefaultThemeHostBased->{$RegExp};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# locate template files
|
||||
my $JSStandardTemplateDir = $ConfigObject->Get('TemplateDir') . '/JavaScript/Templates/' . 'Standard';
|
||||
my $JSTemplateDir = $ConfigObject->Get('TemplateDir') . '/JavaScript/Templates/' . $Theme;
|
||||
|
||||
# Check if 'Standard' fallback exists
|
||||
if ( !-e $JSStandardTemplateDir ) {
|
||||
$Self->FatalDie(
|
||||
Message =>
|
||||
"No existing template directory found ('$JSTemplateDir')! Check your Home in Kernel/Config.pm."
|
||||
);
|
||||
}
|
||||
|
||||
if ( !-e $JSTemplateDir ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message =>
|
||||
"No existing template directory found ('$JSTemplateDir')!.
|
||||
Default theme used instead.",
|
||||
);
|
||||
|
||||
# Set TemplateDir to 'Standard' as a fallback.
|
||||
$Theme = 'Standard';
|
||||
$JSTemplateDir = $JSStandardTemplateDir;
|
||||
}
|
||||
|
||||
my $JSCustomStandardTemplateDir = $ConfigObject->Get('CustomTemplateDir') . '/JavaScript/Templates/' . 'Standard';
|
||||
my $JSCustomTemplateDir = $ConfigObject->Get('CustomTemplateDir') . '/JavaScript/Templates/' . $Theme;
|
||||
|
||||
my @TemplateFolders = (
|
||||
"$JSCustomTemplateDir",
|
||||
"$JSCustomStandardTemplateDir",
|
||||
"$JSTemplateDir",
|
||||
"$JSStandardTemplateDir",
|
||||
);
|
||||
|
||||
my $JSHome = $ConfigObject->Get('Home') . '/var/httpd/htdocs/js';
|
||||
my $TargetFilenamePrefix = "TemplateJS";
|
||||
|
||||
my $TemplateChecksum;
|
||||
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
||||
my $CacheType = 'Loader';
|
||||
my $CacheKey = "LoaderCreateJavaScriptTemplateData:${Theme}:" . $ConfigObject->ConfigChecksum();
|
||||
|
||||
# Even getting the list of files recursively from the directories is expensive,
|
||||
# so cache the checksum to avoid that.
|
||||
$TemplateChecksum = $CacheObject->Get(
|
||||
Type => $CacheType,
|
||||
Key => $CacheKey,
|
||||
);
|
||||
|
||||
if ( !$TemplateChecksum ) {
|
||||
|
||||
my %ChecksumData;
|
||||
|
||||
TEMPLATEFOLDER:
|
||||
for my $TemplateFolder (@TemplateFolders) {
|
||||
|
||||
next TEMPLATEFOLDER if !-e $TemplateFolder;
|
||||
|
||||
# get main object
|
||||
my @Templates = $MainObject->DirectoryRead(
|
||||
Directory => $TemplateFolder,
|
||||
Filter => '*.tmpl',
|
||||
Recursive => 1,
|
||||
);
|
||||
|
||||
TEMPLATE:
|
||||
for my $Template ( sort @Templates ) {
|
||||
|
||||
next TEMPLATE if !-e $Template;
|
||||
|
||||
my $Key = $Template;
|
||||
$Key =~ s/^$TemplateFolder\///xmsg;
|
||||
$Key =~ s/\.(\w+)\.tmpl$//xmsg;
|
||||
|
||||
# check if a template with this name does already exist
|
||||
next TEMPLATE if $ChecksumData{$Key};
|
||||
|
||||
# get file metadata
|
||||
my $Stat = stat($Template);
|
||||
if ( !$Stat ) {
|
||||
print STDERR "Error: cannot stat file '$Template': $!";
|
||||
next TEMPLATE;
|
||||
}
|
||||
|
||||
$ChecksumData{$Key} = $Template . $Stat->mtime();
|
||||
}
|
||||
}
|
||||
|
||||
# generate a checksum only of the actual used files
|
||||
for my $Checksum ( sort keys %ChecksumData ) {
|
||||
$TemplateChecksum .= $ChecksumData{$Checksum};
|
||||
}
|
||||
$TemplateChecksum = Digest::MD5::md5_hex($TemplateChecksum);
|
||||
|
||||
$CacheObject->Set(
|
||||
Type => $CacheType,
|
||||
Key => $CacheKey,
|
||||
TTL => 60 * 60 * 24,
|
||||
Value => $TemplateChecksum,
|
||||
);
|
||||
}
|
||||
|
||||
# Check if cache already exists.
|
||||
if ( -e "$JSHome/js-cache/${TargetFilenamePrefix}_$TemplateChecksum.js" ) {
|
||||
$Self->Block(
|
||||
Name => 'CommonJS',
|
||||
Data => {
|
||||
JSDirectory => 'js-cache/',
|
||||
Filename => "${TargetFilenamePrefix}_$TemplateChecksum.js",
|
||||
},
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# if it doesnt exist, go through the folders and get the template content
|
||||
my %TemplateData;
|
||||
|
||||
TEMPLATEFOLDER:
|
||||
for my $TemplateFolder (@TemplateFolders) {
|
||||
|
||||
next TEMPLATEFOLDER if !-e $TemplateFolder;
|
||||
|
||||
# get main object
|
||||
my @Templates = $MainObject->DirectoryRead(
|
||||
Directory => $TemplateFolder,
|
||||
Filter => '*.tmpl',
|
||||
Recursive => 1,
|
||||
);
|
||||
|
||||
TEMPLATE:
|
||||
for my $Template ( sort @Templates ) {
|
||||
|
||||
next TEMPLATE if !-e $Template;
|
||||
|
||||
my $Key = $Template;
|
||||
$Key =~ s/^$TemplateFolder\///xmsg;
|
||||
$Key =~ s/\.(\w+)\.tmpl$//xmsg;
|
||||
|
||||
# check if a template with this name does already exist
|
||||
next TEMPLATE if $TemplateData{$Key};
|
||||
|
||||
my $TemplateContent = ${
|
||||
$MainObject->FileRead(
|
||||
Location => $Template,
|
||||
Result => 'SCALAR',
|
||||
)
|
||||
};
|
||||
|
||||
# Remove DTL-style comments (lines starting with #)
|
||||
$TemplateContent =~ s/^#.*\n//gm;
|
||||
$TemplateData{$Key} = $TemplateContent;
|
||||
}
|
||||
}
|
||||
|
||||
my $TemplateDataJSON = $Kernel::OM->Get('Kernel::System::JSON')->Encode(
|
||||
Data => \%TemplateData,
|
||||
Pretty => 0,
|
||||
);
|
||||
|
||||
my $Content = <<"EOF";
|
||||
// The content of this file is automatically generated, do not edit.
|
||||
Core.Template.Load($TemplateDataJSON);
|
||||
EOF
|
||||
my $MinifiedFile = $Kernel::OM->Get('Kernel::System::Loader')->MinifyFiles(
|
||||
Checksum => $TemplateChecksum,
|
||||
Content => $Content,
|
||||
Type => 'JavaScript',
|
||||
TargetDirectory => "$JSHome/js-cache/",
|
||||
TargetFilenamePrefix => $TargetFilenamePrefix,
|
||||
);
|
||||
|
||||
$Self->Block(
|
||||
Name => 'CommonJS',
|
||||
Data => {
|
||||
JSDirectory => 'js-cache/',
|
||||
Filename => $MinifiedFile,
|
||||
},
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 LoaderCreateJavaScriptTranslationData()
|
||||
|
||||
Generate a minified file for the translation data that
|
||||
needs to be present on the client side for JavaScript based translations.
|
||||
|
||||
$LayoutObject->LoaderCreateJavaScriptTranslationData();
|
||||
|
||||
=cut
|
||||
|
||||
sub LoaderCreateJavaScriptTranslationData {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
my $JSHome = $ConfigObject->Get('Home') . '/var/httpd/htdocs/js';
|
||||
|
||||
my $UserLanguage = $Self->{UserLanguage};
|
||||
my $LanguageObject = $Self->{LanguageObject};
|
||||
my $LanguageChecksum = $LanguageObject->LanguageChecksum();
|
||||
|
||||
my $TargetFilenamePrefix = "TranslationJS_$UserLanguage";
|
||||
|
||||
# Check if cache already exists.
|
||||
if ( -e "$JSHome/js-cache/${TargetFilenamePrefix}_$LanguageChecksum.js" ) {
|
||||
$Self->Block(
|
||||
Name => 'CommonJS',
|
||||
Data => {
|
||||
JSDirectory => 'js-cache/',
|
||||
Filename => "${TargetFilenamePrefix}_$LanguageChecksum.js",
|
||||
},
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Now create translation data for JavaScript.
|
||||
my %TranslationData;
|
||||
STRING:
|
||||
for my $String ( @{ $LanguageObject->{JavaScriptStrings} // [] } ) {
|
||||
next STRING if $TranslationData{$String};
|
||||
$TranslationData{$String} = $LanguageObject->{Translation}->{$String};
|
||||
}
|
||||
|
||||
my %LanguageMetaData = (
|
||||
LanguageCode => $UserLanguage,
|
||||
DateFormat => $LanguageObject->{DateFormat},
|
||||
DateFormatLong => $LanguageObject->{DateFormatLong},
|
||||
DateFormatShort => $LanguageObject->{DateFormatShort},
|
||||
DateInputFormat => $LanguageObject->{DateInputFormat},
|
||||
DateInputFormatLong => $LanguageObject->{DateInputFormatLong},
|
||||
Completeness => $LanguageObject->{Completeness},
|
||||
Separator => $LanguageObject->{Separator},
|
||||
DecimalSeparator => $LanguageObject->{DecimalSeparator},
|
||||
);
|
||||
|
||||
my $LanguageMetaDataJSON = $Kernel::OM->Get('Kernel::System::JSON')->Encode(
|
||||
Data => \%LanguageMetaData,
|
||||
SortKeys => 1,
|
||||
Pretty => 0,
|
||||
);
|
||||
|
||||
my $TranslationDataJSON = $Kernel::OM->Get('Kernel::System::JSON')->Encode(
|
||||
Data => \%TranslationData,
|
||||
SortKeys => 1,
|
||||
Pretty => 0,
|
||||
);
|
||||
|
||||
my $Content = <<"EOF";
|
||||
// The content of this file is automatically generated, do not edit.
|
||||
Core.Language.Load($LanguageMetaDataJSON, $TranslationDataJSON);
|
||||
EOF
|
||||
my $MinifiedFile = $Kernel::OM->Get('Kernel::System::Loader')->MinifyFiles(
|
||||
Checksum => $LanguageChecksum,
|
||||
Content => $Content,
|
||||
Type => 'JavaScript',
|
||||
TargetDirectory => "$JSHome/js-cache/",
|
||||
TargetFilenamePrefix => $TargetFilenamePrefix,
|
||||
);
|
||||
|
||||
$Self->Block(
|
||||
Name => 'CommonJS',
|
||||
Data => {
|
||||
JSDirectory => 'js-cache/',
|
||||
Filename => $MinifiedFile,
|
||||
},
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 LoaderCreateCustomerCSSCalls()
|
||||
|
||||
Generate the minified CSS files and the tags referencing them,
|
||||
taking a list from the Loader::Customer::CommonCSS config item.
|
||||
|
||||
$LayoutObject->LoaderCreateCustomerCSSCalls();
|
||||
|
||||
=cut
|
||||
|
||||
sub LoaderCreateCustomerCSSCalls {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
my $SkinSelected = $ConfigObject->Get('Loader::Customer::SelectedSkin')
|
||||
|| 'default';
|
||||
|
||||
# force a skin based on host name
|
||||
my $DefaultSkinHostBased = $ConfigObject->Get('Loader::Customer::SelectedSkin::HostBased');
|
||||
if ( $DefaultSkinHostBased && $ENV{HTTP_HOST} ) {
|
||||
REGEXP:
|
||||
for my $RegExp ( sort keys %{$DefaultSkinHostBased} ) {
|
||||
|
||||
# do not use empty regexp or skin directories
|
||||
next REGEXP if !$RegExp;
|
||||
next REGEXP if !$DefaultSkinHostBased->{$RegExp};
|
||||
|
||||
# check if regexp is matching
|
||||
if ( $ENV{HTTP_HOST} =~ /$RegExp/i ) {
|
||||
$SkinSelected = $DefaultSkinHostBased->{$RegExp};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $SkinHome = $ConfigObject->Get('Home') . '/var/httpd/htdocs/skins';
|
||||
my $DoMinify = $ConfigObject->Get('Loader::Enabled::CSS');
|
||||
|
||||
{
|
||||
my $CommonCSSList = $ConfigObject->Get('Loader::Customer::CommonCSS');
|
||||
|
||||
my @FileList;
|
||||
|
||||
for my $Key ( sort keys %{$CommonCSSList} ) {
|
||||
push @FileList, @{ $CommonCSSList->{$Key} };
|
||||
}
|
||||
|
||||
$Self->_HandleCSSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'CommonCSS',
|
||||
SkinHome => $SkinHome,
|
||||
SkinType => 'Customer',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
# now handle module specific CSS
|
||||
my $LoaderAction = $Self->{Action} || 'Login';
|
||||
$LoaderAction = 'Login' if ( $LoaderAction eq 'Logout' );
|
||||
|
||||
{
|
||||
my $Setting = $ConfigObject->Get("Loader::Module::$LoaderAction") || {};
|
||||
|
||||
my @FileList;
|
||||
|
||||
MODULE:
|
||||
for my $Module ( sort keys %{$Setting} ) {
|
||||
next MODULE if ref $Setting->{$Module}->{CSS} ne 'ARRAY';
|
||||
@FileList = ( @FileList, @{ $Setting->{$Module}->{CSS} || [] } );
|
||||
}
|
||||
|
||||
$Self->_HandleCSSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'ModuleCSS',
|
||||
SkinHome => $SkinHome,
|
||||
SkinType => 'Customer',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
# handle the responsive CSS
|
||||
{
|
||||
my @FileList;
|
||||
my $ResponsiveCSSList = $ConfigObject->Get('Loader::Customer::ResponsiveCSS');
|
||||
|
||||
for my $Key ( sort keys %{$ResponsiveCSSList} ) {
|
||||
push @FileList, @{ $ResponsiveCSSList->{$Key} };
|
||||
}
|
||||
|
||||
$Self->_HandleCSSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'ResponsiveCSS',
|
||||
SkinHome => $SkinHome,
|
||||
SkinType => 'Customer',
|
||||
Skin => $SkinSelected,
|
||||
);
|
||||
}
|
||||
|
||||
#print STDERR "Time: " . Time::HiRes::tv_interval([$t0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 LoaderCreateCustomerJSCalls()
|
||||
|
||||
Generate the minified JavaScript files and the tags referencing them,
|
||||
taking a list from the Loader::Customer::CommonJS config item.
|
||||
|
||||
$LayoutObject->LoaderCreateCustomerJSCalls();
|
||||
|
||||
=cut
|
||||
|
||||
sub LoaderCreateCustomerJSCalls {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
#use Time::HiRes;
|
||||
#my $t0 = Time::HiRes::gettimeofday();
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
my $JSHome = $ConfigObject->Get('Home') . '/var/httpd/htdocs/js';
|
||||
my $DoMinify = $ConfigObject->Get('Loader::Enabled::JS');
|
||||
|
||||
{
|
||||
my $CommonJSList = $ConfigObject->Get('Loader::Customer::CommonJS');
|
||||
|
||||
my @FileList;
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{$CommonJSList} ) {
|
||||
next KEY if $Key eq '100-CKEditor' && !$ConfigObject->Get('Frontend::RichText');
|
||||
push @FileList, @{ $CommonJSList->{$Key} };
|
||||
}
|
||||
|
||||
$Self->_HandleJSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'CommonJS',
|
||||
JSHome => $JSHome,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
# now handle module specific JS
|
||||
{
|
||||
my $LoaderAction = $Self->{Action} || 'CustomerLogin';
|
||||
$LoaderAction = 'CustomerLogin' if ( $LoaderAction eq 'Logout' );
|
||||
|
||||
my $Setting = $ConfigObject->Get("Loader::Module::$LoaderAction") || {};
|
||||
|
||||
my @FileList;
|
||||
|
||||
MODULE:
|
||||
for my $Module ( sort keys %{$Setting} ) {
|
||||
next MODULE if ref $Setting->{$Module}->{JavaScript} ne 'ARRAY';
|
||||
@FileList = ( @FileList, @{ $Setting->{$Module}->{JavaScript} || [] } );
|
||||
}
|
||||
|
||||
$Self->_HandleJSList(
|
||||
List => \@FileList,
|
||||
DoMinify => $DoMinify,
|
||||
BlockName => 'ModuleJS',
|
||||
JSHome => $JSHome,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#print STDERR "Time: " . Time::HiRes::tv_interval([$t0]);
|
||||
return;
|
||||
}
|
||||
|
||||
sub _HandleCSSList {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my @Skins = ('default');
|
||||
|
||||
# validating selected custom skin, if any
|
||||
if ( $Param{Skin} && $Param{Skin} ne 'default' && $Self->SkinValidate(%Param) ) {
|
||||
push @Skins, $Param{Skin};
|
||||
}
|
||||
|
||||
#load default css files
|
||||
for my $Skin (@Skins) {
|
||||
my @FileList;
|
||||
|
||||
CSSFILE:
|
||||
for my $CSSFile ( @{ $Param{List} } ) {
|
||||
my $SkinFile = "$Param{SkinHome}/$Param{SkinType}/$Skin/css/$CSSFile";
|
||||
next CSSFILE if ( !-e $SkinFile );
|
||||
|
||||
if ( $Param{DoMinify} ) {
|
||||
push @FileList, $SkinFile;
|
||||
}
|
||||
else {
|
||||
$Self->Block(
|
||||
Name => $Param{BlockName},
|
||||
Data => {
|
||||
Skin => $Skin,
|
||||
CSSDirectory => 'css',
|
||||
Filename => $CSSFile,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $Param{DoMinify} && @FileList ) {
|
||||
my $MinifiedFile = $Kernel::OM->Get('Kernel::System::Loader')->MinifyFiles(
|
||||
List => \@FileList,
|
||||
Type => 'CSS',
|
||||
TargetDirectory => "$Param{SkinHome}/$Param{SkinType}/$Skin/css-cache/",
|
||||
TargetFilenamePrefix => $Param{BlockName},
|
||||
);
|
||||
|
||||
$Self->Block(
|
||||
Name => $Param{BlockName},
|
||||
Data => {
|
||||
Skin => $Skin,
|
||||
CSSDirectory => 'css-cache',
|
||||
Filename => $MinifiedFile,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _HandleJSList {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $Content = $Param{Content};
|
||||
return if !$Param{List} && !$Content;
|
||||
|
||||
my %UsedFiles;
|
||||
|
||||
my @FileList;
|
||||
JSFILE:
|
||||
for my $JSFile ( @{ $Param{List} // [] } ) {
|
||||
next JSFILE if $UsedFiles{$JSFile};
|
||||
|
||||
if ( $Param{DoMinify} ) {
|
||||
push @FileList, "$Param{JSHome}/$JSFile";
|
||||
}
|
||||
else {
|
||||
$Self->Block(
|
||||
Name => $Param{BlockName},
|
||||
Data => {
|
||||
JSDirectory => '',
|
||||
Filename => $JSFile,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
# Save it for checking duplicates.
|
||||
$UsedFiles{$JSFile} = 1;
|
||||
}
|
||||
|
||||
return 1 if $Param{List} && !@FileList;
|
||||
|
||||
if ( $Param{DoMinify} ) {
|
||||
my $MinifiedFile;
|
||||
|
||||
if (@FileList) {
|
||||
$MinifiedFile = $Kernel::OM->Get('Kernel::System::Loader')->MinifyFiles(
|
||||
List => \@FileList,
|
||||
Type => 'JavaScript',
|
||||
TargetDirectory => "$Param{JSHome}/js-cache/",
|
||||
TargetFilenamePrefix => $Param{FilenamePrefix} // $Param{BlockName},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$MinifiedFile = $Kernel::OM->Get('Kernel::System::Loader')->MinifyFiles(
|
||||
Content => $Content,
|
||||
Type => 'JavaScript',
|
||||
TargetDirectory => "$Param{JSHome}/js-cache/",
|
||||
TargetFilenamePrefix => $Param{FilenamePrefix} // $Param{BlockName},
|
||||
);
|
||||
}
|
||||
|
||||
$Self->Block(
|
||||
Name => $Param{BlockName},
|
||||
Data => {
|
||||
JSDirectory => 'js-cache/',
|
||||
Filename => $MinifiedFile,
|
||||
},
|
||||
);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 SkinValidate()
|
||||
|
||||
Returns 1 if skin is available for Agent or Customer frontends and 0 if not.
|
||||
|
||||
my $SkinIsValid = $LayoutObject->SkinValidate(
|
||||
UserType => 'Agent' # Agent or Customer,
|
||||
Skin => 'ExampleSkin',
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub SkinValidate {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
for my $Needed ( 'SkinType', 'Skin' ) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Message => "Needed param: $Needed!",
|
||||
Priority => 'error',
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( exists $Self->{SkinValidateCache}->{ $Param{SkinType} . '::' . $Param{Skin} } ) {
|
||||
return $Self->{SkinValidateCache}->{ $Param{SkinType} . '::' . $Param{Skin} };
|
||||
}
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
my $SkinType = $Param{SkinType};
|
||||
my $PossibleSkins = $ConfigObject->Get("Loader::${SkinType}::Skin") || {};
|
||||
my $Home = $ConfigObject->Get('Home');
|
||||
my %ActiveSkins;
|
||||
|
||||
# prepare the list of active skins
|
||||
for my $PossibleSkin ( values %{$PossibleSkins} ) {
|
||||
if ( $PossibleSkin->{InternalName} eq $Param{Skin} ) {
|
||||
my $SkinDir = $Home . "/var/httpd/htdocs/skins/$SkinType/" . $PossibleSkin->{InternalName};
|
||||
if ( -d $SkinDir ) {
|
||||
$Self->{SkinValidateCache}->{ $Param{SkinType} . '::' . $Param{Skin} } = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Self->{SkinValidateCache}->{ $Param{SkinType} . '::' . $Param{Skin} } = undef;
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
99
Perl OTRS/Kernel/Output/HTML/Layout/Popup.pm
Normal file
99
Perl OTRS/Kernel/Output/HTML/Layout/Popup.pm
Normal file
@@ -0,0 +1,99 @@
|
||||
# --
|
||||
# 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::Layout::Popup;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::Popup - CSS/JavaScript
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All valid functions.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 PopupClose()
|
||||
|
||||
Generate a small HTML page which closes the pop-up window and
|
||||
executes an action in the main window.
|
||||
|
||||
# load specific URL in main window
|
||||
$LayoutObject->PopupClose(
|
||||
URL => "Action=AgentTicketZoom;TicketID=$TicketID"
|
||||
);
|
||||
|
||||
or
|
||||
|
||||
# reload main window
|
||||
$Self->{LayoutObject}->PopupClose(
|
||||
Reload => 1,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub PopupClose {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
if ( !$Param{URL} && !$Param{Reload} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need URL or Reload!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# Generate the call Header() and Footer(
|
||||
my $Output = $Self->Header( Type => 'Small' );
|
||||
|
||||
if ( $Param{URL} ) {
|
||||
|
||||
# add session if no cookies are enabled
|
||||
if ( $Self->{SessionID} && !$Self->{SessionIDCookie} ) {
|
||||
$Param{URL} .= ';' . $Self->{SessionName} . '=' . $Self->{SessionID};
|
||||
}
|
||||
|
||||
# send data to JS
|
||||
$Self->AddJSData(
|
||||
Key => 'PopupClose',
|
||||
Value => 'LoadParentURLAndClose',
|
||||
);
|
||||
$Self->AddJSData(
|
||||
Key => 'PopupURL',
|
||||
Value => $Param{URL},
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
# send data to JS
|
||||
$Self->AddJSData(
|
||||
Key => 'PopupClose',
|
||||
Value => 'ReloadParentAndClose',
|
||||
);
|
||||
}
|
||||
|
||||
$Output .= $Self->Footer( Type => 'Small' );
|
||||
return $Output;
|
||||
}
|
||||
|
||||
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
|
||||
365
Perl OTRS/Kernel/Output/HTML/Layout/Template.pm
Normal file
365
Perl OTRS/Kernel/Output/HTML/Layout/Template.pm
Normal file
@@ -0,0 +1,365 @@
|
||||
# --
|
||||
# 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::Layout::Template;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Scalar::Util qw();
|
||||
use Template;
|
||||
use Template::Stash::XS;
|
||||
use Template::Context;
|
||||
use Template::Plugins;
|
||||
|
||||
use Kernel::Output::Template::Provider;
|
||||
|
||||
our $ObjectManagerDisabled = 1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::Output::HTML::Layout::Template - template rendering engine based on Template::Toolkit
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 Output()
|
||||
|
||||
generates HTML output based on a template file.
|
||||
|
||||
Using a template file:
|
||||
|
||||
my $HTML = $LayoutObject->Output(
|
||||
TemplateFile => 'AdminLog.tt',
|
||||
Data => \%Param,
|
||||
);
|
||||
|
||||
Using a template string:
|
||||
|
||||
my $HTML = $LayoutObject->Output(
|
||||
Template => '<b>[% Data.SomeKey | html %]</b>',
|
||||
Data => \%Param,
|
||||
);
|
||||
|
||||
Additional parameters:
|
||||
|
||||
AJAX - AJAX-specific adjustements: this causes [% WRAPPER JSOnDocumentComplete %] blocks NOT
|
||||
to be replaced. This is important to be able to generate snippets which can be cached.
|
||||
Also, JS data added with AddJSData() calls is appended to the output here.
|
||||
|
||||
my $HTML = $LayoutObject->Output(
|
||||
TemplateFile => 'AdminLog.tt',
|
||||
Data => \%Param,
|
||||
AJAX => 1,
|
||||
);
|
||||
|
||||
KeepScriptTags - DEPRECATED, please use the parameter "AJAX" instead
|
||||
|
||||
=cut
|
||||
|
||||
sub Output {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
$Param{Data} ||= {};
|
||||
|
||||
# get and check param Data
|
||||
if ( ref $Param{Data} ne 'HASH' ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need HashRef in Param Data! Got: '" . ref( $Param{Data} ) . "'!",
|
||||
);
|
||||
$Self->FatalError();
|
||||
}
|
||||
|
||||
# asure compatibility with old KeepScriptTags parameter
|
||||
if ( $Param{KeepScriptTags} && !$Param{AJAX} ) {
|
||||
$Param{AJAX} = $Param{KeepScriptTags};
|
||||
}
|
||||
|
||||
# fill init Env
|
||||
if ( !$Self->{EnvRef} ) {
|
||||
%{ $Self->{EnvRef} } = %ENV;
|
||||
|
||||
# all $Self->{*}
|
||||
for ( sort keys %{$Self} ) {
|
||||
if ( defined $Self->{$_} && !ref $Self->{$_} ) {
|
||||
$Self->{EnvRef}->{$_} = $Self->{$_};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# add new env
|
||||
if ( $Self->{EnvNewRef} ) {
|
||||
for my $Key ( sort keys %{ $Self->{EnvNewRef} } ) {
|
||||
$Self->{EnvRef}->{$Key} = $Self->{EnvNewRef}->{$Key};
|
||||
}
|
||||
undef $Self->{EnvNewRef};
|
||||
}
|
||||
|
||||
# if we use the HTML5 input type 'email' jQuery Validate will always validate
|
||||
# we do not want that if CheckEmailAddresses is set to 'no' in SysConfig
|
||||
$Self->{EnvRef}->{EmailFieldType}
|
||||
= $Kernel::OM->Get('Kernel::Config')->Get('CheckEmailAddresses') ? 'email' : 'text';
|
||||
|
||||
my @TemplateFolders = (
|
||||
"$Self->{CustomTemplateDir}",
|
||||
"$Self->{CustomStandardTemplateDir}",
|
||||
"$Self->{TemplateDir}",
|
||||
"$Self->{StandardTemplateDir}",
|
||||
);
|
||||
|
||||
my $TemplateString;
|
||||
|
||||
if ( $Param{TemplateFile} ) {
|
||||
$Param{TemplateFileTT} .= "$Param{TemplateFile}.tt";
|
||||
}
|
||||
|
||||
# take templates from string/array
|
||||
elsif ( defined $Param{Template} && ref $Param{Template} eq 'ARRAY' ) {
|
||||
for ( @{ $Param{Template} } ) {
|
||||
$TemplateString .= $_;
|
||||
}
|
||||
}
|
||||
elsif ( defined $Param{Template} ) {
|
||||
$TemplateString = $Param{Template};
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Template or TemplateFile Param!',
|
||||
);
|
||||
$Self->FatalError();
|
||||
}
|
||||
|
||||
if ( !$Self->{TemplateObject} ) {
|
||||
|
||||
$Self->{TemplateProviderObject} = Kernel::Output::Template::Provider->new(
|
||||
{
|
||||
INCLUDE_PATH => \@TemplateFolders,
|
||||
EVAL_PERL => 1,
|
||||
COMPILE_EXT => '.ttc',
|
||||
}
|
||||
);
|
||||
$Self->{TemplateProviderObject}->OTRSInit(
|
||||
LayoutObject => $Self,
|
||||
);
|
||||
|
||||
my $Plugins = Template::Plugins->new(
|
||||
{
|
||||
PLUGIN_BASE => 'Kernel::Output::Template::Plugin',
|
||||
}
|
||||
);
|
||||
|
||||
my $Context = Template::Context->new(
|
||||
{
|
||||
EVAL_PERL => 1,
|
||||
STASH => Template::Stash::XS->new(),
|
||||
LOAD_TEMPLATES => [ $Self->{TemplateProviderObject} ],
|
||||
LOAD_PLUGINS => [$Plugins],
|
||||
}
|
||||
);
|
||||
|
||||
# Store a weak reference to the LayoutObject in the context
|
||||
# to avoid ring references. We need it for the plugins.
|
||||
$Context->{LayoutObject} = $Self;
|
||||
Scalar::Util::weaken( $Context->{LayoutObject} );
|
||||
|
||||
my $Success = $Self->{TemplateObject} = Template->new(
|
||||
{
|
||||
CONTEXT => $Context,
|
||||
|
||||
#DEBUG => Template::Constants::DEBUG_ALL,
|
||||
}
|
||||
);
|
||||
|
||||
if ( !$Success ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "$Template::ERROR;",
|
||||
);
|
||||
|
||||
# $Self->FatalError(); # Don't use FatalError here, might cause infinite recursion
|
||||
die "$Template::ERROR\n";
|
||||
}
|
||||
}
|
||||
|
||||
my $Output;
|
||||
my $Success = $Self->{TemplateObject}->process(
|
||||
$Param{TemplateFileTT} // \$TemplateString,
|
||||
{
|
||||
Data => $Param{Data} // {},
|
||||
global => {
|
||||
BlockData => $Self->{BlockData} // [],
|
||||
KeepScriptTags => $Param{AJAX} // 0,
|
||||
},
|
||||
},
|
||||
\$Output,
|
||||
);
|
||||
if ( !$Success ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => $Self->{TemplateObject}->error(),
|
||||
);
|
||||
$Self->FatalError();
|
||||
}
|
||||
|
||||
# If the browser does not send the session cookie, we need to append it to all links and image urls.
|
||||
# We cannot do this in the template preprocessor because links are often dynamically generated.
|
||||
if ( $Self->{SessionID} && !$Self->{SessionIDCookie} ) {
|
||||
|
||||
# rewrite a hrefs
|
||||
$Output =~ s{
|
||||
(<a.+?href=")(.+?)(\#.+?|)(".+?>)
|
||||
}
|
||||
{
|
||||
my $AHref = $1;
|
||||
my $Target = $2;
|
||||
my $End = $3;
|
||||
my $RealEnd = $4;
|
||||
if ( lc($Target) =~ /^(http:|https:|#|ftp:)/ ||
|
||||
$Target !~ /\.(pl|php|cgi|fcg|fcgi|fpl)(\?|$)/ ||
|
||||
$Target =~ /(\?|&|;)\Q$Self->{SessionName}\E=/) {
|
||||
$AHref.$Target.$End.$RealEnd;
|
||||
}
|
||||
else {
|
||||
$AHref.$Target.';'.$Self->{SessionName}.'='.$Self->{SessionID}.$End.$RealEnd;
|
||||
}
|
||||
}iegxs;
|
||||
|
||||
# rewrite img and iframe src
|
||||
$Output =~ s{
|
||||
(<(?:img|iframe).+?src=")(.+?)(".+?>)
|
||||
}
|
||||
{
|
||||
my $AHref = $1;
|
||||
my $Target = $2;
|
||||
my $End = $3;
|
||||
if (lc($Target) =~ m{^http s? :}smx || !$Self->{SessionID} ||
|
||||
$Target !~ /\.(pl|php|cgi|fcg|fcgi|fpl)(\?|$)/ ||
|
||||
$Target =~ /\Q$Self->{SessionName}\E=/) {
|
||||
$AHref.$Target.$End;
|
||||
}
|
||||
else {
|
||||
$AHref.$Target.'&'.$Self->{SessionName}.'='.$Self->{SessionID}.$End;
|
||||
}
|
||||
}iegxs;
|
||||
}
|
||||
|
||||
#
|
||||
# "Post" Output filter handling
|
||||
#
|
||||
if ( $Self->{FilterElementPost} && ref $Self->{FilterElementPost} eq 'HASH' ) {
|
||||
|
||||
# extract filter list
|
||||
my %FilterList = %{ $Self->{FilterElementPost} };
|
||||
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
FILTER:
|
||||
for my $Filter ( sort keys %FilterList ) {
|
||||
|
||||
# extract filter config
|
||||
my $FilterConfig = $FilterList{$Filter};
|
||||
|
||||
# extract template list
|
||||
my %TemplateList = %{ $FilterConfig->{Templates} || {} };
|
||||
|
||||
next FILTER if !$Param{TemplateFile};
|
||||
next FILTER if !$TemplateList{ $Param{TemplateFile} };
|
||||
|
||||
next FILTER if !$Kernel::OM->Get('Kernel::System::Main')->Require( $FilterConfig->{Module} );
|
||||
|
||||
# create new instance
|
||||
my $Object = $FilterConfig->{Module}->new(
|
||||
%{$Self},
|
||||
LayoutObject => $Self,
|
||||
);
|
||||
|
||||
next FILTER if !$Object;
|
||||
|
||||
# run output filter
|
||||
$Object->Run(
|
||||
%{$FilterConfig},
|
||||
Data => \$Output,
|
||||
TemplateFile => $Param{TemplateFile} || '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# AddJSData() handling
|
||||
#
|
||||
if ( $Param{AJAX} ) {
|
||||
my %Data = %{ $Self->{_JSData} // {} };
|
||||
if (%Data) {
|
||||
my $JSONString = $Kernel::OM->Get('Kernel::System::JSON')->Encode(
|
||||
Data => \%Data,
|
||||
SortKeys => 1,
|
||||
);
|
||||
$Output
|
||||
.= "\n<script type=\"text/javascript\">//<![CDATA[\n\"use strict\";\nCore.Config.AddConfig($JSONString);\n//]]></script>";
|
||||
}
|
||||
delete $Self->{_JSData};
|
||||
}
|
||||
|
||||
return $Output;
|
||||
}
|
||||
|
||||
=head2 AddJSOnDocumentComplete()
|
||||
|
||||
dynamically add JavaScript code that should be executed in Core.App.Ready().
|
||||
Call this for any dynamically generated code that is not in a template.
|
||||
|
||||
$LayoutObject->AddJSOnDocumentComplete(
|
||||
Code => $MyCode,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub AddJSOnDocumentComplete {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
$Self->{_JSOnDocumentComplete} //= [];
|
||||
push @{ $Self->{_JSOnDocumentComplete} }, $Param{Code};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
=head2 AddJSData()
|
||||
|
||||
dynamically add JavaScript data that should be handed over to
|
||||
JavaScript via Core.Config.
|
||||
|
||||
$LayoutObject->AddJSData(
|
||||
Key => 'Key1', # the key to store this data
|
||||
Value => { ... } # simple or complex data
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub AddJSData {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return if !$Param{Key};
|
||||
|
||||
$Self->{_JSData} //= {};
|
||||
$Self->{_JSData}->{ $Param{Key} } = $Param{Value};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
1127
Perl OTRS/Kernel/Output/HTML/Layout/Ticket.pm
Normal file
1127
Perl OTRS/Kernel/Output/HTML/Layout/Ticket.pm
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user