FILTERABLE-LIST-BLUEPRINT (LMU Physik Module )
src/app/shared/components/filterable-list-blueprint/templates
Demo Section
Each variation will be presented in the following section.
Readme
filterableListBlueprint (component
)
Description
This blueprint is based on the blueprint of Veams.
Requirements
Veams#5.0.0
Installation
Installation with Veams from local machine
veams install bp absolute/filepath/to/filterable-list-blueprint
Fields
filterable-list-blueprint.hbs
The partial is a wrapWith
partial. This means that you can access all properties and hashes via props
.
See Mangony Handlebars Helper - wrapWith for detailed instructions.
Settings
Parameter | Type | Default | Description |
---|---|---|---|
settings.filterableListBlueprintClasses | String | '' |
Modifier classes for component |
settings.filterableListBlueprintContextClass | String | 'default' |
Context class of component |
Content
Parameter | Type | Description |
---|---|---|
content.filterableListBlueprintField | String | Please add a description! |
SASS
Variables
There are multiple variables which you can change:
Variable | Value | Description |
---|---|---|
$filterable-list-blueprint-my-custom-var | 0px |
Please add a description! |
Modifier Classes
There are modifier classes you can add to c-filterable-list-blueprint
:
Modifier | Description |
---|---|
is-modifier | Please add a description! |
Templates
filterable-list-blueprint.hbs
<div class="c-filterable-list-blueprint{{#if settings.filterableListblueprintContextClass}}--{{settings.filterableListblueprintContextClass}}{{else}}--default{{/if}}{{#if settings.filterableListblueprintClasses}} {{settings.filterableListblueprintClasses}}{{/if}}"
data-css="c-filterable-list-blueprint"
data-js-module="filterable-list-blueprint">
{{#wrapWith "grid__container"}}
{{#wrapWith "grid__row"}}
{{#with content.filterForm}}
<form class="{{settings.formClasses}} {{settings.formJsOptions.classes.loading}}"
action="{{settings.formActionQA}}"
method="{{settings.formMethod}}"
data-js-item="{{settings.formJsItem}}">
{{#each content.fieldsets}}
{{> form__fieldset}}
{{/each}}
<!-- Results Info -->
<div class="filterable-list-blueprint__results-info" data-js-item="js-filterable-list-blueprint-results-info">
<p><strong><span data-js-item="js-filterable-list-blueprint__total-item-count"> </span> {{{settings.formContent.i18n.resultsText}}}</strong></p>
</div>
<!-- Loader -->
<div class="filterable-list-blueprint__results-loader" data-js-item="js-filterable-list-blueprint-results-loader">
<span class="filterable-list-blueprint__results-loader-box is-one"></span>
<span class="filterable-list-blueprint__results-loader-box is-two"></span>
<span class="filterable-list-blueprint__results-loader-box is-three"></span>
</div>
<!-- Template for Results -->
<ul class="filterable-list-blueprint__results-template">
<li class="filterable-list-blueprint__results-item" data-js-item="js-filterable-list-blueprint-results-template">
<div class="filterable-list-blueprint__results-item-image">
<picture class="c-picture--default lazyloaded" data-css="c-picture">
<img src="" class="picture__image lazyautosizes lazyloaded" alt="">
</picture>
</div>
<div class="filterable-list-blueprint__results-item-text-wrapper">
<em class="filterable-list-blueprint__results-item-meta">
<span class="filterable-list-blueprint__results-item-meta-category">{{settings.resultTemplateContent.category}}</span>
<span class="filterable-list-blueprint__results-item-meta-date">{{settings.resultTemplateContent.date}}</span>
</em>
<a href="" class="filterable-list-blueprint__results-item-link">{{settings.resultTemplateContent.title}}</a>
<p class="filterable-list-blueprint__results-item-description">{{settings.resultTemplateContent.description}}</p>
<a href="" class="filterable-list-blueprint__a11y-clickarea" aria-hidden="true" tabindex="-1"></a>
</div>
</li>
</ul>
<!-- Results -->
<ul class="filterable-list-blueprint__results" data-js-item="js-filterable-list-blueprint-results">
</ul>
<!-- Load More Button -->
<div class="filterable-list-blueprint__load-more-wrapper is-loading">
<button type="submit" class="filterable-list-blueprint__load-more" data-js-item="js-filterable-list-blueprint-load-more-btn">
<span class="filterable-list-blueprint__load-more-loader">
<span class="filterable-list-blueprint__load-more-loader-box is-one"></span>
<span class="filterable-list-blueprint__load-more-loader-box is-two"></span>
<span class="filterable-list-blueprint__load-more-loader-box is-three"></span>
</span>
<span class="filterable-list-blueprint__load-more-text">{{settings.loadMoreLabel}}</span></button>
</div>
</form>
{{/with}}
{{/wrapWith}}
{{/wrapWith}}
</div>
Data File
filterable-list-blueprint.hjson
{
"variations": {
"default": {
"docs": {
"variationName": "Default"
},
"settings": {
"filterableListContextClass": "default",
"filterableListClasses": ""
},
"content": {
"filterForm": {
"settings": {
"formClasses": "c-filterable-list-blueprint--form",
"formContextClass": "filterable-list",
"formJsOptions": {
"classes": {
"loading": "is-loading"
},
"submitOnChange": true
},
"formJsItem": "js-filterable-list-blueprint-filter-form",
"formAction": "//localhost:3000/api/connector/get",
"formActionQA": "//localhost:3000/mocks/connector/getFilterableListBlueprint.json",
"formMethod": "GET",
"formAjax": true,
"formContent": {
"i18n": {
"loadMore": "Mehr laden",
"noResultsText": "<strong>Es wurden keine Ergebnisse gefunden</strong>",
"resultsText": "Ergebnisse zum <span data-js-item=\"js-filterable-list-blueprint__total-item-tag-name\"></span> Forschen",
"showAll": "Alle anzeigen"
}
},
"resultTemplateContent": {
"category": "News",
"date": "2020-05-21",
"title": "Title Leuchtende Chamäleons",
"description": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam...",
"link": ""
},
"loadMoreLabel": "Show More"
},
"content": {
"fieldsets": [
{
"settings": {
"fieldsetClasses": "is-small",
"legendClasses": "is-col-mobile-p-12 is-hidden"
},
"content": {
"legend": "Radio Buttons",
"rows": [
{
"settings": {
"rowClasses": ""
},
"content": {
"cols": [
{
"settings": {
"radioClasses": "is-inline-block is-filternav",
"colClasses": "is-text-align-right",
"inputClasses": "is-radios",
"labelWrapperClasses": "",
"radioWrapperClasses": "",
"legendClasses": "",
"id": "category",
"required": false,
"typeOf": "radio"
},
"content": {
"label": "Zeige",
"radios": [
{
"settings": {
"wrapperClass": "is-radio-wrapper",
"inputClass": "",
"required": false,
"dataAttr": false,
"id": "tag-one",
"labelClass": "",
"name": "radio-group"
},
"content": {
"label": "Tag One"
}
},
{
"settings": {
"wrapperClass": "is-radio-wrapper",
"inputClass": "",
"required": false,
"dataAttr": false,
"id": "tag-two",
"labelClass": "",
"name": "radio-group"
},
"content": {
"label": "Tag Two"
}
},
{
"settings": {
"wrapperClass": "is-radio-wrapper",
"inputClass": "",
"required": false,
"dataAttr": false,
"id": "tag-three",
"labelClass": "",
"name": "radio-group"
},
"content": {
"label": "Tag Three"
}
},
{
"settings": {
"wrapperClass": "is-radio-wrapper",
"inputClass": "",
"required": false,
"dataAttr": false,
"id": "key-all",
"labelClass": "",
"name": "radio-group"
},
"content": {
"label": "All"
}
}
]
}
}
]
}
}
]
}
}
]
}
}
}
}
}
}
Styles
filterable-list-blueprint.scss
/* ===================================================
component: filterable-list-blueprint
=================================================== */
/* ---------------------------------------------------
Global Styles
--------------------------------------------------- */
[data-css="c-filterable-list-blueprint"] {
}
/* ---------------------------------------------------
Context: Default
--------------------------------------------------- */
.c-filterable-list-blueprint--default {
h2 {
@include headline-h2-styles();
}
p.title-description {
@include content-p-styles();
margin-bottom: 50px;
}
.c-filterable-list-blueprint--form {
position: relative;
min-height: 400px;
&.is-loading {
.filterable-list-blueprint__results-loader {
opacity: 1;
}
.filterable-list-blueprint__results {
height: 0;
opacity: 0;
overflow: hidden;
}
.filterable-list-blueprint__result-error {
height: 0;
opacity: 0;
}
}
&.is-success {
.filterable-list-blueprint__results-loader {
z-index: -1;
opacity: 0;
}
.filterable-list-blueprint__results {
height: auto;
opacity: 1;
}
.filterable-list-blueprint__result-error {
height: 0;
opacity: 0;
}
}
&.is-error {
.filter-course-finder__results-loader {
z-index: -1;
opacity: 0;
}
.filter-course-finder__results {
height: 0;
opacity: 0;
overflow: hidden;
}
.filter-course-finder__result-error {
height: auto;
opacity: 1;
}
}
}
.form__row {
border-bottom: 1px solid $color-gray;
padding-bottom: 2px;
margin-bottom: 25px;
.is-inline-block {
width: 100%;
@include bp($bp-tablet-p) {
width: auto;
}
}
}
.form__radio-input {
@extend %visuallyhidden;
@include hcm() {
border: 1px solid $color-white;
margin: 6px 0 0;
clip: auto;
position: relative;
float: left;
& ~ .form__radio-label {
margin-left: 28px;
padding-left: 0;
width: auto;
display: block;
&::before {
display: none !important;
}
}
}
&:checked {
& ~ .form__radio-label {
&::before {
box-shadow: inset 0 0 0 10px $color-green;
border: 0;
width: 28px;
height: 28px;
}
}
&.a11y-focus-key {
& ~ .form__radio-label {
&::before {
@include pseudo();
border: 2px dashed #800;
}
}
}
}
}
.form__radio-label {
position: relative;
display: inline-block;
padding: 2px 0 5px 42px;
font-family: $font-bold;
color: $color-dark;
font-size: 1.6rem;
line-height: (24/16);
letter-spacing: .3px;
&:hover {
cursor: pointer;
}
&::before {
content: "";
width: 24px;
height: 24px;
display: inline-block;
position: absolute;
top: 0;
left: 0;
background: $color-white;
border-radius: 50%;
border: 2px solid $color-green;
}
}
/*
Labels & Types
----------------------- */
.is-filternav {
// Radio
.form__radio-wrapper,
.form__label-wrapper{
display: block;
float: left;
width: 100%;
@include bp($bp-tablet-p) {
display: inline;
width: auto;
}
}
.form__radio-list {
width: 100%;
margin-left: 0;
margin-bottom: 0;
}
.form__radio-item {
display: inline-block;
margin-left: 0;
margin-right: 0;
margin-bottom: 0;
padding-left: 0;
&:before {
content: none;
}
&:last-of-type {
.form__radio-label {
border-right: none;
@include bp($bp-tablet-p) {
padding-right: 0;
}
}
}
.form__radio-label {
margin-bottom: 0;
}
}
.form__radio-legend {
color: $color-dark;
margin-right: 10px;
font-size: 1.7rem;
line-height: (20/17);
letter-spacing: .25px;
margin-bottom: 10px;
display: block;
text-align: left;
@include bp($bp-tablet-p) {
font-size: 1.8rem;
line-height: (21/18);
letter-spacing: .27px;
margin-bottom: 0;
text-align: right;
}
@include bp($bp-desktop-l) {
font-size: 2rem;
line-height: (24/20);
letter-spacing: .3px;
}
}
.form__radio-input {
@include hcm() {
@extend %visuallyhidden;
}
&:checked {
& ~ .form__radio-label {
background-color: $color-green;
color: $color-white;
@include bp($bp-tablet-p) {
background-color: transparent;
color: $color-dark;
}
@include print() {
text-decoration: underline;
}
@include hcm() {
text-decoration: underline;
}
}
}
&.a11y-focus-key {
& ~ .form__radio-label {
@include a11y-focus-key();
&::before {
display: none;
}
}
}
}
.form__radio-label {
background-color: $color-light;
font-family: $font-bold;
color: $color-green;
padding: 6px 12px;
font-size: 1.7rem;
line-height: (20/17);
letter-spacing: .25px;
margin-bottom: 5px;
@include bp($bp-tablet-p) {
background-color: transparent;
border-right: 1px solid $color-dark;
font-size: 1.8rem;
padding: 0 20px;
line-height: (21/18);
letter-spacing: .27px;
}
@include bp($bp-desktop-l) {
font-size: 2rem;
line-height: (24/20);
letter-spacing: .3px;
}
&::before {
display: none;
}
}
}
.filterable-list-blueprint__total-item-count {
display: inline-block;
}
.filterable-list-blueprint__results {
@include grid-column(12);
@include bp($bp-tablet-l) {
@include grid-column(10);
@include grid-push-h(1);
}
@include bp($bp-desktop-l) {
@include grid-column(8);
@include grid-push-h(2);
}
}
.filterable-list-blueprint__results-info {
@include headline-h3-styles();
font-family: $font-regular;
font-weight: 400;
padding-bottom: 20px;
p {
font-family: $font-regular;
font-weight: 400;
display: inline-block;
strong {
font-family: $font-bold;
}
}
}
.filterable-list-blueprint__results-item {
@include clearfix();
display: flex;
width: 100%;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 30px;
padding-bottom: 30px;
padding-left: 0;
border-bottom: 1px solid $color-gray-border;
position: relative;
opacity: 1;
transform: translate3d(0, 0, 0);
transition: opacity 2 * $animation-duration-std $animation-easing-std,
transform 2 * $animation-duration-std $animation-easing-std;
&::before {
content: none;
}
&:hover {
.filterable-list-blueprint__results-item-link {
color: $color-dark;
&::before {
@include sprites-icon-arrow-black();
transform: translateX(5px);
}
/*
MODIFIERS
----------------------- */
&.is-publication,
&.is-download {
&::before {
@include sprites-icon-download-black();
}
}
}
.filterable-list-blueprint__results-item-dates {
background-color: $color-white;
border: 1px solid $color-green;
}
.filterable-list-blueprint__results-item-date-month,
.filterable-list-blueprint__results-item-date-day,
.filterable-list-blueprint__results-item-date-connect {
color: $color-green;
}
.filterable-list-blueprint__results-item-image {
/*
MODIFIERS
----------------------- */
&.is-publication,
&.is-gallery,
&.is-video {
&::before {
opacity: 0;
}
&::after {
opacity: 1;
}
}
}
}
&:focus {
outline: none;
}
/*
MODIFIERS
----------------------- */
&:last-of-type {
border-bottom: none;
}
&.is-loading {
opacity: 0;
transform: translate3d(0, 50%, 0);
}
}
.filterable-list-blueprint__results-item-image {
display: none;
position: relative;
@include bp($bp-tablet-p) {
display: block;
width: 110px;
height: 110px;
flex: 0 0 110px;
margin-right: 30px;
}
@include bp($bp-tablet-l) {
width: 148px;
height: 148px;
flex: 0 0 148px;
}
@include bp($bp-desktop-l) {
width: 206px;
height: 206px;
flex: 0 0 206px;
margin-right: 40px;
}
&::before,
&::after {
@include pseudo();
position: absolute;
right: 0;
bottom: 0;
display: block;
z-index: 2;
transition: opacity $animation-duration-std $animation-easing-std;
}
&::before {
opacity: 1;
}
&::after {
opacity: 0;
}
}
.filterable-list-blueprint__results-item-text-wrapper {
display: block;
position: relative;
flex: 1 1;
}
.filterable-list-blueprint__results-item-meta {
display: block;
color: $color-gray;
font-size: 1.5rem;
line-height: (20/15);
letter-spacing: 1px;
text-transform: uppercase;
margin-bottom: 15px;
font-family: $font-regular;
}
.filterable-list-blueprint__results-item-meta-category + .filterable-list-blueprint__results-item-meta-date {
&::before {
@include pseudo();
position: relative;
display: inline-block;
vertical-align: middle;
width: 3px;
height: 3px;
background-color: $color-gray;
border-radius: 50%;
margin: -3px 7px 0 4px;
}
}
.filterable-list-blueprint__results-item-link {
color: $color-green;
font-family: $font-bold;
font-size: 1.6rem;
line-height: (24/16);
letter-spacing: .3px;
margin-bottom: 12px;
text-decoration: none;
display: block;
transition: color $animation-duration-std/2 $animation-easing-std;
position: relative;
padding-left: 25px;
@include print() {
padding-left: 0;
}
&:focus {
outline: none;
}
&:hover,
&:focus {
color: $color-dark;
&::before {
@include sprites-icon-arrow-black();
transform: translateX(5px);
}
}
&::before {
@include pseudo();
@include sprites-icon-arrow-green100();
position: absolute;
display: inline-block;
top: 5px;
left: 0;
margin-right: 10px;
vertical-align: unset;
transition: transform $animation-duration-std $animation-easing-std;
@include print() {
display: none;
}
}
}
.filterable-list-blueprint__results-item-description {
display: block;
font-size: 1.6rem;
line-height: (24/16);
letter-spacing: .25px;
color: $color-dark;
margin-bottom: 0;
a {
font-family: $font-bold;
font-weight: 700;
color: $color-green;
text-decoration: none;
transition: color $animation-duration-std $animation-easing-std;
&:focus {
outline: none;
}
&:hover,
&:focus {
color: $color-dark;
}
}
strong {
font-family: $font-bold;
}
}
.filterable-list-blueprint__a11y-clickarea {
@include clickarea();
z-index: 3;
}
.filterable-list-blueprint__tag-template {
display: none;
&+label {
display: none;
}
}
.filterable-list-blueprint__results-template {
display: none;
}
.filterable-list-blueprint__load-more-wrapper {
width: 100%;
height: auto;
display: block;
text-align: center;
position: relative;
clear: both;
opacity: 1;
transform: translate3d(0, 0, 0);
transition: opacity 2 * $animation-duration-std $animation-easing-std,
transform 2 * $animation-duration-std $animation-easing-std;
@include print() {
display: none;
}
&::before {
@include pseudo();
@include centering(v);
position: absolute;
width: 100%;
height: 1px;
border-top: 1px solid $color-gray-light;
margin-top: 1px;
}
&.is-loading {
height: 0;
overflow: hidden;
opacity: 0;
transform: translate3d(0, 50%, 0);
}
}
.filterable-list-blueprint__load-more {
@include reset-btn();
padding: 10px 30px;
min-width: 275px;
display: inline-block;
text-align: center;
background-color: $color-green;
cursor: pointer;
position: relative;
transition: background-color $animation-duration-std
$animation-easing-std;
@include bp($bp-desktop-l) {
padding: 18px 30px;
}
&:focus {
outline: none;
}
&:hover,
&.a11y-focus-key {
background-color: $color-white;
.filterable-list-blueprint__load-more-text {
color: $color-green;
&::before,
&::after {
background-color: $color-green;
}
}
&::before {
opacity: 1;
}
}
&::before {
@include pseudo();
position: absolute;
width: calc(100% - 2px);
height: calc(100% - 2px);
border: 1px solid $color-green;
display: block;
z-index: 2;
top: 0;
left: 0;
opacity: 0;
transition: opacity $animation-duration-std $animation-easing-std;
}
}
.filterable-list-blueprint__load-more-text {
color: $color-white;
font-size: 1.6rem;
line-height: (24/16);
letter-spacing: .3px;
font-family: $font-bold;
display: inline-block;
transition: color $animation-duration-std $animation-easing-std;
position: relative;
padding-left: 25px;
&::before {
@include pseudo();
width: 15px;
height: 3px;
display: block;
background-color: $color-white;
position: absolute;
left: 0;
top: 10px;
transition: background-color $animation-duration-std
$animation-easing-std;
}
&::after {
@include pseudo();
@include centering(v);
width: 3px;
height: 15px;
display: block;
background-color: $color-white;
position: absolute;
top: 11px;
left: 6px;
transition: background-color $animation-duration-std
$animation-easing-std;
}
}
.filterable-list-blueprint__results-loader {
@include centering(h);
position: absolute;
top: 200px;
display: flex;
width: 200px;
flex-direction: row;
background-color: $color-white;
height: 60px;
align-items: center;
justify-content: center;
pointer-events: none;
opacity: 0;
transition: opacity $animation-duration-std $animation-easing-std;
z-index: 100;
border: 1px solid $color-green;
}
.filterable-list-blueprint__results-loader-box {
display: block;
margin: 10px;
border: 1em solid $color-green;
opacity: 0;
/*
MODIFIERS
----------------------- */
&.is-one {
animation: boxAppear 2s linear infinite;
}
&.is-two {
animation: boxAppear 2s linear .3s infinite;
}
&.is-three {
animation: boxAppear 2s linear .62s infinite;
}
}
// LOAD MORE LOADER
.filterable-list-blueprint__load-more-loader {
@include centering(hv);
position: absolute;
display: flex;
flex-direction: row;
background-color: $color-green;
z-index: 2;
width: calc(100% - 2px);
height: 100%;
align-items: center;
justify-content: center;
pointer-events: none;
opacity: 0;
transition: opacity $animation-duration-std $animation-easing-std;
&.is-loading {
opacity: 1;
}
}
.filterable-list-blueprint__load-more-loader-box {
display: block;
margin: 10px;
border: 1em solid $color-white;
opacity: 0;
/*
MODIFIERS
----------------------- */
&.is-one {
animation: boxAppear 2s linear infinite;
}
&.is-two {
animation: boxAppear 2s linear .3s infinite;
}
&.is-three {
animation: boxAppear 2s linear .62s infinite;
}
}
}
Scripts
filterable-list-blueprint.js
/**
* Description of FilterableListBlueprint.
* Class properties and decorators are supported.
*
* @module FilterableListBlueprint
* @version v1.0.0
*
* @author your_name
*/
// Imports
import $ from 'jquery';
import Component from '@veams/component';
class FilterableListBlueprint extends Component {
/**
* Class Properties
*/
$el = $(this.el);
$filterForm = $(this.options.selectors.filterForm, this.el);
$lang = document.getElementsByTagName("HTML")[0].getAttribute("lang") ? document.getElementsByTagName("HTML")[0].getAttribute("lang").toUpperCase() : 'DE';
$data = '';
$totalResults = 0;
$lastResult = 0;
$resultPerPage = 10;
$resultPerPageCounter = this.$resultPerPage;
$counterResults = 1;
$resultTemplate = document.querySelector(this.options.selectors.resultTemplate);
/**
* Constructor for our class
*
* @see module.js
*
* @param {Object} obj - Object which is passed to our class
* @param {Object} obj.el - element which will be saved in this.el
* @param {Object} obj.options - options which will be passed in as JSON object
*/
constructor(obj) {
let options = {
selectors: {
filterForm: '[data-js-item="js-filterable-list-blueprint-filter-form"]',
resultTemplate: '[data-js-item="js-filterable-list-blueprint-results-template"]',
resultsList: '[data-js-item="js-filterable-list-blueprint-results"]',
totalResults: '[data-js-item="js-filterable-list-blueprint__total-item-count"]',
tagName: '[data-js-item="js-filterable-list-blueprint__total-item-tag-name"]',
btnLoadMore: '[data-js-item="js-filterable-list-blueprint-load-more-btn"]',
resultsLoader: '[data-js-item="js-filterable-list-blueprint-results-loader"]',
loadMoreLoader: '.filterable-list-blueprint__load-more-loader',
keyAll: 'key-all'
},
classes: {
isSuccess: 'is-success',
isError: 'is-error',
isLoading: 'is-loading'
}
};
super(obj, options);
}
/**
* Lifecycle Hooks
*/
willMount() {
console.log('Component FilterableListBlueprint will mount!');
}
didMount() {
console.log('Component FilterableListBlueprint mounted!');
}
/**
* @desc Debounce a function for a specific time
*/
bindEvents() {
this.options.filterForm = document.querySelector(
this.options.selectors.filterForm
);
this.options.resultsList = this.options.filterForm.querySelector(
this.options.selectors.resultsList
);
this.options.btnLoadMore = this.options.filterForm.querySelector(
this.options.selectors.btnLoadMore
);
this.options.tagName = this.options.filterForm.querySelector(
this.options.selectors.tagName
);
this.getAndFillMyResults();
// Click on LoadMore Button
this.options.btnLoadMore.addEventListener('click', (ev) => {
ev.preventDefault();
this.options.btnLoadMore.querySelector(this.options.selectors.loadMoreLoader).classList.add(this.options.classes.isLoading);
setTimeout(() => {
this.options.btnLoadMore.parentElement.classList.add(this.options.classes.isLoading);
this.$lastResult += 1;
this.$resultPerPageCounter = this.$resultPerPageCounter + this.$resultPerPage;
this.populateResults(false);
this.options.btnLoadMore.querySelector(this.options.selectors.loadMoreLoader).classList.remove(this.options.classes.isLoading);
}, 250);
});
}
/**
* @desc Get data from JSON and fill in function initializationForm
*/
getAndFillMyResults() {
const uri = this.$filterForm[0].action;
if (uri) {
this.getJSON(uri, (data) => {
const results = data;
if (typeof results !== 'undefined') this.initializationForm(results);
});
}
}
/**
* @desc Data initialization
* @param {String} data - Results from JSON file
*/
initializationForm(data) {
this.$data = data;
// Print Results List
this.populateResults(true);
}
/**
* @desc Checking is the first iteration or not
* @param {Boolean} firstIteration - Status of first iteration: yes (true) or no (false)
*/
populateResults(firstIteration) {
// Fill from URL
const urlOptions = decodeURI(window.location.href.split('?')[1]).split('&');
let keyFromUrl = '';
if (urlOptions[0] !== 'undefined') {
urlOptions.forEach((key) => {
const option = key.split('=');
if (option[0] === 'keyIdentifier' && option[1] !== this.options.selectors.keyAll) {
keyFromUrl = option[1];
}
if (this.options.filterForm.querySelector(`input[value="${option[1]}"]`)) {
this.options.filterForm.querySelector(`input[value="${option[1]}"]`).checked = true;
}
});
}
this.objectOrArrayToArray(this.$data[this.$lang]).forEach((item, index) => {
if (keyFromUrl) {
this.objectOrArrayToArray(item.tags).forEach((key) => {
if (keyFromUrl === key.identifier) {
this.createResultItem(item, index, firstIteration);
}
});
} else {
this.createResultItem(item, index, firstIteration);
}
});
this.options.tagName.innerHTML = this.options.filterForm.querySelector(`label[for="${this.options.selectors.keyAll}"]`).innerHTML;
this.options.filterForm.querySelector(this.options.selectors.totalResults).innerHTML = this.$totalResults;
this.clickOnFilterTag();
this.loadingProcess();
}
/**
* @desc Creating a single result
* @param {String} item - Result
* @param {Number} index - Index of item
* @param {Boolean} firstIteration - Status of first iteration: yes (true) or no (false)
*/
createResultItem(item, index, firstIteration) {
if (this.$counterResults <= this.$resultPerPageCounter && this.$lastResult <= index) {
const result = this.$resultTemplate.cloneNode(true);
const date = new Date(item.date).toLocaleString(`${this.$lang.toLowerCase()}-${this.$lang}`, {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
result.removeAttribute('data-js-item');
result.classList.remove('filterable-list-blueprint__results-template');
result.classList.add(this.options.classes.isLoading);
if (item.category && result.querySelector('.filterable-list-blueprint__results-item-meta-category')) {
result.querySelector('.filterable-list-blueprint__results-item-meta-category').innerHTML = this.arrayToString(item.category);
}
result.querySelector('.filterable-list-blueprint__results-item-meta-date').innerHTML = this.arrayToString(date);
result.querySelector('.filterable-list-blueprint__results-item-link').innerHTML = this.arrayToString(item.title);
result.querySelector('.filterable-list-blueprint__results-item-description').innerHTML = this.arrayToString(item.teaserText);
result.querySelector('.filterable-list-blueprint__results-item-link').setAttribute('href', item.link);
result.querySelector('.filterable-list-blueprint__a11y-clickarea').setAttribute('href', item.link);
if (item.teaserImage) {
result.querySelector('picture img').setAttribute('alt', item.teaserImage.alt);
result.querySelector('picture img').setAttribute('src', item.teaserImage.src);
result.querySelector('picture img').setAttribute('title', item.teaserImage.title ? item.teaserImage.title : '');
}
this.options.resultsList.appendChild(result);
this.$lastResult = index;
this.$counterResults += 1;
}
firstIteration ? this.$totalResults += 1 : '';
}
/**
* @desc Filter Tag click-related processes
*/
clickOnFilterTag() {
this.options.filterLabel = [].slice.call(
this.options.filterForm.querySelectorAll('label')
);
this.options.filterLabel.forEach((label) => {
label.addEventListener('click', (ev) => {
this.el.querySelector('form').classList.remove(this.options.classes.isSuccess);
this.el.querySelector('form').classList.add(this.options.classes.isLoading);
this.options.btnLoadMore.parentElement.classList.add(this.options.classes.isLoading);
this.$counterResults = 1;
this.$totalResults = 0;
this.$lastResult = 0;
this.$resultPerPageCounter = this.$resultPerPage;
this.options.btnLoadMore.parentElement.style.display = 'block';
// Empty
this.options.resultsList.innerHTML = '';
this.objectOrArrayToArray(this.$data[this.$lang]).forEach((item, index) => {
if (label.parentElement.firstElementChild.value === this.options.selectors.keyAll) {
this.createResultItem(item, index, true);
} else {
this.objectOrArrayToArray(item.tags).forEach((key) => {
if (label.parentElement.firstElementChild.value === key.identifier) {
this.createResultItem(item, index, true);
}
});
}
});
this.options.tagName.innerHTML = ev.target.innerHTML;
let output = `keyIdentifier=${label.parentElement.firstElementChild.value}`;
history.pushState(output, 'Search history', `${window.location.href.split('?')[0]}?${output}`);
this.options.filterForm.querySelector(this.options.selectors.totalResults).innerHTML = this.$totalResults;
this.loadingProcess();
});
});
}
/**
* @desc Processes related to data loading
*/
loadingProcess() {
setTimeout(() => {
const liElements = [].slice.call(this.options.resultsList.querySelectorAll('li'));
liElements.forEach((item) => {
item.classList.remove(this.options.classes.isLoading);
});
this.el.querySelector('form').classList.remove(this.options.classes.isLoading);
this.el.querySelector('form').classList.add(this.options.classes.isSuccess);
this.$totalResults <= this.$resultPerPageCounter ? this.options.btnLoadMore.parentElement.style.display = 'none' : '';
this.options.btnLoadMore.parentElement.classList.remove(this.options.classes.isLoading);
}, 250);
}
/**
* @desc Convert Array to String
* @param {Array} item - Array
* @return {String} - String
*
*/
arrayToString = (item) => {
item = item ? item.toString() : '';
return item;
}
/**
* @desc JSON request
* @param {Object} url - Link to JSON file
* @param {Object} callback - For results
* @param {Object} requestHeader - For request with Header like user, pass, type...
* @return {callback} - Return callback
*
*/
getJSON = (url, callback, requestHeader) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
if (requestHeader) {
requestHeader.forEach((element) => {
xhr.setRequestHeader(element.name, element.value);
});
}
xhr.onload = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
const res = xhr.responseText;
callback(JSON.parse(res));
} else {
console.error(xhr.statusText);
}
};
xhr.send(null);
};
/**
* @desc Convert Object or Array to Array
* @param {Object} item - Object or Array
* @return {Array} - Array
*
*/
objectOrArrayToArray = (item) => {
if (typeof item === 'undefined' || Array.isArray(item)) {
return item;
}
return [item];
};
/**
* @desc Render class
*/
render() {
return this;
}
}
export default FilterableListBlueprint;
HTML Output
Default
<div class="c-filterable-list-blueprint--default" data-css="c-filterable-list-blueprint" data-js-module="filterable-list-blueprint">
<div class="grid__container">
<div class="grid__row">
<form class="c-filterable-list-blueprint--form is-loading" action="//localhost:3000/mocks/connector/getFilterableListBlueprint.json" method="GET" data-js-item="js-filterable-list-blueprint-filter-form">
<fieldset class="form__fieldset is-small">
<legend class="form__legend is-col-mobile-p-12 is-hidden">
Radio Buttons </legend>
<div class="form__row">
<div class="form__col is-text-align-right">
<div class="form__radio is-inline-block is-filternav">
<div class="form__label-wrapper">
<strong class="form__radio-legend">Zeige</strong>
</div>
<div class="form__radio-wrapper">
<ul class="form__radio-list">
<li class="form__radio-item">
<input id="tag-one" name="radio-group" type="radio" value="tag-one" class="form__radio-input" />
<label role="button" for="tag-one" class="form__radio-label">
Tag One
</label>
</li>
<li class="form__radio-item">
<input id="tag-two" name="radio-group" type="radio" value="tag-two" class="form__radio-input" />
<label role="button" for="tag-two" class="form__radio-label">
Tag Two
</label>
</li>
<li class="form__radio-item">
<input id="tag-three" name="radio-group" type="radio" value="tag-three" class="form__radio-input" />
<label role="button" for="tag-three" class="form__radio-label">
Tag Three
</label>
</li>
<li class="form__radio-item">
<input id="key-all" name="radio-group" type="radio" value="key-all" class="form__radio-input" />
<label role="button" for="key-all" class="form__radio-label">
All
</label>
</li>
</ul>
</div>
</div>
</div>
</div>
</fieldset>
<!-- Results Info -->
<div class="filterable-list-blueprint__results-info" data-js-item="js-filterable-list-blueprint-results-info">
<p><strong><span data-js-item="js-filterable-list-blueprint__total-item-count"> </span> Ergebnisse zum <span data-js-item="js-filterable-list-blueprint__total-item-tag-name"></span> Forschen</strong></p>
</div>
<!-- Loader -->
<div class="filterable-list-blueprint__results-loader" data-js-item="js-filterable-list-blueprint-results-loader">
<span class="filterable-list-blueprint__results-loader-box is-one"></span>
<span class="filterable-list-blueprint__results-loader-box is-two"></span>
<span class="filterable-list-blueprint__results-loader-box is-three"></span>
</div>
<!-- Template for Results -->
<ul class="filterable-list-blueprint__results-template">
<li class="filterable-list-blueprint__results-item" data-js-item="js-filterable-list-blueprint-results-template">
<div class="filterable-list-blueprint__results-item-image">
<picture class="c-picture--default lazyloaded" data-css="c-picture">
<img src="" class="picture__image lazyautosizes lazyloaded" alt="">
</picture>
</div>
<div class="filterable-list-blueprint__results-item-text-wrapper">
<em class="filterable-list-blueprint__results-item-meta">
<span class="filterable-list-blueprint__results-item-meta-category">News</span>
<span class="filterable-list-blueprint__results-item-meta-date">2020-05-21</span>
</em>
<a href="" class="filterable-list-blueprint__results-item-link">Title Leuchtende Chamäleons</a>
<p class="filterable-list-blueprint__results-item-description">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam...</p>
<a href="" class="filterable-list-blueprint__a11y-clickarea" aria-hidden="true" tabindex="-1"></a>
</div>
</li>
</ul>
<!-- Results -->
<ul class="filterable-list-blueprint__results" data-js-item="js-filterable-list-blueprint-results">
</ul>
<!-- Load More Button -->
<div class="filterable-list-blueprint__load-more-wrapper is-loading">
<button type="submit" class="filterable-list-blueprint__load-more" data-js-item="js-filterable-list-blueprint-load-more-btn">
<span class="filterable-list-blueprint__load-more-loader">
<span class="filterable-list-blueprint__load-more-loader-box is-one"></span>
<span class="filterable-list-blueprint__load-more-loader-box is-two"></span>
<span class="filterable-list-blueprint__load-more-loader-box is-three"></span>
</span>
<span class="filterable-list-blueprint__load-more-text">Show More</span></button>
</div>
</form>
</div>
</div>
</div>