From ddedd978c4e11e8226f3ffe39bcff3dd5f06d6d5 Mon Sep 17 00:00:00 2001 From: mmitiche <86681870+mmitiche@users.noreply.github.com> Date: Fri, 9 Dec 2022 12:04:51 -0500 Subject: [PATCH] feat(quantic): QuanticResultCopyToClipboard component created (#2558) * SFINT-4476 QuanticResultAction component created * SFINT-4476 QuanticResultAction improved * SFINT-4476 QuanticResultActionBar component created * SFINT-4476 improvments to the QuanticResult action components * SFINT-4476 typo fixed * SFINT-4476 tests improved * SFINT-4476 QuanticResultAction component improved * SFINT-4481 QuanticResultCopyToClipboard component created * SFINT-4476 QuanticResultAction and QuanticResultActionBar improved * SFINT-4476 typos fixed * Update packages/quantic/force-app/main/default/lwc/quanticResultAction/quanticResultAction.js * Update packages/quantic/force-app/main/default/lwc/quanticResultAction/quanticResultAction.js * SFINT-4476 typing added * SFINT-4476 few improvements added * SFINT-4476 PR feedbacks applied * SFINT-4476 margin added * SFINT-4481 copy to clipboard analytics logged * Update packages/quantic/force-app/main/default/lwc/quanticResultAction/__tests__/quanticResultAction.test.js Co-authored-by: Luc Bergeron <10946843+lbergeron@users.noreply.github.com> * SFINT-4476 new selectedIconName property added * SFINT-4481 e2e tests for QuanticResultCopyToClipboard setup * e2e tests setup * SFINT-4481 temp folder deleted * SFINT-4481 comments added * SFINT-4481 e2e for QuanticResultCopyToClipboard improved * SFINT-4481 logCopyToClipboard added * SFINT-4481 imroved e2e tests for copy to clipboard * Update packages/quantic/force-app/main/default/lwc/quanticQueryError/quanticQueryError.js * SFINT-4481 improvments applied * SFINT-4481 unused import deleted * Update packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js Co-authored-by: Nathan Lafrance-Berger * SFINT-4481 feedbacks from PR applied * SFINT-4481 comments updated * SFINT-4481 deprecated copyToClipboard fallback removed Co-authored-by: Luc Bergeron <10946843+lbergeron@users.noreply.github.com> Co-authored-by: Nathan Lafrance-Berger --- .../copy-to-clipboard-actions.ts | 18 +++ .../copy-to-clipboard-expectations.ts | 53 ++++++++ .../copy-to-clipboard-selectors.ts | 17 +++ .../copy-to-clipboard.cypress.ts | 96 +++++++++++++ .../quantic/cypress/page-objects/search.ts | 1 + .../exampleQuanticResultCopyToClipboard.html | 16 +++ .../exampleQuanticResultCopyToClipboard.js | 57 ++++++++ ...leQuanticResultCopyToClipboard.js-meta.xml | 9 ++ .../labels/CustomLabels.labels-meta.xml | 14 ++ .../quanticQueryError/quanticQueryError.js | 28 +--- .../quanticResultCopyToClipboard.html | 3 + .../quanticResultCopyToClipboard.js | 126 ++++++++++++++++++ .../quanticResultCopyToClipboard.js-meta.xml | 5 + .../default/lwc/quanticUtils/quanticUtils.js | 43 ++++++ .../main/translations/fr.translation-meta.xml | 8 ++ .../routes/quanticResultCopyToClipboard.json | 11 ++ .../Quantic_Examples1/views/home.json | 2 +- .../views/quanticResultCopyToClipboard.json | 67 ++++++++++ 18 files changed, 551 insertions(+), 23 deletions(-) create mode 100644 packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-actions.ts create mode 100644 packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-expectations.ts create mode 100644 packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-selectors.ts create mode 100644 packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard.cypress.ts create mode 100644 packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.html create mode 100644 packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js create mode 100644 packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js-meta.xml create mode 100644 packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.html create mode 100644 packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js create mode 100644 packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js-meta.xml create mode 100644 packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/routes/quanticResultCopyToClipboard.json create mode 100644 packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/quanticResultCopyToClipboard.json diff --git a/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-actions.ts b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-actions.ts new file mode 100644 index 00000000000..44088b20e1b --- /dev/null +++ b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-actions.ts @@ -0,0 +1,18 @@ +import { + CopyToClipboardSelector, + CopyToClipboardSelectors, +} from './copy-to-clipboard-selectors'; + +function copyToClipboardActions(selector: CopyToClipboardSelector) { + return { + clickCopyToClipboardButton: () => + selector + .copyToClipboardButton() + .click() + .logAction('When clicking on the copy to clipboard button'), + }; +} + +export const CopyToClipboardActions = { + ...copyToClipboardActions(CopyToClipboardSelectors), +}; diff --git a/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-expectations.ts b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-expectations.ts new file mode 100644 index 00000000000..36fd4d0f70d --- /dev/null +++ b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-expectations.ts @@ -0,0 +1,53 @@ +import {InterceptAliases} from '../../../page-objects/search'; +import { + CopyToClipboardSelector, + CopyToClipboardSelectors, +} from './copy-to-clipboard-selectors'; + +function copyToClipboardExpectations(selector: CopyToClipboardSelector) { + return { + displayCopyToClipboardButton: (display: boolean) => { + selector + .copyToClipboardButton() + .should(display ? 'exist' : 'not.exist') + .log('should display the copy to clipboard button'); + }, + + displayCopyToClipboardTooltip: (label: string) => { + selector + .copyToClipboardTooltip() + .contains(label) + .log('should display the copy to clipboard tooltip'); + }, + + logCopyToClipboard: (result: { + title: string; + clickUri: string; + raw: {urihash: string}; + }) => { + cy.wait(InterceptAliases.UA.CopyToClipboard) + .then((interception) => { + const analyticsBody = interception.request.body; + expect(analyticsBody).to.have.property('documentTitle', result.title); + expect(analyticsBody).to.have.property( + 'documentUri', + result.clickUri + ); + expect(analyticsBody).to.have.property( + 'documentUrl', + result.clickUri + ); + expect(analyticsBody).to.have.property( + 'documentUriHash', + result.raw.urihash + ); + expect(analyticsBody).to.have.property('documentPosition', 1); + }) + .logDetail("should log the 'copyToClipboard' UA event"); + }, + }; +} + +export const CopyToClipboardExpectations = { + ...copyToClipboardExpectations(CopyToClipboardSelectors), +}; diff --git a/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-selectors.ts b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-selectors.ts new file mode 100644 index 00000000000..76affe38c0d --- /dev/null +++ b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard-selectors.ts @@ -0,0 +1,17 @@ +import {ComponentSelector, CypressSelector} from '../../common-selectors'; + +export const copyToClpboardComponent = 'c-quantic-result-copy-to-clipboard'; + +export interface CopyToClipboardSelector extends ComponentSelector { + copyToClipboardButton: () => CypressSelector; + copyToClipboardTooltip: () => CypressSelector; +} + +export const CopyToClipboardSelectors: CopyToClipboardSelector = { + get: () => cy.get(copyToClpboardComponent), + + copyToClipboardButton: () => + CopyToClipboardSelectors.get().find('lightning-button-icon-stateful'), + copyToClipboardTooltip: () => + CopyToClipboardSelectors.get().find('.slds-popover'), +}; diff --git a/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard.cypress.ts b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard.cypress.ts new file mode 100644 index 00000000000..cdc8c1e1c66 --- /dev/null +++ b/packages/quantic/cypress/e2e/default-2/copy-to-clipboard/copy-to-clipboard.cypress.ts @@ -0,0 +1,96 @@ +import {performSearch} from '../../../page-objects/actions/action-perform-search'; +import {configure} from '../../../page-objects/configurator'; +import {interceptSearch} from '../../../page-objects/search'; +import {InsightInterfaceExpectations as InsightInterfaceExpect} from '../../../page-objects/use-case'; +import {CopyToClipboardActions as Actions} from './copy-to-clipboard-actions'; +import {CopyToClipboardExpectations as Expect} from './copy-to-clipboard-expectations'; + +interface copyToClipboardOptions { + label: string; + successLabel: string; + textTemplate: string; +} + +const testResult = { + clickUri: 'https://test.com', + Excerpt: 'Test excerpt', + title: 'Test result', + raw: { + urihash: 'Test uri hash', + objecttype: 'Test', + source: 'Test source', + date: 1669504751000, + }, +}; + +const defaultLabel = 'Copy'; +const defaultSuccessLabel = 'Copied!'; +const customLabel = 'Copy to clipboard'; +const customSuccessLabel = 'Copied to clipboard!'; +const customTextTemplate = '${raw.source} : ${clickUri}'; + +// access to the clipboard reliably works in Electron browser +// in other browsers, there are popups asking for permission +// thus we should only run these tests in Electron +describe('quantic-result-copy-to-clipboard', {browser: 'electron'}, () => { + const pageUrl = 's/quantic-result-copy-to-clipboard'; + + function visitCopyToClipboard(options: Partial) { + interceptSearch(); + cy.visit(pageUrl); + configure(options); + InsightInterfaceExpect.isInitialized(); + performSearch(); + } + + describe('with the default options', () => { + it('should correctly display the copy to clipboard button', () => { + visitCopyToClipboard({}); + + Expect.displayCopyToClipboardButton(true); + Expect.displayCopyToClipboardTooltip(defaultLabel); + }); + + it('should correctly copy the result to clipboard', () => { + visitCopyToClipboard({}); + + Expect.displayCopyToClipboardButton(true); + Actions.clickCopyToClipboardButton(); + Expect.displayCopyToClipboardTooltip(defaultSuccessLabel); + Expect.logCopyToClipboard(testResult); + + cy.window() + .its('navigator.clipboard') + .invoke('readText') + .should('equal', `${testResult.title}\n${testResult.clickUri}`); + }); + }); + + describe('with custom options', () => { + it('should correctly display the copy to clipboard button', () => { + visitCopyToClipboard({ + label: customLabel, + }); + + Expect.displayCopyToClipboardButton(true); + Expect.displayCopyToClipboardTooltip(customLabel); + }); + + it('should correctly copy the result to clipboard', () => { + visitCopyToClipboard({ + successLabel: customSuccessLabel, + textTemplate: customTextTemplate, + }); + + Expect.displayCopyToClipboardButton(true); + Actions.clickCopyToClipboardButton(); + Expect.displayCopyToClipboardTooltip(customSuccessLabel); + Expect.logCopyToClipboard(testResult); + + cy.window() + .its('navigator.clipboard') + .invoke('readText') + .should('equal', `${testResult.raw.source} : ${testResult.clickUri}`); + }); + }); +}); diff --git a/packages/quantic/cypress/page-objects/search.ts b/packages/quantic/cypress/page-objects/search.ts index 1b707e27aa2..b62359942d0 100644 --- a/packages/quantic/cypress/page-objects/search.ts +++ b/packages/quantic/cypress/page-objects/search.ts @@ -44,6 +44,7 @@ export const InterceptAliases = { DocumentOpen: uaAlias('documentOpen'), DocumentQuickview: uaAlias('documentQuickview'), SearchFromLink: uaAlias('searchFromLink'), + CopyToClipboard: uaAlias('copyToClipboard'), }, QuerySuggestions: '@coveoQuerySuggest', Search: '@coveoSearch', diff --git a/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.html b/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.html new file mode 100644 index 00000000000..6681339a87b --- /dev/null +++ b/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.html @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js b/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js new file mode 100644 index 00000000000..64d952345f9 --- /dev/null +++ b/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js @@ -0,0 +1,57 @@ +import {LightningElement, api, track} from 'lwc'; + +export default class ExampleQuanticResultCopyToClipboard extends LightningElement { + @api engineId = 'quantic-result-copy-to-clipboard-engine'; + @track config = {}; + isConfigured = false; + + pageTitle = 'Quantic Result Copy To Clipboard'; + pageDescription = + 'The QuanticResultCopyToClipboard component allows the end user to copy a result to clipboard.'; + options = [ + { + attribute: 'label', + label: 'Label', + description: 'The label to be displayed in the tooltip of the button.', + defaultValue: 'Copy', + }, + { + attribute: 'successLabel', + label: 'Success Label', + description: + 'The label to be displayed in the tooltip of the button when the action is successful.', + defaultValue: 'Copied!', + }, + { + attribute: 'textTemplate', + label: 'Text Template', + description: + 'The template used to generate the text to copy to clipboard.', + defaultValue: '${title}\n${clickUri}', + }, + ]; + + testResult = { + clickUri: 'https://test.com', + excerpt: 'Test excerpt', + title: 'Test result', + uniqueId: 'Test unique id', + uri: 'https://test.com', + raw: { + urihash: 'Test uri hash', + permanentid: 'Test permanent id', + objecttype: 'Test', + source: 'Test source', + date: 1669504751000, + }, + }; + + resultTemplateManager = { + selectTemplate: () => null, + }; + + handleTryItNow(evt) { + this.config = evt.detail; + this.isConfigured = true; + } +} diff --git a/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js-meta.xml b/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js-meta.xml new file mode 100644 index 00000000000..fc9ee9b9130 --- /dev/null +++ b/packages/quantic/force-app/examples/main/lwc/exampleQuanticResultCopyToClipboard/exampleQuanticResultCopyToClipboard.js-meta.xml @@ -0,0 +1,9 @@ + + + 52.0 + true + + lightningCommunity__Page + lightningCommunity__Default + + \ No newline at end of file diff --git a/packages/quantic/force-app/main/default/labels/CustomLabels.labels-meta.xml b/packages/quantic/force-app/main/default/labels/CustomLabels.labels-meta.xml index 0ea0a223ad5..9bc6c30df81 100644 --- a/packages/quantic/force-app/main/default/labels/CustomLabels.labels-meta.xml +++ b/packages/quantic/force-app/main/default/labels/CustomLabels.labels-meta.xml @@ -889,4 +889,18 @@ false No filters available in the current tab + + quantic_Copy + Copy + en_US + false + Copy + + + quantic_Copied + Copied! + en_US + false + Copied! + \ No newline at end of file diff --git a/packages/quantic/force-app/main/default/lwc/quanticQueryError/quanticQueryError.js b/packages/quantic/force-app/main/default/lwc/quanticQueryError/quanticQueryError.js index 1525c2670af..89990ad3fe9 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticQueryError/quanticQueryError.js +++ b/packages/quantic/force-app/main/default/lwc/quanticQueryError/quanticQueryError.js @@ -1,6 +1,7 @@ import { LightningElement, api, track } from 'lwc'; import { registerComponentForInit, initializeWithHeadless, getHeadlessBundle } from 'c/quanticHeadlessLoader'; import { AriaLiveRegion, I18nUtils } from 'c/quanticUtils'; +import { copyToClipboard } from 'c/quanticUtils'; import coveoOnlineHelpLink from '@salesforce/label/c.quantic_CoveoOnlineHelpLink'; import moreInformation from '@salesforce/label/c.quantic_MoreInformation'; @@ -36,7 +37,7 @@ export default class QuanticQueryError extends LightningElement { /** @type {Boolean} */ @track hasError; /** @type {string} */ - @track error + @track error; /** @type {QueryError} */ queryError; @@ -111,27 +112,10 @@ export default class QuanticQueryError extends LightningElement { async handleCopyToClipboard() { const text = this.template.querySelector('code').textContent; - if (navigator?.clipboard?.writeText) { - try { - await navigator.clipboard.writeText(text); - } catch (err) { - console.error('Copy to clipboard failed.', text, err); - this.copyToClipboardFallback(text); - } - } else { - this.copyToClipboardFallback(text); - } - } - /** - * @param {string} text - */ - copyToClipboardFallback(text) { - const el = document.createElement('textarea'); - el.value = text; - document.body.appendChild(el); - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); + + copyToClipboard(text).catch((err) => { + console.error('Copy to clipboard failed.', text, err); + }); } get checkForMoreLabel() { diff --git a/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.html b/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.html new file mode 100644 index 00000000000..f55f59a8a74 --- /dev/null +++ b/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js b/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js new file mode 100644 index 00000000000..c6e092d5460 --- /dev/null +++ b/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js @@ -0,0 +1,126 @@ +import copied from '@salesforce/label/c.quantic_Copied'; +import copy from '@salesforce/label/c.quantic_Copy'; +import { + registerComponentForInit, + initializeWithHeadless, + getHeadlessBundle, +} from 'c/quanticHeadlessLoader'; +import {copyToClipboard, buildTemplateTextFromResult} from 'c/quanticUtils'; +import {LightningElement, api} from 'lwc'; + +/** @typedef {import("coveo").Result} Result */ +/** @typedef {import("coveo").InsightEngine} InsightEngine */ + +/** + * The `QuanticResultCopyToClipboard` component allows the end user to copy a result's details to clipboard. + * @category Insight Panel + * @example + * + */ +export default class QuanticResultCopyToClipboard extends LightningElement { + labels = { + copy, + copied, + }; + + /** + * The ID of the engine instance the component registers to. + * @api + * @type {string} + */ + @api engineId; + /** + * The result to copy. + * @api + * @type {Result} + */ + @api result; + /** + * The label to be displayed in the tooltip of the button. + * @api + * @type {string} + */ + @api label = this.labels.copy; + /** + * The label to be displayed in the tooltip of the button when the action is successful. + * @api + * @type {string} + */ + @api successLabel = this.labels.copied; + /** + * The template used to generate the text to copy to clipboard. + * Use references to result [fields](https://docs.coveo.com/en/2036/index-content/about-fields) to get their value. + * @api + * @type {string} + */ + @api textTemplate = '${title}\n${clickUri}'; + + /** @type {object} */ + actions; + /** @type {string} */ + displayedLabel; + /** @type {InsightEngine} */ + engine; + + connectedCallback() { + this.displayedLabel = this.label; + registerComponentForInit(this, this.engineId); + this.addEventListener( + 'quantic__copytoclipboard', + this.handleCopyToClipBoard + ); + } + + disconnectedCallback() { + this.removeEventListener( + 'quantic__copytoclipboard', + this.handleCopyToClipBoard + ); + } + + renderedCallback() { + initializeWithHeadless(this, this.engineId, this.initialize); + } + + initialize = (engine) => { + this.engine = engine; + this.headless = getHeadlessBundle(this.engineId); + + this.actions = { + ...this.headless.loadInsightAnalyticsActions(engine), + }; + }; + + /** + * Performs the copy to clipboard action. + * @param {CustomEvent} event + */ + handleCopyToClipBoard = (event) => { + event.stopPropagation(); + const {setLoading, result} = event.detail; + setLoading(true); + const resultText = buildTemplateTextFromResult(this.textTemplate, result); + + copyToClipboard(resultText) + .then(() => { + setLoading(false); + this.engine.dispatch(this.actions.logCopyToClipboard(this.result)); + this.displayedLabel = this.successLabel; + this.resetOriginalLabel(); + }) + .catch((err) => { + setLoading(false); + console.error('Copy to clipboard action failed.', err); + }); + }; + + /** + * Resets the original label after 1000ms. + */ + resetOriginalLabel() { + // eslint-disable-next-line @lwc/lwc/no-async-operation + setTimeout(() => { + this.displayedLabel = this.label; + }, 1000); + } +} diff --git a/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js-meta.xml b/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js-meta.xml new file mode 100644 index 00000000000..eac275d0879 --- /dev/null +++ b/packages/quantic/force-app/main/default/lwc/quanticResultCopyToClipboard/quanticResultCopyToClipboard.js-meta.xml @@ -0,0 +1,5 @@ + + + 55.0 + false + \ No newline at end of file diff --git a/packages/quantic/force-app/main/default/lwc/quanticUtils/quanticUtils.js b/packages/quantic/force-app/main/default/lwc/quanticUtils/quanticUtils.js index 5483b351ce9..aff3e63ae91 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticUtils/quanticUtils.js +++ b/packages/quantic/force-app/main/default/lwc/quanticUtils/quanticUtils.js @@ -4,6 +4,8 @@ import dayPattern from '@salesforce/label/c.quantic_DatePatternDay'; import monthPattern from '@salesforce/label/c.quantic_DatePatternMonth'; import yearPattern from '@salesforce/label/c.quantic_DatePatternYear'; +/** @typedef {import("coveo").Result} Result */ + export class Debouncer { _timeout; @@ -688,3 +690,44 @@ export function isParentOf(element, targetElement) { false ); } + +/** + * Copies text to clipboard using the Clipboard API. + * https://developer.mozilla.org/en-US/docs/Web/API/Clipboard + * @param {string} text + */ +export async function copyToClipboard(text) { + await navigator.clipboard.writeText(text); +} + +/** + * Read the value of a given key from an object. + * @param {object} object + * @param {string} key + */ +export function readFromObject(object, key) { + const firstPeriodIndex = key.indexOf('.'); + if (object && firstPeriodIndex !== -1) { + let newKey = key.substring(firstPeriodIndex + 1); + key = key.substring(0, firstPeriodIndex); + return readFromObject(object[key], newKey); + } + return object ? object[key] : undefined; +} + +/** + * Generates a text from a result based on a given template. + * @param {string} template + * @param {Result} result + * @returns {string} + */ +export function buildTemplateTextFromResult(template, result) { + if (!template) { + return ''; + } + return template.replace(/\$\{(.*?)\}/g, (value) => { + const key = value.substring(2, value.length - 1); + const newValue = readFromObject(result, key); + return newValue || value; + }); +} diff --git a/packages/quantic/force-app/main/translations/fr.translation-meta.xml b/packages/quantic/force-app/main/translations/fr.translation-meta.xml index edf3fcea6bd..a05b7962c04 100644 --- a/packages/quantic/force-app/main/translations/fr.translation-meta.xml +++ b/packages/quantic/force-app/main/translations/fr.translation-meta.xml @@ -468,4 +468,12 @@ quantic_NoFilterForCurrentTab + + + quantic_Copy + + + + quantic_Copied + \ No newline at end of file diff --git a/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/routes/quanticResultCopyToClipboard.json b/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/routes/quanticResultCopyToClipboard.json new file mode 100644 index 00000000000..3e0c5ef93eb --- /dev/null +++ b/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/routes/quanticResultCopyToClipboard.json @@ -0,0 +1,11 @@ +{ + "activeViewId" : "e921fbf3-b6da-4356-9bc1-b6ed0126accd", + "appPageId" : "2199ef25-89a9-44a1-ad69-7cb8bd918245", + "configurationTags" : [ ], + "id" : "7d87392d-03b1-4103-b64d-3a823f86ed5b", + "label" : "Quantic Result Copy To Clipboard", + "pageAccess" : "UseParent", + "routeType" : "custom-quantic-result-copy-to-clipboard", + "type" : "route", + "urlPrefix" : "quantic-result-copy-to-clipboard" +} \ No newline at end of file diff --git a/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/home.json b/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/home.json index 5ca61dda686..afeac8422a3 100644 --- a/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/home.json +++ b/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/home.json @@ -10,7 +10,7 @@ }, { "components" : [ { "componentAttributes" : { - "richTextValue" : "

Quantic Examples


Typical Use Cases



Quantic Components


" + "richTextValue" : "

Quantic Examples


Typical Use Cases



Quantic Components


" }, "componentName" : "forceCommunity:richTextInline", "id" : "1c5c28a3-9570-4c6c-abf9-52ad1b26582a", diff --git a/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/quanticResultCopyToClipboard.json b/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/quanticResultCopyToClipboard.json new file mode 100644 index 00000000000..3dc421834c3 --- /dev/null +++ b/packages/quantic/quantic-examples-community/experiences/Quantic_Examples1/views/quanticResultCopyToClipboard.json @@ -0,0 +1,67 @@ +{ + "appPageId" : "2199ef25-89a9-44a1-ad69-7cb8bd918245", + "componentName" : "siteforce:dynamicLayout", + "id" : "e921fbf3-b6da-4356-9bc1-b6ed0126accd", + "label" : "Quantic Result Copy To Clipboard", + "regions" : [ { + "components" : [ { + "componentAttributes" : { + "background" : "background: rgba(0,0,0,0)", + "backgroundOverlay" : "rgba(0,0,0,0.5)", + "contentAreaWidth" : 100, + "sectionConfig" : { + "UUID" : "8446f678-f922-4615-86fc-f36447faead4", + "columns" : [ { + "UUID" : "12fe6ecd-7a93-4033-a222-2a4adbb326ab", + "columnKey" : "1", + "columnName" : "Column 1", + "columnWidth" : "12", + "seedComponents" : [ ] + } ] + }, + "sectionHeight" : 300 + }, + "componentName" : "forceCommunity:section", + "id" : "8446f678-f922-4615-86fc-f36447faead4", + "regions" : [ { + "components" : [ { + "componentAttributes" : { }, + "componentName" : "c:exampleQuanticResultCopyToClipboard", + "id" : "2fcdf07c-4094-4bdf-bf52-fb7e652565d7", + "renderPriority" : "NEUTRAL", + "renditionMap" : { }, + "type" : "component" + } ], + "id" : "12fe6ecd-7a93-4033-a222-2a4adbb326ab", + "regionLabel" : "Column 1", + "regionName" : "1", + "renditionMap" : { }, + "type" : "region" + } ], + "renderPriority" : "NEUTRAL", + "renditionMap" : { }, + "type" : "component" + } ], + "id" : "7910dc90-2697-4a4d-856b-e12f5efe0a98", + "regionName" : "content", + "type" : "region" + }, { + "components" : [ { + "componentAttributes" : { + "customHeadTags" : "", + "description" : "", + "title" : "Quantic Result Copy To Clipboard" + }, + "componentName" : "forceCommunity:seoAssistant", + "id" : "1b26b71c-3923-42f9-b9a4-f4d59740996f", + "renditionMap" : { }, + "type" : "component" + } ], + "id" : "328c1f51-b941-4467-a0fa-15dd3d864291", + "regionName" : "sfdcHiddenRegion", + "type" : "region" + } ], + "themeLayoutType" : "Inner", + "type" : "view", + "viewType" : "custom-quantic-result-copy-to-clipboard" +} \ No newline at end of file