@yashwant.dharmdas/elementor-mcp 3.2.6 → 3.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +133 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1092,15 +1092,16 @@ function createMcpServer(sites) {
|
|
|
1092
1092
|
await page.goto(pageUrl, { waitUntil: "networkidle2", timeout: 45_000 });
|
|
1093
1093
|
// ── Auto-scroll with multi-pass stabilization ────────────────────
|
|
1094
1094
|
// Many Elementor pages lazy-load content on scroll (images, Swiper
|
|
1095
|
-
// carousels, reveal animations).
|
|
1096
|
-
//
|
|
1097
|
-
// total page height stops increasing
|
|
1095
|
+
// carousels, reveal animations). We scroll slowly so IntersectionObservers
|
|
1096
|
+
// have time to fire, then wait at the bottom for content to settle, and
|
|
1097
|
+
// repeat passes until the total page height stops increasing.
|
|
1098
1098
|
if (auto_scroll !== false) {
|
|
1099
1099
|
await page.evaluate(async () => {
|
|
1100
1100
|
const getHeight = () => Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight);
|
|
1101
1101
|
const scrollOnce = () => new Promise((resolve) => {
|
|
1102
1102
|
let y = 0;
|
|
1103
|
-
const step =
|
|
1103
|
+
const step = 180; // smaller step
|
|
1104
|
+
const delay = 110; // slower interval — gives observers time to fire
|
|
1104
1105
|
const timer = setInterval(() => {
|
|
1105
1106
|
const h = getHeight();
|
|
1106
1107
|
window.scrollBy(0, step);
|
|
@@ -1109,50 +1110,166 @@ function createMcpServer(sites) {
|
|
|
1109
1110
|
clearInterval(timer);
|
|
1110
1111
|
resolve();
|
|
1111
1112
|
}
|
|
1112
|
-
},
|
|
1113
|
+
}, delay);
|
|
1113
1114
|
});
|
|
1114
1115
|
// Repeat until height stabilizes (max 4 passes)
|
|
1115
1116
|
let lastHeight = 0;
|
|
1116
1117
|
for (let i = 0; i < 4; i++) {
|
|
1117
1118
|
window.scrollTo(0, 0);
|
|
1118
|
-
await new Promise(r => setTimeout(r,
|
|
1119
|
+
await new Promise(r => setTimeout(r, 200));
|
|
1119
1120
|
await scrollOnce();
|
|
1120
|
-
//
|
|
1121
|
-
await new Promise(r => setTimeout(r,
|
|
1121
|
+
// Long wait at the bottom — bg images / Swipers need time
|
|
1122
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
1122
1123
|
const h = getHeight();
|
|
1123
|
-
if (h === lastHeight)
|
|
1124
|
+
if (h === lastHeight && i > 0)
|
|
1124
1125
|
break;
|
|
1125
1126
|
lastHeight = h;
|
|
1126
1127
|
}
|
|
1128
|
+
// One more slow scroll pass at half speed to nail any stragglers
|
|
1129
|
+
await new Promise((resolve) => {
|
|
1130
|
+
window.scrollTo(0, 0);
|
|
1131
|
+
let y = 0;
|
|
1132
|
+
const step = 120;
|
|
1133
|
+
const timer = setInterval(() => {
|
|
1134
|
+
const h = getHeight();
|
|
1135
|
+
window.scrollBy(0, step);
|
|
1136
|
+
y += step;
|
|
1137
|
+
if (y >= h) {
|
|
1138
|
+
clearInterval(timer);
|
|
1139
|
+
resolve();
|
|
1140
|
+
}
|
|
1141
|
+
}, 130);
|
|
1142
|
+
});
|
|
1143
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
1127
1144
|
// Back to top for the capture
|
|
1128
1145
|
window.scrollTo(0, 0);
|
|
1129
1146
|
});
|
|
1130
1147
|
}
|
|
1131
|
-
// ── Force-load all
|
|
1148
|
+
// ── Force-load all images, Elementor backgrounds, and reveal sections ─
|
|
1132
1149
|
await page.evaluate(async () => {
|
|
1133
|
-
//
|
|
1150
|
+
// 1. Inject CSS that disables animations AND forces opacity:1
|
|
1151
|
+
// on Elementor's hidden reveal states. This MUST be first so
|
|
1152
|
+
// subsequent layout / render passes don't re-hide content.
|
|
1153
|
+
const style = document.createElement("style");
|
|
1154
|
+
style.id = "__mcp_screenshot_overrides__";
|
|
1155
|
+
style.textContent = `
|
|
1156
|
+
*, *::before, *::after {
|
|
1157
|
+
animation-duration: 0s !important;
|
|
1158
|
+
animation-delay: 0s !important;
|
|
1159
|
+
transition-duration: 0s !important;
|
|
1160
|
+
transition-delay: 0s !important;
|
|
1161
|
+
}
|
|
1162
|
+
.elementor-invisible,
|
|
1163
|
+
.elementor-element[data-settings*="animation"] {
|
|
1164
|
+
opacity: 1 !important;
|
|
1165
|
+
visibility: visible !important;
|
|
1166
|
+
transform: none !important;
|
|
1167
|
+
}
|
|
1168
|
+
/* Defeat any lazy-load opacity tricks */
|
|
1169
|
+
.elementor-element { opacity: 1 !important; }
|
|
1170
|
+
`;
|
|
1171
|
+
document.head.appendChild(style);
|
|
1172
|
+
// 2. Strip loading="lazy" on images
|
|
1134
1173
|
document.querySelectorAll('img[loading="lazy"]').forEach((img) => {
|
|
1135
1174
|
img.setAttribute("loading", "eager");
|
|
1136
1175
|
});
|
|
1137
|
-
// Resolve data-src → src for
|
|
1176
|
+
// 3. Resolve data-src → src for any deferred-load libraries
|
|
1138
1177
|
document.querySelectorAll("img[data-src]").forEach((img) => {
|
|
1139
1178
|
const ds = img.getAttribute("data-src");
|
|
1140
1179
|
if (ds && !img.getAttribute("src"))
|
|
1141
1180
|
img.setAttribute("src", ds);
|
|
1142
1181
|
});
|
|
1182
|
+
// 4. Resolve <source srcset> inside <picture> (just in case)
|
|
1183
|
+
document.querySelectorAll("source[data-srcset]").forEach((src) => {
|
|
1184
|
+
const ds = src.getAttribute("data-srcset");
|
|
1185
|
+
if (ds && !src.getAttribute("srcset"))
|
|
1186
|
+
src.setAttribute("srcset", ds);
|
|
1187
|
+
});
|
|
1188
|
+
// 5. Force-load Elementor's lazy background images.
|
|
1189
|
+
// Elementor uses MULTIPLE patterns over the years:
|
|
1190
|
+
// - class .elementor-element-bg-lazyload + CSS var --e-bg-lazyload
|
|
1191
|
+
// - data-bg / data-background-image
|
|
1192
|
+
// - data-settings JSON containing background_image
|
|
1193
|
+
// We try all of them.
|
|
1194
|
+
document.querySelectorAll(".elementor-element-bg-lazyload, [data-bg], [data-background-image], [data-settings]").forEach((el) => {
|
|
1195
|
+
let url = el.getAttribute("data-bg") ||
|
|
1196
|
+
el.getAttribute("data-background-image");
|
|
1197
|
+
// Try the CSS variable
|
|
1198
|
+
if (!url) {
|
|
1199
|
+
const v = getComputedStyle(el).getPropertyValue("--e-bg-lazyload").trim();
|
|
1200
|
+
if (v && v !== "none") {
|
|
1201
|
+
url = v.replace(/^url\(["']?|["']?\)$/g, "");
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
// Try parsing data-settings JSON
|
|
1205
|
+
if (!url) {
|
|
1206
|
+
try {
|
|
1207
|
+
const ds = el.getAttribute("data-settings");
|
|
1208
|
+
if (ds) {
|
|
1209
|
+
const obj = JSON.parse(ds);
|
|
1210
|
+
url = obj?.background_image?.url
|
|
1211
|
+
|| obj?._background_image?.url
|
|
1212
|
+
|| obj?.background_overlay_image?.url
|
|
1213
|
+
|| null;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
catch { /* ignore */ }
|
|
1217
|
+
}
|
|
1218
|
+
if (url && url !== "none") {
|
|
1219
|
+
// Set inline so it overrides any external lazy CSS
|
|
1220
|
+
el.style.setProperty("background-image", `url("${url}")`, "important");
|
|
1221
|
+
el.style.setProperty("--e-bg-lazyload", "none");
|
|
1222
|
+
}
|
|
1223
|
+
el.classList.remove("elementor-element-bg-lazyload");
|
|
1224
|
+
});
|
|
1225
|
+
// 6. Force-show Elementor reveal-animation elements
|
|
1226
|
+
document.querySelectorAll(".elementor-invisible").forEach((el) => {
|
|
1227
|
+
el.classList.remove("elementor-invisible");
|
|
1228
|
+
el.style.opacity = "1";
|
|
1229
|
+
el.style.visibility = "visible";
|
|
1230
|
+
el.style.transform = "none";
|
|
1231
|
+
});
|
|
1232
|
+
// 7. Re-trigger Elementor frontend lazy-load if available.
|
|
1233
|
+
// Elementor exposes the global `elementorFrontend`; calling its
|
|
1234
|
+
// elementsHandler reinitialises lazy modules.
|
|
1235
|
+
try {
|
|
1236
|
+
const ef = window.elementorFrontend;
|
|
1237
|
+
if (ef?.elementsHandler?.runReadyTrigger) {
|
|
1238
|
+
document.querySelectorAll(".elementor-element").forEach((el) => {
|
|
1239
|
+
try {
|
|
1240
|
+
ef.elementsHandler.runReadyTrigger(el);
|
|
1241
|
+
}
|
|
1242
|
+
catch { /* ignore */ }
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
catch { /* ignore */ }
|
|
1247
|
+
// 8. Dispatch scroll/resize to wake any remaining IntersectionObservers
|
|
1248
|
+
window.dispatchEvent(new Event("scroll"));
|
|
1249
|
+
window.dispatchEvent(new Event("resize"));
|
|
1250
|
+
document.dispatchEvent(new Event("DOMContentLoaded"));
|
|
1251
|
+
// 9. Wait for ALL <img> tags (now eager) to finish loading + decode
|
|
1143
1252
|
const images = Array.from(document.querySelectorAll("img"));
|
|
1144
1253
|
await Promise.all(images.map((img) => {
|
|
1145
|
-
if (img.complete && img.naturalWidth > 0)
|
|
1146
|
-
return Promise.resolve();
|
|
1254
|
+
if (img.complete && img.naturalWidth > 0) {
|
|
1255
|
+
return img.decode?.().catch(() => { }) ?? Promise.resolve();
|
|
1256
|
+
}
|
|
1147
1257
|
return new Promise((resolve) => {
|
|
1148
1258
|
img.addEventListener("load", () => resolve(), { once: true });
|
|
1149
1259
|
img.addEventListener("error", () => resolve(), { once: true });
|
|
1150
1260
|
setTimeout(() => resolve(), 5000);
|
|
1151
1261
|
});
|
|
1152
1262
|
}));
|
|
1263
|
+
// 10. Wait for fonts to be fully ready (avoids FOUT in screenshot)
|
|
1264
|
+
if (document.fonts?.ready) {
|
|
1265
|
+
try {
|
|
1266
|
+
await document.fonts.ready;
|
|
1267
|
+
}
|
|
1268
|
+
catch { /* ignore */ }
|
|
1269
|
+
}
|
|
1153
1270
|
});
|
|
1154
|
-
// Extra settle time
|
|
1155
|
-
await new Promise(resolve => setTimeout(resolve, wait ??
|
|
1271
|
+
// Extra settle time — bumped to 3500ms default to handle slow CDNs / videos
|
|
1272
|
+
await new Promise(resolve => setTimeout(resolve, wait ?? 3500));
|
|
1156
1273
|
const fmt = format ?? "jpeg";
|
|
1157
1274
|
const baseOptions = { type: fmt, fullPage: !max_height && (full_page ?? true) };
|
|
1158
1275
|
if (max_height)
|
package/package.json
CHANGED