diff --git a/Kernel/Language/de_FAQ.pm b/Kernel/Language/de_FAQ.pm
index 69efb71..b501453 100644
--- a/Kernel/Language/de_FAQ.pm
+++ b/Kernel/Language/de_FAQ.pm
@@ -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.';
diff --git a/Kernel/Language/en_GB_FAQ.pm b/Kernel/Language/en_GB_FAQ.pm
index 2955d61..aedc85f 100644
--- a/Kernel/Language/en_GB_FAQ.pm
+++ b/Kernel/Language/en_GB_FAQ.pm
@@ -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.';
diff --git a/Kernel/Output/HTML/FilterElementPost/FAQCustomerRelatedArticles.pm b/Kernel/Output/HTML/FilterElementPost/FAQCustomerRelatedArticles.pm
index 64833ba..4328bed 100644
--- a/Kernel/Output/HTML/FilterElementPost/FAQCustomerRelatedArticles.pm
+++ b/Kernel/Output/HTML/FilterElementPost/FAQCustomerRelatedArticles.pm
@@ -100,9 +100,9 @@ sub Run {
Data => {},
);
- my $Search = '()';
${ $Param{Data} }
- =~ s{$Search}{
+
-
diff --git a/var/httpd/htdocs/js/FAQ.Customer.RelatedArticles.js b/var/httpd/htdocs/js/FAQ.Customer.RelatedArticles.js
index 34a8c5a..4044621 100644
--- a/var/httpd/htdocs/js/FAQ.Customer.RelatedArticles.js
+++ b/var/httpd/htdocs/js/FAQ.Customer.RelatedArticles.js
@@ -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*\|\|-?/, '');
@@ -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 ) {
@@ -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('
');
}
else if (!$('#FAQRelatedArticles .Header .AJAXLoader').length) {
- $('#FAQRelatedArticles .Header h3').after('
');
+ $('#FAQRelatedArticles .Header h2').after('
');
}
if ($('#Subject').data('RelatedFAQArticlesXHR')) {
@@ -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');
@@ -103,6 +127,7 @@ 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 ) {
@@ -110,44 +135,54 @@ FAQ.Customer.RelatedArticles = (function (TargetNS) {
// 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');
diff --git a/var/httpd/htdocs/skins/Customer/default/css/FAQ.RelatedArticles.css b/var/httpd/htdocs/skins/Customer/default/css/FAQ.RelatedArticles.css
index 65f63dd..05c9fdd 100644
--- a/var/httpd/htdocs/skins/Customer/default/css/FAQ.RelatedArticles.css
+++ b/var/httpd/htdocs/skins/Customer/default/css/FAQ.RelatedArticles.css
@@ -18,6 +18,21 @@ along with this program. If not, see
.
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;
@@ -48,9 +63,31 @@ along with this program. If not, see
.
}
#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;
@@ -67,16 +104,18 @@ along with this program. If not, see
.
}
@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;
}