-
Notifications
You must be signed in to change notification settings - Fork 9
/
script.js
209 lines (167 loc) · 7.17 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
class TechMaterialsApp {
constructor() {
this.materials = [];
this.isDarkMode = false;
this.init();
}
async init() {
try {
const storedDarkMode = localStorage.getItem('darkMode');
if (storedDarkMode === 'true') {
this.isDarkMode = true;
this.updateTheme();
}
await this.loadMaterials();
this.setupEventListeners();
this.renderMaterials();
this.updateTheme();
} catch (error) {
this.showError('Failed to initialize the application');
}
}
async loadMaterials() {
try {
// Fetch data from 'data.json'
const response = await fetch('data.json');
if (!response.ok) throw new Error('Failed to load materials from data.json');
const fileMaterials = await response.json();
// Fetch data from localStorage
const localStorageMaterials = JSON.parse(localStorage.getItem('materials')) || [];
// Merge materials from 'data.json' and localStorage
this.materials = [...fileMaterials, ...localStorageMaterials];
console.log(this.materials);
} catch (error) {
console.error('Error loading materials:', error);
throw new Error('Error loading materials: ' + error.message);
}
}
setupEventListeners() {
// Form submission
document.getElementById('materialForm').addEventListener('submit', (e) => {
e.preventDefault();
this.handleFormSubmission();
});
// Search functionality
document.getElementById('searchInput').addEventListener('input', (e) => {
this.handleSearch(e.target.value);
});
// Theme toggle button
const toggleButton = document.getElementById('toggleTheme');
toggleButton.addEventListener('click', () => {
this.toggleTheme();
});
}
handleFormSubmission() {
const contributor = this.escapeHtml(document.getElementById('contributor').value);
const resourceName = this.escapeHtml(document.getElementById('resourceName').value);
const link = this.escapeHtml(document.getElementById('link').value);
const tags = document.getElementById('tags').value;
const newMaterial = {
contributor,
resourceName,
link,
tags: tags.split(',').map(tag => tag.trim())
};
this.addMaterial(newMaterial);
this.resetForm();
}
addMaterial(material) {
// Retrieve the existing materials array from local storage or initialize it as an empty array
let storedMaterials = JSON.parse(localStorage.getItem('materials')) || [];
// Add the new material to the materials array
storedMaterials.push(material);
// Save the updated materials array back to local storage
localStorage.setItem('materials', JSON.stringify(storedMaterials));
// Update the local state if needed (e.g., for rendering purposes)
this.materials = storedMaterials;
this.renderMaterials();
console.log(material);
}
resetForm() {
document.getElementById('materialForm').reset();
}
handleSearch(searchTerm) {
const filteredMaterials = this.materials.filter(material => {
const searchString = `${material.contributor} ${material.resourceName} ${material.tags.join(' ')}`.toLowerCase();
return searchString.includes(searchTerm.toLowerCase());
});
this.renderMaterials(filteredMaterials);
}
async renderMaterials() {
try {
// Fetch data from 'data.json'
const response = await fetch('data.json');
if (!response.ok) throw new Error('Failed to load materials from data.json');
const fileMaterials = await response.json();
// Fetch data from localStorage
const localStorageMaterials = JSON.parse(localStorage.getItem('materials')) || [];
// Merge materials from 'data.json' and localStorage
const combinedMaterials = [...fileMaterials, ...localStorageMaterials];
// Now render the combined materials
const container = document.getElementById('materialsList');
container.innerHTML = '';
combinedMaterials.forEach(material => {
const card = this.createMaterialCard(material);
container.appendChild(card);
});
} catch (error) {
console.error('Error rendering materials:', error);
}
}
createMaterialCard(material) {
const card = document.createElement('div');
card.className = 'material-card';
card.innerHTML = `
<h3>${this.escapeHtml(material.resourceName)}</h3>
<p><strong>Contributor:</strong> ${this.escapeHtml(material.contributor)}</p>
<p><strong>Link:</strong> <a href="${this.escapeHtml(material.link)}" target="_blank">${this.escapeHtml(material.link)}</a></p>
<div class="tags">
${material.tags.map(tag => `<span class="tag">${this.escapeHtml(tag)}</span>`).join('')}
</div>
`;
return card;
}
escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
//in cases where escapeHtml is used for href attributes
escapeHtmlAttribute(unsafe){
return unsafe.replace(/"/g, """).replace(/'/g, "'");
} // now links can be used like this::: <a href="${this.escapeHtmlAttribute(material.link)}" target="_blank">${this.escapeHtml(material.link)}</a>
showError(message) {
console.error(message);
// You could implement a more user-friendly error display here
}
toggleTheme() {
this.isDarkMode = !this.isDarkMode;
this.updateTheme();
localStorage.setItem('darkMode', this.isDarkMode);
}
updateTheme() {
const body = document.body;
const addMaterialSection = document.querySelector('.add-material');
const materialCards = document.querySelectorAll('.material-card');
const header = document.querySelector('h1');
const labels = document.querySelectorAll('label');
if (this.isDarkMode) {
body.classList.add('dark-mode');
addMaterialSection.classList.add('dark-mode');
materialCards.forEach(card => card.classList.add('dark-mode'));
header.classList.add(' dark-mode');
labels.forEach(label => label.classList.add('dark-mode'));
} else {
body.classList.remove('dark-mode');
addMaterialSection.classList.remove('dark-mode');
materialCards.forEach(card => card.classList.remove('dark-mode'));
header.classList.remove('dark-mode');
labels.forEach(label => label.classList.remove('dark-mode'));
}
}
}
// Initialize the application
new TechMaterialsApp();