PageSourceSearch

https://www.veltra.com/_drive/veltra-footer.js?v=39

js veltra.com collected 2026-09-24 08:59:27 UTC 16,309 bytes, 231 lines download raw bytes

1/*
2  veltra-footer.js — VELTRA Drive 共通グローバルフッター(全 Drive ユーザー向けページ共通・レスポンシブ)
3  使い方(home / place / theme / search / detail / legal など全ページ共通):
4    <div data-vw-footer></div>
5    <script src="veltra-footer.js" defer></script>
6  ・mount: [data-vw-footer] があればそこへ、無ければ <body> 末尾へ自動追加。
7  ・CSS は .vw-footer 名前空間 + ブランドトークン fallback 内蔵 → 単体でもホスト埋め込みでも崩れない。
8
9  正式版(FOOTER-1・uxagent ChangeSpec + mock footer-v1.html・user 二木 承認 2026-07-08・bd uxagent-h9mt):
10    上段=サービス導線 4 群(顧客の利用優先度順): Support / Other Services / Partnerships / Company。
11      タブ挙動=本番 base=www.veltra.com/en 前提で「離脱かどうか」で判定: veltra 圏内(www.veltra.com/*・
12      support/feature/corp サブドメイン)は同一タブ。別サービスの Hawaii Activities のみ別タブ(blank:true)。
13      外部指標アイコン(↗)は付けない(圏内リンクに離脱感を出さない)。
14    下段=薄い区切り線の下に法務 3 リンク(中央・淡い縦棒区切り・drive 内部 /legal/{type} 同一サイト遷移)
15      +コピーライト『© {現在年} VELTRA Corporation or its affiliates』(年は自動更新・中央)。
16    レスポンシブ: PC(≥761)=4 列全展開(chevron なし)。モバイル(≤760)=旅行者が使う Support/Other Services は
17      常時展開、旅行者に無関係な Partnerships(出品者向け)/Company(会社・IR)はアコーディオン(既定=閉・
18      chevron・タップ展開・群独立)=優先順位の表明。
19  正本ルール = veltra/design/veltra-brand-core/CHANGES.md §FOOTER-1。
20*/
21(function () {
22  'use strict';
23
24  // ---- 1) CSS(.vw-footer 名前空間・トークン fallback はブランド既定値)----
25  var css = '' +
26  '.vw-footer{background:var(--footer-bg,#F7F7F7);color:var(--ink,#2D1C21);border-top:1px solid var(--line,#ece5d8);font-family:var(--body,\'Inter\',\'Noto Sans JP\',system-ui,sans-serif);line-height:1.55}' +
27  '.vw-footer *{box-sizing:border-box}' +
28  '.vw-footer .vwf-wrap{max-width:1200px;margin:0 auto;padding:48px 32px 30px}' +
29  // 上段: サービス導線 4 群
30  '.vw-footer .vwf-cols{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:28px 48px}' +
31  '.vw-footer .vwf-h{font-family:var(--en,\'Inter\',sans-serif);font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--label,#6b625a);margin:0 0 14px;overflow-wrap:anywhere}' +
32  '.vw-footer .vwf-links{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:11px}' +
33  '.vw-footer .vwf-links a{color:var(--ink,#2D1C21);text-decoration:none;font-size:14px;line-height:1.35;overflow-wrap:anywhere}' +
34  '.vw-footer .vwf-links a:hover{color:var(--blue-deep,#5B86A8);text-decoration:underline;text-underline-offset:2px}' +
35  // 下段: 法務(内部・同一サイト遷移)+ コピーライト
36  '.vw-footer .vwf-bar{margin-top:38px;padding-top:22px;border-top:1px solid var(--line,#ece5d8);text-align:center}' +
37  '.vw-footer .vwf-legal{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:0 4px;margin:0}' +
38  '.vw-footer .vwf-legal a{color:var(--ink,#2D1C21);text-decoration:none;font-size:13px;line-height:1.9;padding:0 10px}' +
39  '.vw-footer .vwf-legal a:hover{color:var(--blue-deep,#5B86A8);text-decoration:underline;text-underline-offset:2px}' +
40  '.vw-footer .vwf-legal .sep{color:var(--line,#ece5d8);font-size:12px;user-select:none}' +
41  '.vw-footer .vwf-copy{margin-top:12px;font-family:var(--en,\'Inter\',sans-serif);font-size:11.5px;color:var(--muted,#8a8077);letter-spacing:.01em}' +
42  // モバイル(≤760): 全群を縦積み。Support/Other Services は常時展開、Partnerships/Company(.vwf-collapsible)はアコーディオン(既定=閉)。
43  '@media(max-width:760px){' +
44    '.vw-footer .vwf-wrap{padding:22px 20px 26px}' +
45    '.vw-footer .vwf-cols{grid-template-columns:1fr;gap:0}' +
46    '.vw-footer .vwf-col{border-bottom:1px solid var(--line,#ece5d8);padding:16px 2px}' +
47    '.vw-footer .vwf-col:first-child{padding-top:0}' +
48    '.vw-footer .vwf-col:last-child{border-bottom:none}' +
49    '.vw-footer .vwf-h{margin:0 0 12px}' +
50    '.vw-footer .vwf-links{gap:12px}' +
51    '.vw-footer .vwf-collapsible .vwf-h{display:flex;align-items:center;justify-content:space-between;margin:0;cursor:pointer}' +
52    '.vw-footer .vwf-collapsible .vwf-h::after{content:\'\';width:8px;height:8px;border-right:2px solid var(--muted,#8a8077);border-bottom:2px solid var(--muted,#8a8077);transform:rotate(45deg);transition:transform .18s;margin:-4px 4px 0 8px;flex:none}' +
53    '.vw-footer .vwf-collapsible.open .vwf-h::after{transform:rotate(225deg);margin-top:3px}' +
54    '.vw-footer .vwf-collapsible .vwf-links{display:none;padding-top:14px}' +
55    '.vw-footer .vwf-collapsible.open .vwf-links{display:flex}' +
56    '.vw-footer .vwf-bar{margin-top:22px;padding-top:20px}' +
57    '.vw-footer .vwf-legal a{padding:0 8px;font-size:13px}' +
58  '}';
59
60  // ---- 2) リンク定義(ここを差し替えれば全ページ一括反映=共通モジュールの肝)----
61  //   上段 4 群(利用優先度順)。mcol=モバイルでアコーディオン畳み対象(旅行者に直接関係ない群)。
62  //   blank=別タブ(別サービスの Hawaii Activities のみ・他は veltra 圏内で同一タブ・↗指標なし)。
63  var COLS = [
64    { h: 'Support', links: [
65      { t: 'Help Center', href: 'https://support.veltra.com/en/support/' }
66    ] },
67    { h: 'Other Services', links: [
68      // #72-4: 日本語サイトへの導線は公開に ja がある間だけ出す(en 単独公開の間は非表示・複数公開で自動復活)。
69      { t: 'VELTRA (Japanese Site)', href: 'https://www.veltra.com/jp/', needsLocale: 'ja' },
70      // 行き先は www.veltra.com 側の入口(core が中継)。ドメインをまたがせないのは、TA(トラベルエージェント)が
71      //   ログイン中に踏むとセッションが切れて手数料の紐付けが落ちるため。一般のお客様は core 側の 301 で
72      //   従来どおり hawaiiactivities.com へ着く(=到達先は変わらない)。
73      { t: 'Hawaii Activities', href: 'https://www.veltra.com/en/hawaii/', blank: true }
74    ] },
75    { h: 'Partnerships', mcol: true, links: [
76      { t: 'Supplier Sign-in', href: 'https://www.veltra.com/ptr/' },
77      { t: 'Add Your Activity', href: 'https://feature.veltra.com/en/partner/' }
78    ] },
79    { h: 'Company', mcol: true, links: [
80      { t: 'About Us', href: 'https://corp.veltra.com/en' },
81      { t: 'Investor Relations', href: 'https://corp.veltra.com/en/ir.html' }
82    ] }
83  ];
84  //   下段 法務 3 リンク(drive 内部・同一サイト遷移)。type=commons 法務 API のキー(/{locale}/legal/{type} ルートと一致)。
85  //   ラベルは commons の正名。URL は locale prefix(サイトの /{locale}/ 正準・多言語 ready)=現ページの locale を path 先頭から導出。
86  var LEGAL = [
87    { t: 'Conditions of Use', type: 'terms-of-service' },
88    { t: 'Privacy Notice', type: 'privacy' },
89    { t: 'Cookie Policy', type: 'cookie-policy' }
90  ];
91  // 現ページの locale(path 先頭 2 文字・例 /en/... → 'en')。footer は /{locale}/... のページにのみ出るので先頭=locale。既定 en。
92  // ★2 文字しか見ておらず /zh-tw /zh-cn で必ず 'en' に落ちていた(二木様 2026-07-28『移動する度に英語に戻る』の
93  //   真因の 1 つ=フッターの法務リンクが英語面へ飛んでいた)。ヘッダー側と同じ規則に揃える。
94  function pageLocale(){ var m=(location.pathname||'').match(/^\/([a-z]{2}(?:-[a-z]+)?)(?:\/|$)/); return m ? m[1] : 'en'; }
95  // #72-4: 一般公開している locale(公開面契約 DRIVE_PUBLISHED_LOCALES)を <html data-vw-langs> から読む(header と同規約)。
96  //   属性不在時は ['en']=安全側(言語リンク非表示)。単一源=SSR が <html data-vw-langs> に焼く DRIVE_PUBLISHED_LOCALES。
97  function pubLocales(){
98    var raw = (document.documentElement.getAttribute('data-vw-langs') || 'en');
99    var a = raw.split(',').map(function(s){ return s.trim(); }).filter(Boolean);
100    return a.length ? a : ['en'];
101  }
102  // client JS gettext(英語ソース→ja)。辞書外(Hawaii Activities 等のサービス/ブランド名・法人名)は英語据置=en は byte 不変。
103  // ★2026-07-28: 日本語しか無く、繁体字/簡体字/韓国語のフッターは英語のまま出ていた。
104  //   フッターは画面上で組み立てるので、配信された HTML を見る検査では**見えã
104ªã„**(実測の死角だった)。
105  //   ★法務文書のラベル(利用規約・プライバシー・Cookie)は **ここに書かない**。正本は commons で、
106  //     サーバが <html data-vw-legal> に載せたものを読む(訳を2か所に持つと必ず片方が腐るため)。
107  //     ja の 3 行だけは commons 未供給時の縮退用として従来から残っている。
108  var I18N = {
109    ja: {
110      'Support': 'サポート', 'Help Center': 'ヘルプセンター',
111      'Other Services': 'その他のサービス', 'VELTRA (Japanese Site)': 'VELTRA(日本語サイト)',
112      'Partnerships': 'パートナー', 'Supplier Sign-in': 'サプライヤーログイン', 'Add Your Activity': 'アクティビティを掲載',
113      'Company': '会社情報', 'About Us': '会社概要', 'Investor Relations': '投資家情報',
114      'Conditions of Use': '利用規約', 'Privacy Notice': 'プライバシーポリシー', 'Cookie Policy': 'Cookieポリシー',
115      'VELTRA Corporation or its affiliates': 'VELTRA Corporation およびその関連会社',
116      'Legal': '法務'
117    },
118    'zh-tw': {
119      'Support': '客戶服務', 'Help Center': '幫助中心',
120      'Other Services': '其他服務', 'VELTRA (Japanese Site)': 'VELTRA(日文網站)',
121      'Partnerships': '合作夥伴', 'Supplier Sign-in': '供應商登入', 'Add Your Activity': '刊登您的體驗',
122      'Company': '公司資訊', 'About Us': '關於我們', 'Investor Relations': '投資人關係',
123      'VELTRA Corporation or its affiliates': 'VELTRA Corporation 或其關聯公司',
124      'Legal': '法律資訊'
125    },
126    'zh-cn': {
127      'Support': '客户服务', 'Help Center': '帮助中心',
128      'Other Services': '其他服务', 'VELTRA (Japanese Site)': 'VELTRA(日文网站)',
129      'Partnerships': '合作伙伴', 'Supplier Sign-in': '供应商登录', 'Add Your Activity': '刊登您的体验',
130      'Company': '公司信息', 'About Us': '关于我们', 'Investor Relations': '投资者关系',
131      'VELTRA Corporation or its affiliates': 'VELTRA Corporation 或其关联公司',
132      'Legal': '法律信息'
133    },
134    ko: {
135      'Support': '고객 지원', 'Help Center': '헬프 센터',
136      'Other Services': '기타 서비스', 'VELTRA (Japanese Site)': 'VELTRA (일본어 사이트)',
137      'Partnerships': '파트너', 'Supplier Sign-in': '공급업체 로그인', 'Add Your Activity': '체험 등록하기',
138      'Company': '회사 정보', 'About Us': '회사 소개', 'Investor Relations': '투자자 정보',
139      'VELTRA Corporation or its affiliates': 'VELTRA Corporation 또는 그 계열사',
140      'Legal': '법적 고지'
141    }
142  };
143;
144  function tr(s){ var d = I18N[pageLocale()]; return (d && d[s]) || s; }
145
146  // ---- 3) markup 生成 ----
147  function esc(s){ return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
148  function colHTML(c){
149    var pub = pubLocales();
150    var items = c.links.map(function(l){
151      var tab = l.blank ? ' target="_blank" rel="noopener"' : '';
152      // #72-4: 言語リンク(needsLocale)は【削除せず】、その locale が非公開の間だけ <li> を display:none で隠す
153      //   (構造温存・多言語再開は display を戻すだけ)。公開されれば自動で表示に戻る。
154      var hidden = l.needsLocale && pub.indexOf(l.needsLocale) < 0;
155      return '<li' + (hidden ? ' style="display:none"' : '') + '><a href="' + esc(l.href) + '"' + tab + '>' + esc(tr(l.t)) + '</a></li>';
156    }).join('');
157    return '<div class="vwf-col' + (c.mcol ? ' vwf-collapsible' : '') + '"><h3 class="vwf-h">' + esc(tr(c.h)) + '</h3><ul class="vwf-links">' + items + '</ul></div>';
158  }
159  // 法務リンクのラベルは **commons の正名**(訳の正本は commons・ここに訳を書き写さない=二重管理にしない)。
160  //   サーバが現ページの locale で引いた {type: title} を <html data-vw-legal='{"…"}'> に載せてくれる(全ページ 1 箇所)。
161  //   ★新しい通信は足さない(フッターは JS 後追い描画なので、ここで fetch するとファーストビューが揺れる)。
162  //   供給が無い時は従来どおり内蔵ラベル(英語 / 日本語)へ縮退=壊れない。
163  function legalLabels(){
164    try {
165      var raw = document.documentElement.getAttribute('data-vw-legal');
166      return raw ? JSON.parse(raw) : null;
167    } catch (e) { return null; }
168  }
169  function legalHTML(){
170    var loc = pageLocale();
171    var supplied = legalLabels();
172    var parts = [];
173    for (var i = 0; i < LEGAL.length; i++) {
174      if (i) parts.push('<span class="sep" aria-hidden="true">|</span>');
175      var label = (supplied && supplied[LEGAL[i].type]) || tr(LEGAL[i].t);
176      parts.push('<a href="/' + loc + '/legal/' + esc(LEGAL[i].type) + '">' + esc(label) + '</a>');
177    }
178    return '<nav class="vwf-legal" aria-label="' + esc(tr('Legal')) + '">' + parts.join('') + '</nav>';
179  }
180  function footerHTML(){
181    var year = new Date().getFullYear();  // 年は自動更新
182    return '<footer class="vw-footer"><div class="vwf-wrap">' +
183      '<div class="vwf-cols">' + COLS.map(colHTML).join('') + '</div>' +
184      '<div class="vwf-bar">' + legalHTML() +
185        '<div class="vwf-copy">© ' + year + ' ' + esc(tr('VELTRA Corporation or its affiliates')) + '</div>' +   // yyzyn-c: ©行も辞書経由(法人名 VELTRA Corporation は固有名=翻訳しない)
186      '</div>' +
187    '</div></footer>';
188  }
189
190  // ---- 4) mount ----
191  function mount(){
192    if (!document.getElementById('vw-footer-style')) {
193      var st = document.createElement('style');
194      st.id = 'vw-footer-style';
195      st.textContent = css;
196      document.head.appendChild(st);
197    }
198    var slot = document.querySelector('[data-vw-footer]');
199    var wrap = document.createElement('div');
200    wrap.innerHTML = footerHTML();
201    var node = wrap.firstChild;
202    if (slot) { slot.replaceWith(node); } else { document.body.appendChild(node); }
203
204    // モバイル(≤760)のみ: Partnerships/Company(.vwf-collapsible)をアコーディオン開閉(群独立・既定=閉)。
205    //   Support/Other Services は常時展開。PC は全群 4 列展開・chevron なし。a11y=role=button + aria-expanded 連動。
206    var mq = window.matchMedia('(max-width:760px)');
207    node.querySelectorAll('.vwf-col.vwf-collapsible').forEach(function(col){
208      var h = col.querySelector('.vwf-h');
209      h.setAttribute('role', 'button');
210      h.setAttribute('aria-expanded', 'false');
211      h.addEventListener('click', function(){
212        if (!mq.matches) return;
213        var open = col.classList.toggle('open');
214        h.setAttribute('aria-expanded', open ? 'true' : 'false');
215      });
216    });
217    // デスクトップへ広げたら畳み状態をリセット(中途半端な open を残さない)
218    mq.addEventListener('change', function(e){
219      if (!e.matches) node.querySelectorAll('.vwf-col.vwf-collapsible.o
219pen').forEach(function(c){
220        c.classList.remove('open');
221        c.querySelector('.vwf-h').setAttribute('aria-expanded', 'false');
222      });
223    });
224  }
225
226  if (document.readyState === 'loading') {
227    document.addEventListener('DOMContentLoaded', mount);
228  } else {
229    mount();
230  }
231})();

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.