@yashwant.dharmdas/elementor-mcp 3.2.7 → 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 +122 -44
- 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,89 +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
|
-
// 1.
|
|
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
|
-
//
|
|
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
|
});
|
|
1143
|
-
//
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
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");
|
|
1153
1222
|
}
|
|
1154
1223
|
el.classList.remove("elementor-element-bg-lazyload");
|
|
1155
1224
|
});
|
|
1156
|
-
//
|
|
1157
|
-
// hidden (opacity:0 / .elementor-invisible) waiting for scroll trigger
|
|
1225
|
+
// 6. Force-show Elementor reveal-animation elements
|
|
1158
1226
|
document.querySelectorAll(".elementor-invisible").forEach((el) => {
|
|
1159
1227
|
el.classList.remove("elementor-invisible");
|
|
1160
1228
|
el.style.opacity = "1";
|
|
1161
1229
|
el.style.visibility = "visible";
|
|
1162
1230
|
el.style.transform = "none";
|
|
1163
1231
|
});
|
|
1164
|
-
//
|
|
1165
|
-
//
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
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
|
|
1179
1248
|
window.dispatchEvent(new Event("scroll"));
|
|
1180
1249
|
window.dispatchEvent(new Event("resize"));
|
|
1181
|
-
|
|
1250
|
+
document.dispatchEvent(new Event("DOMContentLoaded"));
|
|
1251
|
+
// 9. Wait for ALL <img> tags (now eager) to finish loading + decode
|
|
1182
1252
|
const images = Array.from(document.querySelectorAll("img"));
|
|
1183
1253
|
await Promise.all(images.map((img) => {
|
|
1184
|
-
if (img.complete && img.naturalWidth > 0)
|
|
1185
|
-
return Promise.resolve();
|
|
1254
|
+
if (img.complete && img.naturalWidth > 0) {
|
|
1255
|
+
return img.decode?.().catch(() => { }) ?? Promise.resolve();
|
|
1256
|
+
}
|
|
1186
1257
|
return new Promise((resolve) => {
|
|
1187
1258
|
img.addEventListener("load", () => resolve(), { once: true });
|
|
1188
1259
|
img.addEventListener("error", () => resolve(), { once: true });
|
|
1189
1260
|
setTimeout(() => resolve(), 5000);
|
|
1190
1261
|
});
|
|
1191
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
|
+
}
|
|
1192
1270
|
});
|
|
1193
|
-
// Extra settle time
|
|
1194
|
-
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));
|
|
1195
1273
|
const fmt = format ?? "jpeg";
|
|
1196
1274
|
const baseOptions = { type: fmt, fullPage: !max_height && (full_page ?? true) };
|
|
1197
1275
|
if (max_height)
|
package/package.json
CHANGED