PageSourceSearch

https://vnpt.com.vn/common/assets_v1/js/hanhtrinh.js

js vnpt.com.vn collected 2026-10-01 12:35:14 UTC 10,398 bytes, 316 lines download raw bytes

1function loadPageDataHanhTrinh(page) {
2  $.ajax({
3    url: "/service/api/article/list",
4    dataType: "jsonp",
5    jsonp: "jsonCallback",
6    data: {
7      scUnitMapId: $("#site_id").html(),
8      saArticleCateId: "8a10ed229a2f4095019aa07d75ad6684",
9      first: 0,
10      pageSize: 52,
11    },
12    success: function (res) {
13      if (res && res.response) {
14        const container = $(".milestones-swiper .swiper-wrapper");
15
16        // Clear existing content if needed
17        container.empty();
18        let first = "";
19        // Loop through each item in the response
20        res.response.forEach((item, index) => {
21          // Featured item (first one)
22
23          first += `
24            <div class="swiper-slide" data-year="${item.subTitle
25            }" data-title="${item.title}" data-content='${JSON.stringify(
26              item.lead || ""
27            )}' data-img="${item.avatarApp}">
28                  <div
29                    class="group transition-all duration-300 mx-auto rounded-xl shadow-lg bg-white border border-gray-100 w-[80%] md:w-88 min-h-[320px] sm:min-h-[460px] md:min-h-88 2xl:w-96 2xl:min-h-96 flex flex-col"
30                  >
31                    <div
32                      class="relative w-full aspect-[16/9] rounded-t-xl overflow-hidden"
33                    >
34                      <img
35                        alt="Năm ${item.subTitle}"
36                        class="object-cover"
37                        sizes="100vw"
38                        src="${item.avatarApp}"
39                        style="
40                          position: absolute;
41                          height: 100%;
42                          width: 100%;
43                          inset: 0px;
44                          color: transparent;
45                        "
46                      />
47                    </div>
48                    <div
49                      class="h-1 w-full bg-gradient-to-r from-blue-600 to-sky-400"
50                    ></div>
51                    <div class="flex-1 px-6 pt-4 pb-6 flex flex-col">
52                      <span class="font-medium text-gray-500 mb-1"
53                        > ${item.subTitle.includes("/")
54              ? item.subTitle
55              : "Năm " + item.subTitle
56            }</span
57                      ><span
58                        class="font-medium text-lg text-gray-800 line-clamp-2 md:line-clamp-4"
59                        >${item.title}</span
60                      >
61                    </div>
62                    <div 
63                    data-index="${index}"
64                    class="btn-detail flex item-center px-6 !pb-4 text-blue-600 cursor-pointer hover:opacity-80"><span class="text-lg font-medium mr-[2px]">Chi tiết</span><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-up-right" aria-hidden="true"><path d="M7 7h10v10"></path><path d="M7 17 17 7"></path></svg></div>
65                  </div>
66                </div>
67          
68          `;
69        });
70
71        container.append(first);
72
73        // ===== 1. Thu thập text để tạo timeline =====
74        var mainSlides = document.querySelectorAll(
75          ".main-swiper .swiper-slide"
76        );
77        var timelineWrapper = document.querySelector(
78          ".timeline-swiper .swiper-wrapper"
79        );
80
81        // tạo slide timeline tương ứng
82        mainSlides.forEach((slide) => {
83          var year = slide.dataset.year || slide.innerText.trim();
84          var el = document.createElement("div");
85          el.classList.add("swiper-slide");
86          if (year.includes("/")) {
87            el.textContent = year;
88          } else {
89            el.textContent = "Năm " + year;
90          }
91          timelineWrapper.appendChild(el);
92        });
93
94        // ===== 2. Khởi tạo timeline swiper =====
95        var timelineSwiper = new Swiper(".timeline-swiper", {
96          slidesPerView: 8,
97          centeredSlides: false,
98          slidesPerGroup: 1,
99          breakpoints: {
100            360: {
101              slidesPerView: 2,
102            },
103            768: {
104              slidesPerView: 8,
105            },
106          },
107        });
108
109        // ===== 3. Khởi tạo main swiper vĂ  link thumbs =====
110        var mainSwiper = new Swiper(".main-swiper", {
111          slidesPerView: 1,
112          centeredSlides: true,
113          spaceBetween: 20,
114          initialSlide: 1,
115          loop: false,
116          breakpoints: {
117            768: {
118              slidesPerView: 3,
119            },
120          },
121          navigation: {
122            nextEl: "#cac-moc-phat-trien .btn-next",
123            prevEl: "#cac-moc-phat-trien .btn-prev",
124          },
125        });
126
127        // ===== 1. Update indicator and scroll timeline if needed =====
128        function updateIndicator(activeIndex) {
129       
130          // Scroll timeline if out of view
131          var firstVisible = timelineSwiper.activeIndex;
132          var notChangePosition = false;
133          var lastVisible =
134            firstVisible + timelineSwiper.params.slidesPerView - 1;
135      
136          var changeHide = null;
137          if (activeIndex > lastVisible) {
138            const rest = activeIndex - lastVisible
139          
140            timelineSwiper.slideTo(firstVisible + rest);
141            notChangePosition = true;
142            changeHide = 1222.5;
143          } else if (activeIndex < firstVisible) {
144            const rest = firstVisible - activeIndex
145            timelineSwiper.slideTo(firstVisible - rest);
146            notChangePosition = true;
147            changeHide = 81.5;
148
149
150          }
151
152          var indicator = document.querySelector(".indicator");
153          var timelineSlides = timelineSwiper.slides;
154          var activeSlide = timelineSlides[activeIndex];
155          console.log("activeSlide",activeSlide)
156
157          if (!activeSlide) return;
158      
159          console.log("activeIndex",activeIndex)
160          updateActiveTimeline(activeIndex);
161
162          // Move indicator
163          var rect = activeSlide.getBoundingClientRect();
164          var wrapperRect = document
165            .querySelector(".timeline-wrapper")
166            .getBoundingClientRect();
167
168          var x = rect.left + rect.width / 2 - wrapperRect.left;
169          if(changeHide != null) {
170            indicator.style.transform = `translateX(${changeHide - 12}px)`;
171            changeHide = null;
172          }
173          if (!notChangePosition) {
174            indicator.style.transform = `translateX(${x - 12}px)`;
175          }
176        }
177
178        // ===== 2. Sync from mainSwiper to timeline =====
179        mainSwiper.on("slideChange", function () {
180          var activeIndex = mainSwiper.activeIndex;
181          updateIndicator(activeIndex);
182        });
183
184        // ===== 3. Sync from timeline click to mainSwiper =====
185        timelineSwiper.on("click", function (swiper, e) {
186          var clickedIndex = swiper.clickedIndex;
187          if (clickedIndex === undefined) return;
188          mainSwiper.slideTo(clickedIndex);
189          updateIndicator(clickedIndex);
190        });
191
192        // ===== 4. Initial indicator =====
193        setTimeout(() => updateIndicator(mainSwiper.activeIndex), 300);
194      }
195    },
196    error: function (err) {
197      console.log("err", err);
198    },
199  });
200}
201if ($("#cac-moc-phat-trien").length > 0) {
202  loadPageDataHanhTrinh();
203}
204
205// === CLICK CHI TIẾT ===
206$(document).on("click", ".btn-detail", function () {
207  const slide = $(this).closest(".swiper-slide");
208
209  const year = slide.data("year") + "";
210  const title = slide.data("title");
211  const img = slide.data("img");
212  const content = slide.data("content") || "";
213
214  // GĂ¡n vĂ o popup
215  if (year.includes("/")) {
216    $("#popupYear").text(year);
217  } else {
218    $("#popupYear").text("Năm " + year);
219  }
220  $("#popupTitle").text(title);
221  $("#popupImg").attr("src", img);
222
223  try {
224    $("#popupContent").html(JSON.parse(content));
225  } catch (e) {
226    $("#popupContent").html(content);
227  }
228
229  $("#popupHanhTrinh").removeClass("hidden");
230});
231
232$(document).on("click", "#closePopupHanhTrinh", function () {
233  $("#popupHanhTrinh").addClass("hidden");
234});
235$(document).on("click", "#popupHanhTrinh", function (e) {
236  if (e.target.id === "popupHanhTrinh") {
237    $("#popupHanhTrinh").addClass("hidden");
238  }
239});
240
241$(document).on("click", ".btn-songphuong", function () {
242
243
244  const title = $("#songphuong .title").html();
245  const img = $("#songphuong .img").html();
246  const content = $("#songphuong .content").html();
247
248  // GĂ¡n vĂ o popup
249
250  $("#popupYear").text(title);
251  $("#popupImg").attr("src", img);
252
253  try {
254    $("#popupContent").html(JSON.parse(content));
255  } catch (e) {
256    $("#popupContent").html(content);
257  }
258
259  $("#popupHanhTrinh").removeClass("hidden");
260});
261
262$(document).on("click", ".btn-daphuong", function () {
263
264
265  const title = $("#daphuong .title").html();
266  const img = $("#daphuong .img").html();
267  const content = $("#daphuong .content").html();
268
269  // GĂ¡n vĂ o popup
270
271  $("#popupYear").text(title);
272  $("#popupImg").attr("src", img);
273
274  try {
275    $("#popupContent").html(JSON.parse(content));
276  } catch (e) {
277    $("#popupContent").html(content);
278  }
279
280  $("#popupHanhTrinh").removeClass("hidden");
281});
282
283$(document).on("click", "#closePopupHanhTrinh", function () {
284  $("#popupHanhTrinh").addClass("hidden");
285});
286$(document).on("click", "#popupHanhTrinh", function (e) {
287  if (e.target.id === "popupHanhTrinh") {
288    $("#popupHanhTrinh").addClass("hidden");
289  }
290});
291
292function updateActiveTimeline(index) {
293  const slides = document.querySelectorAll(".timeline-swiper .swiper-slide");
294
295  slides.forEach((s, i) => {
296    if (i === index) {
297      s.classList.add(
298        "!text-blue-600",
299        "cursor-pointer",
300        "transition",
301        "text-blue-600",
302        "!font-bold",
303        "timeline-active"
304      );
305    } else {
306      s.classList.remove(
307        "!text-blue-600",
308        "cursor-pointer",
309        "transition",
310        "text-blue-600",
311        "!font-bold",
312        "timeline-active"
313      );
314    }
315  });
316}

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.