PageSourceSearch

https://dfc-kyoto.co.jp/wp-content/themes/dfc-kyoto/assets/js/pdf-gate.js?ver=1786333702

js dfc-kyoto.co.jp collected 2026-09-28 13:39:55 UTC 7,011 bytes, 281 lines download raw bytes

1/**
2 * PDFダウンロードゲート
3 *
4 * .js-pdf-gate クラスが付いたリンクをクリックしたとき、
5 * cookie(フォーム送信済みフラグ)がなければCF7フォームのポップアップを表示し、
6 * あれば data-pdf 属性(なければ href)のPDFを別タブで開く。
7 * フォームは「入力 → 確認 → 送信」の2ステップ構成。
8 * フォーム送信完了(wpcf7mailsent)で cookie を保存し、
9 * 「PDFを開く」ボタンを表示する(自動でのページ遷移はしない)。
10 *
11 * フォーム送信が不要な言語(日本語)では、PHP側から requiresForm が空で渡され、
12 * モーダルも出力されないため、クリックでそのままPDFを別タブで開く。
13 */
14(function () {
15	"use strict";
16
17	const COOKIE_NAME = "dfc_pdf_gate";
18	const COOKIE_VALUE = "1";
19	const COOKIE_DAYS = 7;
20
21	let pendingPdfUrl = "";
22
23	/**
24	 * cookie に送信済みフラグがあるか
25	 */
26	function hasCookie() {
27		return (
28			document.cookie
29				.split("; ")
30				.indexOf(COOKIE_NAME + "=" + COOKIE_VALUE) !== -1
31		);
32	}
33
34	/**
35	 * 送信済みフラグを cookie に保存
36	 */
37	function setCookie() {
38		const expires = new Date();
39		expires.setTime(expires.getTime() + COOKIE_DAYS * 24 * 60 * 60 * 1000);
40		document.cookie =
41			COOKIE_NAME +
42			"=" +
43			COOKIE_VALUE +
44			"; expires=" +
45			expires.toUTCString() +
46			"; path=/; SameSite=Lax";
47	}
48
49	/**
50	 * PDFを別タブで開く(ポップアップブロック時は false を返す)
51	 */
52	function openPdf(url) {
53		const win = window.open(url, "_blank", "noopener");
54		return !!win;
55	}
56
57	/**
58	 * ゲート対象リンクのクリックを購読する
59	 *
60	 * デフォルト挙動(href="#" によるページ上部へのジャンプ等)を常に無効化し、
61	 * PDFのURLをハンドラに渡す。URLが未設定のリンクは何もしない。
62	 */
63	function onGateClick(handler) {
64		document.addEventListener("click", function (e) {
65			const link = e.target.closest("a.js-pdf-gate");
66
67			if (!link) {
68				return;
69			}
70
71			e.preventDefault();
72
73			const url =
74				link.getAttribute("data-pdf") || link.getAttribute("href");
75
76			if (!url || url === "#") {
77				return;
78			}
79
80			handler(url);
81		});
82	}
83
84	function init() {
85		const config = window.dfcPdfGate || {};
86		const modal = document.getElementById("pdf-gate-modal");
87
88		// フォーム送信が不要(日本語)な場合はゲートをかけずに直接PDFを開く
89		if (!config.requiresForm || !modal) {
90			onGateClick(openPdf);
91			return;
92		}
93
94		const content = modal.querySelector(".pdf-gate-modal__content");
95		const errorEl = modal.querySelector(".pdf-gate-modal__error");
96		const fallback = modal.querySelector(".pdf-gate-modal__fallback");
97		const fallbackLink = fallback ? fallback.querySelector("a") : null;
98
99		/**
100		 * フォーム内の入力フィールド一覧(hidden・ボタン類は除く)
101		 */
102		function getFields() {
103			return modal.querySelectorAll(
104				'.wpcf7-form input:not([type="hidden"]):not([type="submit"]):not([type="button"]), .wpcf7-form textarea',
105			);
106		}
107
108		function showError(show) {
109			if (errorEl) {
110				errorEl.hidden = !show;
111			}
112		}
113
114		/**
115		 * 確認ステップへ(入力欄を readonly にして表示を切り替える)
116		 */
117		function enterConfirm() {
118			getFields().forEach(function (el) {
119				el.setAttribute("readonly", "readonly");
120			});
121			modal.classList.add("is-confirm");
122			showError(false);
123			if (content) {
124				content.scrollTop = 0;
125			}
126		}
127
128		/**
129		 * 入力ステップへ戻る
130		 */
131		function exitConfirm() {
132			getFields().forEach(function (el) {
133				el.removeAttribute("readonly");
134			});
135			modal.classList.remove("is-confirm");
136			if (content) {
137				content.scrollTop = 0;
138			}
139		}
140
141		/**
142		 * 確認ステップへ進む前の簡易バリデーション
143		 * (必須未入力・メール等の形式エラーをチェック。最終判定はCF7側で実施)
144		 */
145		function validateForm() {
146			let valid = true;
147			let firstInvalid = null;
148
149			getFields().forEach(function (el) {
150				let ok = true;
151
152				if (
153					"true" === el.getAttribute("aria-required") &&
154					!el.value.trim()
155				) {
156					ok = false;
157				}
158
159				if (ok && el.value && el.checkValidity && !el.checkValidity()) {
160					ok = false;
161				}
162
163				el.classList.toggle("pdf-gate-invalid", !ok);
164
165				if (!ok) {
166					valid = false;
167					if (!firstInvalid) {
168						firstInvalid = el;
169					}
170				}
171			});
172
173			showError(!valid);
174
175			if (firstInvalid) {
176				firstInvalid.focus();
177			}
178
179			return valid;
180		}
181
182		function openModal(url) {
183			pendingPdfUrl = url;
184
185			// 送信完了後に表示する「PDFを開く」ボタンを準備
186			if (fallback) {
187				fallback.hidden = true;
188			}
189			if (fallbackLink) {
190				fallbackLink.setAttribute("href", url);
191			}
192
193			exitConfirm();
194			showError(false);
195			modal.classList.remove("is-sent");
196			modal.classList.add("is-open");
197			modal.setAttribute("aria-hidden", "false");
198			document.body.classList.add("pdf-gate-open");
199		}
200
201		function closeModal() {
202			modal.classList.remove("is-open");
203			modal.setAttribute("aria-hidden", "true");
204			document.body.classList.remove("pdf-gate-open");
205			exitConfirm();
206		}
207
208		// ゲート対象リンクのクリック
209		onGateClick(function (url) {
210			if (hasCookie()) {
211				openPdf(url);
212				return;
213			}
214
215			openModal(url);
216		});
217
218		// モーダル内のクリック(閉じる・確認へ進む・戻る)
219		modal.addEventListener("click", function (e) {
220			if (e.target.closest(".js-pdf-gate-close")) {
221				e.preventDefault();
222				closeModal();
223				return;
224			}
225
226			if (e.target.closest(".pdf-gate-confirm-btn")) {
227				e.preventDefault();
228				if (validateForm()) {
229					enterConfirm();
230				}
231				return;
232			}
233
234			if (e.target.closest(".pdf-gate-back-btn")) {
235				e.preventDefault();
236				exitConfirm();
237			}
238		});
239
240		// ESCキーで閉じる
241		document.addEventListener("keydown", function (e) {
242			if (e.key === "Escape" && modal.classList.contains("is-open")) {
243				closeModal();
244			}
245		});
246
247		// CF7バリデーションエラー・送信失敗時は入力ステップに戻す(エラー表示を見せるため)
248		["wpcf7invalid", "wpcf7spam", "wpcf7mailfailed"].forEach(
249			function (eventName) {
250				document.addEventListener(eventName, function (e) {
251					if (modal.contains(e.target)) {
252						exitConfirm();
253					}
254				});
255			},
256		);
257
258		// CF7送信完了
259		document.addEventListener("wpcf7mailsent", function (e) {
260			// このモーダル内のフォーム以外(お問い合わせページ等)は対象外
261			if (!modal.contains(e.target)) {
262				return;
263			}
264
265			setCookie();
266			exitConfirm();
267			modal.classList.add("is-sent");
268
269			// 自動では開かず、「PDFを開く」ボタンからユーザー操作で開いてもらう
270			if (fallback && pendingPdfUrl) {
271				fallback.hidden = false;
272			}
273		});
274	}
275
276	if ("loading" === document.readyState) {
277		document.addEventListener("DOMContentLoaded", init);
278	} else {
279		init();
280	}
281})();

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.