Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: in-context editable blocks #5

Merged
merged 7 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions blocks/cards/cards.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { createOptimizedPicture } from '../../scripts/aem.js';
import { moveInstrumentation } from '../../scripts/scripts.js';

export default function decorate(block) {
/* change to ul, li */
const ul = document.createElement('ul');
[...block.children].forEach((row) => {
const li = document.createElement('li');
[...row.attributes].forEach(({ nodeName, nodeValue }) => {
li.setAttribute(nodeName, nodeValue);
});
moveInstrumentation(row, li);
while (row.firstElementChild) li.append(row.firstElementChild);
[...li.children].forEach((div) => {
if (div.children.length === 1 && div.querySelector('picture')) div.className = 'cards-card-image';
else div.className = 'cards-card-body';
});
ul.append(li);
});
ul.querySelectorAll('img').forEach((img) => img.closest('picture').replaceWith(createOptimizedPicture(img.src, img.alt, false, [{ width: '750' }])));
ul.querySelectorAll('img').forEach((img) => {
const optimizedPic = createOptimizedPicture(img.src, img.alt, false, [{ width: '750' }]);
moveInstrumentation(img, optimizedPic.querySelector('img'));
img.closest('picture').replaceWith(optimizedPic);
});
block.textContent = '';
block.append(ul);
}
12 changes: 12 additions & 0 deletions scripts/aem.js
Original file line number Diff line number Diff line change
Expand Up @@ -634,10 +634,22 @@ function decorateBlock(block) {
if ((!firstChild && cellText)
|| (firstChild && !firstChild.tagName.match(/^(P(RE)?|H[1-6]|(U|O)L|TABLE)$/))) {
const paragraph = document.createElement('p');
[...cell.attributes]
// move the instrumentation from the cell to the new paragraph, also keep the class
// in case the content is a buttton and the cell the button-container
.filter(({ nodeName }) => nodeName === 'class'
|| nodeName.startsWith('data-aue')
|| nodeName.startsWith('data-richtext'))
.forEach(({ nodeName, nodeValue }) => {
paragraph.setAttribute(nodeName, nodeValue);
cell.removeAttribute(nodeName);
});
paragraph.append(...cell.childNodes);
cell.replaceChildren(paragraph);
}
});
// eslint-disable-next-line no-use-before-define
decorateButtons(block);
}
}

Expand Down
47 changes: 33 additions & 14 deletions scripts/editor-support-rte.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,59 @@
// group editable texts in single wrappers if applicable
//
// this script should execute after script.js by editor-support.js
/* eslint-disable no-cond-assign */
/* eslint-disable import/prefer-default-export */

// group editable texts in single wrappers if applicable.
// this script should execute after script.js but before the the universal editor cors script
// and any block being loaded

// eslint-disable-next-line import/prefer-default-export
export function decorateRichtext(container = document) {
function deleteInstrumentation(element) {
delete element.dataset.richtextResource;
delete element.dataset.richtextProp;
delete element.dataset.richtextFilter;
delete element.dataset.richtextLabel;
}

let element;
// eslint-disable-next-line no-cond-assign
while (element = container.querySelector('[data-richtext-resource]')) {
const { richtextResource, richtextProp, richtextFilter } = element.dataset;
while (element = container.querySelector('[data-richtext-prop]:not(div)')) {
const {
richtextResource,
richtextProp,
richtextFilter,
richtextLabel,
} = element.dataset;
deleteInstrumentation(element);
const siblings = [];
let sibling = element;
// eslint-disable-next-line no-cond-assign
while (sibling = sibling.nextElementSibling) {
if (sibling.dataset.richtextResource === richtextResource
&& sibling.dataset.richtextProp === richtextProp) {
deleteInstrumentation(sibling);
siblings.push(sibling);
} else break;
}
const orphanElements = document.querySelectorAll(`[data-richtext-id="${richtextResource}"][data-richtext-prop="${richtextProp}"]`);

let orphanElements;
if (richtextResource && richtextProp) {
orphanElements = document.querySelectorAll(`[data-richtext-id="${richtextResource}"][data-richtext-prop="${richtextProp}"]`);
} else {
const editable = element.closest('[data-aue-resource]');
if (editable) {
orphanElements = editable.querySelectorAll(`[data-richtext-prop="${richtextProp}"]`);
} else {
console.warn(`Editable parent not found or richtext property ${richtextProp}`);

Check warning on line 43 in scripts/editor-support-rte.js

View workflow job for this annotation

GitHub Actions / build

Unexpected console statement
return;
}
}

if (orphanElements.length) {
// eslint-disable-next-line no-console
console.warn('Found orphan elements of a richtext, that were not consecutive siblings of '

Check warning on line 49 in scripts/editor-support-rte.js

View workflow job for this annotation

GitHub Actions / build

Unexpected console statement
+ 'the first paragraph.', orphanElements);
orphanElements.forEach((el) => deleteInstrumentation(el));
+ 'the first paragraph', orphanElements);
orphanElements.forEach((orphanElement) => deleteInstrumentation(orphanElement));
} else {
const group = document.createElement('div');
group.dataset.aueResource = richtextResource;
group.dataset.aueProp = richtextProp;
if (richtextResource) group.dataset.aueResource = richtextResource;
if (richtextProp) group.dataset.aueProp = richtextProp;
if (richtextLabel) group.dataset.aueLabel = richtextLabel;
if (richtextFilter) group.dataset.aueFilter = richtextFilter;
group.dataset.aueBehavior = 'component';
group.dataset.aueType = 'richtext';
Expand Down
2 changes: 1 addition & 1 deletion scripts/editor-support.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ async function applyChanges(event) {
block.insertAdjacentElement('afterend', newBlock);
decorateButtons(newBlock);
decorateIcons(newBlock);
decorateRichtext(newBlock);
decorateBlock(newBlock);
decorateRichtext(newBlock);
await loadBlock(newBlock);
block.remove();
newBlock.style.display = null;
Expand Down
34 changes: 34 additions & 0 deletions scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,40 @@ import {

const LCP_BLOCKS = []; // add your LCP blocks to the list

/**
* Moves all the attributes from a given elmenet to another given element.
* @param {Element} from the element to copy attributes from
* @param {Element} to the element to copy attributes to
*/
export function moveAttributes(from, to, attributes) {
if (!attributes) {
// eslint-disable-next-line no-param-reassign
attributes = [...from.attributes].map(({ nodeName }) => nodeName);
}
attributes.forEach((attr) => {
const value = from.getAttribute(attr);
if (value) {
to.setAttribute(attr, value);
from.removeAttribute(attr);
}
});
}

/**
* Move instrumentation attributes from a given element to another given element.
* @param {Element} from the element to copy attributes from
* @param {Element} to the element to copy attributes to
*/
export function moveInstrumentation(from, to) {
moveAttributes(
from,
to,
[...from.attributes]
.map(({ nodeName }) => nodeName)
.filter((attr) => attr.startsWith('data-aue-') || attr.startsWith('data-richtext-')),
);
}

/**
* load fonts.css and set a session storage flag
*/
Expand Down