PageSourceSearch

https://lagom-japan.co.jp/wp-content/plugins/channel-io/channel_plugin_script.js?ver=0.18

js lagom-japan.co.jp collected 2026-10-06 19:14:46 UTC 5,142 bytes, 161 lines download raw bytes

1;
2function ch_parseInt(data) {
3  if (!data) { return undefined; }
4  try {
5    return parseInt(data);
6  } catch (e) {
7    return undefined;
8  }
9}
10
11(function() {
12  var w = window;
13  if (w.ChannelIO) {
14    return (window.console.error || window.console.log || function(){})('ChannelIO script included twice.');
15  }
16  var ch = function() {
17    ch.c(arguments);
18  };
19  ch.q = [];
20  ch.c = function(args) {
21    ch.q.push(args);
22  };
23  w.ChannelIO = ch;
24
25  function loadSdk() {
26    if (w.ChannelIOInitialized) {
27      return;
28    }
29    w.ChannelIOInitialized = true;
30    var s = document.createElement('script');
31    s.type = 'text/javascript';
32    s.async = true;
33    s.src = 'https://cdn.channel.io/plugin/ch-plugin-web.js';
34    s.charset = 'UTF-8';
35    var x = document.getElementsByTagName('script')[0];
36    x.parentNode.insertBefore(s, x);
37  }
38
39  function buildBaseSettings() {
40    return {
41      "pluginKey": channel_io_options.channel_io_plugin_key,
42      "hideChannelButtonOnBoot": channel_io_options.channel_io_hide_default_launcher === 'on',
43      "customLauncherSelector": channel_io_options.channel_io_custom_launcher_selector,
44      "mobileMessengerMode": channel_io_options.channel_io_mobile_messenger_mode === 'on' ? 'iframe' : undefined,
45      "zIndex": ch_parseInt(channel_io_options.channel_io_z_index),
46      "scriptProvider": "channel",
47      "scriptPlatform": "wordpress",
48      "scriptVersion": "2.0.0"
49    };
50  }
51
52  function bootAnonymous() {
53    ChannelIO('boot', buildBaseSettings());
54  }
55
56  function bootWithProfile(me) {
57    var settings = buildBaseSettings();
58    if (me && me.login && me.memberId) {
59      settings.memberId = me.memberId;
60      if (me.memberHash) {
61        settings.memberHash = me.memberHash;
62      }
63      settings.profile = me.profile || {};
64    }
65    ChannelIO('boot', settings);
66  }
67
68  // 페이지 HTML 에 회원 정보를 박지 않고, AJAX profile endpoint 에서 받아 boot 한다.
69  // 이렇게 하면 어떤 페이지 캐시 (LiteSpeed Cache, WP Rocket 등) 환경에서도
70  // 한 회원의 정보가 다른 방문자에게 노출되는 누출이 발생하지 않는다.
71  //
72  // fetch / XHR 의 정상 응답 / 에러 외에 응답이 stalled 되어 promise 가 영영
73  // settle 안 되는 케이스(slow 3G, 끊긴 네트워크, 서버 hang 등)도 막아야 한다.
74  // settle 안 되면 start() 의 started 가드 때문에 재시도도 없이 ChannelIO('boot')
75  // 자체가 호출되지 않아 위젯이 영원히 안 뜬다. settled 플래그 + 5초 타임아웃으로
76  // 어떤 경로로든 정확히 한 번 익명 부트 fallback 이 보장되도록 한다.
77  function fetchProfileAndBoot() {
78    if (!channel_io_options || !channel_io_options.profile_url) {
79      bootAnonymous();
80      return;
81    }
82
83    var settled = false;
84    var timeoutId = window.setTimeout(function() {
85      if (settled) {
86        return;
87      }
88      settled = true;
89      bootAnonymous();
90    }, 5000);
91
92    function finish(callback) {
93      if (settled) {
94        return;
95      }
96      settled = true;
97      window.clearTimeout(timeoutId);
98      callback();
99    }
100
101    if (typeof window.fetch === 'function') {
102      window.fetch(channel_io_options.profile_url, {
103        credentials: 'same-origin'
104      })
105        .then(function(res) { return res.ok ? res.json() : null; })
106        .then(function(me) {
107          finish(function() { bootWithProfile(me); });
108        })
109        .catch(function() { finish(bootAnonymous); });
110      return;
111    }
112
113    // fetch 미지원 브라우저용 fallback
114    try {
115      var xhr = new XMLHttpRequest();
116      xhr.open('GET', channel_io_options.profile_url, true);
117      xhr.withCredentials = true;
118      xhr.onreadystatechange = function() {
119        if (xhr.readyState !== 4) return;
120        if (xhr.status >= 200 && xhr.status < 300) {
121          try {
122            var me = JSON.parse(xhr.responseText);
123            finish(function() { bootWithProfile(me); });
124          } catch (e) {
125            finish(bootAnonymous);
126          }
127        } else {
128          finish(bootAnonymous);
129        }
130      };
131      xhr.onerror = function() { finish(bootAnonymous); };
132      xhr.send();
133    } catch (e) {
134      finish(bootAnonymous);
135    }
136  }
137
138  // start() 는 한 번만 실행되어야 한다. document.readyState 검사 + DOMContentLoaded
139  // + load 세 경로 중 둘 이상이 동작할 수 있어 (예: load 가 DOMContentLoaded 뒤에
140  // 한 번 더 발생) 가드 없이 두면 fetchProfileAndBoot() 가 두 번 호출되어 /profile
141  // 호출과 ChannelIO('boot', ...) 가 중복 실행된다. loadSdk() 는 자체 가드(
142  // ChannelIOInitialized) 가 있지만 boot 호출 자체는 막지 못하므로 여기서 차단.
143  var started = false;
144  function start() {
145    if (started) {
146      return;
147    }
148    started = true;
149    loadSdk();
150    fetchProfileAndBoot();
151  }
152
153  if (document.readyState === 'complete') {
154    start();
155  } else if (window.attachEvent) {
156    window.attachEvent('onload', start);
157  } else {
158    window.addEventListener('DOMContentLoaded', start, false);
159    window.addEventListener('load', start, false);
160  }
161})();

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.