diff --git a/README.md b/README.md
index 54f220d..82b86de 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,33 @@
# Project: Search UI
-Purpose of this repository is to provide MWS pages with the proper JS and CSS assets to achieve a working search page with the vendor's (Coveo) technology called Headless.
+Purpose of this repository is to provide MWS pages with the proper JS and CSS assets to achieve working search pages with the vendor's (Coveo) technology called Headless, sitting on top of GCWeb.
## References
- Coveo Headless: https://docs.coveo.com/en/headless/latest/
+- GCWeb: https://wet-boew.github.io/GCWeb/index-en.html
## Key details
### Sponsor / Contact
-This project is led by Principal Publisher at ESDC. The key contact in case of questions related to the project is Francis Gorman, who can be reached at francis.gorman@hrsdc-rhdcc.gc.ca. If no reply is received from this person, fallback contact is ESDC.SD.DEV-DEV.DS.EDSC@servicecanada.gc.ca.
+This project is led by Principal Publisher at Service Canada (ESDC). The key contact in case of questions related to the project is Francis Gorman, who can be reached at francis.gorman@hrsdc-rhdcc.gc.ca. If no reply is received from this person, fallback contact is ESDC.SD.DEV-DEV.DS.EDSC@servicecanada.gc.ca.
### Timeline and frequency
The goal is to continue to refine and improve this code base on a regular basis. Every 6 months, if no activity is recorded on this repository, the key contact shall be reached out to in order to ensure it isn't stale.
-**Removal date** will coincide with end of contract with vendor.
+**Removal date** would align with end of contract with current vendor.
### Improvement plan
To manage development activities related to this project, a standard internal issue tracking system used at Principal Publisher will be used. Also, regular touchpoints with the search vendor, as well as formal service requests entered through their portal, could also spark some development activities from a vendor perspective.
-In the medium to long term, some activities may take place related to:
-- stabilization of the query suggestion combobox;
-- porting of some parts of the codebase to GCWeb;
-- addition of machine learning features.
+Example of code contributions may be related to:
+
+- development/configurations of AI-powered features and other innovations
+- bug fixes, accessibility and security improvements
+- project maintenance chores
For more details, please [consult full checklist of to do items](todo.md).
@@ -41,7 +43,7 @@ Search UI follows [Semantic Versioning 2.0.0](https://semver.org/)
## Getting started
-This rubric is for developers.
+This rubric is for developers and testers.
### Build files for release or to test code quality before opening a Pull request
@@ -54,30 +56,36 @@ This rubric is for developers.
#### Test locally
1. Install Docker
-2. Add an API key to your site settings as described below in [Setting an API key](#setting-an-api-key). Otherwise, please see [Alternative to the API key by getting a token](#alternative-to-the-api-key-by-getting-a-token) below.
+2. Add an API key to your site settings as described below in [Setting an API key](#setting-an-api-key).
3. run `docker compose up --build`
##### Setting an API key
-1. Create a `_data` folder at the root. Then, add a file named `token.yml` inside the `_data` folder. This file needs to simply have a key-value pair of `API_KEY: "[API KEY HERE]"` on line 1. The key value can be found at https://github.com/ServiceCanada/devops-documentation/blob/master/search/local-testing.md to replace the `[API KEY HERE]`. If you do not have access to the previous link, please see the next section on how to use a token as described below.
+Create a `_data` folder at the root. Then, add a file named `token.yml` inside the `_data` folder. This file needs to simply have a key-value pair of `API_KEY: "[API KEY HERE]"` on line 1. The key value can be found at https://github.com/ServiceCanada/devops-documentation/blob/master/search/local-testing.md to replace the `[API KEY HERE]`. If you do not have access to the previous link and/or are unable to get an API key, you can use a token instead; in which case, see the [Getting a token](#getting-a-token) section below.
+
+#### Testing through GitHub Pages
-##### Alternative to the API key by getting a token
+##### Main website
-Since you need a token to communicate with the Coveo API, you can do the following to go to get a token valid for 24 hrs:
+At all time, you can visit the GitHub website to view and test the GC Search UI with the latest Pull requests merged at play: https://servicecanada.github.io/search-ui/.
-1. Go to a search page on the Canada.ca Preview server such as: **/en/sr/srb.html**.
-2. Open the inspector (developer tool) and look for the `div` tag that has the attribute called `data-gc-search`.
-3. Inside this attribute, you'll find a Javascript object that has a field called `accessToken`. Grab the value of that token.
-4. a) If you are **testing locally**, create a `_data` folder at the root. Then, add a file named `token.yml` inside the `_data` folder. This file needs to simply have a key-value pair of `API_KEY: "[API KEY HERE]"` on line 1. Add the token value as the key in `[API KEY HERE]`. b) If you are **testing through GitHub pages**, replace instances of `{{ site.data.token.API_KEY }}` with the token, on HTML pages would like to test.
-5. If the token doesn't seem valid or if you have passed the 24 hours time-to-live (TTL), go back to step one and take another one from the Canada.ca Preview server.
+Since search pages need a token to communicate with the Coveo API and functioning properly, you will need to get your token by following the instructions in the [Getting a token](#getting-a-token) section below. You can then take this token and save it through the form linked from the website's index page under the "Test pages" section. Your token will be saved for the duration of your session on the website. If you close the tab or stay inactive for a while, you will need to go back and generate a new one.
-#### Testing through GitHub Pages
+##### In your fork
-1. Add the required token on HTML pages would like to test by [following the instructions on Alternative to the API key by getting a token](#alternative-to-the-api-key-by-getting-a-token). Do not use the `token.yml` approach documented for testing locally, since it may generate potential a [security risk](SECURITY.md) in the context of GitHub pages.
-2. Push your code to a branch of your choice in your origin remote (fork). It is recommended that you use a dedicated branch for testing, one that you would never open a Pull request from.
+This is usually to test your changes before opening a pull request, or to conduct usability testing and accessibility assessments.
+
+1. Do not use the `token.yml` approach documented for testing locally, since it may generate potential a [security risk](SECURITY.md) in the context of GitHub pages. Instead, get a token described in the [Getting a token](#getting-a-token) section below and replace instances of `{{ site.data.token.API_KEY }}` with the token, on HTML pages would like to test.
+2. Push your code to a branch of your choice in your origin remote (fork). It is recommendeded that you use a dedicated branch for testing, one that you would never open a Pull request from.
3. Make sure your repository has GitHub Pages enabled, on that specific above-mentioned branch.
4. Your site is live on GitHub pages!
+**Important note:** A token is only available for 24 hrs, after which a new one must be generated. Alternatively, instead of putting a token on all pages, you can let the user get their own token through the same process as described in the [Main website](#main-website) section above.
+
+##### Getting a token
+
+While on the GC network, go to the [Search token](https://canada-preview.adobecqms.net/en/service-canada/francis/get-sr-token.html) page and copy the value of the entire token loaded inside the page.
+
### Deployment
1. The content of the "dist" folder is what's needed for a release / deployment. See [Build files](#build-files) section above to generate this folder.
@@ -102,6 +110,8 @@ They must be used within the `[data-gc-search]` attribute. See the **/test/src-e
: Langague of the text to output, in short format (`en` or `fr`). Will detect the langauge of the HTML page if not defined. If not determined, default is: `en`
- `numberOfSuggestions`
: Number of suggestions to show in the Query Suggestion (QS) box. This will activate the QS feature on your search page. Default: `0`
+- `minimumCharsForSuggestions`
+: Number of characters entered by the users needed to trigger the QS feature
- `enableHistoryPush`
: Allows for UI elements that are not hyperlink tags to register their action in the history, such as pagination. Default: `true`
- `isContextSearch`
@@ -109,7 +119,7 @@ They must be used within the `[data-gc-search]` attribute. See the **/test/src-e
- `isAdvancedSearch`
: Set the search behavior of the page as an advanced search. This is optional since it will detect automatically from the path of your page if it is advanced. If not determined, default is: `false`
- `originLevel3`
-: Allows for mimicking a specific search page/context, such as the ESDC contextual search if you set it to: `/en/employment-social-development/search.html`. Default is the current page relative location (domain agnostic).
+: Allows for mimicking a specific search page/context, such as the ESDC contextual search if you set it to: `/en/employment-social-development/search.html`; this value can be be relative or absolute and is used to differentiate and contextualize a search page from another both in terms of scoping the search results and in terms of knowledge base for machine learning-powered features. Default is set to the current page's absolute URL
#### Templates
@@ -218,10 +228,118 @@ Sometimes your search pages contain more than one input relevant to the search's
- `filetype`
: Search , within documents of a certain file type. Options are: `application/pdf`, `ps`, `application/msword`, `application/vnd.ms-excel`, `application/vnd.ms-powerpoint`, `application/rtf`
- `originLevel3`
-: Allows for mimicking a specific search page/context by setting its path through this URL parameter
+: Allows for mimicking a specific search page/context by setting its path through this URL parameter; this takes precedence over the configuration through data attribute
### Other
#### Analytics tracking
-Custom event named `searchEvent` can used to hook onto from Analytics tools, such as Adobe Analytics. This allows to listen to search actions, more specifically "doing a search", since the Search UI is acting similar to a Single Page App (SPA).
+Custom event named `searchEvent` can used to hook onto from Analytics tools, such as Adobe Analytics. This allows to listen to search actions, more specifically "doing a search", since the Search UI is acting similar to a Single Page App (SPA). The payload varies based on the event type triggered, which is usually dictated by the `actionCause`. In the case where there is no `actionCause` in the payload of a beacon, then the `eventType` will tell you more about it. List of action causes:
+
+- interfaceLoad
+: Search interface was initially loaded (or refreshed) with a search term
+- searchboxSubmit
+: any subsequent searches from the search box
+- omniboxAnalytics
+: User clicks on a query suggestion
+- documentOpen
+: User clicks on a search result
+
+And the main event type for when an action cause is not provided:
+
+- getMoreResults
+: User clicked on a pagination button
+
+They each carry the following fields in their respective payloads:
+
+##### interfaceLoad
+
+- language
+- userAgent
+- originContext
+- originLevel1
+- originLevel2
+- originLevel3
+- splitTestRunName
+- splitTestRunVersion
+- customData
+ - context_searchPageUrl
+ - c_context_searchpagerelativeurl
+ - coveoHeadlessVersion
+- facetState
+- anonymous
+- clientId
+- queryText
+- responseTime
+- results
+ - documentUri
+ - documentUriHash
+- numberOfResults
+- queryPipeline
+- actionCause
+- searchQueryUid
+
+##### searchboxSubmit
+
+Same as [interfaceLoad](#interfaceLoad).
+
+##### documentOpen
+
+Same as [interfaceLoad](#interfaceLoad), plus the following:
+
+- collectionName
+- documentAuthor
+- documentPosition
+- documentTitle
+- documentUri
+- documentUriHash
+- documentUrl
+- rankingModifier
+- sourceName
+- customData
+ - context_searchPageUrl
+ - c_context_searchpagerelativeurl
+ - coveoHeadlessVersion
+ - contentIDKey
+ - contentIDValue
+
+##### omniboxAnalytics
+
+Same as [interfaceLoad](#interfaceLoad), plus the following:
+
+- customData
+ - context_searchPageUrl
+ - c_context_searchpagerelativeurl
+ - coveoHeadlessVersion
+ - suggestionRanking
+ - partialQuery
+ - partialQueries
+ - suggestions
+ - querySuggestResponseId
+ - queryText
+
+##### getMoreResults
+
+- language
+- userAgent
+- originContext
+- originLevel1
+- originLevel2
+- originLevel3
+- splitTestRunName
+- splitTestRunVersion
+- customData
+ - context_searchPageUrl
+ - c_context_searchpagerelativeurl
+ - coveoHeadlessVersion
+ - pagerNumber
+- facetState
+- anonymous
+- clientId
+- eventType
+- eventValue
+- lastSearchQueryUid
+
+#### Removing on-page content from index
+
+You can add the class `sr-no-index` to any HTML element inside the main content of your page if you wish for that content to be ignored by the search engine. In which case, said content won't be indexed nor returned in the search result excerpts.
diff --git a/index.html b/index.html
index 2b0227c..cf59828 100644
--- a/index.html
+++ b/index.html
@@ -7,17 +7,20 @@
This is a demo site for the GC Search UI.
Test pages
+To test search pages, please make sure you have a valid token.
Regular pages
Advanced tests
diff --git a/package-lock.json b/package-lock.json
index 224d009..6fc07d4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "search-ui",
- "version": "1.5.0",
+ "version": "1.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 4f5f090..631927a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "search-ui",
- "version": "1.5.0",
+ "version": "1.6.0",
"description": "Canada.ca Search UI with Headless",
"main": "index.html",
"repository": {
diff --git a/src/connector.js b/src/connector.js
index 0b52807..a37156b 100644
--- a/src/connector.js
+++ b/src/connector.js
@@ -9,6 +9,7 @@ import {
buildDidYouMean,
buildContext,
buildInteractiveResult,
+ buildNotifyTrigger,
loadAdvancedSearchQueryActions,
loadSortCriteriaActions,
HighlightUtils,
@@ -30,8 +31,8 @@ const defaults = {
"accessToken":"",
"searchBoxQuery": "#sch-inp-ac",
"lang": "en",
- "numberOfSuggestions": 0,
- "minimumCharsForSuggestions": 2,
+ "numberOfSuggestions": 5,
+ "minimumCharsForSuggestions": 3,
"enableHistoryPush": true,
"isContextSearch": false,
"isAdvancedSearch": false,
@@ -44,6 +45,7 @@ let paramsDetect = {};
let params = {};
let urlParams;
let hashParams;
+let originLevel3RelativeUrl = "";
// Headless controllers
let headlessEngine;
@@ -54,6 +56,7 @@ let querySummaryController;
let didYouMeanController;
let pagerController;
let statusController;
+let notifyTriggerController;
let urlManager;
let unsubscribeManager;
let unsubscribeSearchBoxController;
@@ -61,17 +64,20 @@ let unsubscribeResultListController;
let unsubscribeQuerySummaryController;
let unsubscribeDidYouMeanController;
let unsubscribePagerController;
+let unsubscribeNotifyTriggerController;
// UI states
let updateSearchBoxFromState = false;
let searchBoxState;
let resultListState;
let querySummaryState;
+let notificationState;
let didYouMeanState;
let pagerState;
let lastCharKeyUp;
let activeSuggestion = 0;
let activeSuggestionWaitMouseMove = true;
+let pagerManuallyCleared = false;
// Firefox patch
let isFirefox = navigator.userAgent.indexOf( "Firefox" ) !== -1;
@@ -83,6 +89,7 @@ let formElement = document.querySelector( '#gc-searchbox, form[action="#wb-land"
let resultsSection = document.querySelector( '#wb-land' );
let resultListElement = document.querySelector( '#result-list' );
let querySummaryElement = document.querySelector( '#query-summary' );
+let notificationTriggerElement = document.querySelector( '#notification-trigger' );
let pagerElement = document.querySelector( '#pager' );
let suggestionsElement = document.querySelector( '#suggestions' );
let didYouMeanElement = document.querySelector( '#did-you-mean' );
@@ -91,11 +98,12 @@ let didYouMeanElement = document.querySelector( '#did-you-mean' );
let resultTemplateHTML = document.getElementById( 'sr-single' )?.innerHTML;
let noResultTemplateHTML = document.getElementById( 'sr-nores' )?.innerHTML;
let resultErrorTemplateHTML = document.getElementById( 'sr-error' )?.innerHTML;
+let notificationTriggerTemplateHTML = document.getElementById( 'sr-notification-trigger' )?.innerHTML;
let querySummaryTemplateHTML = document.getElementById( 'sr-query-summary' )?.innerHTML;
let didYouMeanTemplateHTML = document.getElementById( 'sr-did-you-mean' )?.innerHTML;
let noQuerySummaryTemplateHTML = document.getElementById( 'sr-noquery-summary' )?.innerHTML;
let previousPageTemplateHTML = document.getElementById( 'sr-pager-previous' )?.innerHTML;
-let pageTemplateHTML = document.getElementById( 'sr-pager-page-' )?.innerHTML;
+let pageTemplateHTML = document.getElementById( 'sr-pager-page' )?.innerHTML;
let nextPageTemplateHTML = document.getElementById( 'sr-pager-next' )?.innerHTML;
let pagerContainerTemplateHTML = document.getElementById( 'sr-pager-container' )?.innerHTML;
@@ -151,6 +159,20 @@ function initSearchUI() {
if ( urlParams.originLevel3 ){
params.originLevel3 = urlParams.originLevel3;
}
+
+ // Auto detect relative path from originLevel3
+ if( !params.originLevel3.startsWith( "/" ) && /http|www/.test( params.originLevel3 ) ) {
+ try {
+ const absoluteURL = new URL( params.originLevel3 );
+ originLevel3RelativeUrl = absoluteURL.pathname;
+ }
+ catch( exception ) {
+ console.warn( "Exception while auto detecting relative path: " + exception.message );
+ }
+ }
+ else {
+ originLevel3RelativeUrl = params.originLevel3;
+ }
if ( !params.endpoints ) {
params.endpoints = getOrganizationEndpoints( params.organizationId, 'prod' );
@@ -230,6 +252,23 @@ function initTpl() {
}
}
+ if ( !notificationTriggerTemplateHTML ) {
+ if ( lang === "fr" ) {
+ notificationTriggerTemplateHTML =
+ `
+ Notification
+ %[notification]
+ `;
+ }
+ else {
+ notificationTriggerTemplateHTML =
+ `
+ Notification
+ %[notification]
+ `;
+ }
+ }
+
if ( !querySummaryTemplateHTML ) {
if ( lang === "fr" ) {
querySummaryTemplateHTML =
@@ -323,6 +362,14 @@ function initTpl() {
baseElement.prepend( resultsSection );
}
+ // auto-create notification trigger element
+ if ( !notificationTriggerElement ) {
+ notificationTriggerElement = document.createElement( "div" );
+ notificationTriggerElement.id = "notification-trigger";
+
+ resultsSection.append( notificationTriggerElement );
+ }
+
// auto-create query summary element
if ( !querySummaryElement ) {
querySummaryElement = document.createElement( "div" );
@@ -354,12 +401,12 @@ function initTpl() {
newPagerElement.innerHTML = pagerContainerTemplateHTML;
resultsSection.append( newPagerElement );
- pagerElement = newPagerElement.querySelector( "#pager" );
+ pagerElement = newPagerElement;
}
// auto-create suggestions element
searchBoxElement = document.querySelector( params.searchBoxQuery );
- if ( !suggestionsElement && searchBoxElement && params.numberOfSuggestions > 0 ) {
+ if ( !suggestionsElement && searchBoxElement && params.numberOfSuggestions > 0 && !params.isAdvancedSearch ) {
searchBoxElement.role = "combobox";
searchBoxElement.setAttribute( 'aria-autocomplete', 'list' );
@@ -418,7 +465,12 @@ function initEngine() {
// filter user sensitive content
requestContent.enableQuerySyntax = params.isAdvancedSearch;
- requestContent.mlParameters = { "filters": { "c_context_searchpageurl": params.originLevel3 } };
+ requestContent.mlParameters = {
+ "filters": {
+ "c_context_searchpageurl": params.originLevel3,
+ "c_context_searchpagerelativeurl": originLevel3RelativeUrl
+ }
+ };
if ( requestContent.analytics ) {
requestContent.analytics.originLevel3 = params.originLevel3;
@@ -438,8 +490,8 @@ function initEngine() {
} );
contextController = buildContext( headlessEngine );
- contextController.set( { "searchPageUrl" : params.originLevel3 } );
-
+ contextController.set( { "searchPageUrl" : params.originLevel3, "searchPageRelativeUrl" : originLevel3RelativeUrl } );
+
// build controllers
searchBoxController = buildSearchBox( headlessEngine, {
options: {
@@ -462,6 +514,7 @@ function initEngine() {
didYouMeanController = buildDidYouMean( headlessEngine, { options: { automaticallyCorrectQuery: false } } );
pagerController = buildPager( headlessEngine, { options: { numberOfPages: 9 } } );
statusController = buildSearchStatus( headlessEngine );
+ notifyTriggerController = buildNotifyTrigger( headlessEngine );
if ( urlParams.allq || urlParams.exctq || urlParams.anyq || urlParams.noneq || urlParams.fqupdate ||
urlParams.dmn || urlParams.fqocct || urlParams.elctn_cat || urlParams.filetype || urlParams.site || urlParams.year ) {
@@ -667,6 +720,7 @@ function initEngine() {
unsubscribeQuerySummaryController = querySummaryController.subscribe( () => updateQuerySummaryState( querySummaryController.state ) );
unsubscribeDidYouMeanController = didYouMeanController.subscribe( () => updateDidYouMeanState( didYouMeanController.state ) );
unsubscribePagerController = pagerController.subscribe( () => updatePagerState( pagerController.state ) );
+ unsubscribeNotifyTriggerController = notifyTriggerController.subscribe( () => updateNotifyTriggerState( notifyTriggerController.state ) );
// Clear event tracking, for legacy browsers
const onUnload = () => {
@@ -677,6 +731,7 @@ function initEngine() {
unsubscribeQuerySummaryController?.();
unsubscribeDidYouMeanController?.();
unsubscribePagerController?.();
+ unsubscribeNotifyTriggerController?.();
};
// Listen to URL change (hash)
@@ -763,6 +818,7 @@ function initEngine() {
querySummaryElement.textContent = "";
didYouMeanElement.textContent = "";
pagerElement.textContent = "";
+ pagerManuallyCleared = true;
}
};
}
@@ -983,8 +1039,9 @@ function updateResultListState( newState ) {
}
let breadcrumb = "";
- let printableUri = stripHtml( result.printableUri );
- let clickUri = stripHtml( result.clickUri );
+ let printableUri = encodeURI( result.printableUri );
+ printableUri = printableUri.replaceAll( '&' , '&' );
+ let clickUri = encodeURI( result.clickUri );
let title = stripHtml( result.title );
if ( result.raw.hostname && result.raw.displaynavlabel ) {
const splittedNavLabel = ( Array.isArray( result.raw.displaynavlabel ) ? result.raw.displaynavlabel[0] : result.raw.displaynavlabel).split( '>' );
@@ -992,7 +1049,7 @@ function updateResultListState( newState ) {
' ' + stripHtml( splittedNavLabel[splittedNavLabel.length-1] ) + '';
}
else {
- breadcrumb = '' + printableUri + '
';
+ breadcrumb = '' + printableUri + '
';
}
sectionNode.innerHTML = resultTemplateHTML
@@ -1002,7 +1059,7 @@ function updateResultListState( newState ) {
.replace( '%[result.title]', title )
.replace( '%[result.raw.author]', author )
.replace( '%[result.breadcrumb]', breadcrumb )
- .replace( '%[result.printableUri]', printableUri.replaceAll( '&' , '&' ) )
+ .replace( '%[result.printableUri]', printableUri )
.replace( '%[short-date-en]', getShortDateFormat( resultDate ) )
.replace( '%[short-date-fr]', getShortDateFormat( resultDate ) )
.replace( '%[long-date-en]', getLongDateFormat( resultDate, 'en' ) )
@@ -1028,6 +1085,18 @@ function updateResultListState( newState ) {
}
}
+// Update notification displayed
+function updateNotifyTriggerState ( newState ) {
+ notificationState = newState;
+
+ if ( notificationState.notifications?.length ) {
+ notificationTriggerElement.innerHTML = notificationTriggerTemplateHTML.replace( "%[notification]", notificationState.notifications[0] );
+ }
+ else {
+ notificationTriggerElement.textContent = "";
+ }
+}
+
// Update heading that has number of results displayed
function updateQuerySummaryState( newState ) {
querySummaryState = newState;
@@ -1039,6 +1108,11 @@ function updateQuerySummaryState( newState ) {
if ( resultListState.firstSearchExecuted && !querySummaryState.isLoading && !querySummaryState.hasError ) {
querySummaryElement.textContent = "";
if ( querySummaryState.total > 0 ) {
+ // Manually ask pager to redraw since even is not sent when manually cleared
+ if ( pagerManuallyCleared ) {
+ updatePagerState( pagerState );
+ }
+
let numberOfResults = querySummaryState.total.toLocaleString( params.lang );
// Generate the text content
const querySummaryHTML = ( ( querySummaryState.query !== "" && !params.isAdvancedSearch ) ? querySummaryTemplateHTML : noQuerySummaryTemplateHTML )
@@ -1057,11 +1131,13 @@ function updateQuerySummaryState( newState ) {
querySummaryElement.innerHTML = noResultTemplateHTML;
}
focusToView();
+ pagerManuallyCleared = false;
}
else if ( querySummaryState.hasError ) {
querySummaryElement.textContent = "";
querySummaryElement.innerHTML = resultErrorTemplateHTML;
focusToView();
+ pagerManuallyCleared = false;
}
}
@@ -1101,7 +1177,16 @@ function updateDidYouMeanState( newState ) {
// Update pagination
function updatePagerState( newState ) {
pagerState = newState;
- pagerElement.textContent = "";
+ if ( pagerState.maxPage === 0 ) {
+ pagerElement.textContent = "";
+ return;
+ }
+ else if ( pagerElement.textContent === "" ) {
+ pagerElement.innerHTML = pagerContainerTemplateHTML;
+ }
+
+ let pagerComponentElement = pagerElement.querySelector( "#pager" );
+ pagerComponentElement.textContent = "";
if ( pagerState.hasPreviousPage ) {
const liNode = document.createElement( "li" );
@@ -1114,7 +1199,7 @@ function updatePagerState( newState ) {
pagerController.previousPage();
};
- pagerElement.appendChild( liNode );
+ pagerComponentElement.appendChild( liNode );
}
pagerState.currentPages.forEach( ( page ) => {
@@ -1141,7 +1226,7 @@ function updatePagerState( newState ) {
pagerController.selectPage( pageNo );
};
- pagerElement.appendChild( liNode );
+ pagerComponentElement.appendChild( liNode );
} );
if ( pagerState.hasNextPage ) {
@@ -1155,7 +1240,7 @@ function updatePagerState( newState ) {
pagerController.nextPage();
};
- pagerElement.appendChild( liNode );
+ pagerComponentElement.appendChild( liNode );
}
}
diff --git a/test/assets/token.js b/test/assets/token.js
new file mode 100644
index 0000000..4ebeca2
--- /dev/null
+++ b/test/assets/token.js
@@ -0,0 +1,32 @@
+// This file is to facilitate testing of the search pages through GitHub pages
+
+const formToken = document.getElementById( "sr-token" );
+const searchElm = document.querySelector( "[data-gc-search]" );
+const sessionName = "searchToken";
+const tokenSaved = sessionStorage.getItem( sessionName );
+
+if( searchElm && tokenSaved ) {
+ let configData = JSON.parse( searchElm.dataset.gcSearch );
+
+ configData.accessToken = tokenSaved;
+ searchElm.dataset.gcSearch = JSON.stringify( configData );
+}
+
+if( formToken ) {
+ formToken.onsubmit = function( e ) {
+ e.preventDefault();
+
+ let formData = new FormData( formToken );
+ let statusElm = document.getElementById( "sr-token-ok" );
+ let tmpElm = document.createElement( "DIV" );
+
+ tmpElm.innerHTML = formData.get( "token" );
+ formData = tmpElm.textContent;
+ sessionStorage.setItem( sessionName, formData );
+
+ statusElm.hidden = false;
+ const hideFeedback = setTimeout( function() { statusElm.hidden = true; }, 5000 );
+
+ return false;
+ };
+}
diff --git a/test/budget.html b/test/budget.html
index 7cfdb1f..fe6acf0 100644
--- a/test/budget.html
+++ b/test/budget.html
@@ -8,8 +8,12 @@
share: false
deptfeature: false
dateModified: 2025-02-24
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
@@ -54,3 +58,8 @@
"isAdvancedSearch": true,
"originLevel3": "/en/department-finance/search-budget/advanced-search.html"
}'>
+
+
+
+ Total results: %[numberOfResults] for this search
+
diff --git a/test/election.html b/test/election.html
index c90dab4..38b9fa0 100644
--- a/test/election.html
+++ b/test/election.html
@@ -8,8 +8,12 @@
share: false
deptfeature: false
dateModified: 2025-02-24
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/gazette.html b/test/gazette.html
index 49a357d..cd47964 100644
--- a/test/gazette.html
+++ b/test/gazette.html
@@ -8,8 +8,12 @@
share: false
deptfeature: false
dateModified: 2025-02-24
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..532dd04
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,24 @@
+---
+title: Add token to test search pages
+description: This page allows to add a token to test search pages for the duration of a session
+lang: en
+dateModified: 2025-05-15
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
+script: assets/token.js
+---
+
+
+
+
diff --git a/test/no-qs-en.html b/test/no-qs-en.html
new file mode 100644
index 0000000..49ab41a
--- /dev/null
+++ b/test/no-qs-en.html
@@ -0,0 +1,49 @@
+---
+title: Search page without Query Suggestions (QS)
+description: Demo page without the QS feature in the Canada.ca Search UI Basic
+lang: en
+altLangPage: no-qs-fr.html
+nositesearch: true
+pageclass: page-type-search
+pageType: recherche
+share: false
+deptfeature: false
+dateModified: 2025-05-21
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
+css: "../src/connector.css"
+script:
+- src: "assets/token.js"
+- src: "../src/connector.js"
+ type: module
+---
+
+
+
+
+
+
+Perform an advanced search
+
+
+Expected output for the result section
+
+ Output for Results section
+ [To be completed, see Connector.js for reference until then]
+
diff --git a/test/no-qs-fr.html b/test/no-qs-fr.html
new file mode 100644
index 0000000..3152e4a
--- /dev/null
+++ b/test/no-qs-fr.html
@@ -0,0 +1,49 @@
+---
+title: Résultats de la recherche sans Suggestions de termes
+description: Page démo sans la fonctionnalité Suggestions de termes dans l'interface utilisateur de recherche Canada.ca
+lang: fr
+altLangPage: no-qs-en.html
+nositesearch: true
+pageclass: page-type-search
+pageType: recherche
+share: false
+deptfeature: false
+dateModified: 2025-05-21
+breadcrumbs:
+- title: "IU Recherche GC"
+ link: "../index.html"
+css: "../src/connector.css"
+script:
+- src: "assets/token.js"
+- src: "../src/connector.js"
+ type: module
+---
+
+
+
+
+
+
+Effectuer une recherche avancée
+
+
+Section Résultats attendu pour la section de résultats
+
+ Section Résultats générée
+ [À compléter, voir Connector.js comme référence pour l'instant]
+
diff --git a/test/qs-en.html b/test/qs-en.html
index 33950f4..3a79361 100644
--- a/test/qs-en.html
+++ b/test/qs-en.html
@@ -1,6 +1,6 @@
---
-title: Search page with Query Suggestions (QS)
-description: Demo page for the QS feature in the Canada.ca Search UI Basic
+title: Search page with 10 Query Suggestions after at least 2 character entered
+description: Demo page without the QS feature in the Canada.ca Search UI Basic, customized to show 10 suggestion after just 2 characters entered
lang: en
altLangPage: qs-fr.html
nositesearch: true
@@ -8,9 +8,13 @@
pageType: recherche
share: false
deptfeature: false
-dateModified: 2025-02-19
+dateModified: 2025-05-21
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
@@ -33,7 +37,8 @@
"organizationId": "employmentandsocialdevelopmentcanadanonproduction14o5d9wry",
"accessToken":"{{ site.data.token.API_KEY }}",
"originLevel3": "/en/sr/srb.html",
- "numberOfSuggestions": 5
+ "numberOfSuggestions": 10,
+ "minimumCharsForSuggestions": 2
}'>
Perform an advanced search
diff --git a/test/qs-fr.html b/test/qs-fr.html
index d069595..d1e4940 100644
--- a/test/qs-fr.html
+++ b/test/qs-fr.html
@@ -1,6 +1,6 @@
---
-title: Résultats de la recherche avec Suggestions de termes
-description: Page démo pour la fonctionnalité Suggestions de termes dans l'interface utilisateur de recherche Canada.ca
+title: Recherche avec 10 Suggestions de termes avec minimum de 2 caractères entrés
+description: Page démo avec la fonctionnalité Suggestions de termes dans l'interface utilisateur de recherche Canada.ca, personnalisée en montrant 10 suggestions lorsque 2 caractères sont entrés ou plus
lang: fr
altLangPage: qs-en.html
nositesearch: true
@@ -8,9 +8,13 @@
pageType: recherche
share: false
deptfeature: false
-dateModified: 2025-02-19
+dateModified: 2025-05-21
+breadcrumbs:
+- title: "IU Recherche GC"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
@@ -33,7 +37,8 @@
"organizationId": "employmentandsocialdevelopmentcanadanonproduction14o5d9wry",
"accessToken":"{{ site.data.token.API_KEY }}",
"originLevel3": "/fr/sr/srb.html",
- "numberOfSuggestions": 5
+ "numberOfSuggestions": 10,
+ "minimumCharsForSuggestions": 2
}'>
Effectuer une recherche avancée
diff --git a/test/sra-en.html b/test/sra-en.html
index 058a36c..8d7e761 100644
--- a/test/sra-en.html
+++ b/test/sra-en.html
@@ -9,8 +9,12 @@
share: false
deptfeature: false
dateModified: 2024-06-05
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/sra-fr.html b/test/sra-fr.html
index be9c450..928e6c9 100644
--- a/test/sra-fr.html
+++ b/test/sra-fr.html
@@ -9,8 +9,12 @@
share: false
deptfeature: false
dateModified: 2024-06-05
+breadcrumbs:
+- title: "IU Recherche GC"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/srb-en.html b/test/srb-en.html
index 05ca524..a5fb890 100644
--- a/test/srb-en.html
+++ b/test/srb-en.html
@@ -9,8 +9,12 @@
share: false
deptfeature: false
dateModified: 2024-06-05
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/srb-fr.html b/test/srb-fr.html
index baa08e5..27c906f 100644
--- a/test/srb-fr.html
+++ b/test/srb-fr.html
@@ -9,8 +9,12 @@
share: false
deptfeature: false
dateModified: 2024-06-05
+breadcrumbs:
+- title: "IU Recherche GC"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/src-en.html b/test/src-en.html
index b74b127..620025e 100644
--- a/test/src-en.html
+++ b/test/src-en.html
@@ -9,8 +9,12 @@
share: false
deptfeature: false
dateModified: 2024-06-05
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/src-fr.html b/test/src-fr.html
index 6fd6c77..b899454 100644
--- a/test/src-fr.html
+++ b/test/src-fr.html
@@ -9,8 +9,12 @@
share: false
deptfeature: false
dateModified: 2024-06-05
+breadcrumbs:
+- title: "IU Recherche GC"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
diff --git a/test/template.html b/test/template.html
index fb05ea2..6b9966f 100644
--- a/test/template.html
+++ b/test/template.html
@@ -8,8 +8,12 @@
share: false
deptfeature: false
dateModified: 2025-02-19
+breadcrumbs:
+- title: "GC Search UI"
+ link: "../index.html"
css: "../src/connector.css"
script:
+- src: "assets/token.js"
- src: "../src/connector.js"
type: module
---
@@ -53,6 +57,41 @@