Skip to content

Commit 5ab70c4

Browse files
committed
feed directory strip out client side js
1 parent e91cec7 commit 5ab70c4

2 files changed

Lines changed: 171 additions & 136 deletions

File tree

src/components/FeedDirectory.astro

Lines changed: 1 addition & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -168,142 +168,7 @@ const staticFeedUrls = configs.map(config => ({
168168
</div>
169169

170170
<!-- Enhanced functionality with vanilla JavaScript -->
171-
<script is:inline>
172-
// Simple debounce helper
173-
function debounce(func, wait) {
174-
let timeout;
175-
return function executedFunction(...args) {
176-
const later = () => {
177-
clearTimeout(timeout);
178-
func(...args);
179-
};
180-
clearTimeout(timeout);
181-
timeout = setTimeout(later, wait);
182-
};
183-
}
184-
185-
// Simple fuzzy search
186-
function fuzzyMatch(text, query) {
187-
if (!query) return true;
188-
const lowerText = text.toLowerCase();
189-
const lowerQuery = query.toLowerCase();
190-
let textIndex = 0;
191-
let queryIndex = 0;
192-
while (queryIndex < lowerQuery.length && textIndex < lowerText.length) {
193-
if (lowerQuery[queryIndex] === lowerText[textIndex]) queryIndex++;
194-
textIndex++;
195-
}
196-
return queryIndex === lowerQuery.length;
197-
}
198-
199-
// Main functionality - wait for DOM to be ready
200-
function initializeFeedDirectory() {
201-
const defaultInstanceUrl = atob("aHR0cHM6Ly8xLmgyci53b3JrZXJzLmRldi8=");
202-
let instanceUrl = defaultInstanceUrl;
203-
const searchInput = document.getElementById('search-input');
204-
const feedItems = document.querySelectorAll('[data-domain]');
205-
206-
// Initialize instance URL field with default value
207-
const instanceInput = document.getElementById('instance-url-input');
208-
209-
if (instanceInput) {
210-
instanceInput.value = defaultInstanceUrl;
211-
instanceUrl = defaultInstanceUrl;
212-
}
213-
214-
// Search functionality
215-
if (searchInput) {
216-
searchInput.addEventListener('input', debounce((e) => {
217-
const query = e.target.value.toLowerCase();
218-
feedItems.forEach(item => {
219-
const searchableText = item.dataset.searchable?.toLowerCase() || '';
220-
item.style.display = fuzzyMatch(searchableText, query) ? 'flex' : 'none';
221-
});
222-
}, 150));
223-
}
224-
225-
// Instance URL updates
226-
if (instanceInput) {
227-
instanceInput.addEventListener('input', debounce((e) => {
228-
instanceUrl = e.target.value || defaultInstanceUrl;
229-
updateFeedUrls();
230-
}, 300));
231-
}
232-
233-
// Parameter forms
234-
document.querySelectorAll('.feed-directory__configure-btn').forEach(button => {
235-
button.addEventListener('click', (e) => {
236-
const targetId = e.target.closest('button').dataset.target;
237-
const form = document.getElementById(targetId);
238-
if (!form) return;
239-
240-
const isExpanded = !form.hidden;
241-
form.hidden = isExpanded;
242-
e.target.closest('button').setAttribute('aria-expanded', !isExpanded);
243-
e.target.closest('button').querySelector('span').textContent = isExpanded ? 'Configure' : 'Hide';
244-
245-
if (!isExpanded) updateFeedUrls();
246-
});
247-
});
248-
249-
// Close forms
250-
document.querySelectorAll('[data-close-form]').forEach(button => {
251-
button.addEventListener('click', (e) => {
252-
const form = e.target.closest('.feed-directory__item-params');
253-
const toggle = document.querySelector(`[data-target="${form.id}"]`);
254-
if (!form || !toggle) return;
255-
256-
form.hidden = true;
257-
toggle.setAttribute('aria-expanded', 'false');
258-
toggle.querySelector('span').textContent = 'Configure';
259-
});
260-
});
261-
262-
// Parameter input updates
263-
document.querySelectorAll('.feed-directory__param-input').forEach(input => {
264-
input.addEventListener('input', debounce(updateFeedUrls, 200));
265-
});
266-
267-
// Initialize feed URLs on page load
268-
updateFeedUrls();
269-
270-
// Update feed URLs
271-
function updateFeedUrls() {
272-
document.querySelectorAll('[data-feed-url]').forEach(link => {
273-
const item = link.closest('[data-domain]');
274-
if (!item) return;
275-
276-
const domain = item.dataset.domain;
277-
const name = item.dataset.name;
278-
if (!domain || !name) return;
279-
280-
// Get parameters
281-
const params = {};
282-
item.querySelectorAll('[data-param-key]').forEach(input => {
283-
if (input.value) params[input.dataset.paramKey] = input.value;
284-
});
285-
286-
// Build URL
287-
let url = instanceUrl.endsWith("/") ? instanceUrl : `${instanceUrl}/`;
288-
url += `${domain}/${name}.rss`;
289-
290-
const queryParams = new URLSearchParams();
291-
Object.entries(params).forEach(([key, value]) => queryParams.append(key, value));
292-
const queryString = queryParams.toString();
293-
if (queryString) url += `?${queryString}`;
294-
295-
link.href = url;
296-
});
297-
}
298-
}
299-
300-
// Initialize when DOM is ready
301-
if (document.readyState === 'loading') {
302-
document.addEventListener('DOMContentLoaded', initializeFeedDirectory);
303-
} else {
304-
initializeFeedDirectory();
305-
}
306-
</script>
171+
<script src="./feed-directory.js"></script>
307172

308173

309174
<style>

src/components/feed-directory.js

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Feed Directory JavaScript functionality
2+
// Simple, focused functions for maintainability
3+
4+
// Simple debounce helper
5+
function debounce(func, wait) {
6+
let timeout;
7+
return function executedFunction(...args) {
8+
const later = () => {
9+
clearTimeout(timeout);
10+
func(...args);
11+
};
12+
clearTimeout(timeout);
13+
timeout = setTimeout(later, wait);
14+
};
15+
}
16+
17+
// Simple fuzzy search
18+
function fuzzyMatch(text, query) {
19+
if (!query) return true;
20+
const lowerText = text.toLowerCase();
21+
const lowerQuery = query.toLowerCase();
22+
let textIndex = 0;
23+
let queryIndex = 0;
24+
while (queryIndex < lowerQuery.length && textIndex < lowerText.length) {
25+
if (lowerQuery[queryIndex] === lowerText[textIndex]) queryIndex++;
26+
textIndex++;
27+
}
28+
return queryIndex === lowerQuery.length;
29+
}
30+
31+
// Search functionality
32+
function setupSearch(searchInput, feedItems) {
33+
if (!searchInput) return;
34+
35+
searchInput.addEventListener('input', debounce((e) => {
36+
const query = e.target.value.toLowerCase();
37+
feedItems.forEach(item => {
38+
const searchableText = item.dataset.searchable?.toLowerCase() || '';
39+
item.style.display = fuzzyMatch(searchableText, query) ? 'flex' : 'none';
40+
});
41+
}, 150));
42+
}
43+
44+
// Instance URL updates
45+
function setupInstanceUrlUpdates(instanceInput, defaultInstanceUrl, updateFeedUrls) {
46+
if (!instanceInput) return;
47+
48+
instanceInput.addEventListener('input', debounce((e) => {
49+
const instanceUrl = e.target.value || defaultInstanceUrl;
50+
updateFeedUrls(instanceUrl);
51+
}, 300));
52+
}
53+
54+
// Parameter forms toggle
55+
function setupParameterForms(updateFeedUrls) {
56+
document.querySelectorAll('.feed-directory__configure-btn').forEach(button => {
57+
button.addEventListener('click', (e) => {
58+
const targetId = e.target.closest('button')?.dataset.target;
59+
const form = document.getElementById(targetId);
60+
if (!form) return;
61+
62+
const isExpanded = !form.hidden;
63+
form.hidden = isExpanded;
64+
const button = e.target.closest('button');
65+
if (button) {
66+
button.setAttribute('aria-expanded', !isExpanded);
67+
const span = button.querySelector('span');
68+
if (span) {
69+
span.textContent = isExpanded ? 'Configure' : 'Hide';
70+
}
71+
}
72+
73+
if (!isExpanded) updateFeedUrls();
74+
});
75+
});
76+
}
77+
78+
// Close forms
79+
function setupCloseForms() {
80+
document.querySelectorAll('[data-close-form]').forEach(button => {
81+
button.addEventListener('click', (e) => {
82+
const form = e.target.closest('.feed-directory__item-params');
83+
const toggle = document.querySelector(`[data-target="${form?.id}"]`);
84+
if (!form || !toggle) return;
85+
86+
form.hidden = true;
87+
toggle.setAttribute('aria-expanded', 'false');
88+
const span = toggle.querySelector('span');
89+
if (span) {
90+
span.textContent = 'Configure';
91+
}
92+
});
93+
});
94+
}
95+
96+
// Parameter input updates
97+
function setupParameterInputs(updateFeedUrls) {
98+
document.querySelectorAll('.feed-directory__param-input').forEach(input => {
99+
input.addEventListener('input', debounce(() => updateFeedUrls(), 200));
100+
});
101+
}
102+
103+
// Update feed URLs
104+
function createUpdateFeedUrlsFunction() {
105+
return function updateFeedUrls(instanceUrl) {
106+
document.querySelectorAll('[data-feed-url]').forEach(link => {
107+
const item = link.closest('[data-domain]');
108+
if (!item) return;
109+
110+
const domain = item.dataset.domain;
111+
const name = item.dataset.name;
112+
if (!domain || !name) return;
113+
114+
// Get parameters
115+
const params = {};
116+
item.querySelectorAll('[data-param-key]').forEach(input => {
117+
if (input.value) params[input.dataset.paramKey] = input.value;
118+
});
119+
120+
// Build URL
121+
let url = instanceUrl.endsWith("/") ? instanceUrl : `${instanceUrl}/`;
122+
url += `${domain}/${name}.rss`;
123+
124+
const queryParams = new URLSearchParams();
125+
Object.entries(params).forEach(([key, value]) => queryParams.append(key, value));
126+
const queryString = queryParams.toString();
127+
if (queryString) url += `?${queryString}`;
128+
129+
link.href = url;
130+
});
131+
}
132+
}
133+
134+
// Main initialization
135+
function initializeFeedDirectory() {
136+
const defaultInstanceUrl = atob("aHR0cHM6Ly8xLmgyci53b3JrZXJzLmRldi8=");
137+
let instanceUrl = defaultInstanceUrl;
138+
const searchInput = document.getElementById('search-input');
139+
const feedItems = document.querySelectorAll('[data-domain]');
140+
const instanceInput = document.getElementById('instance-url-input');
141+
142+
// Initialize instance URL field
143+
if (instanceInput) {
144+
instanceInput.value = defaultInstanceUrl;
145+
instanceUrl = defaultInstanceUrl;
146+
}
147+
148+
// Create update function with current instance URL
149+
const updateFeedUrls = createUpdateFeedUrlsFunction();
150+
151+
// Setup all functionality
152+
setupSearch(searchInput, feedItems);
153+
setupInstanceUrlUpdates(instanceInput, defaultInstanceUrl, (newUrl) => {
154+
instanceUrl = newUrl;
155+
updateFeedUrls(instanceUrl);
156+
});
157+
setupParameterForms(() => updateFeedUrls(instanceUrl));
158+
setupCloseForms();
159+
setupParameterInputs(() => updateFeedUrls(instanceUrl));
160+
161+
// Initialize feed URLs on page load
162+
updateFeedUrls(instanceUrl);
163+
}
164+
165+
// Initialize when DOM is ready
166+
if (document.readyState === 'loading') {
167+
document.addEventListener('DOMContentLoaded', initializeFeedDirectory);
168+
} else {
169+
initializeFeedDirectory();
170+
}

0 commit comments

Comments
 (0)