From ed57c386db34d8693ca75311972d0929ebe5f488 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 01 Jun 2026 22:23:19 +0000
Subject: [PATCH] =Added some more Schema classes, allowed for override of  array in outputSchema for complex schema, as for timeline post types

---
 build/feed/view.js |  690 ---------------------------------------------------------
 1 files changed, 1 insertions(+), 689 deletions(-)

diff --git a/build/feed/view.js b/build/feed/view.js
index 4cd0ac5..4ddf769 100644
--- a/build/feed/view.js
+++ b/build/feed/view.js
@@ -1,689 +1 @@
-/******/ (() => { // 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
\ No newline at end of file
+(()=>{class e{constructor(){this.container=document.querySelector("section.feed-block"),this.container&&(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:!1,view:this.cache.get("feedView")||"grid",...this.container.dataset},this.init())}init(){this.initElements(),this.defineTemplates(),this.initListeners(),this.initFilters(),"requestIdleCallback"in window?requestIdleCallback(()=>{this.initStore(),this.initTaxonomies(),this.processCachedFilters(),this.processURLFilters(),this.updateFilterUI(),this.initGallery()},{timeout:2e3}):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),["content","orderby","order","taxonomy"].forEach(e=>{let t=this.ui.filters.container.querySelectorAll(this.selectors.filters[e]);this.ui[e]=Array.from(t)}),this.contentTypes=this.ui.content.length>0?this.ui.content.map(e=>e.value):[this.container.dataset.content],this.taxonomies=this.ui.taxonomies?.length>0?Array.from(this.ui.taxonomies).map(e=>e.dataset.taxonomy):[]}getChecked(e){["content","orderby","order"].includes(e)||console.log("Invalid item to check: ",e);let t=this.ui[e];if(!t)return;let i=t.filter(e=>e.checked);return"content"===e&&i.length>0&&this.updateContentFor(i[0].value),0===i.length?t[0].value:i[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 e={content:this.getChecked("content"),orderby:this.getChecked("orderby"),order:this.getChecked("order"),page:1};this.config.context&&(e.context=this.config.context),this.config.contextId&&(e.contextId=this.config.contextId),this.filters=e,this.defaults={...e}}updateFilterUI(){if(this.ui.filters.container&&([this.ui.content,this.ui.orderby,this.ui.order].forEach(e=>{if(e)for(let t of e){let[e,i]=[t.dataset.filter,t.value];if(!Object.hasOwn(this.store.filters,e))break;let s=this.store.filters[e]===i;if(s){t.checked=s;break}}}),Object.hasOwn(this.store.filters,"taxonomy")))for(let[e,t]of Object.entries(this.store.filters.taxonomy))t.forEach(e=>{e=parseInt(e),this.selector.store.get(e)&&this.createTermElement(e)})}handlePopState(e){e.state?.filters&&this.processURLFilters()&&(this.store.setFilters(this.filters),this.a11y.announce("Feed filters updated from browser history"))}handleClick(e){window.targetCheck(e,this.selectors.buttons.loadMore)?this.nextPage():window.targetCheck(e,this.selectors.buttons.clearFilters)&&this.clearFilters();let t=window.targetCheck(e,this.selectors.buttons.remove);t&&this.removeSelectedTerm(t),window.targetCheck(e,this.selectors.buttons.refresh)&&(this.store.clearCache(),this.store.fetch());let i=window.targetCheck(e,'[data-filter="orderby"]');i&&"random"===i.value&&i.checked&&this.renderItems()}nextPage(){const e=(this.store.filters.page||1)+1,t=this.store.lastResponse?.pages||e;this.store.setFilters({page:Math.min(e,t)})}handleChange(e){const t=e.target;if(Object.hasOwn(t.dataset,"filter")){if(this.allowedFilters.includes(t.dataset.filter)){let e={};e[t.dataset.filter]=t.value,this.resetFilters(e)}switch(t.dataset.filter){case"content":this.updateContentFor(t.value);break;case"orderby":this.updateOrderOptions(t.value)}}}clearFilters(){this.taxFilters={},window.removeChildren(this.ui.selected),this.taxonomies.forEach(e=>{let t=this.getFieldId(e);this.selector.selectedTerms.get(t)?.clear()}),this.store.setFilters({...this.defaults,taxonomy:null}),this.updateURL(),this.saveToCacheFilters()}resetFilters(e){e={...this.store.filters,page:1,...e},this.store.setFilters(e),this.updateURL(),this.saveToCacheFilters()}getFieldId(e){return this.selector.getFieldId(this.ui.taxonomies.filter(t=>t.dataset.taxonomy===e)[0]??null)}removeSelectedTerm(e){const t=parseInt(e.dataset.id),i=e.dataset.taxonomy;Object.hasOwn(this.taxFilters,i)&&(this.taxFilters[i]=this.taxFilters[i].filter(e=>e!==t),0===this.taxFilters[i].length&&delete this.taxFilters[i]),e.remove();const s=this.getFieldId(i);s&&(this.selector.activeField=s,this.selector.removeSelected(t,s)),this.resetFilters({taxonomy:Object.keys(this.taxFilters).length>0?this.taxFilters:null})}updateContentFor(e){let t=[this.ui.taxonomies,this.ui.orderby];this.ui.filters.showing.textContent=this.ui.content.filter(t=>t.value===e)[0].dataset.label,t.forEach(t=>{t&&t.forEach(t=>{const i=t.dataset.for?.split(",")??[];t.hidden=i.length>0&&!i.includes(e),t.hidden&&t.checked&&(t.checked=!1)})})}updateOrderOptions(e){if(this.ui.filters.orderWrap){let t=this.ui.filters.orderWrap.dataset.forOrder.split(",")??[];this.ui.filters.orderWrap.hidden=!t.includes(e)}}updateFilterControls(){const e=Object.keys(this.taxFilters);this.ui.buttons.clearFilters&&(this.ui.buttons.clearFilters.hidden=0===e.length),this.ui.filters.actions&&(this.ui.filters.actions.hidden=e.length<=1)}async initTaxonomies(){this.taxFilters={},this.selector=window.jvbSelector,this.selector.subscribe((e,t)=>{"selected-terms"===e&&this.handleTaxonomyChange(t)})}handleTaxonomyChange(e){const{terms:t,taxonomy:i}=e;0!==t.size&&(this.taxFilters[i]=Array.from(t),this.resetFilters({taxonomy:this.taxFilters}),t.forEach(e=>{this.createTermElement(e)}),this.updateFilterControls())}getTaxonomyIcon(e){let t=this.ui.taxonomies.find(t=>t.dataset.taxonomy===e);return t?.dataset.icon.trim()||"tag"}createTermElement(e){const t=this.selector.store.get(e);t&&(this.ui.selected.querySelector(`[data-id="${e}"]`)||(t.icon=this.getTaxonomyIcon(t.taxonomy),this.ui.selected.append(this.templates.create("feedTerm",t))))}processCachedFilters(){Object.keys(this.filters).forEach(e=>{let t=this.cache.get(`${this.config.contextId}_${this.config.context}_${e}`);t&&t!==this.filters[e]&&(this.filters[e]=t)})}processURLFilters(){if(!this.isFirstPage())return!1;const e=new URLSearchParams(window.location.search);if(!e.toString())return!1;let t=!1;this.allowedFilters.forEach(i=>{let s=e.get(`f_${i}`);s&&(t=!0,this.filters[i]=s)});let i=!1;return e.forEach((e,s)=>{if(s.startsWith("f_tax_")){i=!0,t=!0;const r=s.replace("f_tax_","");this.taxFilters[r]=e.split(",").map(Number)}}),t&&(i&&(this.filters.taxonomy=this.taxFilters),this.resetFilters(this.filters)),!0}updateURL(){const e=new URLSearchParams;this.allowedFilters.forEach(t=>{Object.hasOwn(this.store.filters,t)&&this.store.filters[t]!==this.defaults[t]&&e.set(`f_${t}`,this.store.filters[t])});for(let[t,i]of Object.entries(this.taxFilters))i.length>0&&e.set(`f_tax_${t}`,i.join(","));const t=`${window.location.pathname}${e.toString()?"?"+e.toString():""}`;t!==window.location.pathname+window.location.search&&window.history.pushState({filters:this.store.filters},"",t)}saveToCacheFilters(){Object.keys(this.store.filters).forEach(e=>{const t=`${this.config.contextId}_${this.config.context}_${e}`;this.store.filters[e]!==this.defaults[e]?this.cache.set(t,this.store.filters[e]):this.cache.remove(t)});const e=`${this.config.contextId}_${this.config.context}_taxonomy`;Object.keys(this.taxFilters).length>0?this.cache.set(e,this.taxFilters):this.cache.remove(e)}initGallery(){this.gallery=!!this.config.gallery&&window.jvbGallery,this.gallery&&this.gallery.subscribe((e,t)=>{"load-more"===e&&this.store.lastResponse?.has_more&&this.nextPage()})}initStore(){let e=this.ui.orderby.filter(e=>!["date","date_modified","title","random"].includes(e.value)),t=[];e.forEach(e=>{t.push({name:e.value,keyPath:e.value})});const i=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"},...t],filters:this.filters,TTL:216e5,showLoading:!0,required:"content"});this.store=i.feed,this.store.subscribe((e,t)=>{"data-loaded"===e&&(this.renderItems(t.items),this.ui.buttons.loadMore.hidden=!0,this.store.lastResponse&&this.store.lastResponse?.has_more&&(this.ui.buttons.loadMore.hidden=!this.store.lastResponse?.has_more??!0))})}isFirstPage(){return 1===this.store.filters.page}renderItems(e=null){e=e??this.store.getFiltered(),this.isFirstPage()&&window.removeChildren(this.ui.grid),0===e.length?(this.showEmptyState(),this.a11y.announceItems(0,this.isFirstPage())):window.chunkIt(e,e=>this.createItemElement(e),t=>{this.removePlaceholders(),this.ui.grid.append(t),this.config.gallery&&this.gallery.buildGalleryItems(".item img"),this.a11y.makeNavigable(this.ui.grid.querySelectorAll(".item:not([data-keyboard-nav])")),this.a11y.announceItems(e.length,!this.isFirstPage(),this.store.lastResponse?.has_more??!1)},5).then(()=>{}),this.updateFilterControls()}showEmptyState(){window.removeChildren(this.ui.grid),this.ui.grid.append(this.templates.create("emptyState"))}createItemElement(e){if("object"==typeof e||(e=this.store.get(e)))return this.templates.create(`feedItem${window.uppercaseFirst(e.content)}`,e)}splitIDs(e){return String(e).split(",").map(e=>parseInt(e.trim())).filter(e=>e)}isImageField(e,t){return!(!Object.hasOwn(e,"images")||0===Object.keys(e.images).length)&&this.splitIDs(t).some(t=>Object.keys(e.images).map(e=>parseInt(e)).includes(parseInt(t)))}formatImageFields(e,t,i){let s=this.splitIDs(t);if(0!==s.length)if(s.length>1){let t=e.querySelector("img");if(!t)return;s.forEach(s=>{let r=t.cloneNode(!0);this.formatImageField(r,s,i),e.append(r)}),t.remove()}else{if("IMG"!==e.tagName&&!(e=e.querySelector("img")))return;this.formatImageField(e,s[0],i)}}formatImageField(e,t,i){let s=i.images[t]??!1;s&&([e.src,e.srcset,e.alt]=[s.tiny,`${s.tiny} 50w, ${s.small} 300w, ${s.medium} 1024w`,s["image-alt-text"]])}isTaxonomyField(e,t){return!(!Object.hasOwn(e,"taxonomies")||0===Object.keys(e.taxonomies).length)&&Object.keys(e.taxonomies).includes(t)}formatTaxonomyField(e,t,i,s){if("UL"!==e.tagName||!e.querySelector("li"))return;let r=this.splitIDs(s);0===r.length&&e.remove();let o=e.querySelector("li");for(let s of r){let r=t.taxonomies[i][s]??!1;if(!r)continue;let a=o.cloneNode(!0),n=a.querySelector("a");if(!n)continue;let l=window.decodeHTMLEntities(r.title);[n.href,n.title,n.textContent]=[r.url,`See more ${l}`,l],e.append(a)}o.remove()}isTimeField(e){return"TIME"===e.tagName||null!==e.querySelector("time")}formatTimeField(e,t){("TIME"===e.tagName||(e=e.querySelector("time")))&&(e.setAttribute("datetime",t),e.textContent=window.formatTimeAgo(t,"F Y"))}formatField(e,t){e.textContent=window.decodeHTMLEntities(t)}addTimelineElements(e,t){let[i,s,r,o]=[t.querySelector("span.after-text"),t.querySelector('[data-field="number"] b'),t.querySelector('[data-field="started"] time'),t.querySelector('[data-field="updated"] time')];i&&(i.textContent=`After ${e.number-1} Tx`),s&&(s.textContent=e.number-1),r&&this.formatTimeField(r,e.fields.timeline[0].post_date),o&&this.formatTimeField(o,e.fields.timeline[e.fields.timeline.length-1].post_date)}removePlaceholders(){const e=this.ui.grid.querySelectorAll(".placeholder");e.length>0&&e.forEach(e=>e.remove())}defineTemplates(){const e=this.templates,t=this;e.define("feedTerm",{refs:{icon:".icon",span:"span"},setup({el:e,refs:t,manyRefs:i,data:s}){e.dataset.id=s.id,e.dataset.taxonomy=s.taxonomy,t.icon&&(t.icon.className=`icon icon-${s.icon}`),t.span&&(t.span.textContent=window.decodeHTMLEntities(s.name))}}),e.define("emptyState"),this.contentTypes.forEach(i=>{e.define(`feedItem${window.uppercaseFirst(i)}`,{refs:{link:"a"},manyRefs:{fields:"[data-field]"},setup({el:e,refs:i,manyRefs:s,data:r}){const o=Object.hasOwn(e.dataset,"timeline");if(s.fields){for(let e of s.fields){if(o&&["timeline","number"].includes(e.dataset.field))continue;const i=!!Object.hasOwn(r.fields,e.dataset.field)&&r.fields[e.dataset.field];i?t.isImageField(r,i)?t.formatImageField(e,i,r):t.isTaxonomyField(r,e.dataset.field)?t.formatTaxonomyField(e,r,e.dataset.field,i):t.isTimeField(e)?t.formatTimeField(e,i):t.formatField(e,i):e.remove()}i.link&&""!==r.url&&(i.link.href=r.url,i.link.title=`View ${r.fields.post_title??"Item"}`),o&&t.addTimelineElements(r,e)}}})})}}document.addEventListener("DOMContentLoaded",async function(){window.auth.subscribe(t=>{"auth-loaded"===t&&(window.feedBlock=new e)})})})();
\ No newline at end of file

--
Gitblit v1.10.0