added logic to always show site text count
This commit is contained in:
@@ -596,6 +596,7 @@ async function refreshToolbar() {
|
|||||||
|
|
||||||
|
|
||||||
let refreshTimer = null;
|
let refreshTimer = null;
|
||||||
|
let contentChangeTimer = null;
|
||||||
function scheduleToolbarRefresh() {
|
function scheduleToolbarRefresh() {
|
||||||
if (refreshTimer) return;
|
if (refreshTimer) return;
|
||||||
refreshTimer = window.setTimeout(() => {
|
refreshTimer = window.setTimeout(() => {
|
||||||
@@ -610,9 +611,22 @@ function scheduleToolbarRefresh() {
|
|||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scheduleContentChangeNotice() {
|
||||||
|
if (contentChangeTimer) return;
|
||||||
|
contentChangeTimer = window.setTimeout(() => {
|
||||||
|
contentChangeTimer = null;
|
||||||
|
chrome.runtime.sendMessage({ type: "SITE_CONTENT_CHANGED" }, () => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
|
||||||
const observer = new MutationObserver(() => {
|
const observer = new MutationObserver(() => {
|
||||||
if (suppressObserver) return;
|
if (suppressObserver) return;
|
||||||
scheduleToolbarRefresh();
|
scheduleToolbarRefresh();
|
||||||
|
scheduleContentChangeNotice();
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(document.documentElement, { childList: true, subtree: true });
|
observer.observe(document.documentElement, { childList: true, subtree: true });
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<span id="postingCount">Site Text: 0 chars</span>
|
<span id="postingCount">Site Text: 0 chars</span>
|
||||||
<span id="promptCount">Task: 0 chars</span>
|
<span id="promptCount">Total: 0 chars</span>
|
||||||
<span id="status" class="status">Idle</span>
|
<span id="status" class="status">Idle</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -57,7 +57,9 @@ const state = {
|
|||||||
selectedTaskId: "",
|
selectedTaskId: "",
|
||||||
selectedEnvId: "",
|
selectedEnvId: "",
|
||||||
selectedProfileId: "",
|
selectedProfileId: "",
|
||||||
alwaysShowOutput: false
|
alwaysShowOutput: false,
|
||||||
|
activeTabId: null,
|
||||||
|
pendingConfigRefresh: false
|
||||||
};
|
};
|
||||||
|
|
||||||
async function switchState(stateName) {
|
async function switchState(stateName) {
|
||||||
@@ -118,6 +120,7 @@ function applyPopupDraft(draft) {
|
|||||||
} else if (typeof draft.siteTextSelector === "string") {
|
} else if (typeof draft.siteTextSelector === "string") {
|
||||||
state.siteTextTarget = { kind: "css", selector: draft.siteTextSelector };
|
state.siteTextTarget = { kind: "css", selector: draft.siteTextSelector };
|
||||||
}
|
}
|
||||||
|
updateCounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchUrl(url, pattern) {
|
function matchUrl(url, pattern) {
|
||||||
@@ -677,6 +680,10 @@ function setAnalyzing(isAnalyzing) {
|
|||||||
updateTaskSelectState();
|
updateTaskSelectState();
|
||||||
updateEnvSelectState();
|
updateEnvSelectState();
|
||||||
updateProfileSelectState();
|
updateProfileSelectState();
|
||||||
|
if (!isAnalyzing && state.pendingConfigRefresh) {
|
||||||
|
state.pendingConfigRefresh = false;
|
||||||
|
scheduleConfigRefresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateOutputVisibility() {
|
function updateOutputVisibility() {
|
||||||
@@ -686,12 +693,93 @@ function updateOutputVisibility() {
|
|||||||
outputSection.classList.toggle("hidden", shouldHide);
|
outputSection.classList.toggle("hidden", shouldHide);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSelectedTask() {
|
||||||
|
if (state.forcedTask) return state.forcedTask;
|
||||||
|
const selectedId = taskSelect?.value || state.selectedTaskId;
|
||||||
|
return state.tasks.find((item) => item.id === selectedId) || state.tasks[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedProfile() {
|
||||||
|
const selectedId = profileSelect?.value || state.selectedProfileId;
|
||||||
|
return (
|
||||||
|
state.profiles.find((item) => item.id === selectedId) ||
|
||||||
|
state.profiles[0] ||
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedEnv() {
|
||||||
|
const selectedId = envSelect?.value || state.selectedEnvId;
|
||||||
|
return state.envs.find((item) => item.id === selectedId) || state.envs[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTotalPromptText() {
|
||||||
|
const task = getSelectedTask();
|
||||||
|
const profile = getSelectedProfile();
|
||||||
|
const env = getSelectedEnv();
|
||||||
|
const systemPrompt = env?.systemPrompt || "";
|
||||||
|
const userPrompt = buildUserMessage(
|
||||||
|
profile?.text || "",
|
||||||
|
task?.text || "",
|
||||||
|
state.siteText || ""
|
||||||
|
);
|
||||||
|
return systemPrompt ? `${systemPrompt}\n\n${userPrompt}` : userPrompt;
|
||||||
|
}
|
||||||
|
|
||||||
function updateSiteTextCount() {
|
function updateSiteTextCount() {
|
||||||
postingCountEl.textContent = `Site Text: ${state.siteText.length} chars`;
|
const length = (state.siteText || "").length;
|
||||||
|
postingCountEl.textContent = `Site Text: ${length} chars`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePromptCount(count) {
|
function updatePromptCount(count) {
|
||||||
promptCountEl.textContent = `Task: ${count} chars`;
|
const total =
|
||||||
|
typeof count === "number" ? count : buildTotalPromptText().length;
|
||||||
|
promptCountEl.textContent = `Total: ${total} chars`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCounts() {
|
||||||
|
updateSiteTextCount();
|
||||||
|
updatePromptCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
let siteContentRefreshTimer = null;
|
||||||
|
function scheduleSiteContentRefresh() {
|
||||||
|
if (siteContentRefreshTimer) return;
|
||||||
|
siteContentRefreshTimer = window.setTimeout(() => {
|
||||||
|
siteContentRefreshTimer = null;
|
||||||
|
void refreshSiteContentCounts();
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
let configRefreshTimer = null;
|
||||||
|
function scheduleConfigRefresh() {
|
||||||
|
if (state.isAnalyzing) {
|
||||||
|
state.pendingConfigRefresh = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (configRefreshTimer) return;
|
||||||
|
configRefreshTimer = window.setTimeout(() => {
|
||||||
|
configRefreshTimer = null;
|
||||||
|
void loadConfig();
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshSiteContentCounts() {
|
||||||
|
if (state.isAnalyzing) return;
|
||||||
|
if (state.currentPopupState !== "normal") return;
|
||||||
|
if (!state.siteTextTarget) return;
|
||||||
|
try {
|
||||||
|
const response = await sendToActiveTab({
|
||||||
|
type: "EXTRACT_BY_SELECTOR",
|
||||||
|
target: state.siteTextTarget
|
||||||
|
});
|
||||||
|
if (!response?.ok) return;
|
||||||
|
state.siteText = response.extracted || "";
|
||||||
|
state.siteTextTarget = response.target || state.siteTextTarget;
|
||||||
|
updateCounts();
|
||||||
|
} catch {
|
||||||
|
// Ignore refresh failures; counts will update on next explicit extract.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTasks(tasks) {
|
function renderTasks(tasks) {
|
||||||
@@ -792,6 +880,7 @@ function setEnvironmentSelection(envId) {
|
|||||||
envSelect.value = target;
|
envSelect.value = target;
|
||||||
}
|
}
|
||||||
state.selectedEnvId = target;
|
state.selectedEnvId = target;
|
||||||
|
updatePromptCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setProfileSelection(profileId) {
|
function setProfileSelection(profileId) {
|
||||||
@@ -803,6 +892,7 @@ function setProfileSelection(profileId) {
|
|||||||
profileSelect.value = target;
|
profileSelect.value = target;
|
||||||
}
|
}
|
||||||
state.selectedProfileId = target;
|
state.selectedProfileId = target;
|
||||||
|
updatePromptCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectTask(taskId, { resetEnv } = { resetEnv: false }) {
|
function selectTask(taskId, { resetEnv } = { resetEnv: false }) {
|
||||||
@@ -814,6 +904,7 @@ function selectTask(taskId, { resetEnv } = { resetEnv: false }) {
|
|||||||
setEnvironmentSelection(getTaskDefaultEnvId(task));
|
setEnvironmentSelection(getTaskDefaultEnvId(task));
|
||||||
setProfileSelection(getTaskDefaultProfileId(task));
|
setProfileSelection(getTaskDefaultProfileId(task));
|
||||||
}
|
}
|
||||||
|
updatePromptCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function persistSelections() {
|
async function persistSelections() {
|
||||||
@@ -900,6 +991,7 @@ function ensurePort() {
|
|||||||
async function loadConfig() {
|
async function loadConfig() {
|
||||||
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
|
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||||
const currentUrl = tabs[0]?.url || "";
|
const currentUrl = tabs[0]?.url || "";
|
||||||
|
state.activeTabId = tabs[0]?.id || null;
|
||||||
|
|
||||||
const { lastPopupState, [POPUP_DRAFT_KEY]: popupDraft } = await getStorage([
|
const { lastPopupState, [POPUP_DRAFT_KEY]: popupDraft } = await getStorage([
|
||||||
"lastPopupState",
|
"lastPopupState",
|
||||||
@@ -968,6 +1060,9 @@ async function loadConfig() {
|
|||||||
state.currentWorkspace = activeWorkspace;
|
state.currentWorkspace = activeWorkspace;
|
||||||
currentWorkspaceName.textContent = activeWorkspace.name || "Global";
|
currentWorkspaceName.textContent = activeWorkspace.name || "Global";
|
||||||
}
|
}
|
||||||
|
if (state.currentSite && !state.siteTextTarget) {
|
||||||
|
state.siteTextTarget = normalizeStoredExtractTarget(state.currentSite);
|
||||||
|
}
|
||||||
if (stored.theme) {
|
if (stored.theme) {
|
||||||
state.globalTheme = stored.theme;
|
state.globalTheme = stored.theme;
|
||||||
}
|
}
|
||||||
@@ -1005,6 +1100,7 @@ async function loadConfig() {
|
|||||||
state.selectedTaskId = "";
|
state.selectedTaskId = "";
|
||||||
setEnvironmentSelection(effectiveEnvs[0]?.id || "");
|
setEnvironmentSelection(effectiveEnvs[0]?.id || "");
|
||||||
setProfileSelection(effectiveProfiles[0]?.id || "");
|
setProfileSelection(effectiveProfiles[0]?.id || "");
|
||||||
|
updateCounts();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,6 +1136,10 @@ async function loadConfig() {
|
|||||||
await persistSelections();
|
await persistSelections();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCounts();
|
||||||
|
if (state.currentSite) {
|
||||||
|
await refreshSiteContentCounts();
|
||||||
|
}
|
||||||
maybeRunDefaultTask();
|
maybeRunDefaultTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,8 +1168,7 @@ async function handleExtract() {
|
|||||||
|
|
||||||
state.siteText = response.extracted || "";
|
state.siteText = response.extracted || "";
|
||||||
state.siteTextTarget = response.target || target;
|
state.siteTextTarget = response.target || target;
|
||||||
updateSiteTextCount();
|
updateCounts();
|
||||||
updatePromptCount(0);
|
|
||||||
setStatus("Text extracted.");
|
setStatus("Text extracted.");
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1199,7 +1298,7 @@ async function handleAnalyze() {
|
|||||||
task.text || "",
|
task.text || "",
|
||||||
state.siteText
|
state.siteText
|
||||||
);
|
);
|
||||||
updatePromptCount(promptText.length);
|
updatePromptCount();
|
||||||
|
|
||||||
state.outputRaw = "";
|
state.outputRaw = "";
|
||||||
renderOutput();
|
renderOutput();
|
||||||
@@ -1298,6 +1397,7 @@ async function runMinimalExtraction(text, minLength = 5) {
|
|||||||
state.siteText = response.extracted;
|
state.siteText = response.extracted;
|
||||||
state.siteTextTarget = response.target || { kind: "textScope", text: trimmed };
|
state.siteTextTarget = response.target || { kind: "textScope", text: trimmed };
|
||||||
extractedPreview.textContent = state.siteText;
|
extractedPreview.textContent = state.siteText;
|
||||||
|
updateCounts();
|
||||||
await fillSiteDefaultsFromTab();
|
await fillSiteDefaultsFromTab();
|
||||||
switchState("review");
|
switchState("review");
|
||||||
await persistPopupDraft();
|
await persistPopupDraft();
|
||||||
@@ -1336,6 +1436,7 @@ extractFullBtn.addEventListener("click", async () => {
|
|||||||
state.siteText = response.extracted;
|
state.siteText = response.extracted;
|
||||||
state.siteTextTarget = target;
|
state.siteTextTarget = target;
|
||||||
extractedPreview.textContent = state.siteText;
|
extractedPreview.textContent = state.siteText;
|
||||||
|
updateCounts();
|
||||||
await fillSiteDefaultsFromTab();
|
await fillSiteDefaultsFromTab();
|
||||||
switchState("review");
|
switchState("review");
|
||||||
await persistPopupDraft();
|
await persistPopupDraft();
|
||||||
@@ -1372,6 +1473,7 @@ retryExtractBtn.addEventListener("click", () => {
|
|||||||
if (workspaceSelect) workspaceSelect.value = "global";
|
if (workspaceSelect) workspaceSelect.value = "global";
|
||||||
state.siteText = "";
|
state.siteText = "";
|
||||||
state.siteTextTarget = null;
|
state.siteTextTarget = null;
|
||||||
|
updateCounts();
|
||||||
setMinimalStatus("");
|
setMinimalStatus("");
|
||||||
void clearPopupDraft();
|
void clearPopupDraft();
|
||||||
setStatus("Ready.");
|
setStatus("Ready.");
|
||||||
@@ -1427,7 +1529,7 @@ confirmSiteBtn.addEventListener("click", async () => {
|
|||||||
currentWorkspaceName.textContent = state.currentWorkspace.name || "Global";
|
currentWorkspaceName.textContent = state.currentWorkspace.name || "Global";
|
||||||
await loadConfig();
|
await loadConfig();
|
||||||
await switchState("normal");
|
await switchState("normal");
|
||||||
updateSiteTextCount();
|
updateCounts();
|
||||||
setStatus("Site saved.");
|
setStatus("Site saved.");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1450,8 +1552,7 @@ profileSelect.addEventListener("change", () => {
|
|||||||
void persistSelections();
|
void persistSelections();
|
||||||
});
|
});
|
||||||
|
|
||||||
updateSiteTextCount();
|
updateCounts();
|
||||||
updatePromptCount(0);
|
|
||||||
renderOutput();
|
renderOutput();
|
||||||
setAnalyzing(false);
|
setAnalyzing(false);
|
||||||
void loadTheme();
|
void loadTheme();
|
||||||
@@ -1597,4 +1698,27 @@ chrome.storage.onChanged.addListener((changes) => {
|
|||||||
state.alwaysShowOutput = Boolean(changes.alwaysShowOutput.newValue);
|
state.alwaysShowOutput = Boolean(changes.alwaysShowOutput.newValue);
|
||||||
updateOutputVisibility();
|
updateOutputVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configKeys = [
|
||||||
|
"tasks",
|
||||||
|
"envConfigs",
|
||||||
|
"profiles",
|
||||||
|
"shortcuts",
|
||||||
|
"workspaces",
|
||||||
|
"sites",
|
||||||
|
"theme",
|
||||||
|
"alwaysShowOutput"
|
||||||
|
];
|
||||||
|
if (configKeys.some((key) => changes[key])) {
|
||||||
|
scheduleConfigRefresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener((message, sender) => {
|
||||||
|
if (message?.type !== "SITE_CONTENT_CHANGED") return;
|
||||||
|
const senderTabId = sender?.tab?.id || null;
|
||||||
|
if (state.activeTabId && senderTabId && senderTabId !== state.activeTabId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scheduleSiteContentRefresh();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user