<link media="all" rel="stylesheet" href="/assets/themes/default/css/events-calendar.css?cb=">

<div class="calendar-events collapsed" data-module="calendarEvents" data-endpoint="/components/preview/events-calendar-api-results" data-event-days-endpoint="/data/eventdays.json">

    <button class="calendar-events__toggle">+</button>
    <h3 class="calendar-events__title"></h3>
    <div class="calendar-events__calendar">
        <div class="calendar-events__calendar-row" style="display: none">
            <div class="calendar-events__calendar-item">Sun</div>
            <div class="calendar-events__calendar-item">Mon</div>
            <div class="calendar-events__calendar-item">Tue</div>
            <div class="calendar-events__calendar-item">Wed</div>
            <div class="calendar-events__calendar-item">Thu</div>
            <div class="calendar-events__calendar-item">Fri</div>
            <div class="calendar-events__calendar-item">Sat</div>
        </div>
        <div class="calendar-body">
        </div>
    </div>
    <div class="calendar-events__calendar-nav">
        <button class="calendar-events__btn-prev"></button>

        <button class="calendar-events__btn-next"></button>
    </div>

    <div class="event-cards__holder" data-url="">
    </div>
</div>
{{#if firstInstance}}
<link media="all" rel="stylesheet" href="/assets/themes/{{theme}}/css/events-calendar.css?cb={{cacheBuster}}">
{{/if}}

<div class="calendar-events collapsed" data-module="calendarEvents" data-endpoint="{{endpoint}}" data-event-days-endpoint="{{eventDaysEndpoint}}">

    <button class="calendar-events__toggle">+</button>
    <h3 class="calendar-events__title"></h3>
    <div class="calendar-events__calendar">
        <div class="calendar-events__calendar-row" style="display: none">
            <div class="calendar-events__calendar-item">Sun</div>
            <div class="calendar-events__calendar-item">Mon</div>
            <div class="calendar-events__calendar-item">Tue</div>
            <div class="calendar-events__calendar-item">Wed</div>
            <div class="calendar-events__calendar-item">Thu</div>
            <div class="calendar-events__calendar-item">Fri</div>
            <div class="calendar-events__calendar-item">Sat</div>
        </div>
        <div class="calendar-body">
        </div>
    </div>
    <div class="calendar-events__calendar-nav">
        <button class="calendar-events__btn-prev"></button>

        <button class="calendar-events__btn-next"></button>
    </div>

    <div class="event-cards__holder" data-url="{{dataUrl}}">
    </div>
</div>
{
  "theme": "default",
  "firstInstance": true,
  "endpoint": "/components/preview/events-calendar-api-results",
  "eventDaysEndpoint": "/data/eventdays.json"
}
  • Content:
    export class EventsCalendar {
        constructor(container) {
    
            this.today = new Date();
    
            this.currentDay = this.today.getDate();
            this.currentMonth = this.today.getMonth();
            this.currentYear = this.today.getFullYear();
            this.selectedDay = null;
            this.selectedMonth = null;
            this.selectedYear = null;
            this.container = container;
            this.monthAndYear = container.querySelector('.calendar-events__title');
            this.eventsListingHolder = container.querySelector('.event-cards__holder');
            const toggleBtn = container.querySelector('.calendar-events__toggle');
    
            this.next = container.querySelector('.calendar-events__btn-next');
            this.previous = container.querySelector('.calendar-events__btn-prev');
    
            this.showCalendar();
    
            this.next.addEventListener('click', () => {
                this.currentYear = (this.currentMonth === 11) ? this.currentYear + 1 : this.currentYear;
                this.currentMonth = (this.currentMonth + 1) % 12;
                this.eventsListingHolder.innerHTML = '';
                this.showCalendar();
            });
    
            this.previous.addEventListener('click', () => {
                this.currentYear = (this.currentMonth === 0) ? this.currentYear - 1 : this.currentYear;
                this.currentMonth = (this.currentMonth === 0) ? 11 : this.currentMonth - 1;
                this.eventsListingHolder.innerHTML = '';
                this.showCalendar();
            });
    
            toggleBtn.addEventListener('click', () => {
                container.classList.toggle('collapsed');
    
                if (container.classList.contains('collapsed')) {
                    toggleBtn.innerHTML = '+';
                    this.showCalendar();
                } else {
                    toggleBtn.innerHTML = '-';
                }
            });
        }
    
        showCalendar() {
            const month = this.currentMonth;
            const year = this.currentYear;
            const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
            const firstDay = (new Date(year, month)).getDay();
            const daysInMonth = 32 - new Date(year, month, 32).getDate();
    
            const tbl = document.querySelector('.calendar-body'); // body of the calendar
    
            // clearing all previous cells
            tbl.innerHTML = '';
    
            // filing data about month and in the page via DOM.
            this.monthAndYear.innerHTML = `${months[month]} ${year}`;
            if (month === 11) {
                this.next.innerHTML = `See ${months[0]} ${year + 1}`;
                this.previous.innerHTML = `See ${months[month - 1]} ${year}`;
            } else if (month === 0) {
                this.next.innerHTML = `See ${months[month + 1]} ${year}`;
                this.previous.innerHTML = `See ${months[11]} ${year - 1}`;
            } else {
                this.next.innerHTML = `See ${months[month + 1]} ${year}`;
                this.previous.innerHTML = `See ${months[month - 1]} ${year}`;
            }
    
            if (this.currentMonth === this.today.getMonth() && this.currentYear === this.today.getFullYear()) {
                this.previous.setAttribute('style', 'display:none;');
            } else if (this.currentMonth > this.today.getMonth() && this.currentYear >= this.today.getFullYear()) {
                this.previous.setAttribute('style', 'display:inline-none;');
            }
    
            // creating all cells
            let date = 1;
            for (let i = 0; i < 6; i++) {
                // creates a table row
                const row = document.createElement('div');
                row.classList.add('calendar-events__calendar-row');
                const daysOfTheWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
    
                // creating individual cells, filing them up with data.
                for (let j = 0; j < 7; j++) {
                    if (i === 0 && j < firstDay) {
    
                        const cellHolder = document.createElement('div');
                        cellHolder.classList.add('calendar-item-holder');
    
                        const cell = document.createElement('div');
                        cell.classList.add('calendar-events__calendar-item');
                        cell.classList.add('calendar-events__calendar-item--empty');
    
                        const dayOfWeek = document.createElement('div');
                        dayOfWeek.classList.add('calendar-weekday');
                        dayOfWeek.innerHTML = daysOfTheWeek[j];
                        cell.appendChild(dayOfWeek);
    
                        const cellText = document.createTextNode('');
                        cell.appendChild(cellText);
                        cellHolder.appendChild(cell);
                        row.appendChild(cellHolder);
                    } else if (date > daysInMonth) {
                        break;
                    } else {
                        const cellHolder = document.createElement('div');
                        cellHolder.classList.add('calendar-item-holder');
    
                        const cell = document.createElement('div');
                        cell.classList.add('calendar-events__calendar-item');
                        const cellText = document.createTextNode(date);
                        if (date === this.today.getDate() && year === this.today.getFullYear() && month === this.today.getMonth()) {
                            // highlight today's date
                            cell.classList.add('calendar-events__calendar-item--today');
                        }
    
                        if (date === this.currentDay && year === this.currentYear && month === this.currentMonth) {
                            row.classList.add('current-row');
                        }
    
                        if (date === this.selectedDay && year === this.selectedYear && month === this.selectedMonth) {
                            cell.classList.add('calendar-events__calendar-item--active');
                        }
    
                        const dayOfWeek = document.createElement('div');
                        dayOfWeek.classList.add('calendar-weekday');
                        dayOfWeek.innerHTML = daysOfTheWeek[j];
                        cell.appendChild(dayOfWeek);
                        cell.appendChild(cellText);
                        cellHolder.appendChild(cell);
                        row.appendChild(cellHolder);
    
                        const selectedMonth = this.currentMonth + 1;
                        const selectedYear = this.currentYear;
                        const dataAttr = `${selectedYear}-${selectedMonth}-${date}`;
    
                        cell.dataset.date = dataAttr;
    
                        date++;
                    }
                }
    
                tbl.appendChild(row); // appending each row into calendar body.
            }
    
            this.loadEventDays();
    
            const cellItem = document.querySelectorAll('.calendar-events__calendar-item');
    
            cellItem.forEach((e) => {
                e.addEventListener('click', () => {
    
                    document.querySelectorAll('.calendar-events__calendar-item').forEach((crnt) => {
                        crnt.classList.remove('calendar-events__calendar-item--active');
                    });
    
                    e.classList.add('calendar-events__calendar-item--active');
                    this.eventsListingHolder.innerHTML = '';
                    const clickedEventDate = e.dataset.date;
                    const selectedDate = new Date(clickedEventDate);
                    this.selectedMonth = selectedDate.getMonth();
                    this.selectedYear = selectedDate.getFullYear();
                    this.selectedDay = selectedDate.getDate();
                    this.loadEvents(clickedEventDate);
                });
            });
        }
    
        loadEventDays() {
            const queryStringPrefix = this.container.dataset.eventDaysEndpoint.includes('?') ? '&' : '?';
            const fetchDataUrl = `${this.container.dataset.eventDaysEndpoint}${queryStringPrefix}month=${this.currentMonth + 1}&year=${this.currentYear}`;
            fetch(fetchDataUrl, { credentials: 'same-origin' })
                .then((resolve) => {
                    if (resolve.ok) {
                        return resolve.text();
                    }
    
                    throw new Error(resolve.status);
                })
                .then((res) => {
                    const dates = JSON.parse(res);
                    dates.forEach((date) => {
                        const calendarItem = this.container.querySelector(`.calendar-events__calendar-item[data-date='${date}']`);
                        if (calendarItem) {
                            calendarItem.classList.add('calendar-events__calendar-item--has-event');
                        }
                    });
                })
                .catch((reject) => {
                    console.error('error', reject);
                });
        }
    
        loadEvents(eventDate) {
            let fetchDataUrl = this.container.dataset.endpoint;
            fetchDataUrl += fetchDataUrl.includes('?') ? '&' : '?';
            fetchDataUrl += `eventDate=${eventDate}`;
    
            fetch(fetchDataUrl, { credentials: 'same-origin' })
                .then((resolve) => {
                    if (resolve.ok) {
                        return resolve.text();
                    }
    
                    throw new Error(resolve.status);
                })
                .then((res) => {
                    const newGrid = new DOMParser().parseFromString(res, 'text/html');
                    const gridList = newGrid.querySelectorAll('.api-events');
    
                    gridList.forEach((grid) => {
                        this.eventsListingHolder.innerHTML = grid.innerHTML;
                    });
    
                    const alsoHappeningLinks = this.container.querySelectorAll('.event-card__repeated-date');
                    alsoHappeningLinks.forEach((alsoHappeningLink) => {
                        alsoHappeningLink.addEventListener('click', (e) => {
                            e.preventDefault();
                            const date = alsoHappeningLink.dataset.eventDate;
                            const alsoHappeningDate = new Date(date);
                            this.selectedMonth = alsoHappeningDate.getMonth();
                            this.selectedYear = alsoHappeningDate.getFullYear();
                            this.selectedDay = alsoHappeningDate.getDate();
                            this.showCalendar();
                            this.loadEvents(date);
                        });
                    });
                })
                .catch((reject) => {
                    console.error('error', reject);
                });
        }
    }
    
    export default (module) => new EventsCalendar(module);
    
  • URL: /components/raw/events-calendar/events-calendar.js
  • Filesystem Path: source/patterns/03-components/events/events-calendar/events-calendar.js
  • Size: 10.3 KB
  • Content:
    @import 'source/scss/01-settings/_import';
    @import 'source/scss/02-tools/_import';
    
    .calendar-events {
        $this: &;
        display: block;
        position: relative;
        width: 100%;
    
        &__title {
            @extend %heading02;
            margin: rem(20);
        }
    
        &__toggle {
            background: transparent;
            border: 0;
            font-size: 30px;
            line-height: 1rem;
            margin: 0;
            outline: none;
            padding: 0;
            position: absolute;
            right: rem(20);
            top: rem(80);
    
            @include breakpoint(medium) {
                top: rem(90);
            }
    
            @include breakpoint(large) {
                font-size: 60px;
                right: rem(20);
                top: rem(95);
            }
        }
    
        &__calendar {
            display: block;
            margin: rem(20) auto;
            width: 100%;
    
            @include breakpoint(medium) {
                width: 100%;
            }
    
            @include breakpoint(large) {
                width: 100%;
            }
        }
    
        &__calendar-row {
            clear: both;
            display: block;
            margin: rem(20) 0;
            width: 90%;
    
            &.current-row {
                display: block;
            }
        }
    
        &.collapsed {
            #{$this}__calendar-nav {
                display: none;
            }
    
            #{$this}__calendar-row {
                display: none;
    
                &.current-row {
                    display: block;
                }
            }
        }
    
        &__calendar-item {
            background-color: $color-calendar-bg;
            border: 1px solid $color-calendar-border;
            border-radius: 100%;
            color: $color-calendar-text;
            display: inline-block;
            font-size: rem(15);
            font-weight: bold;
            height: rem(46);
            line-height: rem(16);
            position: relative;
            text-align: center;
            transition: background-color .3s;
            vertical-align: top;
            width: rem(46);
    
            @include breakpoint(medium) {
                font-size: rem(25);
                font-weight: normal;
                height: rem(70);
                width: rem(70);
            }
    
            &--has-event {
                background-color: $color-calendar-bg-has-event;
                color: $color-calendar-has-event;
                cursor: pointer;
    
                &:hover {
                    background-color: $color-calendar-bg-hover;
                    color: $color-calendar-hover;
                }
            }
    
            &--active {
                background-color: $color-calendar-bg-active;
                color: $color-calendar-active;
            }
    
            &--today {
                background-color: $color-calendar-bg-today;
                color: $color-calendar-today;
            }
    
            &--empty {
                opacity: 0;
            }
        }
    
        &__calendar-nav {
            display: block;
            width: 100%;
    
            &::after {
                clear: both;
                content: '';
                display: block;
            }
        }
    
        &__btn-prev {
            float: left;
        }
    
        &__btn-next {
            float: right;
        }
    }
    
    .calendar-item-holder {
        display: inline-block;
        margin: 0 1%;
        text-align: center;
        width: 12%;
    }
    
    .current-month__title {
        @extend %heading02;
        display: block;
        margin-bottom: rem(20px);
    }
    
    .calendar-weekday {
        font-size: rem(10);
        line-height: 1rem;
        margin-top: rem(5);
        padding-bottom: 0;
        text-align: center;
    
        @include breakpoint(medium) {
            font-size: rem(13);
            line-height: 1rem;
            margin-top: rem(11);
            padding-bottom: rem(6);
        }
    
        @include breakpoint(large) {
            font-size: 13px;
            line-height: 1rem;
            margin-top: rem(11);
            padding-bottom: rem(6);
        }
    }
    
    .calendar-body {
        display: block;
        width: 100%;
    }
    
    .event-cards__holder {
        border-top: 1px solid;
        display: block;
        padding: rem(20) 0;
        width: 100%;
    }
    
    .event-card {
        &__holder {
            background-color: $color-events-card-bg;
            margin: rem(20);
        }
    
        &__timings {
            @extend %p--strong;
            padding: rem(20);
        }
    
        &__title {
            @extend %heading02;
            padding: 0 rem(20);
        }
    
        &__description {
            @extend %p--body;
            line-height: 1.7rem;
            padding: rem(20);
        }
    
        &__location {
            @extend %p--strong;
            padding: rem(20) rem(20) 0;
        }
    
        &__price {
            @extend %p--strong;
            padding: rem(20);
        }
    
        &__cta {
            padding: rem(20);
        }
    
        &__repeated {
            @extend %p--small;
            padding: rem(20);
        }
    
        &__repeated-date {
            display: block;
            padding: 0 rem(20) rem(20);
        }
    }
    
    .api-holder__no-results {
        @extend %p--lead;
    }
    
  • URL: /components/raw/events-calendar/events-calendar.scss
  • Filesystem Path: source/patterns/03-components/events/events-calendar/events-calendar.scss
  • Size: 4.6 KB

No notes defined.