PageSourceSearch

https://www.e-hokuei.net/ssi/js/jibuntokei.js

js e-hokuei.net collected 2026-10-02 06:10:45 UTC 6,201 bytes, 136 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function() {
2
3	// --- 設定 ---
4	const timeElementId = 'tokei_time';      // 時刻表示要素のID
5	// 画像要素のIDではなく、共通クラス名とIDプレフィックスを使う
6	const imageWrapperId = 'tokei_photo';
7	const imageClass = 'clock-image';
8	const imageIdPrefix = 'clock-image-'; // IDは clock-image-1, clock-image-2 とする
9	const activeClass = 'active';         // 表示中を示すクラス名
10	// 画像の設定
11	const imagePathPrefix = '/img/tokei/photo/'; // 画像ディレクトリのパス
12	const imageExtension = '.jpg';         // 画像の拡張子
13	const defaultImageFile = '00';         // デフォルト画像のファイル名 (拡張子なし)
14	// const fadeDuration = 1000; // フェード時間 (ミリ秒、CSSのtransitionと合わせる)
15
16	// --- 要素の取得 ---
17	const timeElement = document.getElementById(timeElementId);
18	const imageWrapper = document.getElementById(imageWrapperId); // コンテナを取得
19
20	// --- 要素存在チェック ---
21	if (!timeElement) {
22		return;
23	}
24	if (!imageWrapper) {
25		return;
26	}
27	// 画像要素を取得 (2つある想定)
28	const imageElements = imageWrapper.querySelectorAll(`.${imageClass}`);
29	if (imageElements.length < 2) {
30		return;
31	}
32	const image1 = document.getElementById(`${imageIdPrefix}1`);
33	const image2 = document.getElementById(`${imageIdPrefix}2`);
34	if (!image1 || !image2) {
35		return;
36	}
37
38	// --- デフォルト画像のパス ---
39	const defaultImagePath = `${imagePathPrefix}${defaultImageFile}${imageExtension}`;
40
41	// --- 画像読み込みエラー時の処理関数 ---
42	function handleImageError(imgElement) {
43		// エラーが発生したらデフォルト画像を表示
44		// ただし、現在のsrcが既にデフォルト画像の場合は無限ループを防ぐため何もしない
45		const currentSrc = imgElement.src.split('?')[0]; // キャッシュ対策を除いたパス
46		if (currentSrc !== defaultImagePath) {
47			// console.warn(`画像の読み込みに失敗しました: ${imgElement.src}. デフォルト画像を表示します。`);
48			imgElement.src = defaultImagePath + '?t=' + Date.now(); // デフォルト画像にもキャッシュ対策
49			// デフォルト画像のalt属性を設定 (任意)
50			imgElement.alt = `デフォルトの時計画像 (${defaultImageFile}分)`;
51		} else {
52			// console.error(`デフォルト画像 (${defaultImagePath}) の読み込みにも失敗しました。`);
53		}
54		// エラーハンドラは src 設定前に毎回設定するので、ここで null にする必要はない
55	}
56
57	// --- 時刻と画像の更新関数 ---
58	function updateClock() {
59		const now = new Date();
60		const hours = String(now.getHours()).padStart(2, '0');
61		const minutes = String(now.getMinutes()).padStart(2, '0');
62
63		// 1. 時刻表示を更新
64		timeElement.textContent = `${hours}:${minutes}`;
65
66		// 2. 表示する画像パスを生成
67		const imagePath = `${imagePathPrefix}${minutes}${imageExtension}`;
68		const cacheBustedImagePath = imagePath + '?t=' + now.getTime(); // キャッシュ対策
69
70		// 3. 現在アクティブな画像と、次にアクティブにする画像要素を特定
71		const activeImage = imageWrapper.querySelector(`.${imageClass}.${activeClass}`);
72		const inactiveImage = imageWrapper.querySelector(`.${imageClass}:not(.${activeClass})`);
73
74		// 念のため存在チェック
75		if (!activeImage || !inactiveImage) {
76			// console.error('アクティブまたは非アクティブな画像要素が見つかりません。');
77			scheduleNextUpdate(now); // 次の更新だけスケジュールして中断
78			return;
79		}
80
81		// 4. 次に表示する画像のパスが、現在非アクティブな画像のパスと同じかチェック
82		const inactiveBaseSrc = inactiveImage.src.split('?')[0];
83		if (inactiveBaseSrc === imagePath) {
84			// すでに裏で正しい画像が読み込まれている場合 (例: エラーから復帰した場合など)
85			// または初回表示などでまだ src が設定されていない場合
86			if (inactiveImage.src === '' || inactiveBaseSrc === imagePath) {
87				// そのままフェード処理へ進む
88				performFade(activeImage, inactiveImage);
89			}
90			scheduleNextUpdate(now); // 次の更新をスケジュール
91			return; // 画像の再読み込みは不要
92		}
93
94		// 5. 非アクティブな画像要素に新しい画像を設定し、読み込みとエラーハンドラを設定
95		inactiveImage.onerror = () => handleImageError(inactiveImage); // エラーハンドラを設定
96		inactiveImage.onload = () => {
97			// 画像読み込み成功!クロスフェードを実行
98			performFade(activeImage, inactiveImage);
99			// 読み込みが成功したのでハンドラをクリア
100			inactiveImage.onload = null;
101			inactiveImage.onerror = null;
102		};
103
104		// src を設定して読み込み開始
105		inactiveImage.src = cacheBustedImagePath;
106		inactiveImage.alt = `${minutes}分の写真`; // alt属性も更新
107
108		// 6. 次の更新をスケジュール
109		scheduleNextUpdate(now);
110	}
111
112	// --- クロスフェード実行関数 ---
113	function performFade(fadeOutElement, fadeInElement) {
114		fadeOutElement.classList.remove(activeClass); // 古い方をフェードアウト
115		fadeInElement.classList.add(activeClass);    // 新しい方をフェードイン
116	}
117
118	// --- 次の更新をスケジュールする関数 ---
119	function scheduleNextUpdate(currentTime) {
120		const seconds = currentTime.getSeconds();
121		const milliseconds = currentTime.getMilliseconds();
122		const delay = (60 - seconds) * 1000 - milliseconds;
123		setTimeout(updateClock, Math.max(100, delay));
124	}
125
126	// --- 初回実行前の準備 ---
127	// 念のため、初期状態でアクティブでない方の画像の src を空にしておく
128	const initialInactiveImage = imageWrapper.querySelector(`.${imageClass}:not(.${activeClass})`);
129	if (initialInactiveImage) {
130		initialInactiveImage.src = ''; // onload/onerror が意図せず発火するのを防ぐ
131	}
132
133	// --- 初回実行 ---
134	updateClock();
135
136});

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.