@skhemata/skhemata-faq
Version:
Skhemata FAQ Web Component. This web component provides website FAQ functionality with question and answer style of FAQ.
340 lines (339 loc) • 12.8 kB
JavaScript
/**
*
* Lit Faq List Element
*
*/
import { __decorate } from "tslib";
// Import litelement base class, html helper function & typescript decorators
import { SkhemataBase, property, html, css } from '@skhemata/skhemata-base';
// Import custom font awesome dependencies
import { faCalendarAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@riovir/wc-fontawesome';
// Import element dependencies
import './SkhemataFaqSearch';
import { decodeHtmlEntities } from '@skhemata/skhemata-base/dist/directives/decodeHtmlEntities.js';
import { translationEngDefault } from '../translation/SkhemataFaqList/eng';
import { SkhemataFaqListStyles } from '../style/SkhemataFaqListStyle';
import { SkhemataFaqSharedStyles } from '../style/SkhemataFaqSharedStyle';
export class SkhemataFaqList extends SkhemataBase {
constructor() {
// Always call super() first
super();
this.apiWordpress = {
url: ''
};
this.postsPerPage = 20;
this.pagerType = "infinite";
this.currentPage = 1;
this.faqPagePath = '';
this.faqPosts = [];
this.totalPages = 0;
this.totalCount = 0;
this.maxLoadCount = 0;
this.count = 1;
this.translationData = {
eng: translationEngDefault
};
this.formatDate = (date) => {
const dateObj = new Date(date);
const month = new Intl.DateTimeFormat('en-US', { month: 'short' }).format(dateObj);
return `${month} ${dateObj.getDate()} ${dateObj.getFullYear()}`;
};
window.addEventListener('popstate', () => {
if (this.pagerType === "traditional") {
this.loadPostPage();
}
else {
this.getPosts();
}
}, false);
}
static get styles() {
return [
...super.styles,
SkhemataFaqListStyles,
SkhemataFaqSharedStyles,
css `
.traditional-pager {
text-align: center;
}
`,
];
}
static get scopedElements() {
return {
'fa-icon': FontAwesomeIcon,
};
}
willUpdate(changedProperties) {
if (changedProperties.has('apiWordpress')) {
this.getPosts();
}
if (changedProperties.has('postsPerPage')) {
this.getPosts();
}
if (changedProperties.has('pagerType')) {
this.getPosts();
}
super.willUpdate(changedProperties);
}
/**
* Implement `render` to define a template for your element.
* Use JS template literals
*/
render() {
let previous = html ``;
let next = html ``;
let previousPages = html ``;
let nextPages = html ``;
let count = 1;
const params = new URLSearchParams(window.location.search);
let page = 1;
const leadingTrailingCount = 3;
const pParam = params.get('p');
const pageParam = parseInt(pParam, 10);
if (pageParam != null && !Number.isNaN(pageParam)) {
page = pageParam;
}
previous = html `<button @click="${() => this.setPageNumber(1)}" class="button" > First </button>
<button @click="${() => this.setPageNumber(page - 1)}" class="button" > Previous </button>`;
if (page <= 1) {
previous = html ``;
}
next = html `<button @click="${() => this.setPageNumber(page + 1)}" class="button" > Next </button>
<button @click="${() => this.setPageNumber(this.totalPages)}" class="button" > Last </button>`;
if (page >= this.totalPages) {
next = html ``;
}
for (let index = page; index > 1; index -= 1) {
if (count > leadingTrailingCount) {
break;
}
previousPages = html `<button @click="${(event) => this.goToButtonPage(event)}" page-value="${page - count}" class="button" >${page - count}</button>${previousPages}`;
count += 1;
}
count = 1;
for (let index = page; index < this.totalPages; index += 1) {
if (count > leadingTrailingCount) {
break;
}
nextPages = html `${nextPages}<button @click="${(event) => this.goToButtonPage(event)}" page-value="${page + count}" class="button" >${page + count}</button>`;
count += 1;
}
let pagination = html ``;
if (this.totalPages > 1) {
pagination = html `
<div class="traditional-pager">
${previous}${previousPages}<button @click="" class="button" ><b>${page}</b></button>${nextPages}${next}
</div>`;
}
return html `
<div class="faq-list block">
${this.faqPosts.map((faq) => html `
<div class="faq-entry" @click=${() => {
this.navigateToPost(faq.slug);
}}>
<div class="article-date">
<fa-icon .icon=${faCalendarAlt}></fa-icon> ${this.formatDate(faq.date)}
</div>
<a class="is-size-4 has-text-weight-bold" @click=${() => {
this.navigateToPost(faq.slug);
}}>
${decodeHtmlEntities(faq.title.rendered)}
</a>
</div>
`)}
</div>
${(this.pagerType === "traditional") ?
pagination :
html `<div class="load-more-button block">
${(this.count < this.maxLoadCount) ?
html `<button @click="${this.loadMorePosts}" class="button">${this.getStr('SkhemataFaqList.showMoreButton')}</button>` : ``}
</div>`}
`;
}
navigateToPost(slug) {
this.dispatchEvent(new CustomEvent('navigate', {
detail: {
slug
},
composed: true,
bubbles: true
}));
window.dispatchEvent(new CustomEvent('clearfaqsearch'));
}
/**
* Implement firstUpdated to perform one-time work after
* the element’s template has been created.
*/
async firstUpdated() {
await super.firstUpdated();
this.getPosts();
}
/**
* Fetch Posts from WP REST API
*/
getPosts() {
// Use fetch method to make a request
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
const params = new URLSearchParams(window.location.search);
const search = params.get('s');
const category = params.get('c');
let searchParams = '';
let categoryParams = '';
const orderbyParam = `&orderby=relevance`;
if (search && search.length > 3) {
searchParams = `&search=${search}${orderbyParam}`;
}
if (category) {
categoryParams = `&ufaq-category=${category}`;
}
fetch(`${this.apiWordpress.url}/ufaq?${searchParams}${categoryParams}&per_page=${this.postsPerPage}`)
.then(response => {
this.totalPages = Number(response.headers.get('X-WP-TotalPages'));
this.totalCount = Number(response.headers.get('X-WP-Total'));
const contentType = response.headers.get('Content-Type');
this.maxLoadCount = Math.ceil(this.totalCount / 10);
// Check if response header content type is json
if (contentType && contentType.includes('application/json')) {
return response.json();
}
// Throw error if above condition isn't met
throw new TypeError('The format is not JSON.');
})
.then(data => {
if (typeof data !== 'undefined') {
// Loop through data
// data.forEach((element: any) => {
// // this.formatCategories(element);
// });
this.faqPosts = data;
}
});
}
/**
* Load more posts event handler
*/
loadMorePosts() {
this.count += 1;
const params = new URLSearchParams(window.location.search);
const search = params.get('s');
const category = params.get('c');
let searchParams = '';
let categoryParams = '';
const orderbyParam = `&orderby=relevance`;
if (search && search.length > 3) {
searchParams = `&search=${search}${orderbyParam}`;
}
if (category) {
categoryParams = `&ufaq-category=${category}`;
}
fetch(`${this.apiWordpress.url}/ufaq?page=${this.count}${searchParams}${categoryParams}&per_page=${this.postsPerPage}`)
.then(response => response.json())
.then(posts => {
for (const post of posts) {
// this.formatCategories(posts[index]);
// Use spread operator for dynamic re-rendering on template
this.faqPosts = [...this.faqPosts, post];
}
});
}
goToButtonPage(event) {
let page = 1;
const buttonValue = event.target.attributes["page-value"].value;
if (buttonValue != null) {
page = parseInt(buttonValue, 10);
}
this.setPageNumber(page);
}
setPageNumber(page) {
let setPage = page;
if (setPage < 1) {
setPage = 1;
}
if (setPage > this.totalPages) {
setPage = this.totalPages;
}
const params = new URLSearchParams(window.location.search);
params.set('p', setPage);
this.currentPage = setPage;
window.history.pushState({}, '', `/${this.faqPagePath}?${params.toString()}`);
window.dispatchEvent(new Event('popstate'));
}
loadPostPage() {
const params = new URLSearchParams(window.location.search);
const page = params.get('p');
const search = params.get('s');
const category = params.get('c');
let searchParams = '';
let categoryParams = '';
const orderbyParam = `&orderby=relevance`;
if (search && search.length > 3) {
searchParams = `&search=${search}${orderbyParam}`;
}
if (category) {
categoryParams = `&ufaq-category=${category}`;
}
fetch(`${this.apiWordpress.url}/ufaq?page=${page}${searchParams}${categoryParams}&per_page=${this.postsPerPage}`)
.then(response => {
if (response.status === 200) {
this.totalPages = Number(response.headers.get('X-WP-TotalPages'));
this.totalCount = Number(response.headers.get('X-WP-Total'));
const contentType = response.headers.get('Content-Type');
this.maxLoadCount = Math.ceil(this.totalCount / 10);
// Check if response header content type is json
if (contentType && contentType.includes('application/json')) {
return response.json();
}
// Throw error if above condition isn't met
throw new TypeError('The format is not JSON.');
}
else {
return response.json();
}
})
.then(response => {
// Set page to 1 if invalid page number.
if (response.code && response.code === "rest_post_invalid_page_number") {
this.setPageNumber(1);
}
else if (!response.code && typeof response !== 'undefined') {
this.faqPosts = response;
}
});
}
}
__decorate([
property({ type: Object, attribute: 'api-wordpress' })
], SkhemataFaqList.prototype, "apiWordpress", void 0);
__decorate([
property({ type: Number, attribute: 'posts-per-page' })
], SkhemataFaqList.prototype, "postsPerPage", void 0);
__decorate([
property({ type: String, attribute: 'pager-type' })
], SkhemataFaqList.prototype, "pagerType", void 0);
__decorate([
property({ type: Number })
], SkhemataFaqList.prototype, "currentPage", void 0);
__decorate([
property({ type: String, attribute: 'faq-page-path' })
], SkhemataFaqList.prototype, "faqPagePath", void 0);
__decorate([
property({ type: Array })
], SkhemataFaqList.prototype, "faqPosts", void 0);
__decorate([
property({ type: Number })
], SkhemataFaqList.prototype, "totalPages", void 0);
__decorate([
property({ type: Number })
], SkhemataFaqList.prototype, "totalCount", void 0);
__decorate([
property({ type: Number })
], SkhemataFaqList.prototype, "maxLoadCount", void 0);
__decorate([
property({ type: Number })
], SkhemataFaqList.prototype, "count", void 0);
__decorate([
property({ type: Object })
], SkhemataFaqList.prototype, "translationData", void 0);
//# sourceMappingURL=SkhemataFaqList.js.map