PageSourceSearch

https://compuempresa.com/js/main.js

js compuempresa.com collected 2026-10-02 20:36:08 UTC 6,502 bytes, 193 lines download raw bytes

1(function(){
2  // No ejecutar en moviles / pantallas < lg (Bootstrap: 992px)
3  if (window.matchMedia && window.matchMedia('(max-width: 991.98px)').matches) return;
4
5  const FEED_URL = window.location.origin + "/ajax/live_feed.php";
6
7  const bar  = document.getElementById('ceLiveBar');
8  const text = document.getElementById('ceLiveText');
9  if (!bar || !text) return;
10
11  let items = [];
12  let idx = 0;
13
14  function esc(str){
15    return String(str).replace(/[&<>"']/g, m => ({
16      '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'
17    }[m]));
18  }
19
20  function timeAgo(ts){
21    // ts viene en segundos (unix). Forzamos número por si llega string.
22    const t = Number(ts || 0);
23    const s = Math.max(0, Math.floor(Date.now()/1000 - t));
24
25    // Evita "hace 0 segundos"
26    if (s === 0) return 'hace un momento';
27
28    if (s < 60) return `hace ${s} segundo${s === 1 ? '' : 's'}`;
29    const m = Math.floor(s / 60);
30    if (m < 60) return `hace ${m} minuto${m === 1 ? '' : 's'}`;
31    const h = Math.floor(m / 60);
32    return `hace ${h} hora${h === 1 ? '' : 's'}`;
33  }
34
35  function renderOne(){
36    if (!items.length) { bar.hidden = true; return; }
37    bar.hidden = false;
38
39    const it = items[idx % items.length];
40    idx++;
41
42    const ago  = timeAgo(it.ts);
43    const city = esc(it.place_label || 'Perú');
44    const name = esc(it.anchor || it.company_name || 'Empresa');
45    const url  = (it.url && typeof it.url === 'string') ? it.url : '';
46
47    if (url) {
48      text.innerHTML = `<a class="meta-live__link" href="${esc(url)}">${name}</a> visto <span class="meta_live__time_ago">${ago}</span> en <b>${city}</b> <img src="${window.location.origin}/images/flags/pe.png" alt="PE" width="20" height="14" loading="lazy" class="meta_live__flag">`;
49    } else {
50      text.innerHTML = `<b>${name}</b> visto <span class="meta_live__time_ago">${ago}</span> en <b>${city}</b>`;
51    }
52  }
53
54  async function fetchFeed(){
55    try{
56      const r = await fetch(FEED_URL, { credentials:'same-origin', cache:'no-store' });
57      if (!r.ok) throw new Error('bad_response');
58      const data = await r.json();
59      if (Array.isArray(data)) items = data;
60      renderOne();
61    } catch(e){
62      // falla silencioso
63    }
64  }
65
66  // Rotación suave (cada 4s)
67  setInterval(renderOne, 4000);
68
69  // Refresh del feed (cada 15s)
70  fetchFeed();
71  setInterval(fetchFeed, 15000);
72})();
73
74
75
76(function(){
77  const btn = document.getElementById('btnFichaUpdate');
78  if(!btn) return;
79
80  const endpoint = "../ajax/fichaUpdate.php";
81  const ruc = (btn.getAttribute('data-ruc') || '').trim();
82  if(!ruc) { btn.style.display = 'none'; return; }
83
84  // ---------- Cookie helpers ----------
85  function setCookie(name, value, days){
86    try{
87      const d = new Date();
88      d.setTime(d.getTime() + (days*24*60*60*1000));
89      document.cookie = name + "=" + encodeURIComponent(value) + "; expires=" + d.toUTCString() + "; path=/; SameSite=Lax";
90    }catch(e){}
91  }
92  function getCookie(name){
93    try{
94      const key = name + "=";
95      const parts = document.cookie.split(';');
96      for(let i=0;i<parts.length;i++){
97        let c = parts[i].trim();
98        if(c.indexOf(key) === 0) return decodeURIComponent(c.substring(key.length));
99      }
100    }catch(e){}
101    return "";
102  }
103
104  // cookie por empresa (RUC)
105  const cookieKey = "ce_ficha_update_" + ruc;
106
107  // Si ya pidió actualización antes (cookie), ocultar el botón aunque PHP lo muestre
108  if (getCookie(cookieKey) === "1") {
109    btn.style.display = "none";
110    return;
111  }
112
113  // ---------- Toast Bootstrap ----------
114  const toastEl = document.getElementById('ceToast');
115  const toastBody = document.getElementById('ceToastBody');
116
117  function showToast(type, msg){
118    // type: success | danger | warning | info
119    if(!toastEl || !toastBody) return;
120
121    // background
122    toastEl.classList.remove('text-bg-success','text-bg-danger','text-bg-warning','text-bg-info','text-bg-dark');
123    if(type === 'success') toastEl.classList.add('text-bg-success');
124    else if(type === 'danger') toastEl.classList.add('text-bg-danger');
125    else if(type === 'warning') toastEl.classList.add('text-bg-warning');
126    else if(type === 'info') toastEl.classList.add('text-bg-info');
127    else toastEl.classList.add('text-bg-dark');
128
129    toastBody.textContent = msg || '—';
130
131    try{
132      const t = bootstrap.Toast.getOrCreateInstance(toastEl, { delay: 5500 });
133      t.show();
134    }catch(e){
135      // fallback silencioso
136    }
137  }
138
139  function setBtnLoading(on){
140    if(on){
141      btn.disabled = true;
142      btn.dataset._old = btn.innerHTML;
143      btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2" aria-hidden="true"></span>Enviando...';
144    }else{
145      btn.disabled = false;
146      if(btn.dataset._old) btn.innerHTML = btn.dataset._old;
147    }
148  }
149
150  btn.addEventListener('click', async function(){
151    setBtnLoading(true);
152
153    try{
154      const body = new URLSearchParams({ type: 'revision', ruc: ruc });
155
156      const res = await fetch(endpoint, {
157        method: 'POST',
158        credentials: 'same-origin',
159        headers: {
160          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
161          'X-Requested-With': 'XMLHttpRequest',
162          'Accept': 'application/json'
163        },
164        body: body.toString()
165      });
166
167      const ct = (res.headers.get('content-type') || '').toLowerCase();
168      const data = ct.includes('application/json') ? await res.json().catch(()=>null) : null;
169
170      if(res.ok && data && data.ok){
171        // Persistir (30 días) para que no reaparezca al refrescar
172        setCookie(cookieKey, "1", 30);
173
174        showToast('success', data.msg || 'Solicitud enviada. Revisaremos la ficha pronto.');
175
176        // UX: cambiar a “enviado” y ocultar
177        btn.classList.remove('btn-outline-secondary');
178        btn.classList.add('btn-outline-success');
179        btn.innerHTML = '<i class="bi bi-check2"></i> Solicitud enviada';
180        setTimeout(()=>{ btn.style.display = 'none'; }, 900);
181        return;
182      }
183
184      const msg = (data && data.msg) ? data.msg : 'No se pudo enviar la solicitud. Intenta nuevamente.';
185      showToast('danger', msg);
186
187    }catch(e){
188      showToast('danger', 'Error de red. Intenta nuevamente.');
189    }finally{
190      if(btn.style.display !== 'none') setBtnLoading(false);
191    }
192  });
193})();

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.