PageSourceSearch

https://firmendo-test.netlify.app/js/lp-table-utils.js

js firmendo-test.netlify.app collected 2026-10-03 10:44:13 UTC 5,368 bytes, 159 lines download raw bytes

1function compareHighlightFirst(a, b) {
2  if (a.highlight && !b.highlight) return -1;
3  if (!a.highlight && b.highlight) return 1;
4  return 0;
5}
6
7function fdGetValue(id) {
8  return document.getElementById(id)?.dataset.value || '';
9}
10
11const fdValueModes = {
12  sortHasValue: Object.freeze({ sortHasValue: true })
13};
14
15function fdSetValue(id, value, label, options = {}) {
16  const {
17    labelMode = 'auto',
18    selectFallback = false,
19    syncAria = true,
20    sortHasValue = false
21  } = options;
22
23  const el = document.getElementById(id);
24  if (!el) return;
25
26  const optionList = Array.from(el.querySelectorAll('.fd-option'));
27  const selectedOption =
28    optionList.find(option => (option.dataset.value || '') === value) ||
29    (selectFallback ? optionList[0] : null);
30  const nextValue = selectedOption ? (selectedOption.dataset.value || '') : value;
31
32  el.dataset.value = nextValue;
33
34  const triggerText = el.querySelector('.fd-trigger-text');
35  const optionLabel = selectedOption ? selectedOption.innerHTML.trim() : undefined;
36  const nextLabel = label !== undefined ? label : optionLabel;
37
38  if (triggerText && nextLabel !== undefined) {
39    const shouldRenderHtml =
40      labelMode === 'html' ||
41      (labelMode === 'auto' && (
42        /<[^>]+>/.test(nextLabel) ||
43        /&(?:[a-zA-Z]+|#\d+|#x[\da-fA-F]+);/.test(nextLabel) ||
44        Boolean(selectedOption?.children.length)
45      ));
46
47    if (shouldRenderHtml) triggerText.innerHTML = nextLabel;
48    else triggerText.textContent = nextLabel;
49  }
50
51  optionList.forEach(option => {
52    const selected = selectedOption ? option === selectedOption : (option.dataset.value || '') === nextValue;
53    option.classList.toggle('selected', selected);
54    if (syncAria) option.setAttribute('aria-selected', selected ? 'true' : 'false');
55  });
56
57  el.classList.toggle('has-value', nextValue !== '' && (sortHasValue || id !== 'fd-sort'));
58}
59
60function fdCloseDropdowns(except = null) {
61  document.querySelectorAll('.fd.open').forEach(fd => {
62    if (fd === except) return;
63    fd.classList.remove('open');
64    fd.querySelector('.fd-trigger')?.setAttribute('aria-expanded', 'false');
65  });
66}
67
68function fdInitControls(options = {}) {
69  const {
70    selector = '.fd',
71    label,
72    valueOptions,
73    onSort,
74    onFilter,
75    onChange
76  } = options;
77
78  document.querySelectorAll(selector).forEach(fd => {
79    const trigger = fd.querySelector('.fd-trigger');
80    const menu = fd.querySelector('.fd-menu');
81    if (!trigger || !menu) return;
82
83    trigger.addEventListener('click', event => {
84      event.stopPropagation();
85      const willOpen = !fd.classList.contains('open');
86      fdCloseDropdowns(fd);
87      fd.classList.toggle('open', willOpen);
88      trigger.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
89    });
90
91    menu.querySelectorAll('.fd-option').forEach(option => {
92      option.addEventListener('click', event => {
93        event.stopPropagation();
94        const nextValue = option.dataset.value || '';
95        const nextLabel = typeof label === 'function' ? label(option, fd) : undefined;
96        const nextOptions = typeof valueOptions === 'function' ? valueOptions(fd, option) : valueOptions;
97
98        fdSetValue(fd.id, nextValue, nextLabel, nextOptions || undefined);
99        fd.classList.remove('open');
100        trigger.setAttribute('aria-expanded', 'false');
101
102        const detail = { fd, option, value: fd.dataset.value || '', isSort: fd.id === 'fd-sort' };
103        if (typeof onChange === 'function') {
104          onChange(detail);
105        } else if (detail.isSort && typeof onSort === 'function') {
106          onSort(detail);
107        } else if (!detail.isSort && typeof onFilter === 'function') {
108          onFilter(detail);
109        }
110      });
111    });
112  });
113
114  if (document.documentElement.dataset.fdControlsBound === 'true') return;
115  document.documentElement.dataset.fdControlsBound = 'true';
116
117  document.addEventListener('click', event => {
118    if (event.target.closest('.fd')) return;
119    fdCloseDropdowns();
120  });
121
122  document.addEventListener('keydown', event => {
123    if (event.key === 'Escape') fdCloseDropdowns();
124  });
125}
126
127function updateTableScrollState(options = {}) {
128  const {
129    tableId = 'tableWrap',
130    shellId = 'tableScrollWrap',
131    hintId = 'scrollHint',
132    scrollThreshold = 2,
133    startOffset = 2,
134    endOffset = 8,
135    trackEnd = true,
136    endWhenNotScrollable = false,
137    hintMode = 'until-end'
138  } = options;
139
140  const tableWrap = document.getElementById(tableId);
141  const scrollWrap = document.getElementById(shellId);
142  const scrollHint = document.getElementById(hintId);
143  if (!tableWrap || !scrollWrap) return;
144
145  const scrollable = tableWrap.scrollWidth > tableWrap.clientWidth + scrollThreshold;
146  const atStart = tableWrap.scrollLeft <= startOffset;
147  const atEnd = tableWrap.scrollLeft + tableWrap.clientWidth >= tableWrap.scrollWidth - endOffset;
148
149  scrollWrap.classList.toggle('scrollable', scrollable);
150  scrollWrap.classList.toggle('at-start', endWhenNotScrollable ? (!scrollable || atStart) : atStart);
151  if (trackEnd) scrollWrap.classList.toggle('at-end', endWhenNotScrollable ? (!scrollable || atEnd) : atEnd);
152
153  if (!scrollHint) return;
154  const hintVisible =
155    hintMode === 'while-scrollable' ? scrollable :
156    hintMode === 'at-start' ? (scrollable && atStart) :
157    (scrollable && !atEnd);
158  scrollHint.classList.toggle('visible', hintVisible);
159}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.