Có lỗi xảy ra trong quá trình xử lý biểu mẫu.
For "#if" condition: Expected a boolean, but this has evaluated to a number (wrapper: f.t.SimpleNumber):
==> parts?size [in template "85872286966386#20120#BASIC-WEB-CONTENT" at line 144, column 54]
----
FTL stack trace ("~" means nesting-related):
- Failed at: #if parts?size [in template "85872286966386#20120#BASIC-WEB-CONTENT" at line 144, column 49]
----
1<#assign AssetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
2<#assign JournalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
3<#assign journalArticle = JournalArticleLocalService.getArticle(getterUtil.getLong(groupId),.vars['reserved-article-id'].data) />
4<#assign categories = AssetCategoryLocalService.getCategories("com.liferay.journal.model.JournalArticle", journalArticle.getResourcePrimKey()) />
5<#assign categoryIdList = [] />
6<#assign categoryNeedCheck = ["36063", "159075", "159071", "36147", "36135"] />
7<#if categories?has_content>
8 <#list categories as category>
9 <#assign categoryIdList = categoryIdList + [category.getCategoryId()?c?string] />
10 </#list>
11</#if>
12<#function hasAny(listA, listB)>
13 <#list listA as a>
14 <#if listB?seq_contains(a)>
15 <#return true>
16 </#if>
17 </#list>
18 <#return false>
19</#function>
20<style>
21.ck-content p, .ck-content span {
22 font-family: var(--font-family-base, system-ui, -apple-system, blinkmacsystemfont, "Segoe UI", roboto, oxygen-sans, ubuntu, cantarell, "Helvetica Neue", arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol") !important;
23}
24</style>
25<#setting locale="vi_VN">
26 <#if .vars["reserved-article-display-date"]??>
27 <#assign displayDate=.vars["reserved-article-display-date"].data?date("EEE, dd MMM yyyy hh:mm:sszzz")?string("dd/MM/yyyy")>
28 <#else>
29 <#assign displayDate="">
30 </#if>
31 <div class="p-[24px_16px_44px_16px] sm:p-[24px_24px_48px_24px] xl:p-[48px_24px_80px_24px] " id="print-content">
32 <div class=" text-start px-0">
33 <h1 class="text-base-color text-4xl max-xl:text-3xl font-semibold">
34 ${.vars["reserved-article-title"].data}
35 </h1>
36 <div class="py-2 justify-between items-center inline-flex w-full">
37 <div class="text-base-color grow shrink basis-0 text-gray-700 text-sm font-medium">
38 <#if displayDate?? && displayDate?has_content>
39 ${displayDate}
40 </#if>
41 </div>
42 <div class="justify-between items-center flex text-base-color gap-2 hidden xl:flex">
43 <!-- in -->
44 <div class="cursor-pointer justify-between flex" id="btn_print">
45 <button id="ic_print" rel="nofollow" onclick="javascript:;" class="cpanel-item print"
46 title="In">
47 <img src="/documents/d/investor/print">
48 </button>
49 </div>
50 <div class="hidden">
51 <div class="container m-auto px-10 py-20" id="printer-pdf"></div>
52 </div>
53 <form id="btn_print_label">
54 <#if locale == "vi_VN">
55 <span>In bài</span>
56 <#else>
57 <span>Print</span>
58 </#if>
59
60 </form>
61
62 </div>
63 </div>
64
65 <div
66 class="flex p-[16px_20px] sm:p-[16px_20px] xl:p-[36px] flex-col items-start gap-5 self-stretch rounded-2xl border border-[#E4E7EC] shadow-custom">
67 <div
68 class="ck-content text-base font-medium leading-normal post-detail prose max-w-full text-justify text-base-color prose-ol:marker:text-primary prose-ul:marker:text-primary prose-li:marker:text-primary">
69 <#if (content.getData())??>
70 ${content.getData()}
71 </#if>
72 </div>
73<#assign groupMap = {} />
74
75<#-- Gom nhóm file -->
76<#list nhomFileDinhKems.getSiblings() as group>
77 <#assign nhomFile = group.nhomFileDinhKem.getData()!"" />
78 <#if !groupMap[nhomFile]??>
79 <#assign groupMap = groupMap + { (nhomFile) : [] } />
80 </#if>
81
82 <#list group.fileDinhKem.getSiblings() as cur_fileDinhKem>
83 <#assign fileName = cur_fileDinhKem.file_name.getData()!"" />
84 <#assign fileLink = cur_fileDinhKem.file_link.getData()!"" />
85 <#assign fileLinkEn = cur_fileDinhKem.file_link_en.getData()!"" />
86 <#if fileName?has_content || fileLink?has_content || fileLinkEn?has_content>
87 <#assign groupMap = groupMap + {
88 (nhomFile) : groupMap[nhomFile] + [cur_fileDinhKem]
89 } />
90 </#if>
91 </#list>
92</#list>
93
94<#-- Render từng nhóm -->
95<#list groupMap?keys as groupName>
96<#assign files = groupMap[groupName]![] />
97<#if files?has_content>
98 <div class="flex p-[24px] flex-col justify-center items-center gap-[10px] self-stretch rounded-[14px] bg-[#F2F4F7]">
99 <div class="flex flex-col items-start gap-3 self-stretch file-group">
100 <div class="flex w-full justify-between">
101 <div class="flex gap-[12px]">
102 <span><img src="/documents/d/investor/file-pdf" alt="icon_file" class="w-6 h-6"></span>
103 <#if groupName?has_content>
104 <#if locale == "vi_VN">
105 <span class="file-title">${groupName}</span>
106 <#else>
107 <#if groupName == "Tài liệu chính thức">
108 <span class="file-title">Official documents</span>
109 <#elseif groupName == "Biên bản, nghị quyết đại hội">
110 <span class="file-title">Minutes & Resolutions</span>
111 <#else>
112 <span class="file-title">Attachments</span>
113 </#if>
114 </#if>
115 <#else>
116 <#if locale == "vi_VN">
117 <span class="file-title">Tệp tin đính kèm</span>
118 <#else>
119 <span class="file-title">Attachments</span>
120 </#if>
121 </#if>
122 </div>
123 <div class="block sm:hidden">
124 <button class="more-file">
125
126 <img src="/documents/d/investor/chevron-down-solid.svg" style="width: 12px;" />
127 </button>
128 </div>
129 </div>
130
131 <div class="file-list hidden sm:block transition-all w-full">
132 <#list groupMap[groupName] as fileItem>
133 <#assign fileName = fileItem.file_name.getData()!"" />
134 <#assign fileLink = fileItem.file_link.getData()!"" />
135 <#assign fileLinkEn = fileItem.file_link_en.getData()!"" />
136 <#assign fileOR = fileLink />
137 <#if !fileOR?has_content>
138 <#assign fileOR = fileLinkEn />
139 </#if>
140 <#-- Nếu fileName trống thì lấy tên file từ URL (phần trước UUID) -->
141 <#if !fileName?has_content && fileOR?has_content>
142 <#assign parts = fileOR?split("/") />
143 <#if parts?size >= 6>
144 <#assign fileName = parts[parts?size - 2] />
145 <#else>
146 <#assign fileName = parts?last />
147 </#if>
148 <#-- Cắt query string nếu có -->
149 <#if fileName?contains("?")>
150 <#assign fileName = fileName?split("\\?")?first />
151 </#if>
152 </#if>
153 <#assign fileExtension = fileOR?split(".")?last?lower_case />
154 <div class="flex flex-col sm:flex-row items-center justify-between w-full">
155 <p class="title-file-items">
156 <a href="${fileOR}" class="flex items-center gap-2">
157 <span class="<#if !hasAny(categoryIdList, categoryNeedCheck) >underline</#if> break-normal">${fileName}</span>
158 </a>
159 </p>
160 <#if hasAny(categoryIdList, categoryNeedCheck) >
161 <div class="flex gap-[24px] dowload-file w-32 sm:w-28 ">
162 <a href="${fileLink}" class="flex gap-[8px] w-12 sm:w-16">
163 <#if fileLink?has_content>
164 <img src="/documents/d/investor/download" alt="btn-color-text" class="!w-5 !h-5">
165 <span class="btn-color-text text-[14px]">VN</span>
166 </#if>
167 </a>
168 <#if fileLinkEn?has_content>
169 <a href="${fileLinkEn}" class="flex gap-[8px]">
170 <img src="/documents/d/investor/download" alt="btn-color-text" class="!w-5 !h-5">
171 <span class="btn-color-text text-[14px]">EN</span>
172 </a>
173 </#if>
174 </div>
175 </#if>
176 </div>
177 </#list>
178 </div>
179 </div>
180 </div>
181 </#if>
182</#list>
183 </div>
184 <div class="flex items-center gap-5 pt-[24px] whitespace-nowrap overflow-visible" id="btn_icon">
185 <div class="text_bottom">
186 <p class="text-black text-[17px] not-italic font-normal leading-[150%]">
187 <#if locale == "vi_VN">
188 Chia sẻ:
189 <#else>
190 Share:
191 </#if>
192 </p>
193 </div>
194 <div class="icon_bottom flex items-center gap-4 ">
195 <!-- copy -->
196 <button type="button" class="cpanel-item link"
197 onclick="copyLink('${friendlyURL}')" title="Copy">
198
199 <img src="/documents/d/investor/copy">
200 </button>
201 <!-- facebook -->
202 <a class="cpanel-item facebook" target="_blank"
203 href="https://www.facebook.com/sharer.php?u=${friendlyURL}"
204 rel="nofollow" title="Chia sẻ bài viết lên facebook">
205 <img src="/documents/d/investor/facebook_icon">
206 </a>
207 <!-- youtube -->
208 <a class="cpanel-item youtube" target="_blank"
209 href="https://www.youtube.com/@vietinbank-nganhangtmcpcon2422/videos" rel="nofollow"
210 title="Chia sẻ bài viết lên facebook">
211 <img src="/documents/d/investor/youtube_icon">
212 </a>
213 <!-- linkedin -->
214 <a class="cpanel-item linkedin" target="_blank"
215 href="https://www.linkedin.com/sharing/share-offsite/?url=${friendlyURL}"
216 rel="nofollow" title="Chia sẻ bài viết lên linkedin">
217 <img src="/documents/d/investor/linkedin">
218 </a>
219 <!-- zalo -->
220 <a class="cpanel-item zalo" target="_blank"
221 href="https://zalo.me/share?url=${friendlyURL!''}" rel="nofollow"
222 title="Chia sẻ bài viết lên zalo">
223 <img src="/documents/d/investor/zalo_normal">
224 </a>
225 <!-- viber -->
226 <a class="cpanel-item viber"
227 href="viber://forward?text=${friendlyURL!''}" target="_blank"
228 data-track-content="" data-content-name="article-actions"
229 data-content-piece="article-actions-twitter" data-content-target="/w/${friendlyURL}"
230 rel="nofollow" title="Chia sẻ bài viết lên viber">
231 <img src="/documents/d/investor/viber">
232 </a>
233 <!-- x -->
234 <a class="cpanel-item twitter"
235 href="https://twitter.com/intent/tweet?text=${friendlyURL!''}"
236 target="_blank" data-track-content="" data-content-name="article-actions"
237 data-content-piece="article-actions-twitter" data-content-target="/w/${friendlyURL}"
238 rel="nofollow" title="Chia sẻ bài viết lên x">
239 <img src="/documents/d/investor/xmedia">
240 </a>
241
242 </div>
243 </div>
244 </div>
245 </div>
246 <style>
247 .file-title{
248 color: #000;
249 text-align: justify;
250 font-size: 20px;
251 font-style: normal;
252 font-weight: 600;
253 line-height: normal;
254 }
255 .title-file-items{
256 color: var(--Base-Color-Black, #000);
257 font-size: 16px;
258 font-style: normal;
259 /* font-weight: 600; */
260 font-weight: 500;
261 line-height: 150%;
262 max-width: 88%;
263 }
264 .icon_bottom img,
265 #ic_print img {
266 width: 36px !important;
267 height: 36px !important;
268 }
269 .asset-full-content.clearfix.mb-5.show-asset-title {
270 margin-bottom: 0px !important;
271}
272.shadow-custom{
273background: var(--Base-Color-White, #FFF);
274/* Drop Shadow On Light/Drop Shadow - On Light - M */
275box-shadow: 0 6px 12px 0 rgba(28, 39, 49, 0.05);
276}
277
278@media screen and (min-width: 641px) and (max-width: 1024px) {
279 .title-file-items{
280 max-width: 75%;
281 }
282}
283 @media only screen and (max-width: 640px) {
284 .title-file-items{
285 width: 100%;
286 text-align: left;
287 }
288 .dowload-file{
289 width: 100%;
290 justify-content: right;
291 }
292 .more-file{
293 border-radius: 100px;
294 background: #FFF;
295 display: flex;
296 padding: 7px;
297 align-items: center;
298 gap: 10px;
299 }
300 }
301 .ck-content table {
302 border-collapse: collapse;
303 width: 100%;
304}
305.ck-content table,
306.ck-content th,
307.ck-content td {
308 border: 1px solid #000;
309}
310.ck-content th,
311.ck-content td {
312 padding: 6px;
313 text-align: center;
314 vertical-align: middle;
315}
316
317 </style>
318 <script>
319 function copyLink(link) {
320 $(".link").append('<span class="tooltiptext">Đã copy</span>');
321 const unsecuredCopyToClipboard = (text) => {
322 const textArea = document.createElement("textarea");
323 textArea.value = text;
324 document.body.appendChild(textArea);
325 textArea.select();
326 try {
327 document.execCommand('copy');
328 } catch (err) {
329 console.error('Unable to copy to clipboard', err);
330 }
331 document.body.removeChild(textArea);
332 };
333
334 if (window.isSecureContext && navigator.clipboard) {
335 navigator.clipboard.writeText(link);
336 } else {
337 unsecuredCopyToClipboard(link);
338 }
339
340 setTimeout(function () {
341 $(".tooltiptext").remove();
342 }, 3000);
343 }
344 //Start xử lý nút in trang
345 const printButton = document.querySelector("#ic_print");
346
347 printButton.addEventListener("click", function (e) {
348 e.preventDefault(); // Ngăn hành vi mặc định
349 debugger
350 // Lấy HTML của <head> (tất cả <link> và <style>)
351 const headHTML = document.head.outerHTML;
352 // Lấy nội dung của class .main
353 const mainContentElement = document.querySelector("#print-content").cloneNode(true);
354
355 // Xóa các phần tử không cần in
356 const btnPrint = mainContentElement.querySelector("#btn_print");
357 if (btnPrint) btnPrint.remove();
358
359 const btnIcon = mainContentElement.querySelector("#btn_icon");
360 if (btnIcon) btnIcon.remove();
361
362 const btnPrintLabel = mainContentElement.querySelector("#btn_print_label");
363 if (btnPrintLabel) btnPrintLabel.remove();
364
365 // Lưu nội dung gốc của trang
366 const originalContent = document.body.innerHTML;
367
368 // Thay thế toàn bộ nội dung body bằng nội dung .main đã xử lý
369 document.body.innerHTML = mainContentElement.innerHTML;
370
371 // Gọi hàm in
372 window.print();
373
374 // Khôi phục lại nội dung gốc
375 document.body.innerHTML = originalContent;
376
377 // Đảm bảo script được chạy lại sau khi khôi phục
378 window.location.reload();
379 });
380
381 document.querySelectorAll(".more-file").forEach(btn => {
382 btn.addEventListener("click", () => {
383 const list = btn.closest(".file-group").querySelector(".file-list");
384 list.classList.toggle("hidden");
385 btn.querySelector("img").classList.toggle("-rotate-90");
386
387 });
388 });
389
390const container = document.querySelector('.ck-content');
391
392// Bước 1: Lấy toàn bộ text của từng phần tử con theo thứ tự
393const blocks = Array.from(container.children);
394
395// Hàm chuẩn hóa text để so sánh
396function normalizeText(el) {
397 return el.innerText
398 .replace(/ /g, ' ') // bỏ nbsp
399 .replace(/\s+/g, ' ') // gộp khoảng trắng
400 .trim();
401}
402
403// Bước 2: Gom text toàn phần
404const fullText = normalizeText(container);
405
406// Bước 3: Dò các đoạn lặp — nếu đoạn HTML con trùng hoàn toàn hoặc là phần con của text đã có, xóa nó
407const seenTexts = new Set();
408blocks.forEach(el => {
409 const text = normalizeText(el);
410 if (!text) return;
411
412 // Nếu text này đã từng xuất hiện (trong bất kỳ block nào trước đó) thì xóa
413 if (seenTexts.has(text)) {
414 el.remove();
415 } else {
416 // Nếu đoạn text này đã nằm trong đoạn dài hơn đã có => cũng xóa
417 for (const s of seenTexts) {
418 if (s.includes(text) || text.includes(s)) {
419 el.remove();
420 return;
421 }
422 }
423 seenTexts.add(text);
424 }
425});
426
427// Bước 4: Sau khi xử lý, nếu vẫn còn đoạn <p> và <div> trùng 100% về nội dung toàn văn → chỉ giữ bản đầu
428const uniqueHTML = [];
429const temp = document.createElement('div');
430temp.innerHTML = container.innerHTML;
431
432Array.from(temp.children).forEach(el => {
433 const t = normalizeText(el);
434 if (!uniqueHTML.some(u => u === t)) {
435 uniqueHTML.push(t);
436 } else {
437 el.remove();
438 }
439});
440
441// Cập nhật lại nội dung đã loại trùng
442container.innerHTML = temp.innerHTML;
443 </script>