PageSourceSearch

https://dtolaw.com/wp-content/themes/dto/scripts/dto/news.js

js dtolaw.com collected 2026-10-06 11:03:05 UTC 13,101 bytes, 387 lines download raw bytes

1const defaultNewsTypeColors = {
2    All: "#003366",
3    Articles: "#4A5568",
4    "Client Wins": "#2D3748",
5    Community: "#1A365D",
6    DEI: "#718096",
7    News: "#2B6CB0",
8    Press: "#4C51BF",
9    Speaking: "#6B46C1",
10};
11
12const defaultNewsGroups = [
13    {
14        label: "Firm News and Recognition",
15        name: "firm-news-recognition",
16        value: ["News", "Press"],
17    },
18    {
19        label: "Client Success & Case Highlights",
20        name: "client-success-case-highlights",
21        value: ["Client Wins"],
22    },
23    {
24        label: "In the Community",
25        name: "in-the-community",
26        value: ["Community", "DEI"],
27    },
28    {
29        label: "Insights & Articles",
30        name: "insights-articles",
31        value: ["Articles", "Speaking"],
32    },
33];
34
35let newsTypeColors = defaultNewsTypeColors;
36let newsGroups = defaultNewsGroups;
37
38try {
39    if (document.querySelector("#news-type-colors"))
40        newsTypeColors = JSON.parse(
41            document.querySelector("#news-type-colors").textContent
42        );
43} catch (error) {
44    console.error("Error parsing news type colors:", error);
45}
46
47try {
48    if (document.querySelector("#news-groups"))
49        newsGroups = JSON.parse(
50            document.querySelector("#news-groups").textContent
51        );
52    if (Object.values(newsGroups).every((group) => group.value.length === 0))
53        newsGroups = defaultNewsGroups;
54} catch (error) {
55    console.error("Error parsing news groups:", error);
56}
57
58// ================================================================================================
59
60/**
61 * Set the color of the filter buttons (FacetWP has client code that we need to wait for).
62 */
63const setFilterColors = () => {
64    try {
65        const filters = document.querySelector(".facetwp-facet-news_types");
66        if (!filters) return;
67
68        for (const filter of filters.querySelectorAll(".facetwp-radio")) {
69            const filterKey =
70                filter.querySelector(".facetwp-display-value")?.textContent ||
71                "All";
72            filter.style.backgroundColor =
73                newsTypeColors[filterKey]?.color ||
74                Object.values(newsTypeColors).find(
75                    (obj) => typeof obj === "object" && obj.label === filterKey
76                )?.color ||
77                newsTypeColors.All;
78        }
79
80        const active = filters.querySelector(".checked");
81        if (!active) return;
82        active.style.fontWeight = "bolder";
83        active.style.textDecoration = "underline";
84    } catch (error) {
85        console.error("Error setting filter colors:", error);
86    }
87};
88
89const setBadgeColors = () => {
90    const badges = document.querySelectorAll("p.dto-news-type-badge");
91    for (const badge of badges)
92        badge.style.backgroundColor =
93            newsTypeColors[badge.textContent]?.color ||
94            Object.values(newsTypeColors).find(
95                (color) => color.label === badge.textContent
96            )?.color ||
97            newsTypeColors.All;
98};
99
100/**
101 * Groups news entries by type and displays them in sections.
102 * Watches for changes in the original list and regroups when needed.
103 * Doing this client-side is better for cost/time, but we may consider server-side in the future.
104 */
105const groupNewsEntries = () => {
106    if (!location.pathname.includes("/news/")) return;
107
108    try {
109        const gridContainer = document.querySelector(
110            "#primary > section.dto-page-news__news-grid > div"
111        );
112        if (!gridContainer) return;
113
114        const originalList = gridContainer.querySelector("ul");
115        if (!originalList) return;
116
117        const existingGroups =
118            gridContainer.querySelectorAll("section.news-group");
119        existingGroups.forEach((group) => gridContainer.removeChild(group));
120
121        const entries = originalList.querySelectorAll("li");
122        if (entries.length === 0) return (originalList.style.display = "");
123        originalList.style.display = "none";
124
125        const entriesByType = new Map();
126        entries.forEach((entry) => {
127            const badge = entry.querySelector("p.dto-news-type-badge");
128            const type = badge ? badge.textContent.trim() : "Uncategorized";
129            if (!entriesByType.has(type)) entriesByType.set(type, []);
130            entriesByType.get(type).push(entry.cloneNode(true));
131        });
132
133        for (const group of newsGroups) {
134            const groupName = group.label;
135            const typesInGroup = group.value;
136            const section = document.createElement("section");
137            section.className = "news-group";
138            section.style.marginBottom = "4rem";
139
140            const heading = document.createElement("h1");
141            const representativeType = typesInGroup[0];
142            const color =
143                newsTypeColors[representativeType]?.color ||
144                Object.values(newsTypeColors).find(
145                    (obj) =>
146                        typeof obj === "object" &&
147                        obj.label === representativeType
148                )?.color ||
149                newsTypeColors.All;
150
151            const textElement = document.createElement("span");
152            textElement.textContent = groupName;
153
154            heading.appendChild(textElement);
155            heading.className = "news-group__heading";
156            heading.style.marginBlock = "1rem";
157            // heading.style.borderBottom = "1px solid " + color;
158            heading.style.borderBottom = "1px solid " + "#000";
159            // heading.style.color = color;
160            section.appendChild(heading);
161
162            const newList = document.createElement("ul");
163            newList.className = "dto-page-news__news-list";
164            newList.dataset.type = groupName;
165            newList.dataset.types = typesInGroup.join(",");
166
167            let hasEntriesInGroup = false;
168            for (const type of typesInGroup) {
169                if (entriesByType.has(type)) {
170                    const groupEntries = entriesByType.get(type);
171                    groupEntries.forEach((entry) => newList.appendChild(entry));
172                    hasEntriesInGroup = true;
173                }
174            }
175
176            if (hasEntriesInGroup) {
177                section.appendChild(newList);
178                gridContainer.appendChild(section);
179            }
180        }
181
182        // console.log(entriesByType);
183        // console.log(newsGroups);
184
185        let uncategorizedEntries = [];
186        let uncategorizedTypeNames = [];
187
188        // Handle uncategorized entries or entries whose types are not in headingGroups
189        entriesByType.forEach((groupEntries, type) => {
190            const isInAnyHeadingGroup = Object.values(newsGroups).some(
191                (types) => types.value.includes(type)
192            );
193            if (!isInAnyHeadingGroup) {
194                uncategorizedEntries =
195                    uncategorizedEntries.concat(groupEntries);
196                uncategorizedTypeNames.push(type);
197            }
198        });
199
200        if (uncategorizedEntries.length > 0) {
201            const section = document.createElement("section");
202            section.className = "news-group news-group--uncategorized";
203            section.style.marginBottom = "4rem";
204
205            const heading = document.createElement("h1");
206            const representativeType = uncategorizedTypeNames[0] || "All";
207            const color =
208                newsTypeColors[representativeType]?.color || newsTypeColors.All;
209
210            const textElement = document.createElement("span");
211            textElement.textContent = "Other News";
212
213            heading.appendChild(textElement);
214            heading.className = "news-group__heading";
215            heading.style.marginBlock = "1rem";
216            // heading.style.borderBottom = "1px solid " + color;
217            heading.style.borderBottom = "1px solid " + "#000";
218            // heading.style.color = color;
219            section.appendChild(heading);
220
221            const newList = document.createElement("ul");
222            newList.className = "dto-page-news__news-list";
223            uncategorizedEntries.forEach((entry) => newList.appendChild(entry));
224            section.appendChild(newList);
225
226            gridContainer.appendChild(section);
227        }
228    } catch (error) {
229        console.error("Error grouping news entries:", error);
230    }
231};
232
233/**
234 * Move the load more button to the end of the grid.
235 */
236const moveLoadMoreButton = (gridContainer) => {
237    if (!gridContainer) return;
238
239    try {
240        const loadMoreButton = gridContainer.querySelector(
241            '[data-type="pager"]'
242        );
243        if (loadMoreButton) gridContainer.appendChild(loadMoreButton);
244    } catch (error) {
245        console.error("Error moving load more button:", error);
246    }
247};
248
249/**
250 * Limit Firm News category to latest 3 posts.
251 */
252const limitFirmNewsCategory = () => {
253    if (!location.pathname.includes("/news/")) return;
254
255    const firmNewsCategory = document.querySelectorAll(
256        'ul.dto-page-news__news-list[data-type="Firm News and Recognition"] li'
257    );
258    if (!firmNewsCategory) return;
259
260    const allFirmNewsPosts = Array.from(firmNewsCategory);
261    const latestThree = allFirmNewsPosts.slice(0, 3);
262    const rest = allFirmNewsPosts.slice(3);
263    for (const post of latestThree) post.style.display = "block";
264    for (const post of rest) post.style.display = "none";
265
266    const firmNewsList = document.querySelector(
267        'ul.dto-page-news__news-list[data-type="Firm News and Recognition"]'
268    );
269    const firmNewsSection = firmNewsList ? firmNewsList.parentElement : null;
270    if (!firmNewsSection) return;
271
272    let viewAllButton = firmNewsSection.querySelector(
273        ".dto-view-all-firm-news"
274    );
275
276    if (rest.length > 0) {
277        if (!viewAllButton) {
278            viewAllButton = document.createElement("button");
279            viewAllButton.className = "dto-link-button dto-view-all-firm-news";
280            viewAllButton.textContent = "View all news";
281            viewAllButton.style.marginTop = "1rem";
282            viewAllButton.style.width = "100%";
283            firmNewsSection.appendChild(viewAllButton);
284        } else {
285            viewAllButton.style.display = "";
286        }
287
288        viewAllButton.onclick = () => {
289            for (const post of rest) post.style.display = "block";
290            viewAllButton.style.display = "none";
291        };
292    } else if (viewAllButton) {
293        viewAllButton.style.display = "none";
294    }
295};
296
297/**
298 * Initialize the featured news carousel.
299 */
300const initializeFeaturedNewsCarousel = () => {
301    if (!location.pathname.includes("/news/")) return;
302
303    const carousel = document.querySelector(".dto-page-news__carousel");
304    if (!carousel) return;
305
306    const carouselContent = carousel.querySelector(
307        ".dto-page-news__carousel-content"
308    );
309    if (!carouselContent) return;
310
311    const carouselItems = Array.from(
312        carouselContent.querySelectorAll(".dto-page-news__carousel-item")
313    );
314    if (carouselItems.length === 0) return;
315
316    const carouselLeftButton = carousel.querySelector(
317        ".dto-page-news__carousel-left-button button"
318    );
319    const carouselRightButton = carousel.querySelector(
320        ".dto-page-news__carousel-right-button button"
321    );
322
323    let currentIndex = 0;
324
325    const showSlide = (index) => {
326        for (const item of carouselItems) item.style.display = "none";
327        carouselItems[index].style.display = "flex";
328    };
329
330    showSlide(currentIndex);
331
332    if (carouselLeftButton) {
333        carouselLeftButton.addEventListener("click", () => {
334            currentIndex =
335                (currentIndex - 1 + carouselItems.length) %
336                carouselItems.length;
337            showSlide(currentIndex);
338        });
339    }
340
341    if (carouselRightButton) {
342        carouselRightButton.addEventListener("click", () => {
343            currentIndex = (currentIndex + 1) % carouselItems.length;
344            showSlide(currentIndex);
345        });
346    }
347};
348
349/**
350 * Run once on load and observe changes.
351 */
352document.addEventListener("DOMContentLoaded", () => {
353    if (!location.pathname.includes("/news/")) return;
354
355    const gridContainer = document.querySelector(
356        "#primary > section.dto-page-news__news-grid > div"
357    );
358    if (!gridContainer) return;
359
360    const originalList = gridContainer.querySelector("ul");
361    if (!originalList) return;
362
363    const recalculate = () => {
364        try {
365            groupNewsEntries();
366            setBadgeColors();
367            setFilterColors();
368            moveLoadMoreButton(gridContainer);
369            limitFirmNewsCategory();
370        } catch (error) {
371            console.error("Error recalculating news:", error);
372        }
373    };
374
375    const observer = new MutationObserver((mutationsList, observer) => {
376        for (const mutation of mutationsList) {
377            if (mutation.type === "childList") {
378                recalculate();
379                break;
380            }
381        }
382    });
383
384    observer.observe(originalList, { childList: true });
385    document.addEventListener("facetwp-loaded", recalculate);
386    initializeFeaturedNewsCarousel();
387});

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