import React, { useEffect, useRef, useState } from 'react'
import { connect } from 'react-redux'
import { store } from '../../store/index'
import './Playground.css'
import PolicyAccordion from '../policy-accordion/PolicyAccordion'
function mapStateToProps(state) {
}
function mapDispatchToProps(dispatch) {
return {
}
}
function Playground(props) {
const { listDataProps = `{}` } = props // props from aem/html
const { componentPath, templatePattern, templateConfigurationPathPattern, liveusageQueryPath, basePagePath, wcmmode, currentResourcePath, fiddleCss, notes, defaultTemplateRegExp, defaultImportContentRegExp } = listDataProps
const [loadingIframes, setLoadingIframes] = useState(true)
const iframeContentRef = useRef(null)
const [urlDialogComponent, setUrlDialogComponent] = useState(null)
const [urlContentPage, setUrlContentPage] = useState(null)
const [iframeContentDisableMode, setIframeContentDisableMode] = useState(true)
const [selectedTemplatePath, setSelectedTemplatePath] = useState(null)
const [componentFullPath, setComponentFullPath] = useState(null)
const [fullBasePagePath, setFullBasePagePath] = useState(null)
const [selectTemplateOptions, setSelectTemplateOptions] = useState([])
// import content
const [selectPreContentOptions, setSelectPreContentOptions] = useState([])
const [selectedPreContent, setSelectedPreContent] = useState('')
const [fiddleValue, setFiddleVaue] = useState(fiddleCss)
const [notesValue, setNotesVaue] = useState(notes)
const [loadedAxeCore, setLoadedAxeCore] = useState(false)
const [axeCoreViolations, setAxeCoreViolations] = useState([])
const [demoControlWindow, setDemoControlWindow] = useState('')
const [tabWindow, setTabWindow] = useState('playground')
const [aemPoliciesList, setAemPoliciesList] = useState([])
const [aemLiveUsageList, setAemLiveUsageList] = useState([])
const [aemLiveUsageListSize, setAemLiveUsageListSize] = useState(0)
const [saveMessage, setSaveMessage] = useState('')
useEffect(async () => {
// get template selected by default
let initSelectedTemplatePath = getUrlParameter('t') // shared link parameter
// will display default or shared selectedTemplatePath.
// Called first to get default precontent, and then pass it to getTemplates to create the page.
let currentStateInfo = await getPreContent(initSelectedTemplatePath)
await getTemplates(currentStateInfo)
// wait for templates to load and then search for precontent
getPolicies()
}, []) // called only once
async function getTemplates(currentStateInfo) {
const details = {
tp: templatePattern,
tcp: templateConfigurationPathPattern,
defaultTemplateRegExp,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
return await fetch('/bin/aemcatalog.playgroundtemplates.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((templates) => {
if (templates && templates.aemTemplateList) {
setSelectTemplateOptions([{ name: 'Select', path: '', nameHint: '' }, ...templates.aemTemplateList])
let currentInitSelectedTemplatePath = null
if (currentStateInfo && currentStateInfo.initSelectedTemplatePath) { // check if its first load, select the default template
currentInitSelectedTemplatePath = currentStateInfo.initSelectedTemplatePath
}
else if (templates.initSelectedTemplate && templates.initSelectedTemplate.path) {
currentInitSelectedTemplatePath = templates.initSelectedTemplate.path
}
handleTemplateChange(currentInitSelectedTemplatePath, currentStateInfo.selectedPreContent) // send default init content
return { initSelectedTemplatePath: currentInitSelectedTemplatePath }
}
else {
setSelectTemplateOptions([])
console.log('No template options loaded.')
return { initSelectedTemplatePath: null }
}
})
.catch(err => console.log(err))
}
async function getPreContent(initSelectedTemplatePath) {
let returnValue = { selectedPreContent: null, initSelectedTemplatePath }
const details = {
defaultImportContentRegExp,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
return await fetch(`/bin/aemcatalogprecontent.list.json${componentPath}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((pages) => {
if (pages && pages.aemPreconfiguredContentList) {
setSelectPreContentOptions([{ title: 'Select', fullPagePath: '', fullComponentPath: '' }, ...pages.aemPreconfiguredContentList])
if (pages.initSelectedPreconfiguredContent) { // set default pre content
setSelectedPreContent(pages.initSelectedPreconfiguredContent.fullPagePath)
returnValue.selectedPreContent = pages.initSelectedPreconfiguredContent.fullPagePath // set default default precontent
}
else {
setSelectedPreContent('')
}
}
else {
setSelectPreContentOptions([])
setSelectedPreContent('')
console.log('No template options loaded.')
}
return returnValue
})
.catch(err => console.log(err))
}
function setIframeDialogUrl(componentPath, resourcePath) {
let url = `/bin/aemdialog.html/mnt/override${componentPath}/_cq_dialog.html${resourcePath}?page=true` + `&time=${Date.now()}` // timestamp force refresh
setLoadingIframes(true)
setUrlDialogComponent(url)
}
function setIframeContentUlr(pagePath, disableMode) {
console.log(`pagePath:${pagePath} disableMode:${disableMode}`)
let url = `${pagePath}.html`
if (disableMode === true) {
url = `${url}?wcmmode=disabled` + `&time=${Date.now()}` // timestamp force refresh
}
else { // author;
url = `/editor.html${url}?time=${Date.now()}`
}
setLoadingIframes(true)
setUrlContentPage(url)
}
function overrideDialog(iframeTarget) {
const iframeDialog = iframeTarget.target
const iframeWinDialog = iframeDialog.contentWindow || iframeDialog
const iframeDocDialog = iframeDialog.contentDocument || iframeDialog.document
// var action = iframeDocDialog.querySelector("form").getAttribute("action");
console.log(`urlDialogComponent${urlDialogComponent}`)
let iframeFrom = iframeDocDialog.querySelector('form')
if (iframeFrom) {
iframeFrom.setAttribute('data-cq-dialog-pageeditor', urlDialogComponent)
}
}
async function handleTemplateChange(templatePath, selectedPreContent) {
// let templatePath = event.target.value;
// call servlet
let result = await createPage (componentPath, templatePath, selectedPreContent)
let _componentFullPath = result.componentFullPath
let _fullBasePagePath = result.fullBasePagePath
setSelectedTemplatePath(templatePath)
setComponentFullPath(_componentFullPath)
setFullBasePagePath(_fullBasePagePath)
if (templatePath) {
console.log(`handleTemplateChange:${templatePath}`)
setIframeDialogUrl(componentPath, _componentFullPath)
setIframeContentUlr(_fullBasePagePath, iframeContentDisableMode)
}
}
async function handlePreContentChange(event) {
console.log(`change clearing..${event.target.value}`)
let pagePath = event.target.value
setSelectedPreContent(pagePath)
}
function getUrlParameter(parameterName) {
const search = window.location.search
const params = new URLSearchParams(search)
const wsValue = params.get(parameterName)
if (wsValue) {
return wsValue
}
return ''
}
async function createPage(componentPath, templatePath, selectedPreContent) {
const details = {
selectedPreContent,
t: templatePath,
ws: getUrlParameter('ws'),
crp: currentResourcePath,
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
let response = fetch(`/bin/aemcatalogpage.getpage.html${componentPath}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
}).then(response => response.json()).catch((err) => {
console.log(err)
})
return await response
}
async function savePage(e) {
if (!fullBasePagePath) {
return
}
const details = {
template: selectedTemplatePath,
componentfullpath: componentFullPath,
page: fullBasePagePath,
componentpath: componentPath,
pagename: 'base',
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch('/bin/aemcatalogsave.save.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((response) => {
getPreContent()
alert('Saved!')
})
.catch((err) => {
console.log(err)
})
}
async function clearAllPages(e) {
const details = {
template: selectedTemplatePath,
componentfullpath: componentFullPath,
page: fullBasePagePath,
componentpath: componentPath,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch('/bin/aemcatalogsave.clearall.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((response) => {
getPreContent()
})
.catch((err) => {
console.log(err)
})
}
async function clearPage(e) {
const details = {
template: selectedTemplatePath,
componentfullpath: componentFullPath,
page: fullBasePagePath,
componentpath: componentPath,
precontentPath: selectedPreContent,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch('/bin/aemcatalogsave.clearpage.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((response) => {
getPreContent()
})
.catch((err) => {
console.log(err)
})
}
async function importContent(event) {
/// ////// /* Post import content*/
const details = {
precontent: selectedPreContent,
template: selectedTemplatePath,
componentfullpath: componentFullPath,
page: fullBasePagePath,
componentpath: componentPath,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch('/bin/aemcatalogprecontent.update.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((response) => {
if (response.fullComponentPath) {
setIframeDialogUrl(componentPath, response.fullComponentPath) // componentPath componentFullPath
setIframeContentUlr(response.fullPagePath, iframeContentDisableMode) // fullBasePagePath toogleDisableMode
}
})
.catch((err) => {
console.log(err)
})
}
async function getCsrfToken() {
const response = await fetch('/libs/granite/csrf/token.json')
const json = await response.json()
return json.token
}
function toggleDisableMode() {
let _togleDisableMode = !iframeContentDisableMode
setIframeContentDisableMode(_togleDisableMode)
updateModifiedPage(_togleDisableMode)
}
async function updateModifiedPage(_togleDisableMode) {
if (!_togleDisableMode) { // change to author, nothing has been updated yet.
setIframeDialogUrl(componentPath, componentFullPath)
setIframeContentUlr(fullBasePagePath, _togleDisableMode)
return
}
const details = {
template: selectedTemplatePath,
componentfullpath: componentFullPath,
page: fullBasePagePath,
componentpath: componentPath,
pagename: 'base',
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch('/bin/aemcatalogsave.update.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((response) => {
let _componentFullPath = response.fullComponentPath
setComponentFullPath(_componentFullPath)
setIframeDialogUrl(componentPath, _componentFullPath)
setIframeContentUlr(fullBasePagePath, _togleDisableMode)
})
.catch((err) => {
console.log(err)
})
}
function redirectNavigation(iframeTarget) {
// prevent navigationa away from current url, just works on publish
// on author it does not work as editor has iframe
const currentIframe = iframeTarget.target
const currentIframeWin = currentIframe.contentWindow || currentIframe
const currentPath = currentIframeWin.location.pathname + currentIframeWin.location.search
if (currentPath && urlContentPage && currentPath != urlContentPage) {
console.log('Not the same Path')
currentIframe.src = urlContentPage
}
}
function disableAuthorPanel(iframeTarget) {
const currentIframe = iframeTarget.target
const currentIframeDoc = currentIframe.contentDocument || currentIframe.document
let paneHeader = currentIframeDoc.querySelector('.editor-GlobalBar.editor-panel-header')
if (paneHeader) {
// paneHeader.style.pointerEvents = 'none';
paneHeader.style.opacity = '0.2'
}
}
async function clearWorkspace() {
await fetch('/bin/aemplayground.clear.html', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'GET',
})
window.location.reload()
}
function applyCss() {
console.log('apply css')
if (iframeContentRef.current) {
const currentIframeDoc = iframeContentRef.current.contentDocument || iframeContentRef.current.document
let existingElement = currentIframeDoc.head.querySelector('#xpfiddle-css')
if (existingElement) {
existingElement.textContent = fiddleValue
}
else {
let style = currentIframeDoc.createElement('style')
style.type = 'text/css'
style.setAttribute('id', 'xpfiddle-css')
style.textContent = fiddleValue
currentIframeDoc.head.appendChild(style)
}
}
}
async function saveCss() {
const details = {
fv: fiddleValue,
crp: currentResourcePath,
t: selectedTemplatePath,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch(`/bin/aemcatalogpage.fiddlecss.json${componentPath}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((templates) => {
})
.catch(err => console.log(err))
}
async function saveNotes() {
const details = {
nv: notesValue,
crp: currentResourcePath,
t: selectedTemplatePath,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch(`/bin/aemcatalogpage.savenotes.json${componentPath}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((templates) => {
setSaveMessage('Saved')
setTimeout(() => { setSaveMessage('') }, 1500)
})
.catch(err => console.log(err))
}
async function shareLink() {
const response = await fetch(`/bin/aemcatalogpage.getid.html${componentPath}?` + `ws=${encodeURIComponent(getUrlParameter('ws'))}`)
const responseValue = await response.json()
if (responseValue.indentifier) {
let ccp = (new URLSearchParams(window.location.search)).get('ccp')
let path = window.location.href.split('?')[0]
let selectedTemplatePathParam = ''
if (selectedTemplatePath) {
selectedTemplatePathParam = `&t=${selectedTemplatePath}`
}
let ccpParam = ''
if (ccp) {
ccpParam = `&ccp=${ccp}`
}
let urlClippboard = `${path}?` + `ws=${encodeURIComponent(responseValue.indentifier)}${ccpParam}${selectedTemplatePathParam}`
await navigator.clipboard.writeText(urlClippboard)
alert(`Copied to clipboard: ${urlClippboard}`)
}
}
function timeout(delay) {
return new Promise(res => setTimeout(res, delay))
}
async function loadAxeCore() {
setLoadedAxeCore(true)
if (!loadedAxeCore) {
const currentIframeDoc = iframeContentRef.current.contentDocument || iframeContentRef.current.document
const iframeWinDialog = iframeContentRef.current.contentWindow || iframeContentRef.current.window
let scriptAxe = currentIframeDoc.createElement('script')
scriptAxe.type = 'text/javascript'
scriptAxe.src = '/etc.clientlibs/aem-component-catalog/clientlibs/clientlib-axe.js'
await currentIframeDoc.head.append(scriptAxe)
await timeout(1000)
let results = await iframeWinDialog.axe.run()
if (results.violations.length > 0) {
setAxeCoreViolations(results.violations)
}
else {
setAxeCoreViolations([])
}
results.violations.forEach(
(item, index) => {
item.nodes.forEach(
(node, index) => {
if (node && node.target) {
let elementNode = currentIframeDoc.querySelector(node.target[0])
if (elementNode) {
// elementNode.style.border ="3px dotted green";
elementNode.style.outline = 'dotted green'
}
}
},
)
},
)
}
}
async function getPolicies() {
let formBody = []
if (componentPath) {
formBody.push(`${encodeURIComponent('c')}=${encodeURIComponent(componentPath)}`)
}
formBody = formBody.join('&')
fetch('/bin/aempolicies.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((components) => {
if (components && components.aemPolicyDTOList) {
setAemPoliciesList(components.aemPolicyDTOList)
}
else {
console.log('No component options loaded.')
setAemPoliciesList([])
}
// setLoading(false);
})
.catch((err) => {
console.log(err)
// setLoading(false);
setAemPoliciesList([])
})
}
async function getLiveUsage() {
const details = {
t: selectedTemplatePath,
bp: liveusageQueryPath,
c: componentPath,
ws: getUrlParameter('ws'),
}
let formBody = []
for (let property in details) {
if (details[property]) {
let encodedKey = encodeURIComponent(property)
let encodedValue = encodeURIComponent(details[property])
formBody.push(`${encodedKey}=${encodedValue}`)
}
}
formBody = formBody.join('&')
fetch('/bin/aemusage.components.json', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'CSRF-Token': await getCsrfToken(),
},
method: 'POST',
body: formBody,
})
.then(response => response.json())
.then((components) => {
if (components && components.aemLiveUsageItemDTOList) {
setAemLiveUsageList(components.aemLiveUsageItemDTOList)
setAemLiveUsageListSize(components.size)
}
else {
console.log('No component options loaded.')
}
// setLoading(false);
})
.catch((err) => {
console.log(err)
// setLoading(false);
setAemLiveUsageList([])
setAemLiveUsageListSize(0)
})
}
return (
<div className="responsivegrid aem-GridColumn aem-GridColumn--default--12">
<div id="container-aacc1dda19" className="cmp-container container">
<div className="aem-Grid aem-Grid--12 aem-Grid--default--12">
<ul className="nav nav-tabs">
<li className="nav-item">
<a className={`nav-link ${tabWindow === 'playground' ? 'active' : ''}`} aria-current="page" onClick={(e) => { setTabWindow('playground') }}>Playground</a>
</li>
<li className="nav-item">
<a className={`nav-link ${tabWindow === 'liveusage' ? 'active' : ''}`} onClick={(e) => { setTabWindow('liveusage'); getLiveUsage() }}>Live Usage Report</a>
</li>
<li className="nav-item">
<a className={`nav-link ${tabWindow === 'policies' ? 'active' : ''}`} onClick={(e) => { setTabWindow('policies') }}>Policies</a>
</li>
</ul>
{/* JSX playground */}
<div className={`playground-react aem-GridColumn aem-GridColumn--default--12 ${tabWindow === 'playground' ? 'display-tab' : 'hide-tab'}`}>
<div className="playground">
<div className="playground-controls row mt-4">
<div className="col-lg-9">
<h3>Workspace Content Controls</h3>
<div className="row">
<div className="col-lg-6 template">
<label htmlFor="template-select" className="form-label">
Select a page
template
</label>
<select
className="template-select form-select"
id="template-select"
value={selectedTemplatePath}
onChange={e => handleTemplateChange(e.target.value, null)}
>
{selectTemplateOptions.map((option, index) => (
<option key={index} value={option.path}>
{option.nameHint}
{' '}
{option.title}
{' '}
{index === 0 && 'Select'}
{' '}
{index !== 0 && `(${option.name})`}
</option>
),
)}
</select>
</div>
<div className="col-lg-6 playground-import">
{selectedTemplatePath && (
<>
<label htmlFor="precontent-select" className="form-label">
Select content
for the component
</label>
<div className="precontent input-group">
<select
className="precontent-select form-select"
id="precontent-select"
value={selectedPreContent}
onChange={e => handlePreContentChange(e)}
>
{selectPreContentOptions.map((option, index) => (
<option key={index} value={option.fullPagePath}>
{option.title}
{' '}
{index !== 0 && `(${option.name})`}
</option>
),
)}
</select>
<button className="btn btn-outline-secondary" type="button" onClick={e => importContent(e)}>Import Content</button>
</div>
</>
)}
</div>
</div>
</div>
{ wcmmode == 'EDIT' && selectedTemplatePath
&& (
<div className="col-lg-2 offset-lg-1 admin-controls">
<h3>Admin</h3>
<div className="form-check form-switch">
<input
disabled={!fullBasePagePath}
className="form-check-input"
type="checkbox"
role="switch"
id="authorSwitchCheck"
onClick={(e) => {
toggleDisableMode()
}}
/>
<label className="form-check-label" htmlFor="authorSwitchCheck">
{!iframeContentDisableMode && ' Disable Author View'}
{' '}
{iframeContentDisableMode && 'Enable Author View'}
</label>
</div>
<button
className="btn btn-sm btn-link"
disabled={!fullBasePagePath || iframeContentDisableMode}
onClick={e => savePage(e)}
>
<span
className="material-symbols-rounded"
>
save
</span>
{' '}
Save Demo Content
</button>
{selectedPreContent && (
<button
className="btn btn-sm btn-link"
onClick={e => clearPage(e)}
>
{' '}
<span
className="material-symbols-rounded"
>
close
</span>
Clear Page Demo Content
</button>
)}
<button
className="btn btn-sm btn-link"
onClick={e => clearAllPages(e)}
>
{' '}
<span
className="material-symbols-rounded"
>
close
</span>
Clear All Demo Content
</button>
</div>
)}
</div>
<div className="row mt-5 playground-container">
<div className="col-lg-2">
<h3>Demo Controls -</h3>
{selectedTemplatePath
&& (
<>
<button
className="btn btn-sm btn-link show-control"
onClick={(e) => {
setDemoControlWindow('dialog')
}}
data-whichcontrol="component-dialog"
>
<span
className="material-symbols-rounded"
>
tune
</span>
{' '}
Edit Component
</button>
<button
className="btn btn-sm btn-link show-control"
onClick={(e) => {
setDemoControlWindow('css')
}}
data-whichcontrol="fiddler-dialog"
>
<span
className="material-symbols-rounded"
>
palette
</span>
{' '}
Component CSS
</button>
<button
onClick={(e) => {
loadAxeCore(e)
setDemoControlWindow('axe')
}}
className="btn btn-sm btn-link btn-axe show-control"
data-whichcontrol="axe-results"
>
<span
className="material-symbols-rounded"
>
accessibility_new
</span>
{' '}
Axe
Accessibility
</button>
</>
)}
<button
className="btn btn-sm btn-link"
onClick={(e) => {
setDemoControlWindow('notes')
}}
data-whichcontrol="fiddler-dialog"
>
<span
className="material-symbols-rounded"
>
tune
</span>
{' '}
Notes      
</button>
<button onClick={e => shareLink(e)} className="btn btn-sm btn-link">
<span
className="material-symbols-rounded"
>
link
</span>
{' '}
Share Link
</button>
<button
className="btn btn-sm btn-link clear"
onClick={e => clearWorkspace(e)}
>
<span
className="material-symbols-rounded"
>
close
</span>
{' '}
Clear Workspace
</button>
</div>
<div className="col-lg-10">
<iframe
id="contentIFrame"
className={`content-iframe ${iframeContentDisableMode ? 'disable-mode ' : 'author-mode '}${loadingIframes ? 'loading ' : ' '}`}
height="800"
src={urlContentPage}
title="description"
ref={iframeContentRef}
onLoad={(iframeTarget) => {
redirectNavigation(iframeTarget)
disableAuthorPanel(iframeTarget)
setLoadedAxeCore(false)
setLoadingIframes(false)
}}
>
</iframe>
</div>
<div
className={`demo-control component-dialog ${demoControlWindow === 'dialog' ? 'active ' : ' '}`}
id="component-dialog"
>
<button
className="btn btn-sm btn-link close-control"
onClick={e => setDemoControlWindow('')}
>
<span
className="material-symbols-rounded"
>
close
</span>
</button>
<iframe
id="dialogIFrame"
height="800"
className={`dialog-iframe ${loadingIframes ? 'loading ' : ' '}${iframeContentDisableMode ? 'disable-mode ' : 'author-mode '}`}
src={urlDialogComponent}
title="description"
onLoad={(iframeTarget) => {
if (!loadingIframes) { // if it is not true it was trigger by submit, //if loading is true then it was trigger by a component action
iframeContentRef.current.contentWindow.location.reload() // no need to timeout since its after the it loads
}
setLoadingIframes(false)
overrideDialog(iframeTarget)
}}
>
</iframe>
</div>
<div
className={`demo-control fiddler-dialog ${demoControlWindow === 'css' ? 'active ' : ' '}`}
id="fiddler-dialog"
>
<button
className="btn btn-sm btn-link close-control"
onClick={e => setDemoControlWindow('')}
>
<span
className="material-symbols-rounded"
>
close
</span>
</button>
<h4>Add custom CSS to the component</h4>
<textarea
id="fiddler-text-area"
name="textarea"
className="mb-3"
value={fiddleValue}
onInput={e => setFiddleVaue(e.target.value)}
>
</textarea>
<button
className="btn btn-outline-secondary"
onClick={(e) => {
applyCss(e)
saveCss(e)
}}
>
Apply css
</button>
</div>
<div
className={`demo-control fiddler-dialog ${demoControlWindow === 'notes' ? 'active ' : ' '}`}
id="fiddler-dialog"
>
<button
className="btn btn-sm btn-link close-control"
onClick={e => setDemoControlWindow('')}
>
<span
className="material-symbols-rounded"
>
close
</span>
</button>
<h4>Notes</h4>
<textarea
id="fiddler-text-area"
name="textarea"
className="mb-3"
value={notesValue}
onInput={e => setNotesVaue(e.target.value)}
>
</textarea>
<button
className="btn btn-outline-secondary"
onClick={(e) => {
saveNotes(e)
}}
>
Save
</button>
{saveMessage
&& (
<div className="alert alert-secondary mt-1 mb-1" role="alert">
{saveMessage}
</div>
)}
</div>
<div
className={`demo-control axe-results ${demoControlWindow === 'axe' ? 'active ' : ' '}`}
id="axe-results"
>
<button
className="btn btn-sm btn-link close-control"
onClick={e => setDemoControlWindow('')}
>
<span
className="material-symbols-rounded"
>
close
</span>
</button>
<h4>Accessibility Scan Results</h4>
{axeCoreViolations && loadedAxeCore
&& (
<div>
{axeCoreViolations.map((group, index) => (
<div>
<h5 className="title">{group.id}</h5>
<span className="title">{group.description}</span>
<ul>
{group.nodes.map((node, index) => (
<li key={index}>
<span>{node.target}</span>
<span>{node.failureSummary}</span>
</li>
))}
</ul>
</div>
),
)}
</div>
)}
</div>
</div>
</div>
</div>
{/* End JSX playground */}
{/* JSX policies */}
<div className={`playground-react aem-GridColumn aem-GridColumn--default--12 ${tabWindow === 'policies' ? 'display-tab' : 'hide-tab'}`}>
{aemPoliciesList
&& (
<ul className="policies-list">
{aemPoliciesList.map((item, index) => (
<PolicyAccordion index={index} item={item} />
),
)}
</ul>
)}
</div>
{/* End JSX policies */}
{/* JSX live usage */}
<div
className={`playground-react aem-GridColumn aem-GridColumn--default--12 ${tabWindow === 'liveusage' ? 'display-tab' : 'hide-tab'}`}
>
<table className="table liveusage-list">
<thead>
<tr>
<th scope="col">Count</th>
<th scope="col">Template</th>
</tr>
</thead>
<tbody>
<tr>
<td>{aemLiveUsageListSize}</td>
<td>{selectedTemplatePath}</td>
</tr>
</tbody>
</table>
<table className="table liveusage-list">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Page or Fragment Path</th>
<th scope="col">Component Path</th>
</tr>
</thead>
{aemLiveUsageList
&& (
<tbody>
{aemLiveUsageList.map((item, index) => (
<tr key={index}>
<td>{item.title}</td>
<td>{item.pagePath}</td>
<td>{item.resourcePath}</td>
</tr>
),
)}
</tbody>
)}
</table>
</div>
{/* End JSX live usage */}
</div>
</div>
</div>
)
}
const ConnectedPlayground = connect(
mapStateToProps,
mapDispatchToProps,
)(Playground)
export { ConnectedPlayground as Playground }