| | |
| | | this.a11y = window.jvbA11y; |
| | | this.error = window.jvbError; |
| | | this.cache = new window.jvbCache('feed'); |
| | | this.templates = window.jvbTemplates; |
| | | |
| | | this.config = { |
| | | source: '', |
| | |
| | | } |
| | | init() { |
| | | this.initElements(); |
| | | this.defineTemplates(); |
| | | this.initListeners(); |
| | | this.initFilters(); |
| | | |
| | |
| | | buttons: { |
| | | loadMore: 'button.load-more', |
| | | remove: '.remove-term', |
| | | clearFilters: 'button.clear-filters' |
| | | clearFilters: 'button.clear-filters', |
| | | refresh: 'button[data-action="refresh"]' |
| | | } |
| | | }; |
| | | this.ui = window.uiFromSelectors(this.selectors, this.container); |
| | | this.ui.buttons.refresh = document.querySelector(this.selectors.buttons.refresh); |
| | | |
| | | //Add content and taxonomies |
| | | this.ui.content = this.ui.filters.container.querySelectorAll('[name="content"]'); |
| | |
| | | if (remove) { |
| | | this.removeSelectedTerm(remove); |
| | | } |
| | | |
| | | let refresh = window.targetCheck(e, this.selectors.buttons.refresh); |
| | | if (refresh) { |
| | | this.store.clearCache(); |
| | | this.store.fetch(); |
| | | } |
| | | } |
| | | |
| | | nextPage() { |
| | |
| | | const term = this.selector.store.get(termId); |
| | | if (!term) return; |
| | | if (this.ui.selected.querySelector(`[data-id="${termId}"]`)) return; |
| | | let icon = this.getTaxonomyIcon(term.taxonomy); |
| | | let template = window.getTemplate('feedTerm'); |
| | | if (!template) return; |
| | | let [iconEl,span] = [template.querySelector('.icon'), template.querySelector('span')]; |
| | | if (!iconEl || !span) return; |
| | | template.dataset.id = term.id; |
| | | template.dataset.taxonomy = term.taxonomy; |
| | | iconEl.className = `icon icon-${icon}`; |
| | | span.textContent = term.name; |
| | | |
| | | this.ui.selected.append(template); |
| | | term.icon = this.getTaxonomyIcon(term.taxonomy); |
| | | this.ui.selected.append(this.templates.create('feedTerm', term)); |
| | | } |
| | | |
| | | processCachedFilters() { |
| | |
| | | this.showEmptyState(); |
| | | this.a11y.announceItems(0, this.isFirstPage()); |
| | | } else { |
| | | const fragment = document.createDocumentFragment(); |
| | | const processBatch = (startIndex) => { |
| | | const endIndex = Math.min(startIndex + 10, items.length); |
| | | for (let i = startIndex; i < endIndex; i++) { |
| | | const item = items[i]; |
| | | const element = this.createItemElement(item); |
| | | fragment.append(element); |
| | | } |
| | | if (endIndex < items.length) { |
| | | requestAnimationFrame(() => processBatch(endIndex)); |
| | | } else { |
| | | window.chunkIt( |
| | | items, |
| | | (item) => this.createItemElement(item), |
| | | (fragment) => { |
| | | this.removePlaceholders(); |
| | | this.ui.grid.append(fragment); |
| | | |
| | | if (this.config.gallery) this.gallery.buildGalleryItems('.item img'); |
| | | this.a11y.makeNavigable(this.ui.grid.querySelectorAll('.item:not([data-keyboard-nav])')); |
| | | this.a11y.announceItems(items.length, !this.isFirstPage(), this.store.lastResponse?.has_more??false); |
| | | } |
| | | }; |
| | | processBatch(0); |
| | | }, |
| | | 5 |
| | | ).then(()=>{}); |
| | | } |
| | | |
| | | this.updateFilterControls(); |
| | |
| | | |
| | | showEmptyState() { |
| | | window.removeChildren(this.ui.grid); |
| | | let template = window.getTemplate('emptyState'); |
| | | if (!template) return; |
| | | this.ui.grid.append(template); |
| | | |
| | | this.ui.grid.append(this.templates.create('emptyState')); |
| | | } |
| | | |
| | | createItemElement(item) { |
| | | let template = window.getTemplate(`feedItem${window.uppercaseFirst(item.content)}`); |
| | | const isTimeline = Object.hasOwn(template.dataset, 'timeline'); |
| | | |
| | | for (let [fieldName, value] of Object.entries(item.fields)) { |
| | | if (isTimeline && ['timeline', 'number'].includes(fieldName)) continue; |
| | | |
| | | let el = template.querySelector(`[data-field="${fieldName}"]`); |
| | | if (!el) continue; |
| | | if (value === '') { |
| | | el.remove(); |
| | | continue; |
| | | } |
| | | |
| | | if (this.isImageField(item, value)) { |
| | | this.formatImageField(el, value, item); |
| | | } else if (this.isTaxonomyField(item, fieldName)) { |
| | | this.formatTaxonomyField(el, item, fieldName, value); |
| | | } else if (this.isTimeField(el)) { |
| | | this.formatTimeField(el, value); |
| | | } else { |
| | | this.formatField(el, value); |
| | | } |
| | | } |
| | | |
| | | let link = template.querySelector('a'); |
| | | if (link && item.url !== '') { |
| | | [link.href, link.title] = |
| | | [item.url, `View ${item.fields['post_title']??'Item'}`]; |
| | | } |
| | | |
| | | if (isTimeline) { |
| | | this.addTimelineElements(item, template); |
| | | } |
| | | |
| | | return template; |
| | | return this.templates.create(`feedItem${window.uppercaseFirst(item.content)}`, item); |
| | | } |
| | | splitIDs(value) { |
| | | return String(value).split(',').map((value) => parseInt(value.trim())).filter(value=>value); |
| | |
| | | ]; |
| | | |
| | | if (afterEl) { |
| | | afterEl.textContent = `After ${item.fields.number} Tx`; |
| | | afterEl.textContent = `After ${item.fields.number - 1} Tx`; |
| | | } |
| | | if (number) { |
| | | number.textContent = item.fields.number; |
| | |
| | | } |
| | | } |
| | | |
| | | defineTemplates() { |
| | | const T = this.templates; |
| | | const f = this; |
| | | |
| | | T.define('feedTerm', { |
| | | refs: { |
| | | icon: '.icon', |
| | | span: 'span' |
| | | }, |
| | | setup({el, refs, manyRefs, data}) { |
| | | el.dataset.id = data.id; |
| | | el.dataset.taxonomy = data.taxonomy; |
| | | if (refs.icon) refs.icon.className = `icon icon=${data.icon}`; |
| | | if (refs.span) refs.span.textContent = data.name; |
| | | } |
| | | }); |
| | | T.define('emptyState'); |
| | | |
| | | this.contentTypes.forEach(content => { |
| | | T.define(`feedItem${window.uppercaseFirst(content)}`, { |
| | | refs: { |
| | | link: 'a', |
| | | }, |
| | | manyRefs: { |
| | | fields: '[data-field]', |
| | | }, |
| | | setup({el, refs, manyRefs, data}) { |
| | | const isTimeline = Object.hasOwn(el.dataset, 'timeline'); |
| | | if (manyRefs.fields) { |
| | | for (let field of manyRefs.fields) { |
| | | if (isTimeline && ['timeline','number'].includes(field.dataset.field)) continue; |
| | | |
| | | const value = Object.hasOwn(data.fields, field.dataset.field)? data.fields[field.dataset.field] : false; |
| | | if (!value) { |
| | | field.remove(); |
| | | continue; |
| | | } |
| | | if (f.isImageField(data, value)) { |
| | | f.formatImageField(field, value, data); |
| | | } else if (f.isTaxonomyField(data, field.dataset.field)) { |
| | | f.formatTaxonomyField(field, data, field.dataset.field, value); |
| | | } else if (f.isTimeField(field)) { |
| | | f.formatTimeField(field, value); |
| | | } else { |
| | | f.formatField(field, value); |
| | | } |
| | | } |
| | | if (refs.link && data.url !== '') { |
| | | refs.link.href = data.url; |
| | | refs.link.title = `View ${data.fields['post_title']??'Item'}`; |
| | | } |
| | | if (isTimeline ) f.addTimelineElements(data, el); |
| | | } |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | // addPlaceholders() { |
| | | // let total = this.contentTypes.length; |
| | | // const fragment = document.createDocumentFragment(); |