{"id":2616,"date":"2025-12-04T17:06:08","date_gmt":"2025-12-04T23:06:08","guid":{"rendered":"https:\/\/desarrollo-web.ddns.net\/matrix\/?page_id=2616"},"modified":"2025-12-04T17:26:22","modified_gmt":"2025-12-04T23:26:22","slug":"inteligencias-ai-crud","status":"publish","type":"page","link":"https:\/\/desarrollo-web.ddns.net\/matrix\/inteligencias-ai-crud\/","title":{"rendered":"Inteligencias AI CRUD"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"2616\" class=\"elementor elementor-2616\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a592ff1 e-con-full e-flex e-con e-parent\" data-id=\"a592ff1\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bc28683 elementor-widget elementor-widget-shortcode\" data-id=\"bc28683\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">    <style>\n      .ix-wrap{--bg:#0b1020;--card:#121a34;--mut:#8aa0d1;--pri:#5b8cff;--ok:#10b981;--err:#ef4444;--bd:#6587ff;--txt:#e6eeff}\n      .ix-wrap{font-family:Inter,system-ui,Segoe UI,Roboto,Arial,sans-serif;background:var(--bg);color:var(--txt);padding:20px;border-radius:16px;box-shadow:0 10px 30px rgba(0,0,0,.35)}\n      .ix-toolbar{display:flex;gap:12px;align-items:flex-start;justify-content:space-between;margin-bottom:14px}\n      .ix-title{font-size:1.25rem;font-weight:700;letter-spacing:.3px}\n      .ix-btn{appearance:none;border:1px solid var(--bd);background:linear-gradient(180deg,#1a2450,#11193a);color:#fff;padding:10px 14px;border-radius:12px;font-weight:600;cursor:pointer;transition:transform .12s ease,opacity .12s ease,box-shadow .12s}\n      .ix-btn:hover{transform:translateY(-1px);box-shadow:0 6px 18px rgba(24,41,97,.35)}\n      .ix-btn--pri{background:linear-gradient(180deg,#6b8cff,#4f75ff);border-color:#3a5fe0}\n      .ix-btn--ok{background:linear-gradient(180deg,#34d399,#10b981);border-color:#0ea371}\n      .ix-btn--err{background:linear-gradient(180deg,#ff6b6b,#ef4444);border-color:#cc3434}\n      .ix-btn--warn{background:linear-gradient(180deg,#fbbf24,#f59e0b);border-color:#d97706;color:#111}\n      .ix-btn--ghost{background:transparent;border:1px dashed var(--bd);color:#e6eeff}\n      .ix-input{background:#0e1530;border:1px solid var(--bd);color:#fff;padding:10px 12px;border-radius:12px;min-width:240px}\n      .ix-select{background:#0e1530;border:1px solid var(--bd);color:#e6eeff;padding:8px 10px;border-radius:10px}\n      .ix-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--card);border:1px solid var(--bd);border-radius:14px;overflow:hidden}\n      .ix-table th,.ix-table td{padding:12px 10px;border-bottom:1px solid var(--bd);vertical-align:top}\n      .ix-table th{position:sticky;top:0;background:#0f1733;text-align:left;font-size:.85rem;color:var(--mut);z-index:1}\n      .ix-table tr:hover td{background:#0f173322}\n      .ix-badge{display:inline-block;padding:.2rem .5rem;border-radius:999px;font-size:.75rem;border:1px solid var(--bd);color:white;}\n      .ix-modal{position:fixed;inset:0;background:rgba(5,8,18,.6);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:9999}\n      .ix-modal.is-open{display:flex}\n      .ix-card{width:min(820px,92vw);background:var(--card);border:1px solid var(--bd);border-radius:16px;box-shadow:0 18px 60px rgba(5,8,18,.55);overflow:hidden}\n      .ix-card-hd{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;background:#fff;border-bottom:1px solid var(--bd);color:#111}\n      .ix-card-tt{font-size:1.05rem;font-weight:700}\n      .ix-card-bd{padding:16px;background:#fff;color:#111}\n      .ix-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:12px}\n      .ix-col-6{grid-column:span 6}.ix-col-12{grid-column:span 12}\n      .ix-lb{font-size:.82rem;color:#374151;margin-bottom:6px;display:block;font-weight:600}\n      .ix-field{width:100%;background:#f9fafb;border:1px solid #d1d5db;color:#111;padding:10px 12px;border-radius:12px}\n      .ix-ta{min-height:100px;resize:vertical}\n      .ix-card-ft{display:flex;gap:10px;justify-content:flex-end;padding:14px 16px;background:#fff;border-top:1px solid var(--bd)}\n      .ix-empty{padding:16px;color:var(--mut)}\n      .ix-table th.sortable{cursor:pointer;user-select:none;position:relative;padding-right:22px}\n      .ix-table th.sortable.asc:after{content:'\u2191';opacity:.85}\n      .ix-table th.sortable.desc:after{content:'\u2193';opacity:.85}\n      .ix-table th.sortable:after{content:'\u2195';position:absolute;right:8px;top:50%;transform:translateY(-50%);opacity:.45;font-size:.85rem}\n      .ix-actions-bar{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}\n      .ix-actions-bar .ix-input{min-width:260px;flex:1 1 320px}\n      .ix-actions-bar .ix-select{height:42px}\n      .ix-pagination--top{margin:0;gap:8px}\n      .ix-pager{display:flex;gap:6px;align-items:center}\n      .ix-pagebtn{appearance:none;border:1px solid var(--bd);background:#0e1530;color:#e6eeff;padding:8px 10px;border-radius:10px;cursor:pointer;min-width:36px;text-align:center}\n      .ix-pagebtn[disabled]{opacity:.4;cursor:default}\n      .ix-pagebtn.is-active{background:linear-gradient(180deg,#6b8cff,#4f75ff);border-color:#3a5fe0;color:#fff}\n      .ix-ellipsis{padding:0 4px;color:#a3b4de}\n      @media (max-width:980px){\n        .ix-actions-bar{flex-wrap:wrap}\n        .ix-actions-bar .ix-input{flex:1 1 100%;min-width:220px}\n        .ix-pagination--top{order:3;width:100%;justify-content:flex-end}\n        #ixNew{order:4}\n      }\n      .ix-pagination--top{display:flex;align-items:center;gap:8px;flex:0 0 auto;white-space:nowrap}\n      .ix-pagination--top .ix-btn{display:inline-flex;align-items:center;justify-content:center;width:42px;height:42px;padding:0;border-radius:12px;line-height:1}\n      #ixPager{display:flex;gap:6px;align-items:center}\n\n      a.ix-badge,\n      a.ix-badge:link,\n      a.ix-badge:visited,\n      a.ix-badge:hover,\n      a.ix-badge:active { color:white !important; text-decoration:none !important; }\n      a.ix-badge:hover { background:#1a2450; color:#ADBFFF; }\n\n      \/* Modal lectura (Prompt\/Comentarios) *\/\n      #ixView .ix-card{width:min(720px,92vw)}\n      #ixViewText{white-space:pre-wrap;word-wrap:break-word}\n\t\/* Modal lectura (Prompt\/Comentarios) *\/\n#ixView .ix-card{width:min(720px,92vw)}\n#ixView .ix-card-bd{\n  max-height:60vh;      \/* l\u00edmite de altura *\/\n  overflow-y:auto;      \/* scroll interno *\/\n}\n#ixViewText{white-space:pre-wrap;word-wrap:break-word}\n\n\n      \/* Modal confirm reutilizable *\/\n      #ixConfirm .ix-card{width:min(560px,92vw)}\n      #ixConfirm[data-variant=\"warn\"] .ix-card-hd{\n        background:#fff7ed; color:#9a3412; border-bottom-color:#fdba74;\n      }\n      #ixConfirm[data-variant=\"warn\"] .ix-card{border-color:#fdba74}\n      #ixConfirm[data-variant=\"danger\"] .ix-card-hd{\n        background:#fef2f2; color:#7f1d1d; border-bottom-color:#fecaca;\n      }\n      #ixConfirm[data-variant=\"danger\"] .ix-card{border-color:#fecaca}\n\n      .ix-confirm-ill{display:none;max-width:100%;height:auto;margin:0 0 12px}\n      #ixConfirm[data-variant=\"danger\"] .ix-confirm-ill{display:block}\n\t\t\t\t\t\t\t\t\t\t\t\t\t   \n\t\/* Botones de acciones en la tabla (Editar \/ Eliminar) m\u00e1s compactos *\/\n.ix-table .ix-btn{\n  padding:4px 8px;      \/* antes: 10px 14px *\/\n  font-size:0.78rem;     \/* opcional: texto un poco m\u00e1s chico *\/\n  border-radius:8px;     \/* opcional: menos redondo *\/\n}\n\n\t\t\/* ===== Versi\u00f3n m\u00f3vil mejorada para IAS CRUD ===== *\/\n\/* ===== Versi\u00f3n m\u00f3vil optimizada IAS ===== *\/\n@media (max-width: 768px){\n\n  .ix-wrap{\n    padding:10px;\n    border-radius:10px;\n  }\n\n  \/* Toolbar compacta y ordenada *\/\n  .ix-toolbar{\n    display:flex;\n    flex-direction:column;\n    gap:6px;\n  }\n\n  .ix-actions-bar{\n    display:grid;\n    grid-template-columns:1fr 1fr;\n    gap:6px;\n    width:100%;\n  }\n\n  \/* Orden ideal *\/\n  #ixSearch{ grid-column:1\/2; }\n  #ixClear{ grid-column:2\/3; }\n\n  #ixPerPage{ grid-column:1\/2; }\n  #ixCSV{ grid-column:2\/3; }\n\n  #ixPrev{ grid-column:1\/2; }\n  #ixNext{ grid-column:2\/3; }\n\n  #ixNew{\n    grid-column:1\/3;        \/* bot\u00f3n ocupa los 2 espacios *\/\n    width:100%;\n  }\n\n  \/* Tama\u00f1o visual m\u00e1s ligero *\/\n  .ix-input,\n  .ix-select,\n  .ix-btn{\n    padding:8px 10px;\n    font-size:.85rem;\n  }\n\n  \/* Tabla m\u00e1s compacta *\/\n  .ix-table{\n    font-size:11px;\n  }\n  .ix-table th,\n  .ix-table td{\n    padding:4px 6px;\n  }\n\n  \/* Botones en tabla a\u00fan m\u00e1s peque\u00f1os *\/\n  .ix-table .ix-btn{\n    padding:3px 6px;\n    font-size:11px;\n    border-radius:6px;\n  }\n\n  \/* Badges *\/\n  .ix-badge{\n    font-size:10px;\n    padding:2px 4px;\n  }\n}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t   \n\t\/* ====== TABLA RESPONSIVE SIN SCROLL EN CELULAR ====== *\/\n@media (max-width: 768px){\n\n  \/* Ocultar encabezados *\/\n  #ixTable thead{\n    display:none;\n  }\n\n  \/* Cada fila se vuelve como tarjeta *\/\n  #ixTable tr{\n    display:block;\n    margin-bottom:10px;\n    border:1px solid var(--bd);\n    border-radius:10px;\n    overflow:hidden;\n    background:#0e1530;\n  }\n\n  #ixTable td{\n    display:flex;\n    justify-content:space-between;\n    padding:6px 10px;\n    border-bottom:1px solid #1c2745;\n    font-size:13px;\n  }\n\n  \/* \u00daltima l\u00ednea sin borde *\/\n  #ixTable td:last-child{\n    border-bottom:none;\n  }\n\n  \/* Etiquetas antes del valor *\/\n  #ixTable td:before{\n    content:attr(data-label);\n    font-weight:600;\n    color:#96a6d9;\n    margin-right:6px;\n    text-align:left;\n    white-space:nowrap;\n  }\n\n  \/* Botones compactos *\/\n  #ixTable .ix-btn{\n    padding:4px 8px;\n    font-size:12px;\n  }\n}\n\t\t\t\t\t\t\t\t\t\t\t\t   \n\t\t\t\t\t\t\t\t\t\t\t   \n    <\/style>\n\n    <div class=\"ix-wrap\" id=\"ixIas\">\n      <div class=\"ix-toolbar\">\n        <div class=\"ix-title\">IAs \/ Prompts guardados<\/div>\n        <div class=\"ix-actions-bar\">\n          <input class=\"ix-input\" type=\"search\" id=\"ixSearch\" placeholder=\"Buscar\u2026 (Nombre, Usuario, URL, Prompt, Comentarios)\">\n          <button class=\"ix-btn ix-btn--ghost\" id=\"ixClear\">Eliminar filtros<\/button>\n\n          <select class=\"ix-select\" id=\"ixPerPage\" title=\"Registros por p\u00e1gina\">\n            <option value=\"10\">10 \/ p\u00e1g.<\/option>\n            <option value=\"20\">20 \/ p\u00e1g.<\/option>\n            <option value=\"50\">50 \/ p\u00e1g.<\/option>\n          <\/select>\n\n          <div class=\"ix-pagination ix-pagination--top\">\n            <button class=\"ix-btn\" id=\"ixPrev\">\u25c0<\/button>\n            <div id=\"ixPager\" class=\"ix-pager\"><\/div>\n            <button class=\"ix-btn\" id=\"ixNext\">\u25b6<\/button>\n          <\/div>\n\n          <button class=\"ix-btn\" id=\"ixCSV\">Exportar CSV<\/button>\n          <button class=\"ix-btn ix-btn--pri\" id=\"ixNew\">+ Nueva IA<\/button>\n        <\/div>\n      <\/div>\n\n      <div style=\"overflow:auto;border-radius:12px\">\n        <table class=\"ix-table\" id=\"ixTable\">\n          <thead>\n            <tr>\n              <th data-col=\"id\" class=\"sortable\">ID<\/th>\n              <th data-col=\"nombre\" class=\"sortable\">Nombre<\/th>\n              <th data-col=\"usuario\" class=\"sortable\">Usuario<\/th>\n              <th data-col=\"url\" class=\"sortable\">URL<\/th>\n              <th data-col=\"prompt\" class=\"sortable\">Prompt<\/th>\n              <th data-col=\"comentarios\" class=\"sortable\">Comentarios<\/th>\n              <th style=\"min-width:140px\">Acciones<\/th>\n            <\/tr>\n          <\/thead>\n          <tbody><\/tbody>\n        <\/table>\n      <\/div>\n\n      <!-- Modal principal (crear\/editar) -->\n      <div class=\"ix-modal\" id=\"ixModal\">\n        <div class=\"ix-card\">\n          <div class=\"ix-card-hd\">\n            <div class=\"ix-card-tt\" id=\"ixModalTitle\">Nueva IA<\/div>\n            <button class=\"ix-btn\" id=\"ixClose\">\u2715<\/button>\n          <\/div>\n          <div class=\"ix-card-bd\">\n            <form id=\"ixForm\" autocomplete=\"off\">\n              <input type=\"hidden\" name=\"cct_id\" id=\"ix_cct_id\" value=\"\">\n              <div class=\"ix-grid\">\n                <div class=\"ix-col-6\">\n                  <label class=\"ix-lb\" for=\"ix_custom_id\">ID<\/label>\n                  <input class=\"ix-field\" id=\"ix_custom_id\" name=\"id\" placeholder=\"ID externo \/ referencia\">\n                <\/div>\n                <div class=\"ix-col-6\">\n                  <label class=\"ix-lb\" for=\"ix_nombre\">Nombre<\/label>\n                  <input class=\"ix-field\" id=\"ix_nombre\" name=\"nombre\" required>\n                <\/div>\n                <div class=\"ix-col-6\">\n                  <label class=\"ix-lb\" for=\"ix_usuario\">Usuario<\/label>\n                  <input class=\"ix-field\" id=\"ix_usuario\" name=\"usuario\">\n                <\/div>\n                <div class=\"ix-col-12\">\n                  <label class=\"ix-lb\" for=\"ix_url\">URL<\/label>\n                  <input class=\"ix-field\" id=\"ix_url\" name=\"url\" placeholder=\"https:\/\/...\">\n                <\/div>\n                <div class=\"ix-col-12\">\n                  <label class=\"ix-lb\" for=\"ix_prompt\">Prompt<\/label>\n                  <textarea class=\"ix-field ix-ta\" id=\"ix_prompt\" name=\"prompt\"><\/textarea>\n                <\/div>\n                <div class=\"ix-col-12\">\n                  <label class=\"ix-lb\" for=\"ix_comentarios\">Comentarios \/ Notas<\/label>\n                  <textarea class=\"ix-field ix-ta\" id=\"ix_comentarios\" name=\"comentarios\"><\/textarea>\n                <\/div>\n              <\/div>\n            <\/form>\n          <\/div>\n          <div class=\"ix-card-ft\">\n            <button class=\"ix-btn\" id=\"ixCancel\">Cancelar<\/button>\n            <button class=\"ix-btn ix-btn--ok\" id=\"ixSave\">Guardar<\/button>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <!-- Modal lectura Prompt\/Comentarios -->\n      <div class=\"ix-modal\" id=\"ixView\">\n        <div class=\"ix-card\">\n          <div class=\"ix-card-hd\">\n            <div class=\"ix-card-tt\" id=\"ixViewTitle\">Detalle<\/div>\n            <button class=\"ix-btn\" id=\"ixViewClose\">\u2715<\/button>\n          <\/div>\n          <div class=\"ix-card-bd\">\n            <div id=\"ixViewText\"><\/div>\n          <\/div>\n          <div class=\"ix-card-ft\">\n            <button class=\"ix-btn\" id=\"ixViewOk\">Cerrar<\/button>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <!-- Modal de confirmaci\u00f3n (doble advertencia) -->\n      <div class=\"ix-modal\" id=\"ixConfirm\" data-variant=\"warn\">\n        <div class=\"ix-card\">\n          <div class=\"ix-card-hd\">\n            <div class=\"ix-card-tt\" id=\"ixConfirmTitle\">Confirmar<\/div>\n            <button class=\"ix-btn\" id=\"ixConfirmClose\">\u2715<\/button>\n          <\/div>\n          <div class=\"ix-card-bd\">\n            <img class=\"ix-confirm-ill\" id=\"ixConfirmImg\" alt=\"Alerta\" loading=\"lazy\">\n            <p id=\"ixConfirmText\" style=\"margin:0\"><\/p>\n          <\/div>\n          <div class=\"ix-card-ft\">\n            <button class=\"ix-btn\" id=\"ixConfirmCancel\">No<\/button>\n            <button class=\"ix-btn ix-btn--warn\" id=\"ixConfirmOk\">S\u00ed<\/button>\n          <\/div>\n        <\/div>\n      <\/div>\n\n    <\/div>\n\n    <script>\n      (function(){\n        const ajaxurl = \"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-admin\/admin-ajax.php\";\n        const nonce   = \"eee07f8014\";\n        const qs = (s, p=document)=>p.querySelector(s);\n        const el  = {\n          tBody: qs('#ixTable tbody'),\n          search: qs('#ixSearch'),\n          clear: qs('#ixClear'),\n          perPage: qs('#ixPerPage'),\n          prev: qs('#ixPrev'),\n          next: qs('#ixNext'),\n          pager: qs('#ixPager'),\n          csv: qs('#ixCSV'),\n          modal: qs('#ixModal'),\n          close: qs('#ixClose'),\n          cancel: qs('#ixCancel'),\n          newBtn: qs('#ixNew'),\n          save: qs('#ixSave'),\n          form: qs('#ixForm'),\n          title: qs('#ixModalTitle'),\n          \/\/ viewer\n          view: qs('#ixView'),\n          viewClose: qs('#ixViewClose'),\n          viewOk: qs('#ixViewOk'),\n          viewText: qs('#ixViewText'),\n          viewTitle: qs('#ixViewTitle'),\n          \/\/ confirm\n          cfm: qs('#ixConfirm'),\n          cfmTitle: qs('#ixConfirmTitle'),\n          cfmText: qs('#ixConfirmText'),\n          cfmOk: qs('#ixConfirmOk'),\n          cfmCancel: qs('#ixConfirmCancel'),\n          cfmClose: qs('#ixConfirmClose'),\n        };\n        let state = { page:1, pages:1, perPage:10, search:'', orderBy:'id', orderDir:'DESC', loading:false };\n\n        function openModal(editData){\n          el.modal.classList.add('is-open');\n          if (editData){\n            el.title.textContent='Editar IA #'+(editData.id || '');\n            el.form.reset();\n            el.form.querySelector('#ix_cct_id').value   = editData.cct_id || '';\n            el.form.querySelector('#ix_custom_id').value= editData.id || '';\n            el.form.querySelector('#ix_nombre').value   = editData.nombre || '';\n            el.form.querySelector('#ix_usuario').value  = editData.usuario || '';\n            el.form.querySelector('#ix_url').value      = editData.url || '';\n            el.form.querySelector('#ix_prompt').value   = editData.prompt || '';\n            el.form.querySelector('#ix_comentarios').value = editData.comentarios || '';\n          } else {\n            el.title.textContent='Nueva IA';\n            el.form.reset();\n            el.form.querySelector('#ix_cct_id').value='';\n          }\n          setTimeout(()=>{ const first = el.form.querySelector('input, textarea'); if(first) first.focus(); }, 0);\n        }\n        function closeModal(){ el.modal.classList.remove('is-open'); }\n\n        function openViewer(text, title){\n          el.viewText.textContent = text || '\u2014';\n          el.viewTitle.textContent = title || 'Detalle';\n          el.view.classList.add('is-open');\n        }\n        function closeViewer(){\n          el.view.classList.remove('is-open');\n          el.viewText.textContent = '';\n        }\n\n        function openConfirm(text, variant, onYes, imgUrl){\n          el.cfmText.textContent = text || '';\n          el.cfm.dataset.variant = (variant === 'danger') ? 'danger' : 'warn';\n\n          el.cfmOk.classList.remove('ix-btn--warn','ix-btn--err');\n          el.cfmOk.classList.add(el.cfm.dataset.variant === 'danger' ? 'ix-btn--err' : 'ix-btn--warn');\n\n          const ill = document.getElementById('ixConfirmImg');\n          if (ill){\n            if (el.cfm.dataset.variant === 'danger' && imgUrl){\n              ill.src = imgUrl;\n              ill.style.display = 'block';\n            } else {\n              ill.removeAttribute('src');\n              ill.style.display = 'none';\n            }\n          }\n\n          el.cfm.classList.add('is-open');\n\n          const cleanup = ()=>{\n            el.cfm.classList.remove('is-open');\n            el.cfmOk.removeEventListener('click', yesH);\n            el.cfmCancel.removeEventListener('click', noH);\n            el.cfmClose.removeEventListener('click', noH);\n            el.cfm.removeEventListener('click', backdropH);\n          };\n          const yesH = ()=>{ cleanup(); if (typeof onYes === 'function') onYes(); };\n          const noH  = cleanup;\n          const backdropH = (ev)=>{ if (ev.target === el.cfm) cleanup(); };\n\n          el.cfmOk.addEventListener('click', yesH);\n          el.cfmCancel.addEventListener('click', noH);\n          el.cfmClose.addEventListener('click', noH);\n          el.cfm.addEventListener('click', backdropH);\n        }\n\n        function enc(txt){ try{return btoa(unescape(encodeURIComponent(txt||'')));}catch(e){return '';} }\n\n        function rowTpl(r){\n  const url = r.url\n    ? `<a href=\"${r.url}\" target=\"_blank\" rel=\"noopener\" class=\"ix-badge\">Abrir<\/a>`\n    : '<span class=\"ix-badge\">\u2014<\/span>';\n\n  const promptBtn = r.prompt\n    ? `<a href=\"#\" class=\"ix-badge\" data-act=\"view\" data-title=\"Prompt\" data-txt=\"${enc(r.prompt)}\">Ver<\/a>`\n    : '<span class=\"ix-badge\">\u2014<\/span>';\n\n  const cmtBtn = r.comentarios\n    ? `<a href=\"#\" class=\"ix-badge\" data-act=\"view\" data-title=\"Comentarios\" data-txt=\"${enc(r.comentarios)}\">Ver<\/a>`\n    : '<span class=\"ix-badge\">\u2014<\/span>';\n\n  const nameSafe = (r.nombre||'').replace(\/\"\/g,'&quot;').replace(\/<\/g,'&lt;');\n\n  return `<tr>\n    <td data-label=\"ID\">${(r.id||'').toString().replace(\/<\/g,'&lt;')}<\/td>\n    <td data-label=\"Nombre\">${(r.nombre||'').replace(\/<\/g,'&lt;')}<\/td>\n    <td data-label=\"Usuario\">${(r.usuario||'').replace(\/<\/g,'&lt;')||'\u2014'}<\/td>\n    <td data-label=\"URL\">${url}<\/td>\n    <td data-label=\"Prompt\">${promptBtn}<\/td>\n    <td data-label=\"Comentarios\">${cmtBtn}<\/td>\n    <td data-label=\"Acciones\">\n      <button class=\"ix-btn ix-btn--pri\" data-act=\"edit\" data-cct-id=\"${r.cct_id}\">Editar<\/button>\n      <button class=\"ix-btn ix-btn--err\" data-act=\"del\" data-cct-id=\"${r.cct_id}\" data-nombre=\"${nameSafe}\">Eliminar<\/button>\n    <\/td>\n  <\/tr>`;\n}\n\n\n        function renderPager(){\n          const total = state.pages, cur = state.page;\n          if (!el.pager) return;\n          if (total <= 1) { el.pager.innerHTML = ''; return; }\n          const btn = (p, label=p, cls='') =>\n            `<button class=\"ix-pagebtn ${cls} ${p===cur?'is-active':''}\" data-page=\"${p}\" ${p===cur?'disabled':''}>${label}<\/button>`;\n          const parts = [];\n          const windowSize = 5;\n          let start = Math.max(1, cur - Math.floor(windowSize\/2));\n          let end   = Math.min(total, start + windowSize - 1);\n          start = Math.max(1, Math.min(start, end - windowSize + 1));\n          if (start > 1) {\n            parts.push(btn(1,'1'));\n            if (start > 2) parts.push('<span class=\"ix-ellipsis\">\u2026<\/span>');\n          }\n          for (let p=start; p<=end; p++) parts.push(btn(p,String(p)));\n          if (end < total) {\n            if (end < total-1) parts.push('<span class=\"ix-ellipsis\">\u2026<\/span>');\n            parts.push(btn(total,String(total)));\n          }\n          el.pager.innerHTML = parts.join('');\n        }\n\n        function load(){\n          if (state.loading) return;\n          state.loading = true;\n          el.tBody.innerHTML = `<tr><td colspan=\"7\" class=\"ix-empty\">Cargando\u2026<\/td><\/tr>`;\n          const fd = new FormData();\n          fd.append('action','ias_list');\n          fd.append('_wpnonce',nonce);\n          fd.append('page',state.page);\n          fd.append('per_page',state.perPage);\n          fd.append('search',state.search);\n          fd.append('order_by',state.orderBy);\n          fd.append('order_dir',state.orderDir);\n          fetch(ajaxurl,{method:'POST',body:fd})\n            .then(r=>r.json()).then(j=>{\n              state.loading=false;\n              if(!j.success){ el.tBody.innerHTML = `<tr><td colspan=\"7\" class=\"ix-empty\">Error: ${j.message||'desconocido'}<\/td><\/tr>`; return; }\n              const rows = j.data.rows || [];\n              state.pages = Math.max(1, Math.ceil((j.data.total||0) \/ state.perPage));\n              el.tBody.innerHTML = rows.length ? rows.map(rowTpl).join('') : `<tr><td colspan=\"7\" class=\"ix-empty\">Sin resultados.<\/td><\/tr>`;\n              renderPager();\n            }).catch(()=>{\n              state.loading=false;\n              el.tBody.innerHTML = `<tr><td colspan=\"7\" class=\"ix-empty\">Error de red.<\/td><\/tr>`;\n            });\n        }\n\n        function save(){\n          const fd = new FormData(el.form);\n          fd.append('action','ias_save');\n          fd.append('_wpnonce',nonce);\n          fetch(ajaxurl,{method:'POST',body:fd})\n            .then(r=>r.json()).then(j=>{\n              if(!j.success){ alert('Error: '+(j.message||'desconocido')); return; }\n              closeModal(); load();\n            }).catch(()=>alert('Error de red'));\n        }\n\n        function del(cct_id){\n          const fd = new FormData();\n          fd.append('action','ias_delete');\n          fd.append('_wpnonce',nonce);\n          fd.append('cct_id',cct_id);\n          fetch(ajaxurl,{method:'POST',body:fd})\n            .then(r=>r.json()).then(j=>{\n              if(!j.success){ alert('Error: '+(j.message||'desconocido')); return; }\n              load();\n            }).catch(()=>alert('Error de red'));\n        }\n\n        function confirmDelete(cct_id, nombre){\n          const name = (nombre||'esta IA');\n          openConfirm(`\u00bfDeseas eliminar \u201c${name}\u201d?`, 'warn', ()=>{\n            openConfirm(\n              `Esta acci\u00f3n eliminar\u00e1 definitivamente \u201c${name}\u201d de tu lista de IAs guardadas.\\n\\n\u00bfEst\u00e1s completamente seguro?`,\n              'danger',\n              ()=>{ del(cct_id); },\n              'https:\/\/desarrollo-web.ddns.net\/matrix\/wp-content\/uploads\/2025\/10\/ramon.png'\n            );\n          });\n        }\n\n        document.getElementById('ixTable').addEventListener('click', e=>{\n          const elAct = e.target.closest('[data-act]');\n          if(!elAct) return;\n          const act = elAct.getAttribute('data-act');\n          if (elAct.tagName === 'A') e.preventDefault();\n\n          if (act==='del'){\n            const cct_id = elAct.getAttribute('data-cct-id');\n            const nombre = elAct.getAttribute('data-nombre') || '';\n            return confirmDelete(cct_id, nombre);\n          }\n          if (act==='edit'){\n            const cct_id = elAct.getAttribute('data-cct-id');\n            const fd = new FormData();\n            fd.append('action','ias_get'); fd.append('_wpnonce',nonce); fd.append('cct_id',cct_id);\n            return fetch(ajaxurl,{method:'POST',body:fd}).then(r=>r.json()).then(j=>{\n              if(!j.success){ alert('Error: '+(j.message||'desconocido')); return; }\n              openModal(j.data);\n            });\n          }\n          if (act==='view'){\n            const b64 = elAct.getAttribute('data-txt') || '';\n            const ttl = elAct.getAttribute('data-title') || 'Detalle';\n            let txt = '';\n            try { txt = decodeURIComponent(escape(atob(b64))); } catch(e){ txt = ''; }\n            openViewer(txt, ttl);\n          }\n        });\n\n        document.querySelectorAll('#ixTable thead th.sortable').forEach(th=>{\n          th.addEventListener('click', ()=>{\n            const col = th.dataset.col; if (!col) return;\n            if (state.orderBy === col) state.orderDir = (state.orderDir === 'ASC') ? 'DESC' : 'ASC';\n            else { state.orderBy = col; state.orderDir = 'ASC'; }\n            document.querySelectorAll('#ixTable thead th.sortable').forEach(h=>h.classList.remove('asc','desc'));\n            th.classList.add(state.orderDir.toLowerCase());\n            state.page = 1; load();\n          });\n        });\n\n        el.perPage.addEventListener('change',()=>{ state.perPage=parseInt(el.perPage.value||10); state.page=1; load(); });\n        el.search.addEventListener('input',()=>{ state.search=el.search.value.trim(); state.page=1; load(); });\n        el.prev.addEventListener('click',()=>{ if(state.page>1){ state.page--; load(); }});\n        el.next.addEventListener('click',()=>{ if(state.page<state.pages){ state.page++; load(); }});\n        if (el.pager){\n          el.pager.addEventListener('click', (e)=>{\n            const b = e.target.closest('.ix-pagebtn'); if(!b || b.disabled) return;\n            const p = parseInt(b.dataset.page, 10);\n            if (Number.isFinite(p) && p>=1 && p<=state.pages){ state.page = p; load(); }\n          });\n        }\n\n        el.clear.addEventListener('click', ()=>{\n          el.search.value = ''; state.search = '';\n          state.orderBy = 'id'; state.orderDir = 'DESC'; state.page = 1;\n          document.querySelectorAll('#ixTable thead th.sortable').forEach(h=>h.classList.remove('asc','desc'));\n          load();\n        });\n\n        el.newBtn.addEventListener('click',()=>openModal());\n        el.close.addEventListener('click',closeModal);\n        el.cancel.addEventListener('click',closeModal);\n        el.save.addEventListener('click',save);\n\n        el.viewClose.addEventListener('click', closeViewer);\n        el.viewOk.addEventListener('click', closeViewer);\n        el.view.addEventListener('click', (ev)=>{ if (ev.target === el.view) closeViewer(); });\n\n        el.csv.addEventListener('click', ()=>{\n          const params = new URLSearchParams({\n            action: 'ias_export',\n            _wpnonce: nonce,\n            search: state.search,\n            order_by: state.orderBy,\n            order_dir: state.orderDir\n          });\n          window.location = ajaxurl + '?' + params.toString();\n        });\n\n        document.addEventListener('keydown', (e)=>{\n          if (e.key==='Escape' && el.modal.classList.contains('is-open')) closeModal();\n          if (e.key==='Escape' && el.view.classList.contains('is-open')) closeViewer();\n          if (e.key==='Escape' && el.cfm.classList.contains('is-open')) { el.cfm.classList.remove('is-open'); }\n        });\n\n        el.form.addEventListener('keydown', (e)=>{ if(e.key==='Enter' && e.target.tagName!=='TEXTAREA'){ e.preventDefault(); save(); }});\n\n        load();\n      })();\n    <\/script>\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2616","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/pages\/2616","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/comments?post=2616"}],"version-history":[{"count":0,"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/pages\/2616\/revisions"}],"wp:attachment":[{"href":"https:\/\/desarrollo-web.ddns.net\/matrix\/wp-json\/wp\/v2\/media?parent=2616"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}