@elementor/editor-audits 4.3.3 → 4.3.5
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.d.mts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1103 -1146
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1075 -1108
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -15
- package/src/api/page-context-client.ts +8 -5
- package/src/audits/accessibility-statement.ts +39 -0
- package/src/audits/accessibility-widget.ts +41 -0
- package/src/audits/cookie-policy.ts +1 -0
- package/src/audits/google-consent-mode.ts +4 -7
- package/src/audits/images-alt-text.ts +6 -4
- package/src/audits/images-inefficient-format.ts +66 -0
- package/src/audits/images-too-large.ts +23 -10
- package/src/audits/nested-boxed-containers.ts +5 -0
- package/src/components/audit-feedback.tsx +4 -1
- package/src/components/audit-panel.tsx +13 -13
- package/src/components/audit-toggle-icon.tsx +22 -0
- package/src/components/fix-violation-with-angie.tsx +18 -7
- package/src/components/pages/category-page.tsx +27 -3
- package/src/components/pages/overview-page.tsx +24 -29
- package/src/components/report-shell.tsx +10 -91
- package/src/components/rescan-button.tsx +38 -0
- package/src/components/severity-icons.tsx +5 -1
- package/src/components/severity-summary-cards.tsx +52 -0
- package/src/components/violation-cta-button.tsx +11 -2
- package/src/components/violation-icons.tsx +2 -2
- package/src/components/violation-row.tsx +120 -62
- package/src/hooks/use-audit-report.ts +5 -4
- package/src/hooks/use-audit-toggle-props.ts +2 -2
- package/src/hooks/use-single-expanded-card.ts +11 -0
- package/src/init.ts +2 -0
- package/src/register-audits.ts +6 -2
- package/src/runner.ts +15 -7
- package/src/store/selectors.ts +4 -0
- package/src/store/slice.ts +10 -1
- package/src/sync-report-staleness.ts +14 -0
- package/src/types.ts +11 -1
- package/src/utils/all-image-sources.ts +17 -0
- package/src/utils/alt-text-image-sources.ts +24 -0
- package/src/utils/atomic-background-image-sources.ts +56 -0
- package/src/utils/atomic-image-sources.ts +66 -0
- package/src/utils/audit-status-summary.ts +0 -57
- package/src/utils/background-image-sources.ts +32 -0
- package/src/utils/image-alt.ts +3 -1
- package/src/utils/image-like-sources.ts +5 -14
- package/src/utils/image-size-key.ts +8 -0
- package/src/utils/page-attachments.ts +7 -6
- package/src/utils/scan-accessibility-widgets.ts +7 -0
- package/src/audits/too-many-widgets.ts +0 -53
- package/src/components/audit-statuses-section.tsx +0 -65
- package/src/components/count-summary-circle.tsx +0 -66
- package/src/components/pages/all-audits-page.tsx +0 -65
- package/src/components/pages/issues-page.tsx +0 -65
- package/src/components/score-bar.tsx +0 -56
- package/src/components/score-circle.tsx +0 -60
- package/src/components/severity-filter-chips.tsx +0 -57
- package/src/utils/score-thresholds.ts +0 -23
package/dist/index.mjs
CHANGED
|
@@ -6,26 +6,131 @@ import { __registerSlice as registerSlice } from "@elementor/store";
|
|
|
6
6
|
import { utilitiesMenu } from "@elementor/editor-app-bar";
|
|
7
7
|
|
|
8
8
|
// src/hooks/use-audit-toggle-props.ts
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import { __ as __18 } from "@wordpress/i18n";
|
|
10
|
+
|
|
11
|
+
// src/components/audit-toggle-icon.tsx
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
import { ShieldCheckIcon } from "@elementor/icons";
|
|
14
|
+
import { __useSelector as useSelector } from "@elementor/store";
|
|
15
|
+
import { Badge } from "@elementor/ui";
|
|
16
|
+
|
|
17
|
+
// src/store/slice.ts
|
|
18
|
+
import { __createSlice } from "@elementor/store";
|
|
19
|
+
var initialState = { status: "idle", report: null, error: null, isStale: false };
|
|
20
|
+
var slice = __createSlice({
|
|
21
|
+
name: "audits",
|
|
22
|
+
initialState,
|
|
23
|
+
reducers: {
|
|
24
|
+
runStarted(state) {
|
|
25
|
+
state.status = "loading";
|
|
26
|
+
state.error = null;
|
|
27
|
+
},
|
|
28
|
+
runSucceeded(state, action) {
|
|
29
|
+
state.status = "ready";
|
|
30
|
+
state.report = action.payload;
|
|
31
|
+
state.isStale = false;
|
|
32
|
+
},
|
|
33
|
+
runFailed(state, action) {
|
|
34
|
+
state.status = "error";
|
|
35
|
+
state.error = action.payload;
|
|
36
|
+
},
|
|
37
|
+
runAborted(state) {
|
|
38
|
+
state.status = state.report ? "ready" : "idle";
|
|
39
|
+
},
|
|
40
|
+
reportRestored(state, action) {
|
|
41
|
+
state.status = "ready";
|
|
42
|
+
state.report = action.payload;
|
|
43
|
+
state.error = null;
|
|
44
|
+
state.isStale = false;
|
|
45
|
+
},
|
|
46
|
+
reportCleared(state) {
|
|
47
|
+
state.status = "idle";
|
|
48
|
+
state.report = null;
|
|
49
|
+
state.error = null;
|
|
50
|
+
state.isStale = false;
|
|
51
|
+
},
|
|
52
|
+
reportStale(state) {
|
|
53
|
+
if (state.report) {
|
|
54
|
+
state.isStale = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// src/store/selectors.ts
|
|
61
|
+
function selectStatus(state) {
|
|
62
|
+
return state.audits.status;
|
|
63
|
+
}
|
|
64
|
+
function selectReport(state) {
|
|
65
|
+
return state.audits.report;
|
|
66
|
+
}
|
|
67
|
+
function selectError(state) {
|
|
68
|
+
return state.audits.error;
|
|
69
|
+
}
|
|
70
|
+
function selectIsStale(state) {
|
|
71
|
+
return state.audits.isStale;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/components/audit-toggle-icon.tsx
|
|
75
|
+
function AuditToggleIcon() {
|
|
76
|
+
const isStale = useSelector((state) => selectIsStale(state));
|
|
77
|
+
return /* @__PURE__ */ React.createElement(
|
|
78
|
+
Badge,
|
|
79
|
+
{
|
|
80
|
+
variant: "dot",
|
|
81
|
+
color: "warning",
|
|
82
|
+
invisible: !isStale,
|
|
83
|
+
overlap: "circular",
|
|
84
|
+
slotProps: { badge: { "data-testid": "audit-stale-indicator" } }
|
|
85
|
+
},
|
|
86
|
+
/* @__PURE__ */ React.createElement(ShieldCheckIcon, null)
|
|
87
|
+
);
|
|
88
|
+
}
|
|
11
89
|
|
|
12
90
|
// src/editor-panel.tsx
|
|
13
91
|
import { createFloatingPanel } from "@elementor/editor-floating-panels";
|
|
14
92
|
|
|
15
93
|
// src/components/audit-panel.tsx
|
|
16
|
-
import * as
|
|
17
|
-
import {
|
|
94
|
+
import * as React21 from "react";
|
|
95
|
+
import { getHostDocumentId as getHostDocumentId3 } from "@elementor/editor-elements";
|
|
18
96
|
import { FloatingPanelBody, FloatingPanelFooter, FloatingPanelHeader } from "@elementor/editor-floating-panels";
|
|
19
|
-
import { Box as
|
|
20
|
-
import { __ as
|
|
97
|
+
import { Box as Box15, Typography as Typography12 } from "@elementor/ui";
|
|
98
|
+
import { __ as __17 } from "@wordpress/i18n";
|
|
99
|
+
|
|
100
|
+
// src/constants.ts
|
|
101
|
+
import { __ } from "@wordpress/i18n";
|
|
102
|
+
var AUDIT_PANEL_ID = "audit-panel";
|
|
103
|
+
var REPORT_STORAGE_KEY_PREFIX = "elementor/audits/report";
|
|
104
|
+
var CREATE_WIDGET_EVENT = "elementor/editor/create-widget";
|
|
105
|
+
var ANGIE_FIX_ENTRY_POINT = "audit_violation";
|
|
106
|
+
var FEEDBACK_EXPERIMENT_NAME = "in_editor_feedback";
|
|
107
|
+
var FEEDBACK_ENTRY_POINT = "audit_panel";
|
|
108
|
+
var FEEDBACK_CLICKED_EVENT = "audit_feedback_clicked";
|
|
109
|
+
var FEEDBACK_SENT_EVENT = "audit_feedback_sent";
|
|
110
|
+
var FEEDBACK_CANCELLED_EVENT = "audit_feedback_cancelled";
|
|
111
|
+
var FEEDBACK_CLOSED_EVENT = "audit_feedback_closed";
|
|
112
|
+
var ALL_CATEGORIES = [
|
|
113
|
+
"best-practices",
|
|
114
|
+
"seo",
|
|
115
|
+
"accessibility",
|
|
116
|
+
"performance",
|
|
117
|
+
"compliance"
|
|
118
|
+
];
|
|
119
|
+
var CATEGORY_LABELS = {
|
|
120
|
+
"best-practices": __("Best Practices", "elementor"),
|
|
121
|
+
seo: __("SEO", "elementor"),
|
|
122
|
+
accessibility: __("Accessibility", "elementor"),
|
|
123
|
+
performance: __("Performance", "elementor"),
|
|
124
|
+
compliance: __("Site compliance", "elementor")
|
|
125
|
+
};
|
|
21
126
|
|
|
22
127
|
// src/hooks/use-audit-report.ts
|
|
23
128
|
import { useEffect } from "react";
|
|
24
|
-
import {
|
|
25
|
-
import { __useDispatch as useDispatch, __useSelector as
|
|
129
|
+
import { getHostDocumentId as getHostDocumentId2 } from "@elementor/editor-elements";
|
|
130
|
+
import { __useDispatch as useDispatch, __useSelector as useSelector2 } from "@elementor/store";
|
|
26
131
|
|
|
27
132
|
// src/runner.ts
|
|
28
|
-
import {
|
|
133
|
+
import { getHostDocumentElements, getHostDocumentId } from "@elementor/editor-elements";
|
|
29
134
|
|
|
30
135
|
// src/api/page-context-client.ts
|
|
31
136
|
import { httpService } from "@elementor/http-client";
|
|
@@ -77,17 +182,17 @@ async function requestFreshNonce() {
|
|
|
77
182
|
}
|
|
78
183
|
|
|
79
184
|
// src/api/page-context-client.ts
|
|
80
|
-
async function fetchPageContext(documentId,
|
|
81
|
-
return requestPageContext(documentId,
|
|
185
|
+
async function fetchPageContext(documentId, imageSizeRequests) {
|
|
186
|
+
return requestPageContext(documentId, imageSizeRequests, true);
|
|
82
187
|
}
|
|
83
|
-
async function requestPageContext(documentId,
|
|
188
|
+
async function requestPageContext(documentId, imageSizeRequests, allowNonceRetry) {
|
|
84
189
|
const { restNamespace, nonce } = getWindowConfig();
|
|
85
190
|
const url = `${restNamespace}/audits/page-context`;
|
|
86
191
|
try {
|
|
87
192
|
const response = await httpService().get(url, {
|
|
88
193
|
params: {
|
|
89
194
|
document_id: documentId,
|
|
90
|
-
|
|
195
|
+
image_size_requests: imageSizeRequests
|
|
91
196
|
},
|
|
92
197
|
headers: { "X-WP-Nonce": nonce }
|
|
93
198
|
});
|
|
@@ -97,52 +202,22 @@ async function requestPageContext(documentId, attachmentIds, allowNonceRetry) {
|
|
|
97
202
|
throw error;
|
|
98
203
|
}
|
|
99
204
|
await refreshAuditsNonce();
|
|
100
|
-
return requestPageContext(documentId,
|
|
205
|
+
return requestPageContext(documentId, imageSizeRequests, false);
|
|
101
206
|
}
|
|
102
207
|
}
|
|
103
208
|
|
|
104
209
|
// src/registry.ts
|
|
105
210
|
var registry = /* @__PURE__ */ new Map();
|
|
106
|
-
function registerAudit(
|
|
107
|
-
registry.set(
|
|
211
|
+
function registerAudit(audit25) {
|
|
212
|
+
registry.set(audit25.id, audit25);
|
|
108
213
|
}
|
|
109
214
|
function getRegisteredAudits() {
|
|
110
215
|
return Array.from(registry.values());
|
|
111
216
|
}
|
|
112
217
|
|
|
113
|
-
// src/constants.ts
|
|
114
|
-
import { __ } from "@wordpress/i18n";
|
|
115
|
-
var AUDIT_PANEL_ID = "audit-panel";
|
|
116
|
-
var REPORT_STORAGE_KEY_PREFIX = "elementor/audits/report";
|
|
117
|
-
var CREATE_WIDGET_EVENT = "elementor/editor/create-widget";
|
|
118
|
-
var ANGIE_FIX_ENTRY_POINT = "audit_violation";
|
|
119
|
-
var FEEDBACK_EXPERIMENT_NAME = "in_editor_feedback";
|
|
120
|
-
var FEEDBACK_ENTRY_POINT = "audit_panel";
|
|
121
|
-
var FEEDBACK_CLICKED_EVENT = "audit_feedback_clicked";
|
|
122
|
-
var FEEDBACK_SENT_EVENT = "audit_feedback_sent";
|
|
123
|
-
var FEEDBACK_CANCELLED_EVENT = "audit_feedback_cancelled";
|
|
124
|
-
var FEEDBACK_CLOSED_EVENT = "audit_feedback_closed";
|
|
125
|
-
var ALL_CATEGORIES = [
|
|
126
|
-
"best-practices",
|
|
127
|
-
"seo",
|
|
128
|
-
"accessibility",
|
|
129
|
-
"performance",
|
|
130
|
-
"compliance"
|
|
131
|
-
];
|
|
132
|
-
var CATEGORY_LABELS = {
|
|
133
|
-
"best-practices": __("Best Practices", "elementor"),
|
|
134
|
-
seo: __("SEO", "elementor"),
|
|
135
|
-
accessibility: __("Accessibility", "elementor"),
|
|
136
|
-
performance: __("Performance", "elementor"),
|
|
137
|
-
compliance: __("Site compliance", "elementor")
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
// src/utils/audit-status-summary.ts
|
|
141
|
-
import { __ as __2 } from "@wordpress/i18n";
|
|
142
|
-
|
|
143
218
|
// src/utils/is-scored-audit.ts
|
|
144
|
-
function isScoredAudit(
|
|
145
|
-
return
|
|
219
|
+
function isScoredAudit(audit25) {
|
|
220
|
+
return audit25.weight > 0;
|
|
146
221
|
}
|
|
147
222
|
|
|
148
223
|
// src/utils/sort-failed-audits.ts
|
|
@@ -194,52 +269,6 @@ function partitionAuditResults(report, options = {}) {
|
|
|
194
269
|
totalViolations
|
|
195
270
|
};
|
|
196
271
|
}
|
|
197
|
-
function auditStatusDisplayCounts(report) {
|
|
198
|
-
let pass = 0;
|
|
199
|
-
let skipped = 0;
|
|
200
|
-
let totalViolations = 0;
|
|
201
|
-
for (const { audit: audit23, result } of report.auditResults) {
|
|
202
|
-
if (!isScoredAudit(audit23)) {
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
switch (result.status) {
|
|
206
|
-
case "fail":
|
|
207
|
-
totalViolations += result.violations.length;
|
|
208
|
-
break;
|
|
209
|
-
case "pass":
|
|
210
|
-
pass++;
|
|
211
|
-
break;
|
|
212
|
-
case "skipped":
|
|
213
|
-
skipped++;
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return {
|
|
218
|
-
fail: totalViolations,
|
|
219
|
-
pass,
|
|
220
|
-
skipped
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
function auditStatusColor(status) {
|
|
224
|
-
switch (status) {
|
|
225
|
-
case "fail":
|
|
226
|
-
return "error";
|
|
227
|
-
case "pass":
|
|
228
|
-
return "success";
|
|
229
|
-
case "skipped":
|
|
230
|
-
return "default";
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
function auditStatusLabel(status) {
|
|
234
|
-
switch (status) {
|
|
235
|
-
case "fail":
|
|
236
|
-
return __2("Failed audits", "elementor");
|
|
237
|
-
case "pass":
|
|
238
|
-
return __2("Passed audits", "elementor");
|
|
239
|
-
case "skipped":
|
|
240
|
-
return __2("Skipped audits", "elementor");
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
272
|
function getPopulatedCategories(categoryTotals, categories) {
|
|
244
273
|
return categories.filter((category) => categoryTotals[category].total > 0);
|
|
245
274
|
}
|
|
@@ -249,16 +278,16 @@ function computeReport(documentId, results) {
|
|
|
249
278
|
const accumulators = Object.fromEntries(
|
|
250
279
|
ALL_CATEGORIES.map((c) => [c, { totalWeight: 0, passedWeight: 0, total: 0, failed: 0 }])
|
|
251
280
|
);
|
|
252
|
-
for (const { audit:
|
|
281
|
+
for (const { audit: audit25, result } of results) {
|
|
253
282
|
if (result.status === "skipped") {
|
|
254
283
|
continue;
|
|
255
284
|
}
|
|
256
|
-
for (const category of
|
|
285
|
+
for (const category of audit25.categories) {
|
|
257
286
|
const acc = accumulators[category];
|
|
258
287
|
acc.total++;
|
|
259
|
-
acc.totalWeight +=
|
|
288
|
+
acc.totalWeight += audit25.weight;
|
|
260
289
|
if (result.status === "pass") {
|
|
261
|
-
acc.passedWeight +=
|
|
290
|
+
acc.passedWeight += audit25.weight;
|
|
262
291
|
} else {
|
|
263
292
|
acc.failed++;
|
|
264
293
|
}
|
|
@@ -282,6 +311,44 @@ function computeReport(documentId, results) {
|
|
|
282
311
|
};
|
|
283
312
|
}
|
|
284
313
|
|
|
314
|
+
// src/utils/fetch-rendered-html.ts
|
|
315
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
316
|
+
async function fetchRenderedHtml(url) {
|
|
317
|
+
if (!url) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const timeoutController = new AbortController();
|
|
321
|
+
const timeoutId = setTimeout(() => timeoutController.abort(), FETCH_TIMEOUT_MS);
|
|
322
|
+
try {
|
|
323
|
+
const response = await fetch(url, { credentials: "omit", signal: timeoutController.signal });
|
|
324
|
+
if (!response.ok) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
return await response.text();
|
|
328
|
+
} catch {
|
|
329
|
+
return null;
|
|
330
|
+
} finally {
|
|
331
|
+
clearTimeout(timeoutId);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/utils/atomic-background-image-sources.ts
|
|
336
|
+
import { getElementStyles } from "@elementor/editor-elements";
|
|
337
|
+
import {
|
|
338
|
+
backgroundImageOverlayPropTypeUtil,
|
|
339
|
+
backgroundOverlayPropTypeUtil,
|
|
340
|
+
backgroundPropTypeUtil
|
|
341
|
+
} from "@elementor/editor-props";
|
|
342
|
+
|
|
343
|
+
// src/utils/atomic-image-sources.ts
|
|
344
|
+
import {
|
|
345
|
+
imageAttachmentIdPropType,
|
|
346
|
+
imagePropTypeUtil,
|
|
347
|
+
imageSrcPropTypeUtil,
|
|
348
|
+
stringPropTypeUtil,
|
|
349
|
+
urlPropTypeUtil
|
|
350
|
+
} from "@elementor/editor-props";
|
|
351
|
+
|
|
285
352
|
// src/utils/walk.ts
|
|
286
353
|
function walkElements(tree, visit) {
|
|
287
354
|
const parents = [];
|
|
@@ -296,17 +363,93 @@ function recurse(nodes, parents, visit) {
|
|
|
296
363
|
}
|
|
297
364
|
}
|
|
298
365
|
|
|
299
|
-
// src/utils/image-
|
|
300
|
-
var
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (
|
|
305
|
-
|
|
366
|
+
// src/utils/atomic-image-sources.ts
|
|
367
|
+
var ATOMIC_CONTENT_IMAGE_PROP_KEYS = ["image"];
|
|
368
|
+
var ATOMIC_IMAGE_PROP_KEYS = [...ATOMIC_CONTENT_IMAGE_PROP_KEYS, "poster"];
|
|
369
|
+
function walkAtomicImageSources(tree, visit, propKeys = ATOMIC_IMAGE_PROP_KEYS) {
|
|
370
|
+
walkElements(tree, (node) => {
|
|
371
|
+
if (node.elType !== "widget") {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
for (const key of propKeys) {
|
|
375
|
+
const media = extractAtomicImageMedia(node.settings[key]);
|
|
376
|
+
if (media) {
|
|
377
|
+
visit({ node, media });
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
function extractAtomicImageMedia(imageProp) {
|
|
383
|
+
const image = imagePropTypeUtil.extract(imageProp);
|
|
384
|
+
if (!image) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
const src = imageSrcPropTypeUtil.extract(image.src);
|
|
388
|
+
if (!src) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
const id = imageAttachmentIdPropType.extract(src.id) ?? void 0;
|
|
392
|
+
const url = urlPropTypeUtil.extract(src.url) ?? void 0;
|
|
393
|
+
if (!id && !url) {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
const alt = stringPropTypeUtil.extract(src.alt) ?? void 0;
|
|
397
|
+
const size = stringPropTypeUtil.extract(image.size) ?? void 0;
|
|
398
|
+
return { id, url, alt, size };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// src/utils/atomic-background-image-sources.ts
|
|
402
|
+
function walkAtomicBackgroundImageSources(tree, visit) {
|
|
403
|
+
walkElements(tree, (node) => {
|
|
404
|
+
const styles = getElementStyles(node.id);
|
|
405
|
+
if (!styles) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
for (const media of extractBackgroundImageMedia(styles)) {
|
|
409
|
+
visit({ node, media });
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
function extractBackgroundImageMedia(styles) {
|
|
414
|
+
const sources = [];
|
|
415
|
+
for (const style of Object.values(styles)) {
|
|
416
|
+
for (const variant of style.variants) {
|
|
417
|
+
const background = backgroundPropTypeUtil.extract(variant.props.background);
|
|
418
|
+
const overlays = backgroundOverlayPropTypeUtil.extract(background?.["background-overlay"]) ?? [];
|
|
419
|
+
for (const overlay of overlays) {
|
|
420
|
+
const imageOverlay = backgroundImageOverlayPropTypeUtil.extract(overlay);
|
|
421
|
+
const media = extractAtomicImageMedia(imageOverlay?.image);
|
|
422
|
+
if (media) {
|
|
423
|
+
sources.push(media);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return sources;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/utils/background-image-sources.ts
|
|
432
|
+
var BACKGROUND_IMAGE_SETTING_KEYS = [
|
|
433
|
+
"background_image",
|
|
434
|
+
"background_hover_image",
|
|
435
|
+
"background_overlay_image",
|
|
436
|
+
"background_overlay_hover_image",
|
|
437
|
+
"_background_image",
|
|
438
|
+
"_background_hover_image"
|
|
439
|
+
];
|
|
440
|
+
function walkBackgroundImageSources(tree, visit) {
|
|
441
|
+
walkElements(tree, (node) => {
|
|
442
|
+
for (const key of BACKGROUND_IMAGE_SETTING_KEYS) {
|
|
443
|
+
const media = node.settings[key];
|
|
444
|
+
if (media?.id || media?.url) {
|
|
445
|
+
visit({ node, media });
|
|
446
|
+
}
|
|
306
447
|
}
|
|
307
448
|
});
|
|
308
|
-
return found;
|
|
309
449
|
}
|
|
450
|
+
|
|
451
|
+
// src/utils/image-like-sources.ts
|
|
452
|
+
var IMAGE_LIKE_WIDGETS = /* @__PURE__ */ new Set(["image", "image-box", "image-carousel", "gallery", "image-gallery"]);
|
|
310
453
|
function walkImageLikeSources(tree, visit) {
|
|
311
454
|
walkElements(tree, (node) => {
|
|
312
455
|
if (node.elType !== "widget") {
|
|
@@ -324,28 +467,42 @@ function collectMediaFromNode(node) {
|
|
|
324
467
|
const sources = [];
|
|
325
468
|
const image = node.settings.image;
|
|
326
469
|
if (image?.id || image?.url) {
|
|
327
|
-
sources.push(image);
|
|
470
|
+
sources.push({ ...image, size: node.settings.image_size });
|
|
328
471
|
}
|
|
329
472
|
const gallery = node.settings.carousel ?? node.settings.gallery ?? node.settings.wp_gallery;
|
|
330
473
|
if (Array.isArray(gallery)) {
|
|
474
|
+
const gallerySize = node.settings.thumbnail_size;
|
|
331
475
|
for (const item of gallery) {
|
|
332
476
|
if (item?.id || item?.url) {
|
|
333
|
-
sources.push(item);
|
|
477
|
+
sources.push({ ...item, size: gallerySize });
|
|
334
478
|
}
|
|
335
479
|
}
|
|
336
480
|
}
|
|
337
481
|
return sources;
|
|
338
482
|
}
|
|
339
483
|
|
|
484
|
+
// src/utils/all-image-sources.ts
|
|
485
|
+
function walkAllImageSources(tree, visit) {
|
|
486
|
+
walkImageLikeSources(tree, visit);
|
|
487
|
+
walkBackgroundImageSources(tree, visit);
|
|
488
|
+
walkAtomicImageSources(tree, visit);
|
|
489
|
+
walkAtomicBackgroundImageSources(tree, visit);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/utils/image-size-key.ts
|
|
493
|
+
function buildImageSizeKey({ id, size }) {
|
|
494
|
+
return `${id}:${size || "full"}`;
|
|
495
|
+
}
|
|
496
|
+
|
|
340
497
|
// src/utils/page-attachments.ts
|
|
341
|
-
function
|
|
342
|
-
const
|
|
343
|
-
|
|
498
|
+
function extractImageSizeRequests(tree) {
|
|
499
|
+
const keys = /* @__PURE__ */ new Set();
|
|
500
|
+
walkAllImageSources(tree, ({ media }) => {
|
|
344
501
|
if (media.id) {
|
|
345
|
-
|
|
502
|
+
keys.add(buildImageSizeKey({ id: media.id, size: media.size }));
|
|
346
503
|
}
|
|
347
504
|
});
|
|
348
|
-
return Array.from(
|
|
505
|
+
return Array.from(keys).sort();
|
|
349
506
|
}
|
|
350
507
|
|
|
351
508
|
// src/utils/read-kit-snapshot.ts
|
|
@@ -439,18 +596,24 @@ function toSnapshot(element) {
|
|
|
439
596
|
|
|
440
597
|
// src/runner.ts
|
|
441
598
|
async function runPageAudit(documentId) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
599
|
+
if (documentId !== getHostDocumentId()) {
|
|
600
|
+
throw new Error("runPageAudit: documentId must match the host document.");
|
|
601
|
+
}
|
|
602
|
+
const tree = buildSnapshotTree(getHostDocumentElements());
|
|
603
|
+
const imageSizeRequests = extractImageSizeRequests(tree);
|
|
604
|
+
const pageContext = await fetchPageContext(documentId, imageSizeRequests);
|
|
445
605
|
const elements = { documentId, tree };
|
|
446
|
-
const kit = await
|
|
447
|
-
|
|
606
|
+
const [kit, renderedHtml] = await Promise.all([
|
|
607
|
+
readKitSnapshot(pageContext.kit_id),
|
|
608
|
+
fetchRenderedHtml(pageContext.frontend_url)
|
|
609
|
+
]);
|
|
610
|
+
const ctx = { documentId, elements, pageContext, kit, renderedHtml };
|
|
448
611
|
const registered = getRegisteredAudits();
|
|
449
612
|
const auditResults = await Promise.all(
|
|
450
|
-
registered.map(async (
|
|
451
|
-
const { evaluate: _evaluate, ...meta } =
|
|
613
|
+
registered.map(async (audit25) => {
|
|
614
|
+
const { evaluate: _evaluate, ...meta } = audit25;
|
|
452
615
|
try {
|
|
453
|
-
const result = await
|
|
616
|
+
const result = await audit25.evaluate(ctx);
|
|
454
617
|
return { audit: meta, result };
|
|
455
618
|
} catch (error) {
|
|
456
619
|
const reason = error instanceof Error ? error.message : "unknown-error";
|
|
@@ -461,52 +624,6 @@ async function runPageAudit(documentId) {
|
|
|
461
624
|
return computeReport(documentId, auditResults);
|
|
462
625
|
}
|
|
463
626
|
|
|
464
|
-
// src/store/slice.ts
|
|
465
|
-
import { __createSlice } from "@elementor/store";
|
|
466
|
-
var initialState = { status: "idle", report: null, error: null };
|
|
467
|
-
var slice = __createSlice({
|
|
468
|
-
name: "audits",
|
|
469
|
-
initialState,
|
|
470
|
-
reducers: {
|
|
471
|
-
runStarted(state) {
|
|
472
|
-
state.status = "loading";
|
|
473
|
-
state.error = null;
|
|
474
|
-
},
|
|
475
|
-
runSucceeded(state, action) {
|
|
476
|
-
state.status = "ready";
|
|
477
|
-
state.report = action.payload;
|
|
478
|
-
},
|
|
479
|
-
runFailed(state, action) {
|
|
480
|
-
state.status = "error";
|
|
481
|
-
state.error = action.payload;
|
|
482
|
-
},
|
|
483
|
-
runAborted(state) {
|
|
484
|
-
state.status = state.report ? "ready" : "idle";
|
|
485
|
-
},
|
|
486
|
-
reportRestored(state, action) {
|
|
487
|
-
state.status = "ready";
|
|
488
|
-
state.report = action.payload;
|
|
489
|
-
state.error = null;
|
|
490
|
-
},
|
|
491
|
-
reportCleared(state) {
|
|
492
|
-
state.status = "idle";
|
|
493
|
-
state.report = null;
|
|
494
|
-
state.error = null;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
// src/store/selectors.ts
|
|
500
|
-
function selectStatus(state) {
|
|
501
|
-
return state.audits.status;
|
|
502
|
-
}
|
|
503
|
-
function selectReport(state) {
|
|
504
|
-
return state.audits.report;
|
|
505
|
-
}
|
|
506
|
-
function selectError(state) {
|
|
507
|
-
return state.audits.error;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
627
|
// src/utils/report-storage.ts
|
|
511
628
|
import { getSessionStorageItem, setSessionStorageItem } from "@elementor/session";
|
|
512
629
|
function getStorageKey(documentId) {
|
|
@@ -521,42 +638,44 @@ function persistReport(documentId, report) {
|
|
|
521
638
|
|
|
522
639
|
// src/hooks/use-audit-report.ts
|
|
523
640
|
function useAuditReport() {
|
|
524
|
-
const status =
|
|
525
|
-
const report =
|
|
526
|
-
const error =
|
|
527
|
-
const
|
|
528
|
-
const
|
|
641
|
+
const status = useSelector2((state) => selectStatus(state));
|
|
642
|
+
const report = useSelector2((state) => selectReport(state));
|
|
643
|
+
const error = useSelector2((state) => selectError(state));
|
|
644
|
+
const isStale = useSelector2((state) => selectIsStale(state));
|
|
645
|
+
const dispatch2 = useDispatch();
|
|
646
|
+
const documentId = getHostDocumentId2() ?? 0;
|
|
529
647
|
useEffect(() => {
|
|
530
648
|
if (!documentId || report?.documentId === documentId) {
|
|
531
649
|
return;
|
|
532
650
|
}
|
|
533
651
|
const persisted = getPersistedReport(documentId);
|
|
534
652
|
if (persisted) {
|
|
535
|
-
|
|
653
|
+
dispatch2(slice.actions.reportRestored(persisted));
|
|
536
654
|
} else if (report) {
|
|
537
|
-
|
|
655
|
+
dispatch2(slice.actions.reportCleared());
|
|
538
656
|
}
|
|
539
|
-
}, [documentId, report,
|
|
657
|
+
}, [documentId, report, dispatch2]);
|
|
540
658
|
const run = async (documentIdToRun) => {
|
|
541
|
-
|
|
659
|
+
dispatch2(slice.actions.runStarted());
|
|
542
660
|
try {
|
|
543
661
|
const nextReport = await runPageAudit(documentIdToRun);
|
|
544
|
-
|
|
662
|
+
dispatch2(slice.actions.runSucceeded(nextReport));
|
|
545
663
|
persistReport(documentIdToRun, nextReport);
|
|
546
664
|
} catch (e) {
|
|
547
665
|
if (e instanceof SessionExpiredError) {
|
|
548
|
-
|
|
666
|
+
dispatch2(slice.actions.runAborted());
|
|
549
667
|
return;
|
|
550
668
|
}
|
|
551
|
-
|
|
669
|
+
dispatch2(slice.actions.runFailed(e instanceof Error ? e.message : "Unknown error"));
|
|
552
670
|
}
|
|
553
671
|
};
|
|
554
|
-
return { status, report, error, run };
|
|
672
|
+
return { status, report, error, isStale, run };
|
|
555
673
|
}
|
|
556
674
|
|
|
557
675
|
// src/components/audit-feedback.tsx
|
|
558
|
-
import * as
|
|
676
|
+
import * as React2 from "react";
|
|
559
677
|
import { useState } from "react";
|
|
678
|
+
import { useFloatingPanelZIndex } from "@elementor/editor-floating-panels";
|
|
560
679
|
import { notify } from "@elementor/editor-notifications";
|
|
561
680
|
import { isExperimentActive } from "@elementor/editor-v1-adapters";
|
|
562
681
|
import { useMixpanel } from "@elementor/events";
|
|
@@ -575,9 +694,9 @@ import {
|
|
|
575
694
|
Tooltip,
|
|
576
695
|
Typography
|
|
577
696
|
} from "@elementor/ui";
|
|
578
|
-
import { __ as
|
|
697
|
+
import { __ as __2 } from "@wordpress/i18n";
|
|
579
698
|
var FEEDBACK_SUBJECT = "Page Audit Tool";
|
|
580
|
-
var FEEDBACK_SUBJECT_LABEL =
|
|
699
|
+
var FEEDBACK_SUBJECT_LABEL = __2("Page Audit Tool", "elementor");
|
|
581
700
|
var SUCCESS_NOTIFICATION_ID = "audit-feedback-success";
|
|
582
701
|
var ERROR_NOTIFICATION_ID = "audit-feedback-error";
|
|
583
702
|
var DIALOG_TITLE_ID = "audit-feedback-dialog-title";
|
|
@@ -586,18 +705,19 @@ var isUserConnected = () => Boolean(window.elementorCommon?.config?.library_conn
|
|
|
586
705
|
var notifySuccess = () => notify({
|
|
587
706
|
id: SUCCESS_NOTIFICATION_ID,
|
|
588
707
|
type: "success",
|
|
589
|
-
message:
|
|
708
|
+
message: __2("Feedback sent. Thanks for helping us out.", "elementor")
|
|
590
709
|
});
|
|
591
710
|
var notifyError = () => notify({
|
|
592
711
|
id: ERROR_NOTIFICATION_ID,
|
|
593
712
|
type: "error",
|
|
594
|
-
message:
|
|
713
|
+
message: __2("Something went wrong. Please try sending your feedback again.", "elementor")
|
|
595
714
|
});
|
|
596
715
|
function AuditFeedback() {
|
|
597
716
|
const [isOpen, setIsOpen] = useState(false);
|
|
598
717
|
const [feedbackText, setFeedbackText] = useState("");
|
|
599
718
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
600
719
|
const { dispatchEvent: trackEvent = (...args) => void args } = useMixpanel();
|
|
720
|
+
const panelZIndex = useFloatingPanelZIndex(AUDIT_PANEL_ID);
|
|
601
721
|
if (!isExperimentActive(FEEDBACK_EXPERIMENT_NAME)) {
|
|
602
722
|
return null;
|
|
603
723
|
}
|
|
@@ -606,7 +726,7 @@ function AuditFeedback() {
|
|
|
606
726
|
if (!connected && !connectUrl) {
|
|
607
727
|
return null;
|
|
608
728
|
}
|
|
609
|
-
const triggerLabel =
|
|
729
|
+
const triggerLabel = __2("Give feedback", "elementor");
|
|
610
730
|
const handleOpen = () => {
|
|
611
731
|
if (!connected) {
|
|
612
732
|
window.open(connectUrl, "_blank", "noopener");
|
|
@@ -639,7 +759,7 @@ function AuditFeedback() {
|
|
|
639
759
|
trackEvent(FEEDBACK_SENT_EVENT, { entry_point: FEEDBACK_ENTRY_POINT });
|
|
640
760
|
}).catch(notifyError).finally(() => setIsSubmitting(false));
|
|
641
761
|
};
|
|
642
|
-
return /* @__PURE__ */
|
|
762
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Tooltip, { title: triggerLabel, placement: "top", PopperProps: { sx: { zIndex: panelZIndex } } }, /* @__PURE__ */ React2.createElement(IconButton, { size: "small", "aria-label": triggerLabel, onClick: handleOpen }, /* @__PURE__ */ React2.createElement(MessageLinesIcon, { fontSize: "small" }))), /* @__PURE__ */ React2.createElement(
|
|
643
763
|
Dialog,
|
|
644
764
|
{
|
|
645
765
|
open: isOpen,
|
|
@@ -648,11 +768,11 @@ function AuditFeedback() {
|
|
|
648
768
|
"aria-describedby": DIALOG_DESCRIPTION_ID,
|
|
649
769
|
PaperProps: { sx: { borderRadius: 1 } }
|
|
650
770
|
},
|
|
651
|
-
/* @__PURE__ */
|
|
652
|
-
/* @__PURE__ */
|
|
771
|
+
/* @__PURE__ */ React2.createElement(DialogHeader, { logo: false, onClose: handleClose }, /* @__PURE__ */ React2.createElement(DialogTitle, { id: DIALOG_TITLE_ID }, __2("Let us know what you think", "elementor"))),
|
|
772
|
+
/* @__PURE__ */ React2.createElement(DialogContent, { dividers: true }, /* @__PURE__ */ React2.createElement(Stack, { direction: "column", gap: 2 }, /* @__PURE__ */ React2.createElement(TextField, { value: FEEDBACK_SUBJECT_LABEL, disabled: true, fullWidth: true, size: "small" }), /* @__PURE__ */ React2.createElement(
|
|
653
773
|
TextField,
|
|
654
774
|
{
|
|
655
|
-
placeholder:
|
|
775
|
+
placeholder: __2(
|
|
656
776
|
"Tell us what you had in mind, what we can improve or fix to make this feature better.",
|
|
657
777
|
"elementor"
|
|
658
778
|
),
|
|
@@ -663,11 +783,11 @@ function AuditFeedback() {
|
|
|
663
783
|
onChange: (event) => setFeedbackText(event.target.value),
|
|
664
784
|
value: feedbackText
|
|
665
785
|
}
|
|
666
|
-
), /* @__PURE__ */
|
|
786
|
+
), /* @__PURE__ */ React2.createElement(Typography, { id: DIALOG_DESCRIPTION_ID, variant: "caption", color: "text.secondary" }, __2(
|
|
667
787
|
"We appreciate your feedback! While we review all submissions, we can't guarantee that every suggestion will result in a change or update.",
|
|
668
788
|
"elementor"
|
|
669
789
|
)))),
|
|
670
|
-
/* @__PURE__ */
|
|
790
|
+
/* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { variant: "text", color: "secondary", onClick: handleCancel }, __2("Cancel", "elementor")), /* @__PURE__ */ React2.createElement(
|
|
671
791
|
Button,
|
|
672
792
|
{
|
|
673
793
|
variant: "contained",
|
|
@@ -675,35 +795,35 @@ function AuditFeedback() {
|
|
|
675
795
|
disabled: isSubmitting || feedbackText.trim().length === 0,
|
|
676
796
|
onClick: handleSubmit
|
|
677
797
|
},
|
|
678
|
-
|
|
798
|
+
__2("Send", "elementor")
|
|
679
799
|
))
|
|
680
800
|
));
|
|
681
801
|
}
|
|
682
802
|
|
|
683
803
|
// src/components/pages/error-page.tsx
|
|
684
|
-
import * as
|
|
804
|
+
import * as React3 from "react";
|
|
685
805
|
import { Box, Button as Button2, Typography as Typography2 } from "@elementor/ui";
|
|
686
|
-
import { __ as
|
|
806
|
+
import { __ as __3 } from "@wordpress/i18n";
|
|
687
807
|
function ErrorPage({ message, onRetry }) {
|
|
688
|
-
return /* @__PURE__ */
|
|
808
|
+
return /* @__PURE__ */ React3.createElement(Box, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 1.5, p: 4 } }, /* @__PURE__ */ React3.createElement(Typography2, { variant: "body2", color: "error", textAlign: "center" }, message), /* @__PURE__ */ React3.createElement(Button2, { variant: "contained", size: "small", onClick: onRetry }, __3("Try again", "elementor")));
|
|
689
809
|
}
|
|
690
810
|
|
|
691
811
|
// src/components/pages/loading-page.tsx
|
|
692
|
-
import * as
|
|
812
|
+
import * as React4 from "react";
|
|
693
813
|
import { Box as Box2, CircularProgress, Typography as Typography3 } from "@elementor/ui";
|
|
694
|
-
import { __ as
|
|
814
|
+
import { __ as __4 } from "@wordpress/i18n";
|
|
695
815
|
function LoadingPage() {
|
|
696
|
-
return /* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ React4.createElement(Box2, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 1.5, p: 4 } }, /* @__PURE__ */ React4.createElement(CircularProgress, { size: 32 }), /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2" }, __4("Audit in progress.", "elementor")));
|
|
697
817
|
}
|
|
698
818
|
|
|
699
819
|
// src/components/pages/welcome-page.tsx
|
|
700
|
-
import * as
|
|
820
|
+
import * as React5 from "react";
|
|
701
821
|
import { Box as Box3, Typography as Typography4 } from "@elementor/ui";
|
|
702
|
-
import { __ as
|
|
822
|
+
import { __ as __5 } from "@wordpress/i18n";
|
|
703
823
|
var INFORMATION_IMAGE_PATH = "images/information.svg";
|
|
704
824
|
function WelcomePage() {
|
|
705
825
|
const assetsUrl = window.elementorCommon?.config?.urls?.assets ?? "";
|
|
706
|
-
return /* @__PURE__ */
|
|
826
|
+
return /* @__PURE__ */ React5.createElement(
|
|
707
827
|
Box3,
|
|
708
828
|
{
|
|
709
829
|
sx: {
|
|
@@ -715,17 +835,17 @@ function WelcomePage() {
|
|
|
715
835
|
p: 3
|
|
716
836
|
}
|
|
717
837
|
},
|
|
718
|
-
/* @__PURE__ */
|
|
838
|
+
/* @__PURE__ */ React5.createElement(
|
|
719
839
|
"img",
|
|
720
840
|
{
|
|
721
841
|
className: "elementor-nerd-box-icon",
|
|
722
842
|
src: `${assetsUrl}${INFORMATION_IMAGE_PATH}`,
|
|
723
843
|
loading: "lazy",
|
|
724
|
-
alt:
|
|
844
|
+
alt: __5("Elementor", "elementor")
|
|
725
845
|
}
|
|
726
846
|
),
|
|
727
|
-
/* @__PURE__ */
|
|
728
|
-
/* @__PURE__ */
|
|
847
|
+
/* @__PURE__ */ React5.createElement(Typography4, { variant: "subtitle1", component: "h3", sx: { marginBlockStart: 2 } }, __5("Audit your page!", "elementor")),
|
|
848
|
+
/* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", textAlign: "center" }, __5(
|
|
729
849
|
'Check SEO, accessibility, performance, and best practices. Click "Run page audit" to begin.',
|
|
730
850
|
"elementor"
|
|
731
851
|
))
|
|
@@ -733,40 +853,59 @@ function WelcomePage() {
|
|
|
733
853
|
}
|
|
734
854
|
|
|
735
855
|
// src/components/report-shell.tsx
|
|
736
|
-
import * as
|
|
737
|
-
import { useState as
|
|
738
|
-
import { Box as
|
|
739
|
-
import { __ as __22 } from "@wordpress/i18n";
|
|
856
|
+
import * as React19 from "react";
|
|
857
|
+
import { useState as useState4 } from "react";
|
|
858
|
+
import { Box as Box14 } from "@elementor/ui";
|
|
740
859
|
|
|
741
|
-
// src/components/pages/
|
|
742
|
-
import * as
|
|
860
|
+
// src/components/pages/category-page.tsx
|
|
861
|
+
import * as React13 from "react";
|
|
743
862
|
import { Box as Box8 } from "@elementor/ui";
|
|
744
|
-
import { __ as
|
|
863
|
+
import { __ as __11 } from "@wordpress/i18n";
|
|
745
864
|
|
|
746
|
-
// src/
|
|
747
|
-
import * as React5 from "react";
|
|
865
|
+
// src/hooks/use-single-expanded-card.ts
|
|
748
866
|
import { useState as useState2 } from "react";
|
|
867
|
+
function useSingleExpandedCard(initialId = null) {
|
|
868
|
+
const [expandedId, setExpandedId] = useState2(initialId);
|
|
869
|
+
const toggle = (id) => {
|
|
870
|
+
setExpandedId((current) => current === id ? null : id);
|
|
871
|
+
};
|
|
872
|
+
return { expandedId, toggle };
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/components/category-icons.ts
|
|
876
|
+
import { BoltIcon, ElementorAccessibilityIcon, FileSearchIcon, Settings2Icon, ShieldCheckIcon as ShieldCheckIcon2 } from "@elementor/icons";
|
|
877
|
+
var CATEGORY_ICONS = {
|
|
878
|
+
"best-practices": Settings2Icon,
|
|
879
|
+
seo: FileSearchIcon,
|
|
880
|
+
accessibility: ElementorAccessibilityIcon,
|
|
881
|
+
performance: BoltIcon,
|
|
882
|
+
compliance: ShieldCheckIcon2
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
// src/components/status-section.tsx
|
|
886
|
+
import * as React6 from "react";
|
|
887
|
+
import { useState as useState3 } from "react";
|
|
749
888
|
import { ChevronDownIcon } from "@elementor/icons";
|
|
750
889
|
import { Box as Box4, Chip, Collapse, IconButton as IconButton2 } from "@elementor/ui";
|
|
751
|
-
import { __ as
|
|
890
|
+
import { __ as __6 } from "@wordpress/i18n";
|
|
752
891
|
function StatusSection({ label, count, color = "default", defaultExpanded = false, children }) {
|
|
753
|
-
const [expanded, setExpanded] =
|
|
754
|
-
if (
|
|
892
|
+
const [expanded, setExpanded] = useState3(defaultExpanded);
|
|
893
|
+
if (React6.Children.count(children) === 0) {
|
|
755
894
|
return null;
|
|
756
895
|
}
|
|
757
|
-
return /* @__PURE__ */
|
|
896
|
+
return /* @__PURE__ */ React6.createElement(Box4, { sx: { paddingBlock: 1 } }, /* @__PURE__ */ React6.createElement(
|
|
758
897
|
Box4,
|
|
759
898
|
{
|
|
760
899
|
sx: { display: "flex", alignItems: "center", gap: 0.5, cursor: "pointer" },
|
|
761
900
|
onClick: () => setExpanded((v) => !v)
|
|
762
901
|
},
|
|
763
|
-
/* @__PURE__ */
|
|
902
|
+
/* @__PURE__ */ React6.createElement(
|
|
764
903
|
IconButton2,
|
|
765
904
|
{
|
|
766
905
|
size: "small",
|
|
767
|
-
"aria-label": expanded ?
|
|
906
|
+
"aria-label": expanded ? __6("Collapse", "elementor") : __6("Expand", "elementor")
|
|
768
907
|
},
|
|
769
|
-
/* @__PURE__ */
|
|
908
|
+
/* @__PURE__ */ React6.createElement(
|
|
770
909
|
ChevronDownIcon,
|
|
771
910
|
{
|
|
772
911
|
fontSize: "small",
|
|
@@ -777,27 +916,27 @@ function StatusSection({ label, count, color = "default", defaultExpanded = fals
|
|
|
777
916
|
}
|
|
778
917
|
)
|
|
779
918
|
),
|
|
780
|
-
/* @__PURE__ */
|
|
781
|
-
), /* @__PURE__ */
|
|
919
|
+
/* @__PURE__ */ React6.createElement(Chip, { label: `${label} (${count})`, size: "small", color, variant: "standard" })
|
|
920
|
+
), /* @__PURE__ */ React6.createElement(Collapse, { in: expanded }, /* @__PURE__ */ React6.createElement(Box4, { sx: { paddingInlineStart: 4.25, paddingBlock: 2 } }, children)));
|
|
782
921
|
}
|
|
783
922
|
|
|
784
923
|
// src/components/subpage-header.tsx
|
|
785
|
-
import * as
|
|
924
|
+
import * as React7 from "react";
|
|
786
925
|
import { ArrowLeftIcon } from "@elementor/icons";
|
|
787
926
|
import { Box as Box5, IconButton as IconButton3, Rotate, Typography as Typography5, useTheme } from "@elementor/ui";
|
|
788
|
-
import { __ as
|
|
927
|
+
import { __ as __7 } from "@wordpress/i18n";
|
|
789
928
|
function SubpageHeader({ title, onBack, backLabel, icon }) {
|
|
790
929
|
const isRtl = "rtl" === useTheme().direction;
|
|
791
|
-
return /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ React7.createElement(Box5, { sx: { display: "flex", alignItems: "center", gap: 0.5, p: 1 } }, /* @__PURE__ */ React7.createElement(IconButton3, { size: "small", onClick: onBack, "aria-label": backLabel ?? __7("Back", "elementor") }, /* @__PURE__ */ React7.createElement(Rotate, { in: isRtl }, /* @__PURE__ */ React7.createElement(ArrowLeftIcon, { fontSize: "small" }))), icon, /* @__PURE__ */ React7.createElement(Typography5, { variant: "subtitle2", fontWeight: "bold" }, title));
|
|
792
931
|
}
|
|
793
932
|
|
|
794
933
|
// src/components/violation-row.tsx
|
|
795
|
-
import * as
|
|
796
|
-
import { useState as useState3 } from "react";
|
|
934
|
+
import * as React12 from "react";
|
|
797
935
|
import { getElementIcon, getElementTitle } from "@elementor/editor-elements";
|
|
798
|
-
import {
|
|
799
|
-
import {
|
|
800
|
-
import {
|
|
936
|
+
import { useFloatingPanelZIndex as useFloatingPanelZIndex2 } from "@elementor/editor-floating-panels";
|
|
937
|
+
import { CheckIcon, ChevronDownIcon as ChevronDownIcon2, HelpIcon, InfoCircleIcon } from "@elementor/icons";
|
|
938
|
+
import { Alert, Box as Box7, Collapse as Collapse2, IconButton as IconButton5, Tooltip as Tooltip3, Typography as Typography6 } from "@elementor/ui";
|
|
939
|
+
import { __ as __10 } from "@wordpress/i18n";
|
|
801
940
|
|
|
802
941
|
// src/hooks/focus-violation.ts
|
|
803
942
|
import { getContainer, selectElement } from "@elementor/editor-elements";
|
|
@@ -838,11 +977,11 @@ function focusViolation(violation) {
|
|
|
838
977
|
}
|
|
839
978
|
|
|
840
979
|
// src/utils/build-angie-prompt.ts
|
|
841
|
-
import { __ as
|
|
980
|
+
import { __ as __8, sprintf } from "@wordpress/i18n";
|
|
842
981
|
function buildAngiePrompt(violationText) {
|
|
843
982
|
return sprintf(
|
|
844
983
|
/* translators: %s: audit violation description. */
|
|
845
|
-
|
|
984
|
+
__8("Help me fix: %s", "elementor"),
|
|
846
985
|
violationText
|
|
847
986
|
);
|
|
848
987
|
}
|
|
@@ -858,13 +997,13 @@ function onKeyboardClick(callback) {
|
|
|
858
997
|
}
|
|
859
998
|
|
|
860
999
|
// src/components/fix-violation-with-angie.tsx
|
|
861
|
-
import * as
|
|
1000
|
+
import * as React8 from "react";
|
|
862
1001
|
import { isAngieAvailable, sendPromptToAngie } from "@elementor/editor-mcp";
|
|
863
1002
|
import { AngieIcon } from "@elementor/icons";
|
|
864
|
-
import { IconButton as IconButton4, Tooltip as Tooltip2 } from "@elementor/ui";
|
|
865
|
-
import { __ as
|
|
866
|
-
function FixViolationWithAngie({ prompt }) {
|
|
867
|
-
const label =
|
|
1003
|
+
import { Button as Button3, IconButton as IconButton4, Tooltip as Tooltip2 } from "@elementor/ui";
|
|
1004
|
+
import { __ as __9 } from "@wordpress/i18n";
|
|
1005
|
+
function FixViolationWithAngie({ prompt, panelZIndex, variant = "icon" }) {
|
|
1006
|
+
const label = __9("Fix with Angie", "elementor");
|
|
868
1007
|
const href = `#angie-prompt=${encodeURIComponent(prompt)}`;
|
|
869
1008
|
const handleClick = (event) => {
|
|
870
1009
|
event.stopPropagation();
|
|
@@ -882,52 +1021,69 @@ function FixViolationWithAngie({ prompt }) {
|
|
|
882
1021
|
})
|
|
883
1022
|
);
|
|
884
1023
|
};
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1024
|
+
if (variant === "button") {
|
|
1025
|
+
return /* @__PURE__ */ React8.createElement(
|
|
1026
|
+
Button3,
|
|
1027
|
+
{
|
|
1028
|
+
component: "a",
|
|
1029
|
+
href,
|
|
1030
|
+
size: "small",
|
|
1031
|
+
color: "secondary",
|
|
1032
|
+
variant: "outlined",
|
|
1033
|
+
startIcon: /* @__PURE__ */ React8.createElement(AngieIcon, { fontSize: "tiny", "aria-hidden": true }),
|
|
1034
|
+
onClick: handleClick
|
|
1035
|
+
},
|
|
1036
|
+
label
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
return /* @__PURE__ */ React8.createElement(Tooltip2, { title: label, placement: "top", PopperProps: { sx: { zIndex: panelZIndex } } }, /* @__PURE__ */ React8.createElement(IconButton4, { component: "a", href, size: "small", "aria-label": label, onClick: handleClick }, /* @__PURE__ */ React8.createElement(AngieIcon, { fontSize: "tiny" })));
|
|
897
1040
|
}
|
|
898
1041
|
|
|
899
1042
|
// src/components/severity-icons.tsx
|
|
900
|
-
import * as
|
|
1043
|
+
import * as React9 from "react";
|
|
901
1044
|
import { AlertCircleIcon, AlertTriangleFilledIcon, BulbIcon } from "@elementor/icons";
|
|
902
1045
|
var SEVERITY_CONFIG = {
|
|
903
1046
|
error: { Icon: AlertTriangleFilledIcon, color: "error" },
|
|
904
1047
|
warning: { Icon: AlertCircleIcon, color: "warning" },
|
|
905
1048
|
info: { Icon: BulbIcon, color: "info" }
|
|
906
1049
|
};
|
|
1050
|
+
var INFO_ICON_VERTICAL_NUDGE = "translateY(-2px)";
|
|
907
1051
|
function SeverityIcon({ severity }) {
|
|
908
1052
|
const { Icon, color } = SEVERITY_CONFIG[severity];
|
|
909
|
-
|
|
1053
|
+
const sx = "info" === severity ? { transform: INFO_ICON_VERTICAL_NUDGE } : void 0;
|
|
1054
|
+
return /* @__PURE__ */ React9.createElement(Icon, { fontSize: "small", color, sx });
|
|
910
1055
|
}
|
|
911
1056
|
|
|
912
1057
|
// src/components/violation-cta-button.tsx
|
|
913
|
-
import * as
|
|
914
|
-
import {
|
|
915
|
-
|
|
1058
|
+
import * as React10 from "react";
|
|
1059
|
+
import { WandIcon } from "@elementor/icons";
|
|
1060
|
+
import { Button as Button4 } from "@elementor/ui";
|
|
1061
|
+
function ViolationCtaButton({ ctaLabel, externalUrl, variant = "outlined", withIcon = false }) {
|
|
916
1062
|
const handleClick = (event) => {
|
|
917
1063
|
event.stopPropagation();
|
|
918
1064
|
event.preventDefault();
|
|
919
1065
|
window.open(externalUrl, "_blank", "noopener");
|
|
920
1066
|
};
|
|
921
|
-
return /* @__PURE__ */
|
|
1067
|
+
return /* @__PURE__ */ React10.createElement(
|
|
1068
|
+
Button4,
|
|
1069
|
+
{
|
|
1070
|
+
variant,
|
|
1071
|
+
color: "secondary",
|
|
1072
|
+
size: "small",
|
|
1073
|
+
startIcon: withIcon ? /* @__PURE__ */ React10.createElement(WandIcon, { fontSize: "tiny", "aria-hidden": true }) : void 0,
|
|
1074
|
+
onClick: handleClick
|
|
1075
|
+
},
|
|
1076
|
+
ctaLabel
|
|
1077
|
+
);
|
|
922
1078
|
}
|
|
923
1079
|
|
|
924
1080
|
// src/components/violation-icons.tsx
|
|
925
|
-
import * as
|
|
926
|
-
import { FileSettingsIcon, SettingsIcon
|
|
1081
|
+
import * as React11 from "react";
|
|
1082
|
+
import { FileSettingsIcon, SettingsIcon } from "@elementor/icons";
|
|
927
1083
|
import { Box as Box6 } from "@elementor/ui";
|
|
928
1084
|
function ViolationIcon({ violation, widgetIcon }) {
|
|
929
1085
|
if (widgetIcon) {
|
|
930
|
-
return /* @__PURE__ */
|
|
1086
|
+
return /* @__PURE__ */ React11.createElement(
|
|
931
1087
|
Box6,
|
|
932
1088
|
{
|
|
933
1089
|
component: "i",
|
|
@@ -938,28 +1094,73 @@ function ViolationIcon({ violation, widgetIcon }) {
|
|
|
938
1094
|
);
|
|
939
1095
|
}
|
|
940
1096
|
if (violation.targetHint === "page-settings") {
|
|
941
|
-
return /* @__PURE__ */
|
|
1097
|
+
return /* @__PURE__ */ React11.createElement(FileSettingsIcon, { fontSize: "inherit", "aria-hidden": true });
|
|
942
1098
|
}
|
|
943
1099
|
if (violation.targetHint === "site-settings" || violation.targetHint === "site-identity-settings") {
|
|
944
|
-
return /* @__PURE__ */
|
|
1100
|
+
return /* @__PURE__ */ React11.createElement(SettingsIcon, { fontSize: "inherit", "aria-hidden": true });
|
|
945
1101
|
}
|
|
946
|
-
return /* @__PURE__ */
|
|
1102
|
+
return /* @__PURE__ */ React11.createElement(SettingsIcon, { fontSize: "inherit", "aria-hidden": true });
|
|
947
1103
|
}
|
|
948
1104
|
|
|
949
1105
|
// src/components/violation-row.tsx
|
|
950
1106
|
function SkipReasonTooltip({ reason }) {
|
|
951
|
-
return /* @__PURE__ */
|
|
1107
|
+
return /* @__PURE__ */ React12.createElement(Tooltip3, { title: reason, placement: "top" }, /* @__PURE__ */ React12.createElement(Box7, { "aria-label": reason, component: "span", sx: { display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React12.createElement(HelpIcon, { fontSize: "small", color: "action" })));
|
|
952
1108
|
}
|
|
953
|
-
function StatusIndicator({ audit:
|
|
1109
|
+
function StatusIndicator({ audit: audit25, violations }) {
|
|
954
1110
|
if (violations) {
|
|
955
|
-
return /* @__PURE__ */
|
|
1111
|
+
return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(SeverityIcon, { severity: audit25.severity }), isScoredAudit(audit25) && /* @__PURE__ */ React12.createElement(Typography6, { variant: "caption", color: "text.secondary", fontWeight: "bold" }, violations.length));
|
|
956
1112
|
}
|
|
957
|
-
return /* @__PURE__ */
|
|
1113
|
+
return /* @__PURE__ */ React12.createElement(CheckIcon, { fontSize: "small", color: "success" });
|
|
958
1114
|
}
|
|
959
|
-
function
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1115
|
+
function GuidanceAction({
|
|
1116
|
+
violation,
|
|
1117
|
+
sharedAngiePrompt,
|
|
1118
|
+
panelZIndex
|
|
1119
|
+
}) {
|
|
1120
|
+
const hasPrimaryCta = !!(violation.ctaLabel && violation.externalUrl);
|
|
1121
|
+
if (!hasPrimaryCta && !sharedAngiePrompt) {
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
return /* @__PURE__ */ React12.createElement(Box7, { display: "flex", alignItems: "center", gap: 1, mt: 1 }, hasPrimaryCta && /* @__PURE__ */ React12.createElement(
|
|
1125
|
+
ViolationCtaButton,
|
|
1126
|
+
{
|
|
1127
|
+
ctaLabel: violation.ctaLabel,
|
|
1128
|
+
externalUrl: violation.externalUrl,
|
|
1129
|
+
withIcon: true
|
|
1130
|
+
}
|
|
1131
|
+
), hasPrimaryCta && violation.secondaryCtaLabel && violation.secondaryCtaUrl && /* @__PURE__ */ React12.createElement(
|
|
1132
|
+
ViolationCtaButton,
|
|
1133
|
+
{
|
|
1134
|
+
ctaLabel: violation.secondaryCtaLabel,
|
|
1135
|
+
externalUrl: violation.secondaryCtaUrl,
|
|
1136
|
+
variant: "text"
|
|
1137
|
+
}
|
|
1138
|
+
), sharedAngiePrompt && /* @__PURE__ */ React12.createElement(FixViolationWithAngie, { prompt: sharedAngiePrompt, panelZIndex, variant: "button" }));
|
|
1139
|
+
}
|
|
1140
|
+
function getSharedAngiePrompt(violations) {
|
|
1141
|
+
if (!violations || violations.length < 2) {
|
|
1142
|
+
return void 0;
|
|
1143
|
+
}
|
|
1144
|
+
const [first, ...rest] = violations;
|
|
1145
|
+
if (!first.angieFix || !first.angiePrompt) {
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
1148
|
+
const allShareTheSameFix = rest.every(
|
|
1149
|
+
(violation) => violation.angieFix && violation.angiePrompt === first.angiePrompt
|
|
1150
|
+
);
|
|
1151
|
+
return allShareTheSameFix ? first.angiePrompt : void 0;
|
|
1152
|
+
}
|
|
1153
|
+
function ViolationRow({ audit: audit25, expanded, onToggleExpand, skipReason, violations }) {
|
|
1154
|
+
const primaryViolation = violations?.[0];
|
|
1155
|
+
const isGuidanceFocusable = !!primaryViolation;
|
|
1156
|
+
const panelZIndex = useFloatingPanelZIndex2(AUDIT_PANEL_ID);
|
|
1157
|
+
const sharedAngiePrompt = getSharedAngiePrompt(violations);
|
|
1158
|
+
const handleGuidanceClick = () => {
|
|
1159
|
+
if (isGuidanceFocusable && primaryViolation) {
|
|
1160
|
+
focusViolation(primaryViolation);
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
return /* @__PURE__ */ React12.createElement(Box7, { sx: { borderBottom: 1, borderColor: "divider", paddingBlock: 0.5 } }, /* @__PURE__ */ React12.createElement(Box7, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React12.createElement(
|
|
963
1164
|
Box7,
|
|
964
1165
|
{
|
|
965
1166
|
sx: {
|
|
@@ -970,18 +1171,18 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
970
1171
|
gap: 0.5,
|
|
971
1172
|
minWidth: 0
|
|
972
1173
|
},
|
|
973
|
-
onClick:
|
|
1174
|
+
onClick: onToggleExpand
|
|
974
1175
|
},
|
|
975
|
-
/* @__PURE__ */
|
|
976
|
-
!skipReason && /* @__PURE__ */
|
|
977
|
-
), skipReason && /* @__PURE__ */
|
|
1176
|
+
/* @__PURE__ */ React12.createElement(Typography6, { variant: "subtitle2", color: "text.secondary", sx: { flex: 1 } }, audit25.title),
|
|
1177
|
+
!skipReason && /* @__PURE__ */ React12.createElement(StatusIndicator, { audit: audit25, violations })
|
|
1178
|
+
), skipReason && /* @__PURE__ */ React12.createElement(SkipReasonTooltip, { reason: skipReason }), /* @__PURE__ */ React12.createElement(
|
|
978
1179
|
IconButton5,
|
|
979
1180
|
{
|
|
980
1181
|
size: "small",
|
|
981
|
-
"aria-label": expanded ?
|
|
982
|
-
onClick:
|
|
1182
|
+
"aria-label": expanded ? __10("Collapse", "elementor") : __10("Expand", "elementor"),
|
|
1183
|
+
onClick: onToggleExpand
|
|
983
1184
|
},
|
|
984
|
-
/* @__PURE__ */
|
|
1185
|
+
/* @__PURE__ */ React12.createElement(
|
|
985
1186
|
ChevronDownIcon2,
|
|
986
1187
|
{
|
|
987
1188
|
fontSize: "small",
|
|
@@ -991,29 +1192,33 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
991
1192
|
}
|
|
992
1193
|
}
|
|
993
1194
|
)
|
|
994
|
-
)), /* @__PURE__ */
|
|
1195
|
+
)), /* @__PURE__ */ React12.createElement(Collapse2, { in: expanded }, /* @__PURE__ */ React12.createElement(Box7, { paddingBlock: 1 }, /* @__PURE__ */ React12.createElement(Tooltip3, { title: audit25.fixHint, placement: "top" }, /* @__PURE__ */ React12.createElement(
|
|
995
1196
|
Alert,
|
|
996
1197
|
{
|
|
997
1198
|
severity: "secondary",
|
|
998
|
-
sx: { p: 1 },
|
|
999
|
-
icon: /* @__PURE__ */
|
|
1199
|
+
sx: { p: 1, cursor: isGuidanceFocusable ? "pointer" : void 0 },
|
|
1200
|
+
icon: /* @__PURE__ */ React12.createElement(InfoCircleIcon, { fontSize: "small", "aria-hidden": true }),
|
|
1201
|
+
role: isGuidanceFocusable ? "button" : void 0,
|
|
1202
|
+
tabIndex: isGuidanceFocusable ? 0 : void 0,
|
|
1203
|
+
onClick: isGuidanceFocusable ? handleGuidanceClick : void 0,
|
|
1204
|
+
onKeyDown: isGuidanceFocusable ? onKeyboardClick(handleGuidanceClick) : void 0
|
|
1000
1205
|
},
|
|
1001
|
-
/* @__PURE__ */
|
|
1002
|
-
/* @__PURE__ */
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
/* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.secondary" }, audit23.fixHint)
|
|
1012
|
-
)), violations && violations.length > 0 && /* @__PURE__ */ React11.createElement(Box7, { role: "list", sx: { paddingBlockEnd: 1, paddingInlineStart: 2 } }, violations.map((violation, idx) => {
|
|
1206
|
+
/* @__PURE__ */ React12.createElement(Typography6, { variant: "caption", component: "p", color: "text.secondary" }, audit25.description),
|
|
1207
|
+
primaryViolation && /* @__PURE__ */ React12.createElement(
|
|
1208
|
+
GuidanceAction,
|
|
1209
|
+
{
|
|
1210
|
+
violation: primaryViolation,
|
|
1211
|
+
sharedAngiePrompt,
|
|
1212
|
+
panelZIndex
|
|
1213
|
+
}
|
|
1214
|
+
)
|
|
1215
|
+
))), violations && violations.length > 0 && /* @__PURE__ */ React12.createElement(Box7, { role: "list", sx: { paddingBlockEnd: 1 } }, violations.map((violation, idx) => {
|
|
1013
1216
|
const widgetIcon = violation.elementId ? getElementIcon(violation.elementId) : null;
|
|
1014
1217
|
const elementTitle = violation.elementId ? getElementTitle(violation.elementId) : null;
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1218
|
+
const displayLabel = elementTitle ?? violation.label;
|
|
1219
|
+
const angiePromptContext = elementTitle ? `${elementTitle} - ${violation.label}` : violation.label;
|
|
1220
|
+
const showsOwnFixAction = !!violation.angieFix && !sharedAngiePrompt;
|
|
1221
|
+
return /* @__PURE__ */ React12.createElement(
|
|
1017
1222
|
Box7,
|
|
1018
1223
|
{
|
|
1019
1224
|
key: idx,
|
|
@@ -1026,258 +1231,130 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
1026
1231
|
alignItems: "center",
|
|
1027
1232
|
gap: 1,
|
|
1028
1233
|
paddingBlock: 0.5,
|
|
1029
|
-
paddingInline:
|
|
1234
|
+
paddingInline: 1,
|
|
1030
1235
|
borderRadius: 1,
|
|
1031
1236
|
cursor: "pointer",
|
|
1032
|
-
"& .violation-hover-icon": { opacity: 0, transition: "opacity .15s" },
|
|
1033
1237
|
"&:hover": { bgcolor: "action.hover" },
|
|
1034
|
-
"&:hover .violation-
|
|
1238
|
+
"&:hover .violation-row-fix-action, &:focus-visible .violation-row-fix-action": {
|
|
1035
1239
|
opacity: 1
|
|
1036
1240
|
}
|
|
1037
1241
|
}
|
|
1038
1242
|
},
|
|
1039
|
-
/* @__PURE__ */
|
|
1040
|
-
/* @__PURE__ */
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
{
|
|
1044
|
-
prompt: violation.angiePrompt ?? buildAngiePrompt(rowLabel)
|
|
1045
|
-
}
|
|
1046
|
-
),
|
|
1047
|
-
violation.ctaLabel && violation.externalUrl ? /* @__PURE__ */ React11.createElement(
|
|
1048
|
-
ViolationCtaButton,
|
|
1049
|
-
{
|
|
1050
|
-
ctaLabel: violation.ctaLabel,
|
|
1051
|
-
externalUrl: violation.externalUrl
|
|
1052
|
-
}
|
|
1053
|
-
) : /* @__PURE__ */ React11.createElement(
|
|
1054
|
-
EyeIcon,
|
|
1243
|
+
/* @__PURE__ */ React12.createElement(ViolationIcon, { violation, widgetIcon }),
|
|
1244
|
+
/* @__PURE__ */ React12.createElement(Box7, { sx: { flex: 1 } }, /* @__PURE__ */ React12.createElement(Typography6, { variant: "caption" }, displayLabel), violation.detail && /* @__PURE__ */ React12.createElement(Typography6, { variant: "caption", color: "text.secondary" }, violation.detail)),
|
|
1245
|
+
showsOwnFixAction && /* @__PURE__ */ React12.createElement(
|
|
1246
|
+
Box7,
|
|
1055
1247
|
{
|
|
1056
|
-
className: "violation-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1248
|
+
className: "violation-row-fix-action",
|
|
1249
|
+
sx: { opacity: 0, transition: "opacity .15s" }
|
|
1250
|
+
},
|
|
1251
|
+
/* @__PURE__ */ React12.createElement(
|
|
1252
|
+
FixViolationWithAngie,
|
|
1253
|
+
{
|
|
1254
|
+
prompt: violation.angiePrompt ?? buildAngiePrompt(angiePromptContext),
|
|
1255
|
+
panelZIndex
|
|
1256
|
+
}
|
|
1257
|
+
)
|
|
1060
1258
|
)
|
|
1061
1259
|
);
|
|
1062
1260
|
}))));
|
|
1063
1261
|
}
|
|
1064
1262
|
|
|
1065
|
-
// src/components/pages/all-audits-page.tsx
|
|
1066
|
-
function AllAuditsPage({ initialExpandedStatus, onBack, report }) {
|
|
1067
|
-
const { failed, passed, skipped, totalViolations } = partitionAuditResults(report);
|
|
1068
|
-
const expandFail = !initialExpandedStatus || initialExpandedStatus === "fail";
|
|
1069
|
-
const expandPass = initialExpandedStatus === "pass";
|
|
1070
|
-
const expandSkipped = initialExpandedStatus === "skipped";
|
|
1071
|
-
return /* @__PURE__ */ React12.createElement(Box8, { key: initialExpandedStatus ?? "default" }, /* @__PURE__ */ React12.createElement(SubpageHeader, { title: __12("All audits", "elementor"), onBack }), /* @__PURE__ */ React12.createElement(Box8, { sx: { p: 1 } }, /* @__PURE__ */ React12.createElement(
|
|
1072
|
-
StatusSection,
|
|
1073
|
-
{
|
|
1074
|
-
label: auditStatusLabel("fail"),
|
|
1075
|
-
count: totalViolations,
|
|
1076
|
-
color: auditStatusColor("fail"),
|
|
1077
|
-
defaultExpanded: expandFail
|
|
1078
|
-
},
|
|
1079
|
-
failed.map((r) => /* @__PURE__ */ React12.createElement(ViolationRow, { key: r.audit.id, audit: r.audit, violations: r.result.violations }))
|
|
1080
|
-
), /* @__PURE__ */ React12.createElement(
|
|
1081
|
-
StatusSection,
|
|
1082
|
-
{
|
|
1083
|
-
label: auditStatusLabel("pass"),
|
|
1084
|
-
count: passed.length,
|
|
1085
|
-
color: auditStatusColor("pass"),
|
|
1086
|
-
defaultExpanded: expandPass
|
|
1087
|
-
},
|
|
1088
|
-
passed.map((r) => /* @__PURE__ */ React12.createElement(ViolationRow, { key: r.audit.id, audit: r.audit }))
|
|
1089
|
-
), /* @__PURE__ */ React12.createElement(
|
|
1090
|
-
StatusSection,
|
|
1091
|
-
{
|
|
1092
|
-
label: auditStatusLabel("skipped"),
|
|
1093
|
-
count: skipped.length,
|
|
1094
|
-
color: auditStatusColor("skipped"),
|
|
1095
|
-
defaultExpanded: expandSkipped
|
|
1096
|
-
},
|
|
1097
|
-
skipped.map((r) => /* @__PURE__ */ React12.createElement(ViolationRow, { key: r.audit.id, audit: r.audit, skipReason: r.result.reason }))
|
|
1098
|
-
)));
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
// src/components/pages/category-page.tsx
|
|
1102
|
-
import * as React13 from "react";
|
|
1103
|
-
import { Box as Box9 } from "@elementor/ui";
|
|
1104
|
-
import { __ as __13 } from "@wordpress/i18n";
|
|
1105
|
-
|
|
1106
|
-
// src/components/category-icons.ts
|
|
1107
|
-
import { BoltIcon, ElementorAccessibilityIcon, FileSearchIcon, Settings2Icon, ShieldCheckIcon as ShieldCheckIcon2 } from "@elementor/icons";
|
|
1108
|
-
var CATEGORY_ICONS = {
|
|
1109
|
-
"best-practices": Settings2Icon,
|
|
1110
|
-
seo: FileSearchIcon,
|
|
1111
|
-
accessibility: ElementorAccessibilityIcon,
|
|
1112
|
-
performance: BoltIcon,
|
|
1113
|
-
compliance: ShieldCheckIcon2
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
1263
|
// src/components/pages/category-page.tsx
|
|
1117
1264
|
function CategoryPage({ category, report, onBack }) {
|
|
1118
1265
|
const Icon = CATEGORY_ICONS[category];
|
|
1119
|
-
const { failed, passed, totalViolations } = partitionAuditResults(report, { category });
|
|
1266
|
+
const { failed, passed, skipped, totalViolations } = partitionAuditResults(report, { category });
|
|
1267
|
+
const { expandedId, toggle } = useSingleExpandedCard();
|
|
1120
1268
|
return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
|
|
1121
1269
|
SubpageHeader,
|
|
1122
1270
|
{
|
|
1123
1271
|
title: CATEGORY_LABELS[category],
|
|
1124
1272
|
onBack,
|
|
1125
|
-
backLabel:
|
|
1273
|
+
backLabel: __11("Back to all issues", "elementor"),
|
|
1126
1274
|
icon: /* @__PURE__ */ React13.createElement(Icon, { fontSize: "small", color: "action" })
|
|
1127
1275
|
}
|
|
1128
|
-
), /* @__PURE__ */ React13.createElement(
|
|
1276
|
+
), /* @__PURE__ */ React13.createElement(Box8, { sx: { p: 1 } }, /* @__PURE__ */ React13.createElement(
|
|
1129
1277
|
StatusSection,
|
|
1130
1278
|
{
|
|
1131
|
-
label:
|
|
1279
|
+
label: __11("Failed audits", "elementor"),
|
|
1132
1280
|
count: totalViolations,
|
|
1133
1281
|
color: "error",
|
|
1134
1282
|
defaultExpanded: true
|
|
1135
1283
|
},
|
|
1136
|
-
failed.map((r) => /* @__PURE__ */ React13.createElement(
|
|
1137
|
-
|
|
1284
|
+
failed.map((r) => /* @__PURE__ */ React13.createElement(
|
|
1285
|
+
ViolationRow,
|
|
1286
|
+
{
|
|
1287
|
+
key: r.audit.id,
|
|
1288
|
+
audit: r.audit,
|
|
1289
|
+
violations: r.result.violations,
|
|
1290
|
+
expanded: expandedId === r.audit.id,
|
|
1291
|
+
onToggleExpand: () => toggle(r.audit.id)
|
|
1292
|
+
}
|
|
1293
|
+
))
|
|
1294
|
+
), /* @__PURE__ */ React13.createElement(StatusSection, { label: __11("Passed audits", "elementor"), count: passed.length, color: "success" }, passed.map((r) => /* @__PURE__ */ React13.createElement(
|
|
1295
|
+
ViolationRow,
|
|
1296
|
+
{
|
|
1297
|
+
key: r.audit.id,
|
|
1298
|
+
audit: r.audit,
|
|
1299
|
+
expanded: expandedId === r.audit.id,
|
|
1300
|
+
onToggleExpand: () => toggle(r.audit.id)
|
|
1301
|
+
}
|
|
1302
|
+
))), /* @__PURE__ */ React13.createElement(StatusSection, { label: __11("Skipped audits", "elementor"), count: skipped.length, color: "default" }, skipped.map((r) => /* @__PURE__ */ React13.createElement(
|
|
1303
|
+
ViolationRow,
|
|
1304
|
+
{
|
|
1305
|
+
key: r.audit.id,
|
|
1306
|
+
audit: r.audit,
|
|
1307
|
+
skipReason: r.result.reason,
|
|
1308
|
+
expanded: expandedId === r.audit.id,
|
|
1309
|
+
onToggleExpand: () => toggle(r.audit.id)
|
|
1310
|
+
}
|
|
1311
|
+
)))));
|
|
1138
1312
|
}
|
|
1139
1313
|
|
|
1140
|
-
// src/components/pages/
|
|
1314
|
+
// src/components/pages/overview-page.tsx
|
|
1141
1315
|
import * as React18 from "react";
|
|
1142
|
-
import {
|
|
1143
|
-
import {
|
|
1144
|
-
import { __ as __17 } from "@wordpress/i18n";
|
|
1316
|
+
import { Box as Box13, Typography as Typography11 } from "@elementor/ui";
|
|
1317
|
+
import { __ as __15 } from "@wordpress/i18n";
|
|
1145
1318
|
|
|
1146
1319
|
// src/utils/severity-counts.ts
|
|
1147
|
-
import { __ as
|
|
1320
|
+
import { __ as __12 } from "@wordpress/i18n";
|
|
1148
1321
|
var ALL_SEVERITIES = ["error", "warning", "info"];
|
|
1149
1322
|
function countSeverities(report, category) {
|
|
1150
1323
|
const counts = { error: 0, warning: 0, info: 0 };
|
|
1151
|
-
for (const { audit:
|
|
1324
|
+
for (const { audit: audit25, result } of report.auditResults) {
|
|
1152
1325
|
if (result.status !== "fail") {
|
|
1153
1326
|
continue;
|
|
1154
1327
|
}
|
|
1155
|
-
if (category && !
|
|
1328
|
+
if (category && !audit25.categories.includes(category)) {
|
|
1156
1329
|
continue;
|
|
1157
1330
|
}
|
|
1158
|
-
if (!isScoredAudit(
|
|
1331
|
+
if (!isScoredAudit(audit25)) {
|
|
1159
1332
|
continue;
|
|
1160
1333
|
}
|
|
1161
|
-
counts[
|
|
1334
|
+
counts[audit25.severity] += result.violations.length;
|
|
1162
1335
|
}
|
|
1163
1336
|
return counts;
|
|
1164
1337
|
}
|
|
1165
1338
|
function severityPluralLabel(severity) {
|
|
1166
1339
|
switch (severity) {
|
|
1167
1340
|
case "error":
|
|
1168
|
-
return
|
|
1341
|
+
return __12("Errors", "elementor");
|
|
1169
1342
|
case "warning":
|
|
1170
|
-
return
|
|
1343
|
+
return __12("Warnings", "elementor");
|
|
1171
1344
|
case "info":
|
|
1172
|
-
return
|
|
1345
|
+
return __12("Suggestions", "elementor");
|
|
1173
1346
|
}
|
|
1174
1347
|
}
|
|
1175
1348
|
|
|
1176
|
-
// src/components/audit-statuses-section.tsx
|
|
1177
|
-
import * as React15 from "react";
|
|
1178
|
-
import { Box as Box11, Divider, Typography as Typography8 } from "@elementor/ui";
|
|
1179
|
-
import { __ as __15, sprintf as sprintf2 } from "@wordpress/i18n";
|
|
1180
|
-
|
|
1181
|
-
// src/components/count-summary-circle.tsx
|
|
1182
|
-
import * as React14 from "react";
|
|
1183
|
-
import { Box as Box10, Chip as Chip2, Typography as Typography7 } from "@elementor/ui";
|
|
1184
|
-
var COUNT_SUMMARY_CIRCLE_SIZE = 64;
|
|
1185
|
-
var COUNT_SUMMARY_BORDER_WIDTH = 4;
|
|
1186
|
-
function chipBorderColor(theme, color) {
|
|
1187
|
-
if (color === "default" || !color) {
|
|
1188
|
-
return theme.palette.text.secondary;
|
|
1189
|
-
}
|
|
1190
|
-
return theme.palette[color].main;
|
|
1191
|
-
}
|
|
1192
|
-
function CountSummaryCircle({ ariaLabel, color, count, label, onClick }) {
|
|
1193
|
-
return /* @__PURE__ */ React14.createElement(
|
|
1194
|
-
Box10,
|
|
1195
|
-
{
|
|
1196
|
-
"aria-label": ariaLabel,
|
|
1197
|
-
component: "button",
|
|
1198
|
-
onClick,
|
|
1199
|
-
type: "button",
|
|
1200
|
-
sx: {
|
|
1201
|
-
alignItems: "center",
|
|
1202
|
-
background: "none",
|
|
1203
|
-
border: "none",
|
|
1204
|
-
cursor: "pointer",
|
|
1205
|
-
display: "flex",
|
|
1206
|
-
flex: 1,
|
|
1207
|
-
flexDirection: "column",
|
|
1208
|
-
gap: 0.5,
|
|
1209
|
-
padding: 0
|
|
1210
|
-
}
|
|
1211
|
-
},
|
|
1212
|
-
/* @__PURE__ */ React14.createElement(
|
|
1213
|
-
Chip2,
|
|
1214
|
-
{
|
|
1215
|
-
color,
|
|
1216
|
-
label: count,
|
|
1217
|
-
size: "small",
|
|
1218
|
-
variant: "standard",
|
|
1219
|
-
sx: (theme) => ({
|
|
1220
|
-
border: `${COUNT_SUMMARY_BORDER_WIDTH}px solid ${chipBorderColor(theme, color)}`,
|
|
1221
|
-
borderRadius: "50%",
|
|
1222
|
-
height: COUNT_SUMMARY_CIRCLE_SIZE,
|
|
1223
|
-
maxWidth: COUNT_SUMMARY_CIRCLE_SIZE,
|
|
1224
|
-
width: COUNT_SUMMARY_CIRCLE_SIZE,
|
|
1225
|
-
"& .MuiChip-label": {
|
|
1226
|
-
fontSize: theme.typography.body2.fontSize,
|
|
1227
|
-
fontWeight: 700,
|
|
1228
|
-
lineHeight: 1,
|
|
1229
|
-
padding: 0
|
|
1230
|
-
}
|
|
1231
|
-
})
|
|
1232
|
-
}
|
|
1233
|
-
),
|
|
1234
|
-
/* @__PURE__ */ React14.createElement(Typography7, { color: "text.secondary", sx: { textAlign: "center" }, variant: "caption" }, label)
|
|
1235
|
-
);
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
// src/components/audit-statuses-section.tsx
|
|
1239
|
-
var STATUS_ARIA_LABELS = {
|
|
1240
|
-
pass: (count) => sprintf2(
|
|
1241
|
-
/* translators: %d: number of passed audits. */
|
|
1242
|
-
__15("%d passed audits, view all", "elementor"),
|
|
1243
|
-
count
|
|
1244
|
-
),
|
|
1245
|
-
fail: (count) => sprintf2(
|
|
1246
|
-
/* translators: %d: number of failed audit violations. */
|
|
1247
|
-
__15("%d failed audits, view all", "elementor"),
|
|
1248
|
-
count
|
|
1249
|
-
),
|
|
1250
|
-
skipped: (count) => sprintf2(
|
|
1251
|
-
/* translators: %d: number of skipped audits. */
|
|
1252
|
-
__15("%d skipped audits, view all", "elementor"),
|
|
1253
|
-
count
|
|
1254
|
-
)
|
|
1255
|
-
};
|
|
1256
|
-
var STATUS_GROUPS = ["fail", "pass", "skipped"];
|
|
1257
|
-
function AuditStatusesSection({ report, onStatusClick }) {
|
|
1258
|
-
const statusCounts = auditStatusDisplayCounts(report);
|
|
1259
|
-
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Typography8, { variant: "subtitle1", fontWeight: "bold" }, __15("Audit statuses", "elementor")), /* @__PURE__ */ React15.createElement(Box11, { sx: { display: "flex", justifyContent: "space-around", gap: 2 } }, STATUS_GROUPS.map((status) => /* @__PURE__ */ React15.createElement(
|
|
1260
|
-
CountSummaryCircle,
|
|
1261
|
-
{
|
|
1262
|
-
key: status,
|
|
1263
|
-
ariaLabel: STATUS_ARIA_LABELS[status](statusCounts[status]),
|
|
1264
|
-
color: auditStatusColor(status),
|
|
1265
|
-
count: statusCounts[status],
|
|
1266
|
-
label: auditStatusLabel(status),
|
|
1267
|
-
onClick: () => onStatusClick(status)
|
|
1268
|
-
}
|
|
1269
|
-
))), /* @__PURE__ */ React15.createElement(Divider, null));
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
1349
|
// src/components/issues-category-row.tsx
|
|
1273
|
-
import * as
|
|
1350
|
+
import * as React14 from "react";
|
|
1274
1351
|
import { ChevronRightIcon } from "@elementor/icons";
|
|
1275
|
-
import { Box as
|
|
1352
|
+
import { Box as Box9, Rotate as Rotate2, Typography as Typography7, useTheme as useTheme2 } from "@elementor/ui";
|
|
1276
1353
|
function IssuesCategoryRow({ category, label, counts, onClick }) {
|
|
1277
1354
|
const isRtl = "rtl" === useTheme2().direction;
|
|
1278
1355
|
const Icon = CATEGORY_ICONS[category];
|
|
1279
|
-
return /* @__PURE__ */
|
|
1280
|
-
|
|
1356
|
+
return /* @__PURE__ */ React14.createElement(
|
|
1357
|
+
Box9,
|
|
1281
1358
|
{
|
|
1282
1359
|
role: "button",
|
|
1283
1360
|
tabIndex: 0,
|
|
@@ -1298,112 +1375,21 @@ function IssuesCategoryRow({ category, label, counts, onClick }) {
|
|
|
1298
1375
|
"&:focus-visible": { outline: "2px solid", outlineColor: "primary.main" }
|
|
1299
1376
|
}
|
|
1300
1377
|
},
|
|
1301
|
-
/* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
1304
|
-
/* @__PURE__ */
|
|
1378
|
+
/* @__PURE__ */ React14.createElement(Icon, { fontSize: "small", color: "action" }),
|
|
1379
|
+
/* @__PURE__ */ React14.createElement(Typography7, { variant: "body2", fontWeight: "bold", sx: { flex: 1 } }, label),
|
|
1380
|
+
/* @__PURE__ */ React14.createElement(Box9, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, ALL_SEVERITIES.filter((s) => counts[s] > 0).map((severity) => /* @__PURE__ */ React14.createElement(Box9, { key: severity, sx: { display: "flex", alignItems: "center", gap: 0.25 } }, /* @__PURE__ */ React14.createElement(SeverityIcon, { severity }), /* @__PURE__ */ React14.createElement(Typography7, { variant: "caption", color: "text.primary", fontWeight: "bold" }, counts[severity])))),
|
|
1381
|
+
/* @__PURE__ */ React14.createElement(Rotate2, { in: isRtl }, /* @__PURE__ */ React14.createElement(ChevronRightIcon, { fontSize: "small", color: "action" }))
|
|
1305
1382
|
);
|
|
1306
1383
|
}
|
|
1307
1384
|
|
|
1308
|
-
// src/components/severity-filter-chips.tsx
|
|
1309
|
-
import * as React17 from "react";
|
|
1310
|
-
import { Box as Box13, Chip as Chip3 } from "@elementor/ui";
|
|
1311
|
-
import { __ as __16 } from "@wordpress/i18n";
|
|
1312
|
-
function SeverityFilterChips({ selected, onChange }) {
|
|
1313
|
-
return /* @__PURE__ */ React17.createElement(Box13, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ React17.createElement(
|
|
1314
|
-
FilterChip,
|
|
1315
|
-
{
|
|
1316
|
-
label: __16("All", "elementor"),
|
|
1317
|
-
isSelected: selected === "all",
|
|
1318
|
-
onClick: () => onChange("all")
|
|
1319
|
-
}
|
|
1320
|
-
), ALL_SEVERITIES.map((severity) => /* @__PURE__ */ React17.createElement(
|
|
1321
|
-
FilterChip,
|
|
1322
|
-
{
|
|
1323
|
-
key: severity,
|
|
1324
|
-
label: severityPluralLabel(severity),
|
|
1325
|
-
icon: /* @__PURE__ */ React17.createElement(SeverityIcon, { severity }),
|
|
1326
|
-
isSelected: selected === severity,
|
|
1327
|
-
onClick: () => onChange(severity)
|
|
1328
|
-
}
|
|
1329
|
-
)));
|
|
1330
|
-
}
|
|
1331
|
-
function FilterChip({ label, icon, isSelected, onClick }) {
|
|
1332
|
-
return /* @__PURE__ */ React17.createElement(
|
|
1333
|
-
Chip3,
|
|
1334
|
-
{
|
|
1335
|
-
label,
|
|
1336
|
-
icon,
|
|
1337
|
-
size: "small",
|
|
1338
|
-
variant: "filled",
|
|
1339
|
-
color: "default",
|
|
1340
|
-
onClick,
|
|
1341
|
-
"aria-pressed": isSelected,
|
|
1342
|
-
sx: { bgcolor: isSelected ? "action.selected" : "transparent" }
|
|
1343
|
-
}
|
|
1344
|
-
);
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
// src/components/pages/issues-page.tsx
|
|
1348
|
-
function filterCounts(counts, filter) {
|
|
1349
|
-
if (filter === "all") {
|
|
1350
|
-
return counts;
|
|
1351
|
-
}
|
|
1352
|
-
return { error: 0, warning: 0, info: 0, [filter]: counts[filter] };
|
|
1353
|
-
}
|
|
1354
|
-
function IssuesPage({ report, onCategoryClick, onAllAuditsClick, onStatusClick }) {
|
|
1355
|
-
const [filter, setFilter] = useState4("all");
|
|
1356
|
-
const populatedCategories = getPopulatedCategories(report.categories, ALL_CATEGORIES);
|
|
1357
|
-
const categoryRows = populatedCategories.map((category) => ({ category, counts: filterCounts(countSeverities(report, category), filter) })).filter(({ counts }) => Object.values(counts).some((count) => count > 0));
|
|
1358
|
-
return /* @__PURE__ */ React18.createElement(Box14, { sx: { display: "flex", flexDirection: "column", gap: 4, p: 2 } }, /* @__PURE__ */ React18.createElement(AuditStatusesSection, { report, onStatusClick }), /* @__PURE__ */ React18.createElement(
|
|
1359
|
-
Link,
|
|
1360
|
-
{
|
|
1361
|
-
component: "button",
|
|
1362
|
-
underline: "none",
|
|
1363
|
-
color: "inherit",
|
|
1364
|
-
onClick: onAllAuditsClick,
|
|
1365
|
-
sx: { textAlign: "start" }
|
|
1366
|
-
},
|
|
1367
|
-
/* @__PURE__ */ React18.createElement(Typography10, { variant: "subtitle1", component: "h2" }, __17("All issues", "elementor"))
|
|
1368
|
-
), /* @__PURE__ */ React18.createElement(SeverityFilterChips, { selected: filter, onChange: setFilter }), /* @__PURE__ */ React18.createElement(Box14, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, categoryRows.map(({ category, counts }) => /* @__PURE__ */ React18.createElement(
|
|
1369
|
-
IssuesCategoryRow,
|
|
1370
|
-
{
|
|
1371
|
-
key: category,
|
|
1372
|
-
category,
|
|
1373
|
-
label: CATEGORY_LABELS[category],
|
|
1374
|
-
counts,
|
|
1375
|
-
onClick: () => onCategoryClick(category)
|
|
1376
|
-
}
|
|
1377
|
-
))));
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
// src/components/pages/overview-page.tsx
|
|
1381
|
-
import * as React23 from "react";
|
|
1382
|
-
import { Box as Box19, Chip as Chip4, Typography as Typography15 } from "@elementor/ui";
|
|
1383
|
-
import { __ as __21 } from "@wordpress/i18n";
|
|
1384
|
-
|
|
1385
|
-
// src/utils/score-thresholds.ts
|
|
1386
|
-
import { __ as __18 } from "@wordpress/i18n";
|
|
1387
|
-
var GOOD_THRESHOLD = 90;
|
|
1388
|
-
var OK_THRESHOLD = 50;
|
|
1389
|
-
function getScoreTier(score) {
|
|
1390
|
-
if (score >= GOOD_THRESHOLD) {
|
|
1391
|
-
return { color: "success", label: __18("Good", "elementor") };
|
|
1392
|
-
}
|
|
1393
|
-
if (score >= OK_THRESHOLD) {
|
|
1394
|
-
return { color: "warning", label: __18("Needs work", "elementor") };
|
|
1395
|
-
}
|
|
1396
|
-
return { color: "error", label: __18("At risk", "elementor") };
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
1385
|
// src/components/promotions.tsx
|
|
1400
|
-
import * as
|
|
1401
|
-
import { Box as
|
|
1402
|
-
import { __ as
|
|
1386
|
+
import * as React16 from "react";
|
|
1387
|
+
import { Box as Box11, Divider, Typography as Typography9 } from "@elementor/ui";
|
|
1388
|
+
import { __ as __14 } from "@wordpress/i18n";
|
|
1403
1389
|
|
|
1404
1390
|
// src/register-promotions.ts
|
|
1405
1391
|
import { ElementorCookieIcon, PhotoIcon, ShieldHalfFilledIcon } from "@elementor/icons";
|
|
1406
|
-
import { __ as
|
|
1392
|
+
import { __ as __13, _n, sprintf as sprintf2 } from "@wordpress/i18n";
|
|
1407
1393
|
function firstFailExternalUrl(run) {
|
|
1408
1394
|
return run.result.status === "fail" ? run.result.violations[0]?.externalUrl : void 0;
|
|
1409
1395
|
}
|
|
@@ -1411,7 +1397,7 @@ var PROMOTIONS = [
|
|
|
1411
1397
|
{
|
|
1412
1398
|
auditId: "audits/images-alt-text",
|
|
1413
1399
|
icon: PhotoIcon,
|
|
1414
|
-
ctaLabel:
|
|
1400
|
+
ctaLabel: __13("Fix with Ally", "elementor"),
|
|
1415
1401
|
formatSubtitle: (run) => {
|
|
1416
1402
|
if (run.result.status !== "fail") {
|
|
1417
1403
|
return null;
|
|
@@ -1420,7 +1406,7 @@ var PROMOTIONS = [
|
|
|
1420
1406
|
if (count === 0) {
|
|
1421
1407
|
return null;
|
|
1422
1408
|
}
|
|
1423
|
-
return
|
|
1409
|
+
return sprintf2(
|
|
1424
1410
|
/* translators: %d: number of images missing alt text. */
|
|
1425
1411
|
_n("%d image", "%d images", count, "elementor"),
|
|
1426
1412
|
count
|
|
@@ -1431,21 +1417,21 @@ var PROMOTIONS = [
|
|
|
1431
1417
|
{
|
|
1432
1418
|
auditId: "audits/cookie-policy",
|
|
1433
1419
|
icon: ElementorCookieIcon,
|
|
1434
|
-
ctaLabel:
|
|
1435
|
-
formatSubtitle: (run) => run.result.status === "fail" ?
|
|
1420
|
+
ctaLabel: __13("Fix with Cookiez", "elementor"),
|
|
1421
|
+
formatSubtitle: (run) => run.result.status === "fail" ? __13("Generate cookie policy", "elementor") : null,
|
|
1436
1422
|
getCtaUrl: firstFailExternalUrl
|
|
1437
1423
|
},
|
|
1438
1424
|
{
|
|
1439
1425
|
auditId: "audits/scan-for-cookies",
|
|
1440
1426
|
icon: ElementorCookieIcon,
|
|
1441
|
-
ctaLabel:
|
|
1442
|
-
formatSubtitle: (run) => run.result.status === "fail" ?
|
|
1427
|
+
ctaLabel: __13("Scan", "elementor"),
|
|
1428
|
+
formatSubtitle: (run) => run.result.status === "fail" ? __13("Scan this page for cookies", "elementor") : null,
|
|
1443
1429
|
getCtaUrl: firstFailExternalUrl
|
|
1444
1430
|
},
|
|
1445
1431
|
{
|
|
1446
1432
|
auditId: "audits/images-too-large",
|
|
1447
1433
|
icon: ShieldHalfFilledIcon,
|
|
1448
|
-
ctaLabel:
|
|
1434
|
+
ctaLabel: __13("Optimize all", "elementor"),
|
|
1449
1435
|
formatSubtitle: (run) => {
|
|
1450
1436
|
if (run.result.status !== "fail") {
|
|
1451
1437
|
return null;
|
|
@@ -1454,7 +1440,7 @@ var PROMOTIONS = [
|
|
|
1454
1440
|
if (count === 0) {
|
|
1455
1441
|
return null;
|
|
1456
1442
|
}
|
|
1457
|
-
return
|
|
1443
|
+
return sprintf2(
|
|
1458
1444
|
/* translators: %d: number of oversized images. */
|
|
1459
1445
|
_n("%d image", "%d images", count, "elementor"),
|
|
1460
1446
|
count
|
|
@@ -1470,11 +1456,11 @@ function findAuditRun(report, auditId) {
|
|
|
1470
1456
|
}
|
|
1471
1457
|
|
|
1472
1458
|
// src/components/promotion-card.tsx
|
|
1473
|
-
import * as
|
|
1474
|
-
import { Box as
|
|
1459
|
+
import * as React15 from "react";
|
|
1460
|
+
import { Box as Box10, Button as Button5, Typography as Typography8 } from "@elementor/ui";
|
|
1475
1461
|
function PromotionCard({ ctaDisabled, ctaLabel, icon: Icon, onCtaClick, subtitle, title }) {
|
|
1476
|
-
return /* @__PURE__ */
|
|
1477
|
-
|
|
1462
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1463
|
+
Box10,
|
|
1478
1464
|
{
|
|
1479
1465
|
sx: {
|
|
1480
1466
|
alignItems: "center",
|
|
@@ -1487,9 +1473,9 @@ function PromotionCard({ ctaDisabled, ctaLabel, icon: Icon, onCtaClick, subtitle
|
|
|
1487
1473
|
py: 1.5
|
|
1488
1474
|
}
|
|
1489
1475
|
},
|
|
1490
|
-
/* @__PURE__ */
|
|
1491
|
-
/* @__PURE__ */
|
|
1492
|
-
/* @__PURE__ */
|
|
1476
|
+
/* @__PURE__ */ React15.createElement(Icon, { fontSize: "small", color: "action" }),
|
|
1477
|
+
/* @__PURE__ */ React15.createElement(Box10, { sx: { display: "flex", flex: 1, flexDirection: "column", gap: 0.25, minWidth: 0 } }, /* @__PURE__ */ React15.createElement(Typography8, { variant: "body2", fontWeight: "bold" }, title), /* @__PURE__ */ React15.createElement(Typography8, { variant: "caption", color: "text.secondary" }, subtitle)),
|
|
1478
|
+
/* @__PURE__ */ React15.createElement(Button5, { variant: "outlined", color: "secondary", size: "small", disabled: ctaDisabled, onClick: onCtaClick }, ctaLabel)
|
|
1493
1479
|
);
|
|
1494
1480
|
}
|
|
1495
1481
|
|
|
@@ -1518,7 +1504,7 @@ function Promotions({ report }) {
|
|
|
1518
1504
|
if (cards.length === 0) {
|
|
1519
1505
|
return null;
|
|
1520
1506
|
}
|
|
1521
|
-
return /* @__PURE__ */
|
|
1507
|
+
return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Divider, null), /* @__PURE__ */ React16.createElement(Typography9, { variant: "subtitle1", fontWeight: "bold" }, __14("Quick actions", "elementor")), /* @__PURE__ */ React16.createElement(Box11, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, cards.map(({ config, ctaUrl, key, run, subtitle }) => /* @__PURE__ */ React16.createElement(
|
|
1522
1508
|
PromotionCard,
|
|
1523
1509
|
{
|
|
1524
1510
|
key,
|
|
@@ -1536,241 +1522,118 @@ function Promotions({ report }) {
|
|
|
1536
1522
|
))));
|
|
1537
1523
|
}
|
|
1538
1524
|
|
|
1539
|
-
// src/components/
|
|
1540
|
-
import * as
|
|
1541
|
-
import {
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
return /* @__PURE__ */ React21.createElement(
|
|
1546
|
-
Box17,
|
|
1547
|
-
{
|
|
1548
|
-
role: onClick ? "button" : void 0,
|
|
1549
|
-
tabIndex: onClick ? 0 : void 0,
|
|
1550
|
-
onClick,
|
|
1551
|
-
onKeyDown: onClick ? onKeyboardClick(onClick) : void 0,
|
|
1552
|
-
sx: {
|
|
1553
|
-
display: "flex",
|
|
1554
|
-
alignItems: "center",
|
|
1555
|
-
gap: 1,
|
|
1556
|
-
cursor: onClick ? "pointer" : "default",
|
|
1557
|
-
outline: "none",
|
|
1558
|
-
"&:focus-visible": { outline: "2px solid", outlineColor: "primary.main", borderRadius: 1 },
|
|
1559
|
-
py: 0.5
|
|
1560
|
-
}
|
|
1561
|
-
},
|
|
1562
|
-
/* @__PURE__ */ React21.createElement(Typography13, { variant: "body2", sx: { minWidth: 96 } }, label),
|
|
1563
|
-
/* @__PURE__ */ React21.createElement(
|
|
1564
|
-
LinearProgress,
|
|
1565
|
-
{
|
|
1566
|
-
variant: "determinate",
|
|
1567
|
-
value: score,
|
|
1568
|
-
color: getScoreTier(score).color,
|
|
1569
|
-
sx: { flex: 1, height: 6, borderRadius: 4, bgcolor: "action.disabledBackground" }
|
|
1570
|
-
}
|
|
1571
|
-
),
|
|
1572
|
-
/* @__PURE__ */ React21.createElement(
|
|
1573
|
-
Typography13,
|
|
1574
|
-
{
|
|
1575
|
-
variant: "body2",
|
|
1576
|
-
color: "text.primary",
|
|
1577
|
-
sx: { minWidth: 24, textAlign: "right", fontWeight: 900 }
|
|
1578
|
-
},
|
|
1579
|
-
score
|
|
1580
|
-
),
|
|
1581
|
-
onClick && /* @__PURE__ */ React21.createElement(Rotate3, { in: isRtl }, /* @__PURE__ */ React21.createElement(ChevronRightIcon2, { fontSize: "small", color: "action" }))
|
|
1582
|
-
);
|
|
1525
|
+
// src/components/severity-summary-cards.tsx
|
|
1526
|
+
import * as React17 from "react";
|
|
1527
|
+
import { Box as Box12, Typography as Typography10 } from "@elementor/ui";
|
|
1528
|
+
function SeveritySummaryCards({ report }) {
|
|
1529
|
+
const counts = countSeverities(report);
|
|
1530
|
+
return /* @__PURE__ */ React17.createElement(Box12, { display: "flex", gap: 1.5 }, ALL_SEVERITIES.map((severity) => /* @__PURE__ */ React17.createElement(SeverityCard, { key: severity, severity, count: counts[severity] })));
|
|
1583
1531
|
}
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
import { Box as Box18, CircularProgress as CircularProgress2, Typography as Typography14 } from "@elementor/ui";
|
|
1588
|
-
var SCORE_CIRCLE_SIZE = 88;
|
|
1589
|
-
var SCORE_CIRCLE_THICKNESS = 3;
|
|
1590
|
-
function ScoreCircle({ color, score }) {
|
|
1591
|
-
const progressColor = color ?? getScoreTier(score).color;
|
|
1592
|
-
return /* @__PURE__ */ React22.createElement(
|
|
1593
|
-
Box18,
|
|
1532
|
+
function SeverityCard({ severity, count }) {
|
|
1533
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1534
|
+
Box12,
|
|
1594
1535
|
{
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
"
|
|
1598
|
-
|
|
1599
|
-
|
|
1536
|
+
display: "flex",
|
|
1537
|
+
flex: 1,
|
|
1538
|
+
flexDirection: "column",
|
|
1539
|
+
gap: 1,
|
|
1540
|
+
bgcolor: "action.hover",
|
|
1541
|
+
borderRadius: 1.5,
|
|
1542
|
+
px: 1.5,
|
|
1543
|
+
py: 1
|
|
1600
1544
|
},
|
|
1601
|
-
/* @__PURE__ */
|
|
1602
|
-
|
|
1603
|
-
{
|
|
1604
|
-
variant: "determinate",
|
|
1605
|
-
value: 100,
|
|
1606
|
-
size: SCORE_CIRCLE_SIZE,
|
|
1607
|
-
thickness: SCORE_CIRCLE_THICKNESS,
|
|
1608
|
-
sx: { color: "action.disabledBackground" }
|
|
1609
|
-
}
|
|
1610
|
-
),
|
|
1611
|
-
/* @__PURE__ */ React22.createElement(
|
|
1612
|
-
CircularProgress2,
|
|
1613
|
-
{
|
|
1614
|
-
variant: "determinate",
|
|
1615
|
-
value: score,
|
|
1616
|
-
size: SCORE_CIRCLE_SIZE,
|
|
1617
|
-
thickness: SCORE_CIRCLE_THICKNESS,
|
|
1618
|
-
color: progressColor,
|
|
1619
|
-
sx: { position: "absolute", left: 0 }
|
|
1620
|
-
}
|
|
1621
|
-
),
|
|
1622
|
-
/* @__PURE__ */ React22.createElement(
|
|
1623
|
-
Box18,
|
|
1624
|
-
{
|
|
1625
|
-
sx: {
|
|
1626
|
-
position: "absolute",
|
|
1627
|
-
inset: 0,
|
|
1628
|
-
display: "flex",
|
|
1629
|
-
alignItems: "center",
|
|
1630
|
-
justifyContent: "center"
|
|
1631
|
-
}
|
|
1632
|
-
},
|
|
1633
|
-
/* @__PURE__ */ React22.createElement(
|
|
1634
|
-
Typography14,
|
|
1635
|
-
{
|
|
1636
|
-
variant: "h4",
|
|
1637
|
-
component: "span",
|
|
1638
|
-
color: "text.primary",
|
|
1639
|
-
sx: { fontWeight: 700, lineHeight: 1 }
|
|
1640
|
-
},
|
|
1641
|
-
score
|
|
1642
|
-
)
|
|
1643
|
-
)
|
|
1545
|
+
/* @__PURE__ */ React17.createElement(SeverityIcon, { severity }),
|
|
1546
|
+
/* @__PURE__ */ React17.createElement(Box12, { display: "flex", flexDirection: "column" }, /* @__PURE__ */ React17.createElement(Typography10, { variant: "h5", fontWeight: 700, component: "span" }, count), /* @__PURE__ */ React17.createElement(Typography10, { variant: "caption", color: "text.secondary" }, severityPluralLabel(severity)))
|
|
1644
1547
|
);
|
|
1645
1548
|
}
|
|
1646
1549
|
|
|
1647
1550
|
// src/components/pages/overview-page.tsx
|
|
1648
1551
|
function OverviewPage({ onCategoryClick, report }) {
|
|
1649
1552
|
const populatedCategories = getPopulatedCategories(report.categories, ALL_CATEGORIES);
|
|
1650
|
-
const
|
|
1651
|
-
return /* @__PURE__ */
|
|
1652
|
-
|
|
1653
|
-
{
|
|
1654
|
-
label: overallScore.label,
|
|
1655
|
-
color: overallScore.color,
|
|
1656
|
-
variant: "standard",
|
|
1657
|
-
size: "small",
|
|
1658
|
-
sx: { fontWeight: 600, alignSelf: "flex-start" }
|
|
1659
|
-
}
|
|
1660
|
-
), /* @__PURE__ */ React23.createElement(Typography15, { variant: "body2", color: "text.secondary" }, __21("Overall score", "elementor")))), /* @__PURE__ */ React23.createElement(Box19, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, populatedCategories.map((category) => /* @__PURE__ */ React23.createElement(
|
|
1661
|
-
ScoreBar,
|
|
1553
|
+
const categoryRows = populatedCategories.map((category) => ({ category, counts: countSeverities(report, category) })).filter(({ counts }) => Object.values(counts).some((count) => count > 0));
|
|
1554
|
+
return /* @__PURE__ */ React18.createElement(Box13, { display: "flex", flexDirection: "column", gap: 3, p: 2 }, /* @__PURE__ */ React18.createElement(SeveritySummaryCards, { report }), /* @__PURE__ */ React18.createElement(Box13, { display: "flex", flexDirection: "column", gap: 1 }, /* @__PURE__ */ React18.createElement(Typography11, { variant: "subtitle1", component: "h2" }, __15("All issues", "elementor")), /* @__PURE__ */ React18.createElement(Box13, { display: "flex", flexDirection: "column", gap: 1 }, categoryRows.map(({ category, counts }) => /* @__PURE__ */ React18.createElement(
|
|
1555
|
+
IssuesCategoryRow,
|
|
1662
1556
|
{
|
|
1663
1557
|
key: category,
|
|
1558
|
+
category,
|
|
1664
1559
|
label: CATEGORY_LABELS[category],
|
|
1665
|
-
|
|
1560
|
+
counts,
|
|
1666
1561
|
onClick: () => onCategoryClick(category)
|
|
1667
1562
|
}
|
|
1668
|
-
))), /* @__PURE__ */
|
|
1563
|
+
)))), /* @__PURE__ */ React18.createElement(Promotions, { report }));
|
|
1669
1564
|
}
|
|
1670
1565
|
|
|
1671
1566
|
// src/components/report-shell.tsx
|
|
1672
|
-
function activeTab(page) {
|
|
1673
|
-
if (page === "overview") {
|
|
1674
|
-
return "overview";
|
|
1675
|
-
}
|
|
1676
|
-
if (page === "issues") {
|
|
1677
|
-
return "issues";
|
|
1678
|
-
}
|
|
1679
|
-
return page.backTo;
|
|
1680
|
-
}
|
|
1681
|
-
function isAllAuditsPage(page) {
|
|
1682
|
-
return typeof page === "object" && "page" in page && page.page === "all-audits";
|
|
1683
|
-
}
|
|
1684
1567
|
function isCategoryPage(page) {
|
|
1685
1568
|
return typeof page === "object" && "category" in page;
|
|
1686
1569
|
}
|
|
1687
1570
|
function ReportShell({ report }) {
|
|
1688
|
-
const [activePage, setActivePage] =
|
|
1689
|
-
const
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
return /* @__PURE__ */ React24.createElement(Box20, { sx: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 } }, /* @__PURE__ */ React24.createElement(Box20, { sx: { flexShrink: 0 } }, /* @__PURE__ */ React24.createElement(
|
|
1705
|
-
Tabs,
|
|
1571
|
+
const [activePage, setActivePage] = useState4("overview");
|
|
1572
|
+
const openCategory = (category) => setActivePage({ category });
|
|
1573
|
+
const backToOverview = () => setActivePage("overview");
|
|
1574
|
+
return /* @__PURE__ */ React19.createElement(Box14, { sx: { flex: 1, minHeight: 0, overflowY: "auto" } }, activePage === "overview" && /* @__PURE__ */ React19.createElement(OverviewPage, { report, onCategoryClick: openCategory }), isCategoryPage(activePage) && /* @__PURE__ */ React19.createElement(CategoryPage, { category: activePage.category, report, onBack: backToOverview }));
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// src/components/rescan-button.tsx
|
|
1578
|
+
import * as React20 from "react";
|
|
1579
|
+
import { useFloatingPanelZIndex as useFloatingPanelZIndex3 } from "@elementor/editor-floating-panels";
|
|
1580
|
+
import { ReloadIcon } from "@elementor/icons";
|
|
1581
|
+
import { Badge as Badge2, Button as Button6, Tooltip as Tooltip4 } from "@elementor/ui";
|
|
1582
|
+
import { __ as __16 } from "@wordpress/i18n";
|
|
1583
|
+
function RescanButton({ hasScanned, isStale, disabled, onClick }) {
|
|
1584
|
+
const panelZIndex = useFloatingPanelZIndex3(AUDIT_PANEL_ID);
|
|
1585
|
+
return /* @__PURE__ */ React20.createElement(
|
|
1586
|
+
Tooltip4,
|
|
1706
1587
|
{
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
textColor: "secondary",
|
|
1711
|
-
indicatorColor: "secondary",
|
|
1712
|
-
size: "small",
|
|
1713
|
-
centered: true,
|
|
1714
|
-
variant: "fullWidth"
|
|
1588
|
+
title: __16("Page content changed - rescan advised", "elementor"),
|
|
1589
|
+
disableHoverListener: !isStale,
|
|
1590
|
+
PopperProps: { sx: { zIndex: panelZIndex } }
|
|
1715
1591
|
},
|
|
1716
|
-
/* @__PURE__ */
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
onCategoryClick: (category) => openCategory(category, "issues"),
|
|
1729
|
-
onAllAuditsClick: () => openAllAudits(),
|
|
1730
|
-
onStatusClick: (status) => openAllAudits(status)
|
|
1731
|
-
}
|
|
1732
|
-
), isAllAuditsPage(activePage) && /* @__PURE__ */ React24.createElement(
|
|
1733
|
-
AllAuditsPage,
|
|
1734
|
-
{
|
|
1735
|
-
report,
|
|
1736
|
-
initialExpandedStatus: activePage.expand,
|
|
1737
|
-
onBack: backFromSubPage
|
|
1738
|
-
}
|
|
1739
|
-
), isCategoryPage(activePage) && /* @__PURE__ */ React24.createElement(CategoryPage, { category: activePage.category, report, onBack: backFromSubPage })));
|
|
1592
|
+
/* @__PURE__ */ React20.createElement(Badge2, { variant: "dot", color: "warning", invisible: !isStale, overlap: "rectangular" }, /* @__PURE__ */ React20.createElement(
|
|
1593
|
+
Button6,
|
|
1594
|
+
{
|
|
1595
|
+
variant: "contained",
|
|
1596
|
+
size: "small",
|
|
1597
|
+
startIcon: hasScanned ? /* @__PURE__ */ React20.createElement(ReloadIcon, { fontSize: "small" }) : void 0,
|
|
1598
|
+
onClick,
|
|
1599
|
+
disabled
|
|
1600
|
+
},
|
|
1601
|
+
hasScanned ? __16("Rescan", "elementor") : __16("Run page audit", "elementor")
|
|
1602
|
+
))
|
|
1603
|
+
);
|
|
1740
1604
|
}
|
|
1741
1605
|
|
|
1742
1606
|
// src/components/audit-panel.tsx
|
|
1743
1607
|
function AuditPanel() {
|
|
1744
|
-
const { status, report, error, run } = useAuditReport();
|
|
1745
|
-
const
|
|
1746
|
-
const onRun = () => run(
|
|
1608
|
+
const { status, report, error, isStale, run } = useAuditReport();
|
|
1609
|
+
const hostDocumentId = getHostDocumentId3() ?? 0;
|
|
1610
|
+
const onRun = () => run(hostDocumentId);
|
|
1747
1611
|
const lastScanLabel = report ? new Date(report.runAt).toLocaleTimeString() : null;
|
|
1748
|
-
return /* @__PURE__ */
|
|
1612
|
+
return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(
|
|
1749
1613
|
FloatingPanelHeader,
|
|
1750
1614
|
{
|
|
1751
|
-
panelId:
|
|
1752
|
-
title:
|
|
1753
|
-
badge:
|
|
1615
|
+
panelId: AUDIT_PANEL_ID,
|
|
1616
|
+
title: __17("Page Audit", "elementor"),
|
|
1617
|
+
badge: __17("Beta", "elementor"),
|
|
1754
1618
|
titleVariant: "subtitle2"
|
|
1755
1619
|
}
|
|
1756
|
-
), /* @__PURE__ */
|
|
1620
|
+
), /* @__PURE__ */ React21.createElement(
|
|
1757
1621
|
FloatingPanelBody,
|
|
1758
1622
|
{
|
|
1759
1623
|
sx: status === "ready" ? { display: "flex", flexDirection: "column", overflow: "hidden", minHeight: 0 } : void 0
|
|
1760
1624
|
},
|
|
1761
|
-
status === "idle" && /* @__PURE__ */
|
|
1762
|
-
status === "loading" && /* @__PURE__ */
|
|
1763
|
-
status === "error" && /* @__PURE__ */
|
|
1764
|
-
status === "ready" && report && /* @__PURE__ */
|
|
1765
|
-
), /* @__PURE__ */
|
|
1766
|
-
|
|
1625
|
+
status === "idle" && /* @__PURE__ */ React21.createElement(WelcomePage, null),
|
|
1626
|
+
status === "loading" && /* @__PURE__ */ React21.createElement(LoadingPage, null),
|
|
1627
|
+
status === "error" && /* @__PURE__ */ React21.createElement(ErrorPage, { message: error ?? "", onRetry: onRun }),
|
|
1628
|
+
status === "ready" && report && /* @__PURE__ */ React21.createElement(ReportShell, { report })
|
|
1629
|
+
), /* @__PURE__ */ React21.createElement(FloatingPanelFooter, null, lastScanLabel ? /* @__PURE__ */ React21.createElement(Typography12, { variant: "caption", sx: { flex: 1 } }, __17("Last scan:", "elementor"), " ", lastScanLabel) : /* @__PURE__ */ React21.createElement(Box15, { sx: { flex: 1 } }), lastScanLabel && /* @__PURE__ */ React21.createElement(AuditFeedback, null), /* @__PURE__ */ React21.createElement(
|
|
1630
|
+
RescanButton,
|
|
1767
1631
|
{
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
}
|
|
1773
|
-
lastScanLabel ? __23("Re-scan", "elementor") : __23("Run page audit", "elementor")
|
|
1632
|
+
hasScanned: Boolean(lastScanLabel),
|
|
1633
|
+
isStale,
|
|
1634
|
+
disabled: status === "loading" || hostDocumentId === 0,
|
|
1635
|
+
onClick: onRun
|
|
1636
|
+
}
|
|
1774
1637
|
)));
|
|
1775
1638
|
}
|
|
1776
1639
|
|
|
@@ -1788,54 +1651,131 @@ var auditPanel = createFloatingPanel({
|
|
|
1788
1651
|
minWidth: 280,
|
|
1789
1652
|
minHeight: 400
|
|
1790
1653
|
}
|
|
1791
|
-
});
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1656
|
+
// src/hooks/use-audit-toggle-props.ts
|
|
1657
|
+
function useAuditToggleProps() {
|
|
1658
|
+
const { isOpen } = auditPanel.useFloatingPanelStatus();
|
|
1659
|
+
const { toggle } = auditPanel.useFloatingPanelActions();
|
|
1660
|
+
return {
|
|
1661
|
+
title: __18("Audit Page", "elementor"),
|
|
1662
|
+
icon: AuditToggleIcon,
|
|
1663
|
+
selected: isOpen,
|
|
1664
|
+
onClick: () => toggle()
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
// src/editor-app-bar.tsx
|
|
1669
|
+
var AUDIT_TOGGLE_PRIORITY = 24;
|
|
1670
|
+
function registerAppBarAuditsToggle() {
|
|
1671
|
+
utilitiesMenu.registerToggleAction({
|
|
1672
|
+
id: "toggle-audit-panel",
|
|
1673
|
+
priority: AUDIT_TOGGLE_PRIORITY,
|
|
1674
|
+
useProps: useAuditToggleProps
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// src/audits/accessibility-policy.ts
|
|
1679
|
+
import { __ as __19 } from "@wordpress/i18n";
|
|
1680
|
+
var audit = {
|
|
1681
|
+
id: "audits/accessibility-policy",
|
|
1682
|
+
title: __19("Accessibility policy", "elementor"),
|
|
1683
|
+
description: __19(
|
|
1684
|
+
"An accessibility policy demonstrates your commitment to digital inclusion and may be legally required in some regions.",
|
|
1685
|
+
"elementor"
|
|
1686
|
+
),
|
|
1687
|
+
fixHint: __19("Install the Ally plugin to add an accessibility policy to your website.", "elementor"),
|
|
1688
|
+
categories: ["compliance"],
|
|
1689
|
+
severity: "info",
|
|
1690
|
+
weight: 1,
|
|
1691
|
+
evaluate: (ctx) => {
|
|
1692
|
+
if (ctx.pageContext.ally_plugin_active) {
|
|
1693
|
+
return { status: "pass" };
|
|
1694
|
+
}
|
|
1695
|
+
return {
|
|
1696
|
+
status: "fail",
|
|
1697
|
+
violations: [
|
|
1698
|
+
{
|
|
1699
|
+
auditId: audit.id,
|
|
1700
|
+
label: __19("Ally plugin is not installed or active.", "elementor"),
|
|
1701
|
+
externalUrl: ctx.pageContext.ally_plugin_url
|
|
1702
|
+
}
|
|
1703
|
+
]
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
// src/audits/accessibility-statement.ts
|
|
1709
|
+
import { __ as __20 } from "@wordpress/i18n";
|
|
1710
|
+
var audit2 = {
|
|
1711
|
+
id: "audits/accessibility-statement",
|
|
1712
|
+
title: __20("Create an accessibility statement", "elementor"),
|
|
1713
|
+
description: __20(
|
|
1714
|
+
"An accessibility statement showcases your efforts to create an inclusive online space, highlighting helpful features and a commitment to accessibility.",
|
|
1715
|
+
"elementor"
|
|
1716
|
+
),
|
|
1717
|
+
fixHint: __20("Use Ally to create and publish an accessibility statement for your site.", "elementor"),
|
|
1718
|
+
categories: ["accessibility"],
|
|
1719
|
+
severity: "info",
|
|
1720
|
+
weight: 1,
|
|
1721
|
+
evaluate: (ctx) => {
|
|
1722
|
+
const isReady = ctx.pageContext.ally_plugin_active;
|
|
1723
|
+
if (isReady && ctx.pageContext.ally_accessibility_statement_created) {
|
|
1724
|
+
return { status: "pass" };
|
|
1725
|
+
}
|
|
1726
|
+
return {
|
|
1727
|
+
status: "fail",
|
|
1728
|
+
violations: [
|
|
1729
|
+
{
|
|
1730
|
+
auditId: audit2.id,
|
|
1731
|
+
label: __20("No accessibility statement has been created for this site.", "elementor"),
|
|
1732
|
+
externalUrl: isReady ? ctx.pageContext.ally_accessibility_statement_url : ctx.pageContext.ally_plugin_url,
|
|
1733
|
+
ctaLabel: __20("Create", "elementor"),
|
|
1734
|
+
secondaryCtaLabel: __20("Learn more", "elementor"),
|
|
1735
|
+
secondaryCtaUrl: "https://elementor.com/help/start-using-ally/#statement"
|
|
1736
|
+
}
|
|
1737
|
+
]
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1792
1741
|
|
|
1793
|
-
// src/
|
|
1794
|
-
|
|
1795
|
-
const { isOpen } = auditPanel.useFloatingPanelStatus();
|
|
1796
|
-
const { toggle } = auditPanel.useFloatingPanelActions();
|
|
1797
|
-
return {
|
|
1798
|
-
title: __24("Audit Page", "elementor"),
|
|
1799
|
-
icon: ShieldCheckIcon3,
|
|
1800
|
-
selected: isOpen,
|
|
1801
|
-
onClick: () => toggle()
|
|
1802
|
-
};
|
|
1803
|
-
}
|
|
1742
|
+
// src/audits/accessibility-widget.ts
|
|
1743
|
+
import { __ as __21 } from "@wordpress/i18n";
|
|
1804
1744
|
|
|
1805
|
-
// src/
|
|
1806
|
-
var
|
|
1807
|
-
function
|
|
1808
|
-
|
|
1809
|
-
id: "toggle-audit-panel",
|
|
1810
|
-
priority: AUDIT_TOGGLE_PRIORITY,
|
|
1811
|
-
useProps: useAuditToggleProps
|
|
1812
|
-
});
|
|
1745
|
+
// src/utils/scan-accessibility-widgets.ts
|
|
1746
|
+
var ACCESSIBILITY_WIDGET_SCRIPT_SOURCES = ["cdn.elementor.com/a11y/widget.js"];
|
|
1747
|
+
function hasAccessibilityWidgetScript(html) {
|
|
1748
|
+
return ACCESSIBILITY_WIDGET_SCRIPT_SOURCES.some((src) => html.includes(src));
|
|
1813
1749
|
}
|
|
1814
1750
|
|
|
1815
|
-
// src/audits/accessibility-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
"elementor"
|
|
1823
|
-
),
|
|
1824
|
-
fixHint: __25("Install the Ally plugin to add an accessibility policy to your website.", "elementor"),
|
|
1825
|
-
categories: ["compliance"],
|
|
1751
|
+
// src/audits/accessibility-widget.ts
|
|
1752
|
+
var audit3 = {
|
|
1753
|
+
id: "audits/accessibility-widget",
|
|
1754
|
+
title: __21("Add an accessibility widget", "elementor"),
|
|
1755
|
+
description: __21("Make your site more inclusive by adding an accessibility widget.", "elementor"),
|
|
1756
|
+
fixHint: __21("Activate Ally\u2019s accessibility widget to give visitors on-page accessibility tools.", "elementor"),
|
|
1757
|
+
categories: ["accessibility"],
|
|
1826
1758
|
severity: "info",
|
|
1827
1759
|
weight: 1,
|
|
1828
1760
|
evaluate: (ctx) => {
|
|
1829
|
-
if (ctx.pageContext.
|
|
1761
|
+
if (!ctx.pageContext.frontend_url) {
|
|
1762
|
+
return { status: "skipped", reason: __21("Page is not published.", "elementor") };
|
|
1763
|
+
}
|
|
1764
|
+
if (!ctx.renderedHtml) {
|
|
1765
|
+
return { status: "skipped", reason: __21("Could not fetch the published page.", "elementor") };
|
|
1766
|
+
}
|
|
1767
|
+
if (hasAccessibilityWidgetScript(ctx.renderedHtml)) {
|
|
1830
1768
|
return { status: "pass" };
|
|
1831
1769
|
}
|
|
1770
|
+
const isReady = ctx.pageContext.ally_plugin_active;
|
|
1832
1771
|
return {
|
|
1833
1772
|
status: "fail",
|
|
1834
1773
|
violations: [
|
|
1835
1774
|
{
|
|
1836
|
-
auditId:
|
|
1837
|
-
label:
|
|
1838
|
-
externalUrl: ctx.pageContext.ally_plugin_url
|
|
1775
|
+
auditId: audit3.id,
|
|
1776
|
+
label: __21("No accessibility widget is active on this site.", "elementor"),
|
|
1777
|
+
externalUrl: isReady ? ctx.pageContext.ally_widget_settings_url : ctx.pageContext.ally_plugin_url,
|
|
1778
|
+
ctaLabel: __21("Activate", "elementor")
|
|
1839
1779
|
}
|
|
1840
1780
|
]
|
|
1841
1781
|
};
|
|
@@ -1843,15 +1783,15 @@ var audit = {
|
|
|
1843
1783
|
};
|
|
1844
1784
|
|
|
1845
1785
|
// src/audits/cookie-policy.ts
|
|
1846
|
-
import { __ as
|
|
1847
|
-
var
|
|
1786
|
+
import { __ as __22 } from "@wordpress/i18n";
|
|
1787
|
+
var audit4 = {
|
|
1848
1788
|
id: "audits/cookie-policy",
|
|
1849
|
-
title:
|
|
1850
|
-
description:
|
|
1789
|
+
title: __22("Cookie policy", "elementor"),
|
|
1790
|
+
description: __22(
|
|
1851
1791
|
"A cookie policy is required by privacy regulations such as GDPR (EU) or CCPA (US) to inform visitors about tracking and data collection.",
|
|
1852
1792
|
"elementor"
|
|
1853
1793
|
),
|
|
1854
|
-
fixHint:
|
|
1794
|
+
fixHint: __22("Install the Cookiez plugin to add a cookie policy to your website.", "elementor"),
|
|
1855
1795
|
categories: ["compliance"],
|
|
1856
1796
|
severity: "info",
|
|
1857
1797
|
weight: 1,
|
|
@@ -1863,9 +1803,10 @@ var audit2 = {
|
|
|
1863
1803
|
status: "fail",
|
|
1864
1804
|
violations: [
|
|
1865
1805
|
{
|
|
1866
|
-
auditId:
|
|
1867
|
-
label:
|
|
1868
|
-
externalUrl: ctx.pageContext.cookiez_plugin_url
|
|
1806
|
+
auditId: audit4.id,
|
|
1807
|
+
label: __22("Cookiez plugin is not installed or active.", "elementor"),
|
|
1808
|
+
externalUrl: ctx.pageContext.cookiez_plugin_url,
|
|
1809
|
+
ctaLabel: __22("Set up cookie consent", "elementor")
|
|
1869
1810
|
}
|
|
1870
1811
|
]
|
|
1871
1812
|
};
|
|
@@ -1874,7 +1815,7 @@ var audit2 = {
|
|
|
1874
1815
|
|
|
1875
1816
|
// src/audits/deep-nesting.ts
|
|
1876
1817
|
import { getWidgetsCache } from "@elementor/editor-elements";
|
|
1877
|
-
import { __ as
|
|
1818
|
+
import { __ as __23 } from "@wordpress/i18n";
|
|
1878
1819
|
var MAX_NESTING_DEPTH = 6;
|
|
1879
1820
|
function isNestingElement(node, widgetsCache) {
|
|
1880
1821
|
if (node.elType === "container") {
|
|
@@ -1882,20 +1823,20 @@ function isNestingElement(node, widgetsCache) {
|
|
|
1882
1823
|
}
|
|
1883
1824
|
return !!widgetsCache?.[node.elType]?.meta?.is_container;
|
|
1884
1825
|
}
|
|
1885
|
-
var
|
|
1826
|
+
var audit5 = {
|
|
1886
1827
|
id: "audits/deep-nesting",
|
|
1887
|
-
title:
|
|
1888
|
-
description:
|
|
1828
|
+
title: __23("Deep container nesting", "elementor"),
|
|
1829
|
+
description: __23(
|
|
1889
1830
|
"Container nesting exceeds the recommended depth. Deep DOM trees hurt rendering performance and readability.",
|
|
1890
1831
|
"elementor"
|
|
1891
1832
|
),
|
|
1892
|
-
fixHint:
|
|
1833
|
+
fixHint: __23("Flatten the layout by removing unnecessary wrapper containers.", "elementor"),
|
|
1893
1834
|
categories: ["performance", "best-practices"],
|
|
1894
1835
|
severity: "warning",
|
|
1895
1836
|
weight: 5,
|
|
1896
1837
|
evaluate: (ctx) => {
|
|
1897
1838
|
if (ctx.elements.tree.length === 0) {
|
|
1898
|
-
return { status: "skipped", reason:
|
|
1839
|
+
return { status: "skipped", reason: __23("No elements", "elementor") };
|
|
1899
1840
|
}
|
|
1900
1841
|
const widgetsCache = getWidgetsCache();
|
|
1901
1842
|
const violations = [];
|
|
@@ -1906,10 +1847,10 @@ var audit3 = {
|
|
|
1906
1847
|
const depth = parents.filter((parent) => isNestingElement(parent, widgetsCache)).length + 1;
|
|
1907
1848
|
if (depth > MAX_NESTING_DEPTH) {
|
|
1908
1849
|
violations.push({
|
|
1909
|
-
auditId:
|
|
1850
|
+
auditId: audit5.id,
|
|
1910
1851
|
elementId: node.id,
|
|
1911
1852
|
targetHint: "element-settings",
|
|
1912
|
-
label:
|
|
1853
|
+
label: __23("Container nesting is too deep.", "elementor")
|
|
1913
1854
|
});
|
|
1914
1855
|
}
|
|
1915
1856
|
});
|
|
@@ -1918,15 +1859,15 @@ var audit3 = {
|
|
|
1918
1859
|
};
|
|
1919
1860
|
|
|
1920
1861
|
// src/audits/default-design-system.ts
|
|
1921
|
-
import { __ as
|
|
1922
|
-
var
|
|
1862
|
+
import { __ as __24 } from "@wordpress/i18n";
|
|
1863
|
+
var audit6 = {
|
|
1923
1864
|
id: "audits/default-design-system",
|
|
1924
|
-
title:
|
|
1925
|
-
description:
|
|
1865
|
+
title: __24("Default website kit", "elementor"),
|
|
1866
|
+
description: __24(
|
|
1926
1867
|
"Your website is using the default design system colors and fonts. Custom branding makes the website feel uniquely yours.",
|
|
1927
1868
|
"elementor"
|
|
1928
1869
|
),
|
|
1929
|
-
fixHint:
|
|
1870
|
+
fixHint: __24("Open Site Settings and customize your kit (colors, fonts, layout).", "elementor"),
|
|
1930
1871
|
categories: ["best-practices"],
|
|
1931
1872
|
severity: "info",
|
|
1932
1873
|
weight: 1,
|
|
@@ -1938,8 +1879,8 @@ var audit4 = {
|
|
|
1938
1879
|
status: "fail",
|
|
1939
1880
|
violations: [
|
|
1940
1881
|
{
|
|
1941
|
-
auditId:
|
|
1942
|
-
label:
|
|
1882
|
+
auditId: audit6.id,
|
|
1883
|
+
label: __24("Kit appears unchanged from default.", "elementor"),
|
|
1943
1884
|
targetHint: "site-settings"
|
|
1944
1885
|
}
|
|
1945
1886
|
]
|
|
@@ -1949,16 +1890,16 @@ var audit4 = {
|
|
|
1949
1890
|
|
|
1950
1891
|
// src/audits/deprecated-widgets.ts
|
|
1951
1892
|
import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
|
|
1952
|
-
import { __ as
|
|
1893
|
+
import { __ as __25 } from "@wordpress/i18n";
|
|
1953
1894
|
var DEPRECATION_CONTROL_NAME = "deprecation_message";
|
|
1954
|
-
var
|
|
1895
|
+
var audit7 = {
|
|
1955
1896
|
id: "audits/deprecated-widgets",
|
|
1956
|
-
title:
|
|
1957
|
-
description:
|
|
1897
|
+
title: __25("Deprecated widgets", "elementor"),
|
|
1898
|
+
description: __25(
|
|
1958
1899
|
"Deprecated widgets should not be used. For better capabilities use the recommended replacement.",
|
|
1959
1900
|
"elementor"
|
|
1960
1901
|
),
|
|
1961
|
-
fixHint:
|
|
1902
|
+
fixHint: __25("Replace each deprecated widget with the recommended new widget shown in its panel.", "elementor"),
|
|
1962
1903
|
categories: ["best-practices", "performance"],
|
|
1963
1904
|
severity: "warning",
|
|
1964
1905
|
weight: 7,
|
|
@@ -1982,10 +1923,10 @@ var audit5 = {
|
|
|
1982
1923
|
return;
|
|
1983
1924
|
}
|
|
1984
1925
|
violations.push({
|
|
1985
|
-
auditId:
|
|
1926
|
+
auditId: audit7.id,
|
|
1986
1927
|
elementId: node.id,
|
|
1987
1928
|
targetHint: "element-settings",
|
|
1988
|
-
label:
|
|
1929
|
+
label: __25("Using deprecated widget.", "elementor")
|
|
1989
1930
|
});
|
|
1990
1931
|
});
|
|
1991
1932
|
return violations.length === 0 ? { status: "pass" } : { status: "fail", violations };
|
|
@@ -1993,28 +1934,7 @@ var audit5 = {
|
|
|
1993
1934
|
};
|
|
1994
1935
|
|
|
1995
1936
|
// src/audits/google-consent-mode.ts
|
|
1996
|
-
import { __ as
|
|
1997
|
-
|
|
1998
|
-
// src/utils/fetch-rendered-html.ts
|
|
1999
|
-
var FETCH_TIMEOUT_MS = 1e4;
|
|
2000
|
-
async function fetchRenderedHtml(url) {
|
|
2001
|
-
if (!url) {
|
|
2002
|
-
return null;
|
|
2003
|
-
}
|
|
2004
|
-
const timeoutController = new AbortController();
|
|
2005
|
-
const timeoutId = setTimeout(() => timeoutController.abort(), FETCH_TIMEOUT_MS);
|
|
2006
|
-
try {
|
|
2007
|
-
const response = await fetch(url, { credentials: "omit", signal: timeoutController.signal });
|
|
2008
|
-
if (!response.ok) {
|
|
2009
|
-
return null;
|
|
2010
|
-
}
|
|
2011
|
-
return await response.text();
|
|
2012
|
-
} catch {
|
|
2013
|
-
return null;
|
|
2014
|
-
} finally {
|
|
2015
|
-
clearTimeout(timeoutId);
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
1937
|
+
import { __ as __26 } from "@wordpress/i18n";
|
|
2018
1938
|
|
|
2019
1939
|
// src/utils/scan-consent-signals.ts
|
|
2020
1940
|
var GOOGLE_TRACKING_PATTERNS = [
|
|
@@ -2035,44 +1955,43 @@ function hasConsentDefaultCall(html) {
|
|
|
2035
1955
|
}
|
|
2036
1956
|
|
|
2037
1957
|
// src/audits/google-consent-mode.ts
|
|
2038
|
-
var
|
|
1958
|
+
var audit8 = {
|
|
2039
1959
|
id: "audits/google-consent-mode",
|
|
2040
|
-
title:
|
|
2041
|
-
description:
|
|
1960
|
+
title: __26("Google Consent Mode", "elementor"),
|
|
1961
|
+
description: __26(
|
|
2042
1962
|
"Google Analytics, Ads, or Tag Manager are running on this site and may not receive a consent signal, which risks losing conversion/analytics data and compliance exposure.",
|
|
2043
1963
|
"elementor"
|
|
2044
1964
|
),
|
|
2045
|
-
fixHint:
|
|
1965
|
+
fixHint: __26(
|
|
2046
1966
|
"Turn on Google Consent Mode in your cookie consent plugin so Google tags respect visitor consent choices.",
|
|
2047
1967
|
"elementor"
|
|
2048
1968
|
),
|
|
2049
1969
|
categories: ["compliance"],
|
|
2050
1970
|
severity: "warning",
|
|
2051
1971
|
weight: 1,
|
|
2052
|
-
evaluate:
|
|
1972
|
+
evaluate: (ctx) => {
|
|
2053
1973
|
if (!ctx.pageContext.frontend_url) {
|
|
2054
|
-
return { status: "skipped", reason:
|
|
1974
|
+
return { status: "skipped", reason: __26("Page is not published.", "elementor") };
|
|
2055
1975
|
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
return { status: "skipped", reason: __30("Could not fetch the published page.", "elementor") };
|
|
1976
|
+
if (!ctx.renderedHtml) {
|
|
1977
|
+
return { status: "skipped", reason: __26("Could not fetch the published page.", "elementor") };
|
|
2059
1978
|
}
|
|
2060
|
-
if (!hasGoogleTracking(
|
|
2061
|
-
return { status: "skipped", reason:
|
|
1979
|
+
if (!hasGoogleTracking(ctx.renderedHtml)) {
|
|
1980
|
+
return { status: "skipped", reason: __26("No Google tracking product detected.", "elementor") };
|
|
2062
1981
|
}
|
|
2063
|
-
if (hasConsentDefaultCall(
|
|
1982
|
+
if (hasConsentDefaultCall(ctx.renderedHtml)) {
|
|
2064
1983
|
return { status: "pass" };
|
|
2065
1984
|
}
|
|
2066
|
-
const label =
|
|
1985
|
+
const label = __26("No Google Consent Mode signal was found on the page.", "elementor");
|
|
2067
1986
|
const isCookiezReady = ctx.pageContext.cookiez_plugin_installed && ctx.pageContext.cookiez_plugin_active;
|
|
2068
1987
|
if (isCookiezReady) {
|
|
2069
1988
|
return {
|
|
2070
1989
|
status: "fail",
|
|
2071
1990
|
violations: [
|
|
2072
1991
|
{
|
|
2073
|
-
auditId:
|
|
1992
|
+
auditId: audit8.id,
|
|
2074
1993
|
label,
|
|
2075
|
-
ctaLabel:
|
|
1994
|
+
ctaLabel: __26("Enable", "elementor"),
|
|
2076
1995
|
externalUrl: ctx.pageContext.cookiez_consent_mode_settings_url
|
|
2077
1996
|
}
|
|
2078
1997
|
]
|
|
@@ -2082,7 +2001,7 @@ var audit6 = {
|
|
|
2082
2001
|
status: "fail",
|
|
2083
2002
|
violations: [
|
|
2084
2003
|
{
|
|
2085
|
-
auditId:
|
|
2004
|
+
auditId: audit8.id,
|
|
2086
2005
|
label,
|
|
2087
2006
|
externalUrl: ctx.pageContext.cookiez_plugin_action_url
|
|
2088
2007
|
}
|
|
@@ -2092,7 +2011,7 @@ var audit6 = {
|
|
|
2092
2011
|
};
|
|
2093
2012
|
|
|
2094
2013
|
// src/audits/heading-structure.ts
|
|
2095
|
-
import { __ as
|
|
2014
|
+
import { __ as __27 } from "@wordpress/i18n";
|
|
2096
2015
|
var HEADING_LEVELS = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
2097
2016
|
var HEADING_CONTROLS_REGISTRY = {
|
|
2098
2017
|
// Core
|
|
@@ -2268,47 +2187,47 @@ function extractPageHeadings(tree) {
|
|
|
2268
2187
|
});
|
|
2269
2188
|
return headings;
|
|
2270
2189
|
}
|
|
2271
|
-
var
|
|
2190
|
+
var audit9 = {
|
|
2272
2191
|
id: "audits/heading-structure",
|
|
2273
|
-
title:
|
|
2274
|
-
description:
|
|
2275
|
-
fixHint:
|
|
2192
|
+
title: __27("Heading structure", "elementor"),
|
|
2193
|
+
description: __27("Pages should have exactly one H1 and a non-skipping heading order.", "elementor"),
|
|
2194
|
+
fixHint: __27("Ensure your page has one H1 and that heading levels do not skip (no H2 \u2192 H4).", "elementor"),
|
|
2276
2195
|
categories: ["seo", "accessibility"],
|
|
2277
2196
|
severity: "error",
|
|
2278
2197
|
weight: 10,
|
|
2279
2198
|
evaluate: (ctx) => {
|
|
2280
2199
|
if (ctx.elements.tree.length === 0) {
|
|
2281
|
-
return { status: "skipped", reason:
|
|
2200
|
+
return { status: "skipped", reason: __27("No elements", "elementor") };
|
|
2282
2201
|
}
|
|
2283
2202
|
const headings = extractPageHeadings(ctx.elements.tree);
|
|
2284
2203
|
const violations = [];
|
|
2285
2204
|
if (headings.length === 0) {
|
|
2286
2205
|
violations.push({
|
|
2287
|
-
auditId:
|
|
2288
|
-
label:
|
|
2206
|
+
auditId: audit9.id,
|
|
2207
|
+
label: __27("No headings found on the page.", "elementor")
|
|
2289
2208
|
});
|
|
2290
2209
|
} else {
|
|
2291
2210
|
const h1Count = headings.filter((h) => h.level === 1).length;
|
|
2292
2211
|
if (h1Count === 0) {
|
|
2293
|
-
violations.push({ auditId:
|
|
2212
|
+
violations.push({ auditId: audit9.id, label: __27("No H1 on the page.", "elementor") });
|
|
2294
2213
|
}
|
|
2295
2214
|
if (h1Count > 1) {
|
|
2296
2215
|
headings.filter((h) => h.level === 1).slice(1).forEach(
|
|
2297
2216
|
(h) => violations.push({
|
|
2298
|
-
auditId:
|
|
2217
|
+
auditId: audit9.id,
|
|
2299
2218
|
elementId: h.elementId,
|
|
2300
2219
|
targetHint: "element-settings",
|
|
2301
|
-
label:
|
|
2220
|
+
label: __27("More than one H1 on the page.", "elementor")
|
|
2302
2221
|
})
|
|
2303
2222
|
);
|
|
2304
2223
|
}
|
|
2305
2224
|
for (let i = 1; i < headings.length; i++) {
|
|
2306
2225
|
if (headings[i].level - headings[i - 1].level > 1) {
|
|
2307
2226
|
violations.push({
|
|
2308
|
-
auditId:
|
|
2227
|
+
auditId: audit9.id,
|
|
2309
2228
|
elementId: headings[i].elementId,
|
|
2310
2229
|
targetHint: "element-settings",
|
|
2311
|
-
label:
|
|
2230
|
+
label: __27("Heading level skipped.", "elementor")
|
|
2312
2231
|
});
|
|
2313
2232
|
}
|
|
2314
2233
|
}
|
|
@@ -2318,33 +2237,33 @@ var audit7 = {
|
|
|
2318
2237
|
};
|
|
2319
2238
|
|
|
2320
2239
|
// src/audits/hidden-elements.ts
|
|
2321
|
-
import { __ as
|
|
2240
|
+
import { __ as __28 } from "@wordpress/i18n";
|
|
2322
2241
|
function isHiddenOnAllDevices(settings) {
|
|
2323
2242
|
return Boolean(settings.hide_desktop) && Boolean(settings.hide_tablet) && Boolean(settings.hide_mobile);
|
|
2324
2243
|
}
|
|
2325
|
-
var
|
|
2244
|
+
var audit10 = {
|
|
2326
2245
|
id: "audits/hidden-elements",
|
|
2327
|
-
title:
|
|
2328
|
-
description:
|
|
2246
|
+
title: __28("Hidden elements", "elementor"),
|
|
2247
|
+
description: __28(
|
|
2329
2248
|
"Elements hidden on all devices simultaneously are effectively dead code in the page tree.",
|
|
2330
2249
|
"elementor"
|
|
2331
2250
|
),
|
|
2332
|
-
fixHint:
|
|
2251
|
+
fixHint: __28("Remove the element or make it visible on at least one device breakpoint.", "elementor"),
|
|
2333
2252
|
categories: ["best-practices", "performance"],
|
|
2334
2253
|
severity: "info",
|
|
2335
2254
|
weight: 3,
|
|
2336
2255
|
evaluate: (ctx) => {
|
|
2337
2256
|
if (ctx.elements.tree.length === 0) {
|
|
2338
|
-
return { status: "skipped", reason:
|
|
2257
|
+
return { status: "skipped", reason: __28("No elements", "elementor") };
|
|
2339
2258
|
}
|
|
2340
2259
|
const violations = [];
|
|
2341
2260
|
walkElements(ctx.elements.tree, (node) => {
|
|
2342
2261
|
if (isHiddenOnAllDevices(node.settings)) {
|
|
2343
2262
|
violations.push({
|
|
2344
|
-
auditId:
|
|
2263
|
+
auditId: audit10.id,
|
|
2345
2264
|
elementId: node.id,
|
|
2346
2265
|
targetHint: "element-settings",
|
|
2347
|
-
label:
|
|
2266
|
+
label: __28("Element is hidden on all devices.", "elementor")
|
|
2348
2267
|
});
|
|
2349
2268
|
}
|
|
2350
2269
|
});
|
|
@@ -2353,7 +2272,22 @@ var audit8 = {
|
|
|
2353
2272
|
};
|
|
2354
2273
|
|
|
2355
2274
|
// src/audits/images-alt-text.ts
|
|
2356
|
-
import { __ as
|
|
2275
|
+
import { __ as __29 } from "@wordpress/i18n";
|
|
2276
|
+
|
|
2277
|
+
// src/utils/alt-text-image-sources.ts
|
|
2278
|
+
function walkAltTextImageSources(tree, visit) {
|
|
2279
|
+
walkImageLikeSources(tree, visit);
|
|
2280
|
+
walkAtomicImageSources(tree, visit, ATOMIC_CONTENT_IMAGE_PROP_KEYS);
|
|
2281
|
+
}
|
|
2282
|
+
function hasAltTextImages(tree) {
|
|
2283
|
+
let found = false;
|
|
2284
|
+
walkAltTextImageSources(tree, ({ media }) => {
|
|
2285
|
+
if (media.id || media.url) {
|
|
2286
|
+
found = true;
|
|
2287
|
+
}
|
|
2288
|
+
});
|
|
2289
|
+
return found;
|
|
2290
|
+
}
|
|
2357
2291
|
|
|
2358
2292
|
// src/utils/image-alt.ts
|
|
2359
2293
|
function hasMeaningfulAlt(media, pageContext) {
|
|
@@ -2361,7 +2295,8 @@ function hasMeaningfulAlt(media, pageContext) {
|
|
|
2361
2295
|
return true;
|
|
2362
2296
|
}
|
|
2363
2297
|
if (media.id) {
|
|
2364
|
-
const
|
|
2298
|
+
const key = buildImageSizeKey({ id: media.id, size: media.size });
|
|
2299
|
+
const alt = pageContext.image_sizes[key]?.alt ?? "";
|
|
2365
2300
|
return alt.trim().length > 0;
|
|
2366
2301
|
}
|
|
2367
2302
|
return (media.alt ?? "").trim().length > 0;
|
|
@@ -2371,22 +2306,23 @@ function isImageSourcePresent(media) {
|
|
|
2371
2306
|
}
|
|
2372
2307
|
|
|
2373
2308
|
// src/audits/images-alt-text.ts
|
|
2374
|
-
var
|
|
2309
|
+
var audit11 = {
|
|
2375
2310
|
id: "audits/images-alt-text",
|
|
2376
|
-
title:
|
|
2377
|
-
description:
|
|
2378
|
-
fixHint:
|
|
2311
|
+
title: __29("Images alt text", "elementor"),
|
|
2312
|
+
description: __29("Every image needs a meaningful alt attribute for screen readers and image-search.", "elementor"),
|
|
2313
|
+
fixHint: __29("Open the image's settings and add an Alt Text describing the image.", "elementor"),
|
|
2379
2314
|
categories: ["seo", "accessibility"],
|
|
2380
2315
|
severity: "error",
|
|
2381
2316
|
weight: 10,
|
|
2382
2317
|
evaluate: (ctx) => {
|
|
2383
|
-
if (!
|
|
2384
|
-
return { status: "skipped", reason:
|
|
2318
|
+
if (!hasAltTextImages(ctx.elements.tree)) {
|
|
2319
|
+
return { status: "skipped", reason: __29("No images", "elementor") };
|
|
2385
2320
|
}
|
|
2321
|
+
const isReady = ctx.pageContext.ally_plugin_active;
|
|
2386
2322
|
const violations = [];
|
|
2387
2323
|
const failedWidgetIds = /* @__PURE__ */ new Set();
|
|
2388
2324
|
let missingAltImageCount = 0;
|
|
2389
|
-
|
|
2325
|
+
walkAltTextImageSources(ctx.elements.tree, ({ node, media }) => {
|
|
2390
2326
|
if (!isImageSourcePresent(media) || hasMeaningfulAlt(media, ctx.pageContext)) {
|
|
2391
2327
|
return;
|
|
2392
2328
|
}
|
|
@@ -2394,11 +2330,12 @@ var audit9 = {
|
|
|
2394
2330
|
if (!failedWidgetIds.has(node.id)) {
|
|
2395
2331
|
failedWidgetIds.add(node.id);
|
|
2396
2332
|
violations.push({
|
|
2397
|
-
auditId:
|
|
2333
|
+
auditId: audit11.id,
|
|
2398
2334
|
elementId: node.id,
|
|
2399
2335
|
targetHint: "element-settings",
|
|
2400
|
-
label:
|
|
2401
|
-
externalUrl: ctx.pageContext.ally_plugin_url
|
|
2336
|
+
label: __29("Image is missing alt text.", "elementor"),
|
|
2337
|
+
externalUrl: isReady ? ctx.pageContext.ally_scan_url : ctx.pageContext.ally_plugin_url,
|
|
2338
|
+
ctaLabel: __29("Fix with Ally", "elementor")
|
|
2402
2339
|
});
|
|
2403
2340
|
}
|
|
2404
2341
|
});
|
|
@@ -2406,30 +2343,79 @@ var audit9 = {
|
|
|
2406
2343
|
}
|
|
2407
2344
|
};
|
|
2408
2345
|
|
|
2346
|
+
// src/audits/images-inefficient-format.ts
|
|
2347
|
+
import { __ as __30 } from "@wordpress/i18n";
|
|
2348
|
+
var LEGACY_RASTER_MIME_TYPES = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/gif", "image/bmp", "image/tiff"]);
|
|
2349
|
+
var audit12 = {
|
|
2350
|
+
id: "audits/images-inefficient-format",
|
|
2351
|
+
title: __30("Inefficient image format", "elementor"),
|
|
2352
|
+
description: __30("Image isn't served in a modern, efficient format like WebP or AVIF.", "elementor"),
|
|
2353
|
+
fixHint: __30("Convert the image to a modern format like WebP or AVIF, or enable image optimization.", "elementor"),
|
|
2354
|
+
categories: ["performance"],
|
|
2355
|
+
severity: "info",
|
|
2356
|
+
weight: 1,
|
|
2357
|
+
evaluate: (ctx) => {
|
|
2358
|
+
const isReady = ctx.pageContext.image_optimization_plugin_active;
|
|
2359
|
+
const offendingElementIds = /* @__PURE__ */ new Set();
|
|
2360
|
+
let hasAnyImage = false;
|
|
2361
|
+
let inefficientImageFormatCount = 0;
|
|
2362
|
+
const evaluateSource = (node, media) => {
|
|
2363
|
+
if (media.id || media.url) {
|
|
2364
|
+
hasAnyImage = true;
|
|
2365
|
+
}
|
|
2366
|
+
const id = media.id;
|
|
2367
|
+
if (!id) {
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
const mime = ctx.pageContext.image_sizes[buildImageSizeKey({ id, size: media.size })]?.mime;
|
|
2371
|
+
if (!mime || !LEGACY_RASTER_MIME_TYPES.has(mime)) {
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
inefficientImageFormatCount++;
|
|
2375
|
+
offendingElementIds.add(node.id);
|
|
2376
|
+
};
|
|
2377
|
+
walkAllImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2378
|
+
if (!hasAnyImage) {
|
|
2379
|
+
return { status: "skipped", reason: __30("No images", "elementor") };
|
|
2380
|
+
}
|
|
2381
|
+
const violations = Array.from(offendingElementIds).map((elementId) => ({
|
|
2382
|
+
auditId: audit12.id,
|
|
2383
|
+
elementId,
|
|
2384
|
+
targetHint: "element-settings",
|
|
2385
|
+
label: __30("Image isn't served in a modern format like WebP or AVIF.", "elementor"),
|
|
2386
|
+
externalUrl: isReady ? ctx.pageContext.image_optimization_settings_url : ctx.pageContext.image_optimization_plugin_url,
|
|
2387
|
+
ctaLabel: __30("Optimize all", "elementor")
|
|
2388
|
+
}));
|
|
2389
|
+
return violations.length === 0 ? { status: "pass" } : { status: "fail", violations, metadata: { inefficientImageFormatCount } };
|
|
2390
|
+
}
|
|
2391
|
+
};
|
|
2392
|
+
|
|
2409
2393
|
// src/audits/images-too-large.ts
|
|
2410
|
-
import { __ as
|
|
2394
|
+
import { __ as __31, sprintf as sprintf3 } from "@wordpress/i18n";
|
|
2411
2395
|
var SIZE_THRESHOLD_BYTES = 500 * 1024;
|
|
2412
2396
|
var BYTES_PER_KB = 1024;
|
|
2413
|
-
var
|
|
2397
|
+
var audit13 = {
|
|
2414
2398
|
id: "audits/images-too-large",
|
|
2415
|
-
title:
|
|
2416
|
-
description:
|
|
2417
|
-
fixHint:
|
|
2399
|
+
title: __31("Oversized images", "elementor"),
|
|
2400
|
+
description: __31("Large image files slow down the page.", "elementor"),
|
|
2401
|
+
fixHint: __31("Replace the image with a smaller version or enable image optimization.", "elementor"),
|
|
2418
2402
|
categories: ["performance"],
|
|
2419
2403
|
severity: "warning",
|
|
2420
2404
|
weight: 7,
|
|
2421
2405
|
evaluate: (ctx) => {
|
|
2422
|
-
|
|
2423
|
-
return { status: "skipped", reason: __34("No images", "elementor") };
|
|
2424
|
-
}
|
|
2406
|
+
const isReady = ctx.pageContext.image_optimization_plugin_active;
|
|
2425
2407
|
const widgetMaxKb = /* @__PURE__ */ new Map();
|
|
2426
2408
|
let oversizedImageCount = 0;
|
|
2427
|
-
|
|
2409
|
+
let hasAnyImage = false;
|
|
2410
|
+
const evaluateSource = (node, media) => {
|
|
2411
|
+
if (media.id || media.url) {
|
|
2412
|
+
hasAnyImage = true;
|
|
2413
|
+
}
|
|
2428
2414
|
const id = media.id;
|
|
2429
2415
|
if (!id) {
|
|
2430
2416
|
return;
|
|
2431
2417
|
}
|
|
2432
|
-
const size = ctx.pageContext.image_sizes[id];
|
|
2418
|
+
const size = ctx.pageContext.image_sizes[buildImageSizeKey({ id, size: media.size })];
|
|
2433
2419
|
if (!size || size.filesize_bytes <= SIZE_THRESHOLD_BYTES) {
|
|
2434
2420
|
return;
|
|
2435
2421
|
}
|
|
@@ -2437,38 +2423,43 @@ var audit10 = {
|
|
|
2437
2423
|
const kb = Math.round(size.filesize_bytes / BYTES_PER_KB);
|
|
2438
2424
|
const currentMax = widgetMaxKb.get(node.id) ?? 0;
|
|
2439
2425
|
widgetMaxKb.set(node.id, Math.max(currentMax, kb));
|
|
2440
|
-
}
|
|
2426
|
+
};
|
|
2427
|
+
walkAllImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2428
|
+
if (!hasAnyImage) {
|
|
2429
|
+
return { status: "skipped", reason: __31("No images", "elementor") };
|
|
2430
|
+
}
|
|
2441
2431
|
const violations = Array.from(widgetMaxKb.entries()).map(([elementId, kb]) => ({
|
|
2442
|
-
auditId:
|
|
2432
|
+
auditId: audit13.id,
|
|
2443
2433
|
elementId,
|
|
2444
2434
|
targetHint: "element-settings",
|
|
2445
|
-
label:
|
|
2435
|
+
label: sprintf3(
|
|
2446
2436
|
/* translators: %d is the image file size in kilobytes. */
|
|
2447
|
-
|
|
2437
|
+
__31("Image is %d KB (over 500 KB).", "elementor"),
|
|
2448
2438
|
kb
|
|
2449
2439
|
),
|
|
2450
|
-
externalUrl: ctx.pageContext.image_optimization_plugin_url
|
|
2440
|
+
externalUrl: isReady ? ctx.pageContext.image_optimization_settings_url : ctx.pageContext.image_optimization_plugin_url,
|
|
2441
|
+
ctaLabel: __31("Optimize all", "elementor")
|
|
2451
2442
|
}));
|
|
2452
2443
|
return violations.length === 0 ? { status: "pass" } : { status: "fail", violations, metadata: { oversizedImageCount } };
|
|
2453
2444
|
}
|
|
2454
2445
|
};
|
|
2455
2446
|
|
|
2456
2447
|
// src/audits/nested-boxed-containers.ts
|
|
2457
|
-
import { __ as
|
|
2448
|
+
import { __ as __32 } from "@wordpress/i18n";
|
|
2458
2449
|
function isBoxed(settings) {
|
|
2459
2450
|
return settings.content_width === "boxed";
|
|
2460
2451
|
}
|
|
2461
|
-
var
|
|
2452
|
+
var audit14 = {
|
|
2462
2453
|
id: "audits/nested-boxed-containers",
|
|
2463
|
-
title:
|
|
2464
|
-
description:
|
|
2465
|
-
fixHint:
|
|
2454
|
+
title: __32("Boxed container nested inside a boxed parent", "elementor"),
|
|
2455
|
+
description: __32("An inner container does not need to be boxed when its parent already is.", "elementor"),
|
|
2456
|
+
fixHint: __32("Change the inner container's content width to Full Width.", "elementor"),
|
|
2466
2457
|
categories: ["best-practices", "performance"],
|
|
2467
2458
|
severity: "info",
|
|
2468
2459
|
weight: 5,
|
|
2469
2460
|
evaluate: (ctx) => {
|
|
2470
2461
|
if (ctx.elements.tree.length === 0) {
|
|
2471
|
-
return { status: "skipped", reason:
|
|
2462
|
+
return { status: "skipped", reason: __32("No elements", "elementor") };
|
|
2472
2463
|
}
|
|
2473
2464
|
const violations = [];
|
|
2474
2465
|
walkElements(ctx.elements.tree, (node, parents) => {
|
|
@@ -2478,10 +2469,15 @@ var audit11 = {
|
|
|
2478
2469
|
const nearestContainerAncestor = [...parents].reverse().find((p) => p.elType === "container");
|
|
2479
2470
|
if (nearestContainerAncestor && isBoxed(nearestContainerAncestor.settings)) {
|
|
2480
2471
|
violations.push({
|
|
2481
|
-
auditId:
|
|
2472
|
+
auditId: audit14.id,
|
|
2482
2473
|
elementId: node.id,
|
|
2483
2474
|
targetHint: "element-settings",
|
|
2484
|
-
label:
|
|
2475
|
+
label: __32("Nested boxed container.", "elementor"),
|
|
2476
|
+
angieFix: true,
|
|
2477
|
+
angiePrompt: __32(
|
|
2478
|
+
"Find containers that have nested containers. Containers can be deep-nested. Update the nested container styling so that when a parent container already uses a boxed setting, any inner container inside it is set to Full Width. Keep the first parent container boxed, remove all boxed styling from the nested inner containers, and preserve the inner container\u2019s content, spacing, alignment, and hierarchy.",
|
|
2479
|
+
"elementor"
|
|
2480
|
+
)
|
|
2485
2481
|
});
|
|
2486
2482
|
}
|
|
2487
2483
|
});
|
|
@@ -2490,12 +2486,12 @@ var audit11 = {
|
|
|
2490
2486
|
};
|
|
2491
2487
|
|
|
2492
2488
|
// src/audits/page-excerpt.ts
|
|
2493
|
-
import { __ as
|
|
2494
|
-
var
|
|
2489
|
+
import { __ as __33 } from "@wordpress/i18n";
|
|
2490
|
+
var audit15 = {
|
|
2495
2491
|
id: "audits/page-excerpt",
|
|
2496
|
-
title:
|
|
2497
|
-
description:
|
|
2498
|
-
fixHint:
|
|
2492
|
+
title: __33("Page excerpt", "elementor"),
|
|
2493
|
+
description: __33("A descriptive excerpt helps search engines and previews summarize the page.", "elementor"),
|
|
2494
|
+
fixHint: __33("Open Page Settings and write a short excerpt.", "elementor"),
|
|
2499
2495
|
categories: ["seo"],
|
|
2500
2496
|
severity: "warning",
|
|
2501
2497
|
weight: 5,
|
|
@@ -2507,8 +2503,8 @@ var audit12 = {
|
|
|
2507
2503
|
status: "fail",
|
|
2508
2504
|
violations: [
|
|
2509
2505
|
{
|
|
2510
|
-
auditId:
|
|
2511
|
-
label:
|
|
2506
|
+
auditId: audit15.id,
|
|
2507
|
+
label: __33("Page has no excerpt.", "elementor"),
|
|
2512
2508
|
targetHint: "page-settings",
|
|
2513
2509
|
angieFix: true
|
|
2514
2510
|
}
|
|
@@ -2518,12 +2514,12 @@ var audit12 = {
|
|
|
2518
2514
|
};
|
|
2519
2515
|
|
|
2520
2516
|
// src/audits/page-featured-image.ts
|
|
2521
|
-
import { __ as
|
|
2522
|
-
var
|
|
2517
|
+
import { __ as __34 } from "@wordpress/i18n";
|
|
2518
|
+
var audit16 = {
|
|
2523
2519
|
id: "audits/page-featured-image",
|
|
2524
|
-
title:
|
|
2525
|
-
description:
|
|
2526
|
-
fixHint:
|
|
2520
|
+
title: __34("Page featured image", "elementor"),
|
|
2521
|
+
description: __34("Featured images are used by social shares and many themes for hero visuals.", "elementor"),
|
|
2522
|
+
fixHint: __34("Open Page Settings and set a featured image.", "elementor"),
|
|
2527
2523
|
categories: ["seo"],
|
|
2528
2524
|
severity: "info",
|
|
2529
2525
|
weight: 5,
|
|
@@ -2535,8 +2531,8 @@ var audit13 = {
|
|
|
2535
2531
|
status: "fail",
|
|
2536
2532
|
violations: [
|
|
2537
2533
|
{
|
|
2538
|
-
auditId:
|
|
2539
|
-
label:
|
|
2534
|
+
auditId: audit16.id,
|
|
2535
|
+
label: __34("No featured image set.", "elementor"),
|
|
2540
2536
|
targetHint: "page-settings"
|
|
2541
2537
|
}
|
|
2542
2538
|
]
|
|
@@ -2545,13 +2541,13 @@ var audit13 = {
|
|
|
2545
2541
|
};
|
|
2546
2542
|
|
|
2547
2543
|
// src/audits/page-title.ts
|
|
2548
|
-
import { __ as
|
|
2544
|
+
import { __ as __35 } from "@wordpress/i18n";
|
|
2549
2545
|
var MAX_TITLE_LENGTH = 60;
|
|
2550
|
-
var
|
|
2546
|
+
var audit17 = {
|
|
2551
2547
|
id: "audits/page-title",
|
|
2552
|
-
title:
|
|
2553
|
-
description:
|
|
2554
|
-
fixHint:
|
|
2548
|
+
title: __35("Page title", "elementor"),
|
|
2549
|
+
description: __35("Pages need a clear title for SEO and screen-reader navigation.", "elementor"),
|
|
2550
|
+
fixHint: __35("Open Page Settings and add a title.", "elementor"),
|
|
2555
2551
|
categories: ["seo"],
|
|
2556
2552
|
severity: "error",
|
|
2557
2553
|
weight: 10,
|
|
@@ -2562,11 +2558,11 @@ var audit14 = {
|
|
|
2562
2558
|
status: "fail",
|
|
2563
2559
|
violations: [
|
|
2564
2560
|
{
|
|
2565
|
-
auditId:
|
|
2566
|
-
label:
|
|
2561
|
+
auditId: audit17.id,
|
|
2562
|
+
label: __35("Page has no title.", "elementor"),
|
|
2567
2563
|
targetHint: "page-settings",
|
|
2568
2564
|
angieFix: true,
|
|
2569
|
-
angiePrompt:
|
|
2565
|
+
angiePrompt: __35(
|
|
2570
2566
|
"Based on this page's contents, generate a title for this page.",
|
|
2571
2567
|
"elementor"
|
|
2572
2568
|
)
|
|
@@ -2579,8 +2575,8 @@ var audit14 = {
|
|
|
2579
2575
|
status: "fail",
|
|
2580
2576
|
violations: [
|
|
2581
2577
|
{
|
|
2582
|
-
auditId:
|
|
2583
|
-
label:
|
|
2578
|
+
auditId: audit17.id,
|
|
2579
|
+
label: __35("Page title is too long.", "elementor"),
|
|
2584
2580
|
targetHint: "page-settings",
|
|
2585
2581
|
angieFix: true
|
|
2586
2582
|
}
|
|
@@ -2592,7 +2588,7 @@ var audit14 = {
|
|
|
2592
2588
|
};
|
|
2593
2589
|
|
|
2594
2590
|
// src/audits/prefer-global-colors.ts
|
|
2595
|
-
import { __ as
|
|
2591
|
+
import { __ as __36, sprintf as sprintf4 } from "@wordpress/i18n";
|
|
2596
2592
|
|
|
2597
2593
|
// src/utils/collect-hardcoded-colors.ts
|
|
2598
2594
|
var RESERVED_SETTING_KEYS = /* @__PURE__ */ new Set(["__globals__", "__dynamic__"]);
|
|
@@ -2658,20 +2654,20 @@ function findMatchingGlobalByValue(value, globals) {
|
|
|
2658
2654
|
}
|
|
2659
2655
|
|
|
2660
2656
|
// src/audits/prefer-global-colors.ts
|
|
2661
|
-
var
|
|
2657
|
+
var audit18 = {
|
|
2662
2658
|
id: "audits/prefer-global-colors",
|
|
2663
|
-
title:
|
|
2664
|
-
description:
|
|
2665
|
-
fixHint:
|
|
2659
|
+
title: __36("Prefer global colors", "elementor"),
|
|
2660
|
+
description: __36("Global colors make the design consistent and easy to update site-wide.", "elementor"),
|
|
2661
|
+
fixHint: __36("Replace the hard-coded value with the matching global color.", "elementor"),
|
|
2666
2662
|
categories: ["best-practices"],
|
|
2667
2663
|
severity: "info",
|
|
2668
2664
|
weight: 3,
|
|
2669
2665
|
evaluate: (ctx) => {
|
|
2670
2666
|
if (ctx.elements.tree.length === 0) {
|
|
2671
|
-
return { status: "skipped", reason:
|
|
2667
|
+
return { status: "skipped", reason: __36("No elements", "elementor") };
|
|
2672
2668
|
}
|
|
2673
2669
|
if (ctx.kit.globals.colors.length === 0) {
|
|
2674
|
-
return { status: "skipped", reason:
|
|
2670
|
+
return { status: "skipped", reason: __36("No global colors", "elementor") };
|
|
2675
2671
|
}
|
|
2676
2672
|
const violations = [];
|
|
2677
2673
|
walkElements(ctx.elements.tree, (node) => {
|
|
@@ -2681,13 +2677,13 @@ var audit15 = {
|
|
|
2681
2677
|
continue;
|
|
2682
2678
|
}
|
|
2683
2679
|
violations.push({
|
|
2684
|
-
auditId:
|
|
2680
|
+
auditId: audit18.id,
|
|
2685
2681
|
elementId: node.id,
|
|
2686
2682
|
targetHint: "element-settings",
|
|
2687
2683
|
angieFix: true,
|
|
2688
|
-
label:
|
|
2684
|
+
label: sprintf4(
|
|
2689
2685
|
/* translators: 1: hard-coded color value, 2: global color title. */
|
|
2690
|
-
|
|
2686
|
+
__36('replace "%1$s" with "%2$s" global color', "elementor"),
|
|
2691
2687
|
value,
|
|
2692
2688
|
global.title
|
|
2693
2689
|
)
|
|
@@ -2699,7 +2695,7 @@ var audit15 = {
|
|
|
2699
2695
|
};
|
|
2700
2696
|
|
|
2701
2697
|
// src/audits/prefer-global-fonts.ts
|
|
2702
|
-
import { __ as
|
|
2698
|
+
import { __ as __37, sprintf as sprintf5 } from "@wordpress/i18n";
|
|
2703
2699
|
|
|
2704
2700
|
// src/utils/collect-hardcoded-fonts.ts
|
|
2705
2701
|
var RESERVED_SETTING_KEYS2 = /* @__PURE__ */ new Set(["__globals__", "__dynamic__"]);
|
|
@@ -2757,20 +2753,20 @@ function collectHardcodedFonts(settings, pathPrefix = "") {
|
|
|
2757
2753
|
}
|
|
2758
2754
|
|
|
2759
2755
|
// src/audits/prefer-global-fonts.ts
|
|
2760
|
-
var
|
|
2756
|
+
var audit19 = {
|
|
2761
2757
|
id: "audits/prefer-global-fonts",
|
|
2762
|
-
title:
|
|
2763
|
-
description:
|
|
2764
|
-
fixHint:
|
|
2758
|
+
title: __37("Prefer global fonts", "elementor"),
|
|
2759
|
+
description: __37("Global fonts make the design consistent and easy to update site-wide.", "elementor"),
|
|
2760
|
+
fixHint: __37("Replace the hard-coded value with the matching global font.", "elementor"),
|
|
2765
2761
|
categories: ["best-practices", "performance"],
|
|
2766
2762
|
severity: "info",
|
|
2767
2763
|
weight: 3,
|
|
2768
2764
|
evaluate: (ctx) => {
|
|
2769
2765
|
if (ctx.elements.tree.length === 0) {
|
|
2770
|
-
return { status: "skipped", reason:
|
|
2766
|
+
return { status: "skipped", reason: __37("No elements", "elementor") };
|
|
2771
2767
|
}
|
|
2772
2768
|
if (ctx.kit.globals.fonts.length === 0) {
|
|
2773
|
-
return { status: "skipped", reason:
|
|
2769
|
+
return { status: "skipped", reason: __37("No global fonts", "elementor") };
|
|
2774
2770
|
}
|
|
2775
2771
|
const violations = [];
|
|
2776
2772
|
walkElements(ctx.elements.tree, (node) => {
|
|
@@ -2780,12 +2776,12 @@ var audit16 = {
|
|
|
2780
2776
|
continue;
|
|
2781
2777
|
}
|
|
2782
2778
|
violations.push({
|
|
2783
|
-
auditId:
|
|
2779
|
+
auditId: audit19.id,
|
|
2784
2780
|
elementId: node.id,
|
|
2785
2781
|
targetHint: "element-settings",
|
|
2786
|
-
label:
|
|
2782
|
+
label: sprintf5(
|
|
2787
2783
|
/* translators: %s: global font title. */
|
|
2788
|
-
|
|
2784
|
+
__37('replace hardcoded typography with "%s" global font', "elementor"),
|
|
2789
2785
|
global.title
|
|
2790
2786
|
)
|
|
2791
2787
|
});
|
|
@@ -2796,15 +2792,15 @@ var audit16 = {
|
|
|
2796
2792
|
};
|
|
2797
2793
|
|
|
2798
2794
|
// src/audits/privacy-policy.ts
|
|
2799
|
-
import { __ as
|
|
2800
|
-
var
|
|
2795
|
+
import { __ as __38 } from "@wordpress/i18n";
|
|
2796
|
+
var audit20 = {
|
|
2801
2797
|
id: "audits/privacy-policy",
|
|
2802
|
-
title:
|
|
2803
|
-
description:
|
|
2798
|
+
title: __38("Privacy policy", "elementor"),
|
|
2799
|
+
description: __38(
|
|
2804
2800
|
"A privacy policy page is required by privacy regulations such as GDPR (EU) and CCPA (US).",
|
|
2805
2801
|
"elementor"
|
|
2806
2802
|
),
|
|
2807
|
-
fixHint:
|
|
2803
|
+
fixHint: __38(
|
|
2808
2804
|
"Go to Settings > Privacy in the WordPress admin and assign a published privacy policy page.",
|
|
2809
2805
|
"elementor"
|
|
2810
2806
|
),
|
|
@@ -2819,10 +2815,10 @@ var audit17 = {
|
|
|
2819
2815
|
status: "fail",
|
|
2820
2816
|
violations: [
|
|
2821
2817
|
{
|
|
2822
|
-
auditId:
|
|
2823
|
-
label:
|
|
2818
|
+
auditId: audit20.id,
|
|
2819
|
+
label: __38("No privacy policy page is set.", "elementor"),
|
|
2824
2820
|
externalUrl: ctx.pageContext.privacy_settings_url,
|
|
2825
|
-
ctaLabel:
|
|
2821
|
+
ctaLabel: __38("Create", "elementor")
|
|
2826
2822
|
}
|
|
2827
2823
|
]
|
|
2828
2824
|
};
|
|
@@ -2830,15 +2826,15 @@ var audit17 = {
|
|
|
2830
2826
|
};
|
|
2831
2827
|
|
|
2832
2828
|
// src/audits/robots-noindex.ts
|
|
2833
|
-
import { __ as
|
|
2834
|
-
var
|
|
2829
|
+
import { __ as __39 } from "@wordpress/i18n";
|
|
2830
|
+
var audit21 = {
|
|
2835
2831
|
id: "audits/robots-noindex",
|
|
2836
|
-
title:
|
|
2837
|
-
description:
|
|
2832
|
+
title: __39("Search engine visibility", "elementor"),
|
|
2833
|
+
description: __39(
|
|
2838
2834
|
"When search engine visibility is checked in WordPress Settings -> Reading -> Search Engine Visibility, search engines are discouraged from indexing the website.",
|
|
2839
2835
|
"elementor"
|
|
2840
2836
|
),
|
|
2841
|
-
fixHint:
|
|
2837
|
+
fixHint: __39(
|
|
2842
2838
|
'Go to Settings \u2192 Reading in the WordPress admin and uncheck "Discourage search engines from indexing this site" when the website should be indexed.',
|
|
2843
2839
|
"elementor"
|
|
2844
2840
|
),
|
|
@@ -2853,8 +2849,8 @@ var audit18 = {
|
|
|
2853
2849
|
status: "fail",
|
|
2854
2850
|
violations: [
|
|
2855
2851
|
{
|
|
2856
|
-
auditId:
|
|
2857
|
-
label:
|
|
2852
|
+
auditId: audit21.id,
|
|
2853
|
+
label: __39("Search engines are discouraged from indexing this website.", "elementor"),
|
|
2858
2854
|
externalUrl: ctx.pageContext.reading_settings_url
|
|
2859
2855
|
}
|
|
2860
2856
|
]
|
|
@@ -2863,15 +2859,15 @@ var audit18 = {
|
|
|
2863
2859
|
};
|
|
2864
2860
|
|
|
2865
2861
|
// src/audits/scan-for-cookies.ts
|
|
2866
|
-
import { __ as
|
|
2867
|
-
var
|
|
2862
|
+
import { __ as __40 } from "@wordpress/i18n";
|
|
2863
|
+
var audit22 = {
|
|
2868
2864
|
id: "audits/scan-for-cookies",
|
|
2869
|
-
title:
|
|
2870
|
-
description:
|
|
2865
|
+
title: __40("Scan for cookies", "elementor"),
|
|
2866
|
+
description: __40(
|
|
2871
2867
|
"Your site may be setting cookies you haven't disclosed. Some countries require a banner even without a full consent policy. Scan to see what needs disclosure.",
|
|
2872
2868
|
"elementor"
|
|
2873
2869
|
),
|
|
2874
|
-
fixHint:
|
|
2870
|
+
fixHint: __40("Run a Cookiez scan on this page to see which cookies need disclosure.", "elementor"),
|
|
2875
2871
|
categories: ["compliance"],
|
|
2876
2872
|
severity: "info",
|
|
2877
2873
|
weight: 0,
|
|
@@ -2881,8 +2877,8 @@ var audit19 = {
|
|
|
2881
2877
|
status: "fail",
|
|
2882
2878
|
violations: [
|
|
2883
2879
|
{
|
|
2884
|
-
auditId:
|
|
2885
|
-
label:
|
|
2880
|
+
auditId: audit22.id,
|
|
2881
|
+
label: __40("This page has not been scanned for cookies yet.", "elementor"),
|
|
2886
2882
|
externalUrl: isReady ? ctx.pageContext.cookiez_scan_url : ctx.pageContext.cookiez_plugin_action_url
|
|
2887
2883
|
}
|
|
2888
2884
|
]
|
|
@@ -2891,29 +2887,29 @@ var audit19 = {
|
|
|
2891
2887
|
};
|
|
2892
2888
|
|
|
2893
2889
|
// src/audits/sections-and-columns.ts
|
|
2894
|
-
import { __ as
|
|
2895
|
-
var
|
|
2890
|
+
import { __ as __41 } from "@wordpress/i18n";
|
|
2891
|
+
var audit23 = {
|
|
2896
2892
|
id: "audits/sections-and-columns",
|
|
2897
|
-
title:
|
|
2898
|
-
description:
|
|
2893
|
+
title: __41("Sections and columns", "elementor"),
|
|
2894
|
+
description: __41(
|
|
2899
2895
|
"Sections and columns are legacy elements. Containers render fewer DOM nodes and are more flexible.",
|
|
2900
2896
|
"elementor"
|
|
2901
2897
|
),
|
|
2902
|
-
fixHint:
|
|
2898
|
+
fixHint: __41("Use the Container Converter to replace each section/column with a container.", "elementor"),
|
|
2903
2899
|
categories: ["best-practices", "performance"],
|
|
2904
2900
|
severity: "warning",
|
|
2905
2901
|
weight: 7,
|
|
2906
2902
|
evaluate: (ctx) => {
|
|
2907
2903
|
if (ctx.elements.tree.length === 0) {
|
|
2908
|
-
return { status: "skipped", reason:
|
|
2904
|
+
return { status: "skipped", reason: __41("No elements", "elementor") };
|
|
2909
2905
|
}
|
|
2910
2906
|
const violations = [];
|
|
2911
2907
|
walkElements(ctx.elements.tree, (node) => {
|
|
2912
2908
|
if (node.elType === "section" || node.elType === "column") {
|
|
2913
2909
|
violations.push({
|
|
2914
|
-
auditId:
|
|
2910
|
+
auditId: audit23.id,
|
|
2915
2911
|
elementId: node.id,
|
|
2916
|
-
label: node.elType === "section" ?
|
|
2912
|
+
label: node.elType === "section" ? __41("Section element", "elementor") : __41("Column element", "elementor")
|
|
2917
2913
|
});
|
|
2918
2914
|
}
|
|
2919
2915
|
});
|
|
@@ -2922,15 +2918,15 @@ var audit20 = {
|
|
|
2922
2918
|
};
|
|
2923
2919
|
|
|
2924
2920
|
// src/audits/site-identity.ts
|
|
2925
|
-
import { __ as
|
|
2926
|
-
var
|
|
2921
|
+
import { __ as __42 } from "@wordpress/i18n";
|
|
2922
|
+
var audit24 = {
|
|
2927
2923
|
id: "audits/site-identity",
|
|
2928
|
-
title:
|
|
2929
|
-
description:
|
|
2924
|
+
title: __42("Site identity", "elementor"),
|
|
2925
|
+
description: __42(
|
|
2930
2926
|
"Site name, description, logo, and favicon establish your brand and appear in search results and browser tabs.",
|
|
2931
2927
|
"elementor"
|
|
2932
2928
|
),
|
|
2933
|
-
fixHint:
|
|
2929
|
+
fixHint: __42("Open Site Settings \u2192 Site Identity and complete all the missing fields.", "elementor"),
|
|
2934
2930
|
categories: ["best-practices", "seo"],
|
|
2935
2931
|
severity: "info",
|
|
2936
2932
|
weight: 7,
|
|
@@ -2939,30 +2935,30 @@ var audit21 = {
|
|
|
2939
2935
|
const violations = [];
|
|
2940
2936
|
if (!identity.site_name_set) {
|
|
2941
2937
|
violations.push({
|
|
2942
|
-
auditId:
|
|
2943
|
-
label:
|
|
2938
|
+
auditId: audit24.id,
|
|
2939
|
+
label: __42("Site name is missing or still uses the default.", "elementor"),
|
|
2944
2940
|
targetHint: "site-identity-settings"
|
|
2945
2941
|
});
|
|
2946
2942
|
}
|
|
2947
2943
|
if (!identity.site_description_set) {
|
|
2948
2944
|
violations.push({
|
|
2949
|
-
auditId:
|
|
2950
|
-
label:
|
|
2945
|
+
auditId: audit24.id,
|
|
2946
|
+
label: __42("Site description is missing or still uses the default.", "elementor"),
|
|
2951
2947
|
targetHint: "site-identity-settings",
|
|
2952
2948
|
angieFix: true
|
|
2953
2949
|
});
|
|
2954
2950
|
}
|
|
2955
2951
|
if (!identity.site_logo_set) {
|
|
2956
2952
|
violations.push({
|
|
2957
|
-
auditId:
|
|
2958
|
-
label:
|
|
2953
|
+
auditId: audit24.id,
|
|
2954
|
+
label: __42("Site logo is not set.", "elementor"),
|
|
2959
2955
|
targetHint: "site-identity-settings"
|
|
2960
2956
|
});
|
|
2961
2957
|
}
|
|
2962
2958
|
if (!identity.site_favicon_set) {
|
|
2963
2959
|
violations.push({
|
|
2964
|
-
auditId:
|
|
2965
|
-
label:
|
|
2960
|
+
auditId: audit24.id,
|
|
2961
|
+
label: __42("Site favicon is not set.", "elementor"),
|
|
2966
2962
|
targetHint: "site-identity-settings"
|
|
2967
2963
|
});
|
|
2968
2964
|
}
|
|
@@ -2976,87 +2972,58 @@ var audit21 = {
|
|
|
2976
2972
|
}
|
|
2977
2973
|
};
|
|
2978
2974
|
|
|
2979
|
-
// src/audits/too-many-widgets.ts
|
|
2980
|
-
import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
|
|
2981
|
-
import { __ as __46 } from "@wordpress/i18n";
|
|
2982
|
-
var WIDGET_COUNT_THRESHOLD = 100;
|
|
2983
|
-
function isCountableWidget(node, widgetsCache) {
|
|
2984
|
-
if (node.elType === "widget") {
|
|
2985
|
-
return true;
|
|
2986
|
-
}
|
|
2987
|
-
return !!widgetsCache?.[node.elType]?.meta?.is_compound;
|
|
2988
|
-
}
|
|
2989
|
-
var audit22 = {
|
|
2990
|
-
id: "audits/too-many-widgets",
|
|
2991
|
-
title: __46("Too many widgets", "elementor"),
|
|
2992
|
-
description: __46("Excessive DOM size caused by too many widgets degrades rendering performance.", "elementor"),
|
|
2993
|
-
fixHint: __46("Reduce the number of widgets on the page by removing or combining elements.", "elementor"),
|
|
2994
|
-
categories: ["best-practices", "performance"],
|
|
2995
|
-
severity: "warning",
|
|
2996
|
-
weight: 5,
|
|
2997
|
-
evaluate: (ctx) => {
|
|
2998
|
-
if (ctx.elements.tree.length === 0) {
|
|
2999
|
-
return { status: "skipped", reason: __46("No elements", "elementor") };
|
|
3000
|
-
}
|
|
3001
|
-
const widgetsCache = getWidgetsCache3();
|
|
3002
|
-
let widgetCount = 0;
|
|
3003
|
-
walkElements(ctx.elements.tree, (node) => {
|
|
3004
|
-
if (isCountableWidget(node, widgetsCache)) {
|
|
3005
|
-
widgetCount++;
|
|
3006
|
-
}
|
|
3007
|
-
});
|
|
3008
|
-
if (widgetCount <= WIDGET_COUNT_THRESHOLD) {
|
|
3009
|
-
return { status: "pass" };
|
|
3010
|
-
}
|
|
3011
|
-
return {
|
|
3012
|
-
status: "fail",
|
|
3013
|
-
violations: [
|
|
3014
|
-
{
|
|
3015
|
-
auditId: audit22.id,
|
|
3016
|
-
label: __46("Page has too many widgets.", "elementor")
|
|
3017
|
-
}
|
|
3018
|
-
]
|
|
3019
|
-
};
|
|
3020
|
-
}
|
|
3021
|
-
};
|
|
3022
|
-
|
|
3023
2975
|
// src/register-audits.ts
|
|
3024
2976
|
var AUDITS = [
|
|
3025
|
-
|
|
3026
|
-
audit12,
|
|
3027
|
-
audit13,
|
|
3028
|
-
audit8,
|
|
3029
|
-
audit5,
|
|
3030
|
-
audit22,
|
|
3031
|
-
audit20,
|
|
3032
|
-
audit3,
|
|
3033
|
-
audit11,
|
|
3034
|
-
audit4,
|
|
3035
|
-
audit21,
|
|
2977
|
+
audit17,
|
|
3036
2978
|
audit15,
|
|
3037
2979
|
audit16,
|
|
3038
|
-
audit7,
|
|
3039
|
-
audit9,
|
|
3040
2980
|
audit10,
|
|
2981
|
+
audit7,
|
|
2982
|
+
audit23,
|
|
2983
|
+
audit5,
|
|
2984
|
+
audit14,
|
|
2985
|
+
audit6,
|
|
2986
|
+
audit24,
|
|
3041
2987
|
audit18,
|
|
3042
|
-
|
|
2988
|
+
audit19,
|
|
2989
|
+
audit9,
|
|
2990
|
+
audit11,
|
|
2991
|
+
audit13,
|
|
2992
|
+
audit12,
|
|
2993
|
+
audit21,
|
|
2994
|
+
audit20,
|
|
3043
2995
|
audit,
|
|
3044
2996
|
audit2,
|
|
3045
|
-
|
|
3046
|
-
|
|
2997
|
+
audit3,
|
|
2998
|
+
audit4,
|
|
2999
|
+
audit22,
|
|
3000
|
+
audit8
|
|
3047
3001
|
];
|
|
3048
3002
|
function registerAllAudits() {
|
|
3049
|
-
for (const
|
|
3050
|
-
registerAudit(
|
|
3003
|
+
for (const audit25 of AUDITS) {
|
|
3004
|
+
registerAudit(audit25);
|
|
3051
3005
|
}
|
|
3052
3006
|
}
|
|
3053
3007
|
|
|
3008
|
+
// src/sync-report-staleness.ts
|
|
3009
|
+
import { __privateListenTo as listenTo, commandEndEvent } from "@elementor/editor-v1-adapters";
|
|
3010
|
+
import { __dispatch as dispatch } from "@elementor/store";
|
|
3011
|
+
function syncReportStaleness() {
|
|
3012
|
+
listenTo(commandEndEvent("document/save/set-is-modified"), (e) => {
|
|
3013
|
+
const event = e;
|
|
3014
|
+
if (event.args?.status) {
|
|
3015
|
+
dispatch(slice.actions.reportStale());
|
|
3016
|
+
}
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3054
3020
|
// src/init.ts
|
|
3055
3021
|
function init() {
|
|
3056
3022
|
registerSlice(slice);
|
|
3057
3023
|
registerAllAudits();
|
|
3058
3024
|
registerFloatingPanel(auditPanel.panel);
|
|
3059
3025
|
registerAppBarAuditsToggle();
|
|
3026
|
+
syncReportStaleness();
|
|
3060
3027
|
}
|
|
3061
3028
|
export {
|
|
3062
3029
|
init,
|