Skip to content

Commit dee51eb

Browse files
authored
Merge pull request #45 from jacobtender/jrt-refresh-button
Add a refresh button
2 parents b29c3e2 + 80bf47e commit dee51eb

File tree

10 files changed

+677
-10
lines changed

10 files changed

+677
-10
lines changed

build.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ async function buildScripts(outDir) {
4848
logLevel: "info",
4949
treeShaking: false,
5050
});
51+
52+
// Popup (separately, as module)
53+
const popupEntry = path.join(SRC_DIR, "popup", "main.js");
54+
const popupOutFile = path.join(outDir, "popup.js");
55+
56+
const popupDir = path.dirname(popupOutFile);
57+
if (!fs.existsSync(popupDir)) fs.mkdirSync(popupDir, { recursive: true });
58+
59+
await esbuild.build({
60+
entryPoints: [popupEntry],
61+
outfile: popupOutFile,
62+
bundle: true,
63+
format: "iife",
64+
platform: "browser",
65+
target: ["chrome109"],
66+
logLevel: "info",
67+
treeShaking: false,
68+
});
5169
}
5270

5371
async function build(target) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "marian-extension",
3-
"version": "1.6.0",
3+
"version": "1.7.0",
44
"description": "Extracts book details from Amazon product pages. Created for the fine librarian corps of Hardcover.app.",
55
"main": "background.js",
66
"scripts": {

src/background.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,17 @@ chrome.action.onClicked.addListener((tab) => {
7979
sendWhenReady({ type: "REFRESH_SIDEBAR", url: tab.url });
8080
}, 300); // give the sidebar a moment to load
8181
});
82+
83+
// when tab URL changes in the current active tab
84+
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
85+
if (tab.active && changeInfo.url) {
86+
chrome.runtime.sendMessage({ type: "TAB_URL_CHANGED", url: changeInfo.url });
87+
}
88+
});
89+
90+
// when the active tab changes
91+
chrome.tabs.onActivated.addListener(() => {
92+
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
93+
chrome.runtime.sendMessage({ type: "TAB_URL_CHANGED", url: tab?.url || "" });
94+
});
95+
});

src/manifest.base.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"https://www.amazon.se/*dp/*",
4545
"https://www.amazon.com.tr/*dp/*",
4646
"https://www.amazon.ae/*dp/*",
47+
4748
"https://www.amazon.com/gp/product/*",
4849
"https://www.amazon.co.uk/gp/product/*",
4950
"https://www.amazon.com.au/gp/product/*",
@@ -65,6 +66,7 @@
6566
"https://www.amazon.se/gp/product/*",
6667
"https://www.amazon.com.tr/gp/product/*",
6768
"https://www.amazon.ae/gp/product/*",
69+
6870
"https://www.goodreads.com/book/show/*",
6971
"https://app.thestorygraph.com/books/*",
7072
"https://www.google.com/books/*",
File renamed without changes.

src/popup.html

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,47 @@
105105
padding: 12px;
106106
}
107107

108-
/* sticky footer */
109-
#footer {
110-
flex-shrink: 0;
108+
#refresh-button {
109+
width: 100%;
111110
display: flex;
112-
flex-direction: column;
113111
align-items: center;
114-
gap: 6px;
115-
padding: 8px 12px;
116-
background: #0f2233;
117-
border-top: 2px solid #384151;
112+
justify-content: center;
113+
background: rgba(255, 255, 255, 0.05);
114+
border-radius: 6px;
115+
padding: 8px;
116+
margin: 10px 0 12px;
117+
font-size: 13px;
118+
line-height: 1.4em;
119+
border: none;
120+
cursor: pointer;
121+
color: black;
122+
}
123+
124+
#refresh-button.refresh-enabled {
125+
background-color: #E6B313;
126+
color: #000;
127+
cursor: pointer;
128+
border-bottom: 2px solid #B8970B;
129+
margin-bottom: 10px;
130+
}
131+
132+
#refresh-button.refresh-enabled:active {
133+
background-color: #d6a912; /* slightly darker yellow */
134+
border: none;
135+
transform: translateY(1px);
136+
margin-bottom: 12px;
137+
}
138+
139+
#refresh-button.refresh-disabled {
140+
background-color: rgba(255, 255, 255, 0.05);
141+
color: #cbd5e1;
142+
cursor: not-allowed;
143+
}
144+
145+
#refresh-button.refresh-unsupported {
146+
background-color: rgba(255, 255, 255, 0.05);
147+
color: #cbd5e1;
148+
cursor: not-allowed;
118149
}
119150

120151
#hardcover-callout,
@@ -132,6 +163,18 @@
132163
margin: 10px 0;
133164
}
134165

166+
/* sticky footer */
167+
#footer {
168+
flex-shrink: 0;
169+
display: flex;
170+
flex-direction: column;
171+
align-items: center;
172+
gap: 6px;
173+
padding: 8px 12px;
174+
background: #0f2233;
175+
border-top: 2px solid #384151;
176+
}
177+
135178
#hardcover-callout img {
136179
height: 32px;
137180
width: auto;
@@ -179,7 +222,7 @@
179222
<button id="download-json">Download JSON</button>
180223
<button id="download-csv">Download CSV</button>
181224
</div> -->
182-
<script src="popup.js"></script>
225+
<script type="module" src="./popup.js"></script>
183226

184227
<footer id="footer">
185228
<div id="hardcover-callout">

src/popup/main.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { isAllowedUrl } from "../shared/allowed-patterns.js";
2+
import { tryGetDetails } from "./messaging.js";
3+
import { showStatus, showDetails, renderDetails, initSidebarLogger,
4+
addRefreshButton, updateRefreshButtonForUrl } from "./ui.js";
5+
import { setLastFetchedUrl } from "./utils.js";
6+
7+
const DEBUG = false;
8+
9+
document.addEventListener("DOMContentLoaded", () => {
10+
if (DEBUG) initSidebarLogger(); // DEBUG: Initialize sidebar logger
11+
12+
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
13+
const url = tab?.url || "";
14+
15+
updateRefreshButtonForUrl(url);
16+
17+
if (!isAllowedUrl(url)) {
18+
showStatus("This extension only works on supported product pages.");
19+
return;
20+
}
21+
22+
showStatus("DOM Loaded, fetching details...");
23+
tryGetDetails()
24+
.then(details => {
25+
showDetails();
26+
const detailsEl = document.getElementById('details');
27+
if (detailsEl) detailsEl.innerHTML = "";
28+
renderDetails(details);
29+
30+
addRefreshButton(() => {
31+
showStatus("Refreshing...");
32+
tryGetDetails()
33+
.then(details => {
34+
showDetails();
35+
renderDetails(details);
36+
})
37+
.catch(err => showStatus(err));
38+
});
39+
40+
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
41+
const currentUrl = tab?.url || '';
42+
setLastFetchedUrl(currentUrl);
43+
updateRefreshButtonForUrl(currentUrl);
44+
});
45+
})
46+
.catch(err => {
47+
showStatus(err);
48+
});
49+
});
50+
});
51+
52+
// Keep your sidebar listener behavior exactly the same
53+
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
54+
if (msg.type === "ping") {
55+
sendResponse("pong");
56+
return;
57+
}
58+
59+
if (msg.type === "REFRESH_SIDEBAR" && msg.url && isAllowedUrl(msg.url)) {
60+
showStatus("Loading details...");
61+
tryGetDetails()
62+
.then(details => {
63+
showDetails();
64+
// clear previous content (matches your original)
65+
const detailsEl = document.getElementById('details');
66+
if (detailsEl) detailsEl.innerHTML = "";
67+
renderDetails(details);
68+
69+
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
70+
const currentUrl = tab?.url || '';
71+
setLastFetchedUrl(currentUrl);
72+
updateRefreshButtonForUrl(currentUrl);
73+
});
74+
})
75+
.catch(err => {
76+
showStatus(err);
77+
});
78+
}
79+
80+
if (msg.type === "TAB_URL_CHANGED") {
81+
updateRefreshButtonForUrl(msg.url);
82+
}
83+
});

src/popup/messaging.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { showStatus } from "./ui.js";
2+
3+
function buildIssueUrl(tabUrl) {
4+
const domain = new URL(tabUrl).hostname.replace(/^www\./, '');
5+
const title = `Unsupported URL detected on ${domain}`;
6+
const body = [
7+
'This page is not currently supported by Marian:',
8+
'',
9+
tabUrl,
10+
'',
11+
'**Steps to reproduce:**',
12+
'1. Open the above URL with the extension installed',
13+
'2. Open the extension sidebar',
14+
'3. See that details are not loaded',
15+
'',
16+
'**Expected behavior:**',
17+
'Details should load for supported product pages.'
18+
].join('\n');
19+
20+
return 'https://github.com/jacobtender/marian-extension/issues/new'
21+
+ `?title=${encodeURIComponent(title)}`
22+
+ `&body=${encodeURIComponent(body)}`
23+
+ `&labels=${encodeURIComponent('bug')}`;
24+
}
25+
26+
// Polling function to try multiple times before giving up (unchanged behavior)
27+
export function tryGetDetails(retries = 8, delay = 300) {
28+
let didRefresh = false;
29+
30+
return new Promise((resolve, reject) => {
31+
function attempt(remaining) {
32+
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
33+
if (!tab?.id) {
34+
reject('No active tab found.');
35+
return;
36+
}
37+
38+
chrome.tabs.sendMessage(tab.id, 'ping', (response) => {
39+
console.log('Ping response:', response, 'Remaining attempts:', remaining);
40+
if (chrome.runtime.lastError || response !== 'pong') {
41+
if (remaining > 0) {
42+
setTimeout(() => attempt(remaining - 1), delay);
43+
} else {
44+
if (!didRefresh) {
45+
didRefresh = true;
46+
// showStatus("Content script not ready, refreshing tab...");
47+
chrome.tabs.reload(tab.id, { bypassCache: true });
48+
showStatus("Tab reloaded, fetching details...");
49+
50+
const onUpdated = (updatedTabId, info) => {
51+
if (updatedTabId === tab.id && info.status === 'complete') {
52+
chrome.tabs.onUpdated.removeListener(onUpdated);
53+
console.log(retries, 'Tab reloaded, fetching details again...');
54+
setTimeout(() => attempt(retries), 350);
55+
}
56+
};
57+
chrome.tabs.onUpdated.addListener(onUpdated);
58+
} else {
59+
const issueUrl = buildIssueUrl(tab?.url || '(unknown URL)');
60+
showStatus(`
61+
This site is supported, but this page isn't yet.<br/>
62+
Please <a href="${issueUrl}" target="_blank" rel="noopener noreferrer">report</a> the full URL of this page so we can add support!
63+
`);
64+
// reject('Unsupported URL or no content script after refresh.');
65+
}
66+
}
67+
return;
68+
}
69+
70+
chrome.tabs.sendMessage(tab.id, 'getDetails', (details) => {
71+
if (chrome.runtime.lastError || !details) {
72+
reject('Failed to retrieve book details.');
73+
return;
74+
}
75+
resolve(details);
76+
});
77+
});
78+
});
79+
}
80+
attempt(retries);
81+
});
82+
}

0 commit comments

Comments
 (0)