document.addEventListener('DOMContentLoaded', function () {
/* ==================================================
GJJ 海外就職体験談
スマホのみ概要を自動アコーディオン化
================================================== */
const mediaQuery = window.matchMedia('(max-width: 767px)');
/* ----------------------------------------------
文字列の余分な空白・改行を整理
---------------------------------------------- */
function normalizeText(text) {
return (text || '')
.replace(/\s+/g, '')
.trim();
}
/* ----------------------------------------------
DOM上でelementAよりelementBが後にあるか
---------------------------------------------- */
function isFollowing(elementA, elementB) {
return !!(
elementA.compareDocumentPosition(elementB) &
Node.DOCUMENT_POSITION_FOLLOWING
);
}
/* ----------------------------------------------
指定した親要素の直下まで要素を持ち上げる
---------------------------------------------- */
function getDirectChild(element, parent) {
let current = element;
while (
current &&
current.parentElement &&
current.parentElement !== parent
) {
current = current.parentElement;
}
return current;
}
/* ==================================================
スマホ時:アコーディオンを生成
================================================== */
function createAccordion() {
/* PCなら何もしない */
if (!mediaQuery.matches) {
return;
}
/* 海外就職体験談ページ以外では何もしない */
if (
window.location.pathname.indexOf('/interview/') === -1
) {
return;
}
/* すでにアコーディオン化されていれば終了 */
if (
document.querySelector('.gjj-interview-accordion')
) {
return;
}
/* ----------------------------------------------
「海外就職前:」を探す
---------------------------------------------- */
const strongElements = Array.from(
document.querySelectorAll('strong, b')
);
const startMarker = strongElements.find(function (element) {
const text = normalizeText(element.textContent);
return (
text === '海外就職前:' ||
text.indexOf('海外就職前:') === 0
);
});
/* 見つからなければ何もしない */
if (!startMarker) {
return;
}
/* ----------------------------------------------
記事本文の範囲を限定
---------------------------------------------- */
const articleScope =
startMarker.closest('article') ||
startMarker.closest('main') ||
document.body;
/*
* 「海外就職前:」が入っている段落を
* アコーディオン開始位置とする
*/
const startBlock =
startMarker.closest('p, li') ||
startMarker.parentElement;
if (!startBlock) {
return;
}
/* ----------------------------------------------
開始位置より後にある見出しを取得
---------------------------------------------- */
const headings = Array.from(
articleScope.querySelectorAll('h2, h3, h4')
).filter(function (heading) {
return isFollowing(startBlock, heading);
});
if (!headings.length) {
return;
}
/* ----------------------------------------------
「インタビュー」という見出しを優先して
アコーディオン終了位置にする
---------------------------------------------- */
let endHeading = headings.find(function (heading) {
const text = normalizeText(heading.textContent);
return (
text.indexOf('インタビュー') !== -1 ||
text.indexOf('Q1') === 0
);
});
/*
* 該当する見出しがなければ、
* 最初に出てくる次の見出しを使用
*/
if (!endHeading) {
endHeading = headings[0];
}
/* ----------------------------------------------
開始要素と終了見出しを含む
最も近い共通親要素を探す
---------------------------------------------- */
let commonParent = startBlock.parentElement;
while (
commonParent &&
!commonParent.contains(endHeading)
) {
commonParent = commonParent.parentElement;
}
if (!commonParent) {
return;
}
/* ----------------------------------------------
共通親の直下要素に変換
---------------------------------------------- */
const startNode =
getDirectChild(startBlock, commonParent);
const endNode =
getDirectChild(endHeading, commonParent);
if (
!startNode ||
!endNode ||
startNode === endNode
) {
return;
}
/* ==================================================
アコーディオンHTMLを自動生成
================================================== */
const wrapper =
document.createElement('div');
wrapper.className =
'gjj-interview-accordion';
const button =
document.createElement('button');
button.type = 'button';
button.className =
'gjj-interview-accordion__button';
button.setAttribute(
'aria-expanded',
'false'
);
const contentId =
'gjj-interview-summary-' +
Math.random()
.toString(36)
.substring(2, 9);
button.setAttribute(
'aria-controls',
contentId
);
button.innerHTML =
'' +
'この方のプロフィール・概要を見る' +
'' +
'' +
'▼' +
'';
const content =
document.createElement('div');
content.className =
'gjj-interview-accordion__content';
content.id = contentId;
content.hidden = true;
/* ----------------------------------------------
元の開始位置にアコーディオンを設置
---------------------------------------------- */
commonParent.insertBefore(
wrapper,
startNode
);
wrapper.appendChild(button);
wrapper.appendChild(content);
/* ----------------------------------------------
「海外就職前:」から
次のインタビュー見出し直前までを
アコーディオン内へ移動
---------------------------------------------- */
let currentNode = startNode;
while (
currentNode &&
currentNode !== endNode
) {
const nextNode =
currentNode.nextSibling;
content.appendChild(currentNode);
currentNode = nextNode;
}
/* ==================================================
開閉処理
================================================== */
button.addEventListener(
'click',
function () {
const isOpen =
wrapper.classList.toggle('is-open');
button.setAttribute(
'aria-expanded',
isOpen ? 'true' : 'false'
);
content.hidden = !isOpen;
const label =
button.querySelector(
'.gjj-interview-accordion__label'
);
if (label) {
label.textContent =
isOpen
? 'この方のプロフィール・概要を閉じる'
: 'この方のプロフィール・概要を見る';
}
}
);
}
/* ==================================================
PCへ戻した場合:
元のHTML構造に完全に戻す
================================================== */
function removeAccordion() {
const wrapper =
document.querySelector(
'.gjj-interview-accordion'
);
if (!wrapper) {
return;
}
const content =
wrapper.querySelector(
'.gjj-interview-accordion__content'
);
if (!content) {
return;
}
const parent =
wrapper.parentNode;
/*
* アコーディオン内の元の記事要素を
* 元の場所へ戻す
*/
while (content.firstChild) {
parent.insertBefore(
content.firstChild,
wrapper
);
}
wrapper.remove();
}
/* ==================================================
画面サイズに応じて実行
================================================== */
function updateAccordion() {
if (mediaQuery.matches) {
createAccordion();
} else {
removeAccordion();
}
}
/* 初回実行 */
updateAccordion();
/* ブラウザ幅変更にも対応 */
if (mediaQuery.addEventListener) {
mediaQuery.addEventListener(
'change',
updateAccordion
);
} else {
/* 古いSafari等への対応 */
mediaQuery.addListener(
updateAccordion
);
}
});