New release: added background persistence, page checking, and also a button injected to the WW posting toolbar

This commit is contained in:
2026-01-17 00:40:49 -05:00
parent 2e6dc5c028
commit 24370c0826
4 changed files with 292 additions and 56 deletions

View File

@@ -8,6 +8,14 @@ const HEADER_LINES = new Set([
"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/);
@@ -23,6 +31,78 @@ function sanitizePostingText(text) {
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) {
@@ -46,3 +126,15 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
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();