PageSourceSearch

https://www.town.soeda.fukuoka.jp/ssi/js/common.js

js town.soeda.fukuoka.jp collected 2026-10-02 16:41:04 UTC 45,082 bytes, 1,383 lines download raw bytes

1/* ==================================================
2common.js
3================================================== */
4
5// 要素の存在判定
6/*
7	概要:
8		要素の存在判定
9	使用例:
10		if(domExistCheck(elements)) {
11			要素がすべて存在するときの処理
12		}
13	引数:
14		配列を渡します。
15		例1)要素が一つのとき
16			let elements = [element1];
17			domExistCheck(elements);
18			または
19			domExistCheck([element1]);
20		例2)要素が複数のとき
21			let elements = [element1,element2,element3];
22			domExistCheck(elements);
23	返り値:
24		すべての要素が存在すれば true,要素が一つでも存在しなければ falseを返します。
25*/
26function domExistCheck(elements) {
27	return elements.every(element => element);
28}
29
30// 通常の文字サイズで印刷
31/*
32	概要:
33		印刷用ページ表示
34	使用例:
35		print_normal();
36	引数
37		無し
38	詳細:
39		- bodyおよび#print_mode_linkにクラスview_print_modeを追加
40		- /ssi/css/print-preview.css をheadに読み込み/削除
41*/
42function print_normal() {
43	const bodyElement = document.querySelector('body');
44	const headElement = document.querySelector('head');
45	const printCssElement = document.querySelector('link[href*="print-preview.css"]');
46	const printLinkElement = document.querySelector('#print_mode_link');
47
48	let printLinkText  = '';
49	if (printLinkElement.classList.contains('view_print_mode')) {
50		printLinkText = '印刷ページ表示';
51	} else {
52		printLinkText = '通常ページへ戻る';
53	}
54
55	if (printLinkElement.classList.contains('view_print_mode')) {
56		// 印刷ページ表示中→通常ページへ
57		initColorMode(); // 背景色を再設定
58		if (printCssElement != null) {
59			printCssElement.remove();
60		}
61		printLinkElement.textContent = printLinkText;
62		printLinkElement.classList.remove('view_print_mode');
63		bodyElement.classList.remove('view_print_mode');
64	} else {
65		// 通常ページ→印刷ページへ
66		initColorMode(0); // 背景色を一時的に初期化
67		headElement.insertAdjacentHTML('beforeend', '<link rel="stylesheet" href="/ssi/css/print-preview.css">');
68		printLinkElement.textContent = printLinkText;
69		printLinkElement.classList.add('view_print_mode');
70		bodyElement.classList.add('view_print_mode');
71	}
72	window.scroll({ top: 0 });
73}
74
75// 色変更
76/*
77	概要:
78		背景色変更
79	使用例・詳細:
80		colorChange('blue');
81			- 青(bodyにクラス color_change,color_blue が追加される)
82		colorChange('black');
83			- 黒(bodyにクラス color_change,color_black が追加される)
84		colorChange();
85		colorChange('init');
86		colorChange('white');
87			- 通常のページに初期化。
88*/
89function colorChange(strColorMode) {
90	const bodyElement = document.querySelector('body');
91	const headElement = document.querySelector('head');
92	const colorCssElement = document.querySelector('link[href*="/ssi/css/color-"]');
93	if (colorCssElement != null) {
94		colorCssElement.remove();
95	}
96	// 引数がない場合は初期化
97	if (typeof strColorMode === 'undefined') {
98		strColorMode = 'init';
99	}
100
101	bodyElement.classList.remove('color_change','color_blue','color_black');
102	switch (strColorMode) {
103		case 'blue':
104			bodyElement.classList.add('color_change','color_blue');
105			headElement.insertAdjacentHTML('beforeend', '<link rel="stylesheet" href="/ssi/css/color-common.css" media="screen">');
106			sessionStorage.setItem('colorMode', 'blue');
107			break;
108		case 'black':
109			bodyElement.classList.add('color_change','color_black');
110			headElement.insertAdjacentHTML('beforeend', '<link rel="stylesheet" href="/ssi/css/color-common.css" media="screen">');
111			sessionStorage.setItem('colorMode', 'black');
112			break;
113		case 'white':
114		case 'init':
115		default:
116			sessionStorage.removeItem('colorMode');
117			break;
118	}
119}
120
121// 色変更されていれば、ページ読み込み時にそれを反映
122/*
123	概要:
124		背景色変更の読み込み
125	使用例・詳細:
126		initColorMode();
127			- ページ読み込み時に、設定されている背景色変更を適用
128		initColorMode(0);
129			- 背景色変更を初期化(保存はされず、ページ遷移・再読み込み等で再び背景色が適用される。
130			印刷ページ表示など、一時的に背景色を初期化したいときに使用。
131*/
132function initColorMode(arg) {
133	if (arg == 0) {
134		const colorCssElement = document.querySelector('link[href*="/ssi/css/color-"]');
135		if (colorCssElement != null) {
136			colorCssElement.remove();
137		}
138	} else {
139		if( ('sessionStorage' in window) && (window.sessionStorage !== null) ) {
140			if(sessionStorage.getItem('colorMode')){
141				colorChange(sessionStorage.getItem('colorMode'));
142			}
143		}
144	}
145}
146
147// 色変更(前スクリプトとの互換性保持)
148/*
149	概要:
150		背景色変更
151		※古いバージョンのCMSと互換性を保つために関数名を同じにしている。
152	使用例・詳細:
153		SetCss(1); → 背景色を白色にする。(標準)
154		SetCss(2); → 背景色を黒色にする。(標準)
155		SetCss(3); → 背景色を青色にする。(標準)
156	引数:
157		半角数値(1~3)
158	返り値:
159		無し
160*/
161function SetCss(cssNumber) {
162	// 引数がない場合は1に設定
163	if (typeof cssNumber === 'undefined') {
164		cssNumber = 1;
165	}
166	switch (cssNumber) {
167		case 1:  colorChange('white');break;
168		case 2:  colorChange('black');break;
169		case 3:  colorChange('blue');break;
170		default: break;
171	}
172}
173
174// 文字サイズ変更
175/*
176	概要:
177		文字サイズを変更する。
178		拡大は3回まで。(変更する場合はmaxFontSizeStepの値を変えてください)
179	使用例:
180		fontSizeChange('large'); → - 文字を大きくする。
181		fontSizeChange('small'); → - 文字を小さくする。
182		fontSizeChange(); → - 文字サイズを初期化(引数がない場合は、default が適用される。)
183		fontSizeChange('default'); → - 文字サイズ変更を初期化
184	引数:
185		'large' , 'small' , 'default'
186	返り値:
187		無し
188*/
189function fontSizeChange(changeType) {
190	const stepNum = 1.25; // 拡大率
191	const maxFontSizeStep = 3; // 拡大を押せる最大回数
192	const bodyElement = document.querySelector('body');
193	let classChk = bodyElement.classList.contains('font_size_changed');
194	let htmlElement = document.querySelector('html');
195	let htmlSTyle = window.getComputedStyle(htmlElement);
196	let currentFontSize = 10;
197	// const maxFontSize = 20;
198	// const minFontSize = 10;
199	let fontSizeStep = 0;
200	const fontSizeLargeButton = document.querySelector('#moji_large');
201	const fontSizeSmallButton = document.querySelector('#moji_small');
202
203	// フォント拡大回数の読み込み
204	if (sessionStorage.getItem('fontSizeStep')) {
205		fontSizeStep = parseInt(sessionStorage.getItem('fontSizeStep'));
206	}
207
208	// 引数がないときにはdefaultを設定
209	if (typeof changeType === 'undefined') {
210		changeType = 'default';
211	}
212
213	switch(changeType) {
214		case 'large':
215			currentFontSize = parseInt(htmlSTyle.getPropertyValue('font-size'));
216			currentFontSize = currentFontSize * stepNum;
217			fontSizeStep = fontSizeStep + 1;
218			if (fontSizeStep <= maxFontSizeStep) {
219				htmlElement.style.fontSize = currentFontSize + 'px';
220				sessionStorage.setItem('fontSize', currentFontSize);
221				sessionStorage.setItem('fontSizeStep', fontSizeStep);
222			} else {
223				break;
224			}
225			if (typeof classChk !== 'undefined') {
226				bodyElement.classList.add('font_size_changed');
227			}
228			break;
229		case 'small':
230			currentFontSize = parseInt(htmlSTyle.getPropertyValue('font-size'));
231			currentFontSize = currentFontSize / stepNum;
232			fontSizeStep = fontSizeStep - 1;
233			if (fontSizeStep > 0) {
234				htmlElement.style.fontSize = currentFontSize + 'px';
235				sessionStorage.setItem('fontSize', currentFontSize);
236				sessionStorage.setItem('fontSizeStep', fontSizeStep);
237			} else if (fontSizeStep == 0) {
238				htmlElement.style.fontSize = '';
239				sessionStorage.removeItem('fontSize');
240				sessionStorage.removeItem('fontSizeStep');
241				if (fontSizeSmallButton !== null) {
242					fontSizeSmallButton.inert = true;
243				}
244			} else {
245				break;
246			}
247			if (typeof classChk !== 'undefined') {
248				bodyElement.classList.add('font_size_changed');
249			}
250			break;
251		case 'default':
252		default:
253			htmlElement.style.fontSize = '';
254			sessionStorage.removeItem('fontSize');
255			sessionStorage.removeItem('fontSizeStep');
256			if (fontSizeSmallButton !== null) {
257				fontSizeSmallButton.inert = true;
258			}
259			fontSizeLargeButton.inert = false;
260			fontSizeStep = 0;
261			if (typeof classChk !== 'undefined') {
262				bodyElement.classList.remove('font_size_changed','font_size_limit_max');
263			}
264			break;
265	}
266	// 拡大が最大回数の時にinert属性とクラスを追加
267	if (fontSizeStep >= maxFontSizeStep) {
268		fontSizeLargeButton.inert = true;
269		bodyElement.classList.add('font_size_limit_max');
270	} else {
271		fontSizeLargeButton.inert = false;
272	}
273	// 縮小ボタン
274	if (fontSizeStep <= 0) {
275		if (fontSizeSmallButton !== null) {
276			fontSizeSmallButton.inert = true;
277		}
278	} else {
279		if (fontSizeSmallButton !== null) {
280			fontSizeSmallButton.inert = false;
281		}
282	}
283}
284
285// 文字サイズ変更の読み込み
286/*
287	概要:
288		文字サイズの変更を読み込み
289	使用例:
290		initFontSize();
291	引数:
292		無し
293	返り値:
294		無し
295	詳細:
296		- ページ表示時に実行する。(DOM構築後に実行すること。)
297*/
298function initFontSize() {
299	if( ('sessionStorage' in window) && (window.sessionStorage !== null) ) {
300		if (sessionStorage.getItem('fontSize')) {
301			let bodyElement = document.querySelector('body');
302			let currentFontSize = sessionStorage.getItem('fontSize');
303			let fontSizeLargeButton = document.querySelector('#moji_large');
304			let currentFontSizeStep = parseInt(sessionStorage.getItem('fontSizeStep'));
305			// 拡大回数が最大のときは拡大ボタンを押せないようにする。
306			if (currentFontSizeStep === 3) {
307				if (fontSizeLargeButton != null) {
308					fontSizeLargeButton.inert = true;
309					bodyElement.classList.add('font_size_limit_max');
310				}
311			}
312			bodyElement.classList.add('font_size_changed');
313			$('html').css('font-size',currentFontSize + 'px');
314		} else {
315			// フォントサイズの設定がない場合は縮小ボタンを非活性に。
316			let fontSizeSmallButton = document.querySelector('#moji_small');
317			if (fontSizeSmallButton !== null) {
318				fontSizeSmallButton.inert = true;
319			}
320		}
321	}
322}
323// 文字サイズ変更(前スクリプトとの互換性保持)
324function fsc(str) {
325	switch(str) {
326		case 'larger' : fontSizeChange('large'); break;
327		case 'small'  : fontSizeChange('small'); break;
328		case 'default' :
329		default: fontSizeChange('default'); break;
330	}
331}
332
333// アコーディオン設定(スマートフォン用)
334/*
335	概要:
336		javascriptで、アコーディオンのためのタグ・イベントを追加する。
337	使用例:
338		setAccordion();
339	引数:
340		無し
341	返り値:
342		無し
343	詳細:
344		アコーディオンさせたい場合、タップさせる要素(タイトル)に対して class="acc_title" を追加する。
345		<div>
346			<h2 class="acc_title">タイトル</h2>
347			<ul>
348				...
349			</ul>
350		</div>
351		上記の場合、h2に .acc_title を付与することで、ulが表示/非表示される。
352
353		<div>
354			<h2 class="acc_title">タイトル</h2>
355		</div>
356		のように、acc_titleの兄弟要素がない場合はアコーディオンにならない
357*/
358function setAccordion() {
359	let accTitle = document.querySelectorAll('.acc_title');
360	// クラス.acc_title の内側にlabelタグを作成。
361	function createLabel() {
362		accTitle.forEach((element, index) => {
363			let parentElement = element.parentNode;
364			let childElementNum = parentElement.children.length;
365			if (childElementNum !== 1) {
366				if (childElementNum === 2 && parentElement.children[1].children.length == 0) {
367					parentElement.classList.add('no_acc');
368				} else {
369					element.innerHTML = '<label for="acc_ttl_label' + index + '">' + element.innerHTML + '</label>';
370					element.insertAdjacentHTML('afterend', '<input id="acc_ttl_label' + index + '" type="checkbox">');
371					parentElement.classList.add('acc_parent');
372				}
373			} else {
374				parentElement.classList.add('no_acc');
375			}
376		});
377	}
378	// クラス.acc_titleにイベントを割り当てる。
379	function addEventToAccTitle() {
380		accTitle.forEach((element) => {
381			if (!(element.parentElement.classList.contains('no_acc'))) {
382				element.addEventListener('click', function () {
383					this.classList.toggle('acc_open');
384				});
385			}
386		});
387	}
388	// 上から順番に実行する。
389	async function createAndSetAccordion() {
390		await createLabel();
391		await addEventToAccTitle();
392	}
393	// すべてを実行
394	if (accTitle.length !== 0) {
395		createAndSetAccordion();
396	}
397}
398
399// スマートフォン用アコーディオン設定(class付与)
400/*
401	概要:
402		javascriptで、アコーディオンのためのクラスを追加する。
403	使用例:
404		setAccordionClass();
405	引数:
406		無し
407	返り値:
408		無し
409	詳細:
410		こちらを使用する場合は、setAccordion()を無効にすること。※併用不可
411*/
412function setAccordionClass() {
413	document.querySelectorAll('.acc_title').forEach(function(element) {
414		element.setAttribute('tabindex', '0');
415		element.classList.add('accordion');
416		let span = document.createElement('span');
417		span.classList.add('accordion_icon');
418		while (element.firstChild) {
419			span.appendChild(element.firstChild);
420		}
421		element.appendChild(span);
422
423		element.addEventListener('click', toggleAccordion);
424		element.addEventListener('keypress', function(event) {
425			if (event.key === 'Enter' || event.key === ' ') {
426				toggleAccordion.call(element);
427			}
428		});
429	});
430
431	document.querySelectorAll('.acc_title a').forEach(function(link) {
432		link.addEventListener('click', function(event) {
433			event.stopPropagation();
434		});
435		link.addEventListener('keypress', function(event) {
436			if (event.key === 'Enter' || event.key === ' ') {
437				event.stopPropagation();
438			}
439		});
440	});
441}
442function toggleAccordion() {
443	this.classList.toggle('acc_open');
444}
445
446// アクセシビリティチェック画面の判定
447/*
448	概要:
449		アクセシビリティチェック画面かどうかの判定
450	使用例:
451		if(accCheckerChk()){
452			// アクセシビリティチェック画面のときの処理
453		}
454	引数:
455		無し
456	返り値:
457		true , false
458	詳細:
459		アクセシビリティチェック画面かどうかの判定
460		クラスerrrangeを判定し、存在すれば(=アクセシビリティチェック画面である)true,
461		存在しなければ(=アクセシビリティチェック画面ではないfalseを返す。
462*/
463function accElementChk() {
464	const accElement = document.getElementsByClassName('errrange');
465	return accElement.length > 0 ? true : false;
466}
467
468// アクセシビリティチェック画面のときに、bodyタグにクラス'acc_check_view'を追加する。
469/*
470	概要:
471		アクセシビリティチェック画面のときにbodyにクラス'acc_check_view'を追加する。
472	使用例:
473		accCheckerChk();
474	引数:
475		無し
476	返り値:
477		無し
478	詳細:
479		実行すると、bodyタグにクラス'acc_check_view'を追加する。
480*/
481function accCheckerChk() {
482	const bodyElement = document.querySelector('body');
483	if (accElementChk()) {
484		bodyElement.classList.add('acc_check_view');
485	}
486}
487
488// 色無しで確認画面の判定
489/*
490	概要:
491		色無しで確認画面かどうかの判定
492	使用例:
493		accGrayCheck();
494	引数:
495		無し
496	返り値:
497		無し
498	詳細:
499	URLに特定の文字列が含まれれば専用のCSSを読み込む。
500	※filterタグが適用されるとposition:fixed;が標準状態と異なる動作想定外になるための対応。
501	※主に非表示にする。
502*/
503function accGrayCheck() {
504	const bodyTag = document.querySelector('body');
505	const headTag = document.querySelector('head');
506	const chkUrl = location.pathname;
507	const compareStr = '/checker/GraceViewer';
508	const grayCSSTag = '<link rel="stylesheet" href="/ssi/css/acc-grayscale.css">';
509
510	// 色無しで確認画面のときに、bodyタグにクラス'accGrayscale'を追加する。
511	if (chkUrl.indexOf(compareStr) != -1) {
512		bodyTag.classList.add('accGrayscale');
513		headTag.insertAdjacentHTML('beforeend', grayCSSTag);
514	}
515}
516
517// 新着情報一覧の判定
518/*
519	概要:
520		URLが新着一覧ページ(index-2.html)であればクラスを追加。
521	使用例:
522		chkIndexListAll();
523	引数:
524		無し
525	返り値:
526		無し
527	詳細:
528		URL中に'/index-2.html'が含まれていれば、ページ内の最初のdiv.tpl_〇〇にクラスindex-2を追加
529*/
530function chkIndexListAll() {
531	const tplElm = document.querySelector('div[class*="tpl_"]');
532	if(location.pathname.includes('/index-2.html') === true){ // URLが一覧ページかどうか
533		tplElm.classList.add('index-2');
534	}
535}
536
537// ページ内見出し
538/*
539	概要:
540		ページ内見出し作成
541	使用例:
542		addTocToDetail('#main_body');
543		addTocToDetail('#main_body , #sidebar2');
544
545		記事ページ,サブサイトトップページ,サブサイト記事ページ,所属トップページの#main_bodyと#sidebar2それぞれに目次(Table of contents)を作成(無い場合は作成されない)
546		if (document.querySelectorAll('.tpl_detail,.tpl_site_index,.tpl_site_detail,.tpl_soshiki_kakuka') > 0) {
547			addTocToDetail('#main_body,#sidebar2');
548		}
549	引数:
550		ページ内目次を挿入したい要素(複数可)
551	返り値:
552		無し
553*/
554function addTocToDetail(targetArg) {
555	const targetElement = Array.from(document.querySelectorAll(targetArg)); // targetArg 指定にマッチする要素のみが取得される。存在しない要素は取得されない。
556	const mainBodyH2Element = document.querySelectorAll('#main_body h2');
557
558	if (mainBodyH2Element.length > 0) {
559		// #main_body内のh2からh6までのタグをすべて取得。
560		const htagAll = Array.from(document.querySelectorAll('#main_body h2,#main_body h3,#main_body h4,#main_body h5,#main_body h6'));
561		let htag = '';
562		let linkElement = '';
563		
564		htagAll.forEach((element, index) => {
565			index += 1; // 自然数にするために+1
566			htag = element.tagName.toLowerCase(); // 見出しタグのタグ名(h2,h3など)の文字列を小文字に。
567			element.insertAdjacentHTML('beforebegin', '<span id="toc' + index + '"></span>'); // アンカーリンク先の設置
568			linkElement = linkElement + '<li class="toc_type_'+ htag + '"><a href="#toc' + index + '">' + element.textContent + '</a></li>'; // リスト+アンカーリンクリンクタグの作成
569		});
570		/*
571			目次のHTMLを作成。(テンプレートリテラル)
572			囲みがバッククォーテーションである点に注意。(shift + @ で入力する)
573			${linkElement} に、上で処理したlinkElement内のタグが出力される。
574		*/
575		let templateToc = `
576		<details class="toc_link_wrap">
577		<summary class="toc_link_toggle">ページ内目次</summary>
578		<ul class="toc_link">${linkElement}</ul>
579		</details>`;
580
581		// 上のテンプレートリテラルで作成した目次を#main_bodyの開始タグ直後に設置。
582		for (let index = 0; index < targetElement.length; index++) {
583			targetElement[index].insertAdjacentHTML('afterbegin', templateToc);
584		}
585	}
586}
587
588// ページ内見出しへのアンカーリンク
589/*
590	概要:
591		別ページからのリンクにページ内目次のアンカーリンクがあったときに、見出しまで移動させる
592	使用例:
593		tocAnchor();
594	引数:
595		無し
596	返り値:
597		無し
598	詳細:
599		load時に発火させること
600*/
601function tocAnchor() {
602	let hashStr = location.hash;
603	if (hashStr.includes('#toc')) {
604		let targetElement = document.querySelector(hashStr);
605		window.scrollTo('top', targetElement.offsetTop);
606	}
607}
608
609// iframeタグスマートフォン対応
610/*
611	概要:
612		Youtube,Googlemapのiframeタグスマートフォン対応
613	使用例:
614		ytIrameResponsive();
615	引数:
616		無し
617	返り値:
618		無し
619*/
620function ytIrameResponsive() {
621	// iframeタグを取得。
622	let ytIframesArr = Array.from(document.querySelectorAll('iframe[src^="https://www.youtube"]'));
623	let gmIframeArr = Array.from(document.querySelectorAll('iframe[src^="https://www.google"]'));
624	// 取得したiframeタグに対し、aspect-ratioをiframeタグのwidth属性とheight属性の値で設定。
625	ytIframesArr.forEach(element => {
626		if (element.hasAttribute('width') && element.hasAttribute('height')) {
627			element.style.aspectRatio = element.getAttribute('width') + '/' + element.getAttribute('height');
628		}
629	});
630	gmIframeArr.forEach(element => {
631		if (element.hasAttribute('width') && element.hasAttribute('height')) {
632			element.style.aspectRatio = element.getAttribute('width') + '/' + element.getAttribute('height');
633		}
634	});
635}
636
637// setTitletoGMIframe関数
638/*
639	概要:
640		title属性を持たないGoogle mapのiframe埋め込みタグにtitle属性を追加する。
641		has()のブラウザ対応度合いによっては、取得する要素を
642		iframe[src^="https://www.google.com/maps/embed"]:not(:has([title]))
643		で絞り込んでも可。
644		取得するGooglemapのセレクタをytIrameResponsive()と合わせている。
645	引数:
646		無し
647	返り値:
648		無し
649	使用例:
650		setTitletoGMIframe();
651*/
652function setTitletoGMIframe(){
653	const iframes = document.querySelectorAll('iframe[src^="https://www.google.com/maps/embed"]');
654	iframes.forEach((elm)=>{
655		// title属性が無ければtitle属性を追加
656		if(!elm.hasAttribute('title')){
657			elm.setAttribute('title','Google map');
658		}
659	});
660}
661function setTitletoGMIframebyAPI() {
662	const mapCanvasIframe = document.querySelector('.gm-style iframe:not([title])');
663	if (mapCanvasIframe !== null) {
664		mapCanvasIframe.setAttribute('title', 'Google map');
665	}
666}
667
668// tableタグにスクロールバーを追加
669/*
670	概要:
671		コンテンツエリア以上の幅をもつtableタグにスクロールバーを追加する。
672	使用例:
673		detailFreeTable();
674	引数:
675		無し
676	返り値:無し
677*/
678function detailFreeTable() {
679	let tableElement = document.querySelectorAll('#main_body div[class*="detail_"] > table');
680	const btnElement = '<button type="button" class="sw_large_table sp_button">表のサイズを切り替える</button>';
681	if (tableElement) {
682		tableElement.forEach((element) => {
683			element.outerHTML = `<div class="sp_table_wrap2">${btnElement}<div class="sp_table_wrap">${element.outerHTML}</div></div>`
684		});
685		let buttons = document.querySelectorAll('#main_body div[class*="detail_"] .sw_large_table');
686		buttons.forEach((btnElm) => {
687			btnElm.addEventListener('click', () => {
688				btnElm.parentElement.classList.toggle('sp_large_table');
689			});
690		});
691	}
692}
693
694// tableタグの幅の書き換え
695/*
696	概要:
697		ワープロライク中のtabelタグがコンテンツ幅よりも大きい幅をインラインスタイルで指定されていた時、
698		インラインスタイルの幅を100%に書き換える
699	引数:
700		無し
701	返り値:
702		無し
703	詳細:
704		safari対応
705*/
706function rewriteTableWidth() {
707	const contentW = parseInt(document.querySelector('#main_body').clientWidth);
708	let tables = document.querySelectorAll('#main_body .detail_free table');
709	tables.forEach((elm) => {
710		let elmW = parseInt(elm.style.width);
711		if (elmW > contentW) {
712		elm.style.width = '100%';
713		}
714	});
715}
716
717// 空の関連情報を削除
718/*
719	概要:
720		空の関連情報を削除
721	使用例:
722		empty_kanren_remove();
723	引数:
724		無し
725	返り値:
726		無し
727*/
728function empty_kanren_remove() {
729	let kanrenElement = document.querySelector('#kanren_info');
730	//取得した#kanren_infoの子要素が1件だけであれば#kanren_infoを削除
731	if (kanrenElement !== null) {
732		if (kanrenElement.childElementCount == 1) {
733			kanrenElement.remove();
734		}
735	}
736}
737
738// 画面内に要素があるか判定
739/*
740	概要:
741		要素が見えているかの判定(ビューポート内にあるか)
742		画面内にある場合には、監視を指定した要素にクラス.is_visibleが追加される。
743		(画面から外れると.is_visibleは消える)
744	使用例:
745		chkViewElement('#header');
746		chkViewElement('.detail_free');
747	引数:
748		要素名(querySelectorAllの仕様による)
749	返り値:
750		無し
751*/
752function chkViewElement(target) {
753	const targetElements = document.querySelectorAll(target);
754	const options = {
755		rootMargin: '0px',
756		threshold: 0
757	};
758	const observer = new IntersectionObserver(intersect, options);
759	targetElements.forEach((targetElement) => {
760		observer.observe(targetElement);
761	});
762
763	function intersect(entries) {
764		entries.forEach((entry) => {
765			if (entry.isIntersecting) {
766				// ビューポート内にある時
767				entry.target.classList.add('is_visible');
768			} else {
769				// ビューポート内に無い時
770				entry.target.classList.remove('is_visible');
771			}
772		});
773	}
774}
775
776// #headerが画面外に出たらクラスを付与
777/*
778	概要:
779		#headerが画面外に出たら、bodyに対してクラス header_hideを追加
780	引数;
781		無し
782	返り値:
783		無し
784	詳細:
785		無し
786*/
787function chkHeaderView() {
788	const observer = new IntersectionObserver(entries => {
789		// 要素が画面内から外に出たかどうかをチェック
790		let addClassElm = document.querySelector('body');
791		entries.forEach(entry => {
792		if (entry.isIntersecting) {
793			// 要素が画面内にいる場合
794			addClassElm.classList.remove('header_hide');
795		} else {
796			// 要素が画面外にいる場合
797			addClassElm.classList.add('header_hide');
798		}
799		});
800	});
801	// 要素を監視する
802	observer.observe(document.querySelector("#header"));
803}
804function headerScroll_scroll() {
805	let headerElement = document.querySelector('#header');
806	let headerElementHeight = headerElement.clientHeight;
807	let scrollVal = 0;
808	if (headerElement != null) {
809		window.addEventListener('scroll', (event) => {
810			scrollVal = window.scrollY;
811			console.log(scrollVal);
812			if (scrollVal > headerElementHeight) {
813				headerElement.classList.add('header_fixed');
814			} else {
815				headerElement.classList.remove('header_fixed');
816			}
817		});
818	}
819}
820
821// スムーススクロール
822/*
823	概要:
824		アンカーリンク押下時にアニメーションでジャンプ
825	引数:
826		無し
827	返り値:
828		無し
829	詳細:
830		無し
831*/
832function setAnchorAnime() {
833	if (!accElementChk()) {
834		document.querySelectorAll('a[href^="#"]').forEach(function(elm) {
835			elm.addEventListener('click', function(event) {
836				event.preventDefault();
837				var target = document.getElementById(this.hash.slice(1));
838				var scrollTop = target.offsetTop;
839				window.scrollTo({
840					top: scrollTop,
841					behavior: "smooth"
842				});
843				// location.hash = this.hash;
844			});
845		});
846	}
847}
848
849// 閲覧補助機能(開閉)
850/*
851	概要:
852		閲覧補助機能展開用クラス追加・削除イベント
853	引数:
854		無し
855	返り値:
856		無し
857	詳細:
858		無し
859*/
860function acc_support_menu() {
861	let eventList = ['click'];
862	// 開閉ボタンをbuttoタグではなくaタグを使用する場合は、下記のpushしている行のコメントを削除して有効にしてください。
863	// eventList.push('keydown');
864
865	let closeElement = document.querySelector('#support_menu_close');
866	let openElement = document.querySelector('#support_menu_open');
867	let boxElement = document.querySelector('#support_menu_box');
868
869	let existChk = [closeElement, openElement, boxElement];
870	// 全ての要素が存在すれば実行
871	if (domExistCheck(existChk)) {
872		eventList.forEach((element) => {
873			closeElement.addEventListener(element, () => {
874				openElement.classList.remove('open');
875				boxElement.classList.remove('open');
876			});
877			openElement.addEventListener(element, (event) => {
878				openElement.classList.toggle('open');
879				boxElement.classList.toggle('open');
880				event.stopPropagation();
881			});
882
883			boxElement.addEventListener('click', function(event) {
884				event.stopPropagation();
885			});
886			document.addEventListener('click', function() {
887				if(boxElement.classList.contains('open')){
888					openElement.classList.remove('open');
889					boxElement.classList.remove('open');
890				}
891			});
892			// キーボード操作対応
893			closeElement.addEventListener('focusout',(event)=> {
894				if(boxElement.classList.contains('open')){
895					openElement.classList.remove('open');
896					boxElement.classList.remove('open');
897				}
898			});
899		});
900	}
901}
902
903// ページID検索(開閉)
904/*
905	概要:
906		ページID検索展開用クラス追加・削除イベント
907	引数:
908		無し
909	返り値:
910		無し
911	詳細:
912		無し
913*/
914function acc_id_search() {
915	let eventList = ['click'];
916	// 開閉ボタンをbuttoタグではなくaタグを使用する場合は、下記のpushしている行のコメントを削除して有効にしてください。
917	// eventList.push('keydown');
918
919	let closeElement = document.querySelector('#id_search_close');
920	let openElement = document.querySelector('#id_search_open');
921	let boxElement = document.querySelector('#id_search_box');
922
923	let existChk = [closeElement, openElement, boxElement];
924	// 全ての要素が存在すれば実行
925	if (domExistCheck(existChk)) {
926		eventList.forEach((element) => {
927			closeElement.addEventListener(element, () => {
928				openElement.classList.remove('open');
929				boxElement.classList.remove('open');
930			});
931			openElement.addEventListener(element, (event) => {
932				openElement.classList.toggle('open');
933				boxElement.classList.toggle('open');
934				event.stopPropagation();
935			});
936
937			boxElement.addEventListener('click', function(event) {
938				event.stopPropagation();
939			});
940			document.addEventListener('click', function() {
941				if(boxElement.classList.contains('open')){
942					openElement.classList.remove('open');
943					boxElement.classList.remove('open');
944				}
945			});
946			// キーボード操作対応
947			closeElement.addEventListener('focusout',(event)=> {
948				if(boxElement.classList.contains('open')){
949					openElement.classList.remove('open');
950					boxElement.classList.remove('open');
951				}
952			});
953		});
954	}
955}
956
957// 回遊ボタン(開閉)
958/*
959	概要:
960		回遊ボタン展開用クラス追加・削除イベント
961	引数:
962		無し
963	返り値:
964		無し
965	詳細:
966		無し
967*/
968function acc_kaiyu_banner() {
969	let eventList = ['click'];
970	// 回遊ボタン開閉をbuttoタグではなくaタグにする場合は下記のpushしている行のコメントを削除してください
971	// eventList.push('keydown');
972
973	let closeElement = document.querySelector('#btn_kaiyu_close');
974	let openElement = document.querySelector('#btn_kaiyu_open');
975	let boxElement = document.querySelector('#kaiyu_banner');
976
977	let existChk = [closeElement, openElement, boxElement];
978	// 全ての要素が存在すれば実行
979	if (domExistCheck(existChk)) {
980		eventList.forEach((element) => {
981			closeElement.addEventListener(element, () => {
982				boxElement.classList.remove('open');
983			});
984			openElement.addEventListener(element, () => {
985				boxElement.classList.toggle('open');
986			})
987
988			boxElement.addEventListener('click', function(event) {
989				event.stopPropagation();
990			});
991			document.addEventListener('click', function() {
992				if(boxElement.classList.contains('open')){
993					openElement.classList.remove('open');
994					boxElement.classList.remove('open');
995				}
996			});
997			// キーボード操作対応
998			closeElement.addEventListener('focusout',(event)=> {
999				if(boxElement.classList.contains('open')){
1000					openElement.classList.remove('open');
1001					boxElement.classList.remove('open');
1002				}
1003			});
1004		});
1005	}
1006}
1007
1008// 検索メニュー開閉
1009/*
1010	概要:
1011		検索メニュー展開用クラス追加・削除イベント
1012	引数:
1013		無し
1014	返り値:
1015		無し
1016	詳細:
1017		無し
1018*/
1019function pcSearchMenuToggle() {
1020	let pcSearchCloseElement = document.querySelector('#pc_search_close');
1021	let pcSearchMenuElement = document.querySelector('#pc_search_open');
1022	let targetElement = document.querySelector('#container');
1023
1024	let existChk = [pcSearchCloseElement, pcSearchMenuElement, targetElement];
1025	// 全ての要素が存在すれば実行
1026	if (domExistCheck(existChk)) {
1027		pcSearchCloseElement.addEventListener('click', () => {
1028			targetElement.classList.remove('pc_search_menu_open');
1029		});
1030		pcSearchMenuElement.addEventListener('click', () => {
1031			targetElement.classList.toggle('pc_search_menu_open');
1032		});
1033		// キーボード操作対応
1034		pcSearchCloseElement.addEventListener('focusout',(event)=> {
1035			if(targetElement.classList.contains('pc_search_menu_open')){
1036				targetElement.classList.remove('pc_search_menu_open');
1037			}
1038		});
1039	}
1040}
1041
1042// スマートフォンボトムメニュー(メニュー開閉)
1043/*
1044	概要:
1045		スマートフォン画面のメニュー展開用クラス追加・削除イベント
1046	引数:
1047		無し
1048	返り値:
1049		無し
1050	詳細:
1051		無し
1052*/
1053function spMenuToggle() {
1054	let spMenuElement = document.querySelector('#spm_menu');
1055	let targetElement = document.querySelector('#container');
1056
1057	let existChk = [spMenuElement, targetElement];
1058	// 全ての要素が存在すれば実行
1059	if (domExistCheck(existChk)) {
1060		spMenuElement.addEventListener('click', () => {
1061			targetElement.classList.remove('spm_search_open','spm_kaiyu_open','spm_support_open');
1062			targetElement.classList.toggle('spm_menu_open');
1063		});
1064	}
1065}
1066
1067// スマートフォンボトムメニュー(検索開閉)
1068/*
1069	概要:
1070		スマートフォン画面の検索展開用クラス追加・削除イベント
1071	引数:
1072		無し
1073	返り値:
1074		無し
1075	詳細:
1076		無し
1077*/
1078function spSearchToggle() {
1079	let spSearchElement = document.querySelector('#spm_search');
1080	let targetElement = document.querySelector('#container');
1081
1082	let existChk = [spSearchElement, targetElement];
1083	// 全ての要素が存在すれば実行
1084	if (domExistCheck(existChk)) {
1085		spSearchElement.addEventListener('click', () => {
1086			targetElement.classList.remove('spm_menu_open','spm_kaiyu_open','spm_support_open');
1087			targetElement.classList.toggle('spm_search_open');
1088		});
1089	}
1090}
1091
1092// スマートフォンボトムメニュー(回遊ボタン開閉)
1093/*
1094	概要:
1095		スマートフォン画面の回遊ボタン展開用クラス追加・削除イベント
1096	引数:
1097		無し
1098	返り値:
1099		無し
1100	詳細:
1101		無し
1102*/
1103function spKaiyuToggle() {
1104	let spKaiyuElement = document.querySelector('#spm_kaiyu');
1105	let targetElement = document.querySelector('#container');
1106
1107	let existChk = [spKaiyuElement, targetElement];
1108	// 全ての要素が存在すれば実行
1109	if (domExistCheck(existChk)) {
1110		spKaiyuElement.addEventListener('click', () => {
1111			targetElement.classList.remove('spm_menu_open','spm_search_open','spm_support_open');
1112			targetElement.classList.toggle('spm_kaiyu_open');
1113		});
1114	}
1115}
1116
1117// スマートフォンボトムメニュー(ページトップボタン)
1118/*
1119	概要:
1120		スマートフォン画面のページトップボタンを押した際、展開メニューが開いていた場合は閉じる
1121	引数:
1122		無し
1123	返り値:
1124		無し
1125	詳細:
1126		無し
1127*/
1128function spPagetopButtonToggle() {
1129	let spPagetopButtonElement = document.querySelector('#spm_pagetop');
1130	let targetElement = document.querySelector('#container');
1131
1132	let existChk = [spPagetopButtonElement, targetElement];
1133	// 全ての要素が存在すれば実行
1134	if (domExistCheck(existChk)) {
1135		spPagetopButtonElement.addEventListener('click', () => {
1136			targetElement.classList.remove('spm_menu_open','spm_search_open','spm_kaiyu_open','spm_support_open');
1137		});
1138	}
1139}
1140
1141// スマートフォン閲覧補助(開閉)
1142/*
1143	概要:
1144		スマートフォン画面の閲覧補助展開用クラス追加・削除イベント
1145	引数:
1146		無し
1147	返り値:
1148		無し
1149	詳細:
1150		無し
1151*/
1152function spSupportToggle() {
1153	let spSupportElement = document.querySelector('#spm_support');
1154	let targetElement = document.querySelector('#container');
1155
1156	let existChk = [spSupportElement, targetElement];
1157	// 全ての要素が存在すれば実行
1158	if (domExistCheck(existChk)) {
1159		spSupportElement.addEventListener('click', () => {
1160			targetElement.classList.remove('spm_menu_open','spm_search_open','spm_kaiyu_open');
1161			targetElement.classList.toggle('spm_support_open');
1162		});
1163	}
1164}
1165
1166// サブサイトメニュー(開閉)
1167/*
1168	概要:
1169		ブラウザ幅でdetailsタグのopen属性のトグルを行う
1170	引数:
1171		無し
1172	返り値:
1173		無し
1174	詳細:
1175		サブサイトメニューのdetailタグのopen属性をブラウザ幅で追加・削除する。
1176		※element.open = true; でopen属性追加。
1177*/
1178function toggleWithMediaQuery() {
1179	function handleTableChange(event) {
1180		if (event.matches) {
1181			submenu.forEach((element) => {
1182				element.open = true;
1183			});
1184		} else {
1185			submenu.forEach((element) => {
1186				element.open = false;
1187			});
1188		}
1189	}
1190	const mediaQuery = window.matchMedia('(min-width: 1080px)');
1191
1192	// メニューの展開トグル
1193	let submenu = Array.from(document.querySelectorAll('#subsite_menu_wrap details'));
1194	if (submenu.length > 0) {
1195		mediaQuery.addListener(handleTableChange);
1196		handleTableChange(mediaQuery);
1197	}
1198}
1199
1200// mouseoverイベントが発生したらfocusを削除
1201/*
1202	概要:
1203		グローバルナビゲーションにフォーカスがあたっている状態(:focus)でマウスを乗せると同時に複数箇所展開されるため、
1204		mouseoverイベントが発生したらfocusを削除(blur)する
1205	引数:
1206		無し
1207	返り値:
1208		無し
1209	詳細:
1210		何もしないと、キーボードのfocusが残った状態でマウスでhoverするとfocusで展開したメニューは開いたままhoverした要素が展開されます。
1211		それを防ぐため、mouseoverイベント発生時にfocusを削除します。
1212*/
1213function gnavDelFocusOnmouseover() {
1214	let ul = document.querySelector('#top_search');
1215	if (ul !== null) {
1216		ul.addEventListener('mouseover', function(){
1217			let focused = document.activeElement;
1218			if(focused.tagName == 'A'){
1219				focused.blur();
1220			}
1221		});
1222	}
1223}
1224
1225// スクロールするとクラスを付与
1226/*
1227	概要:
1228		一定量スクロールすると、elmIDで指定した要素にクラス.fixedを追加する。
1229	引数:
1230		scrollVal : スクロール量(px)
1231		elmID : 対象要素。IDを指定。クラスを指定した場合はページ内の最初のクラスが対象になる。
1232	返り値:
1233		無し
1234*/
1235function scroll_fixed(scrollVal,elmID) {
1236	window.addEventListener('scroll', function() {
1237		let header = document.querySelector(elmID);
1238		let scrollPosition = window.scrollY;
1239		if (header != null) {
1240			if (scrollPosition > scrollVal) {
1241				header.classList.add('fixed');
1242			} else {
1243				header.classList.remove('fixed');
1244			}
1245		}
1246	});
1247}
1248
1249// makeCloneSlideElm関数
1250/*
1251	概要:
1252		複数枚表示するスライドに対応するため、
1253		規定値以上になるまでulタグの中身のコピーを作成する。
1254		※コピー後のliタグの数は、処理前のliタグの倍数となる。
1255	引数:
1256		targetElm : 対象要素。ulタグを指定。
1257					ページ内に同じクラスの要素が複数ある場合は
1258					最初の要素が対象となる。
1259		MAXNUM    : スライドが発火するために必要な要素の数。
1260					例えば、スライドの画像を一度に3件表示したいときは、最低4件必要になる。
1261		NOSLIDENUM: スライドさせない枚数。デフォルト(省略したとき)は 1。
1262	返り値:
1263		真偽値(true / false)
1264		true  : スライドの要素のコピーを実行したとき
1265		        →スライドの準備が出来た状態
1266		false : スライドの要素のコピーをしなかったとき
1267		        (スライドの枚数が最低枚数かそれ以下のとき)
1268		        →スライドをさせない状態
1269	使用例:
1270		※コピーを作成した後にスライドを実行させる順番を守るため、asyncを使用。
1271		----------------------------------------
1272		async function setSlide() { // 名前は何でもよい。
1273			let doSlide = await makeCloneSlideElm('ul#top_banner_pr_list', 4, 1); // awaitを指定し、処理が終わるまで待機。
1274			if(doSlide === true){
1275				banner_pr_slider(); // スライドさせる関数
1276			}
1277		}
1278		setSlide();
1279		----------------------------------------
1280		※単にスライドをコピーする場合は下記のいずれか一方の書式を使用
1281		makeCloneSlideElm('ul#top_banner_pr_list', 4);
1282		makeCloneSlideElm('ul#top_banner_pr_list', 4, 1); //1枚の時はスライドを実行しない
1283*/
1284function makeCloneSlideElm(parentElm, MAXNUM, NOSLIDENUM = 1) {
1285	function getChildlenElm(parentElm) {
1286		return ulSlide.querySelectorAll(parentElm + ' > *').length;
1287	}
1288	const ulSlide = document.querySelector(parentElm);
1289	let liNum = getChildlenElm(parentElm);
1290	const ulClone = ulSlide.cloneNode(true);
1291	if (liNum > NOSLIDENUM) {
1292		if (liNum < MAXNUM) {
1293			while (liNum < MAXNUM) {
1294				ulSlide.insertAdjacentHTML('beforeend', ulClone.innerHTML);
1295				liNum = getChildlenElm(parentElm);
1296			}
1297		}
1298		return true;
1299	} else {
1300		return false;
1301	}
1302}
1303
1304/* ==================================================
1305関数 ここまで
1306================================================== */
1307
1308
1309/* ==================================================
1310html読み込み後に実行される処理
1311================================================== */
1312document.addEventListener('DOMContentLoaded', function() {
1313
1314	// 実行したい処理
1315	// チェック関係
1316	accCheckerChk();
1317	accGrayCheck();
1318	chkIndexListAll();
1319
1320	// 画面初期化関係
1321	initColorMode();
1322	initFontSize();
1323
1324	// DOM操作関係
1325	// setAccordion();
1326	setAccordionClass(); /* こちらを使用する場合は setAccordion() を無効にすること ※併用不可 */
1327	detailFreeTable();
1328
1329	// イベントの登録(ポップアップの展開など)
1330	acc_support_menu();
1331	acc_id_search();
1332	acc_kaiyu_banner();
1333	pcSearchMenuToggle();
1334	spMenuToggle();
1335	spSearchToggle();
1336	spKaiyuToggle();
1337	spPagetopButtonToggle();
1338	spSupportToggle();
1339	toggleWithMediaQuery();
1340	scroll_fixed(200, '#footer_link_pagetop'); // 200pxスクロールすると#footer_link_pagetopに.fixedを追加
1341
1342	// 指定のクラスが存在するページの#main_bodyと#sidebar2それぞれに目次を作成(無い場合は作成されない)
1343	if (document.querySelectorAll('.detail,.site_index,.site_detail,.soshiki_kakuka,.sitemap,.tpl_detail,.tpl_site_index,.tpl_site_detail,.tpl_soshiki_kakuka,.tpl_sitemap').length > 0) {
1344		addTocToDetail('#main_body,#sidebar2');
1345	}
1346
1347	// 部局、所属、分類ページで実行
1348	if (document.querySelectorAll('.soshiki_kakubu,.soshiki_kakuka,.life,.tpl_soshiki_kakubu,.tpl_soshiki_kakuka,.tpl_life').length > 0) {
1349		empty_kanren_remove();
1350	}
1351
1352	// ワープロライクが存在するページで実行
1353	if (document.querySelector('#main_body div[class*="detail_"]') != null) {
1354		rewriteTableWidth();
1355	}
1356
1357	// chkViewElement('#skip');
1358	// chkViewElement('.detail_free');
1359	chkHeaderView();
1360	// headerScroll_scroll();
1361	ytIrameResponsive();
1362	setTitletoGMIframe();
1363	// setAnchorAnime();
1364	tocAnchor();
1365
1366	// グローバルナビゲーションを展開させる際に使用する
1367	// gnavDelFocusOnmouseover();
1368
1369});
1370/* ==================================================
1371html読み込み後に実行される処理 ここまで
1372================================================== */
1373
1374
1375/* ==================================================
1376ページ読み込み完了時に実行される処理
1377================================================== */
1378window.addEventListener('load', (event) => {
1379	setTimeout(setTitletoGMIframebyAPI, 1000);
1380});
1381/* ==================================================
1382ページ読み込み完了時に実行される処理 ここまで
1383================================================== */

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.