Component: Content Revealer

Implementation Notes

  • All functional elements are linked via a data attribute that contains a selector for the container, e.g. data-content-revealer-target="#contentRevealerTarget".
  • There is exactly one container that matches the selector (e.g. <div id="contentRevealerTarget">).
  • There is at least one button with the selector in the data attribute that triggers the revealing, e.g. <button data-content-revealer-target="#contentRevealerTarget">.
  • The button can contain an additional data attribute that defines the number of elements to be revealed, e.g. <button … data-content-revealer-batch-count="6">.

When all elements are revealed, the button is set to disabled.

<!-- Default -->
<div class="contentRevealer"></div>

<!-- Demo only -->
<section class="doc-section">

    <h2 class="doc-section-title">Demo für aufzudeckende Inhalte</h2>

    <div id="contentRevealerTarget" class="doc-box" style="margin-top: var(--sp-component);">

        <ol class="ol" style="margin-top: 0;">
            <li>
                Hashtag Echo Park selfies
            </li>
            <li>
                PBR try-hard skateboardplaid 8-bit
            </li>
            <li>
                Flexitarian retro single-origin coffee
            </li>
            <li data-content-revealer-hidden="true">
                Church-key vinyl pug cardigan
            </li>
            <li data-content-revealer-hidden="true">
                Biodiesel locavore PBR try-hard skateboard
            </li>
            <li data-content-revealer-hidden="true">
                Plaid 8-bit
            </li>
            <li data-content-revealer-hidden="true">
                Flexitarian retro single-origin coffee
            </li>
            <li data-content-revealer-hidden="true">
                Biodiesel locavore PBR try-hard skateboard
            </li>
        </ol>

    </div>

    <p><button class="button" data-content-revealer-target="#contentRevealerTarget" data-content-revealer-batch-count="3">Weitere laden</button></p>

</section>

  • Handle: @contentrevealer
  • Preview:
  • Filesystem Path: components/03-fragments/contentRevealer/contentRevealer.html
<!-- Default -->
<div class="contentRevealer{{#modifier}} {{.}}{{/modifier}}"></div>

<!-- Demo only -->
<section class="doc-section">

    <h2 class="doc-section-title">Demo für aufzudeckende Inhalte</h2>

    <div id="{{id}}" class="doc-box" style="margin-top: var(--sp-component);">

        <ol class="ol" style="margin-top: 0;">
                {{#items}}
            <li{{#if hidden}} data-content-revealer-hidden="true"{{/if}}>
                {{{content}}}
            </li>
                {{/items}}
        </ol>

    </div>

    <p><button class="button" data-content-revealer-target="#{{id}}" data-content-revealer-batch-count="{{batch}}">Weitere laden</button></p>

</section>
/* Default: No context defined. */

/* Demo only */
{
  "id": "contentRevealerTarget",
  "batch": 3,
  "items": [
    {
      "content": "Hashtag Echo Park selfies"
    },
    {
      "content": "PBR try-hard skateboardplaid 8-bit"
    },
    {
      "content": "Flexitarian retro single-origin coffee"
    },
    {
      "hidden": true,
      "content": "Church-key vinyl pug cardigan"
    },
    {
      "hidden": true,
      "content": "Biodiesel locavore PBR try-hard skateboard"
    },
    {
      "hidden": true,
      "content": "Plaid 8-bit"
    },
    {
      "hidden": true,
      "content": "Flexitarian retro single-origin coffee"
    },
    {
      "hidden": true,
      "content": "Biodiesel locavore PBR try-hard skateboard"
    }
  ]
}

  • Content:
    export default (function (){
    
        const defaults = {
            selectors: {
                trigger: "button[data-content-revealer-target]",
            },
            batchCount: 3,
        };
    
        function init(options) {
    
            const triggers = document.querySelectorAll(defaults.selectors.trigger);
    
            for (let i = 0; i < triggers.length; i++) {
                new ContentRevealer(triggers[i], options);
            }
    
        }
    
        const ContentRevealer = function(trigger, options) {
    
            this.settings = Object.assign({}, defaults, options);
    
            this.trigger = trigger;
    
            if (! this.trigger.dataset.contentRevealerTarget) {
                console.warn("contentRevealer: No target defined!");
                return false;
            }
    
            this.selector = this.trigger.dataset.contentRevealerTarget;
    
            this.target = document.querySelector(this.selector);
    
            if (this.target.length === 0) {
                console.warn(`contentRevealer: No target match selector "${this.selector}"`);
                return false;
            }
    
            this.trigger.addEventListener(
                "click",
                (e) => {
    
                    e.preventDefault();
    
                    let batchCount = this.settings.batchCount;
    
                    if (this.trigger.dataset.contentRevealerBatchCount && parseInt(this.trigger.dataset.contentRevealerBatchCount) !== 0) {
                        batchCount = parseInt(this.trigger.dataset.contentRevealerBatchCount);
                    }
    
                    this.reveal(batchCount);
    
                }
            );
    
        }
    
        ContentRevealer.prototype.reveal = function(batchCount) {
    
            if (typeof batchCount != "number") {
                batchCount = this.settings.batchCount;
            }
    
            const items = this.target.querySelectorAll(`[data-content-revealer-hidden="true"]`);
    
            if (items.length === 0) {
                console.warn(`contentRevealer: No hidden items found!`);
                return false;
            }
    
            for (let i = 0; i < batchCount && i < items.length; i++) {
                items[i].dataset.contentRevealerHidden = "false";
            }
    
            const leftover = items.length - batchCount;
    
            if (leftover <= 0) {
                this.disable();
            }
    
        }
    
        ContentRevealer.prototype.disable = function(data) {
    
            const triggers = document.querySelectorAll(defaults.selectors.trigger + `[data-content-revealer-target="${this.selector}"]`);
    
            for (let i = 0; i < triggers.length; i++) {
                triggers[i].disabled = "disabled";
            }
    
        }
    
        return {
            init: init
        }
    
    })();
    
  • URL: /components/raw/contentrevealer/_contentRevealer.script.js
  • Filesystem Path: components/03-fragments/contentRevealer/_contentRevealer.script.js
  • Size: 2.6 KB
  • Content:
    %contentRevealer {
    
        &-item {
    
            &[data-content-revealer-hidden="true"] {
                display: none;
            }
    
        }
    
        &-trigger {
    
            &[disabled] {
                display: none;
            }
    
        }
    
    
    }
    
    .contentRevealer {
        @extend %contentRevealer;
    
        &-item {
            @extend %contentRevealer-item;
        }
    
    }
    
    [data-content-revealer-hidden] {
        @extend %contentRevealer-item;
    }
    
    button[data-content-revealer-target] {
        @extend %contentRevealer-trigger;
    }
    
  • URL: /components/raw/contentrevealer/_contentRevealer.styles.scss
  • Filesystem Path: components/03-fragments/contentRevealer/_contentRevealer.styles.scss
  • Size: 478 Bytes