From d34e9e384d8c2f7101cf0c2fa451bab1c2a46a86 Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Fri, 14 Nov 2025 12:27:15 -0700
Subject: [PATCH 1/7] Initial commit, accessibility updates, misc changes
---
src/connector.css | 27 ++++
src/connector.js | 339 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 366 insertions(+)
diff --git a/src/connector.css b/src/connector.css
index 854ed83..47a2268 100644
--- a/src/connector.css
+++ b/src/connector.css
@@ -111,3 +111,30 @@
content: "\e092";
margin-left: .5em;
}
+.smart-snippet-container {
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ padding: 10px 20px 20px 20px;
+}
+.smart-snippet-container .smart-snippet-answer {
+ padding: 30px 20px 20px 20px;
+ position: relative;
+ overflow: hidden;
+}
+.smart-snippet-container .smart-snippet-toggle-height {
+ text-align: center;
+}
+.smart-snippet-container .smart-snippet-answer .smart-snippet-answer-truncated,
+.smart-snippet-container.smart-snippet-height-limiter .smart-snippet-answer .smart-snippet-answer-full {
+ display: none;
+}
+.smart-snippet-container .smart-snippet-answer .smart-snippet-answer-full,
+.smart-snippet-container.smart-snippet-height-limiter .smart-snippet-answer .smart-snippet-answer-truncated {
+ display: block;
+}
+.smart-snippet-ai-disclaimer {
+ font-style: italic;
+ font-size: .85em;
+ border-top: 1px solid #eee;
+ padding-top: .85em;
+}
\ No newline at end of file
diff --git a/src/connector.js b/src/connector.js
index cc5a41f..0fc767e 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -6,6 +6,8 @@ import {
buildPager,
buildResultsPerPage,
buildSearchStatus,
+ buildSmartSnippet,
+ buildSmartSnippetQuestionsList,
buildUrlManager,
buildDidYouMean,
buildContext,
@@ -35,6 +37,8 @@ const defaults = {
"numberOfSuggestions": 5,
"minimumCharsForSuggestions": 3,
"enableHistoryPush": true,
+ "enableSmartSnippets": false,
+ "smartSnippetToggleLimit": 250,
"isContextSearch": false,
"isAdvancedSearch": false,
"originLevel3": originPath,
@@ -58,6 +62,8 @@ let resultListController;
let querySummaryController;
let didYouMeanController;
let pagerController;
+let smartSnippetController;
+let smartSnippetQuestionListController;
let statusController;
let urlManager;
let unsubscribeManager;
@@ -66,6 +72,8 @@ let unsubscribeResultListController;
let unsubscribeQuerySummaryController;
let unsubscribeDidYouMeanController;
let unsubscribePagerController;
+let unsubscribeSmartSnippetController;
+let unsubscribeSmartSnippetQuestionListController;
// UI states
let updateSearchBoxFromState = false;
@@ -74,6 +82,8 @@ let resultListState;
let querySummaryState;
let didYouMeanState;
let pagerState;
+let smartSnippetState;
+let smartSnippetQuestionListState;
let lastCharKeyUp;
let activeSuggestion = 0;
let pagerManuallyCleared = false;
@@ -92,6 +102,8 @@ let querySummaryElement = document.querySelector( '#query-summary' );
let pagerElement = document.querySelector( '#pager' );
let suggestionsElement = document.querySelector( '#suggestions' );
let didYouMeanElement = document.querySelector( '#did-you-mean' );
+let smartSnippetsElement = document.querySelector( '#smart-snippet' );
+let smartSnippetQuestionListContainerElement = document.querySelector( '#smart-snippet-question-list' );
// UI templates
let resultTemplateHTML = document.getElementById( 'sr-single' )?.innerHTML;
@@ -105,6 +117,9 @@ let pageTemplateHTML = document.getElementById( 'sr-pager-page' )?.innerHTML;
let nextPageTemplateHTML = document.getElementById( 'sr-pager-next' )?.innerHTML;
let pagerContainerTemplateHTML = document.getElementById( 'sr-pager-container' )?.innerHTML;
let qsA11yHintHTML = document.getElementById( 'sr-qs-hint' )?.innerHTML;
+let smartSnippetHTML = document.getElementById( 'sr-smart-snippet-container' )?.innerHTML;
+let smartSnippetQuestionListHTML = document.getElementById( 'sr-smart-snippet-question-list-container' )?.innerHTML;
+let smartSnippetQuestionListContainerHTML = document.getElementById( 'sr-smart-snippet-question-list-container' )?.innerHTML;
// Init parameters and UI
function initSearchUI() {
@@ -374,6 +389,77 @@ function initTpl() {
resultsSection.append( querySummaryElement );
}
+ // Smart snippet - Featured SS
+ if ( params.enableSmartSnippets && !smartSnippetHTML ) {
+ smartSnippetHTML =
+ `
+
+
%[question]
+
+
+
+ %[answer]
+
%[smart_snippet_answer_ai_disclaimer]
+
+
+ %[answer_truncated]
+
+
+
+
+
+
+
+
- %[source.raw.displaynavlabel]
+
+
`;
+
+ // Localize
+ if ( lang === "fr" ) {
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" )
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Afficher plus" )
+ } else {
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'The information was retrieved by Artificial Intelligence' )
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Show more" )
+ }
+
+ }
+
+ // Smart snippet - Question list container
+ if ( params.enableSmartSnippets && !smartSnippetQuestionListContainerHTML ) {
+ smartSnippetQuestionListContainerHTML =
+ ``;
+
+ // Localize
+ if ( lang === "fr" ) {
+ smartSnippetQuestionListContainerHTML = smartSnippetQuestionListContainerHTML.replace( '%[smart_snippet_question_list_title]', 'Les gens demandent aussi' )
+ } else {
+ smartSnippetQuestionListContainerHTML = smartSnippetQuestionListContainerHTML.replace( '%[smart_snippet_question_list_title]', 'People also ask' )
+ }
+ }
+
+ // Smart snippets - Featured SS
+ if ( params.enableSmartSnippets && !smartSnippetsElement ) {
+ smartSnippetsElement = document.createElement( "div" );
+ smartSnippetsElement.id = "smart-snippets";
+
+ resultsSection.append( smartSnippetsElement );
+ }
+
// auto-create did you mean element
if ( !didYouMeanElement ) {
didYouMeanElement = document.createElement( "div" );
@@ -400,6 +486,44 @@ function initTpl() {
pagerElement = newPagerElement;
}
+
+ // Smart snippet - Question list item
+ if( params.enableSmartSnippets && !smartSnippetQuestionListHTML ) {
+ smartSnippetQuestionListHTML =
+ `
+
+ %[question]
+
+
+ %[answer]
+
%[smart_snippet_answer_ai_disclaimer]
+
+
+
+
+
- %[source.raw.displaynavlabel]
+
+
+
+ `;
+
+ // Localize
+ if ( lang === "fr" ) {
+ smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" )
+ } else {
+ smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'Information retrieved by artificial intelligence.' )
+ }
+ }
+
+ // Smart snippets - Questions list container
+ if ( params.enableSmartSnippets && !smartSnippetQuestionListContainerElement ) {
+ smartSnippetQuestionListContainerElement = document.createElement( "div" );
+ smartSnippetQuestionListContainerElement.id = "smart-snippets-question-list";
+
+ // Add it after the results list element (after the results, before the paging)
+ resultListElement.after( smartSnippetQuestionListContainerElement );
+ }
+
// initialize the search box
searchBoxElement = document.querySelector( params.searchBoxQuery );
@@ -512,6 +636,97 @@ function stripHtml(html) {
return tmp.textContent || tmp.innerText || "";
}
+// Calculates the length of the text for a block of HTML
+function getTextLength( content ){
+ var elem;
+
+ // If a string is passed in, convert it to an element
+ if( !( content instanceof Element ) ){
+ elem = document.createElement( 'div' );
+ elem.innerHTML = String( content );
+ } else {
+ elem = content
+ }
+
+ // Get the inside content
+ var fullText = elem.textContent || ''
+
+ // Strip out extra whitespace, like indenting
+ fullText = fullText.replace( /[\n\r]+|[\s]{2,}/g, ' ' ).trim()
+ return fullText.length
+
+}
+
+// Truncate an HTML string to a given text length, preserving tag structure.
+function truncateHtml( html, maxLength ) {
+
+ // Put into a temp div element, so we can work with it
+ const container = document.createElement( "div" );
+ container.innerHTML = html;
+
+ // If content is less than maxLength, return it as-is
+ if ( maxLength < 0 || getTextLength( container ) <= maxLength ) {
+ return html;
+ }
+
+ let remaining = maxLength;
+
+ // Recursive function that goes through the HTML tree, rebuilding it to the
+ // point where we reach `maxLength`
+ function cloneWithLimit( node ) {
+ if ( remaining <= 0 ) return null;
+
+ // If this node is just text, we're at the deepest point of this part of the tree.
+ // If we're below the limit, return as-is. If we hit the limit, truncate here and add the ellipsis.
+ if ( node.nodeType === Node.TEXT_NODE ) {
+ const text = node.nodeValue || '';
+ if ( text.length <= remaining ) {
+ remaining -= text.length;
+ return document.createTextNode( text );
+ } else {
+ const truncatedText = text.slice( 0, remaining ) + '…';
+ remaining = 0;
+ return document.createTextNode( truncatedText );
+ }
+ }
+
+ // If it's a tag, we go inside and recursively iterate through the children until we hit the length limit
+ if ( node.nodeType === Node.ELEMENT_NODE ) {
+ // Create a copy of the current tag
+ const clone = node.cloneNode( false );
+
+ // Iterate through the children of the original node
+ for ( let child of node.childNodes ) {
+ if ( remaining <= 0 ) break; // If we hit the limit, stop here.
+ const childClone = cloneWithLimit( child );
+ if ( childClone ) clone.appendChild( childClone );
+ }
+
+ // Drop empty elements (except self-closing ones)
+ if ( !clone.hasChildNodes() && !['BR', 'IMG'].includes( clone.tagName ) ) {
+ return null;
+ }
+ return clone;
+ }
+
+ // Drop comments and other node types
+ return null;
+ }
+
+ // Build a truncated copy of the HTML structure
+ const truncatedHtml = document.createDocumentFragment();
+ for ( let child of container.childNodes ) {
+ if ( remaining <= 0 ) break;
+ const chunk = cloneWithLimit( child );
+ if ( chunk ) truncatedHtml.appendChild( chunk );
+ }
+
+ // Serialize back to HTML
+ const wrapper = document.createElement( 'div' );
+ wrapper.appendChild( truncatedHtml );
+ return wrapper.innerHTML;
+}
+
// Focus to H2 heading in results section
function focusToView() {
let focusElement = resultsSection.querySelector( "h2" );
@@ -658,6 +873,11 @@ function initEngine() {
didYouMeanController = buildDidYouMean( headlessEngine, { options: { automaticallyCorrectQuery: params.automaticallyCorrectQuery } } );
pagerController = buildPager( headlessEngine, { options: { numberOfPages: params.numberOfPages } } );
statusController = buildSearchStatus( headlessEngine );
+
+ if( params.enableSmartSnippets ){
+ smartSnippetController = buildSmartSnippet( headlessEngine );
+ smartSnippetQuestionListController = buildSmartSnippetQuestionsList( headlessEngine );
+ }
// Refine search based on URL parameters for filters, mostly used in Advanced Search to trigger only one search per page load
if ( urlParams.allq || urlParams.exctq || urlParams.anyq || urlParams.noneq || urlParams.fqupdate || urlParams.dmn || urlParams.fqocct || urlParams.elctn_cat || urlParams.filetype || urlParams.site || urlParams.year || urlParams.declaredtype || urlParams.startdate || urlParams.enddate || urlParams.dprtmnt ) {
@@ -892,6 +1112,10 @@ function initEngine() {
unsubscribeQuerySummaryController = querySummaryController.subscribe( () => updateQuerySummaryState( querySummaryController.state ) );
unsubscribeDidYouMeanController = didYouMeanController.subscribe( () => updateDidYouMeanState( didYouMeanController.state ) );
unsubscribePagerController = pagerController.subscribe( () => updatePagerState( pagerController.state ) );
+ if( params.enableSmartSnippets ) {
+ unsubscribeSmartSnippetController = smartSnippetController.subscribe( () => updateSmartSnippetState( smartSnippetController.state ) );
+ unsubscribeSmartSnippetQuestionListController = smartSnippetQuestionListController.subscribe( () => updateSmartSnippetQuestionListState( smartSnippetQuestionListController.state ) );
+ }
// Clear event tracking, for legacy browsers
const onUnload = () => {
@@ -902,6 +1126,8 @@ function initEngine() {
unsubscribeQuerySummaryController?.();
unsubscribeDidYouMeanController?.();
unsubscribePagerController?.();
+ unsubscribeSmartSnippetController?.();
+ unsubscribeSmartSnippetQuestionListController?.();
};
// Listen to URL change (hash)
@@ -990,6 +1216,14 @@ function initEngine() {
didYouMeanElement.textContent = "";
pagerElement.textContent = "";
pagerManuallyCleared = true;
+ if( params.enableSmartSnippets ) {
+ if( smartSnippetsElement && smartSnippetsElement.textContent ) {
+ smartSnippetsElement.textContent = "";
+ }
+ if( smartSnippetQuestionListContainerElement && smartSnippetQuestionListContainerElement.textContent ) {
+ smartSnippetQuestionListContainerElement.textContent = "";
+ }
+ }
// Show no results message in Query Summary if no query entered
querySummaryElement.innerHTML = noResultTemplateHTML;
@@ -1414,5 +1648,110 @@ function updatePagerUrlParam( currentPage ) {
window.history.replaceState( {}, '', `${winPath}?${newSearch}${winLoc.hash}` );
}
+// Function in insert values into smart snippet HTML templates
+function insertSmartSnippetValues ( smartSnippetState, standalone = false, truncateLimit = -1) {
+ const { question, answer, source } = smartSnippetState;
+
+ var snippetHTML = (standalone ? smartSnippetHTML : smartSnippetQuestionListHTML)
+ snippetHTML = snippetHTML
+ .replace( '%[question]', DOMPurify.sanitize( question ) )
+ .replace( '%[answer]', DOMPurify.sanitize( answer ) )
+ .replace( '%[answer_truncated]', truncateHtml( DOMPurify.sanitize( answer ), truncateLimit ) );
+
+ if(source) {
+ var displaynavlabel = source?.raw?.displaynavlabel ? source.raw.displaynavlabel.split( '>' ).join( ' ' ) : source.uri
+ snippetHTML = snippetHTML.replace( '%[source.raw.displaynavlabel]', displaynavlabel )
+ .split( '%[source.title]' ).join ( source.title )
+ .split( '%[source.uri]' ).join ( source.uri );
+ }
+
+ return snippetHTML;
+}
+
+// Update the "featured" Smart Snippets section
+function updateSmartSnippetState ( newState ) {
+ console.log('newState', newState)
+ smartSnippetState = newState;
+ smartSnippetsElement.innerHTML = ''; // Clear contents of SM
+
+ // We don't get the full smart snippet state past the first page, so don't render anything
+ if( pagerState.currentPage > 1 ) return;
+
+ if( smartSnippetState.answerFound ) {
+ smartSnippetsElement.innerHTML = insertSmartSnippetValues( smartSnippetState, true, params.smartSnippetToggleLimit );
+
+ // If the length of the answer is less that params.smartSnippetToggleLimit, remove toggle controls
+ if( getTextLength( smartSnippetState.answer ) <= params.smartSnippetToggleLimit ) {
+
+ document.querySelector( '.smart-snippet-toggle-height' ).remove()
+ document.querySelector( '.smart-snippet-answer-truncated' ).remove()
+
+ } else {
+
+ // Add height toggle stuff
+ const smartSnippetsContainerElement = document.getElementById( 'smart-snippet-container' );
+ smartSnippetsContainerElement.classList.add( 'smart-snippet-height-limiter' ); // Collapse by default
+ const smartSnippetToggleButton = document.getElementById( 'smart-snippet-toggle' );
+ const smartSnippetAnswer = document.getElementById( 'smart-snippet-answer' );
+ smartSnippetAnswer.querySelectorAll( "a, link, button, input" ).forEach( ( el ) => {
+ el.setAttribute( 'disabled', 'true' );
+ el.setAttribute( 'tabindex', '-1' );
+ } )
+
+ // Handle the
+ smartSnippetToggleButton.addEventListener( 'click', (event) => {
+
+ // Expand the container
+ if(smartSnippetsContainerElement.classList.contains( 'smart-snippet-height-limiter' )){
+ smartSnippetsContainerElement.classList.remove( 'smart-snippet-height-limiter' )
+ smartSnippetAnswer.setAttribute( "aria-hidden", "false" );
+ smartSnippetAnswer.querySelectorAll( "a, link, button, input" ).forEach( ( el ) => {
+ el.removeAttribute( 'disabled' );
+ el.removeAttribute( 'tabindex' );
+ } )
+ smartSnippetToggleButton.setAttribute( "aria-expanded", "true" );
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-label' ).innerText = lang === "fr" ? "Afficher moins": "Show less";
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.remove( 'glyphicon-chevron-down' )
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.add( 'glyphicon-chevron-up' )
+
+ // Collapse the container
+ } else {
+ smartSnippetsContainerElement.classList.add( 'smart-snippet-height-limiter' );
+ smartSnippetAnswer.setAttribute( "aria-hidden", "true" );
+ smartSnippetToggleButton.setAttribute( "aria-expanded", "false" );
+ smartSnippetAnswer.querySelectorAll( "a, link, button, input" ).forEach( ( el ) => {
+ el.setAttribute( 'disabled', 'true' );
+ el.setAttribute( 'tabindex', '-1' );
+ } )
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-label' ).innerText = lang === "fr" ? "Afficher plus": "Show more";
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.add( 'glyphicon-chevron-down' )
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.remove( 'glyphicon-chevron-up' )
+ smartSnippetToggleButton.focus()
+ }
+ } )
+
+ }
+ }
+}
+
+// Update the Smart Snippets questions section
+function updateSmartSnippetQuestionListState ( newState ) {
+ smartSnippetQuestionListState = newState;
+ smartSnippetQuestionListContainerElement.innerHTML = ''; // Clear contents of SS question list container
+
+ // We don't get the full smart snippet state past the first page, so don't render anything
+ if( pagerState.currentPage > 1 ) return;
+
+ // If there are questions, populate smartSnippetQuestionListItemsHTML
+ if( smartSnippetQuestionListState?.questions && smartSnippetQuestionListState?.questions.length > 0 ) {
+ let smartSnippetQuestionListItemsHTML = '';
+ for ( const i in smartSnippetQuestionListState.questions ) {
+ smartSnippetQuestionListItemsHTML += insertSmartSnippetValues( smartSnippetQuestionListState.questions[i], false )
+ }
+ smartSnippetQuestionListContainerElement.innerHTML = smartSnippetQuestionListContainerHTML.split( '%[smart_snippet_question_list]' ).join( smartSnippetQuestionListItemsHTML );
+ }
+
+}
+
// Run Search UI
initSearchUI();
From 10c90873b84ccd66b2aec3317a7df3e209bebf40 Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Fri, 14 Nov 2025 12:36:10 -0700
Subject: [PATCH 2/7] Linter fixes
---
src/connector.js | 75 ++++++++++++++++++++++++------------------------
1 file changed, 37 insertions(+), 38 deletions(-)
diff --git a/src/connector.js b/src/connector.js
index 0fc767e..8f76106 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -417,15 +417,14 @@ function initTpl() {
`;
- // Localize
- if ( lang === "fr" ) {
- smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" )
- smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Afficher plus" )
- } else {
- smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'The information was retrieved by Artificial Intelligence' )
- smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Show more" )
- }
-
+ // Localize
+ if ( lang === "fr" ) {
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" );
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Afficher plus" );
+ } else {
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'The information was retrieved by Artificial Intelligence' );
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Show more" );
+ }
}
// Smart snippet - Question list container
@@ -446,9 +445,9 @@ function initTpl() {
// Localize
if ( lang === "fr" ) {
- smartSnippetQuestionListContainerHTML = smartSnippetQuestionListContainerHTML.replace( '%[smart_snippet_question_list_title]', 'Les gens demandent aussi' )
+ smartSnippetQuestionListContainerHTML = smartSnippetQuestionListContainerHTML.replace( '%[smart_snippet_question_list_title]', 'Les gens demandent aussi' );
} else {
- smartSnippetQuestionListContainerHTML = smartSnippetQuestionListContainerHTML.replace( '%[smart_snippet_question_list_title]', 'People also ask' )
+ smartSnippetQuestionListContainerHTML = smartSnippetQuestionListContainerHTML.replace( '%[smart_snippet_question_list_title]', 'People also ask' );
}
}
@@ -507,12 +506,12 @@ function initTpl() {
`;
- // Localize
- if ( lang === "fr" ) {
- smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" )
- } else {
- smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'Information retrieved by artificial intelligence.' )
- }
+ // Localize
+ if ( lang === "fr" ) {
+ smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" );
+ } else {
+ smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'Information retrieved by artificial intelligence.' );
+ }
}
// Smart snippets - Questions list container
@@ -645,15 +644,15 @@ function getTextLength( content ){
elem = document.createElement( 'div' );
elem.innerHTML = String( content );
} else {
- elem = content
+ elem = content;
}
// Get the inside content
- var fullText = elem.textContent || ''
+ var fullText = elem.textContent || '';
// Strip out extra whitespace, like indenting
- fullText = fullText.replace( /[\n\r]+|[\s]{2,}/g, ' ' ).trim()
- return fullText.length
+ fullText = fullText.replace( /[\n\r]+|[\s]{2,}/g, ' ' ).trim();
+ return fullText.length;
}
@@ -1652,14 +1651,14 @@ function updatePagerUrlParam( currentPage ) {
function insertSmartSnippetValues ( smartSnippetState, standalone = false, truncateLimit = -1) {
const { question, answer, source } = smartSnippetState;
- var snippetHTML = (standalone ? smartSnippetHTML : smartSnippetQuestionListHTML)
+ var snippetHTML = (standalone ? smartSnippetHTML : smartSnippetQuestionListHTML);
snippetHTML = snippetHTML
.replace( '%[question]', DOMPurify.sanitize( question ) )
.replace( '%[answer]', DOMPurify.sanitize( answer ) )
.replace( '%[answer_truncated]', truncateHtml( DOMPurify.sanitize( answer ), truncateLimit ) );
if(source) {
- var displaynavlabel = source?.raw?.displaynavlabel ? source.raw.displaynavlabel.split( '>' ).join( ' ' ) : source.uri
+ var displaynavlabel = source?.raw?.displaynavlabel ? source.raw.displaynavlabel.split( '>' ).join( ' ' ) : source.uri;
snippetHTML = snippetHTML.replace( '%[source.raw.displaynavlabel]', displaynavlabel )
.split( '%[source.title]' ).join ( source.title )
.split( '%[source.uri]' ).join ( source.uri );
@@ -1670,7 +1669,7 @@ function insertSmartSnippetValues ( smartSnippetState, standalone = false, trunc
// Update the "featured" Smart Snippets section
function updateSmartSnippetState ( newState ) {
- console.log('newState', newState)
+
smartSnippetState = newState;
smartSnippetsElement.innerHTML = ''; // Clear contents of SM
@@ -1683,8 +1682,8 @@ function updateSmartSnippetState ( newState ) {
// If the length of the answer is less that params.smartSnippetToggleLimit, remove toggle controls
if( getTextLength( smartSnippetState.answer ) <= params.smartSnippetToggleLimit ) {
- document.querySelector( '.smart-snippet-toggle-height' ).remove()
- document.querySelector( '.smart-snippet-answer-truncated' ).remove()
+ document.querySelector( '.smart-snippet-toggle-height' ).remove();
+ document.querySelector( '.smart-snippet-answer-truncated' ).remove();
} else {
@@ -1696,23 +1695,23 @@ function updateSmartSnippetState ( newState ) {
smartSnippetAnswer.querySelectorAll( "a, link, button, input" ).forEach( ( el ) => {
el.setAttribute( 'disabled', 'true' );
el.setAttribute( 'tabindex', '-1' );
- } )
+ } );
// Handle the
- smartSnippetToggleButton.addEventListener( 'click', (event) => {
+ smartSnippetToggleButton.addEventListener( 'click', () => {
// Expand the container
if(smartSnippetsContainerElement.classList.contains( 'smart-snippet-height-limiter' )){
- smartSnippetsContainerElement.classList.remove( 'smart-snippet-height-limiter' )
+ smartSnippetsContainerElement.classList.remove( 'smart-snippet-height-limiter' );
smartSnippetAnswer.setAttribute( "aria-hidden", "false" );
smartSnippetAnswer.querySelectorAll( "a, link, button, input" ).forEach( ( el ) => {
el.removeAttribute( 'disabled' );
el.removeAttribute( 'tabindex' );
- } )
+ } );
smartSnippetToggleButton.setAttribute( "aria-expanded", "true" );
smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-label' ).innerText = lang === "fr" ? "Afficher moins": "Show less";
- smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.remove( 'glyphicon-chevron-down' )
- smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.add( 'glyphicon-chevron-up' )
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.remove( 'glyphicon-chevron-down' );
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.add( 'glyphicon-chevron-up' );
// Collapse the container
} else {
@@ -1722,13 +1721,13 @@ function updateSmartSnippetState ( newState ) {
smartSnippetAnswer.querySelectorAll( "a, link, button, input" ).forEach( ( el ) => {
el.setAttribute( 'disabled', 'true' );
el.setAttribute( 'tabindex', '-1' );
- } )
+ } );
smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-label' ).innerText = lang === "fr" ? "Afficher plus": "Show more";
- smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.add( 'glyphicon-chevron-down' )
- smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.remove( 'glyphicon-chevron-up' )
- smartSnippetToggleButton.focus()
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.add( 'glyphicon-chevron-down' );
+ smartSnippetToggleButton.querySelector( '#smart-snippet-toggle-icon' ).classList.remove( 'glyphicon-chevron-up' );
+ smartSnippetToggleButton.focus();
}
- } )
+ } );
}
}
@@ -1746,7 +1745,7 @@ function updateSmartSnippetQuestionListState ( newState ) {
if( smartSnippetQuestionListState?.questions && smartSnippetQuestionListState?.questions.length > 0 ) {
let smartSnippetQuestionListItemsHTML = '';
for ( const i in smartSnippetQuestionListState.questions ) {
- smartSnippetQuestionListItemsHTML += insertSmartSnippetValues( smartSnippetQuestionListState.questions[i], false )
+ smartSnippetQuestionListItemsHTML += insertSmartSnippetValues( smartSnippetQuestionListState.questions[i], false );
}
smartSnippetQuestionListContainerElement.innerHTML = smartSnippetQuestionListContainerHTML.split( '%[smart_snippet_question_list]' ).join( smartSnippetQuestionListItemsHTML );
}
From e078b6f006cedfec543310a8dad3ece8a6cae394 Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Fri, 14 Nov 2025 13:00:39 -0700
Subject: [PATCH 3/7] Update connector.js
---
src/connector.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/connector.js b/src/connector.js
index 8f76106..9f900f0 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -396,7 +396,7 @@ function initTpl() {
%[question]
-
+
%[answer]
%[smart_snippet_answer_ai_disclaimer]
From c52c1effc58ea2ef259ead62e09a9581f62e0c13 Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Fri, 14 Nov 2025 13:04:30 -0700
Subject: [PATCH 4/7] French disclaimer
---
src/connector.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/connector.js b/src/connector.js
index 9f900f0..f39f09f 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -419,7 +419,7 @@ function initTpl() {
// Localize
if ( lang === "fr" ) {
- smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" );
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Information récupérée en utilisant l'intelligence artificielle." );
smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Afficher plus" );
} else {
smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'The information was retrieved by Artificial Intelligence' );
From 6e1e213fc88560429809f00081d5d6045da75766 Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Mon, 17 Nov 2025 13:35:04 -0700
Subject: [PATCH 5/7] Updates
---
src/connector.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/connector.js b/src/connector.js
index f39f09f..974781c 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -399,7 +399,7 @@ function initTpl() {
%[answer]
-
%[smart_snippet_answer_ai_disclaimer]
+
%[smart_snippet_answer_ai_disclaimer]
%[answer_truncated]
@@ -412,7 +412,7 @@ function initTpl() {
-
+
- %[source.raw.displaynavlabel]
`;
@@ -422,7 +422,7 @@ function initTpl() {
smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Information récupérée en utilisant l'intelligence artificielle." );
smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Afficher plus" );
} else {
- smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'The information was retrieved by Artificial Intelligence' );
+ smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'Information retrieved by artificial intelligence.' );
smartSnippetHTML = smartSnippetHTML.replace( '%[smart_snippet_toggle_more]', "Show more" );
}
}
@@ -499,7 +499,7 @@ function initTpl() {
-
+
- %[source.raw.displaynavlabel]
@@ -508,7 +508,7 @@ function initTpl() {
// Localize
if ( lang === "fr" ) {
- smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Les informations ont été récupérées par l'intelligence artificielle" );
+ smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', "Information récupérée en utilisant l'intelligence artificielle." );
} else {
smartSnippetQuestionListHTML = smartSnippetQuestionListHTML.replace( '%[smart_snippet_answer_ai_disclaimer]', 'Information retrieved by artificial intelligence.' );
}
From 19e2bbfbf603045081c0e8c4e8faf36796733783 Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Tue, 18 Nov 2025 08:34:16 -0700
Subject: [PATCH 6/7] Latest feedback
---
src/connector.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/connector.js b/src/connector.js
index 974781c..46e0564 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -399,7 +399,7 @@ function initTpl() {
%[answer]
-
%[smart_snippet_answer_ai_disclaimer]
+
%[smart_snippet_answer_ai_disclaimer]
%[answer_truncated]
From 5b5146cb327cd60cec8f7d0b4bc178a257f3896c Mon Sep 17 00:00:00 2001
From: Cody Foss <160176245+cfoss-coveo@users.noreply.github.com>
Date: Wed, 19 Nov 2025 08:45:56 -0700
Subject: [PATCH 7/7] Update connector.js
---
src/connector.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/connector.js b/src/connector.js
index 46e0564..76bdbed 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -493,11 +493,10 @@ function initTpl() {
%[question]
-
+
%[answer]
-
%[smart_snippet_answer_ai_disclaimer]
+
%[smart_snippet_answer_ai_disclaimer]
-
- %[source.raw.displaynavlabel]