PageSourceSearch

https://www.theengineeringprojects.com/res/js/tools/guest-posting.3awly329mn.js

js theengineeringprojects.com collected 2026-10-02 03:56:49 UTC 6,320 bytes, 98 lines download raw bytes

1// Browser-only helpers for the guest posting tool: clipboard, CSV download and a viewport check. No storage, no network.
2export async function copy(text) { await navigator.clipboard.writeText(text); }
3export function download(csv, name) {
4    const url = URL.createObjectURL(new Blob(["", csv], { type: "text/csv;charset=utf-8" }));
5    const link = document.createElement("a");
6    link.href = url;
7    link.download = name || "guest-post-sites.csv";
8    document.body.append(link);
9    link.click();
10    link.remove();
11    setTimeout(() => URL.revokeObjectURL(url), 1000);
12}
13// Writes the selection into the address in place (no reload, no history entry) and returns the full link.
14// Only the sheet's own keys are replaced; anything else already in the address stays.
15export function link(keys, pairs) {
16    const url = new URL(location.href);
17    for (const key of keys) url.searchParams.delete(key);
18    for (const [key, value] of pairs) url.searchParams.set(key, value);
19    history.replaceState(history.state, "", url);
20    return url.href;
21}
22// The sheet is two tables: the header (in .gp-head-wrap, no scrollbar) and the rows (in .gp-grid-wrap, which
23// scrolls). mount() keeps the header following the rows sideways; align() gives both tables the same column
24// widths, each column as wide as the wider of its header cell and its widest row cell.
25const state = new WeakMap();
26export function mount(sheet) {
27    const head = sheet.querySelector(".gp-head-wrap"), body = sheet.querySelector(".gp-grid-wrap");
28    if (!head || !body || state.has(sheet)) return;
29    body.addEventListener("scroll", () => { head.scrollLeft = body.scrollLeft; }, { passive: true });
30    const observer = new ResizeObserver(() => align(sheet));
31    observer.observe(body);
32    state.set(sheet, observer);
33    align(sheet);
34}
35export function align(sheet) {
36    const head = sheet.querySelector(".gp-head-wrap"), body = sheet.querySelector(".gp-grid-wrap");
37    const headTable = head?.querySelector("table"), bodyTable = body?.querySelector("table");
38    if (!headTable || !bodyTable) return;
39    const headCells = [...headTable.querySelectorAll("tr.gp-columns > th")];
40    const headCols = [...headTable.querySelectorAll("colgroup col")], bodyCols = [...bodyTable.querySelectorAll("colgroup col")];
41    if (headCols.length !== headCells.length || bodyCols.length !== headCells.length) return;
42    // The header wrap ends where the rows end, before the vertical scrollbar, so both tables are laid out in the same width.
43    head.style.paddingRight = (body.offsetWidth - body.clientWidth) + "px";
44    // Natural widths first (no fixed layout), then the wider of the two per column is set on both.
45    for (const table of [headTable, bodyTable]) { table.style.tableLayout = ""; table.style.width = ""; }
46    for (const col of [...headCols, ...bodyCols]) col.style.width = "";
47    const rows = [...bodyTable.querySelectorAll("tbody > tr:not(.gp-empty)")].slice(0, 60);
48    const widths = headCells.map((cell, i) => Math.ceil(Math.max(cell.offsetWidth, ...rows.map(r => r.children[i]?.offsetWidth ?? 0))));
49    const total = widths.reduce((a, b) => a + b, 0);
50    if (total === 0) return;
51    // Full screen is the one place the sheet stretches to the edge; otherwise the columns keep their own widths.
52    const full = document.fullscreenElement === sheet || sheet.classList.contains("is-fullwindow");
53    const width = full ? Math.max(total, body.clientWidth) : total;
54    if (width > total) { const extra = width - total; widths.forEach((w, i) => { widths[i] = w + extra * w / total; }); }
55    for (const cols of [headCols, bodyCols]) cols.forEach((col, i) => { col.style.width = widths[i] + "px"; });
56    for (const table of [headTable, bodyTable]) { table.style.tableLayout = "fixed"; table.style.width = width + "px"; }
57    head.scrollLeft = body.scrollLeft;
58}
59// Full screen for the sheet element. Where the browser refuses real full screen (some embedded views do), the
60// sheet fills the window instead. Returns whether it is on; tells .NET when it ends by other means (Esc included).
61export async function fullscreen(sheet, dotnet) {
62    const fill = "is-fullwindow";
63    if (document.fullscreenElement === sheet) { await document.exitFullscreen(); return false; }
64    if (sheet.classList.contains(fill)) { sheet.classList.remove(fill); align(sheet); return false; }
65    if (!sheet.dataset.fullscreenWatched) {
66        sheet.dataset.fullscreenWatched = "1";
67        sheet.addEventListener("fullscreenchange", () => dotnet.invokeMethodAsync("FullScreenChanged", document.fullscreenElement === sheet));
68        document.addEventListener("keydown", e => {
69            if (e.key === "Escape" && sheet.classList.contains(fill)) { sheet.classList.remove(fill); dotnet.invokeMethodAsync("FullScreenChanged", false); }
70        });
71    }
72    try { await sheet.requestFullscreen(); }
73    catch { sheet.classList.add(fill); }
74    align(sheet);
75    return true;
76}
77// The zoom, in percent, at which every column of the sheet is in view.
78export function fit() {
79    const wrap = document.querySelector(".gp-grid-wrap"), sheet = wrap?.querySelector(".gp-grid");
80    if (!wrap || !sheet) return 100;
81    // A zoomed-out sheet is stretched to fill the frame, so its real width is measured at normal size.
82    const zoom = sheet.style.zoom, width = sheet.style.width, layout = sheet.style.tableLayout;
83    sheet.style.zoom = "1"; sheet.style.width = ""; sheet.style.tableLayout = "";
84    const natural = sheet.offsetWidth;
85    sheet.style.zoom = zoom; sheet.style.width = width; sheet.style.tableLayout = layout;
86    return natural > 0 ? Math.floor(wrap.clientWidth * 100 / natural) : 100;
87}
88// Esc closes the site card. Registered once; .NET decides whether anything is open.
89let escapeWatched = false;
90export function watchEscape(dotnet) {
91    if (escapeWatched) return;
92    escapeWatched = true;
93    document.addEventListener("keydown", e => { if (e.key === "Escape") dotnet.invokeMethodAsync("EscapePressed"); });
94}
95// A new page starts at its first row.
96export function top() { const sheet = document.querySelector(".gp-grid-wrap"); if (sheet) sheet.scrollTop = 0; }
97// Matches the stylesheet's single-column breakpoint, where the filter panel starts closed.
98export function narrow() { return matchMedia("(max-width: 800px)").matches; }

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.