Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion webapp/_webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
"scripts": {
"dev": "nodemon --watch src --ext ts,js,tsx,jsx,json --exec 'npm run build'",
"dev:chat": "vite dev --config vite.config.dev.ts",
"build": "tsc -b && npm run _build:default && npm run _build:background && npm run _build:intermediate",
"build": "tsc -b && npm run _build:default && npm run _build:background && npm run _build:intermediate && npm run _build:settings && npm run _build:popup",
"_build": "vite build",
"_build:default": "VITE_CONFIG=default npm run _build",
"_build:background": "VITE_CONFIG=background npm run _build",
"_build:intermediate": "VITE_CONFIG=intermediate npm run _build",
"_build:settings": "VITE_CONFIG=settings npm run _build",
"_build:popup": "VITE_CONFIG=popup npm run _build",
"lint": "eslint .",
"format": "prettier --write .",
"build:local:chrome": "bash -c 'source ./scripts/build-local-chrome.sh'",
Expand Down
Binary file added webapp/_webapp/public/images/locator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 9 additions & 111 deletions webapp/_webapp/public/popup.html
Original file line number Diff line number Diff line change
@@ -1,114 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PaperDebugger</title>
<link href="https://fonts.googleapis.com/css2?family=Exo+2:wght@600&display=swap" rel="stylesheet" />
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
padding: 1rem;
padding-left: 1.5rem;
min-width: 280px;
max-width: 340px;
min-height: 220px;
background: #fafafa;
color: #222;
font-family:
"Exo 2",
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
"Helvetica Neue",
Arial,
sans-serif;
border: 1px solid #ececec;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}
.title {
font-size: 1.5rem;
font-weight: 600;
letter-spacing: 0.02em;
text-align: left;
font-family: "Exo 2", sans-serif;
}
.subtitle {
font-size: 1rem;
font-weight: 600;
letter-spacing: 0.02em;
text-align: left;
font-family: "Exo 2", sans-serif;
}
.steps {
margin: 0.5rem 0 0 0;
padding: 0 0rem;
flex: 1;
}
.step {
font-size: 0.9rem;
font-weight: 400;
margin-bottom: 0.7rem;
line-height: 1.5;
border-left: 3px solid #e0e0e0;
padding-left: 0.7em;
background: none;
border-radius: 0;
}
.step strong {
color: #3b82f6;
font-weight: 600;
margin-right: 0.3em;
}
.footer {
font-size: 0.75rem;
text-align: right;
font-weight: 100;
color: #888;
padding: 0.7rem 1.2rem 1.1rem 0;
border-top: 1px solid #ececec;
background: none;
border-radius: 0;
letter-spacing: 0.01em;
}
.highlight {
color: #3b82f6;
font-weight: 600;
}
.noselect {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.nodrag {
-webkit-user-drag: none;
-webkit-user-select: none;
-webkit-user-select: none;
}
</style>
</head>
<body oncontextmenu="return false" class="nodrag">
<div oncontextmenu="return false" class="title noselect">PaperDebugger</div>
<div class="subtitle noselect">How to use</div>
<div class="steps noselect">
<div class="step">
<strong>1.</strong>In
<a class="highlight nodrag" href="https://overleaf.com/project" target="_blank">overleaf.com</a>, open any of
your projects.
</div>
<div class="step"><strong>2.</strong>PaperDebugger is in the <b>top left</b> of the project page.</div>
</div>
<div class="footer noselect">Happy writing!</div>
</body>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PaperDebugger Popup</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="popup.js"></script>
</body>
</html>
13 changes: 13 additions & 0 deletions webapp/_webapp/public/settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PaperDebugger Settings</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="settings.js"></script>
</body>
</html>

13 changes: 12 additions & 1 deletion webapp/_webapp/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { getAllCookies } from "./libs/browser";
import { HANDLER_NAMES } from "./shared/constants";
import { blobToBase64 } from "./libs/helpers";
import { registerContentScripts } from "./libs/permissions";

export type Handler<A, T> = {
name: string;
Expand Down Expand Up @@ -78,12 +79,20 @@ export const fetchImageHandler: Handler<string, string> = {
},
};

export const requestHostPermissionHandler: Handler<string, boolean> = {
name: HANDLER_NAMES.REQUEST_HOST_PERMISSION,
handler: async (origin, sendResponse) => {
const granted = await chrome.permissions.request({ origins: [origin] });
Comment thread
Junyi-99 marked this conversation as resolved.
sendResponse(granted);
},
};
Comment thread
Junyi-99 marked this conversation as resolved.

// @ts-expect-error: browser may not be defined in all environments
const browserAPI = typeof browser !== "undefined" ? browser : chrome;

browserAPI.runtime?.onMessage?.addListener(
(request: { action: string; args: unknown }, _: unknown, sendResponse: (response: unknown) => void) => {
const handlers = [getCookiesHandler, getUrlHandler, getOrCreateSessionIdHandler, fetchImageHandler];
const handlers = [getCookiesHandler, getUrlHandler, getOrCreateSessionIdHandler, fetchImageHandler, requestHostPermissionHandler];

const handler = handlers.find((h) => h.name === request.action) as HandlerAny;
if (!handler) {
Expand All @@ -100,3 +109,5 @@ browserAPI.runtime?.onMessage?.addListener(
return true;
},
);

registerContentScripts();
Comment thread
Junyi-99 marked this conversation as resolved.
Outdated
1 change: 1 addition & 0 deletions webapp/_webapp/src/intermediate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,4 @@ export { getCookies };
export const getUrl = makeFunction<string, string>(HANDLER_NAMES.GET_URL);
export const getOrCreateSessionId = makeFunction<void, string>(HANDLER_NAMES.GET_OR_CREATE_SESSION_ID);
export const fetchImage = makeFunction<string, string>(HANDLER_NAMES.FETCH_IMAGE);
export const requestHostPermission = makeFunction<string, boolean>(HANDLER_NAMES.REQUEST_HOST_PERMISSION);
24 changes: 24 additions & 0 deletions webapp/_webapp/src/libs/permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// can not running in content_script. registerContentScripts can only be called in service_worker.
export async function registerContentScripts() {
const origins = (await chrome.permissions.getAll()).origins || [];
const scriptIds = (await chrome.scripting.getRegisteredContentScripts()).map(script => script.id);

console.log("[PaperDebugger] Unregistering dynamic content scripts", scriptIds);
await chrome.scripting.unregisterContentScripts({ ids: scriptIds });

await chrome.scripting.registerContentScripts([{
id: "content-script-main",
js: ["paperdebugger.js"],
persistAcrossSessions: true,
matches: origins,
world: "MAIN",
}, {
id: "content-script-intermediate",
js: ["intermediate.js"],
persistAcrossSessions: true,
matches: origins,
runAt: "document_start"
}])
Comment thread
Junyi-99 marked this conversation as resolved.
Outdated
Comment thread
Junyi-99 marked this conversation as resolved.
Outdated

console.log("[PaperDebugger] Registration complete", origins);
}
2 changes: 2 additions & 0 deletions webapp/_webapp/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ export const Main = () => {
);
};

console.log("[PaperDebugger] PaperDebugger injected, find toolbar-left or ide-redesign-toolbar-menu-bar to add button");

if (!import.meta.env.DEV) {
onElementAppeared(".toolbar-left .toolbar-item, .ide-redesign-toolbar-menu-bar", () => {
logInfo("initializing");
Expand Down
37 changes: 20 additions & 17 deletions webapp/_webapp/src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,34 @@
"128": "images/logo-1024.png",
"48": "images/logo-1024.png"
},
"host_permissions": ["*://*.overleaf.com/"],
"permissions": ["cookies", "storage"],
"host_permissions": [
"*://*.overleaf.com/"
],
"optional_host_permissions": [
"*://*/*"
],
Comment thread
Junyi-99 marked this conversation as resolved.
Outdated
"permissions": [
"cookies",
"storage",
"scripting",
"activeTab"
],
"options_page": "settings.html",
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"js": ["paperdebugger.js"],
"matches": ["https://*.overleaf.com/project/*"],
"world": "MAIN"
},
{
"js": ["intermediate.js"],
"matches": ["https://*.overleaf.com/project/*"],
"run_at": "document_start"
}
],
"web_accessible_resources": [
{
"resources": ["images/*"],
"matches": ["https://*.overleaf.com/*"]
"resources": [
"images/*"
],
"matches": [
"*://*/*"
]
}
],
"key": "[AUTO-GENERATED]"
}
}
40 changes: 40 additions & 0 deletions webapp/_webapp/src/popup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* popup.ts
*
* Script for the extension popup page.
* Handles the request host permission button click.
*/

// Disable context menu (right-click) to comply with CSP
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
return false;
});

document.getElementById('myButton')?.addEventListener('click', async () => {
const origin = "https://www.google.com/";

try {
// 直接调用 background script,类似于 intermediate.ts 中的实现
Comment thread
Junyi-99 marked this conversation as resolved.
Outdated
const response = await chrome.runtime.sendMessage({
action: "requestHostPermission",
args: origin,
});

if (response?.error) {
console.error("Error requesting permissions:", response.error);
alert(`Permission request failed: ${response.error}`);
} else if (response === true) {
console.log(`Permission granted for ${origin}`);
alert(`Permission granted for ${origin}`);
} else {
console.log(`Permission denied for ${origin}`);
alert(`Permission denied for ${origin}`);
}
} catch (error) {
console.error("Error requesting permissions:", error);
const errorMessage = error instanceof Error ? error.message : String(error);
alert(`Error: ${errorMessage}`);
}
});

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file (popup.ts) appears to be unused/dead code. The popup is implemented using React in src/views/extension-popup/app.tsx, making this vanilla JavaScript implementation redundant. Additionally, it references a non-existent myButton element and contains hardcoded test logic for requesting Google permissions. Consider removing this file.

Suggested change
/*
* popup.ts
*
* Script for the extension popup page.
* Handles the request host permission button click.
*/
// Disable context menu (right-click) to comply with CSP
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
return false;
});
document.getElementById('myButton')?.addEventListener('click', async () => {
const origin = "https://www.google.com/";
try {
// 直接调用 background script,类似于 intermediate.ts 中的实现
const response = await chrome.runtime.sendMessage({
action: "requestHostPermission",
args: origin,
});
if (response?.error) {
console.error("Error requesting permissions:", response.error);
alert(`Permission request failed: ${response.error}`);
} else if (response === true) {
console.log(`Permission granted for ${origin}`);
alert(`Permission granted for ${origin}`);
} else {
console.log(`Permission denied for ${origin}`);
alert(`Permission denied for ${origin}`);
}
} catch (error) {
console.error("Error requesting permissions:", error);
const errorMessage = error instanceof Error ? error.message : String(error);
alert(`Error: ${errorMessage}`);
}
});

Copilot uses AI. Check for mistakes.
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
1 change: 1 addition & 0 deletions webapp/_webapp/src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export const HANDLER_NAMES = {
GET_URL: "getUrl",
GET_OR_CREATE_SESSION_ID: "getOrCreateSessionId",
FETCH_IMAGE: "fetchImage",
REQUEST_HOST_PERMISSION: "requestHostPermission",
} as const;
Loading