PageSourceSearch

https://www.moneypost.jp/wp-content/plugins/shogakukan-utility/sta…shogakukan-utility-script.js?ver=20240515_1

js moneypost.jp collected 2026-10-02 04:49:26 UTC 21,365 bytes, 631 lines download raw bytes

1/**
2 * ShogakukanUtilityの名前空間
3 * @type {{}}
4 */
5window.SgkUtil = {
6  /**
7   * オブジェクトに対象のキーが存在するかチェック
8   * @param obj
9   * @param key
10   * @returns {boolean|boolean}
11   */
12  hasProperty: function(obj, key) {
13    return !!obj && Object.prototype.hasOwnProperty.call(obj, key);
14  },
15  /**
16   * ランダム文字列を取得する
17   * @returns {string}
18   */
19  getRandomStr: function() {
20    return Math.random()
21      .toString(32)
22      .substring(2);
23  },
24  /**
25   * テンプレート文字列を変換する
26   * @param templateStr
27   * @param bindMap
28   * @param cnvNum
29   */
30  cnvTemplateStr: function(templateStr, bindMap, cnvNum) {
31    cnvNum = cnvNum || 3;
32    do {
33      templateStr = templateStr.replace(/{{(.*?)}}/g, function(match, key) {
34        return bindMap[key] || '';
35      });
36    } while (--cnvNum > 0);
37    return templateStr;
38  },
39  /**
40   * UUIDを生成する
41   * @returns {string}
42   */
43  generateUuid: function() {
44    const chars = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.split('');
45    for (var i = 0, len = chars.length; i < len; i++) {
46      switch (chars[i]) {
47        case 'x':
48          chars[i] = Math.floor(Math.random() * 16).toString(16);
49          break;
50        case 'y':
51          chars[i] = (Math.floor(Math.random() * 4) + 8).toString(16);
52          break;
53      }
54    }
55    return chars.join('');
56  },
57  /**
58   * LocalStorageに格納されているUuidを取得する。存在しない場合は新規作成して取得する。
59   * @returns {string}
60   */
61  getUuid: function() {
62    var uuid = window.localStorage ? window.localStorage.getItem('__user_uuid__') : null;
63    if (uuid) return uuid;
64    uuid = window.SgkUtil.generateUuid();
65    if (window.localStorage) {
66      window.localStorage.setItem('__user_uuid__', uuid);
67    }
68    return uuid;
69  },
70  /**
71   * 対象の型を取得する
72   * @function
73   * @param {*} value 判定対象の値
74   * @returns {string} 判別結果
75   * @example
76   * Value.getType(''); // => 'String'
77   * Value.getType(0); // => 'Number'
78   * Value.getType(true); // => 'Boolean'
79   * Value.getType({}); // => 'Object'
80   * Value.getType([]); // => 'Array'
81   * Value.getType(null); // => 'Null'
82   * Value.getType(void 0); // => 'Undefined'
83   * Value.getType(function(){}); // => 'Function'
84   * Value.getType(new Date()); // => 'Date'
85   * Value.getType(JSON); // => 'JSON'
86   * Value.getType(Math); // => 'Math'
87   * Value.getType(new RegExp()); // => 'RegExp'
88   */
89  getType: function(value) {
90    return Object.prototype.toString.call(value).slice(8, -1);
91  }
92};
93
94/**
95 * ロギング関連機能定義
96 */
97(function(SgkUtil) {
98  SgkUtil.Logger = SgkUtil.Logger || {};
99  const Logger = SgkUtil.Logger;
100
101  /**
102   * encode utf8
103   * @param n
104   * @returns {string}
105   */
106  function __utf8Encode(n) {
107    var cc = String.fromCharCode;
108    var o = '';
109    var i = 0;
110    var c;
111    while (i < n.length) {
112      c = n.charCodeAt(i++);
113      o =
114        o +
115        (c < 128
116          ? cc(c)
117          : c > 127 && c < 2048
118          ? cc((c >> 6) | 192) + cc((c & 63) | 128)
119          : cc((c >> 12) | 224) + cc(((c >> 6) & 63) | 128) + cc((c & 63) | 128));
120    }
121    return o;
122  }
123  /**
124   * base64 encode a string
125   * @param {object} obj
126   * @return {string}
127   */
128  function __toBase64(obj) {
129    var m = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
130    var n = JSON.stringify(obj);
131    var o = '';
132    var i = 0;
133    var i1, i2, i3, e1, e2, e3, e4;
134    n = __utf8Encode(n);
135    while (i < n.length) {
136      i1 = n.charCodeAt(i++);
137      i2 = n.charCodeAt(i++);
138      i3 = n.charCodeAt(i++);
139      e1 = i1 >> 2;
140      e2 = ((i1 & 3) << 4) | (i2 >> 4);
141      e3 = isNaN(i2) ? 64 : ((i2 & 15) << 2) | (i3 >> 6);
142      e4 = isNaN(i2) || isNaN(i3) ? 64 : i3 & 63;
143      o = o + m.charAt(e1) + m.charAt(e2) + m.charAt(e3) + m.charAt(e4);
144    }
145    return o;
146  }
147
148  /**
149   * TDに処理ログを送信する
150   * @param {number} process_no
151   * @param {string} process_name
152   * @param {string} log_name
153   * @param {string|object} [attrs]
154   * @param {object} [options]
155   */
156  Logger.sendTdClientProcessLog = function(process_no, process_name, log_name, attrs, options) {
157    options = options || {};
158    const td_database = options.database || 'cosmi_9534';
159    const td_table = options.table || 'client_process_log';
160    const td_api_key = options.apiKey || '7848/3b0fc6c552d5272ab8a9258cd339da06a8782bc3';
161    const td_endpoint = 'https://in.treasuredata.com/js/v3/event/' + td_database + '/' + td_table;
162    log_name = log_name || 'NONE';
163
164    const xhr = new XMLHttpRequest();
165    xhr.onload = function(e) {
166      if (xhr.status === 200 || xhr.status === 304) {
167        console.log(['sendTdClientProcessLog', log_name, process_name, 'Success'].join(':'));
168      } else {
169        console.log(['sendTdClientProcessLog', log_name, process_name, 'Error'].join(':'));
170      }
171    };
172    xhr.onerror = function(e) {
173      console.log(['sendTdClientProcessLog', log_name, process_name, 'Error'].join(':'));
174    };
175    xhr.onabort = function(e) {
176      console.log(['sendTdClientProcessLog', log_name, process_name, 'Abort'].join(':'));
177    };
178    xhr.ontimeout = function(e) {
179      console.log(['sendTdClientProcessLog', log_name, process_name, 'Timeout'].join(':'));
180    };
181    attrs = attrs || {};
182    attrs =
183      ['Object', 'Array'].indexOf(SgkUtil.getType(attrs)) > -1
184        ? JSON.stringify(attrs)
185        : String(attrs);
186    const params = [
187      'api_key=' + encodeURIComponent(td_api_key),
188      'modified=' + encodeURIComponent(new Date().getTime()),
189      'data=' +
190        encodeURIComponent(
191          __toBase64({
192            log_name: log_name,
193            host: location.host,
194            uuid: SgkUtil.getUuid(),
195            process_no: process_no,
196            process_name: process_name,
197            attrs: attrs
198          })
199        )
200    ];
201    xhr.open('GET', td_endpoint + '?' + params.join('&'), true);
202    xhr.send(null);
203  };
204})(window.SgkUtil);
205
206/**
207 * Modal関連機能定義
208 */
209(function(SgkUtil) {
210  SgkUtil.Modal = SgkUtil.Modal || {};
211  const Modal = SgkUtil.Modal;
212
213  /**
214   * ModalHtml文字列を取得する
215   * @param {object} bindMap
216   * @param {string} [modalTemplate]
217   */
218  Modal.getModalHtmlStr = function(bindMap, modalTemplate) {
219    bindMap = bindMap || {};
220    bindMap.headerHtmlStr = SgkUtil.hasProperty(bindMap, 'headerHtmlStr')
221      ? bindMap.headerHtmlStr
222      : // prettier-ignore
223        '<span class="modal__title" id="{{modalId}}-title">{{modalTitle}}</span>' +
224      '<button class="modal__close" aria-label="Close modal" data-micromodal-close></button>';
225    bindMap.modalOverLayProps = SgkUtil.hasProperty(bindMap, 'modalOverLayProps')
226      ? bindMap.modalOverLayProps
227      : 'data-micromodal-close';
228    modalTemplate =
229      modalTemplate ||
230      // prettier-ignore
231      '<div class="su-modal modal micromodal-slide" id="{{modalId}}" aria-hidden="true">' +
232      '    <div class="modal__overlay" tabindex="-1" {{modalOverLayProps}}>' +
233      '        <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="{{modalId}}-title">' +
234      '            <modal-header class="modal__header" id="{{modalId}}-header">{{headerHtmlStr}}</modal-header>' +
235      '            <modal-main class="modal__content" id="{{modalId}}-content">
235{{contentHtmlStr}}</modal-main>' +
236      '            <modal-footer class="modal__footer" id="{{modalId}}-footer">{{footerHtmlStr}}</modal-footer>' +
237      '        </div>' +
238      '    </div>' +
239      '</div>';
240    return SgkUtil.cnvTemplateStr(modalTemplate, bindMap);
241  };
242
243  /**
244   * 追加済のModalDomIDを管理する
245   * @type {{}}
246   */
247  Modal.alreadyAppendModalId = {};
248
249  /**
250   * Modalを起動する
251   * @param bindMap
252   * @param options
253   * @param modalId
254   * @param reNum
255   * @return {any | string}
256   */
257  Modal.openModal = function(bindMap, options, modalId, reNum) {
258    bindMap = bindMap || {};
259    options = options || {};
260    modalId = modalId || SgkUtil.getRandomStr();
261    bindMap.modalId = modalId;
262    reNum = reNum || 0;
263    if (document.getElementById(modalId)) {
264      if (window.MicroModal) {
265        setTimeout(function() {
266          window.MicroModal.show(modalId, {
267            onShow: function(m, el, e) {
268              if (options.onShow) {
269                options.onShow(m, el, e);
270              }
271            },
272            onClose: function(m, el, e) {
273              if (options.onClose) {
274                options.onClose(m, el, e);
275              }
276              if (e) {
277                e.preventDefault();
278                e.stopPropagation();
279              }
280              if (options.deleteClose) {
281                delete Modal.alreadyAppendModalId[modalId];
282                const selfEl = document.getElementById(modalId);
283                if (selfEl) {
284                  selfEl.parentNode.removeChild(selfEl);
285                }
286              }
287            },
288            disableScroll: options.disableScroll,
289            disableFocus: options.disableFocus,
290            awaitOpenAnimation: options.awaitOpenAnimation,
291            awaitCloseAnimation: options.awaitCloseAnimation,
292            debugMode: options.debugMode
293          });
294        }, options.showDelay || 0);
295      } else {
296        console.error('ShogakukanUtilityScript: Not Found MicroModal Object.');
297      }
298    } else {
299      if (!Modal.alreadyAppendModalId[modalId]) {
300        const modalDom = document
301          .createRange()
302          .createContextualFragment(Modal.getModalHtmlStr(bindMap, options.modalTemplate));
303        document.body.appendChild(modalDom);
304        Modal.alreadyAppendModalId[modalId] = true;
305        Modal.openModal(bindMap, options, modalId, 1);
306      } else {
307        if (reNum <= 10) {
308          setTimeout(function() {
309            Modal.openModal(bindMap, options, modalId, ++reNum);
310          }, 100);
311        } else {
312          console.error('ShogakukanUtilityScript: Can Not Add Modal DOM.');
313        }
314      }
315    }
316    return modalId;
317  };
318
319  /**
320   * iframe埋込Modalを起動する
321   * @param src
322   * @param bindMap
323   * @param options
324   * @param modalId
325   * @returns {*|string}
326   */
327  Modal.openIframeModal = function(src, bindMap, options, modalId) {
328    bindMap = bindMap || {};
329    const defaultBindMap = {
330      headerHtmlStr:
331        '<span class="modal__title" id="{{modalId}}-title">{{modalTitle}}</span>' +
332        '<button class="modal__close" aria-label="Close modal" data-micromodal-close></button>',
333      contentHtmlStr:
334        '<iframe id="{{modalId}}-iframe" src="{{src}}" marginheight="0" marginwidth="0" width="{{bodyWidth}}" height="{{bodyHeight}}"></iframe>',
335      bodyWidth: window.innerWidth * 0.95,
336      bodyHeight: window.innerHeight * 0.85,
337      src: src
338    };
339    for (const key in defaultBindMap) {
340      bindMap[key] = bindMap[key] || defaultBindMap[key];
341    }
342    return Modal.openModal(bindMap, options, modalId);
343  };
344})(window.SgkUtil);
345
346/**
347 * 広告関連機能定義
348 */
349(function(SgkUtil) {
350  SgkUtil.Ad = SgkUtil.Ad || {};
351  const Ad = SgkUtil.Ad;
352
353  /**
354   * adUnit管理オブジェクト
355   * @type {{}}
356   */
357  Ad.adUnitObj = {};
358
359  /**
360   * 広告ブロッカーを使用しているユーザーかチェックする
361   * @returns {boolean}
362   */
363  Ad.isAdBlockUser = function() {
364    return !document.getElementById(window._sgkUtilConfig.dummyAdPulseId).offsetHeight;
365  };
366
367  /**
368   * 広告ブロッカーを使用しているユーザーかチェックする
369   * 疑似広告タグが追加されるのを待ってからチェックを実施
370   * @param useAdBlockFunc 広告ブロッカーを使用しているユーザーの場合に実行する関数
371   * @param notUseAdBlockFunc 広告ブロッカーを使用していないユーザーの場合に実行する関数
372   * @param options オプション
373   */
374  Ad.checkAdBlockUserInterval = function(useAdBlockFunc, notUseAdBlockFunc, options) {
375    options = options || {};
376    options.interval = options.interval || 500;
377    options.checkLimit = options.checkLimit || 10;
378    options.checkCnt = options.checkCnt || 0;
379    options.exceededLimitFunc = options.exceededLimitFunc || function() {};
380    if (window.addedAdPulse) {
381      if (Ad.isAdBlockUser()) {
382        if (useAdBlockFunc) {
383          useAdBlockFunc();
384        }
385      } else {
386        options.checkCnt++;
387        if (options.checkCnt >= options.checkLimit) {
388          if (notUseAdBlockFunc) {
389            notUseAdBlockFunc();
390          }
391          return;
392        }
393        setTimeout(function() {
394          Ad.checkAdBlockUserInterval(useAdBlockFunc, notUseAdBlockFunc, options);
395        }, options.interval);
396      }
397    } else {
398      options.checkCnt++;
399      if (options.checkCnt >= options.checkLimit) {
400        options.exceededLimitFunc();
401        console.error('ShogakukanUtilityScript:Ad.checkAdBlockUserInterval:Exceeded 
401Limit.');
402        return;
403      }
404      setTimeout(function() {
405        Ad.checkAdBlockUserInterval(useAdBlockFunc, notUseAdBlockFunc, options);
406      }, options.interval);
407    }
408  };
409
410  /**
411   * GPTモーダルウィンドウを表示する
412   * @param {string} adUnitPath
413   * @param {Array.<Array.<number>>} size
414   * @param {object} [options]
415   */
416  Ad.openGptModal = function(adUnitPath, size, options) {
417    options = options || {};
418    const reUse = options.reUse;
419    const sendLog = options.sendLog;
420    const adDivStyle = options.adDivStyle || 'text-align: center;';
421    const isArrayAdUnitPath = SgkUtil.getType(adUnitPath) === 'Array';
422    const contentHtmlStrTemplate =
423      // prettier-ignore
424      '<div id="{{adSlotDivId}}" style="{{adDivStyle}}">' +
425      '  <script>' +
426      '    window.googletag = window.googletag || {cmd: []};' +
427      '    googletag.cmd.push(function() {' +
428      "      const adSlot = googletag.defineSlot('{{adUnitPath}}', {{size}}, '{{adSlotDivId}}').addService(googletag.pubads());" +
429      '      googletag.pubads().collapseEmptyDivs();' +
430      '      googletag.enableServices();' +
431      "      googletag.display('{{adSlotDivId}}');" +
432      "      window.SgkUtil.Ad.adUnitObj['{{adUnitPath}}'] = window.SgkUtil.Ad.adUnitObj['{{adUnitPath}}'] || {};" +
433      "      window.SgkUtil.Ad.adUnitObj['{{adUnitPath}}'].adSlot = adSlot;" +
434      "      window.SgkUtil.Ad.adUnitObj['{{adUnitPath}}'].slotDivId = '{{adSlotDivId}}';" +
435      '    });' +
436      '  </script>' +
437      '</div>';
438    var contentHtmlStr = '';
439    if (isArrayAdUnitPath) {
440      contentHtmlStr =
441        '<div style="display: flex; justify-content: ' +
442        (options.wrapJustifyContent || 'center') +
443        '">' +
444        adUnitPath
445          .map(function(path, idx) {
446            return SgkUtil.cnvTemplateStr(contentHtmlStrTemplate, {
447              adSlotDivId: SgkUtil.getRandomStr(),
448              adUnitPath: path,
449              adDivStyle: SgkUtil.getType(adDivStyle) === 'Array' ? adDivStyle[idx] : adDivStyle,
450              size: JSON.stringify(size)
451            });
452          })
453          .join('') +
454        '</div>';
455    } else {
456      contentHtmlStr = SgkUtil.cnvTemplateStr(contentHtmlStrTemplate, {
457        adSlotDivId: SgkUtil.getRandomStr(),
458        adUnitPath: adUnitPath,
459        adDivStyle: adDivStyle,
460        size: JSON.stringify(size)
461      });
462    }
463    const adUnitPathKey = isArrayAdUnitPath ? adUnitPath[0] : adUnitPath;
464    Ad.adUnitObj[adUnitPathKey] = Ad.adUnitObj[adUnitPathKey] || { showCnt: 0 };
465    Ad.adUnitObj[adUnitPathKey].modalId = SgkUtil.Modal.openModal(
466      {
467        headerHtmlStr: null,
468        modalOverLayProps: null,
469        contentHtmlStr: contentHtmlStr,
470        footerHtmlStr:
471          options.footerHtmlStr ||
472          '<button data-micromodal-close style="width:100%;">広告を閉じる</button>'
473      },
474      {
475        onShow: function(m, el, e) {
476          try {
477            (isArrayAdUnitPath ? adUnitPath : [adUnitPath]).forEach(function(path) {
478              const adUnitObj = window.SgkUtil.Ad.adUnitObj[path];
479              if (adUnitObj.showCnt && reUse && adUnitObj && adUnitObj.adSlot) {
480                window.googletag.pubads().refresh([adUnitObj.adSlot]);
481              }
482              adUnitObj.showCnt = adUnitObj.showCnt || 0;
483              adUnitObj.showCnt++;
484            });
485            if (sendLog) {
486              SgkUtil.Logger.sendTdClientProcessLog(
487                10,
488                (Ad.isAdBlockUser() ? 'USE_AD_BLOCKER' : 'NOT_USE_AD_BLOCKER') + '_ON_SHOW',
489                options.logName || 'OPEN_GPT_MODAL'
490              );
491            }
492          } catch (e) {
493            // ignore
494          }
495        },
496        onClose: function(m, el, e) {
497          if (sendLog) {
498            try {
499              SgkUtil.Logger.sendTdClientProcessLog(
500                20,
501                (Ad.isAdBlockUser() ? 'USE_AD_BLOCKER' : 'NOT_USE_AD_BLOCKER') + '_ON_CLOSE',
502                options.logName || 'OPEN_GPT_MODAL'
503              );
504            } catch (e) {
505              // ignore
506            }
507          }
508          try {
509            (isArrayAdUnitPath ? adUnitPath : [adUnitPath]).forEac
509h(function(path) {
510              const adUnitObj = window.SgkUtil.Ad.adUnitObj[path];
511              if (!reUse && adUnitObj && adUnitObj.adSlot) {
512                window.googletag.destroySlots([adUnitObj.adSlot]);
513                delete window.SgkUtil.Ad.adUnitObj[path];
514              }
515            });
516          } catch (e) {
517            // ignore
518          }
519        },
520        deleteClose: !reUse,
521        showDelay: options.showDelay,
522        disableScroll: options.disableScroll,
523        disableFocus: options.disableFocus
524      },
525      reUse ? Ad.adUnitObj[adUnitPathKey].modalId : null
526    );
527  };
528
529  /**
530   * リワード広告で登録するハンドラーが複数回実行されないようにするための管理オブジェクト
531   * @type {{}}
532   */
533  Ad.rewardAdEventHandlerId = {};
534
535  /**
536   * リワード広告を制御するハンドラーを登録する
537   * @param {string} adUnitPath 広告ユニットバス
538   * @param {object} eventHandler イベントハンドラーオブジェクト(key: イベント名, value: ハンドラー関数)
539   * @param {boolean} refresh 広告Slotをリフレッシュするかどうか(disableInitialLoad()を実施している場合はtrueを指定)
540   */
541  Ad.setRewardAdHandler = function(adUnitPath, eventHandler, refresh) {
542    window.googletag = window.googletag || { cmd: [] };
543    const googletag = window.googletag;
544    googletag.cmd.push(function() {
545      const rewardedSlot = googletag
546        .defineOutOfPageSlot(adUnitPath, googletag.enums.OutOfPageFormat.REWARDED)
547        .addService(googletag.pubads());
548      googletag.enableServices();
549      const bindObj = {
550        rewardedSlot: rewardedSlot
551      };
552      if (eventHandler) {
553        // リワード広告を閉じる際にはスロットの破棄をまず実行
554        googletag.pubads().addEventListener(
555          'rewardedSlotClosed',
556          (function(execId) {
557            return function f(evt) {
558              if (!Ad.rewardAdEventHandlerId[execId]) {
559                googletag.destroySlots([rewardedSlot]);
560                googletag.pubads().removeEventListener('rewardedSlotClosed', f);
561                Ad.rewardAdEventHandlerId[execId] = true;
562              }
563            };
564          })(SgkUtil.getRandomStr())
565        );
566        for (const key in eventHandler) {
567          const handler = eventHandler[key];
568          if (SgkUtil.getType(handler) === 'Function') {
569            googletag.pubads().addEventListener(
570              key,
571              (function(execId) {
572                return function f(evt) {
573                  if (!Ad.rewardAdEventHandlerId[execId]) {
574                    handler.bind(bindObj)(evt);
575                    googletag.pubads().removeEventListener(key, f);
576                    Ad.rewardAdEventHandlerId[execId] = true;
577                  }
578                };
579              })(SgkUtil.getRandomStr())
580            );
581          }
582        }
583      }
584      googletag.display(rewardedSlot);
585      if (refresh) {
586        googletag.pubads().refresh([rewardedSlot]);
587      }
588    });
589  };
590})(window.SgkUtil);
591
592/**
593 * ためし読み関連機能定義
594 */
595(function(SgkUtil) {
596  SgkUtil.Book = SgkUtil.Book || {};
597  const Book = SgkUtil.Book;
598
599  Book.contentIdModalIdMap = {};
600
601  /**
602   * 試し読みModalを起動する
603   * @param contentId
604   * @param title
605   * @param options
606   */
607  Book.openTameshiyomiModal = function(contentId, title, options) {
608    options = options || {};
609    const modalId = Book.contentIdModalIdMap[contentId];
610    if (modalId) {
611      const tgtIframe = document.getElementById(modalId + '-iframe');
612      if (tgtIframe) {
613        tgtIframe.width = options.bodyWidth || window.innerWidth * 0.95;
614        tgtIframe.height = options.bodyHeight || window.innerHeight * 0.85;
615        tgtIframe.style = null;
616      }
617    }
618    Book.contentIdModalIdMap[contentId] = SgkUtil.Modal.openIframeModal(
619      'https://{{tameshiyomiDomain}}/{{contentId}}',
620      {
621        contentId: contentId,
622        modalTitle: title,
623        bodyWidth: options.bodyWidth,
624        bodyHeight: options.bodyHeight,
625        tameshiyomiDomain: options.tameshiyomiDomain || 'media.tameshiyo.me'
626      },
627      {},
628      modalId
629    );
630  };
631})(window.SgkUtil);

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.