From 50f80e8bb8eaa3c403a287d52937ec87bdf6dfce Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Wed, 28 Aug 2024 16:49:12 -0400 Subject: [PATCH 1/8] [sitecore-jss] fix isEditorActive for XMCloud Pages --- .../sitecore-jss/src/editing/utils.test.ts | 41 +++++++++++++------ packages/sitecore-jss/src/editing/utils.ts | 8 +++- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/sitecore-jss/src/editing/utils.test.ts b/packages/sitecore-jss/src/editing/utils.test.ts index a58f365b73..9e27032d0d 100644 --- a/packages/sitecore-jss/src/editing/utils.test.ts +++ b/packages/sitecore-jss/src/editing/utils.test.ts @@ -15,6 +15,14 @@ interface Global { declare const global: Global; describe('utils', () => { + const pagesDocument = { + getElementById: (id: unknown) => (id === 'hrz-canvas-state' ? 'present' : null), + }; + + const nonPagesDocument = { + getElementById: (id: unknown) => (id === 'hrz-canvas-state' ? null : 'present'), + }; + describe('isEditorActive', () => { it('should return false when invoked on server', () => { expect(isEditorActive()).to.be.false; @@ -22,25 +30,34 @@ describe('utils', () => { it('should return true when EE is active', () => { global.window = { - document: {}, + document: nonPagesDocument, location: { search: '' }, Sitecore: { PageModes: { ChromeManager: {} } }, }; expect(isEditorActive()).to.be.true; }); - it('should return true when Horizon is active', () => { + it('should return true when XMC Pages edit mode is active', () => { global.window = { - document: {}, - location: { search: '?sc_horizon=editor' }, + document: pagesDocument, + location: { search: '' }, Sitecore: null, }; expect(isEditorActive()).to.be.true; }); - it('should return false when EE and Horizon are not active', () => { + it('should return false when XMC Pages preview mode is active', () => { + global.window = { + document: pagesDocument, + location: { search: '?sc_horizon=preview' }, + Sitecore: null, + }; + expect(isEditorActive()).to.be.false; + }); + + it('should return false when EE and XMC Pages are not active', () => { global.window = { - document: {}, + document: nonPagesDocument, location: { search: '' }, Sitecore: null, }; @@ -60,7 +77,7 @@ describe('utils', () => { it('should reset chromes when EE is active', () => { const resetChromes = spy(); global.window = { - document: {}, + document: nonPagesDocument, location: { search: '' }, Sitecore: { PageModes: { ChromeManager: { resetChromes } } }, }; @@ -68,11 +85,11 @@ describe('utils', () => { expect(resetChromes).to.have.been.called.once; }); - it('should reset chromes when Horizon is active', () => { + it('should reset chromes when XMC Pages edit mode is active', () => { const resetChromes = spy(); global.window = { - document: {}, - location: { search: '?sc_horizon=editor' }, + document: pagesDocument, + location: { search: '' }, Sitecore: null, }; global.window[ChromeRediscoveryGlobalFunctionName.name] = resetChromes; @@ -80,9 +97,9 @@ describe('utils', () => { expect(resetChromes).to.have.been.called.once; }); - it('should not throw when EE and Horizon are not active', () => { + it('should not throw when EE and XMC Pages are not active', () => { global.window = { - document: {}, + document: nonPagesDocument, location: { search: '' }, Sitecore: null, }; diff --git a/packages/sitecore-jss/src/editing/utils.ts b/packages/sitecore-jss/src/editing/utils.ts index 81c174f882..b3a2261dee 100644 --- a/packages/sitecore-jss/src/editing/utils.ts +++ b/packages/sitecore-jss/src/editing/utils.ts @@ -74,8 +74,12 @@ export class HorizonEditor { if (isServer()) { return false; } - // Horizon will add "sc_horizon=editor" query string parameter for the editor and "sc_horizon=simulator" for the preview - return window.location.search.indexOf('sc_horizon=editor') > -1; + // XMCloud Pages (ex-Horizon) will have hrz-canvas-state element present in Edit and Preview + // But Edit would not have the have the sc_horizon query string param + return ( + !!window.document.getElementById('hrz-canvas-state') && + window.location.search.indexOf('sc_horizon=preview') === -1 + ); } static resetChromes(): void { if (isServer()) { From 835b9ce4e359edc9d361a1dbfedf6cc92e22c097 Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Wed, 28 Aug 2024 17:32:32 -0400 Subject: [PATCH 2/8] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4196f554b1..68dacbeff4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Our versioning strategy is as follows: * `[templates/nextjs]` `[templates/react]` `[templates/angular]` `[templates/vue]` Fixed an issue when environment variable is undefined (not present in .env), that produced an "undefined" value in generated config file ([#1875](https://github.com/Sitecore/jss/pull/1875)) * `[templates/nextjs]` Fix embedded personalization not rendering correctly after navigation through router links. ([#1911](https://github.com/Sitecore/jss/pull/1911)) +* `[sitecore-jss]` Fix isEditorActive returning false in XMCloud Pages ([#1912](https://github.com/Sitecore/jss/pull/1912)) ### ๐ŸŽ‰ New Features & Improvements From 3da505dfc6a6d5f3253edd2aa081637ebe561d16 Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Thu, 29 Aug 2024 14:25:03 -0400 Subject: [PATCH 3/8] render JSS-specific element in Pages editing --- .../src/components/EditingScripts.test.tsx | 88 ++++++++++++++----- .../src/components/EditingScripts.tsx | 33 +++++-- packages/sitecore-jss/src/editing/index.ts | 2 + .../sitecore-jss/src/editing/utils.test.ts | 29 +++--- packages/sitecore-jss/src/editing/utils.ts | 27 ++++-- 5 files changed, 129 insertions(+), 50 deletions(-) diff --git a/packages/sitecore-jss-react/src/components/EditingScripts.test.tsx b/packages/sitecore-jss-react/src/components/EditingScripts.test.tsx index 9f6e1f49cd..5bdab8aa06 100644 --- a/packages/sitecore-jss-react/src/components/EditingScripts.test.tsx +++ b/packages/sitecore-jss-react/src/components/EditingScripts.test.tsx @@ -10,6 +10,7 @@ import { import { EditingScripts } from './EditingScripts'; import { SitecoreContext } from './SitecoreContext'; import { ComponentFactory } from './sharedTypes'; +import { getJssHorizonClientData } from '@sitecore-jss/sitecore-jss/editing'; describe('', () => { const mockComponentFactory: ComponentFactory = () => null; @@ -75,31 +76,62 @@ describe('', () => { expect(scripts.find('script')).to.have.length(0); }); - ['Preview', 'Edit'].forEach((pageState) => { - it(`should render nothing when ${pageState} and edit mode is Chromes`, () => { - const layoutData = getLayoutData({ - editMode: EditMode.Chromes, - pageState: LayoutServicePageState[pageState], - pageEditing: true, - }); + it('should render nothing when Preview and edit mode is Chromes', () => { + const layoutData = getLayoutData({ + editMode: EditMode.Chromes, + pageState: LayoutServicePageState.Preview, + pageEditing: true, + }); + + const component = mount( + + + + ); - const component = mount( - - - - ); + const scripts = component.find('EditingScripts'); - const scripts = component.find('EditingScripts'); + expect(scripts.html()).to.be.null; + expect(scripts.find('script')).to.have.length(0); + }); - expect(scripts.html()).to.be.null; - expect(scripts.find('script')).to.have.length(0); + it('should render JSS client data script elements when Edit and edit mode is Chromes', () => { + const layoutData = getLayoutData({ + editMode: EditMode.Chromes, + pageState: LayoutServicePageState.Edit, + pageEditing: true, }); - describe(`should render scripts when ${pageState} and edit mode is Metadata`, () => { + const component = mount( + + + + ); + + const scripts = component.find('EditingScripts'); + const ids = Object.keys(getJssHorizonClientData()); + expect(scripts.html()).to.not.be.null; + ids.forEach((id) => { + expect(scripts.exists(`#${id}`)).to.equal(true); + }); + expect(scripts.find('script')).to.have.length(ids.length); + }); + + [ + { + pageState: 'Edit', + jssData: getJssHorizonClientData(), + }, + { + pageState: 'Preview', + jssData: {}, + }, + ].forEach((scenario) => { + describe(`should render Pages scripts when ${scenario.pageState} and edit mode is Metadata`, () => { it('should render scripts', () => { const layoutData = getLayoutData({ editMode: EditMode.Metadata, - pageState: LayoutServicePageState[pageState], + pageState: LayoutServicePageState[scenario.pageState], pageEditing: true, }); @@ -110,8 +142,9 @@ describe('', () => { ); const scripts = component.find('EditingScripts'); + const jssScriptsLength = Object.keys(scenario.jssData).length; - expect(scripts.find('script')).to.have.length(4); + expect(scripts.find('script')).to.have.length(4 + jssScriptsLength); const script1 = scripts.find('script').at(0); expect(script1.prop('src')).to.equal('http://test.foo/script1.js'); @@ -140,10 +173,12 @@ describe('', () => { ); }); - it('should render nothing when data is not provided', () => { + it(`should render ${scenario.jssData ? 'jss client scripts' : 'nothing'} when edit mode is ${ + scenario.pageState + } and data is not provided`, () => { const layoutData = getLayoutData({ editMode: EditMode.Metadata, - pageState: LayoutServicePageState[pageState], + pageState: LayoutServicePageState[scenario.pageState], pageEditing: true, clientData: {}, clientScripts: [], @@ -156,9 +191,16 @@ describe('', () => { ); const scripts = component.find('EditingScripts'); - - expect(scripts.html()).to.equal(''); - expect(scripts.find('script')).to.have.length(0); + if (scenario.jssData) { + const ids = Object.keys(scenario.jssData); + ids.forEach((id) => { + expect(scripts.exists(`#${id}`)).to.equal(true); + }); + expect(scripts.find('script')).to.have.length(ids.length); + } else { + expect(scripts.html()).to.equal(''); + expect(scripts.find('script')).to.have.length(0); + } }); }); }); diff --git a/packages/sitecore-jss-react/src/components/EditingScripts.tsx b/packages/sitecore-jss-react/src/components/EditingScripts.tsx index fd57c02695..aa81a95ee4 100644 --- a/packages/sitecore-jss-react/src/components/EditingScripts.tsx +++ b/packages/sitecore-jss-react/src/components/EditingScripts.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { EditMode, LayoutServicePageState } from '@sitecore-jss/sitecore-jss/layout'; import { useSitecoreContext } from '../enhancers/withSitecoreContext'; +import { getJssHorizonClientData } from '@sitecore-jss/sitecore-jss/editing'; /** * Renders client scripts and data for editing/preview mode in Pages. @@ -11,24 +12,38 @@ export const EditingScripts = (): JSX.Element => { sitecoreContext: { pageState, editMode, clientData, clientScripts }, } = useSitecoreContext(); + const renderClientData = () => ( + <> + {Object.keys(jssClientData).map((id) => ( + ' - ); - - const script4 = scripts.find('script').at(3); - expect(script4.prop('id')).to.equal('bar'); - expect(script4.prop('type')).to.equal('application/json'); - expect(script4.prop('dangerouslySetInnerHTML')).to.deep.equal({ - __html: '{"a":2,"b":"2","c":false}', - }); - expect(script4.html()).to.equal( - '' - ); + const script3 = scripts.find('script').at(2); + expect(script3.prop('id')).to.equal('foo'); + expect(script3.prop('type')).to.equal('application/json'); + expect(script3.prop('dangerouslySetInnerHTML')).to.deep.equal({ + __html: '{"x":1,"y":"1","z":true}', }); + expect(script3.html()).to.equal( + '' + ); + + const script4 = scripts.find('script').at(3); + expect(script4.prop('id')).to.equal('bar'); + expect(script4.prop('type')).to.equal('application/json'); + expect(script4.prop('dangerouslySetInnerHTML')).to.deep.equal({ + __html: '{"a":2,"b":"2","c":false}', + }); + expect(script4.html()).to.equal( + '' + ); + }); + + it('should render jss pages script elements when data is not provided', () => { + const layoutData = getLayoutData({ + editMode: EditMode.Metadata, + pageState: LayoutServicePageState.Edit, + pageEditing: true, + clientData: {}, + clientScripts: [], + }); + + const component = mount( + + + + ); - it(`should render ${scenario.jssData ? 'jss client scripts' : 'nothing'} when edit mode is ${ - scenario.pageState - } and data is not provided`, () => { - const layoutData = getLayoutData({ - editMode: EditMode.Metadata, - pageState: LayoutServicePageState[scenario.pageState], - pageEditing: true, - clientData: {}, - clientScripts: [], - }); - - const component = mount( - - - - ); - - const scripts = component.find('EditingScripts'); - if (scenario.jssData) { - const ids = Object.keys(scenario.jssData); - ids.forEach((id) => { - expect(scripts.exists(`#${id}`)).to.equal(true); - }); - expect(scripts.find('script')).to.have.length(ids.length); - } else { - expect(scripts.html()).to.equal(''); - expect(scripts.find('script')).to.have.length(0); - } + const scripts = component.find('EditingScripts'); + const ids = Object.keys(getJssPagesClientData()); + ids.forEach((id) => { + expect(scripts.exists(`#${id}`)).to.equal(true); }); + expect(scripts.find('script')).to.have.length(ids.length); }); }); }); diff --git a/packages/sitecore-jss-react/src/components/EditingScripts.tsx b/packages/sitecore-jss-react/src/components/EditingScripts.tsx index c3ab5ac938..3d6f502eef 100644 --- a/packages/sitecore-jss-react/src/components/EditingScripts.tsx +++ b/packages/sitecore-jss-react/src/components/EditingScripts.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { EditMode, LayoutServicePageState } from '@sitecore-jss/sitecore-jss/layout'; import { useSitecoreContext } from '../enhancers/withSitecoreContext'; -import { getJssHorizonClientData } from '@sitecore-jss/sitecore-jss/editing'; +import { getJssPagesClientData } from '@sitecore-jss/sitecore-jss/editing'; /** * Renders client scripts and data for editing/preview mode in Pages. @@ -16,10 +16,7 @@ export const EditingScripts = (): JSX.Element => { if (pageState === LayoutServicePageState.Normal) return <>; if (editMode === EditMode.Metadata) { - let jssClientData: Record = clientData; - if (pageState === LayoutServicePageState.Edit) { - jssClientData = { ...jssClientData, ...getJssHorizonClientData() }; - } + const jssClientData = { ...clientData, ...getJssPagesClientData() }; return ( <> diff --git a/packages/sitecore-jss/src/editing/index.ts b/packages/sitecore-jss/src/editing/index.ts index 0d37316883..030ef88b24 100644 --- a/packages/sitecore-jss/src/editing/index.ts +++ b/packages/sitecore-jss/src/editing/index.ts @@ -6,7 +6,7 @@ export { resetEditorChromes, handleEditorAnchors, Metadata, - getJssHorizonClientData, + getJssPagesClientData, EDITING_ALLOWED_ORIGINS, QUERY_PARAM_EDITING_SECRET, PAGES_EDITING_MARKER, diff --git a/packages/sitecore-jss/src/editing/utils.ts b/packages/sitecore-jss/src/editing/utils.ts index 1d80d7a498..495b2a5f29 100644 --- a/packages/sitecore-jss/src/editing/utils.ts +++ b/packages/sitecore-jss/src/editing/utils.ts @@ -158,7 +158,7 @@ export const handleEditorAnchors = () => { * Gets extra JSS clientData scripts to render in XMC Pages in addition to clientData from Pages itself * @returns {Record} collection of clientData */ -export const getJssHorizonClientData = () => { +export const getJssPagesClientData = () => { const clientData: Record> = {}; clientData[PAGES_EDITING_MARKER] = {};