1import { fixedBodyOn, fixedBodyOff } from './modules/m_fixedBody.js'; 2import { createRangePicker, addDragRangeSupport } from './modules/calendar-common.js'; 3 4let cleanupAvailabilityPicker = null; 5 6// ==================================================================== 7// â å¨åº«ãã§ãã¯æ©è½ã®å®ç¾© (ãããã¬ãã«) 8// ==================================================================== 9 10const resetBookingButtonStatus = function(buttonElement, message = 'äºç´ãã', disabled = true) { 11 if (!buttonElement) return; 12 13 // ç¶æ ãé©ç¨ 14 buttonElement.textContent = message; 15 16 if (disabled) { 17 // ãã¿ã³ãç¡å¹å 18 buttonElement.style.opacity = '0.5'; 19 buttonElement.style.backgroundColor = '#ccc'; 20 buttonElement.style.pointerEvents = 'none'; 21 buttonElement.removeAttribute('href'); // hrefãåé¤ã¾ãã¯ç¡å¹ãªå¤ã« 22 } else { 23 // ãã¿ã³ãæå¹å 24 buttonElement.style.opacity = '1'; 25 buttonElement.style.backgroundColor = ''; 26 buttonElement.style.pointerEvents = 'auto'; 27 // 注æ: href屿§ã¯checkAvailabilityå ã§è¨å®ããã 28 } 29}; 30 31function debounce(func, delay) { 32 let timeoutId; 33 return function(...args) { 34 if (timeoutId) { 35 clearTimeout(timeoutId); 36 } 37 timeoutId = setTimeout(() => { 38 func.apply(this, args); 39 }, delay); 40 }; 41} 42 43const checkAvailability = function(e) { 44 if (e && typeof e.stopPropagation === 'function') { 45 e.stopPropagation(); 46 } 47 48 const currentCheckinInput = document.getElementById('checkin'); 49 const currentCheckoutInput = document.getElementById('checkout'); 50 const liveBookingButton = document.getElementById('booking-button'); 51 const resultDiv = document.getElementById('availability-result'); 52 const postId = document.getElementById('post-id')?.value; 53 const priceResultEl = document.getElementById('price-result'); 54 const priceValueEl = document.getElementById('price-value'); 55 56 const showPrice = (price) => { 57 if (!priceResultEl || !priceValueEl || !price) { hidePrice(); return; } 58 const nights = Math.round((new Date(checkout) - new Date(checkin)) / 86400000); 59 priceValueEl.textContent = (price * nights).toLocaleString(); 60 priceResultEl.style.display = 'block'; 61 }; 62 const hidePrice = () => { if (priceResultEl) priceResultEl.style.display = 'none'; }; 63 64 // å¿ é è¦ç´ ã®åå¨ãã§ã㯠65 if (!currentCheckinInput || !currentCheckoutInput || !postId || !liveBookingButton || !resultDiv) { 66 console.error("Required element missing for availability check."); 67 return; 68 } 69 70 const checkin = currentCheckinInput.value; 71 const checkout = currentCheckoutInput.value; 72 73 console.log("--- checkAvailability (Overlay) fired ---"); 74 75 // æ¥ä»æªå ¥åã®å ´å 76 if (!checkin || !checkout) { 77 // â ä¿®æ£ç¹â : data-base-href ã«æ»ãã¦ãã¿ã³ãæå¹å 78 const baseHref = liveBookingButton.getAttribute('data-base-href'); 79 if (baseHref) { 80 liveBookingButton.setAttribute('href', baseHref); 81 resetBookingButtonStatus(liveBookingButton, 'äºç´ãã', false); 82 } else { 83 resetBookingButtonStatus(liveBookingButton, 'äºç´ãã', true); 84 } 85 resultDiv.textContent = ''; 86 hidePrice(); 87 return; 88 } 89 90 // ã¯ã©ã¤ã¢ã³ãå´ã§ã®æ¥ä»æ¤è¨¼ 91 const today = new Date(); 92 today.setHours(0, 0, 0, 0); 93 const checkinDate = new Date(checkin); 94 95 if (checkinDate < today) { 96 resultDiv.textContent = 'â éå»ã®æ¥ä»ã¯é¸æã§ãã¾ããã'; 97 resultDiv.style.color = 'red'; 98 resetBookingButtonStatus(liveBookingButton, 'æ¥ä»ã¨ã©ã¼', true); 99 hidePrice(); 100 return; 101 } 102 103 if (checkinDate >= new Date(checkout)) { 104 resultDiv.textContent = 'â ãã§ãã¯ã¢ã¦ãæ¥ã¯ãã§ãã¯ã¤ã³æ¥ããå¾ã«è¨å®ãã¦ãã ããã'; 105 resultDiv.style.color = 'red'; 106 resetBookingButtonStatus(liveBookingButton, 'æ¥ä»ã¨ã©ã¼', true); 107 hidePrice(); 108 return; 109 } 110 111 // ãµã¼ãã¼ãµã¤ãã§ã®å¨åº«ãã§ãã¯ã¸ 112 const data = new URLSearchParams(); 113 data.append('action', 'check_availability'); 114 data.append('post_id', postId); 115 data.append('checkin', checkin); 116 data.append('checkout', checkout); 117 118 // PHPããæ¸¡ããã illiStaysVars.ajaxUrl ãä½¿ç¨ 119 const ajaxUrl = (typeof illiStaysVars !== 'undefined' && illiStaysVars.ajaxUrl) ? illiStaysVars.ajaxUrl : '/wp-admin/admin-ajax.php'; 120 121 resultDiv.textContent = '確èªä¸...'; 122 resultDiv.style.color = 'gray'; 123 liveBookingButton.textContent = '確èªä¸...'; 124 // 確èªä¸ã¯ç¡å¹å 125 resetBookingButtonStatus(liveBookingButton, '確èªä¸...', true); 126 127 fetch(ajaxUrl, { 128 method: 'POST', 129 body: data 130 }) 131 .then(response => response.json()) 132 .then(response => { 133 console.log('Ajax Response:', response); 134 135 // ç©ºå®¤ã»æºå®¤ã«é¢ãããä¾¡æ ¼ã¯å¸¸ã«è¡¨ç¤ºï¼hotel-lowest-price ã¯æ½è¨ã®åºå®ãã£ã¼ã«ãï¼ 136 showPrice(response.data?.price); 137 138 if (response.success && response.data.available) { 139 resultDiv.textContent = `â 空室ãã`; 140 resultDiv.style.color = 'green'; 141 142 // â ä¿®æ£ç¹â : data-base-href ã使ç¨ã㦠URL ãçæ 143 const baseHref = liveBookingButton.getAttribute('data-base-href'); 144 145 if (baseHref) { 146 // ãã¼ã¹URLã«æ¥ä»ãã©ã¡ã¼ã¿ã追å 147 const url = new URL(baseHref); 148 url.searchParams.set('start_date', checkin); 149 url.searchParams.set('end_date', checkout); 150 151 const finalUrl = url.toString(); 152 console.log("Final Booking URL (Overlay):", finalUrl); 153 154 liveBookingButton.setAttribute('href', finalUrl); 155 resetBookingButtonStatus(liveBookingButton, 'äºç´ãã', false); // æå¹å 156 } else { 157 console.error("Base Href is missing."); 158 resultDiv.textContent = 'URLã¨ã©ã¼ãçºçãã¾ããã'; 159 resetBookingButtonStatus(liveBookingButton, 'ã¨ã©ã¼', true); 160 } 161 162 } else { 163 const message = response.data?.message || '鏿ãããæ¥ç¨ã«ç©ºå®¤ãããã¾ããã';
164 resultDiv.textContent = `â ${message}`; 165 resultDiv.style.color = 'red'; 166 resetBookingButtonStatus(liveBookingButton, 'æºå®¤', true); // ç¡å¹å 167 } 168 }) 169 .catch(error => { 170 console.error('Fetch Error:', error); 171 resultDiv.textContent = 'éä¿¡ã¨ã©ã¼ãçºçãã¾ããã'; 172 resultDiv.style.color = 'red'; 173 resetBookingButtonStatus(liveBookingButton, 'ã¨ã©ã¼', true); // ç¡å¹å 174 hidePrice(); 175 }); 176}; 177 178const debouncedCheckAvailability = debounce(checkAvailability, 300); 179 180// â appendTo 弿°ã追å : 181// ã¢ã¼ãã«æã¯ modalContent è¦ç´ ãæ¸¡ãï¼å ã®åä½ãç¶æï¼ 182// ç¬ç«ãã¼ã¸æã¯ null ãæ¸¡ãï¼appendTo ãªãã§ createRangePicker ãå¼ã¶ï¼ 183function initializeAvailabilityChecker(appendTo = null) { 184 const form = document.getElementById('availability-form'); 185 const bookingButton = document.getElementById('booking-button'); 186 const checkinEl = document.getElementById('checkin'); 187 const checkoutEl = document.getElementById('checkout'); 188 189 if (form && bookingButton && checkinEl && checkoutEl) { 190 191 // ååã®ããã«ã¼ãæ®ã£ã¦ããã°ã¯ãªã¼ã³ã¢ãã 192 if (cleanupAvailabilityPicker) { 193 cleanupAvailabilityPicker(); 194 cleanupAvailabilityPicker = null; 195 } 196 197 // appendTo ã null ã®å ´åï¼ç¬ç«ãã¼ã¸ï¼ã¯ãªãã·ã§ã³ã«å«ããªã 198 const { picker, langObserver } = createRangePicker({ 199 checkinEl, 200 checkoutEl, 201 ...(appendTo ? { appendTo } : {}) 202 }); 203 const dragCleanup = addDragRangeSupport(picker); 204 205 cleanupAvailabilityPicker = () => { 206 dragCleanup(); 207 langObserver.disconnect(); 208 picker.destroy(); 209 }; 210 211 // 以ä¸ãæ¢åã®ãã¸ãã¯ãç¶æ 212 if (!bookingButton.getAttribute('data-base-href')) { 213 const baseHref = bookingButton.getAttribute('href') || ''; 214 const cleanBaseHref = baseHref.split('?')[0]; 215 bookingButton.setAttribute('data-base-href', cleanBaseHref); 216 } 217 const initialBaseHref = bookingButton.getAttribute('data-base-href'); 218 if (initialBaseHref) { 219 bookingButton.setAttribute('href', initialBaseHref); 220 resetBookingButtonStatus(bookingButton, 'äºç´ãã', false); 221 } 222 form.addEventListener('submit', function(e) { e.preventDefault(); }); 223 } 224} 225 226 227document.addEventListener('DOMContentLoaded', () => { 228 const modal = document.getElementById('hotelDetailModal'); 229 const modalContent = modal ? document.getElementById('hotelDetailModalContent') : null; 230 231 // ==================================================================== 232 // é²è¦§å±¥æ´ï¼ã¢ã¼ãã«ã»ç¬ç«ãã¼ã¸å ±éï¼ 233 // ==================================================================== 234 235 const HISTORY_KEY = 'viewedHotelsHistory'; 236 const MAX_HISTORY_ITEMS = 20; 237 238 function getHistory() { 239 const historyJson = localStorage.getItem(HISTORY_KEY); 240 return historyJson ? JSON.parse(historyJson) : []; 241 } 242 243 function saveHistory(historyArray) { 244 localStorage.setItem(HISTORY_KEY, JSON.stringify(historyArray)); 245 } 246 247 function addToHistory(hotelData) { 248 let history = getHistory(); 249 history = history.filter(item => item.id !== hotelData.id); 250 history.unshift(hotelData); 251 history = history.slice(0, MAX_HISTORY_ITEMS); 252 saveHistory(history); 253 } 254 255 // â scope 弿°ã追å : ã¢ã¼ãã«æã¯ modal è¦ç´ ãç¬ç«ãã¼ã¸æã¯ document.body ãæ¸¡ã 256 function initializeHistoryView(scope, currentPostId) { 257 const history = getHistory(); 258 const section = scope.querySelector('#recentlyViewedSection'); 259 const listContainer = scope.querySelector('#recentlyViewedList'); 260 261 if (!section || !listContainer) return; 262 263 const filteredHistory = history.filter(item => item.id.toString() !== currentPostId); 264 const displayList = filteredHistory.slice(0, 6); 265 266 listContainer.innerHTML = ''; 267 268 if (displayList.length > 0) { 269 section.style.display = 'block'; 270 271 displayList.forEach(item => { 272 const listItem = document.createElement('li');
273 listItem.className = 'recently-viewed-item'; 274 275 let imageHtml = ''; 276 if (item.thumbnail) { 277 imageHtml = ` 278 <div class="recently-viewed-item__image"> 279 <img src="${item.thumbnail}" alt=""> 280 </div>`; 281 } else { 282 imageHtml = ` 283 <div class="recently-viewed-item__image" data-state="noimage"> 284 <span>No Image</span> 285 </div>`; 286 } 287 288 let locationHtml = ''; 289 if (item.location) { 290 locationHtml = `<p class="recently-viewed-item__location">${item.location}</p>`; 291 } 292 293 listItem.innerHTML = ` 294 <a href="${item.url}" class="js-history-link" data-post-id="${item.id}"> 295 ${imageHtml} 296 <div class="recently-viewed-item__text"> 297 <p class="recently-viewed-item__title">${item.title}</p> 298 ${locationHtml} 299 </div> 300 </a>`; 301 302 listContainer.appendChild(listItem); 303 }); 304 } else { 305 section.style.display = 'none'; 306 } 307 } 308 309 // â scope 弿°ã追å : ã¢ã¼ãã«æã¯ modal è¦ç´ ãç¬ç«ãã¼ã¸æã¯ document.body ãæ¸¡ã 310 function initializeReadMore(scope) { 311 const descriptionAreas = scope.querySelectorAll('.rooms-detail-location__description-area'); 312 if (!descriptionAreas.length) return; 313 descriptionAreas.forEach(area => { 314 const description = area.querySelector('.rooms-detail-location__description p'); 315 const button = area.querySelector('.js-button-viremore--text'); 316 if (!description || !button) return; 317 const lineHeight = parseFloat(window.getComputedStyle(description).lineHeight); 318 const fiveLinesHeight = lineHeight * 5; 319 if (description.scrollHeight > fiveLinesHeight) { 320 area.classList.add('is-clamp-text'); 321 if (!button.dataset.initialized) { 322 button.addEventListener('click', () => area.classList.add('is-opened'), { once: true }); 323 button.dataset.initialized = 'true'; 324 } 325 } 326 }); 327 } 328 329 // â scope 弿°ã追å : ã¢ã¼ãã«æã¯ modal è¦ç´ ãç¬ç«ãã¼ã¸æã¯ document.body ãæ¸¡ã 330 function initializeRoomInfoTabs(scope) { 331 const tabList = scope.querySelector('.room-information-tabs'); 332 if (!tabList) return; 333 if (tabList.dataset.initialized) return; 334 tabList.dataset.initialized = 'true'; 335 336 tabList.addEventListener('click', function(event) { 337 const clickedTab = event.target.closest('button[role="tab"]'); 338 if (!clickedTab) return; 339 340 if (window.innerWidth <= 768) { 341 const detailContainer = scope.querySelector('.rooms-detail'); 342 if (detailContainer) { 343 detailContainer.scrollIntoView({ behavior: 'auto', block: 'start' }); 344 } 345 } else { 346 const infoColumn = scope.querySelector('.rooms-detail-information'); 347 if (infoColumn) { 348 infoColumn.scrollTop = 0; 349 } 350 } 351 352 const allTabs = tabList.querySelectorAll('button[role="tab"]'); 353 allTabs.forEach(tab => { 354 tab.classList.remove('active'); 355 tab.setAttribute('aria-selected', 'false'); 356 }); 357 358 const allContents = scope.querySelectorAll('.room-info-content'); 359 allContents.forEach(content => content.classList.remove('active')); 360 361 clickedTab.classList.add('active'); 362 clickedTab.setAttribute('aria-selected', 'true'); 363 364 const targetIds = clickedTab.dataset.controls.split(' '); 365 targetIds.forEach(id => { 366 if (id) { 367 const targetContent = document.getElementById(id); 368 if (targetContent) { 369 targetContent.classList.add('active'); 370 initializeSwiper(targetContent); 371 resizeAFrameScene(targetContent); 372 } 373 } 374 }); 375 }); 376 } 377 378 function activateTabByHash(scope, hash) { 379 if (!hash) return; 380 const decoded = decodeURIComponent(hash.replace(/^#/, '')); 381 if (!decoded) return; 382 const tabs = scope.querySelectorAll('button[role="tab"]'); 383 for (const tab of tabs) { 384 if (tab.textContent.trim() === decoded) { 385 tab.click(); 386 return; 387 } 388 } 389 } 390 391 // â scope 弿°ã追å : ã¢ã¼ãã«æã¯ modal è¦ç´ ãç¬ç«ãã¼ã¸æã¯ document.body ãæ¸¡ã 392 function initializeEquipmentReadMore(scope) { 393 const equipmentAreas = scope.querySelectorAll('.equipment-contents'); 394 if (!equipmentAreas.length) return; 395 equipmentAreas.forEach(area => { 396 const items = area.querySelectorAll('.equipment-item'); 397 const button = area.querySelector('.js-button-viremore--equipment-area'); 398 if (!items.length || !button) return; 399 const itemCount = items.length; 400 const browserWidth = window.innerWidth; 401 let needsClamp = false;
402 if (browserWidth >= 769 && itemCount >= 10) needsClamp = true; 403 else if (browserWidth <= 768 && itemCount >= 11) needsClamp = true; 404 if (needsClamp) { 405 area.classList.add('is-clamp-equipment'); 406 if (!button.dataset.initialized) { 407 button.addEventListener('click', () => { 408 area.classList.remove('is-clamp-equipment'); 409 area.classList.add('is-opened-equipment'); 410 }, { once: true }); 411 button.dataset.initialized = 'true'; 412 } 413 } 414 }); 415 } 416 417 function initializeSwiper(container) { 418 const sliderContainer = container.querySelector('.room-detail-image-slide'); 419 if (!sliderContainer || sliderContainer.dataset.swiperInitialized) return; 420 const swiperMainEl = sliderContainer.querySelector('.swiper-main'); 421 const swiperThumbEl = sliderContainer.querySelector('.swiper-thumb'); 422 if (!swiperMainEl || !swiperThumbEl) return; 423 424 const mySwiper_thumb = new Swiper(swiperThumbEl, { 425 slidesPerView: 5, 426 spaceBetween: 8, 427 breakpoints: { 428 769: { slidesPerView: 7 }, 429 }, 430 }); 431 432 const mySwiper_main = new Swiper(swiperMainEl, { 433 grabCursor: false, 434 allowTouchMove: false, 435 navigation: { 436 nextEl: sliderContainer.querySelector('.swiper-button-next'), 437 prevEl: sliderContainer.querySelector('.swiper-button-prev'), 438 }, 439 pagination: { 440 el: ".custom-fraction", 441 type: "fraction", 442 renderFraction:function (currentClass, totalClass) { 443 return '<span class="' + currentClass + '"></span>' + 'ï½' + '<span class="' + totalClass + '"></span>'; 444 } 445 }, 446 thumbs: { 447 swiper: mySwiper_thumb, 448 }, 449 }); 450 451 sliderContainer.dataset.swiperInitialized = 'true'; 452 } 453 454 function resizeAFrameScene(container) { 455 const aframeScene = container.querySelector('a-scene'); 456 if (aframeScene && typeof aframeScene.resize === 'function') { 457 setTimeout(() => { 458 aframeScene.resize(); 459 }, 100); 460 } 461 } 462 463 function trapFocus(element) { 464 const focusableElements = Array.from( 465 element.querySelectorAll('a, button, textarea, input, select, [tabindex]:not([tabindex="-1"])') 466 ).filter(el => !el.hasAttribute('disabled') && el.offsetParent !== null); 467 if (focusableElements.length === 0) return () => {}; 468 const firstFocusableElement = focusableElements[0]; 469 const lastFocusableElement = focusableElements[focusableElements.length - 1]; 470 const handleFocusTrap = (event) => { 471 if (event.key === 'Tab') { 472 if (event.shiftKey) { 473 if (document.activeElement === firstFocusableElement) { 474 event.preventDefault(); 475 lastFocusableElement.focus(); 476 } 477 } else { 478 if (document.activeElement === lastFocusableElement) { 479 event.preventDefault(); 480 firstFocusableElement.focus(); 481 } 482 } 483 } 484 }; 485 firstFocusableElement.focus(); 486 element.addEventListener('keydown', handleFocusTrap); 487 return () => { 488 element.removeEventListener('keydown', handleFocusTrap); 489 }; 490 } 491 492 // â scopeã»modalContent 弿°ã追å ï¼ã¢ã¼ãã«å°ç¨é¢æ°ï¼ 493 async function loadContent(url, scope, modalContent) { 494 modalContent.innerHTML = ` 495 <div class="loading-container"> 496 <svg width="200" height="100" viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg"> 497 <g transform="translate(22 10)"> 498 <circle cx="18.445" cy="18.445" r="18.445" class="logo-shape shape-1" /> 499 <path d="M39.408,0 H76.3 V36.89 H56.3 A20,20 0 0 1 39.408,18.445 Z" class="logo-shape shape-2" /> 500 <path d="M78.813,0 H115.7 V36.89 H95.7 A20,20 0 0 1 78.813,18.445 Z" class="logo-shape shape-3" /> 501 <circle cx="136.665" cy="18.445" r="18.445" class="logo-shape shape-4" /> 502 <path fill="#1a1311" d="M101.407,80.572l4.4-8.13-5.7-10.175h3.927l3.706,6.8,3.316-6.8h3.817l-9.65,18.305Zm-38.862-9.4,2.353-2.24a4.318,4.318,0,0,0,3.868,2.461,2.587,2.587,0,0,0,2.848-2.545,2.14,2.14,0,0,0-.717-1.659,8.3,8.3,0,0,0-2.849-1.354,8.9,8.9,0,0,1-3.069-1.6A4.3,4.3,0,0,1,63.512,60.8c0-2.71,1.827-5.42,5.918-5.42a
5027.089,7.089,0,0,1,5.225,2.157L72.775,60a3.6,3.6,0,0,0-3.014-1.577c-1.934,0-2.545,1.218-2.545,2.158a1.557,1.557,0,0,0,.581,1.244,6.354,6.354,0,0,0,2.212,1.051,10.725,10.725,0,0,1,3.735,1.851A5.02,5.02,0,0,1,75.32,68.6c0,3.6-2.6,6.057-6.416,6.057A7.592,7.592,0,0,1,62.545,71.169Zm52.877,1.467,1.77-2.045a3.712,3.712,0,0,0,2.654,1.381c.94,0,1.659-.468,1.659-1.3a1.337,1.337,0,0,0-1.051-1.218l-.773-.275a6.46,6.46,0,0,1-2.572-1.438,3.213,3.213,0,0,1-.912-2.3,3.554,3.554,0,0,1,1.244-2.71,4.938,4.938,0,0,1,3.124-.856,5.975,5.975,0,0,1,3.817,1.271l-1.66,1.965a2.8,2.8,0,0,0-1.963-.8c-.8,0-1.3.387-1.3.968,0,.3.139.774,1.079,1.079l.8.249a6.124,6.124,0,0,1,3.042,1.714,3.477,3.477,0,0,1,.608,1.991,3.977,3.977,0,0,1-1.326,3.039,5.029,5.029,0,0,1-3.6,1.272A6.054,6.054,0,0,1,115.422,72.636ZM85.16,68.24c0-3.54,2.405-6.36,5.946-6.36a4.331,4.331,0,0,1,3.842,1.935V62.266h3.375V74.239H94.947V72.691a4.287,4.287,0,0,1-3.676,1.935A6.075,6.075,0,0,1,85.16,68.24Zm3.484,0a3.319,3.319,0,1,0,3.318-3.373A3.278,3.278,0,0,0,88.644,68.24Zm-38.862,6V62.266h3.373V74.239Zm-19.731,0V62.266h3.373V74.239Zm47.78,0v-9.1H76.906V62.266h1.326V58.173h3.375v4.093h2.322v2.875H81.607v9.1Zm-34.631,0V54.079h3.375V74.238Zm-6.566,0V54.079h3.373V74.238ZM49.851,57.207a2.019,2.019,0,1,1,2.019,2.017A2.029,2.029,0,0,1,49.851,57.207Zm-19.731,0a2.019,2.019,0,1,1,2.019,2.017A2.03,2.03,0,0,1,30.12,57.207Z"/> 503 </g> 504 </svg> 505 </div> 506 `; 507 508 const infoColumn = scope.querySelector('.rooms-detail-information'); 509 if (infoColumn) { 510 infoColumn.scrollTop = 0; 511 } 512 513 try { 514 // const response = await fetch(url); 515 const response = await fetch(url, { 516 headers: { 517 'X-Requested-With': 'modal-request' 518 } 519 }); 520 if (!response.ok) throw new Error('ã³ã³ãã³ãã®èªã¿è¾¼ã¿ã«å¤±æãã¾ããã'); 521 const text = await response.text(); 522 const parser = new DOMParser(); 523 const doc = parser.parseFromString(text, 'text/html'); 524 525 const content = doc.querySelector('.content-main'); 526 527 if (content) { 528 const postId = content.dataset.postId; 529 const postTitle = content.dataset.postTitle; 530 const postUrl = content.dataset.postUrl; 531 const postThumbnail = content.dataset.postThumbnail; 532 const postLocation = content.dataset.postLocation; 533 534 if (postId && postTitle && postUrl) { 535 addToHistory({ 536 id: postId, 537 title: postTitle, 538 url: postUrl, 539 thumbnail: postThumbnail, 540 location: postLocation 541 }); 542 543 if (typeof handleMarkerClick === 'function') { 544 handleMarkerClick(postId); 545 } 546 } 547 548 modalContent.innerHTML = content.innerHTML; 549 550 initializeHistoryView(scope, postId); 551 initializeReadMore(scope); 552 initializeRoomInfoTabs(scope); 553 initializeEquipmentReadMore(scope); 554 555 const activeTabContent = scope.querySelector('.room-info-content.active'); 556 if (activeTabContent) { 557 initializeSwiper(activeTabContent); 558 // â ä¿®æ£ç®æï¼ targetContent ã¨ããæªå®ç¾©ã®å¤æ°åãã¹ã activeTabContent ã«ä¿®æ£ãã¾ãã 559 resizeAFrameScene(activeTabContent); 560 } 561 562 // â ã¨ã©ã¼ãè§£æ¶ããããããããããã«ã¬ã³ãã¼ã®åæåï¼ç¿»è¨³è¨å®å«ãï¼ã確å®ã«å®è¡ããã¾ã 563 initializeAvailabilityChecker(modalContent); 564 565 } else { 566 modalContent.innerHTML = '<p>ã³ã³ãã³ããåå¾ã§ãã¾ããã§ããã</p>'; 567 } 568 } catch (error) { 569 console.error('Fetch Error:', error); 570 modalContent.innerHTML = '<p>ã¨ã©ã¼ãçºçãã¾ããããã¼ã¸ãåèªã¿è¾¼ã¿ãã¦ãã ããã</p>'; 571 } 572 } 573 574 // ==================================================================== 575 // â ã¢ã¼ãã« 576 // #hotelDetailModal ãåå¨ããå ´åã®ã¿èµ·å 577 // ==================================================================== 578 579 if (modal) { 580 const closeButton = modal.querySelector('.hotel-detail-modal__close'); 581 let lastFocusedElement, disableFocusTrap; 582 583 document.body.addEventListener('click', (e) => { 584 const trigger = e.target.closest('.js-show-hotel-detail-modal-toriger'); 585 if (!trigger) return; 586 e.preventDefault(); 587 lastFocusedElement = document.activeElement; 588 const url = trigger.href; 589 const hash = new URL(trigger.getAttribute('href'), location.href).hash; 590 modal.showModal(); 591 fixedBodyOn(); 592 593 modal.scrollTop = 0; 594 595 loadContent(url, modal, modalContent).then(() => { 596 disableFocusTrap = trapFocus(modal); 597 activateTabByHash(modal, hash); 598 }); 599 }); 600 601 modalContent.addEventListener('click', (e) => { 602 const historyLink = e.target.closest('.js-history-link'); 603 if (!historyLink) return; 604 605 e.preventDefault(); 606 const url = historyLink.href; 607 608 if (window.innerWidth <= 768) { 609 const detailContainer = modal.querySelector('.rooms-detail'); 610 if (detailContainer) { 611 detailContainer.scrollIntoView({ behavior: 'auto', block: 'start' }); 612 } 613 } 614 615 loadContent(url, modal, modalContent); 616 }); 617 618 const closeModal = () => { 619 modal.close(); 620 }; 621 closeButton.addEventListener('click', closeModal); 622 modal.addEventListener('click', (e) => { 623 if (e.target === modal) closeModal(); 624 }); 625 modal.addEventListener('close', () => { 626 fixedBodyOff(); 627 if (typeof disableFocusTrap === 'function') disableFocusTrap(); 628 if (cleanupAvailabilityPicker) { 629 cleanupAvailabilityPicker(); 630 cleanupAvailabilityPicker = null; 631 } 632 modalContent.innerHTML = ''; 633 if (lastFocusedElement) lastFocusedElement.focus(); 634 }); 635 636 console.log("â â Event Delegation Listeners Registered (Overlay) â â "); 637 638 // DOMContentLoadedã®æå¾ã«ãAvailabilityCheckerãåæå 639 initializeAvailabilityChecker(modalContent); 640 } 641 642 // ==================================================================== 643 // â¡ ç¬ç«è©³ç´°ãã¼ã¸ 644 // #hotelDetailModal ãåå¨ããã.content-main ãç´æ¥ãã¼ã¸ã«ããå ´åã«èµ·å 645 // ==================================================================== 646 647 if (!modal) { 648 const standaloneContent = document.querySelector('.content-main'); 649 if (!standaloneContent) return; 650 651 // ç¬ç«ãã¼ã¸ã§ãããã¨ã示ãclassãä»ä¸ï¼CSSåºãããç¨ï¼ 652 standaloneContent.classList.add('content-main--standalone'); 653 654 const postId = standaloneContent.dataset.postId; 655 const postTitle = standaloneContent.dataset.postTitle; 656 const postUrl = standaloneContent.dataset.postUrl; 657 const postThumbnail = standaloneContent.dataset.postThumbnail; 658 const postLocation = standaloneContent.dataset.postLocation; 659 660 // é²è¦§å±¥æ´ã«è¿½å 661 if (postId && postTitle && postUrl) { 662 addToHistory({ 663 id: postId, 664 title: postTitle, 665 url: postUrl, 666 thumbnail: postThumbnail, 667 location: postLocation 668 }); 669 } 670 671 // ã¢ã¼ãã«ã¨åãåæåå¦çã document.body ã¹ã³ã¼ãã§å®è¡ 672 initializeHistoryView(document.body, postId); 673 initializeReadMore(document.body); 674 initializeRoomInfoTabs(document.body); 675 initializeEquipmentReadMore(document.body); 676 677 const activeTabContent = document.querySelector('.room-info-content.active'); 678 if (activeTabContent) { 679 initializeSwiper(activeTabContent); 680 resizeAFrameScene(activeTabContent); 681 } 682 683 // appendTo ãªãï¼ç¬ç«ãã¼ã¸ã§ã¯ã¢ã¼ãã«ã³ã³ãããåå¨ããªãããï¼ã§ã«ã¬ã³ãã¼åæå 684 initializeAvailabilityChecker(null); 685 686 activateTabByHash(document.body, window.location.hash); 687
688 console.log("â â Standalone Detail Page Initialized â â "); 689 } 690 691 // change / input ã¯ã¢ã¼ãã«ã»ç¬ç«ãã¼ã¸å ±éã§å§è² 692 document.addEventListener('change', function(e) { 693 if (e.target && (e.target.id === 'checkin' || e.target.id === 'checkout')) { 694 debouncedCheckAvailability(e); 695 } 696 }); 697 698 document.addEventListener('input', function(e) { 699 if (e.target && (e.target.id === 'checkin' || e.target.id === 'checkout')) { 700 debouncedCheckAvailability(e); 701 } 702 }); 703 704}); 705 706 707// ==================================================================== 708// â URLã³ãã¼ãã¿ã³ã®å¦ç 709// ==================================================================== 710document.addEventListener('click', function(e) { 711 const copyBtn = e.target.closest('.js-copy-btn'); 712 if (!copyBtn) return; 713 714 // 1. URLå ¥åæ¬ãæ¢ã 715 const targetInput = document.querySelector('.room-info-content.active .js-url-target') 716 || document.querySelector('.js-url-target'); 717 718 if (!targetInput) return; 719 720 // 2. 䏿çã«é表示ããããã¹ãã«å¤æ´ãã¦é¸æ 721 const originalType = targetInput.type; 722 targetInput.type = "text"; 723 targetInput.style.position = "fixed"; 724 targetInput.style.left = "-9999px"; 725 726 targetInput.select(); 727 728 try { 729 const successful = document.execCommand('copy'); 730 if (successful) { 731 // â æåããå ´åã®ã¿ã¢ã¼ãã«ã表示 732 showClipboardMessage(); 733 } 734 } catch (err) { 735 console.error('ã³ãã¼å¤±æ', err); 736 } 737 738 // 3. å ã«æ»ã 739 targetInput.type = originalType; 740}); 741 742// ã¢ã¼ãã«è¡¨ç¤ºç¨é¢æ° 743function showClipboardMessage() { 744 const messageEl = document.getElementById('clipboardMessage'); 745 if (!messageEl) return; 746 747 // ã¯ã©ã¹ã追å ãã¦è¡¨ç¤ºï¼CSSå´ã§ .is-show ãªã©ãå®ç¾©ãã¦ãã ããï¼ 748 messageEl.classList.add('is-active'); 749 750 // 2ç§å¾ã«ã¯ã©ã¹ãåé¤ 751 setTimeout(() => { 752 messageEl.classList.remove('is-active'); 753 }, 2000); 754}
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.