Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Kernel/Language/de_FAQ.pm
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ sub Data {

# Template: CustomerFAQRelatedArticles
$Self->{Translation}->{'This might be helpful'} = 'Hilfreiche Artikel';
$Self->{Translation}->{'One helpful faq article found.'} = 'Es wurde ein passender FAQ Artikel gefunden.';
$Self->{Translation}->{'%s helpful faq articles found.'} = 'Es wurden %s passende FAQ Artikel gefunden.';
$Self->{Translation}->{'Could not load helpful faq articles.'} = 'Die hilfreichen FAQ Artikel konnten nicht geladen werden.';
$Self->{Translation}->{'Found no helpful resources for the subject and text.'} = 'Leider wurden keine passenden Artikel gefunden.';
$Self->{Translation}->{'Type a subject or text to get a list of helpful resources.'} = 'Nach dem Eintippen eines Betreffs oder Textes werden hier passende Artikel angezeigt.';

Expand Down
3 changes: 3 additions & 0 deletions Kernel/Language/en_GB_FAQ.pm
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ sub Data {

# Template: CustomerFAQRelatedArticles
$Self->{Translation}->{'This might be helpful'} = 'This might be helpful';
$Self->{Translation}->{'One helpful faq article found.'} = 'One helpful faq article found.';
$Self->{Translation}->{'%s helpful faq articles found.'} = '%s helpful faq articles found.';
$Self->{Translation}->{'Could not load helpful faq articles.'} = 'Could not load helpful faq articles.';
$Self->{Translation}->{'Found no helpful resources for the subject and text.'} = 'Found no helpful resources for the subject and text.';
$Self->{Translation}->{'Type a subject or text to get a list of helpful resources.'} = 'Type a subject or text to get a list of helpful resources.';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ sub Run {
Data => {},
);

my $Search = '(<textarea id="RichText")';
my $Search = '(<textarea id="RichText"[^>]*>.*?</textarea>)';
${ $Param{Data} }
=~ s{$Search}{<div id="FAQRelatedArticles" class="Hidden">$CustomerRelatedFAQArticlesHTMLString</div>$1}msg;
=~ s{$Search}{$1<div id="FAQRelatedArticlesStatus" class="FAQRelatedArticlesStatus" role="status" aria-atomic="true"></div><section id="FAQRelatedArticles" class="Hidden" aria-labelledby="FAQRelatedArticlesHeading">$CustomerRelatedFAQArticlesHTMLString</section>}msg;

my $FrontendCustomerTicketMessageConfig = $ConfigObject->Get("Ticket::Frontend::CustomerTicketMessage");
my $FrontendCustomerFAQRelatedArticlesConfig = $ConfigObject->Get("FAQ::Frontend::CustomerFAQRelatedArticles");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# --


<div class="WidgetSimple">
<div class="WidgetSimple"[% IF Data.RelatedFAQArticleList.size == 1 %] data-status-message="[% Translate("One helpful faq article found.") | html %]"[% ELSIF Data.RelatedFAQArticleList.size %] data-status-message="[% Translate("%s helpful faq articles found.", Data.RelatedFAQArticleList.size) | html %]"[% ELSIF Data.RelatedFAQArticleFoundNothing %] data-status-message="[% Translate("Found no helpful resources for the subject and text.") | html %]"[% END %]>

<div class="Header">
<h3>[% Translate("This might be helpful") | html %]</h3>
<div class="Clear"></div>
<h2 id="FAQRelatedArticlesHeading">[% Translate("This might be helpful") | html %]</h2>
</div>

<div class="Content">
Expand All @@ -28,7 +26,7 @@
[% FOREACH FAQArticle IN Data.RelatedFAQArticleList %]
<li>
<hr>
<a class='RelatedFAQArticleList oool' href="[% Env("Baselink") %]Action=CustomerFAQZoom;ItemID=[% FAQArticle.ItemID | uri %]" target="_blank" title="[% FAQArticle.Title | html %] ([% FAQArticle.CategoryName | html %])">
<a class='RelatedFAQArticleList oool' href="[% Env("Baselink") %]Action=CustomerFAQZoom;ItemID=[% FAQArticle.ItemID | uri %]" target="_blank">
[% FAQArticle.Title | html %]
</a>
# [% IF FAQArticle.Votes && Data.VoteStarsVisible && FAQArticle.StarCounter >= Data.VoteStarsVisible %]
Expand All @@ -46,4 +44,3 @@
[% END %]
</div>
</div>
<div class="Clear"></div>
73 changes: 54 additions & 19 deletions var/httpd/htdocs/js/FAQ.Customer.RelatedArticles.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,28 @@ FAQ.Customer = FAQ.Customer || {};
FAQ.Customer.RelatedArticles = (function (TargetNS) {

var QueuesEnabled = $('#QueuesEnabled').val(),
SearchDelay = 400,
SearchTimer,
LastData;

function UpdateStatus(Message) {
$('#FAQRelatedArticlesStatus').text(Message || '');
}

if (typeof QueuesEnabled != 'undefined') {
Core.App.Subscribe('Event.UI.RichTextEditor.InstanceCreated', function() {
Core.App.Subscribe('Event.UI.RichTextEditor.InstanceCreated', function(Editor) {
// CKEditor 5 updates its model after input events such as keydown.
// Defer the subject change so getData() reads the updated editor content.
var TriggerSubjectChange = function () {
window.setTimeout(function () {
$('#Subject').trigger('change');
}, 0);
};

if (!Editor || Editor.ElementId !== 'RichText') {
return;
}

$('#Dest').on('change.RelatedFAQArticle', function () {
var SelectedQueue = $(this).val(),
SelectedQueueName = SelectedQueue.replace(/\d*\|\|-?/, '');
Expand All @@ -53,18 +71,22 @@ FAQ.Customer.RelatedArticles = (function (TargetNS) {
});

// FAQ Service
$('#ServiceID').on('change', function () {
$('#ServiceID').on('change', function (Event) {
$('#Subject').trigger('change');
});
// eo FAQ Service

$('#Subject').on('change', function () {
$('#Subject').on('change', function (Event) {
window.clearTimeout(SearchTimer);

SearchTimer = window.setTimeout(function () {
var SelectedQueue = $('#Dest').val(),
SelectedQueueName,
RelatedArticlesXHR,
Data;

if (SelectedQueue) {
SelectedQueue.replace(/\d*\|\|-?/, '')
SelectedQueueName = SelectedQueue.replace(/\d*\|\|-?/, '');
}

if ( !QueuesEnabled.length || !SelectedQueueName || $.inArray(SelectedQueueName, QueuesEnabled) > -1 ) {
Expand All @@ -78,11 +100,13 @@ FAQ.Customer.RelatedArticles = (function (TargetNS) {

if ( !LastData || LastData.Subject != Data.Subject || LastData.Body != Data.Body || LastData.ServiceID != Data.ServiceID ) {

UpdateStatus(Core.Config.Get('LoadingMsg'));

if (!$('.FAQMiniList').length) {
$('#FAQRelatedArticles .Content').html('<div class="Center"><span class="AJAXLoader" title="' + Core.Config.Get('LoadingMsg') + '"></span></div>');
}
else if (!$('#FAQRelatedArticles .Header .AJAXLoader').length) {
$('#FAQRelatedArticles .Header h3').after('<span class="AJAXLoader" style="float: right; margin: 0;" title="' + Core.Config.Get('LoadingMsg') + '"></span>');
$('#FAQRelatedArticles .Header h2').after('<span class="AJAXLoader" title="' + Core.Config.Get('LoadingMsg') + '"></span>');
}

if ($('#Subject').data('RelatedFAQArticlesXHR')) {
Expand All @@ -91,7 +115,7 @@ FAQ.Customer.RelatedArticles = (function (TargetNS) {
$('#Subject').removeData('RelatedFAQArticlesXHR');
}

$('#Subject').data('RelatedFAQArticlesXHR', Core.AJAX.FunctionCall(Core.Config.Get('Baselink'), Data, function (Response) {
RelatedArticlesXHR = Core.AJAX.FunctionCall(Core.Config.Get('Baselink'), Data, function (Response) {

$('#Subject').removeData('RelatedFAQArticlesXHR');

Expand All @@ -103,51 +127,62 @@ FAQ.Customer.RelatedArticles = (function (TargetNS) {
$('#FAQRelatedArticles').html(Response.CustomerRelatedFAQArticlesHTMLString);
$('#FAQRelatedArticles').removeClass('Hidden'); // XXX handle class
$('#FAQRelatedArticles:not(.Hidden)').show();
UpdateStatus($('#FAQRelatedArticles > .WidgetSimple').attr('data-status-message'));
}

if ( $('#FAQRelatedArticles .Content > .FAQMiniList').length == 0 ) {
// $('#FAQRelatedArticles').hide(); // XXX: maybe the bug
// XXX: is hidden necessary at all?
// $('#FAQRelatedArticles').addClass('Hidden');
}
}));
});

RelatedArticlesXHR.fail(function (XHRObject, Status) {
if (Status !== 'abort') {
UpdateStatus(Core.Language.Translate('Could not load helpful articles.'));
}
});

$('#Subject').data('RelatedFAQArticlesXHR', RelatedArticlesXHR);
}
}
}, SearchDelay);
});

$('#Subject').on('paste keydown', function (Event) {
var Value = $('#Subject').val();

// trigger only the change event for the subject, if space or enter was pressed
if (( Event.type === 'keydown' && ( Event.which == 32 || Event.which == 13 ) && ( Value.length > 10 || CKEditorInstances['RichText'].getData())) || Event.type !== 'keydown') {
if (( Event.type === 'keydown' && ( Event.which == 32 || Event.which == 13 ) ) || Event.type !== 'keydown') {
$('#Subject').trigger('change');
}
});

// The "change" event is fired whenever a change is made in the editor.
CKEditorInstances['RichText'].editing.view.document.on( 'keydown', function (_Event, data) {

// The "keydown" event is fired whenever a key is pressed in the editor.
Editor.editing.view.document.on('keydown', function (Event, Data) {
// trigger only the change event for the subject, if space or enter was pressed
if ( data.keyCode == 32 || data.keyCode == 13) {
$('#Subject').trigger('change');
if (Data.keyCode == 32 || Data.keyCode == 13) {
TriggerSubjectChange();
}
});

// The "paste" event is fired whenever a paste is made in the editor.
CKEditorInstances['RichText'].editing.view.document.on( 'paste', function () {

Editor.editing.view.document.on('clipboardInput', function () {
// trigger only the change event for the subject
$('#Subject').trigger('change');
TriggerSubjectChange();
});

// The "blur" event is fired whenever a blur is made in the editor.
CKEditorInstances['RichText'].editing.view.document.on( 'blur', function () {
Editor.ui.focusTracker.on('change:isFocused', function (Event, Name, IsFocused) {
if (IsFocused) {
return;
}

// trigger only the change event for the subject
$('#Subject').trigger('change');
TriggerSubjectChange();
});

// Trigger the 'RelatedFAQArticle' change event to hide/show the related faq article widget for the case
// Trigger the 'RelatedFAQArticle' change event to hide/show the relatd faq article widget for the case
// that the queue is already selected at the page load or show the widget always if the queue selection is disabled.
if ( !$('#Dest').length ) {
$('#FAQRelatedArticles').removeClass('Hidden');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
display: none !important;
}

/* Keep live status updates available to assistive technology without adding
* another visible message to the related-article widget. */
.FAQRelatedArticlesStatus {
position: absolute !important;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}

#FAQRelatedArticles:before {
position: relative;
top: 5px;
Expand Down Expand Up @@ -48,9 +63,31 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
}

#FAQRelatedArticles .Header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
}

#FAQRelatedArticles .Header h2 {
color: inherit;
font-size: 16px;
font-weight: 500;
letter-spacing: 0.4px;
}

#FAQRelatedArticles .Header .AJAXLoader {
flex: 0 0 auto;
}

#FAQRelatedArticles li:focus-within {
border-bottom: 2px solid var(--colMainLight);
}

#FAQRelatedArticles li:hover {
border-bottom: 1px solid var(--colMainLight);
}

#FAQRelatedArticles li {
padding-top: 16px;
margin-bottom: 16px;
Expand All @@ -67,16 +104,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
}

@media only screen and (max-width: 1279px) {
fieldset > .RichTextHolder:has(> #FAQRelatedArticles:not(.Hidden)) {
margin-bottom: 180px;
}

#FAQRelatedArticles {
position: relative;
left: 8px;

display: inline-block;
vertical-align: top;
position: static;
display: block;
clear: both;

box-sizing: border-box;
width: 100%;
margin: 8px 0;
padding: 8px;
}

Expand Down