/******/ (() => { // webpackBootstrap
|
/*!**************************!*\
|
!*** ./src/feed/view.js ***!
|
\**************************/
|
class FeedBlock {
|
constructor() {
|
this.container = document.querySelector('section.feed-block');
|
if (!this.container) return;
|
this.a11y = window.jvbA11y;
|
this.error = window.jvbError;
|
this.cache = new window.jvbCache('feed');
|
this.templates = window.jvbTemplates;
|
this.config = {
|
contextId: '',
|
context: '',
|
highlight: null,
|
gallery: false,
|
view: this.cache.get('feedView') || 'grid',
|
...this.container.dataset
|
};
|
console.log(this.config);
|
this.init();
|
}
|
init() {
|
this.initElements();
|
this.defineTemplates();
|
this.initListeners();
|
this.initFilters();
|
if ('requestIdleCallback' in window) {
|
requestIdleCallback(() => {
|
this.initStore();
|
this.initTaxonomies();
|
this.processCachedFilters();
|
this.processURLFilters();
|
this.updateFilterUI();
|
this.initGallery();
|
}, {
|
timeout: 2000
|
});
|
} else {
|
setTimeout(() => {
|
this.initStore();
|
this.initTaxonomies();
|
this.processCachedFilters();
|
this.processURLFilters();
|
this.updateFilterUI();
|
this.initGallery();
|
}, 100);
|
}
|
}
|
initElements() {
|
this.selectors = {
|
filterTrigger: '[data-filter]',
|
filters: {
|
actions: '.filter-actions .toggle-text',
|
container: '.all-filters',
|
showing: '.all-filters summary .current',
|
content: '[data-filter="content"]',
|
ordering: '.ordering',
|
orderby: '[data-filter="orderby"]',
|
order: '[data-filter="order"]',
|
orderWrap: '.order-direction',
|
match: '[data-filter="match"]',
|
favourites: '[data-filter="favourites"]',
|
taxonomy: '[data-filter^="taxonomy"]'
|
},
|
grid: '.item-grid',
|
selected: '.selected-items',
|
buttons: {
|
loadMore: 'button.load-more',
|
remove: '.remove-term',
|
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
|
let getAll = ['content', 'orderby', 'order', 'taxonomy'];
|
getAll.forEach(item => {
|
let items = this.ui.filters.container.querySelectorAll(this.selectors.filters[item]);
|
this.ui[item] = Array.from(items);
|
});
|
this.contentTypes = this.ui.content.length > 0 ? this.ui.content.map(c => c.value) : [this.container.dataset.content];
|
this.taxonomies = this.ui.taxonomies?.length > 0 ? Array.from(this.ui.taxonomies).map(t => t.dataset.taxonomy) : [];
|
}
|
|
/**
|
*
|
* @param {string} item
|
*/
|
getChecked(item) {
|
if (!['content', 'orderby', 'order'].includes(item)) {
|
console.log('Invalid item to check: ', item);
|
}
|
let items = this.ui[item];
|
if (!items) {
|
return;
|
}
|
let checked = items.filter(i => i.checked);
|
if (item === 'content' && checked.length > 0) {
|
this.updateContentFor(checked[0].value);
|
}
|
return checked.length === 0 ? items[0].value : checked[0].value;
|
}
|
initListeners() {
|
this.popStateHandler = this.handlePopState.bind(this);
|
this.clickHandler = this.handleClick.bind(this);
|
this.changeHandler = this.handleChange.bind(this);
|
window.addEventListener('popstate', this.popStateHandler);
|
document.addEventListener('click', this.clickHandler);
|
document.addEventListener('change', this.changeHandler);
|
}
|
initFilters() {
|
this.allowedFilters = ['content', 'order', 'orderby', 'favourites', 'match'];
|
let defaults = {
|
content: this.getChecked('content'),
|
orderby: this.getChecked('orderby'),
|
order: this.getChecked('order'),
|
page: 1
|
};
|
if (this.config.context) defaults.context = this.config.context;
|
if (this.config.contextId) defaults.contextId = this.config.contextId;
|
this.filters = defaults;
|
console.log(this.filters);
|
this.defaults = {
|
...defaults
|
};
|
}
|
updateFilterUI() {
|
if (this.ui.filters.container) {
|
//Get cached inputs
|
let groups = [this.ui.content, this.ui.orderby, this.ui.order];
|
groups.forEach(group => {
|
if (group) {
|
for (let input of group) {
|
let [filter, value] = [input.dataset.filter, input.value];
|
if (!Object.hasOwn(this.store.filters, filter)) break;
|
let doit = this.store.filters[filter] === value;
|
if (doit) {
|
input.checked = doit;
|
break;
|
}
|
}
|
}
|
});
|
if (Object.hasOwn(this.store.filters, 'taxonomy')) {
|
for (let [taxonomy, terms] of Object.entries(this.store.filters.taxonomy)) {
|
terms.forEach(termId => {
|
termId = parseInt(termId);
|
const term = this.selector.store.get(termId);
|
if (term) {
|
this.createTermElement(termId);
|
}
|
});
|
}
|
}
|
}
|
}
|
handlePopState(e) {
|
if (e.state?.filters) {
|
if (this.processURLFilters()) {
|
this.store.setFilters(this.filters);
|
this.a11y.announce('Feed filters updated from browser history');
|
}
|
}
|
}
|
handleClick(e) {
|
if (window.targetCheck(e, this.selectors.buttons.loadMore)) {
|
this.nextPage();
|
} else if (window.targetCheck(e, this.selectors.buttons.clearFilters)) {
|
this.clearFilters();
|
}
|
let remove = window.targetCheck(e, this.selectors.buttons.remove);
|
if (remove) {
|
this.removeSelectedTerm(remove);
|
}
|
let refresh = window.targetCheck(e, this.selectors.buttons.refresh);
|
if (refresh) {
|
this.store.clearCache();
|
this.store.fetch();
|
}
|
let orderbyButton = window.targetCheck(e, '[data-filter="orderby"]');
|
if (orderbyButton && orderbyButton.value === 'random' && orderbyButton.checked) {
|
// Already selected random, just re-render to trigger new shuffle
|
this.renderItems();
|
}
|
}
|
nextPage() {
|
const nextPage = (this.store.filters.page || 1) + 1;
|
const maxPage = this.store.lastResponse?.pages || nextPage;
|
this.store.setFilters({
|
page: Math.min(nextPage, maxPage)
|
});
|
}
|
handleChange(e) {
|
const target = e.target;
|
if (Object.hasOwn(target.dataset, 'filter')) {
|
if (this.allowedFilters.includes(target.dataset.filter)) {
|
let filters = {};
|
filters[target.dataset.filter] = target.value;
|
this.resetFilters(filters);
|
}
|
switch (target.dataset.filter) {
|
case 'content':
|
this.updateContentFor(target.value);
|
break;
|
case 'orderby':
|
this.updateOrderOptions(target.value);
|
break;
|
}
|
}
|
}
|
clearFilters() {
|
this.taxFilters = {};
|
window.removeChildren(this.ui.selected);
|
this.taxonomies.forEach(tax => {
|
let fieldId = this.getFieldId(tax);
|
this.selector.selectedTerms.get(fieldId)?.clear();
|
});
|
this.store.setFilters({
|
...this.defaults,
|
taxonomy: null
|
});
|
this.updateURL();
|
this.saveToCacheFilters();
|
}
|
resetFilters(filters) {
|
filters = {
|
...this.store.filters,
|
page: 1,
|
...filters
|
};
|
this.store.setFilters(filters);
|
this.updateURL();
|
this.saveToCacheFilters();
|
}
|
getFieldId(taxonomy) {
|
return this.selector.getFieldId(this.ui.taxonomies.filter(tax => tax.dataset.taxonomy === taxonomy)[0] ?? null);
|
}
|
removeSelectedTerm(button) {
|
const termId = parseInt(button.dataset.id);
|
const taxonomy = button.dataset.taxonomy;
|
if (Object.hasOwn(this.taxFilters, taxonomy)) {
|
this.taxFilters[taxonomy] = this.taxFilters[taxonomy].filter(id => id !== termId);
|
if (this.taxFilters[taxonomy].length === 0) {
|
delete this.taxFilters[taxonomy];
|
}
|
}
|
button.remove();
|
|
// Find the fieldId for this taxonomy
|
const field = this.getFieldId(taxonomy);
|
if (field) {
|
this.selector.activeField = field;
|
// Notify selector to remove from its selectedTerms
|
this.selector.removeSelected(termId, field);
|
}
|
this.resetFilters({
|
taxonomy: Object.keys(this.taxFilters).length > 0 ? this.taxFilters : null
|
});
|
}
|
updateContentFor(content) {
|
let checkIt = [this.ui.taxonomies, this.ui.orderby];
|
this.ui.filters.showing.textContent = this.ui.content.filter(c => c.value === content)[0].dataset.label;
|
checkIt.forEach(check => {
|
if (!check) return;
|
check.forEach(button => {
|
const forTypes = button.dataset.for?.split(',') ?? [];
|
button.hidden = forTypes.length > 0 && !forTypes.includes(content);
|
if (button.hidden && button.checked) {
|
button.checked = false;
|
}
|
});
|
});
|
}
|
updateOrderOptions(order) {
|
if (this.ui.filters.orderWrap) {
|
let options = this.ui.filters.orderWrap.dataset.forOrder.split(',') ?? [];
|
this.ui.filters.orderWrap.hidden = !options.includes(order);
|
}
|
}
|
updateFilterControls() {
|
const keys = Object.keys(this.taxFilters);
|
if (this.ui.buttons.clearFilters) {
|
this.ui.buttons.clearFilters.hidden = keys.length === 0;
|
}
|
if (this.ui.filters.actions) {
|
this.ui.filters.actions.hidden = keys.length <= 1;
|
}
|
}
|
async initTaxonomies() {
|
this.taxFilters = {};
|
this.selector = window.jvbSelector;
|
// this.selector.scanExistingFields(this.ui.filters.container);
|
// this.taxonomies.map(tax => this.selector.batchFetch.add(tax));
|
// this.selector.batchFetchTaxonomies();
|
this.selector.subscribe((event, data) => {
|
switch (event) {
|
case 'selected-terms':
|
this.handleTaxonomyChange(data);
|
break;
|
}
|
});
|
}
|
handleTaxonomyChange(data) {
|
const {
|
terms,
|
taxonomy
|
} = data;
|
if (terms.size === 0) return;
|
this.taxFilters[taxonomy] = Array.from(terms);
|
this.resetFilters({
|
taxonomy: this.taxFilters
|
});
|
terms.forEach(t => {
|
this.createTermElement(t);
|
});
|
this.updateFilterControls();
|
}
|
getTaxonomyIcon(taxonomy) {
|
let iconButton = this.ui.taxonomies.find(t => t.dataset.taxonomy === taxonomy);
|
return iconButton?.dataset.icon.trim() || 'tag';
|
}
|
createTermElement(termId) {
|
const term = this.selector.store.get(termId);
|
if (!term) return;
|
if (this.ui.selected.querySelector(`[data-id="${termId}"]`)) return;
|
term.icon = this.getTaxonomyIcon(term.taxonomy);
|
this.ui.selected.append(this.templates.create('feedTerm', term));
|
}
|
processCachedFilters() {
|
Object.keys(this.filters).forEach(filter => {
|
let cached = this.cache.get(`${this.config.contextId}_${this.config.context}_${filter}`);
|
if (cached && cached !== this.filters[filter]) {
|
this.filters[filter] = cached;
|
}
|
});
|
}
|
processURLFilters() {
|
if (!this.isFirstPage()) return false;
|
const params = new URLSearchParams(window.location.search);
|
if (!params.toString()) return false;
|
let shouldUpdate = false;
|
this.allowedFilters.forEach(filter => {
|
let value = params.get(`f_${filter}`);
|
if (value) {
|
shouldUpdate = true;
|
this.filters[filter] = value;
|
}
|
});
|
let hasTax = false;
|
params.forEach((value, key) => {
|
if (key.startsWith('f_tax_')) {
|
hasTax = true;
|
shouldUpdate = true;
|
const taxonomy = key.replace('f_tax_', '');
|
this.taxFilters[taxonomy] = value.split(',').map(Number);
|
}
|
});
|
if (shouldUpdate) {
|
if (hasTax) {
|
this.filters.taxonomy = this.taxFilters;
|
}
|
this.resetFilters(this.filters);
|
}
|
return true;
|
}
|
updateURL() {
|
const params = new URLSearchParams();
|
this.allowedFilters.forEach(key => {
|
if (Object.hasOwn(this.store.filters, key) && this.store.filters[key] !== this.defaults[key]) {
|
params.set(`f_${key}`, this.store.filters[key]);
|
}
|
});
|
for (let [tax, terms] of Object.entries(this.taxFilters)) {
|
if (terms.length > 0) {
|
params.set(`f_tax_${tax}`, terms.join(','));
|
}
|
}
|
const newURL = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`;
|
const currentURL = window.location.pathname + window.location.search; // Change this line
|
|
if (newURL !== currentURL) {
|
window.history.pushState({
|
filters: this.store.filters
|
}, '', newURL);
|
}
|
}
|
saveToCacheFilters() {
|
Object.keys(this.store.filters).forEach(filter => {
|
const cacheKey = `${this.config.contextId}_${this.config.context}_${filter}`;
|
if (this.store.filters[filter] !== this.defaults[filter]) {
|
this.cache.set(cacheKey, this.store.filters[filter]);
|
} else {
|
this.cache.remove(cacheKey);
|
}
|
});
|
const taxCacheKey = `${this.config.contextId}_${this.config.context}_taxonomy`;
|
if (Object.keys(this.taxFilters).length > 0) {
|
this.cache.set(taxCacheKey, this.taxFilters);
|
} else {
|
this.cache.remove(taxCacheKey);
|
}
|
}
|
initGallery() {
|
this.gallery = this.config.gallery ? window.jvbGallery : false;
|
if (this.gallery) {
|
this.gallery.subscribe((event, data) => {
|
if (event === 'load-more' && this.store.lastResponse?.has_more) {
|
this.nextPage();
|
}
|
});
|
}
|
}
|
initStore() {
|
let extraOrderby = this.ui.orderby.filter(v => !['date', 'date_modified', 'title', 'random'].includes(v.value));
|
let extraIndexes = [];
|
extraOrderby.forEach(orderby => {
|
extraIndexes.push({
|
name: orderby.value,
|
keyPath: orderby.value
|
});
|
});
|
const store = window.jvbStore.register('feed', {
|
storeName: 'feed',
|
endpoint: 'feed',
|
keyPath: 'id',
|
indexes: [{
|
name: 'content',
|
keyPath: 'content'
|
}, {
|
name: 'taxonomy',
|
keyPath: 'taxonomy'
|
}, {
|
name: 'user',
|
keyPath: 'user'
|
}, {
|
name: 'date',
|
keyPath: 'date'
|
}, {
|
name: 'modified',
|
keyPath: 'modified'
|
}, {
|
name: 'title',
|
keyPath: 'title'
|
}, ...extraIndexes],
|
filters: this.filters,
|
TTL: 6 * 60 * 60 * 1000,
|
//6 hours
|
showLoading: true,
|
required: 'content'
|
});
|
this.store = store.feed;
|
this.store.subscribe((event, data) => {
|
switch (event) {
|
case 'data-loaded':
|
this.renderItems(data.items);
|
this.ui.buttons.loadMore.hidden = true;
|
if (this.store.lastResponse && this.store.lastResponse?.has_more) {
|
this.ui.buttons.loadMore.hidden = !this.store.lastResponse?.has_more ?? true;
|
}
|
break;
|
}
|
});
|
}
|
isFirstPage() {
|
return this.store.filters.page === 1;
|
}
|
renderItems(items = null) {
|
items = items ?? this.store.getFiltered();
|
if (this.isFirstPage()) {
|
window.removeChildren(this.ui.grid);
|
}
|
if (items.length === 0) {
|
this.showEmptyState();
|
this.a11y.announceItems(0, this.isFirstPage());
|
} 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);
|
}, 5).then(() => {});
|
}
|
this.updateFilterControls();
|
}
|
showEmptyState() {
|
window.removeChildren(this.ui.grid);
|
this.ui.grid.append(this.templates.create('emptyState'));
|
}
|
createItemElement(item) {
|
if (typeof item !== 'object') {
|
item = this.store.get(item);
|
if (!item) return;
|
}
|
return this.templates.create(`feedItem${window.uppercaseFirst(item.content)}`, item);
|
}
|
splitIDs(value) {
|
return String(value).split(',').map(value => parseInt(value.trim())).filter(value => value);
|
}
|
isImageField(item, value) {
|
if (!Object.hasOwn(item, 'images') || Object.keys(item.images).length === 0) {
|
return false;
|
}
|
let values = this.splitIDs(value);
|
return values.some(v => Object.keys(item.images).map(k => parseInt(k)).includes(parseInt(v)));
|
}
|
formatImageFields(element, value, item) {
|
let values = this.splitIDs(value); // Convert string to array first
|
if (values.length === 0) return;
|
if (values.length > 1) {
|
let image = element.querySelector('img');
|
if (!image) return;
|
values.forEach(imgID => {
|
let img = image.cloneNode(true);
|
this.formatImageField(img, imgID, item);
|
element.append(img);
|
});
|
image.remove();
|
} else {
|
if (element.tagName !== 'IMG') {
|
element = element.querySelector('img');
|
if (!element) return;
|
}
|
this.formatImageField(element, values[0], item);
|
}
|
}
|
formatImageField(element, value, item) {
|
let imgData = item.images[value] ?? false;
|
if (!imgData) return;
|
[element.src, element.srcset, element.alt] = [imgData.tiny, `${imgData.tiny} 50w, ${imgData.small} 300w, ${imgData.medium} 1024w`, imgData['image-alt-text']];
|
}
|
isTaxonomyField(item, field) {
|
if (!Object.hasOwn(item, 'taxonomies') || Object.keys(item.taxonomies).length === 0) {
|
return false;
|
}
|
return Object.keys(item.taxonomies).includes(field);
|
}
|
formatTaxonomyField(element, item, field, value) {
|
if (element.tagName !== 'UL' || !element.querySelector('li')) return;
|
let values = this.splitIDs(value);
|
if (values.length === 0) {
|
element.remove();
|
}
|
let listItem = element.querySelector('li');
|
for (let termID of values) {
|
let term = item.taxonomies[field][termID] ?? false;
|
if (!term) continue;
|
let termItem = listItem.cloneNode(true);
|
let link = termItem.querySelector('a');
|
if (!link) continue;
|
let title = window.decodeHTMLEntities(term.title);
|
[link.href, link.title, link.textContent] = [term.url, `See more ${title}`, title];
|
element.append(termItem);
|
}
|
listItem.remove();
|
}
|
isTimeField(el) {
|
return el.tagName === 'TIME' || el.querySelector('time') !== null;
|
}
|
formatTimeField(element, value) {
|
if (element.tagName !== 'TIME') {
|
element = element.querySelector('time');
|
if (!element) return;
|
}
|
element.setAttribute('datetime', value);
|
element.textContent = window.formatTimeAgo(value, 'F Y');
|
}
|
formatField(element, value) {
|
element.textContent = window.decodeHTMLEntities(value);
|
}
|
addTimelineElements(item, template) {
|
let [afterEl, number, started, last] = [template.querySelector('span.after-text'), template.querySelector('[data-field="number"] b'), template.querySelector('[data-field="started"] time'), template.querySelector('[data-field="updated"] time')];
|
if (afterEl) {
|
afterEl.textContent = `After ${item.number - 1} Tx`;
|
}
|
if (number) {
|
number.textContent = item.number - 1;
|
}
|
if (started) {
|
this.formatTimeField(started, item.fields.timeline[0]['post_date']);
|
}
|
if (last) {
|
this.formatTimeField(last, item.fields.timeline[item.fields.timeline.length - 1]['post_date']);
|
}
|
}
|
removePlaceholders() {
|
const placeholders = this.ui.grid.querySelectorAll('.placeholder');
|
if (placeholders.length > 0) {
|
placeholders.forEach(p => p.remove());
|
}
|
}
|
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 = window.decodeHTMLEntities(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();
|
// for (let i = 0; i < 12; i++) {
|
// let template = window.getTemplate('placeholderTemplate');
|
//
|
// let rand = Math.floor(Math.random() * total);
|
// let icon;
|
// if (this.ui.content && this.ui.content.length > 0) {
|
// icon = this.ui.content.filter((content) => { return content.value === this.contentTypes[rand]}).querySelector('.icon').cloneNode(true);
|
// } else {
|
// icon = window.getIcon(this.container.dataset.icon);
|
// }
|
// template.append(icon);
|
// fragment.append(template);
|
// }
|
// this.ui.grid.append(fragment);
|
// }
|
}
|
document.addEventListener('DOMContentLoaded', async function () {
|
window.auth.subscribe(event => {
|
if (event === 'auth-loaded') {
|
window.feedBlock = new FeedBlock();
|
}
|
});
|
});
|
/******/ })()
|
;
|
//# sourceMappingURL=view.js.map
|