Skip to content

Instantly share code, notes, and snippets.

@watershed
Last active July 21, 2021 01:57
Show Gist options
  • Save watershed/e6d7b013d5d5c3903bf1575419a85e4b to your computer and use it in GitHub Desktop.
Save watershed/e6d7b013d5d5c3903bf1575419a85e4b to your computer and use it in GitHub Desktop.
{#####
For a `body` field with type:fieldHandles structure:
collStart: collId*, attr
subheading: text*, customId, hWrap, incToC
text: text*
quote: text*, cite, citeUrl
images images* (needs work)
video: videoUrl*,ratio
collEnd collId*
Plugin dependencies are 'Empty Coalesce', and 'Twig Perversion' for the {% return %} scope within macros.
A macro for each block type plus:
* An `updateBody` macro to update the cumulative html and hWrap status captured in a `results` hash
* Utility macros called within the block type macros for:
* setAspect : sets aspect ratio
* youTubeSrc: ensures coherent YouTube embed for most inputs
* vimeoSrc : ensures coherent Vimeo embed for most inputs
* docDetails: generates a <details> element with error help text from a `Docs` entry
#####}
{#
Set an aspect ratio from a Matrix block with a ratio field
The default is '16 / 9'
#}
{% macro setAspect(block, width) %}
{% set ratio = block.ratio ??? null %}
{% if ratio %}
{% set ratioArr = ratio|split(':') %}
{% set factor = ratioArr[0] / ratioArr[1] %}
{% set height = width // factor %}
{% endif %}
{% set ratio = ratio ? ratio|split(':')|join(' / ') : '16 / 9' %}
{% set aspect = {
width : width,
height: height,
ratio : ratio
} %}
{% return aspect %}
{% endmacro %}
{# Create a YouTube embed URL #}
{% macro youTubeSrc(vidUrl) %}
{% set vidId = 'embed' in vidUrl ? vidUrl|replace('/^http.*embed\\/([^\\?]+)(\\?.*)?$/', '$1') : null %}
{% set vidId = 'watch' in vidUrl ? vidUrl|replace('/^http.*\\?v=([^\\&]+)(\\&.*)?$/', '$1') : null %}
{% set vidId = '.be/' in vidUrl ? vidUrl|replace('/^http.*\\.be\\/([^\\?]+)(\\?.*)?$/', '$1') : null %}
{% set srcUrl = vidId ? "https://www.youtube.com/embed/#{vidId}" : null %}
{% return srcUrl %}
{% endmacro %}
{# Create a Vimeo embed URL #}
{% macro vimeoSrc(vidUrl) %}
{% set vidId = vidUrl|replace('/^http.*video\\/([0-9]+)(\\?.*)?$/', '$1') %}
{% set vidId = vidId ? vidId : vidUrl|replace('/^http.*\\.com(.*)?\\/([0-9]+)(\\?.*)?$/', '$2') %}
{% set srcUrl = vidId ? "https://player.vimeo.com/video/#{vidId}" : null %}
{% return srcUrl %}
{% endmacro %}
{# Set an alert message #}
{% macro docDetails(doc) %}
{% set inner = doc.body.type('text').one() ?? null %}
{% set inner = inner ? "<summary>View guidance</summary>#{inner|md}" : null %}
{% set html = inner ? "<details>#{inner}</details>" : '' %}
{% return html %}
{% endmacro %}
{# Body content: collection start #}
{% macro collStart(block) %}
{% set html = "<div id=\"#{block.collId|kebab}\" #{block.attr}>" %}
{% return html %}
{% endmacro %}
{# Body content: subheading
text (required)
customId
hWrap
inToC
#}
{% macro subheading(block) %}
{% set hWrap = block.hWrap %}
{% set prefix = hWrap ? '<div class="hwrap">' : '' %}
{% set hId = block.customId ??? null %}
{% set html = block.text matches '/^#+.*$/' ? block.text|md : "<h2>#{block.text}</h2>" %}
{% set hasId = hId ? true : 'id=' in html %}
{% set autoId = hasId ? hId : block.text|replace('/(^#+)?(.*)$/', '$2')|trim|kebab %}
{% set html = autoId ? html|replace('/^(<h[^>]+)>(.*)$/', "$1 id=\"#{autoId}\">$2") : html %}
{% set html = "#{prefix}#{html}" %}
{% return html %}
{% endmacro %}
{# Body content: text #}
{% macro text(block) %}
{% set html = block.text|md %}
{% return html %}
{% endmacro %}
{# Body content: quote
text (required)
cite
citeUrl
#}
{% macro quote(block) %}
{% set citeAttr = block.citeUrl ??? null %}
{% set citeAttr = citeAttr ? "cite=\"#{citeAttr}\"" : '' %}
{% set citeElem = block.cite|md(inlineOnly=true) %}
{% set citeElem = citeElem ? "<cite>#{citeElem}</cite>" : '' %}
{% set html = "<blockquote #{citeAttr}>#{block.text|md} #{citeElem}</blockquote>" %}
{% return html %}
{% endmacro %}
{# Body content: images
images (required)
#}
{% macro images(block) %}
{# #}
{% return results %}
{% endmacro %}
{# Body content: video #}
{% macro video(block) %}
{% import _self as macro %}
{#
Initialise an HTML width of 352 to comfortably fit within a 375px mobile viewport,
which is then resized by appropriate CSS
#}
{% set aspect = macro.setAspect(block, 352) %}
{% set vidUrl = block.videoUrl %}
{% set srcUrl = null %}
{% if 'youtu' in vidUrl %}
{% set srcUrl = macro.youTubeSrc(vidUrl) %}
{% endif %}
{% if 'vimeo' in vidUrl %}
{% set srcUrl = macro.vimeoSrc(vidUrl) %}
{% endif %}
{% if srcUrl %}
{% set iframe %}
{{ tag('iframe', {
id : "video-#{vidId}",
src : srcUrl,
width : aspect.width,
height : aspect.height,
frameborder : '0',
allowfullscreen: true
}) }}
{% endset %}
{% set html %}
{{ tag('figure', {
style: "aspect-ratio:#{aspect.ratio}",
html: iframe
}) }}
{% endset %}
{% else %}
{% if admin %}
{% set doc = craft.entries.section('doc').slug('embedding-videos').one() ?? null %}
{% set details = doc ? macro.docDetails(doc) : '' %}
{% set html %}
<div class="alert">
<p>Sorry, we couldn’t insert an embedded video from the video URL format provided.</p>
{{ details|raw }}
</div>
{% endset %}
{% endif %}
{% endif %}
{% return html %}
{% endmacro %}
{# Body content: collection end #}
{% macro collEnd(block, results) %}
{% set collId = block.collId|kebab %}
{% set alert = "<div class=\"alert\">The collection called ‘#{collId}’ has not been started, so it can’t be ended!</div>" %}
{% set html = "id=\"#{collId}\"" in results.html ? '</div>' : alert %}
{% return html %}
{% endmacro %}
{# Update body html after processing a block #}
{% macro updateBody(results, html, nextType, openWrap) %}
{% set hWrap = openWrap is not null ? openWrap : null %}
{% set suffix = '' %}
{% if (results.hWrap and nextType == 'subheading') or (results.hWrap and nextType == 'collEnd') or (results.hWrap and not nextType) %}
{% set suffix = '</div>' %}
{% set hWrap = hWrap ? false : hWrap %}
{% endif %}
{% set html = "#{results.html}#{html}#{suffix}" %}
{% set results = results|merge({
html : html,
hWrap: hWrap,
}) %}
{% return results %}
{% endmacro %}
{#####
The above macros called in a template partial which does the following
#####}
{# Initialise a hash to contain our HTML #}
{% set results = {
html : '',
hWrap: false
} %}
{% for block in body %}
{% set openWrap = null %}
{% set next = block.next ?? false %}
{% set nextType = next ? next.type.handle : false %}
{% switch block.type.handle %}
{% case 'collStart' %}
{% set html = siteMacros.collStart(block) %}
{% case 'subheading' %}
{% set html = siteMacros.subheading(block) %}
{% set openWrap = 'hwrap' in html %}
{% case 'text' %}
{% set html = siteMacros.text(block) %}
{% case 'quote' %}
{% set html = siteMacros.quote(block) %}
{% case 'images' %}
{% set html = siteMacros.images(block) %}
{% case 'video' %}
{% set html = siteMacros.video(block) %}
{% case 'collEnd' %}
{% set html = siteMacros.collEnd(block, results) %}
{% endswitch %}
{% set results = siteMacros.updateBody(results, html, nextType, openWrap) %}
{% endfor %}
{{ results.html|raw }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment