Purpose
Inspect Langere's commercial-property listing filter mechanism and extract structured HTML details from property cards, including the filtered Retail view.
When to Use
Use when a caller needs to discover available commercial-property type filters, apply one of them, or inspect/extract the listing cards shown on Langere's commercial-properties page.
Workflow
- Navigate directly to
https://langere.com/commercial-propertiesand wait for the page's listing JavaScript to finish rendering (about 4 seconds). - Run the following evaluator on the loaded page. It records the type-filter controls, applies the
Retailfilter through Langere's client-side control, waits briefly for the DOM visibility changes, and returns the visible Retail cards plus their HTML and links:
(async () => {
const text = (el) => (el?.textContent || "").replace(/\\s+/g, " ").trim();
const attrs = (el) =>
Object.fromEntries(
Array.from(el?.attributes || []).map((a) => [a.name, a.value]),
);
const filter = document.querySelector('ul[data-filter="type"]');
const options = Array.from(filter?.querySelectorAll("li a") || []).map((a) => ({
label: text(a),
href: a.href,
attributes: attrs(a),
liClass: a.parentElement?.className || "",
}));
const retail = options.find((o) => o.label.toLowerCase() === "retail");
if (retail) {
const retailAnchor = Array.from(filter.querySelectorAll("li a")).find(
(a) => text(a).toLowerCase() === "retail",
);
retailAnchor?.click();
await new Promise((resolve) => setTimeout(resolve, 1200));
}
const visible = (el) => {
let node = el;
while (node && node !== document.documentElement) {
const style = getComputedStyle(node);
if (
style.display === "none" ||
style.visibility === "hidden" ||
style.opacity === "0"
)
return false;
if (node.classList?.contains("hidden")) return false;
node = node.parentElement;
}
return true;
};
const cards = Array.from(document.querySelectorAll(".section-property"));
const retailCards = cards.filter(visible).map((card) => ({
html: card.outerHTML,
text: text(card),
attributes: attrs(card),
propertyLinks: Array.from(
card.querySelectorAll('a[href*="/commercial-property/"]'),
).map((a) => ({
href: a.href,
text: text(a),
attributes: attrs(a),
})),
}));
return {
filterSelector: 'ul[data-filter="type"]',
filterMode:
"client-side DOM filtering; the filter control does not expose a navigable URL in the observed page",
options,
requestedFilter: "Retail",
retailFilterFound: !!retail,
totalCards: cards.length,
visibleRetailCards: retailCards.length,
cards: retailCards,
};
})();Site-Specific Gotchas
- The type controls are under
ul[data-filter="type"]; locate the option by normalized anchor text rather than assuming an option index. Retailis applied by clicking the matching anchor and changing card visibility in the DOM. No filter URL or query parameter was exposed during inspection, so do not invent a direct Retail URL.- Property cards use the
.section-propertyclass, while property detail links contain/commercial-property/. Extract card containers rather than treating every matching anchor as a separate card. - Wait for the page JavaScript before querying cards or filters; an immediate query can run before the listing markup is available.
- The evaluator returns raw
outerHTML; treat class names and nested markup as site-specific and preserve the card-level link extraction for stable structured results.
Expected Output
An object containing the available commercial-property type options, whether the Retail filter was found, the total number of .section-property cards, the number visible after applying Retail, and each visible card's normalized text, attributes, raw HTML, and commercial-property detail links.