PageSourceSearch

https://maonline.jp/assets/client/prime_digest-76f9b411.js

js maonline.jp collected 2026-10-02 07:41:56 UTC 9,248 bytes, 272 lines download raw bytes

1import { convertBodyFigcaptions } from "client/body_citation"
2
3document.addEventListener('DOMContentLoaded', function() {
4  initPrimeDigest();
5});
6
7function initPrimeDigest() {
8  console.log("prime_digest.js loaded");
9
10  const qs = (selector) => document.querySelector(selector);
11  const qsa = (selector) => Array.from(document.querySelectorAll(selector));
12  const setStyle = (selector, property, value) => {
13    qsa(selector).forEach((el) => {
14      el.style[property] = value;
15    });
16  };
17  const setDisplay = (selector, value) => {
18    qsa(selector).forEach((el) => {
19      el.style.display = value;
20    });
21  };
22
23  // .body_wrap内の.alertにmgnB60クラスを追加(strike_movieクラスが存在する場合のみ)
24  if (qsa('.strike_movie').length > 0) {
25    qsa('.body_wrap .alert').forEach((el) => el.classList.add('mgnB60'));
26  }
27
28  // ブラウザバック対策
29  history.replaceState(null, null, null);
30  window.addEventListener('popstate', function(e) {
31    location.reload();
32  });
33
34  // 関連記事用のスライド(Swiperを動的に読み込み)
35  import('swiper').then(SwiperModule => {
36    const Swiper = SwiperModule.default || SwiperModule.Swiper;
37    new Swiper('.mini-swiper', {
38      spaceBetween: 5,
39      slidesPerView: 5,
40      autoHeight: true,
41      loop: true,
42      navigation: {
43        nextEl: '.mini-next-button',
44        prevEl: '.mini-prev-button'
45      },
46      pagination: {
47        el: '.mini-pegination',
48        type: 'bullets',
49        clickable: true
50      }
51    });
52  }).catch(error => {
53    console.log('Swiper could not be loaded:', error);
54  });
55
56  convertBodyFigcaptions();
57
58  // フォーム検証関数
59  function change_value() {
60    const formEl = qs('#new_inquiry');
61    if (!formEl) return;
62
63    function isNumber(val) {
64      return /^0\d{9,10}$/.test(val);
65    }
66
67    function isKana(val) {
68      return /^[ァ-ンヴー]*$/.test(val);
69    }
70
71    const requiredFields = Array.from(formEl.querySelectorAll('[required]')).filter((field) => {
72      if (field.disabled) return false;
73      if (field.type === 'hidden') return false;
74      if (field.name && field.name.includes('g-recaptcha-response')) return false;
75      return true;
76    });
77
78    let isValid = requiredFields.every((field) => {
79      if (field.type === 'checkbox' || field.type === 'radio') {
80        if (!field.name) return field.checked;
81        return formEl.querySelectorAll('input[name="' + field.name + '"]:checked').length > 0;
82      }
83
84      if (field.tagName === 'SELECT') {
85        return field.value !== '';
86      }
87
88      return typeof field.value === 'string' ? field.value.trim() !== '' : !!field.value;
89    });
90
91    // 複数の個別 checkbox がある場合、1つ以上が checked であることを必須
92    const allCheckboxes = Array.from(formEl.querySelectorAll('input[type="checkbox"]'));
93    if (allCheckboxes.length > 1) {
94      const hasChecked = allCheckboxes.some(checkbox => checkbox.checked);
95      isValid = isValid && hasChecked;
96    }
97
98    const kanaInputs = Array.from(formEl.querySelectorAll('input[type="text"]')).filter((input) => {
99      if (!input.id) return false;
100      const label = formEl.querySelector('label[for="' + input.id + '"]');
101      return label && label.textContent.includes('(カナ)');
102    });
103
104    const hasInvalidKana = kanaInputs.some((input) => {
105      const value = input.value.trim();
106      return value !== '' && !isKana(value);
107    });
108
109    const phoneInput = Array.from(formEl.querySelectorAll('input[type="text"], input[type="tel"]')).find((input) => {
110      if (!input.id) return false;
111      const label = formEl.querySelector('label[for="' + input.id + '"]');
112      return label && label.textContent.includes('お電話番号');
113    });
114
115    const phoneNumber = phoneInput ? phoneInput.value.trim() : '';
116    if (phoneNumber) {
117      isValid = isValid && isNumber(phoneNumber);
118    }
119
120    isValid = isValid && !hasInvalidKana;
121
122    qsa('.btn-base').forEach((btn) => {
123      btn.style.backgroundColor = isValid ? '#e60012' : 'grey';
124      btn.disabled = !isValid;
125    });
126  }
127
128  // Cookiesオブジェクトの確認(js-cookie が読み込まれているか確認)
129  let submit = null;
130  if (typeof Cookies !== 'undefined') {
131    submit = Cookies.get('submit');
132  }
133
134  // 変数の初期化
135  var url = qs('.confirm_btn')?.dataset.url || qs('.inquiry-form')?.dataset.url;
136  if (!url) return;
137  const keyName = url + '_agreed_1';
138  const keyValue = 'true';
139
140  if (submit && submit == url) {
141    //localStorageにキーと値を追加
142    localStorage.setItem(keyName, keyValue);
143  }
144
145  qsa('.inquiry-form').forEach((form) => {
146    form.addEventListener('input', function() {
147      change_value();
148    });
149    form.addEventListener('change', function() {
150      change_value();
151    });
152  });
153  change_value();
154
155  // 同意ボタンを押したら、同意済みのフラグをlocalStorageに保存
156  var isLoggedIn = window.userSignedIn || false; // ERBから受け取る
157
158  const confirmBtn = qs('.confirm_btn .btn');
159  if (confirmBtn) {
160    confirmBtn.addEventListener('click', async function() {
161    if (confirmBtn.disabled) return;
162    confirmBtn.disabled = true;
163
164    // localStorageに保存
165    localStorage.setItem(keyName, keyValue);
166
167    //CVを記録
168    var article_id = qs('.confirm_btn')?.dataset.articleId;
169    
170    // CSRFトークンを取得
171    var csrf_token = qs('meta[name="csrf-token"]')?.getAttribute('content');
172    
173    if (article_id && csrf_token) {
174      try {
175        const response = await fetch('/pages/count_cv_without_form', {
176          method: 'POST',
177          headers: {
178            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
179            'X-CSRF-Token': csrf_token,
180            'X-Requested-With': 'XMLHttpRequest'
181          },
182          body: new URLSearchParams({ article_id: article_id }).toString()
183        });
184        console.log('Success:', response.status);
185      } catch (error) {
186        console.error('Error:', error);
187      }
188    }
189
190    location.reload();
191    });
192  }
193
194  //localStorageにキーが存在すれば、同意済みならば
195  if (localStorage.getItem(keyName) && isLoggedIn) {
196
197    // 本編動画の要素を取得
198    const mainVideo = qs('figure:nth-child(2)');
199
200    // 一旦非表示のままレイアウト確定(高さ保持)
201    if (mainVideo) {
202      mainVideo.style.visibility = 'hidden';
203      mainVideo.style.display = 'block';
204    }
205
206    // 少し待ってから表示(ブラウザに高さ確定させる時間)
207    setTimeout(() => {
208      // 本編動画を表示
209      if (mainVideo) mainVideo.style.visibility = 'visible';
210    
211      const footer = qs('#footer');
212      if (footer) {
213        footer.style.visibility = 'hidden';
214        footer.style.display = 'block';
215      }
216      
217      // ダイジェスト動画を非表示
218      setDisplay('figure:first-child', 'none');
219    
220      // パーミッションメッセージを非表示
221      setDisplay('.permission-message', 'none');
222    
223      // 本編動画を表示
224      setDisplay('figure:nth-child(2)', 'block');
225    
226      // アクション後ページテキストを表示
227      setDisplay('#promotion_content', 'block');
228      setDisplay('#article_content', 'none');
229    
230      // フォームを非表示
231      setDisplay('.inquiry-form', 'none');
232    
233      // 同意ボタンを非表示
234      setDisplay('.confirm_btn_wrapper', 'none');
235    
236      // 色の変更
237      qsa('.logo img, .logo a img').forEach((img) => img.setAttribute('src', '/images/white_logo_mao.png'));
238      setStyle('.body_wrap, body, .navbar_wrapper, .active, .media, .navbar_search, button, .navbar-header, .signup, #main-navbar', 'backgroundColor', 'black');
239      setStyle('#header .menuSub a', 'backgroundColor', 'black');
240      qsa('a').forEach((anchor) => {
241        if (anchor.closest('#header .navbar_tab_content > div > ul > li')) return;
242        if (anchor.closest('#footer')) return;
243        anchor.style.backgroundColor = 'black';
244      });
245      setStyle('.navbar_tab_content, .tab-pane, .time_wrap, .menuSub', 'backgroundColor', '#333');
246      setStyle('#manews a, #kabuhoyu a, #tobnews a, .manda a, .business a, .life a, .toushi a, .sns a, .upper_sns a, .dropdown-btn a', 'backgroundColor', '#333');
247      setStyle('.logo, .navbar', 'border', 'none');
248      setStyle('h1, h2, p, time, .genre_title, a, li', 'color', 'white');
249      setStyle('h3, h4, h5, h6', 'color', '#fff');
250      setStyle('.body_wrap, .time_wrap, .navbar_tab_content', 'border', 'none');
251      qsa('li.media.active').forEach((el) => el.classList.toggle('black'));
252      setStyle('.new_tag_list li > *', 'backgroundColor', '#e60012');
253      setStyle('.sns_button_box a svg', 'fill', '#fff');
254
255      setStyle('#footer', 'backgroundColor', '#333');
256      setStyle('h1, h2, p, a, .row_1', 'color', 'white');
257      qsa('.footer_logo img').forEach((img) => img.setAttribute('src', '/images/white_logo_mao.png'));
258
259      setTimeout(function() {
260        window.scrollTo({ top: 0, behavior: 'auto' });
261      }, 100);
262      history.scrollRestoration = 'manual';
263
264      if (footer) {
265        footer.style.visibility = 'visible';
266      }
267    }, 10); 
268  }
269
270  // 必須を隠す
271  setDisplay('span.required', 'none');
272}

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.