base for AI migration/extension of WWCompanion

This commit is contained in:
2026-01-18 03:46:51 -05:00
commit a02c6ed1db
10 changed files with 5394 additions and 0 deletions

140
sitecompanion/content.js Normal file
View File

@@ -0,0 +1,140 @@
const HEADER_LINES = new Set([
"OVERVIEW",
"PRE-SCREENING",
"WORK TERM RATINGS",
"JOB POSTING INFORMATION",
"APPLICATION INFORMATION",
"COMPANY INFORMATION",
"SERVICE TEAM"
]);
const ACTION_BAR_SELECTOR = "nav.floating--action-bar";
const INJECTED_ATTR = "data-wwcompanion-default-task";
const DEFAULT_TASK_LABEL = "Default WWCompanion Task";
function isJobPostingOpen() {
return document.getElementsByClassName("modal__content").length > 0;
}
function sanitizePostingText(text) {
let cleaned = text.replaceAll("fiber_manual_record", "");
const lines = cleaned.split(/\r?\n/);
const filtered = lines.filter((line) => {
const trimmed = line.trim();
if (!trimmed) return true;
return !HEADER_LINES.has(trimmed.toUpperCase());
});
cleaned = filtered.join("\n");
cleaned = cleaned.replace(/[ \t]+/g, " ");
cleaned = cleaned.replace(/\n{3,}/g, "\n\n");
return cleaned.trim();
}
function buildDefaultTaskButton(templateButton) {
const button = document.createElement("button");
button.type = "button";
button.textContent = DEFAULT_TASK_LABEL;
button.className = templateButton.className;
button.setAttribute(INJECTED_ATTR, "true");
button.setAttribute("aria-label", DEFAULT_TASK_LABEL);
button.addEventListener("click", () => {
document.dispatchEvent(new CustomEvent("WWCOMPANION_RUN_DEFAULT_TASK"));
chrome.runtime.sendMessage({ type: "RUN_DEFAULT_TASK" });
});
return button;
}
function getActionBars() {
return [...document.querySelectorAll(ACTION_BAR_SELECTOR)];
}
function getActionBarButtonCount(bar) {
return bar.querySelectorAll(`button:not([${INJECTED_ATTR}])`).length;
}
function selectTargetActionBar(bars) {
if (!bars.length) return null;
let best = bars[0];
let bestCount = getActionBarButtonCount(best);
for (const bar of bars.slice(1)) {
const count = getActionBarButtonCount(bar);
if (count > bestCount) {
best = bar;
bestCount = count;
}
}
return best;
}
function ensureDefaultTaskButton() {
const bars = getActionBars();
if (!bars.length) return;
if (!isJobPostingOpen()) {
for (const bar of bars) {
const injected = bar.querySelector(`[${INJECTED_ATTR}]`);
if (injected) injected.remove();
}
return;
}
const toolbar = selectTargetActionBar(bars);
if (!toolbar) return;
for (const bar of bars) {
if (bar === toolbar) continue;
const injected = bar.querySelector(`[${INJECTED_ATTR}]`);
if (injected) injected.remove();
}
const existing = toolbar.querySelector(`[${INJECTED_ATTR}]`);
if (existing) return;
const templateButton = toolbar.querySelector("button");
if (!templateButton) return;
const button = buildDefaultTaskButton(templateButton);
const firstChild = toolbar.firstElementChild;
if (firstChild) {
toolbar.insertBefore(button, firstChild);
} else {
toolbar.appendChild(button);
}
}
function extractPostingText() {
const contents = [...document.getElementsByClassName("modal__content")];
if (!contents.length) {
return { ok: false, error: "No modal content found on this page." };
}
// WaterlooWorks renders multiple modal containers; choose the longest visible text block.
const el = contents.reduce((best, cur) =>
cur.innerText.length > best.innerText.length ? cur : best
);
const rawText = el.innerText;
const sanitized = sanitizePostingText(rawText);
return { ok: true, rawText, sanitized };
}
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message?.type !== "EXTRACT_POSTING") return;
const result = extractPostingText();
sendResponse(result);
});
chrome.runtime.onConnect.addListener((port) => {
if (port.name !== "wwcompanion-keepalive") return;
port.onDisconnect.addListener(() => {});
});
const observer = new MutationObserver(() => {
ensureDefaultTaskButton();
});
observer.observe(document.documentElement, { childList: true, subtree: true });
ensureDefaultTaskButton();