PageSourceSearch

https://hue.gov.vn/DesktopModules/MVC/TinBaiNew/Assets/js/LayoutTrinhDien.js

js hue.gov.vn collected 2026-10-02 18:39:22 UTC 18,232 bytes, 484 lines download raw bytes

1function baiVietRedirect(desttab) {
2    $(document).off('click', '.ds-bv-List');
3    $(document).on('click', '.ds-bv-List', function () {
4        const id = $(this).data("bid");
5        if (id) {
6            const curr = window.location.href;
7            if (checkEmptyBlank(desttab)) {
8                location.href = `${curr}/tb/${id}`;
9            }
10            else {
11                location.href = `${desttab}/tb/${id}`;
12            }
13        }
14    });
15};
16
17function chuyenMucRedirect(desttab) {
18    /* $(document).off('click', '.ds-cm-menu-item');
19    $(document).on('click', '.ds-cm-menu-item', function () {
20        const id = $(this).data("cid");
21        if (id) {
22            const curr = window.location.href;
23
24            if (checkEmptyBlank(desttab)) {
25                location.href = `${curr}/cm/${id}`;
26            }
27            else {
28                location.href = `${desttab}/cm/${id}`;
29            }
30        }
31    }); */
32};
33
34function ConvertHTML(content) {
35    //console.log(content, "Content")
36    if (content != null && content != "") {
37        // convert html string into DOM
38        const document = $.parseHTML(content);
39        // make a new parser
40        const parser = new DOMParser();
41        // convert html string into DOM
42        if (document != null) {
43            const documen1t = parser.parseFromString(document[0].data, "text/html");
44            const bodyInnerContent = documen1t.body.innerHTML;
45            //console.log(bodyInnerContent, "BodyContent")
46            return bodyInnerContent;
47        }
48        else {
49            return;
50        }
51        //console.log(documen1t)
52    }
53}
54
55function nestChuyenMucData(data) {
56    const map = new Map();
57    const roots = [];
58
59    data.forEach(item => {
60        map.set(item.ID, { ...item, children: [] });
61    });
62
63    data.forEach(item => {
64        if (item.ChuyenMucChaID === null || item.Level == 0) {
65            roots.push(map.get(item.ID));
66        }
67        else {
68            const parent = map.get(item.ChuyenMucChaID);
69            if (parent) {
70                parent.children.push(map.get(item.ID));
71            }
72        }
73    });
74
75    if (roots.length > 0) {
76        return roots
77    }
78    else {
79        return map
80    }
81};
82
83// trường hợp Level bắt đầu từ 1
84function nestChuyenMucDataV2(data) {
85    const map = new Map();
86    const roots = [];
87
88    data.forEach(item => {
89        map.set(item.ID, { ...item, children: [] });
90    });
91
92    data.forEach(item => {
93        if (item.ChuyenMucChaID === null || item.Level == 0) {
94            roots.push(map.get(item.ID));
95        }
96        else {
97            const parent = map.get(item.ChuyenMucChaID);
98            if (parent) {
99                parent.children.push(map.get(item.ID));
100            }
101        }
102    });
103
104    if (roots.length > 0) {
105        return roots
106    }
107    else {
108        return map
109    }
110};
111
112function renderMenu(items, useid) {
113    let html = '<ul>';
114    items.forEach(item => {
115        let rendercid = useid == true ? item.ID : item.MetaDuongDan;
116        
117        html += `<li class="ds-cm-menu-item" data-cid="${rendercid}" data-pid="${item.ID}">${item.TenChuyenMuc}`;
118
119        if (item.children.length > 0) {
120            html += renderMenu(item.children, useid);
121        }
122
123        html += '</li>';
124    });
125
126    html += '</ul>';
127
128    return html;
129};
130
131function renderMenuAva(items, useid) {
132    let html = '<ul>';
133    items.forEach(item => {
134        //console.log('item', item);
135        let rendercid = useid == true ? item.ID : item.MetaDuongDan;
136
137        html += `<li class="ds-cm-menu-item" data-cid="${rendercid}" data-pid="${item.ID}">`
138       
139        if (item.AnhBieuTuong) {
140            html += `<img src="${item.AnhBieuTuong}" alt="" />`;
141        }
142
143        html += `<span class="ds-cm-menu-item-title">${item.TenChuyenMuc}</span>`;
144
145        if (item.children.length > 0) {
146            html += renderMenu(item.children, useid);
147        }
148
149        html += '</li>';
150    });
151
152    html += '</ul>';
153
154    return html;
155};
156
157// async function renderMenuGioiThieu(items, useid, PID) {
158//     let html = ``;
159//     html += `<ul>`;
160
161//     for (const item of items) {
162//         let rendercid = useid == true ? item.ID : item.MetaDuongDan;
163
164//         html += `<li class="ds-cm-menu-item" data-cid="${rendercid}" data-pid="${item.ID}">`;
165//         html += `<span class="ds-cm-menu-item-title">${item.TenChuyenMuc}</span>`;
166//         html += `<div class="ds-cm-menu-item" data-cid="${rendercid}" data-pid="${item.ID}">`;
167
168
169//         // get /api/TinBaiNew/BaiVIetApi/Paging by item.ID
170//         const renderDataForTab = async (idChuyenMuc) => {
171//             const request = {
172//                 "TuKhoa": "",
173//                 "trangThai": 4,
174//                 "pageSize": 5,
175//                 "PageIndex": 1,
176//                 "DsDoiTuong": idChuyenMuc,
177//                 "ChiLayTinTieuDiem": false,
178//                 "GiaTriSapXep": "ThoiGianCongBo",
179//                 "LoaiSapXep": "DESC",
180//                 "PortalID": PID
181//             };
182
183//             try {
184//                 const data = await getDataWithApi("POST", `/api/TinBaiNew/BaiVIetApi/Paging`, request);
185//                 if (data && data.data && data.data.length > 0) {
186//                     console.log("data.data.length", data.data.length);
187//                     let itemsHtml = '';
188//                     data.data.forEach((item, index) => {
189//                         console.log("item", item);
190//                         // Render each item in the tab content
191//                         // from index 1, set css inline by -(index * 46px - index * 16px)
192//                         if (index === 0) {
193//                             itemsHtml += `<span class="ds-bv-List" data-bid="${item.ID}">${item.TieuDe}: ${item.TomTat}</span>`;
194//                         } else {
195//                             itemsHtml += `<span class="ds-bv-List" data-bid="${item.ID}" style="transform: translateY(-${(index * 46 - index * 16)}px);">${item.TieuDe}: ${item.TomTat}</span>`;
196//                             console.log("index", index);
197//                             console.log("index", index * 46 - index * 16);
198//                         }
199//                     });
200//                     return itemsHtml;
201//                 }
202//                 return '';
203//             } catch (error) {
204//                 //console.log("error", error);
205//                 return '';
206//             }
207//         }
208
209//         const tabData = await renderDataForTab(item.ID);
210//         html += tabData;
211
212//         if (item.children.length > 0) {
213//             html += renderMenu(item.children, useid);
214//         }
215
216//         html += `</div>`;
217//         html += `</li>`;
218//     }
219
220//     html += `</ul>`;
221
222//     return html;
223// };
224
225// renderMenuGioiThieu: build HTML, append, đo và apply transform cho <li>
226// async function renderMenuGioiThieu(items, useid, PID, containerId = 'menu') {
227//     const escapeHtml = (s) => String(s ?? '')
228//         .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
229
230//     const liGap = 30; // khoảng cách mong muốn giữa 2 <li>
231
232//     // --- helper: build HTML recursively (chỉ trả về string, không append) ---
233//     async function buildHtml(nodes) {
234//         let html = '<ul class="ds-menu-root">';
235//         for (const item of nodes) {
236//             const rendercid = useid ? item.ID : item.MetaDuongDan;
237
238//             // gọi API để lấy các bài bên trong chuyên mục
239//             let data = null;
240//             try {
241//                 data = await getDataWithApi("POST", `/api/TinBaiNew/BaiVIetApi/Paging`, {
242//                     "TuKhoa": "",
243//                     "trangThai": 4,
244//                     "pageSize": 5,
245//                     "PageIndex": 1,
246//                     "DsDoiTuong": item.ID,
247//                     "ChiLayTinTieuDiem": false,
248//                     "GiaTriSapXep": "ThoiGianCongBo",
249//                     "LoaiSapXep": "DESC",
250//                     "PortalID": PID
251//                 });
252//             } catch (err) {
253//                 console.error("API error for category", item.ID, err);
254//             }
255
256//             html += `<li class="ds-cm-menu-item" data-cid="${escapeHtml(rendercid)}" data-pid="${escapeHtml(item.ID)}">`;
257//             html += `<span class="ds-cm-menu-item-title">${escapeHtml(item.TenChuyenMuc)}</span>`;
258//             html += `<div class="ds-cm-menu-item">`;
259
260//             // render các .ds-bv-List; giữ transform nội bộ để stack
261//             if (data && Array.isArray(data.data) && data.data.length > 0) {
262//                 data.data.forEach((bv, idx) => {
263//                     const title = escapeHtml(bv.TieuDe);
264//                     const summary = escapeHtml(bv.TomTat);
265//                     // offset per item (bạn có thể điều chỉnh công thức nếu cần)
266//                     const offsetItem = idx === 0 ? 0 : idx * 30; // ví dụ 30px cho mỗi step
267//                     const style = offsetItem ? ` style="transform: translateY(-${offsetItem}px);"` : '';
268//                     html += `<span class="ds-bv-List" data-bid="${escapeHtml(bv.ID)}"${style}>${title}: ${summary}</span>`;
269//                 });
270//             }
271
272//             // children (đệ quy) — trả về HTML chuỗi
273//             if (item.children && item.children.length > 0) {
274//                 html += await buildHtml(item.children);
275//             }
276
277//             html += `</div></li>`;
278//         }
279//         html += '</ul>';
280//         return html;
281//     }
282
283//     // --- Build and insert HTML ---
284//     const html = await buildHtml(items);
285//     const container = containerId ? document.getElementById(containerId) : null;
286//     if (!container) {
287//         // nếu không có container (ví dụ gọi đệ quy), trả HTML để caller dùng
288//         return html;
289//     }
290//     container.innerHTML = html;
291
292//     // Đợi DOM paint xong để getBoundingClientRect() trả đúng giá trị
293//     await new Promise((r) => requestAnimationFrame(r));
294
295//     // --- Process each UL (bao gồm nested) ---
296//     const uls = Array.from(container.querySelectorAll('ul'));
297//     uls.forEach((ul) => {
298//         const liEls = Array.from(ul.children).filter(n => n.tagName === 'LI');
299
300//         let cumulativeHeight = 0;   // tổng chiều cao (visual) đã chiếm bởi các <li> trước
301//         let sumTranslate = 0;       // tổng translate applied (âm)
302
303//         liEls.forEach((li, idx) => {
304//             // đo content height của li dựa trên .ds-bv-List (đã có transform nội bộ)
305//             const spans = Array.from(li.querySelectorAll('.ds-bv-List'));
306//             let contentHeight = 0;
307
308//             if (spans.length > 0) {
309//                 const rects = spans.map(s => s.getBoundingClientRect());
310//                 const minTop = Math.min(...rects.map(r => r.top));
311//                 const maxBottom = Math.max(...rects.map(r => r.bottom));
312//                 contentHeight = Math.max(0, maxBottom - minTop);
313//             } else {
314//                 // fallback: dùng height của chính li
315//                 const r = li.getBoundingClientRect();
316//                 contentHeight = r.height;
317//             }
318
319//             if (idx === 0) {
320//                 // đảm bảo li đầu không transform
321//                 li.style.transform = '';
322//                 li.style.position = li.style.position || 'relative';
323//             } else {
324//                 // dịch lên bằng tổng chiều cao các li trước + gap
325//                 const translateY = -(cumulativeHeight + liGap);
326//                 // đảm bảo position để translate hiển thị như mong muốn
327//                 li.style.position = 'relative';
328//                 li.style.transform = `translateY(${translateY}px)`; // translateY âm
329//                 sumTranslate += translateY;
330//             }
331
332//             // sau khi xử lý li này, cộng chiều cao nó (visual) + gap vào cumulativeHeight
333//             cumulativeHeight += contentHeight + liGap;
334//         });
335
336//         // set max-height cho ul: baseScroll + sumTranslate (sumTranslate <= 0)
337//         const baseScroll = ul.scrollHeight;
338//         let adjusted = Math.round(baseScroll + sumTranslate);
339//         if (adjusted < 0) adjusted = 0;
340//         ul.style.maxHeight = adjusted + 'px';
341//         ul.style.overflow = 'hidden';
342
343//         // debug (bật khi cần)
344//         // console.log('UL debug:', { baseScroll, sumTranslate, adjusted, cumulativeHeight });
345//     });
346
347//     return html;
348// }
349
350async function renderMenuGioiThieu(items, useid, PID, containerId) {
351    const escapeHtml = (s) => String(s ?? '')
352        .replace(/&/g, '&amp;')
353        .replace(/</g, '&lt;')
354        .replace(/>/g, '&gt;');
355
356    let html = ``;
357    let cumulativeOffset = 0; // tổng offset cho các li
358
359    html += `<ul id="ds-menu-root">`;
360
361    for (let i = 0; i < items.length; i++) {
362        const item = items[i];
363        const rendercid = useid ? item.ID : item.MetaDuongDan;
364
365        const request = {
366            "TuKhoa": "",
367            "trangThai": 4,
368            "pageSize": 5,
369            "PageIndex": 1,
370            "DsDoiTuong": item.ID,
371            "ChiLayTinTieuDiem": false,
372            "GiaTriSapXep": "ThoiGianCongBo",
373            "LoaiSapXep": "DESC",
374            "IsLienThong": true,
375            "PortalID": PID
376        };
377
378        let data = null;
379        try {
380            data = await getDataWithApi("POST", `/api/TinBaiNew/BaiVIetApi/Paging`, request);
381        } catch (err) {
382            console.error("API error for category", item.ID, err);
383        }
384
385        const length = (data && data.data) ? data.data.length : 0;
386
387        let localOffset = 0;
388        if (i > 0) {
389            localOffset = -((length) * 46 - (length) * 16 + 30);
390            cumulativeOffset += localOffset;
391        }
392        
393        const liStyle = (i > 0 && cumulativeOffset !== 0)
394            ? ` style="transform: translateY(${cumulativeOffset + data.data.length * 24}px);"`
395            : "";
396
397        html += `<li class="ds-cm-menu-item" data-cid="${escapeHtml(rendercid)}" data-pid="${escapeHtml(item.ID)}"${liStyle}>`;
398        html += `<span class="ds-cm-menu-item-title">${escapeHtml(item.TenChuyenMuc)}</span>`;
399        html += `<div class="ds-cm-menu-item" data-cid="${escapeHtml(rendercid)}" data-pid="${escapeHtml(item.ID)}">`;
400
401        if (data && data.data && data.data.length > 0) {
402            // sort data by ThoiGianCongBo: "2001-05-24T00:00:00" ASC
403            data.data.sort((a, b) => new Date(a.ThoiGianCongBo) - new Date(b.ThoiGianCongBo));
404            data.data.forEach((bv, index) => {
405                const title = escapeHtml(bv.TieuDe);
406                const summary = escapeHtml(bv.TomTat);
407                if (index === 0) {
408                    html += `<span class="ds-bv-List box-shadow" data-bid="${escapeHtml(bv.ID)}">
409                                <div class="item">
410                                    <div class="item-inner">
411                                        ${title}: ${summary}
412                                    </div>
413                                </div>
414                            </span>`;
415                } else {
416                    const offsetItem = index * 46 - index * 16;
417                    html += `<span class="ds-bv-List box-shadow" data-bid="${escapeHtml(bv.ID)}" style="transform: translateY(-${offsetItem}px);">
418                                <div class="item">
419                                    <div class="item-inner">
420                                        ${title}: ${summary}
421                                    </div>
422                                </div>
423                            </span>`;
424                }
425            });
426        }
427
428        if (item.children && item.children.length > 0) {
429            html += await renderMenuGioiThieu(item.children, useid, PID);
430        }
431
432        html += `</div>`;
433        html += `</li>`;
434    }
435
436    html += `</ul>`;
437
438    // Gắn HTML vào container
439    if (containerId) {
440        const container = document.getElementById(containerId);
441        if (container) {
442            container.innerHTML = html;
443
444            // Sau khi DOM đã render -> đo lại chiều cao thật
445            requestAnimationFrame(() => {
446                const ul = container.querySelector("#ds-menu-root");
447                if (!ul) return;
448
449                // Lấy tất cả li và .ds-bv-List bên trong
450                const nodes = [
451                    ...ul.querySelectorAll(":scope > li"),
452                    ...ul.querySelectorAll(".ds-bv-List")
453                ];
454
455                if (nodes.length === 0) {
456                    ul.style.maxHeight = ul.scrollHeight + "px";
457                    return;
458                }
459
460                const ulRect = ul.getBoundingClientRect();
461                let minTop = Infinity;
462                let maxBottom = -Infinity;
463
464                nodes.forEach(node => {
465                    const r = node.getBoundingClientRect();
466                    const topRel = r.top - ulRect.top;
467                    const bottomRel = r.bottom - ulRect.top;
468                    if (topRel < minTop) minTop = topRel;
469                    if (bottomRel > maxBottom) maxBottom = bottomRel;
470                });
471
472                const adjustedHeight = Math.max(0, maxBottom - minTop);
473
474                ul.style.maxHeight = Math.round(adjustedHeight - 100) + "px";
475                ul.style.overflow = "hidden";
476
477                // console.log("UL adjustedHeight (li + ds-bv-List):", adjustedHeight);
478            });
479        }
480    }
481
482    return html;
483}
484

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.