Skip to content

Commit e6a0243

Browse files
authored
Merge pull request #4 from kiing-dom/issues/options-always-accessible
fix: resolved issue with popup content
2 parents 27ae81d + c27525d commit e6a0243

File tree

2 files changed

+126
-115
lines changed

2 files changed

+126
-115
lines changed

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 2,
33
"name": "KeepCode",
4-
"version": "0.1.0",
4+
"version": "0.2.0",
55
"description": "Focus on answering problems, let KeepCode handle the rest",
66
"permissions": ["storage", "tabs", "activeTab", "https://leetcode.com/*"],
77
"background": {

popup/popup.js

Lines changed: 125 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
document.addEventListener("DOMContentLoaded", () => {
22
browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
33
const tab = tabs[0];
4-
// Get the problem slug from the URL
4+
55
const url = new URL(tab.url);
66
const pathParts = url.pathname.split("/").filter(Boolean);
77
const slug = pathParts[1] || null;
88
if (!slug) {
9-
document.body.innerHTML = "<p>Not a leetcode problem page</p>";
9+
document.getElementById("popupContent").innerHTML = "<p>To track a problem, please visit a leetcode problem page</p>";
1010
return;
1111
}
12-
// Ask background for the latest problem data
13-
browser.runtime.sendMessage({ type: "GET_PROBLEM_DATA", slug })
12+
13+
browser.runtime
14+
.sendMessage({ type: "GET_PROBLEM_DATA", slug })
1415
.then((data) => {
16+
const container = document.getElementById("popupContent");
1517
if (!data) {
16-
document.body.innerHTML = "<p>Not a leetcode problem page</p>";
18+
container.innerHTML = "<p>To track a problem please visit a leetcode problem page</p>";
1719
return;
1820
}
19-
const container = document.getElementById("popupContent");
2021

2122
container.innerHTML = "";
2223
const titleEl = document.createElement("h3");
@@ -34,133 +35,143 @@ document.addEventListener("DOMContentLoaded", () => {
3435

3536
// Listen for problem solved message
3637
browser.runtime.onMessage.addListener((msg) => {
37-
if (msg.type === "PROBLEM_SOLVED" && msg.slug === data.slug) {
38-
const statusEl = document.getElementById("status");
39-
if (statusEl) statusEl.textContent = "Solved ✅";
40-
}
38+
if (msg.type === "PROBLEM_SOLVED" && msg.slug === data.slug) {
39+
const statusEl = document.getElementById("status");
40+
if (statusEl) statusEl.textContent = "Solved ✅";
41+
}
4142
});
4243
})
4344
.catch((err) => {
44-
document.body.innerHTML = "<p>Unable to read this page</p>";
45+
document.getElementById("popupContent").innerHTML = "<p>Unable to read this page</p>";
4546
console.error(err);
4647
});
4748
});
4849
});
4950

5051
document.addEventListener("DOMContentLoaded", () => {
51-
browser.storage.local.get(null).then((allData) => {
52-
// Filter out invalid/undefined problems before displaying
53-
const problems = Object.values(allData).filter(p =>
54-
p &&
55-
typeof p.title === 'string' && p.title !== 'Unknown Title' &&
56-
typeof p.slug === 'string' && p.slug !== 'unknown-problem' &&
57-
typeof p.difficulty === 'string' && p.difficulty !== 'Unknown Difficulty' &&
58-
p.status === "Solved"
59-
);
60-
// Sort by solvedAt descending (most recent first)
61-
problems.sort((a, b) => (b.solvedAt || 0) - (a.solvedAt || 0));
52+
browser.storage.local.get(null).then((allData) => {
53+
// Filter out invalid/undefined problems before displaying
54+
const problems = Object.values(allData).filter(
55+
(p) =>
56+
p &&
57+
typeof p.title === "string" &&
58+
p.title !== "Unknown Title" &&
59+
typeof p.slug === "string" &&
60+
p.slug !== "unknown-problem" &&
61+
typeof p.difficulty === "string" &&
62+
p.difficulty !== "Unknown Difficulty" &&
63+
p.status === "Solved"
64+
);
65+
// Sort by solvedAt descending (most recent first)
66+
problems.sort((a, b) => (b.solvedAt || 0) - (a.solvedAt || 0));
6267

63-
// Collect all unique tags (flattened)
64-
const tagSet = new Set();
65-
problems.forEach(p => {
66-
if (Array.isArray(p.tags)) {
67-
p.tags.forEach(tag => tagSet.add(tag));
68-
}
68+
// Collect all unique tags (flattened)
69+
const tagSet = new Set();
70+
problems.forEach((p) => {
71+
if (Array.isArray(p.tags)) {
72+
p.tags.forEach((tag) => tagSet.add(tag));
73+
}
74+
});
75+
const tags = Array.from(tagSet);
76+
77+
// Populate tag filter dropdown
78+
const tagFilter = document.getElementById("tagFilter");
79+
if (tagFilter) {
80+
// Remove old options except 'All'
81+
tagFilter.innerHTML = '<option value="all">All</option>';
82+
if (tags.length > 0) {
83+
tags.forEach((tag) => {
84+
const opt = document.createElement("option");
85+
opt.value = tag;
86+
opt.textContent = tag;
87+
tagFilter.appendChild(opt);
6988
});
70-
const tags = Array.from(tagSet);
89+
} else {
90+
const opt = document.createElement("option");
91+
opt.value = "none";
92+
opt.textContent = "No tags";
93+
tagFilter.appendChild(opt);
94+
}
95+
}
7196

72-
// Populate tag filter dropdown
73-
const tagFilter = document.getElementById("tagFilter");
74-
if (tagFilter) {
75-
// Remove old options except 'All'
76-
tagFilter.innerHTML = '<option value="all">All</option>';
77-
if (tags.length > 0) {
78-
tags.forEach(tag => {
79-
const opt = document.createElement("option");
80-
opt.value = tag;
81-
opt.textContent = tag;
82-
tagFilter.appendChild(opt);
83-
});
84-
} else {
85-
const opt = document.createElement("option");
86-
opt.value = "none";
87-
opt.textContent = "No tags";
88-
tagFilter.appendChild(opt);
89-
}
90-
}
97+
// Render problems (filtered and limited)
98+
function renderProblems() {
99+
const list = document.getElementById("solvedList");
100+
list.innerHTML = "";
101+
let filtered = problems;
102+
const selectedTag = tagFilter ? tagFilter.value : "all";
103+
if (selectedTag && selectedTag !== "all" && selectedTag !== "none") {
104+
filtered = problems.filter(
105+
(p) => Array.isArray(p.tags) && p.tags.includes(selectedTag)
106+
);
107+
}
108+
const toShow = filtered.slice(0, 5);
109+
if (toShow.length === 0) {
110+
list.innerHTML = "<p>No solved problems yet</p>";
111+
}
112+
toShow.forEach((problem) => {
113+
const item = document.createElement("div");
114+
item.className = "problem-item";
115+
const difficultyClass = problem.difficulty
116+
? problem.difficulty.toLowerCase()
117+
: "";
118+
// Use DOM methods instead of innerHTML for safety
119+
const link = document.createElement("a");
120+
link.href = problem.url;
121+
link.target = "_blank";
122+
link.textContent = problem.title;
91123

92-
// Render problems (filtered and limited)
93-
function renderProblems() {
94-
const list = document.getElementById("solvedList");
95-
list.innerHTML = "";
96-
let filtered = problems;
97-
const selectedTag = tagFilter ? tagFilter.value : "all";
98-
if (selectedTag && selectedTag !== "all" && selectedTag !== "none") {
99-
filtered = problems.filter(p => Array.isArray(p.tags) && p.tags.includes(selectedTag));
100-
}
101-
const toShow = filtered.slice(0, 5);
102-
if (toShow.length === 0) {
103-
list.innerHTML = "<p>No solved problems yet</p>";
104-
}
105-
toShow.forEach(problem => {
106-
const item = document.createElement("div");
107-
item.className = "problem-item";
108-
const difficultyClass = problem.difficulty ? problem.difficulty.toLowerCase() : "";
109-
// Use DOM methods instead of innerHTML for safety
110-
const link = document.createElement('a');
111-
link.href = problem.url;
112-
link.target = '_blank';
113-
link.textContent = problem.title;
124+
const diffSpan = document.createElement("span");
125+
diffSpan.className = `difficulty ${difficultyClass}`;
126+
diffSpan.textContent = problem.difficulty;
114127

115-
const diffSpan = document.createElement('span');
116-
diffSpan.className = `difficulty ${difficultyClass}`;
117-
diffSpan.textContent = problem.difficulty;
128+
const tagsSpan = document.createElement("span");
129+
tagsSpan.style.fontSize = "0.85em";
130+
tagsSpan.style.color =
131+
problem.tags && problem.tags.length > 0 ? "#666" : "#bbb";
132+
tagsSpan.style.marginLeft = "8px";
133+
tagsSpan.textContent =
134+
problem.tags && problem.tags.length > 0
135+
? `[${problem.tags.join(", ")}]`
136+
: "[No tags]";
118137

119-
const tagsSpan = document.createElement('span');
120-
tagsSpan.style.fontSize = '0.85em';
121-
tagsSpan.style.color = problem.tags && problem.tags.length > 0 ? '#666' : '#bbb';
122-
tagsSpan.style.marginLeft = '8px';
123-
tagsSpan.textContent = problem.tags && problem.tags.length > 0
124-
? `[${problem.tags.join(', ')}]`
125-
: '[No tags]';
138+
item.appendChild(link);
139+
item.appendChild(diffSpan);
140+
item.appendChild(tagsSpan);
141+
list.appendChild(item);
142+
});
143+
}
126144

127-
item.appendChild(link);
128-
item.appendChild(diffSpan);
129-
item.appendChild(tagsSpan);
130-
list.appendChild(item);
131-
});
132-
}
145+
if (tagFilter) {
146+
tagFilter.addEventListener("change", renderProblems);
147+
}
148+
renderProblems();
149+
});
133150

134-
if (tagFilter) {
135-
tagFilter.addEventListener("change", renderProblems);
136-
}
137-
renderProblems();
151+
// View All link opens options page
152+
const viewAllLink = document.getElementById("viewAllLink");
153+
if (viewAllLink) {
154+
viewAllLink.addEventListener("click", (e) => {
155+
e.preventDefault();
156+
if (browser.runtime && browser.runtime.openOptionsPage) {
157+
browser.runtime.openOptionsPage();
158+
} else {
159+
window.open("../options/options.html", "_blank");
160+
}
138161
});
139-
140-
// View All link opens options page
141-
const viewAllLink = document.getElementById("viewAllLink");
142-
if (viewAllLink) {
143-
viewAllLink.addEventListener("click", (e) => {
144-
e.preventDefault();
145-
if (browser.runtime && browser.runtime.openOptionsPage) {
146-
browser.runtime.openOptionsPage();
147-
} else {
148-
window.open("../options/options.html", "_blank");
149-
}
150-
});
151-
}
162+
}
152163
});
153164

154165
document.addEventListener("DOMContentLoaded", () => {
155-
const optionsBtn = document.getElementById("optionsBtn");
156-
if (optionsBtn) {
157-
optionsBtn.addEventListener("click", () => {
158-
if (browser.runtime && browser.runtime.openOptionsPage) {
159-
browser.runtime.openOptionsPage();
160-
} else {
161-
// fallback for browsers that don't support openOptionsPage
162-
window.open("../options/options.html", "_blank");
163-
}
164-
});
165-
}
166+
const optionsBtn = document.getElementById("optionsBtn");
167+
if (optionsBtn) {
168+
optionsBtn.addEventListener("click", () => {
169+
if (browser.runtime && browser.runtime.openOptionsPage) {
170+
browser.runtime.openOptionsPage();
171+
} else {
172+
// fallback for browsers that don't support openOptionsPage
173+
window.open("../options/options.html", "_blank");
174+
}
175+
});
176+
}
166177
});

0 commit comments

Comments
 (0)