v1.5
This commit is contained in:
parent
632cd3a0c8
commit
fb8a786f8c
@ -8,6 +8,8 @@ A simple, versatile language processing interface for websites.
|
|||||||
- Adjust opacity of responses
|
- Adjust opacity of responses
|
||||||
- Hidden
|
- Hidden
|
||||||
- Only visible to those who know where to look
|
- Only visible to those who know where to look
|
||||||
|
- Exam mode
|
||||||
|
- Make text selection hard to see to avoid detection
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
After installing the extensions, selecting text and pressing `Ctrl+Space` will display the answer above the selected text in the configured opacity. To hide the answer, press `Ctrl+Space` again without selecting any text.
|
After installing the extensions, selecting text and pressing `Ctrl+Space` will display the answer above the selected text in the configured opacity. To hide the answer, press `Ctrl+Space` again without selecting any text.
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// Constants
|
// contents
|
||||||
const DEFAULT_SETTINGS = {
|
const DEFAULT_SETTINGS = {
|
||||||
apiUrl: "https://api.elia.network",
|
apiUrl: "https://api.elia.network",
|
||||||
apiKey: "sk-TvFhtxHAPXEcmRtyva-ctA",
|
apiKey: "sk-TvFhtxHAPXEcmRtyva-ctA",
|
||||||
textOpacity: 10,
|
textOpacity: 10,
|
||||||
model: "llama3.2-90b",
|
model: "llama3.2-90b",
|
||||||
background: false,
|
background: false,
|
||||||
|
examModeStates: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_CONTEXT_LENGTH = 6000;
|
const MAX_CONTEXT_LENGTH = 6000;
|
||||||
|
@ -18,7 +18,14 @@
|
|||||||
"js": ["content.js"]
|
"js": ["content.js"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"permissions": ["activeTab", "storage", "*://api.elia.network/*"],
|
"permissions": [
|
||||||
|
"activeTab",
|
||||||
|
"storage",
|
||||||
|
"*://api.elia.network/*",
|
||||||
|
"scripting",
|
||||||
|
"tabs",
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
"commands": {
|
"commands": {
|
||||||
"print-selection": {
|
"print-selection": {
|
||||||
"suggested_key": {
|
"suggested_key": {
|
||||||
|
@ -163,6 +163,33 @@
|
|||||||
background: var(--primary-hover);
|
background: var(--primary-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.exam-mode-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--surface);
|
||||||
|
color: var(--text);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exam-mode-button:hover {
|
||||||
|
background: var(--surface-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.exam-mode-button.active {
|
||||||
|
background: #065f46;
|
||||||
|
border-color: #059669;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exam-mode-button.active:hover {
|
||||||
|
background: #047857;
|
||||||
|
}
|
||||||
|
|
||||||
#status {
|
#status {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
@ -181,7 +208,6 @@
|
|||||||
color: #fef2f2;
|
color: #fef2f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scrollbar Styling */
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
@ -204,7 +230,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h2>CAS</h2>
|
<h2>CAS</h2>
|
||||||
<span class="version-badge">v1.4</span>
|
<span class="version-badge">v1.5</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="settingsForm">
|
<form id="settingsForm">
|
||||||
@ -266,6 +292,8 @@
|
|||||||
<button type="submit" class="save-button">Save Settings</button>
|
<button type="submit" class="save-button">Save Settings</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<button id="examMode" class="exam-mode-button">Enable Exam Mode</button>
|
||||||
|
|
||||||
<div id="status"></div>
|
<div id="status"></div>
|
||||||
|
|
||||||
<script src="popup.js"></script>
|
<script src="popup.js"></script>
|
||||||
|
200
src/popup.js
200
src/popup.js
@ -4,14 +4,128 @@ const DEFAULT_SETTINGS = {
|
|||||||
textOpacity: 10,
|
textOpacity: 10,
|
||||||
model: "llama3.2-90b",
|
model: "llama3.2-90b",
|
||||||
background: false,
|
background: false,
|
||||||
|
examModeStates: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load settings when the popup opens
|
// track for each tab
|
||||||
|
const tabStates = new Map();
|
||||||
|
|
||||||
|
async function updateExamModeState(tabId, enabled) {
|
||||||
|
try {
|
||||||
|
const data = await browser.storage.sync.get("settings");
|
||||||
|
const settings = { ...DEFAULT_SETTINGS, ...data.settings };
|
||||||
|
|
||||||
|
settings.examModeStates = {
|
||||||
|
...settings.examModeStates,
|
||||||
|
[tabId]: enabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
await browser.storage.sync.set({ settings });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating exam mode state:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scriptinjector
|
||||||
|
async function injectExamModeScript(enabled) {
|
||||||
|
try {
|
||||||
|
const tabs = await browser.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true,
|
||||||
|
});
|
||||||
|
const tabId = tabs[0].id;
|
||||||
|
|
||||||
|
// update for this tab
|
||||||
|
tabStates.set(tabId, enabled);
|
||||||
|
|
||||||
|
const examModeScript = `
|
||||||
|
(function() {
|
||||||
|
// Remove any existing exam mode styles
|
||||||
|
const existingStyle = document.getElementById('exam-mode-style');
|
||||||
|
if (existingStyle) {
|
||||||
|
existingStyle.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If enabled, add the new style
|
||||||
|
if (${enabled}) {
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.id = 'exam-mode-style';
|
||||||
|
style.textContent = \`
|
||||||
|
::selection {
|
||||||
|
background-color: rgba(0, 0, 255, 0.05) !important;
|
||||||
|
}
|
||||||
|
::-moz-selection {
|
||||||
|
background-color: rgba(0, 0, 255, 0.05) !important;
|
||||||
|
}
|
||||||
|
\`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})();
|
||||||
|
`;
|
||||||
|
|
||||||
|
// inject ;3
|
||||||
|
await browser.tabs.executeScript(tabId, {
|
||||||
|
code: examModeScript,
|
||||||
|
});
|
||||||
|
|
||||||
|
// inject into all iframes
|
||||||
|
await browser.tabs.executeScript(tabId, {
|
||||||
|
code: examModeScript,
|
||||||
|
allFrames: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error injecting exam mode script:", error);
|
||||||
|
if (error.message.includes("non-structured-clonable data")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSettings() {
|
||||||
|
try {
|
||||||
|
const data = await browser.storage.sync.get("settings");
|
||||||
|
const settings = { ...DEFAULT_SETTINGS, ...data.settings };
|
||||||
|
|
||||||
|
// get exam mode status for this tab
|
||||||
|
const tabs = await browser.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true,
|
||||||
|
});
|
||||||
|
const tabId = tabs[0].id;
|
||||||
|
const tabExamMode = settings.examModeStates[tabId] || false;
|
||||||
|
|
||||||
|
return { ...settings, examMode: tabExamMode };
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading settings:", error);
|
||||||
|
return DEFAULT_SETTINGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// exam mode status
|
||||||
|
function updateExamModeButton(enabled) {
|
||||||
|
const button = document.getElementById("examMode");
|
||||||
|
button.textContent = enabled ? "Disable Exam Mode" : "Enable Exam Mode";
|
||||||
|
button.classList.toggle("active", enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStatus(message, type) {
|
||||||
|
const status = document.getElementById("status");
|
||||||
|
status.textContent = message;
|
||||||
|
status.className = type;
|
||||||
|
status.style.display = "block";
|
||||||
|
setTimeout(() => {
|
||||||
|
status.style.display = "none";
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", async () => {
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
try {
|
try {
|
||||||
const settings = await loadSettings();
|
const settings = await loadSettings();
|
||||||
|
// load settings into the form
|
||||||
// Populate form fields
|
|
||||||
document.getElementById("apiUrl").value = settings.apiUrl;
|
document.getElementById("apiUrl").value = settings.apiUrl;
|
||||||
document.getElementById("model").value = settings.model;
|
document.getElementById("model").value = settings.model;
|
||||||
document.getElementById("apiKey").value = settings.apiKey;
|
document.getElementById("apiKey").value = settings.apiKey;
|
||||||
@ -19,23 +133,59 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
document.getElementById("opacityValue").textContent =
|
document.getElementById("opacityValue").textContent =
|
||||||
`${settings.textOpacity}%`;
|
`${settings.textOpacity}%`;
|
||||||
document.getElementById("background").checked = settings.background;
|
document.getElementById("background").checked = settings.background;
|
||||||
|
|
||||||
|
// update button state
|
||||||
|
updateExamModeButton(settings.examMode);
|
||||||
|
|
||||||
|
// if exam mode is enabled, inject the script
|
||||||
|
if (settings.examMode) {
|
||||||
|
await injectExamModeScript(true);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading settings:", error);
|
console.error("Error loading settings:", error);
|
||||||
showStatus("Error loading settings", "error");
|
showStatus("Error loading settings", "error");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle opacity slider changes
|
// handle opacity slider
|
||||||
document.getElementById("textOpacity").addEventListener("input", (e) => {
|
document.getElementById("textOpacity").addEventListener("input", (e) => {
|
||||||
document.getElementById("opacityValue").textContent = `${e.target.value}%`;
|
document.getElementById("opacityValue").textContent = `${e.target.value}%`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle form submission
|
document.getElementById("examMode").addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
const tabs = await browser.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true,
|
||||||
|
});
|
||||||
|
const tabId = tabs[0].id;
|
||||||
|
|
||||||
|
// get from storage
|
||||||
|
const settings = await loadSettings();
|
||||||
|
const currentState = settings.examMode;
|
||||||
|
const newExamMode = !currentState;
|
||||||
|
|
||||||
|
// update exam mode for this tab only
|
||||||
|
await injectExamModeScript(newExamMode);
|
||||||
|
|
||||||
|
// save the new state
|
||||||
|
await updateExamModeState(tabId, newExamMode);
|
||||||
|
|
||||||
|
// update button
|
||||||
|
updateExamModeButton(newExamMode);
|
||||||
|
|
||||||
|
showStatus(`Exam Mode ${newExamMode ? "enabled" : "disabled"}`, "success");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error toggling exam mode:", error);
|
||||||
|
showStatus("Error toggling exam mode", "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// form submission handler
|
||||||
document
|
document
|
||||||
.getElementById("settingsForm")
|
.getElementById("settingsForm")
|
||||||
.addEventListener("submit", async (e) => {
|
.addEventListener("submit", async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
apiUrl: document.getElementById("apiUrl").value,
|
apiUrl: document.getElementById("apiUrl").value,
|
||||||
apiKey: document.getElementById("apiKey").value,
|
apiKey: document.getElementById("apiKey").value,
|
||||||
@ -43,7 +193,6 @@ document
|
|||||||
textOpacity: parseInt(document.getElementById("textOpacity").value),
|
textOpacity: parseInt(document.getElementById("textOpacity").value),
|
||||||
background: document.getElementById("background").checked,
|
background: document.getElementById("background").checked,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await browser.storage.sync.set({ settings });
|
await browser.storage.sync.set({ settings });
|
||||||
showStatus("Settings saved successfully!", "success");
|
showStatus("Settings saved successfully!", "success");
|
||||||
@ -53,30 +202,27 @@ document
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load settings from storage or use defaults
|
browser.tabs.onActivated.addListener(async (activeInfo) => {
|
||||||
async function loadSettings() {
|
const tabId = activeInfo.tabId;
|
||||||
|
const tabExamMode = tabStates.get(tabId) || false;
|
||||||
|
updateExamModeButton(tabExamMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.tabs.onRemoved.addListener(async (tabId) => {
|
||||||
try {
|
try {
|
||||||
const data = await browser.storage.sync.get("settings");
|
const data = await browser.storage.sync.get("settings");
|
||||||
return { ...DEFAULT_SETTINGS, ...data.settings };
|
const settings = { ...DEFAULT_SETTINGS, ...data.settings };
|
||||||
} catch (error) {
|
|
||||||
console.error("Error loading settings:", error);
|
if (settings.examModeStates[tabId]) {
|
||||||
return DEFAULT_SETTINGS;
|
delete settings.examModeStates[tabId];
|
||||||
|
await browser.storage.sync.set({ settings });
|
||||||
}
|
}
|
||||||
}
|
} catch (error) {
|
||||||
|
console.error("Error cleaning up exam mode state:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Show status message
|
// errorhandler
|
||||||
function showStatus(message, type) {
|
|
||||||
const status = document.getElementById("status");
|
|
||||||
status.textContent = message;
|
|
||||||
status.className = type;
|
|
||||||
status.style.display = "block";
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
status.style.display = "none";
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle errors
|
|
||||||
window.addEventListener("error", (event) => {
|
window.addEventListener("error", (event) => {
|
||||||
console.error("Error:", event.error);
|
console.error("Error:", event.error);
|
||||||
showStatus("An error occurred", "error");
|
showStatus("An error occurred", "error");
|
||||||
|
Loading…
Reference in New Issue
Block a user