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: Add decoration handler for handling fragment decoration #39

Merged
merged 7 commits into from
Aug 6, 2024
Merged
Changes from 1 commit
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
55 changes: 52 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,46 @@ export function removeLeadingHyphens(inputString) {
return inputString.replace(/^(-+)/, '');
}

/**
* Check if the block is a hero block and rebuild it if needed.
* @param {Function} buildBlock
* @param {Element} el
* @returns revised element
*/
function rebuildIfHeroBlock(buildBlock, element) {
ramboz marked this conversation as resolved.
Show resolved Hide resolved
if (!element.classList.contains('hero')) return element;
const main = element.parentElement.parentElement;
[...element.children].reverse().forEach((el) => main.prepend(el));
element.remove();

// build hero block
const h1 = main.querySelector('main > div > h1');
const picture = main.querySelector('main > div > p > picture');
// eslint-disable-next-line no-bitwise
if (h1 && picture && (h1.compareDocumentPosition(picture) & Node.DOCUMENT_POSITION_PRECEDING)) {
const section = document.createElement('div');
section.append(buildBlock('hero', { elems: [picture, h1] }));
main.prepend(section);
}

return document.querySelector('.hero');
}

/**
* Check if the reDecorateBlocks() and buildBlock() are defined.
* @param {Function} buildBlock
* @param {Function} reDecorateBlocks
* @returns boolean
*/
function isRedecorateValid(buildBlock, reDecorateBlocks) {
if (typeof reDecorateBlocks === 'function' && typeof buildBlock === 'function') {
return true;
}
// eslint-disable-next-line no-console
console.warn('reDecorateBlocks() or buildBlock() is not defined.');
return false;
}

/**
* Retrieves the content of metadata tags.
* @param {String} name The metadata name (or property)
Expand Down Expand Up @@ -709,6 +749,9 @@ async function runExperiment(document, pluginOptions) {
variant,
},
}));
if (variant !== 'control' && isRedecorateValid(this.buildBlock, this.reDecorateBlocks)) {
Copy link
Contributor

@ramboz ramboz Aug 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken… page and section level will directly inline the HTML before the decoration as well, so the default Franklin decoration would work on those.

Only block/fragment done via the manifest are loaded after the decoration and would need to be redecorated. Correct?
So this could be moved to the ~L478 where we replace the HTML for the fragments.

We then can be in any of those use cases:

  1. we have a selector for an element inside a block and it doesn't need redecoration
  2. we have a selector for an element inside a block and the block needs to be redecorated
  3. we have a .block selector and we need to redecorate => switch block status to "loading" and call loadBlock(el)
  4. we have a .section selector and we need to redecorate => call decorateBlocks(el)
  5. we have a main selector and we need to redecorate => call decorateMain(el)
  6. we have a selector for an autoblock selector and we don't know what to do with it
  7. we have some random selector and we don't know what to do with it

We can offer a default implementation in scripts.js for 3, 4 & 5 pretty easily, but all the other ones will be dependent on the project implementation. We'd add this to the readme, since it's outside the scope of the plugin

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks! Makes more sense to move that in L478 :)

You are correct, the redecoration is only needed for fragment.

I did check if they are blocks in the project level(BHR case), if they are not, they will be ignored, so even adding that for page and section, it still works.

this.reDecorateBlocks(rebuildIfHeroBlock(this.buildBlock, el));
}
},
);
}
Expand Down Expand Up @@ -810,6 +853,9 @@ async function runCampaign(document, pluginOptions) {
campaign,
},
}));
if (campaign !== 'default' && isRedecorateValid(this.buildBlock, this.reDecorateBlocks)) {
this.reDecorateBlocks(rebuildIfHeroBlock(this.buildBlock, el));
}
},
);
}
Expand Down Expand Up @@ -892,6 +938,9 @@ async function serveAudience(document, pluginOptions) {
audience,
},
}));
if (audience !== 'default' && isRedecorateValid(this.buildBlock, this.reDecorateBlocks)) {
this.reDecorateBlocks(rebuildIfHeroBlock(this.buildBlock, el));
}
},
);
}
Expand All @@ -901,9 +950,9 @@ export async function loadEager(document, options = {}) {
setDebugMode(window.location, pluginOptions);

const ns = window.aem || window.hlx || {};
ns.audiences = await serveAudience(document, pluginOptions);
ns.experiments = await runExperiment(document, pluginOptions);
ns.campaigns = await runCampaign(document, pluginOptions);
ns.audiences = await serveAudience.call(this, document, pluginOptions);
ns.experiments = await runExperiment.call(this, document, pluginOptions);
ns.campaigns = await runCampaign.call(this, document, pluginOptions);

// Backward compatibility
ns.experiment = ns.experiments.find((e) => e.type === 'page');
Expand Down
Loading