| | |
| | | this.error = window.jvbError; |
| | | this.cache = new window.jvbCache('feed'); |
| | | this.templates = window.jvbTemplates; |
| | | this.isFirstLoad = true; |
| | | |
| | | this.config = { |
| | | source: '', |
| | | contextId: '', |
| | | context: '', |
| | | highlight: null, |
| | | gallery: false, |
| | |
| | | ... this.container.dataset |
| | | }; |
| | | |
| | | |
| | | this.init(); |
| | | } |
| | | init() { |
| | | this.initElements(); |
| | | this.defineTemplates(); |
| | | |
| | | this.initListeners(); |
| | | this.initFilters(); |
| | | |
| | | if ('requestIdleCallback' in window) { |
| | | requestIdleCallback(() => { |
| | | this.initStore(); |
| | | this.initTaxonomies(); |
| | | this.initStore(); |
| | | this.initTaxonomies().then(r => {}); |
| | | |
| | | 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); |
| | | } |
| | | this.processCachedFilters(); |
| | | this.processURLFilters(); |
| | | this.updateFilterUI(); |
| | | this.initGallery(); |
| | | } |
| | | |
| | | initElements() { |
| | |
| | | filterTrigger: '[data-filter]', |
| | | filters: { |
| | | actions: '.filter-actions .toggle-text', |
| | | container: '.filters', |
| | | 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"]', |
| | |
| | | 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 (this.ui.content.length === 0) this.ui.content = false; |
| | | this.ui.taxonomies = this.ui.filters.container.querySelectorAll('[data-taxonomy]'); |
| | | if (this.ui.taxonomies.length === 0) this.ui.taxonomies = false; |
| | | this.ui.orderbyWrap = this.ui.filters.container.querySelector('[data-for-order]'); |
| | | if (this.ui.orderbyWrap.length === 0) this.ui.orderbyWrap = false; |
| | | this.ui.order = this.ui.filters.container.querySelectorAll('[data-filter="order"]'); |
| | | if (this.ui.order.length === 0) this.ui.order = false; |
| | | this.ui.orderby = this.ui.filters.container.querySelectorAll('[data-filter="orderby"]'); |
| | | if (this.ui.orderby.length === 0) this.ui.orderby = false; |
| | | 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.orderbyFilters = (this.ui.orderby) |
| | | ? Array.from(this.ui.orderby).map(o => o.value) |
| | | : []; |
| | | |
| | | this.contentTypes = (this.ui.content) |
| | | ? Array.from(this.ui.content).map(c => c.value) |
| | | 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); |
| | |
| | | initFilters() { |
| | | this.allowedFilters = ['content', 'order', 'orderby', 'favourites', 'match']; |
| | | let defaults = { |
| | | content: this.contentTypes[0], |
| | | orderby: 'date', |
| | | order: 'desc', |
| | | 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.source) defaults.source = this.config.source; |
| | | if (this.config.contextId) defaults.contextId = this.config.contextId; |
| | | |
| | | this.filters = defaults; |
| | | |
| | | this.defaults = {...defaults}; |
| | | } |
| | | updateFilterUI() { |
| | |
| | | } |
| | | |
| | | getFieldId(taxonomy) { |
| | | return this.selector.getFieldId(Array.from(this.ui.taxonomies).filter(tax => tax.dataset.taxonomy === taxonomy)[0]??null); |
| | | return this.selector.getFieldId(this.ui.taxonomies.filter(tax => tax.dataset.taxonomy === taxonomy)[0]??null); |
| | | } |
| | | removeSelectedTerm(button) { |
| | | const termId = parseInt(button.dataset.id); |
| | |
| | | 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 => { |
| | |
| | | }); |
| | | } |
| | | updateOrderOptions(order) { |
| | | if (this.ui.orderbyWrap) { |
| | | let options = this.ui.orderbyWrap.dataset.forOrder.split(',')??[]; |
| | | this.ui.orderbyWrap.hidden = !options.includes(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 isHidden = Object.keys(this.taxFilters).length === 0; |
| | | const keys = Object.keys(this.taxFilters); |
| | | if (this.ui.buttons.clearFilters) { |
| | | this.ui.buttons.clearFilters.hidden = isHidden; |
| | | this.ui.buttons.clearFilters.hidden = keys.length === 0; |
| | | } |
| | | if (this.ui.filters.actions) { |
| | | this.ui.filters.actions.hidden = isHidden; |
| | | this.ui.filters.actions.hidden = keys.length <= 1; |
| | | } |
| | | } |
| | | |
| | |
| | | this.updateFilterControls(); |
| | | } |
| | | getTaxonomyIcon(taxonomy) { |
| | | let iconButton = Array.from(this.ui.taxonomies) |
| | | let iconButton = this.ui.taxonomies |
| | | .find(t => t.dataset.taxonomy === taxonomy); |
| | | return iconButton?.dataset.icon.trim() || 'tag'; |
| | | } |
| | |
| | | |
| | | processCachedFilters() { |
| | | Object.keys(this.filters).forEach(filter => { |
| | | let cached = this.cache.get(`${this.config.source}_${this.config.context}_${filter}`); |
| | | let cached = this.cache.get(`${this.config.contextId}_${this.config.context}_${filter}`); |
| | | if (cached && cached !== this.filters[filter]) { |
| | | this.filters[filter] = cached; |
| | | } |
| | |
| | | |
| | | saveToCacheFilters() { |
| | | Object.keys(this.store.filters).forEach(filter => { |
| | | const cacheKey = `${this.config.source}_${this.config.context}_${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]); |
| | |
| | | } |
| | | }); |
| | | |
| | | const taxCacheKey = `${this.config.source}_${this.config.context}_taxonomy`; |
| | | const taxCacheKey = `${this.config.contextId}_${this.config.context}_taxonomy`; |
| | | if (Object.keys(this.taxFilters).length > 0) { |
| | | this.cache.set(taxCacheKey, this.taxFilters); |
| | | } else { |
| | |
| | | } |
| | | } |
| | | initStore() { |
| | | let extraOrderby = this.orderbyFilters.filter(v => !['date','modified','title','random'].includes(v)); |
| | | let extraOrderby = this.ui.orderby.filter(v => !['date','date_modified','title','random'].includes(v.value)); |
| | | |
| | | let extraIndexes = []; |
| | | extraOrderby.forEach(orderby =>{ |
| | | extraIndexes.push({name:orderby, keyPath: orderby}); |
| | | extraIndexes.push({name:orderby.value, keyPath: orderby.value}); |
| | | }); |
| | | const store = window.jvbStore.register( |
| | | 'feed', |
| | |
| | | TTL: 6 * 60 * 60 * 1000, //6 hours |
| | | showLoading: true, |
| | | required: 'content', |
| | | } |
| | | }, |
| | | 2 |
| | | ); |
| | | |
| | | this.store = store.feed; |
| | |
| | | this.store.subscribe((event, data) => { |
| | | switch (event) { |
| | | case 'data-loaded': |
| | | if (this.isFirstLoad) { |
| | | //We rendered the first page in php already |
| | | this.isFirstLoad = false; |
| | | return; |
| | | } |
| | | // if (this.store.filters.page === 1) { |
| | | // return; |
| | | // } |
| | | this.renderItems(data.items); |
| | | this.ui.buttons.loadMore.hidden = true; |
| | | if (this.store.lastResponse && this.store.lastResponse?.has_more) { |
| | |
| | | ]; |
| | | |
| | | if (afterEl) { |
| | | afterEl.textContent = `After ${item.number - 1} Tx`; |
| | | afterEl.textContent = `After ${item.number} Tx`; |
| | | } |
| | | if (number) { |
| | | number.textContent = item.number - 1; |
| | | number.textContent = item.number; |
| | | } |
| | | if (started) { |
| | | this.formatTimeField(started, item.fields.timeline[0]['post_date']); |
| | |
| | | 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.icon) refs.icon.className = `icon icon-${data.icon}`; |
| | | if (refs.span) refs.span.textContent = window.decodeHTMLEntities(data.name); |
| | | } |
| | | }); |
| | |
| | | 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(); |