PageSourceSearch

https://sam1039.com/wp-content/plugins/proradio-simplechat/assets/js/chat.js?ver=9.0

js sam1039.com collected 2026-10-02 23:09:42 UTC 10,430 bytes, 343 lines download raw bytes

1(function ($) {
2  'use strict';
3
4  // Stato globale minimale (un solo polling per pagina)
5  var GLOBAL = window.PRCHAT_APP || (window.PRCHAT_APP = {
6    pollId: null,
7    initedOnce: false
8  });
9
10  // Chiavi localStorage condivise (no cookie)
11  var LS = {
12    USERNAME: 'prchat_username',
13    PRIVACY:  'prchat_privacy',
14    YOB:      'prchat_yob'
15  };
16
17  // --------- UTIL ----------
18  function lsGet(key, def) { try { var v = localStorage.getItem(key); return (v==null)?def:v; } catch(e){ return def; } }
19  function lsSet(key, val) { try { localStorage.setItem(key, val); } catch(e){} }
20  function lsDel(key)      { try { localStorage.removeItem(key); } catch(e){} }
21
22  function nowYear(){ return (new Date()).getFullYear(); }
23
24  function renderMessage(m){
25    var time = new Date(m.t*1000).toLocaleTimeString();
26    return '<div class="prchat-rowmsg" data-id="'+m.id+'">' +
27      '<span class="prchat-time">['+time+']</span> ' +
28      '<span class="prchat-user">'+m.u+':</span> ' +
29      '<span class="prchat-text">'+m.m+'</span>' +
30      '</div>';
31  }
32
33  // --------- ISTANZA ----------
34  // Ogni wrapper gestisce il proprio stato, salvato via $.data
35  function getState($wrap){
36    var st = $wrap.data('prchatState');
37    if (!st) {
38      st = {
39        lastId: 0,
40        busy: false,
41        unlocked: !PRCHAT.agegate, // se agegate disattivo, sbloccato by default
42        yob: null,
43        initialized: false
44      };
45      $wrap.data('prchatState', st);
46    }
47    return st;
48  }
49
50  function scope($wrap, sel){
51    // limita la ricerca all'interno del wrapper (supporta id duplicati)
52    return $wrap.find(sel);
53  }
54
55  function buildEmojiPicker($wrap){
56    var $pop = scope($wrap, '#prchat-emoji-pop');
57    if (!$pop.length) return;
58    var list = (window.PRCHAT && PRCHAT.emojis) || [];
59    var html = '<div class="prchat-emoji-grid">';
60    for (var i=0;i<list.length;i++){
61      var e = list[i];
62      html += '<button type="button" class="prchat-emoji-item" data-emoji="'+e+'">'+e+'</button>';
63    }
64    html += '</div>';
65    $pop.html(html);
66  }
67
68  function buildYOB($wrap){
69    if (!PRCHAT.agegate) return;
70    var $sel = scope($wrap, '#prchat-yob');
71    if (!$sel.length) return;
72    if ($sel.children('option').length === 0) {
73      $sel.append('<option value="">'+PRCHAT.strings.yob+'</option>');
74      var yMax = PRCHAT.yMax || nowYear();
75      var yMin = PRCHAT.yMin || 1900;
76      for (var y=yMax; y>=yMin; y--) $sel.append('<option value="'+y+'">'+y+'</option>');
77    }
78  }
79
80  function prefillFromLocal($wrap){
81    var st = getState($wrap);
82    var u = lsGet(LS.USERNAME, '');
83    if (u) scope($wrap, '#prchat-username').val(u);
84
85    var pv = lsGet(LS.PRIVACY, '');
86    if (pv === '1') scope($wrap, '#prchat-privacy').prop('checked', true);
87
88    var yob = lsGet(LS.YOB, '');
89    if (yob) {
90      scope($wrap, '#prchat-yob').val(yob);
91      st.yob = yob;
92      if (PRCHAT.agegate) {
93        var age = nowYear() - parseInt(yob, 10);
94        if (PRCHAT.minAge && age >= PRCHAT.minAge) {
95          st.unlocked = true;
96          $wrap.removeClass('prchat-locked');
97          scope($wrap, '#prchat-agegate').remove();
98        }
99      }
100    }
101  }
102
103  function insertAtCursor($input, text) {
104    var el = $input.get(0);
105    if (!el) return;
106    el.focus();
107    if (typeof el.selectionStart === 'number') {
108      var start = el.selectionStart, end = el.selectionEnd;
109      var val = el.value;
110      el.value = val.slice(0,start) + text + val.slice(end);
111      el.selectionStart = el.selectionEnd = start + text.length;
112    } else {
113      el.value += text;
114    }
115    $input.trigger('input');
116  }
117
118  function lockUsername($wrap){
119    var $u = scope($wrap, '#prchat-username');
120    if ($u.length && !$u.prop('disabled')) {
121      $u.prop('disabled', true).attr('title', 'Username locked for this session');
122    }
123  }
124
125  // GET messaggi per istanza
126  function loadMessages($wrap){
127    var st = getState($wrap);
128    if (PRCHAT.agegate && !st.unlocked) return;
129    if (st.busy) return;
130
131    var $body = scope($wrap, '#prchat-body');
132    if (!$body.length) return;
133
134    st.busy = true;
135    $.post(PRCHAT.ajax, {
136      action: 'prchat_get',
137      nonce: PRCHAT.nonce,
138      since: st.lastId
139    }, function(resp){
140      if (resp && resp.success && resp.data && resp.data.messages) {
141        resp.data.messages.forEach(function(m){
142          $body.append(renderMessage(m));
143          st.lastId = Math.max(st.lastId, m.id);
144        });
145        if (resp.data.messages && resp.data.messages.length) {
146          $body.scrollTop($body[0].scrollHeight);
147        }
148      }
149    }).always(function(){ st.busy = false; });
150  }
151
152  // POST messaggio per istanza
153  function sendMessage($wrap, u, m, pv, hp) {
154    var st = getState($wrap);
155    return $.post(PRCHAT.ajax, {
156      action: 'prchat_post',
157      nonce: PRCHAT.nonce,
158      u: u,
159      m: m,
160      pv: pv ? '1' : '0',
161      hp: hp || '',
162      yob: st.yob || ''
163    });
164  }
165
166  // Inizializza UNA istanza
167  function initInstance($wrap){
168    var st = getState($wrap);
169    if (st.initialized) return;
170
171    // Build UI parziali
172    buildEmojiPicker($wrap);
173    buildYOB($wrap);
174    prefillFromLocal($wrap);
175
176    // Primo load se già sbloccata
177    if (st.unlocked) loadMessages($wrap);
178
179    st.initialized = true;
180    $wrap.attr('data-prchat-initialized', 'true');
181  }
182
183  // Inizializza TUTTE le istanze presenti
184  function initAll(){
185    $('.prchat-wrap').each(function(){
186      initInstance($(this));
187    });
188  }
189
190  // --------- EVENTI DELEGATI (una sola volta a documento) ----------
191  function bindDelegatedEvents(){
192    if (GLOBAL.initedOnce) return;
193    GLOBAL.initedOnce = true;
194
195    // Unlock (per istanza)
196    $(document).on('click', '#prchat-unlock', function(){
197      var $wrap = $(this).closest('.prchat-wrap');
198      var st = getState($wrap);
199      var $yob = scope($wrap, '#prchat-yob');
200      var yob = $yob.val();
201      if (!yob) { alert(PRCHAT.strings.yob); return; }
202      st.yob = yob;
203      lsSet(LS.YOB, yob);
204      var age = nowYear() - parseInt(yob, 10);
205      if (PRCHAT.minAge && age < PRCHAT.minAge) { alert(PRCHAT.strings.age); return; }
206      st.unlocked = true;
207      $wrap.removeClass('prchat-locked');
208      scope($wrap, '#prchat-agegate').remove();
209      loadMessages($wrap);
210    });
211
212    // Emoji toggle (istanza)
213    $(document).on('click', '#prchat-emoji-btn', function(e){
214      e.preventDefault();
215      var $wrap = $(this).closest('.prchat-wrap');
216      var $pop = scope($wrap, '#prchat-emoji-pop');
217      var isOpen = !$pop.attr('hidden');
218      if (isOpen) { $pop.attr('hidden', true); $(this).attr('aria-expanded','false'); }
219      else { $pop.attr('hidden', false); $(this).attr('aria-expanded','true'); }
220    });
221
222    // Emoji chiusura click fuori
223    $(document).on('click', function(e){
224      var $t = $(e.target);
225      if (!$t.closest('#prchat-emoji-pop').length && !$t.closest('#prchat-emoji-btn').length) {
226        $('.prchat-emoji-pop').attr('hidden', true);
227        $('#prchat-emoji-btn').attr('aria-expanded','false');
228      }
229    });
230
231    // Emoji pick (istanza)
232    $(document).on('click', '.prchat-emoji-item', function(){
233      var $wrap = $(this).closest('.prchat-wrap');
234      var $input = scope($wrap, '#prchat-message');
235      insertAtCursor($input, $(this).data('emoji'));
236    });
237
238    // Persistenza campi
239    $(document).on('input', '#prchat-username', function(){
240      lsSet(LS.USERNAME, $.trim($(this).val()));
241    });
242    $(document).on('change', '#prchat-privacy', function(){
243      lsSet(LS.PRIVACY, $(this).is(':checked') ? '1' : '0');
244    });
245    $(document).on('change', '#prchat-yob', function(){
246      lsSet(LS.YOB, $(this).val() || '');
247    });
248
249    // Submit (istanza)
250    $(document).on('submit', '#prchat-form', function(e){
251      e.preventDefault();
252      var $wrap = $(this).closest('.prchat-wrap');
253      var st = getState($wrap);
254
255      if (PRCHAT.agegate && !st.unlocked) { alert(PRCHAT.strings.unlock); return; }
256
257      var $u  = scope($wrap, '#prchat-username');
258      var $m  = scope($wrap, '#prchat-message');
259      var $pv = scope($wrap, '#prchat-privacy');
260      var $hp = scope($wrap, '#prchat_hp');
261
262      var u  = $.trim($u.val());
263      var m  = $.trim($m.val());
264      var pv = $pv.is(':checked');
265      var hp = $hp.val();
266
267      if (!u || !m || !pv) { alert(PRCHAT.strings.required); return; }
268
269      lsSet(LS.USERNAME, u);
270      lsSet(LS.PRIVACY, pv ? '1' : '0');
271
272      var $btn = $(this).find('.prchat-btn').prop('disabled', true);
273      sendMessage($wrap, u, m, pv, hp).done(function(resp){
274        if (resp && resp.success && resp.data && resp.data.message) {
275          var $body = scope($wrap, '#prchat-body');
276          var msg = resp.data.message;
277          $body.append(renderMessage(msg));
278          st.lastId = Math.max(st.lastId, msg.id);
279          $m.val('');
280          $body.scrollTop($body[0].scrollHeight);
281          // lock username per istanza
282          lockUsername($wrap);
283        } else if (resp && resp.data && resp.data.error === 'rate') {
284          alert(PRCHAT.strings.rate);
285        } else if (resp && resp.data && resp.data.error === 'age') {
286          alert(PRCHAT.strings.age);
287        }
288      }).fail(function(xhr){
289        if (xhr && xhr.responseJSON) {
290          var err = xhr.responseJSON.data && xhr.responseJSON.data.error;
291          if (err === 'banned') alert(PRCHAT.strings.banned);
292          else if (err === 'rate') alert(PRCHAT.strings.rate);
293          else if (err === 'age') alert(PRCHAT.strings.age);
294        }
295      }).always(function(){ $btn.prop('disabled', false); });
296    });
297  }
298
299  // --------- POLLING GLOBALE ----------
300  function ensurePolling(){
301    if (GLOBAL.pollId) return;
302    GLOBAL.pollId = setInterval(function(){
303      $('.prchat-wrap').each(function(){
304        var $wrap = $(this);
305        var st = getState($wrap);
306        if (!st.initialized) return; // non ancora pronto
307        loadMessages($wrap);
308      });
309    }, 4000);
310  }
311
312  // --------- BOOT ----------
313  function boot(){
314    bindDelegatedEvents();
315    initAll();
316    ensurePolling();
317  }
318
319  // Primo avvio
320  $(function(){ boot(); });
321
322  // AJAX nav custom (ProRadio)
323  $(window).on('qtAjaxpageLoadEnd', function(){
324    boot();
325  });
326
327  // Elementor / PJAX / altri injector
328  try {
329    var obs = new MutationObserver(function(){
330      boot();
331    });
332    obs.observe(document.body, { childList: true, subtree: true });
333  } catch(e){ /* noop */ }
334
335})(jQuery);
336
337
338
339
340
341
342
343

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.