/** * * Lit Blog Post Element * * */ // Import litelement base class, html helper function & typescript decorators import { SkhemataBase, html, css, CSSResult, property } from '@skhemata/skhemata-base'; import { faLinkedin, faTwitter, faFacebook, } from '@fortawesome/free-brands-svg-icons'; import { faCalendarAlt, faTag, faFolder, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@riovir/wc-fontawesome'; // Import custom element directives import { stringToHtml } from '@skhemata/skhemata-base/dist/directives/stringToHtml.js'; import { customDateFormat } from '@skhemata/skhemata-base/dist/directives/customDateFormat.js'; import { decodeHtmlEntities } from '@skhemata/skhemata-base/dist/directives/decodeHtmlEntities.js'; import { SkhemataBlogPostStyle } from '../style/SkhemataBlogPostStyle'; import { SkhemataBlogSharedStyle } from '../style/SkhemataBlogSharedStyle'; import { translationEngDefault } from '../translation/SkhemataBlogPost/eng'; export class SkhemataBlogPost extends SkhemataBase { @property({ type: Object, attribute: 'api-wordpress' }) apiWordpress = { url: '' }; @property({ type: String, attribute: 'blog-page-path' }) blogPagePath = ''; @property({ type: Boolean, attribute: 'has-featured-image' }) hasFeaturedImage = false; // Component specific properties @property({ type: String }) slug?: string = ''; @property({ type: Object }) private blogPost: any; @property({ type: Object }) translationData = { eng: translationEngDefault, }; static get styles(): CSSResult[] { return [ ...super.styles, SkhemataBlogPostStyle, SkhemataBlogSharedStyle, css` .blog-category-item { display: inline; cursor: pointer; color: var(--skhemata-blog-link-color, var(--default-blue)); transition: all 0.3s ease 0s; } .blog-category-item:hover { color: rgb(28, 119, 185); } `, ]; } static get scopedElements() { return { 'fa-icon': FontAwesomeIcon, }; } constructor() { super(); window.onhashchange = () => { this.shadowRoot ?.getElementById(window.location.hash.slice(1)) ?.scrollIntoView(); }; } handleGoBack() { this.dispatchEvent( new CustomEvent('navigate', { detail: { slug: '', }, composed: true, bubbles: true, }) ); } /** * Implement `render` to define a template for your element. * Use JS template literals */ protected render() { return this.blogPost ? html`

${decodeHtmlEntities(this.blogPost.title)}

${this.hasFeaturedImage ? html`
${this.blogPost.featured_media.alt_text}
` : html``}
${stringToHtml(this.blogPost.content.replace('slack', 'slick'))}
${this.getStr('SkhemataBlogPost.categories')}: ${this.blogPost.categories ? this.blogPost.categories.map( (item: any, index: Number, arr: any) => html`
{ if (e.keyCode === '13') this.filterPostsBy(item.id, 'c'); }} > ${item.name}
${arr.length > 1 && arr.length - 1 !== index ? html`, ` : html``} ` ) : ''}
${this.getStr('SkhemataBlogPost.tags')}: ${this.blogPost.tags ? this.blogPost.tags.map( (item: any, index: Number, arr: any) => html`
{ if (e.keyCode === '13') this.filterPostsBy(item.id, 't'); }} > ${item.name}
${arr.length > 1 && arr.length - 1 !== index ? html`, ` : html``} ` ) : ''}
` : html``; } /** * Implement firstUpdated to perform one-time work after * the element’s template has been created. */ async firstUpdated() { await super.firstUpdated(); this.getPost(); } /** * Fetch a single post based on post id from WP REST API */ private getPost() { // Use fetch method to make a request // https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch fetch(`${this.apiWordpress.url}/posts?_embed&slug=${this.slug}`) .then(response => { const contentType = response.headers.get('Content-Type'); // 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 (Array.isArray(data) && data.length > 0) { const postData = data[0]; if (postData && postData.status === 'publish') { // Filter out all the categories of the post const filteredCategories = postData._embedded['wp:term'].filter( (term: any) => { if (term) { for (let index = 0; index < term.length; index += 1) { return term[index].taxonomy === 'category'; } } return true; } ); // Filter out all the tags of the post const filteredTags = postData._embedded['wp:term'].filter( (term: any) => { if (term) { for (let index = 0; index < term.length; index += 1) { return term[index].taxonomy === 'post_tag'; } } return true; } ); const featuredMedia = postData._embedded['wp:featuredmedia'] ? { source_url: postData._embedded['wp:featuredmedia'][0].source_url, alt_text: postData._embedded['wp:featuredmedia'][0].alt_text, title: postData._embedded['wp:featuredmedia'][0].title, } : { source_url: '', alt_text: '', title: '', }; // Pass data to Object to be used to bind data on the template this.blogPost = { id: postData.id, title: postData.title.rendered, content: postData.content.rendered.replaceAll( 'href="#', `href="${window.location.href}#` ), date: postData.date, author: { id: postData._embedded.author[0].id, name: postData._embedded.author[0].name, description: postData._embedded.author[0].description, avatar_url: postData._embedded.author[0].avatar_urls, }, categories: filteredCategories[0], excerpt: postData.excerpt.rendered, tags: filteredTags[0], featured_media: featuredMedia, }; this.setMetaTags(); } } }); } setMetaTags() { const metaDesc = document.querySelector("meta[name='description' i]"); const excerpt = this.blogPost.excerpt.replace(/<[^>]*>?/gm, ''); if (metaDesc) { metaDesc.setAttribute('content', excerpt); } else { const newMetaDesc = document.createElement('meta'); newMetaDesc.name = 'description'; newMetaDesc.content = excerpt; document.getElementsByTagName('head')[0].appendChild(newMetaDesc); } const title = document.querySelector('title'); if (title) { title.innerHTML = this.blogPost.title; } else { const newTitle = document.createElement('title'); newTitle.innerHTML = this.blogPost.title; document.getElementsByTagName('head')[0].appendChild(newTitle); } const metaKeywords = document.querySelector("meta[name='keywords' i]"); let keywordsText = ''; for (let i = 0; i < this.blogPost.tags.length; i += 1) { keywordsText += `${this.blogPost.tags[i].name}, `; } if (metaKeywords) { metaKeywords.setAttribute('content', keywordsText); } else { const newMetaKeywords = document.createElement('meta'); newMetaKeywords.name = 'keywords'; newMetaKeywords.content = keywordsText; document.getElementsByTagName('head')[0].appendChild(newMetaKeywords); } } filterPostsBy(id: string, queryId: string) { const params = new URLSearchParams(window.location.search); if (params.get(queryId) === id) { params.delete(queryId); } else { params.set(queryId, id); } window.history.pushState( {}, '', decodeURIComponent(`${this.blogPagePath}?${params.toString()}`) ); window.scrollTo({ top: 0 }); window.dispatchEvent(new Event('popstate')); } }