(function (){
'use strict';
var root=document.getElementById('hwpfc-comments');
if(!root){ return; }
var CFG={
ajax: root.getAttribute('data-ajax')||(typeof HWPFC!=='undefined' ? HWPFC.ajax:''),
postId: root.getAttribute('data-post')||(typeof HWPFC!=='undefined' ? HWPFC.postId:''),
forum: root.getAttribute('data-forum')||(typeof HWPFC!=='undefined' ? HWPFC.forum:'')
};
if(!CFG.ajax||!CFG.postId){ return; }
var box=root.querySelector('.hwpfc-box');
var state={ user: null, csrf: '', login_url: '', logout_url: '', register_url: '', topic_url: '', topic_id: 0, guests_enabled: false };
var commentsById={};
var activeEditor=null;
document.addEventListener('focusin', function (e){
if(e.target&&e.target.classList&&e.target.classList.contains('hwpfc-editor')){
activeEditor=e.target;
}});
function esc(s){
var d=document.createElement('div');
d.textContent=(s==null ? '':String(s));
return d.innerHTML;
}
function fmtDate(iso){
if(!iso){ return ''; }
var d=new Date(iso);
if(isNaN(d.getTime())){ return ''; }
try {
return d.toLocaleDateString('es-ES', { day: 'numeric', month: 'long', year: 'numeric' }) +
' ' + d.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });
} catch (e){
return d.toLocaleString();
}}
function avatar(url, name){
if(url){
return '<img src="' + esc(url) + '" alt="' + esc(name) + '" loading="lazy">';
}
return '<img src="data:image/svg+xml;utf8,' +
encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="44" height="44"><rect width="44" height="44" fill="#cfcfcf"/></svg>') +
'" alt="">';
}
var ICON_LIKE='<svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true"><path fill="currentColor" d="M2 21h2.5V9H2v12zm20-9.6c0-.9-.8-1.7-1.7-1.7h-5.3l.8-3.9v-.3c0-.4-.2-.7-.4-1l-.9-.9-5.6 5.6c-.3.3-.5.7-.5 1.2v8.1c0 .9.8 1.7 1.7 1.7h7.5c.7 0 1.3-.4 1.6-1l2.5-5.9c.1-.2.1-.4.1-.6v-1.6z"/></svg>';
var ICON_DISLIKE='<svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true"><path fill="currentColor" d="M22 3h-2.5v12H22V3zM2 12.6c0 .9.8 1.7 1.7 1.7H9l-.8 3.9v.3c0 .4.2.7.4 1l.9.9 5.6-5.6c.3-.3.5-.7.5-1.2V5.5c0-.9-.8-1.7-1.7-1.7H6.4c-.7 0-1.3.4-1.6 1L2.3 10.7c-.1.2-.1.4-.1.6v1.3z"/></svg>';
function reactBtns(c){
var likeOn=c.my==='like' ? ' is-on':'';
var disOn=c.my==='dislike' ? ' is-on':'';
return '<div class="hwpfc-react">' +
'<button type="button" class="hwpfc-vote hwpfc-like' + likeOn + '" data-id="' + esc(c.id) + '" data-type="like" title="Me gusta">' +
ICON_LIKE + '<span class="hwpfc-n">' + esc(c.likes||0) + '</span></button>' +
'<button type="button" class="hwpfc-vote hwpfc-dislike' + disOn + '" data-id="' + esc(c.id) + '" data-type="dislike" title="No me gusta">' +
ICON_DISLIKE + '<span class="hwpfc-n">' + esc(c.dislikes||0) + '</span></button>' +
'</div>';
}
function commentHTML(c){
commentsById[c.id]=c;
var name=c.url
? '<a class="hwpfc-c-name" href="' + esc(c.url) + '" target="_blank" rel="noopener">' + esc(c.name) + '</a>'
: '<span class="hwpfc-c-name">' + esc(c.name) + '</span>';
var editedTag=c.edited ? '<span class="hwpfc-edited" title="Editado">(editado)</span>':'';
var isAdmin = !!(state.user&&state.user.is_admin);
var ownActions='';
if(c.mine&&!c.guest){ ownActions +='<button type="button" class="hwpfc-edit" data-id="' + esc(c.id) + '">Editar</button>'; }
if(isAdmin){ ownActions +='<button type="button" class="hwpfc-del" data-id="' + esc(c.id) + '">Eliminar</button>'; }
return '<li class="hwpfc-item" data-id="' + esc(c.id) + '">' +
'<div class="hwpfc-c-avatar">' + avatar(c.photo, c.name) + '</div>' +
'<div class="hwpfc-c-body">' +
'<div class="hwpfc-c-head">' + name + '<span class="hwpfc-c-date">' + esc(fmtDate(c.date)) + '</span>' + editedTag + '</div>' +
'<div class="hwpfc-c-text">' + (c.html||'') + '</div>' +
'<div class="hwpfc-c-foot">' + reactBtns(c) +
'<div class="hwpfc-c-actions">' +
'<button type="button" class="hwpfc-reply" data-id="' + esc(c.id) + '"><span class="hwpfc-reply-ico">&#8617;</span> Responder</button>' +
ownActions +
'</div></div></div></li>';
}
function buildQuote(c){
var contents=c.html||'';
return '<blockquote class="ipsQuote" data-ipsquote="" ' +
'data-ipsquote-userid="' + esc(c.author_id||0) + '" ' +
'data-ipsquote-username="' + esc(c.name) + '" ' +
'data-ipsquote-contentapp="forums" data-ipsquote-contenttype="forums" ' +
'data-ipsquote-contentclass="forums_Topic" ' +
'data-ipsquote-contentid="' + esc(state.topic_id||0) + '" ' +
'data-ipsquote-contentcommentid="' + esc(c.id) + '">' +
'<header class="ipsQuote_citation">' + esc(c.name) + ' dijo:</header>' +
'<div class="ipsQuote_contents">' + contents + '</div>' +
'</blockquote><p><br></p>';
}
function quoteComment(id){
var c=commentsById[id];
if(!c){ return; }
if(!state.user){
if(state.guests_enabled){
openGuestForm();
var ged=box.querySelector('.hwpfc-guest-form .hwpfc-editor');
if(ged){
activeEditor=ged;
insertHtmlAtCursor(buildQuote(c));
ged.focus();
var gform=box.querySelector('.hwpfc-guest-form');
if(gform){ gform.scrollIntoView({ behavior: 'smooth', block: 'center' });}}
return;
}
window.location.href=state.login_url;
return;
}
var ed=editor();
if(!ed){ return; }
insertHtmlAtCursor(buildQuote(c));
ed.focus();
var form=box.querySelector('.hwpfc-form');
if(form){ form.scrollIntoView({ behavior: 'smooth', block: 'center' });}}
var SVG={
ul: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="9" y1="6" x2="20" y2="6"/><line x1="9" y1="12" x2="20" y2="12"/><line x1="9" y1="18" x2="20" y2="18"/><circle cx="4" cy="6" r="1.4" fill="currentColor" stroke="none"/><circle cx="4" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="4" cy="18" r="1.4" fill="currentColor" stroke="none"/></svg>',
ol: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="10" y1="6" x2="20" y2="6"/><line x1="10" y1="12" x2="20" y2="12"/><line x1="10" y1="18" x2="20" y2="18"/><text x="2" y="8" font-size="7" fill="currentColor" stroke="none">1</text><text x="2" y="14" font-size="7" fill="currentColor" stroke="none">2</text><text x="2" y="20" font-size="7" fill="currentColor" stroke="none">3</text></svg>',
quote: '<svg viewBox="0 0 24 24" width="17" height="17" fill="currentColor"><path d="M6 7C4.3 7 3 8.3 3 10s1.3 3 3 3c.2 0 .4 0 .5-.1-.3 1.3-1.4 2.3-2.5 2.6v2c2.8-.5 5-3 5-6.5V10c0-1.7-1.3-3-3-3zm9 0c-1.7 0-3 1.3-3 3s1.3 3 3 3c.2 0 .4 0 .5-.1-.3 1.3-1.4 2.3-2.5 2.6v2c2.8-.5 5-3 5-6.5V10c0-1.7-1.3-3-3-3z"/></svg>',
link: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 17H7A5 5 0 0 1 7 7h2"/><path d="M15 7h2a5 5 0 0 1 0 10h-2"/><line x1="8" y1="12" x2="16" y2="12"/></svg>',
img: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.6"/><path d="M21 15l-5-5L4 21"/></svg>',
upload: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12v9"/><path d="m8 16 4-4 4 4"/><path d="M20.4 16.5A5 5 0 0 0 18 7.2 7 7 0 0 0 4.3 9 4.5 4.5 0 0 0 5 18"/></svg>',
spoiler: '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="2.6"/></svg>'
};
var TOOLBAR =
'<div class="hwpfc-toolbar">' +
'<button type="button" class="hwpfc-tool hwpfc-tool--txt" data-cmd="bold" title="Negrita"><b>B</b></button>' +
'<button type="button" class="hwpfc-tool hwpfc-tool--txt" data-cmd="italic" title="Cursiva"><i>I</i></button>' +
'<button type="button" class="hwpfc-tool hwpfc-tool--txt" data-cmd="underline" title="Subrayado"><u>U</u></button>' +
'<button type="button" class="hwpfc-tool hwpfc-tool--txt" data-cmd="strikeThrough" title="Tachado"><s>S</s></button>' +
'<span class="hwpfc-tool-sep"></span>' +
'<button type="button" class="hwpfc-tool" data-cmd="insertUnorderedList" title="Lista de puntos">' + SVG.ul + '</button>' +
'<button type="button" class="hwpfc-tool" data-cmd="insertOrderedList" title="Lista numerada">' + SVG.ol + '</button>' +
'<button type="button" class="hwpfc-tool" data-cmd="formatBlock" data-val="blockquote" title="Cita">' + SVG.quote + '</button>' +
'<button type="button" class="hwpfc-tool" data-act="spoiler" title="Spoiler">' + SVG.spoiler + '</button>' +
'<button type="button" class="hwpfc-tool" data-act="link" title="Enlace">' + SVG.link + '</button>' +
'<span class="hwpfc-tool-sep"></span>' +
'<button type="button" class="hwpfc-tool" data-act="imgurl" title="Insertar imagen por URL">' + SVG.img + '</button>' +
'<button type="button" class="hwpfc-tool" data-act="upload" title="Subir imagen">' + SVG.upload + '</button>' +
'</div>';
function topComposer(){
if(state.user){
var ph=avatar(state.user.photo, state.user.name);
return '<div class="hwpfc-form">' +
'<div class="hwpfc-avatar">' + ph + '</div>' +
'<div class="hwpfc-fields">' +
'<div class="hwpfc-me">Comentando como <strong>' + esc(state.user.name) + '</strong>. ' +
'(<a class="hwpfc-logout">Salir</a>)</div>' +
TOOLBAR +
'<div class="hwpfc-editor" contenteditable="true" data-placeholder="Escribe un comentario…"></div>' +
'<input type="file" class="hwpfc-file" accept="image/png,image/jpeg,image/webp,image/gif" style="display:none">' +
'<div class="hwpfc-msg-slot"></div>' +
'<div class="hwpfc-actions">' +
'<button type="button" class="hwpfc-btn hwpfc-send">Publicar comentario</button></div>' +
'</div></div>';
}
var reg=state.register_url
? '<a class="hwpfc-btn hwpfc-btn--ghost hwpfc-do-register" href="' + esc(state.register_url) + '">¡Regístrate!</a>'
: '';
var guest=state.guests_enabled
? '<div class="hwpfc-guest-row"><button type="button" class="hwpfc-btn hwpfc-btn--white hwpfc-do-guest">Comentar como invitado</button></div>'
: '';
return '<div class="hwpfc-login">' +
'<p>Para comentar necesitas tu cuenta del foro. Cualquiera puede leer los comentarios.</p>' +
'<div class="hwpfc-login-btns">' +
'<a class="hwpfc-btn hwpfc-do-login" href="' + esc(state.login_url) + '">Iniciar sesión con HardwarePremium</a>' +
reg +
'</div>' +
guest +
'<div class="hwpfc-guest-slot"></div>' +
'</div>';
}
function guestForm(){
return '<form class="hwpfc-guest-form" autocomplete="off">' +
'<input type="text" class="hwpfc-g-name" maxlength="40" placeholder="Tu nombre o apodo" required>' +
'<div class="hwpfc-g-hp" aria-hidden="true" style="position:absolute;left:-9999px"><input type="text" name="website" tabindex="-1" autocomplete="off"></div>' +
TOOLBAR +
'<div class="hwpfc-editor" contenteditable="true" data-placeholder="Escribe tu comentario…"></div>' +
'<input type="file" class="hwpfc-file" accept="image/png,image/jpeg,image/webp,image/gif" style="display:none">' +
'<div class="hwpfc-g-captcha"><label class="hwpfc-g-q">…</label> <input type="text" class="hwpfc-g-a" inputmode="numeric" maxlength="3" style="width:64px"></div>' +
'<div class="hwpfc-msg-slot"></div>' +
'<div class="hwpfc-actions" style="justify-content:flex-start;gap:8px">' +
'<button type="submit" class="hwpfc-btn hwpfc-g-send">Publicar como invitado</button>' +
'<button type="button" class="hwpfc-btn hwpfc-btn--white hwpfc-g-cancel">Cancelar</button>' +
'</div></form>';
}
function render(comments){
commentsById={};
var html='';
var forumBack=forumBackUrl();
if(forumBack){
html +='<div class="hwpfc-back"><a class="hwpfc-btn hwpfc-btn--white" href="' + esc(forumBack) + '">&#8592; Volver al tema del foro</a></div>';
}
html +=topComposer();
if(comments&&comments.length){
html +='<ul class="hwpfc-list">';
comments.forEach(function (c){ html +=commentHTML(c); });
html +='</ul>';
}else{
html +='<div class="hwpfc-empty">Aún no hay comentarios. ¡Sé el primero!</div>';
}
if(state.topic_url){
html +='<div class="hwpfc-foot"><a href="' + esc(state.topic_url) + '" target="_blank" rel="noopener">Ver el hilo en el foro »</a></div>';
}
box.innerHTML=html;
box.setAttribute('data-state', 'ready');
wire();
preloadDraft();
}
function forumBackUrl(){
var c=(('; ' + document.cookie).split('; hwpfc_forum=')[1]||'').split(';')[0];
if(!c){ return ''; }
var dec='';
try { dec=decodeURIComponent(c); } catch (e){ dec=c; }
var ix=dec.indexOf(':');
if(ix < 0){ return ''; }
var fpid=dec.slice(0, ix), furl=dec.slice(ix + 1);
if(String(fpid)!==String(CFG.postId)){ return ''; }
document.cookie='hwpfc_forum=;path=/;domain=.hardwarepremium.com;max-age=0;samesite=lax';
document.cookie='hwpfc_forum=;path=/;max-age=0;samesite=lax';
if(!/^https?:\/\/foro\.hardwarepremium\.com\//i.test(furl)){ return ''; } // solo URLs del foro
return furl;
}
function preloadDraft(){
var raw=(('; ' + document.cookie).split('; hwpfc_draft=')[1]||'').split(';')[0];
if(!raw){ return; }
var ed=box.querySelector('.hwpfc-editor');
if(!ed){ return; }
var decoded='';
try { decoded=decodeURIComponent(raw); } catch (e){ decoded=raw; }
var idx=decoded.indexOf(':');
var pid='', text=decoded;
if(idx >=0){ pid=decoded.slice(0, idx); text=decoded.slice(idx + 1); }
if(pid&&String(pid)!==String(CFG.postId)){ return; }
document.cookie='hwpfc_draft=;path=/;domain=.hardwarepremium.com;max-age=0;samesite=lax';
document.cookie='hwpfc_draft=;path=/;max-age=0;samesite=lax';
if(!text.trim()){ return; }
root.scrollIntoView({ behavior: 'smooth' });
function publishDraft(html){
if(!html||!html.trim()){ return; }
publishHtml(html, function (ok){
if(!ok){
ed.innerHTML=html;
activeEditor=ed;
ed.focus();
}});
}
if(text.charAt(0)==='#'){
fetchStash(text.slice(1), 0, publishDraft);
}else if(/^\s*</.test(text)){
publishDraft(text);
}else{
publishDraft(text.split(/\n{2,}/).map(function (p){
return '<p>' + esc(p).replace(/\n/g, '<br>') + '</p>';
}).join(''));
}}
function fetchStash(token, attempt, cb){
fetch(CFG.ajax + '?action=hwpfc_unstash', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'token=' + encodeURIComponent(token)
}).then(function (r){ return r.json(); }).then(function (res){
var d=(res&&res.success&&res.data) ? res.data:null;
var t=d ? (d.text||''):'';
if(t&&(!d.post||String(d.post)===String(CFG.postId))){ cb(t); return; }
if(attempt < 3){ setTimeout(function (){ fetchStash(token, attempt + 1, cb); }, 700); }}).catch(function (){
if(attempt < 3){ setTimeout(function (){ fetchStash(token, attempt + 1, cb); }, 700); }});
}
function publishHtml(html, done){
var body=new URLSearchParams();
body.set('post', CFG.postId);
body.set('text', html);
body.set('csrf', state.csrf);
fetch(CFG.ajax + '?action=hwpfc_post', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString()
}).then(function (r){ return r.json().then(function (j){ return { ok: r.ok, j: j };});})
.then(function (res){
if(!res.ok||!res.j||!res.j.success){ if(done){ done(false); } return; }
var list=box.querySelector('.hwpfc-list');
if(!list){
var empty=box.querySelector('.hwpfc-empty'); if(empty){ empty.remove(); }
list=document.createElement('ul'); list.className='hwpfc-list';
var foot=box.querySelector('.hwpfc-foot');
if(foot){ box.insertBefore(list, foot); }else{ box.appendChild(list); }}
list.insertAdjacentHTML('beforeend', commentHTML(res.j.data.comment));
if(done){ done(true); }})
.catch(function (){ if(done){ done(false); }});
}
function editor(){ return (activeEditor&&box.contains(activeEditor)) ? activeEditor:box.querySelector('.hwpfc-editor'); }
function insertHtmlAtCursor(html){
var ed=editor();
if(!ed){ return; }
ed.focus();
var sel=window.getSelection();
if(sel&&sel.rangeCount&&ed.contains(sel.anchorNode)){
var range=sel.getRangeAt(0);
range.deleteContents();
var el=document.createElement('div');
el.innerHTML=html;
var frag=document.createDocumentFragment(), node, last;
while ((node=el.firstChild)){ last=frag.appendChild(node); }
range.insertNode(frag);
if(last){
range=range.cloneRange();
range.setStartAfter(last);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}}else{
ed.innerHTML +=html;
}}
function wire(){
var logout=box.querySelector('.hwpfc-logout');
if(logout){
logout.addEventListener('click', function (){ window.location.href=state.logout_url; });
}
var send=box.querySelector('.hwpfc-send');
if(send){ send.addEventListener('click', submit); }}
function runTool(btn, ed){
if(!ed){ return; }
ed.focus();
var cmd=btn.getAttribute('data-cmd');
var act=btn.getAttribute('data-act');
if(cmd){
var val=btn.getAttribute('data-val')||null;
try { document.execCommand (cmd, false, val); } catch (e){}}else if(act==='link'){
var url=prompt('Dirección del enlace (https://…):', 'https://');
if(url&&/^https?:\/\//i.test(url)){ try { document.execCommand ('createLink', false, url); } catch (e){}}
}else if(act==='imgurl'){
var iu=prompt('URL de la imagen o GIF (https://…):', 'https://');
if(iu&&/^https?:\/\//i.test(iu)){ insertHtmlAtCursor('<img src="' + esc(iu) + '" alt="">'); }}else if(act==='spoiler'){
insertHtmlAtCursor('<div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Spoiler</span></div><div class="ipsSpoiler_contents"><p>' + (window.getSelection&&String(window.getSelection()) ? esc(String(window.getSelection())):'Texto oculto') + '</p></div></div><p><br></p>');
}else if(act==='upload'){
var scope=btn.closest('.hwpfc-fields, .hwpfc-edit-wrap')||box;
var f=scope.querySelector('.hwpfc-file');
if(f){ f.click(); }}
}
function showMsg(kind, text){
var slot=box.querySelector('.hwpfc-msg-slot');
if(!slot){ return; }
slot.innerHTML='<div class="hwpfc-msg hwpfc-msg--' + (kind==='ok' ? 'ok':'err') + '">' + esc(text) + '</div>';
}
function uploadImage(f){
if(f.size > 8 * 1024 * 1024){ showMsg('err', 'La imagen supera el máximo de 8 MB.'); return; }
showMsg('ok', 'Subiendo imagen…');
var fd=new FormData();
fd.append('file', f);
fd.append('csrf', state.csrf);
fetch(CFG.ajax + '?action=hwpfc_upload', {
method: 'POST', credentials: 'same-origin', body: fd
}).then(function (r){ return r.json().then(function (j){ return { ok: r.ok, j: j };});})
.then(function (res){
if(!res.ok||!res.j||!res.j.success||!res.j.data||!res.j.data.url){
var m=(res.j&&res.j.data&&res.j.data.message) ? res.j.data.message:'No se pudo subir la imagen.';
showMsg('err', m);
return;
}
insertHtmlAtCursor('<img src="' + esc(res.j.data.url) + '" alt="">');
showMsg('ok', 'Imagen añadida.');
})
.catch(function (){ showMsg('err', 'Error de red al subir la imagen.'); });
}
function submit(){
var ed=editor();
var btn=box.querySelector('.hwpfc-send');
if(!ed){ return; }
var html=ed.innerHTML.trim();
var plain=(ed.textContent||'').trim();
if(!plain&&html.indexOf('<img')===-1){ showMsg('err', 'Escribe algo antes de publicar.'); return; }
btn.setAttribute('disabled', 'disabled');
btn.textContent='Publicando…';
var body=new URLSearchParams();
body.set('post', CFG.postId);
body.set('text', html);
body.set('csrf', state.csrf);
fetch(CFG.ajax + '?action=hwpfc_post', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body.toString()
}).then(function (r){
return r.json().then(function (j){ return { ok: r.ok, j: j };});
}).then(function (res){
btn.removeAttribute('disabled');
btn.textContent='Publicar comentario';
if(!res.ok||!res.j||!res.j.success){
var m=(res.j&&res.j.data&&res.j.data.message) ? res.j.data.message:'No se pudo publicar.';
showMsg('err', m);
return;
}
ed.innerHTML='';
showMsg('ok', 'Comentario publicado.');
var list=box.querySelector('.hwpfc-list');
if(!list){
var empty=box.querySelector('.hwpfc-empty');
if(empty){ empty.remove(); }
list=document.createElement('ul');
list.className='hwpfc-list';
var foot=box.querySelector('.hwpfc-foot');
if(foot){ box.insertBefore(list, foot); }else{ box.appendChild(list); }}
list.insertAdjacentHTML('beforeend', commentHTML(res.j.data.comment));
}).catch(function (){
btn.removeAttribute('disabled');
btn.textContent='Publicar comentario';
showMsg('err', 'Error de red, inténtalo de nuevo.');
});
}
function maybeAutoLogin(){
var intent=(('; ' + document.cookie).split('; hwpfc_intent=')[1]||'').split(';')[0];
if(intent!=='1'){ return false; }
if(!state.login_url){ return false; }
document.cookie='hwpfc_intent=;path=/;domain=.hardwarepremium.com;max-age=0;samesite=lax';
document.cookie='hwpfc_intent=;path=/;max-age=0;samesite=lax';
window.location.href=state.login_url;
return true;
}
function load(attempt){
attempt=attempt||1;
fetch(CFG.ajax + '?action=hwpfc_load&post=' + encodeURIComponent(CFG.postId) + '&_=' + Date.now(), {
credentials: 'same-origin', cache: 'no-store'
}).then(function (r){ if(!r.ok){ throw new Error('http ' + r.status); } return r.json(); })
.then(function (data){
state.user=data.user;
state.csrf=data.csrf||'';
state.login_url=data.login_url||'';
state.logout_url=data.logout_url||'';
state.register_url=data.register_url||'';
state.guests_enabled = !!data.guests_enabled;
state.topic_url=data.topic_url||'';
state.topic_id=data.topic_id||0;
if(!state.user&&maybeAutoLogin()){ return; }
render(data.comments||[]);
var hash=window.location.hash;
if(hash.indexOf('hwpfc')!==-1){
root.scrollIntoView({ behavior: 'smooth' });
}})
.catch(function (){
if(attempt < 3){ setTimeout(function (){ load(attempt + 1); }, attempt * 1200); return; }
box.setAttribute('data-state', 'error');
box.innerHTML='<div class="hwpfc-msg hwpfc-msg--err">No se pudieron cargar los comentarios. <a class="hwpfc-retry" style="text-decoration:underline;cursor:pointer">Reintentar</a></div>';
var rt=box.querySelector('.hwpfc-retry');
if(rt){ rt.addEventListener('click', function (){ box.innerHTML='<div class="hwpfc-loading">Cargando comentarios…</div>'; load(1); });}});
}
box.addEventListener('mousedown', function (e){
if(e.target.closest&&e.target.closest('.hwpfc-tool')){ e.preventDefault(); }});
box.addEventListener('click', function (e){
if(!e.target.closest){ return; }
var tool=e.target.closest('.hwpfc-tool');
if(tool){
var scope=tool.closest('.hwpfc-fields, .hwpfc-edit-wrap, .hwpfc-guest-form')||box;
runTool(tool, scope.querySelector('.hwpfc-editor'));
return;
}
var gbtn=e.target.closest('.hwpfc-do-guest');
if(gbtn){ openGuestForm(); return; }
var gcancel=e.target.closest('.hwpfc-g-cancel');
if(gcancel){ var slot=box.querySelector('.hwpfc-guest-slot'); if(slot){ slot.innerHTML=''; } var gr=box.querySelector('.hwpfc-guest-row'); if(gr){ gr.style.display=''; } return; }
var rep=e.target.closest('.hwpfc-reply');
if(rep){ quoteComment(rep.getAttribute('data-id')); return; }
var vote=e.target.closest('.hwpfc-vote');
if(vote){ doVote(vote); return; }
var edb=e.target.closest('.hwpfc-edit');
if(edb){ startEdit(edb.getAttribute('data-id')); return; }
var del=e.target.closest('.hwpfc-del');
if(del){ doDelete(del.getAttribute('data-id')); return; }
var sp=e.target.closest('.hwpfc-c-text .ipsSpoiler_header');
if(sp){ var box2=sp.closest('.ipsSpoiler'); if(box2){ box2.classList.toggle('is-open'); }}
});
box.addEventListener('change', function (e){
var f=e.target.closest ? e.target.closest('.hwpfc-file'):null;
if(f&&f.files&&f.files[0]){
var scope=f.closest('.hwpfc-fields, .hwpfc-edit-wrap, .hwpfc-guest-form')||box;
activeEditor=scope.querySelector('.hwpfc-editor');
uploadImage(f.files[0]);
f.value='';
}});
box.addEventListener('submit', function (e){
var gf=e.target.closest ? e.target.closest('.hwpfc-guest-form'):null;
if(gf){ e.preventDefault(); submitGuest(gf); }});
box.addEventListener('dragover', function (e){
var ed=e.target.closest ? e.target.closest('.hwpfc-editor'):null;
if(ed&&e.dataTransfer&&e.dataTransfer.types&&Array.prototype.indexOf.call(e.dataTransfer.types, 'Files')!==-1){
e.preventDefault();
ed.classList.add('hwpfc-dragover');
}});
box.addEventListener('dragleave', function (e){
var ed=e.target.closest ? e.target.closest('.hwpfc-editor'):null;
if(ed){ ed.classList.remove('hwpfc-dragover'); }});
box.addEventListener('drop', function (e){
var ed=e.target.closest ? e.target.closest('.hwpfc-editor'):null;
if(!ed||!e.dataTransfer||!e.dataTransfer.files||!e.dataTransfer.files.length){ return; }
e.preventDefault();
ed.classList.remove('hwpfc-dragover');
activeEditor=ed; ed.focus();
var files=e.dataTransfer.files;
for (var i=0; i < files.length; i++){
if(/^image\//.test(files[i].type)){ uploadImage(files[i]); }}
});
box.addEventListener('mouseover', function (e){
if(!e.target.closest){ return; }
var v=e.target.closest('.hwpfc-vote');
if(v&&!v.getAttribute('data-tip-done')){ loadReactors(v); }});
function loadReactors(btn){
var n=parseInt(btn.querySelector('.hwpfc-n').textContent, 10)||0;
btn.setAttribute('data-tip-done', '1');
if(n===0){ btn.title=''; return; }
var id=btn.getAttribute('data-id'), type=btn.getAttribute('data-type');
fetch(CFG.ajax + '?action=hwpfc_reactors&post=' + encodeURIComponent(id) + '&type=' + encodeURIComponent(type), { credentials: 'same-origin' })
.then(function (r){ return r.json(); })
.then(function (res){
if(res&&res.success&&res.data&&res.data.names&&res.data.names.length){
var names=res.data.names;
var extra=n > names.length ? (' y ' + (n - names.length) + ' más'):'';
btn.title=names.join(', ') + extra;
}}).catch(function (){ btn.removeAttribute('data-tip-done'); });
}
function doDelete(id){
if(!state.user){ window.location.href=state.login_url; return; }
if(!window.confirm('¿Eliminar este comentario? No se puede deshacer.')){ return; }
var item=box.querySelector('.hwpfc-item[data-id="' + id + '"]');
var body=new URLSearchParams();
body.set('post', id);
body.set('csrf', state.csrf);
fetch(CFG.ajax + '?action=hwpfc_delete', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString()
}).then(function (r){ return r.json().then(function (j){ return { ok: r.ok, j: j };});})
.then(function (res){
if(res.ok&&res.j&&res.j.success){
if(item){ item.parentNode.removeChild(item); }}else{
alert((res.j&&res.j.data&&res.j.data.message) ? res.j.data.message:'No se pudo eliminar.');
}}).catch(function (){ alert('Error de red.'); });
}
function cleanForEdit(html){
var h=html.replace(/<p>\s*<span class="hwpfc-ednote">[\s\S]*?<\/span>\s*<\/p>/gi, '');
h=h.replace(/(<p>(\s|&nbsp;|<br\s*\/?>)*<\/p>\s*)+$/gi, '');
return h.trim();
}
function startEdit(id){
if(!state.user){ window.location.href=state.login_url; return; }
var c=commentsById[id];
var item=box.querySelector('.hwpfc-item[data-id="' + id + '"]');
if(!c||!item){ return; }
var textEl=item.querySelector('.hwpfc-c-text');
if(item.querySelector('.hwpfc-edit-wrap')){ return; }
textEl.style.display='none';
var wrap=document.createElement('div');
wrap.className='hwpfc-edit-wrap';
wrap.innerHTML=TOOLBAR +
'<div class="hwpfc-editor" contenteditable="true"></div>' +
'<input type="file" class="hwpfc-file" accept="image/png,image/jpeg,image/webp,image/gif" style="display:none">' +
'<div class="hwpfc-msg-slot"></div>' +
'<div class="hwpfc-edit-actions">' +
'<button type="button" class="hwpfc-btn hwpfc-edit-save">Guardar</button>' +
'<button type="button" class="hwpfc-edit-cancel">Cancelar</button></div>';
textEl.parentNode.insertBefore(wrap, textEl.nextSibling);
var ed=wrap.querySelector('.hwpfc-editor');
ed.innerHTML=cleanForEdit(c.html||'');
activeEditor=ed;
ed.focus();
wrap.querySelector('.hwpfc-edit-cancel').addEventListener('click', function (){
wrap.parentNode.removeChild(wrap); textEl.style.display='';
});
wrap.querySelector('.hwpfc-edit-save').addEventListener('click', function (){
var btn=this, html=ed.innerHTML.trim();
if(!(ed.textContent||'').trim()&&html.indexOf('<img')===-1){ return; }
btn.setAttribute('disabled', 'disabled'); btn.textContent='Guardando…';
var b=new URLSearchParams();
b.set('post', id); b.set('wp_post', CFG.postId); b.set('text', html); b.set('csrf', state.csrf);
fetch(CFG.ajax + '?action=hwpfc_edit', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: b.toString()
}).then(function (r){ return r.json().then(function (j){ return { ok: r.ok, j: j };});})
.then(function (res){
btn.removeAttribute('disabled'); btn.textContent='Guardar';
if(res.ok&&res.j&&res.j.success&&res.j.data){
textEl.innerHTML=res.j.data.html;
if(c){ c.html=res.j.data.html; c.edited=true; }
wrap.parentNode.removeChild(wrap); textEl.style.display='';
var head=item.querySelector('.hwpfc-c-head');
if(head&&!head.querySelector('.hwpfc-edited')){
head.insertAdjacentHTML('beforeend', '<span class="hwpfc-edited">(editado)</span>');
}}else{
var slot=wrap.querySelector('.hwpfc-msg-slot');
if(slot){ slot.innerHTML='<div class="hwpfc-msg hwpfc-msg--err">' + esc((res.j&&res.j.data&&res.j.data.message) ? res.j.data.message:'No se pudo guardar.') + '</div>'; }}
}).catch(function (){ btn.removeAttribute('disabled'); btn.textContent='Guardar'; });
});
}
function doVote(btn){
if(!state.user){ window.location.href=state.login_url; return; }
var id=btn.getAttribute('data-id');
var type=btn.getAttribute('data-type');
var foot=btn.closest('.hwpfc-c-foot');
if(foot.getAttribute('data-busy')==='1'){ return; }
foot.setAttribute('data-busy', '1');
var body=new URLSearchParams();
body.set('post', id);
body.set('type', type);
body.set('csrf', state.csrf);
fetch(CFG.ajax + '?action=hwpfc_react', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body.toString()
}).then(function (r){ return r.json().then(function (j){ return { ok: r.ok, j: j };});})
.then(function (res){
foot.removeAttribute('data-busy');
if(!res.ok||!res.j||!res.j.success||!res.j.data){ return; }
var d=res.j.data;
var likeB=foot.querySelector('.hwpfc-like');
var disB=foot.querySelector('.hwpfc-dislike');
if(likeB){ likeB.querySelector('.hwpfc-n').textContent=d.likes; likeB.classList.toggle('is-on', d.my==='like'); }
if(disB){ disB.querySelector('.hwpfc-n').textContent=d.dislikes; disB.classList.toggle('is-on', d.my==='dislike'); }
if(commentsById[id]){ commentsById[id].likes=d.likes; commentsById[id].dislikes=d.dislikes; commentsById[id].my=d.my; }})
.catch(function (){ foot.removeAttribute('data-busy'); });
}
function openGuestForm(){
var slot=box.querySelector('.hwpfc-guest-slot');
if(!slot||slot.querySelector('.hwpfc-guest-form')){ return; }
var row=box.querySelector('.hwpfc-guest-row');
if(row){ row.style.display='none'; }
slot.innerHTML=guestForm();
var ed=slot.querySelector('.hwpfc-editor');
activeEditor=ed;
fetch(CFG.ajax + '?action=hwpfc_captcha&_=' + Date.now(), { credentials: 'same-origin', cache: 'no-store' })
.then(function (r){ return r.json(); })
.then(function (res){
if(res&&res.success&&res.data){
slot.querySelector('.hwpfc-g-q').textContent=res.data.question;
slot.querySelector('.hwpfc-guest-form').setAttribute('data-ctoken', res.data.token);
}}).catch(function (){});
var nm=slot.querySelector('.hwpfc-g-name'); if(nm){ nm.focus(); }}
function submitGuest(form){
var name=(form.querySelector('.hwpfc-g-name').value||'').trim();
var ed=form.querySelector('.hwpfc-editor');
var html=ed ? ed.innerHTML.trim():'';
var plain=ed ? (ed.textContent||'').trim():'';
var hp=form.querySelector('input[name="website"]');
var answer=(form.querySelector('.hwpfc-g-a').value||'').trim();
var token=form.getAttribute('data-ctoken')||'';
var slot=box.querySelector('.hwpfc-msg-slot')||form.querySelector('.hwpfc-msg-slot');
function msg(kind, t){ var s=form.querySelector('.hwpfc-msg-slot'); if(s){ s.innerHTML='<div class="hwpfc-msg hwpfc-msg--' + (kind==='ok' ? 'ok':'err') + '">' + esc(t) + '</div>'; }}
if(!name){ msg('err', 'Indica tu nombre.'); return; }
if(!plain&&html.indexOf('<img')===-1){ msg('err', 'Escribe tu comentario.'); return; }
if(!answer){ msg('err', 'Responde la verificación.'); return; }
var btn=form.querySelector('.hwpfc-g-send');
btn.setAttribute('disabled', 'disabled'); btn.textContent='Publicando…';
var body=new URLSearchParams();
body.set('post', CFG.postId);
body.set('name', name);
body.set('text', html);
body.set('canswer', answer);
body.set('ctoken', token);
body.set('website', hp ? hp.value:'');
fetch(CFG.ajax + '?action=hwpfc_guest_post', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString()
}).then(function (r){ return r.json().then(function (j){ return { ok: r.ok, j: j };});})
.then(function (res){
btn.removeAttribute('disabled'); btn.textContent='Publicar como invitado';
if(!res.ok||!res.j||!res.j.success){
msg('err', (res.j&&res.j.data&&res.j.data.message) ? res.j.data.message:'No se pudo publicar.');
fetch(CFG.ajax + '?action=hwpfc_captcha&_=' + Date.now(), { credentials: 'same-origin', cache: 'no-store' })
.then(function (r){ return r.json(); })
.then(function (cr){ if(cr&&cr.success&&cr.data){ form.querySelector('.hwpfc-g-q').textContent=cr.data.question; form.setAttribute('data-ctoken', cr.data.token); form.querySelector('.hwpfc-g-a').value=''; }});
return;
}
var list=box.querySelector('.hwpfc-list');
if(!list){
var empty=box.querySelector('.hwpfc-empty'); if(empty){ empty.remove(); }
list=document.createElement('ul'); list.className='hwpfc-list';
var foot=box.querySelector('.hwpfc-foot');
if(foot){ box.insertBefore(list, foot); }else{ box.appendChild(list); }}
list.insertAdjacentHTML('beforeend', commentHTML(res.j.data.comment));
var gslot=box.querySelector('.hwpfc-guest-slot'); if(gslot){ gslot.innerHTML=''; }
var grow=box.querySelector('.hwpfc-guest-row'); if(grow){ grow.style.display=''; }})
.catch(function (){ btn.removeAttribute('disabled'); btn.textContent='Publicar como invitado'; msg('err', 'Error de red.'); });
}
load();
})();