1/* ========================================================= 2 WF BRIDGE · BootstrapDialog -> ventana_wf (WF) 3 Cargar DESPUÃS de bootstrap-dialog.*.js y DESPUÃS de wf.js 4 ========================================================= */ 5(function(window) 6{ 7 if (!window.BootstrapDialog) 8 { 9 console.warn(`[WF Bridge] BootstrapDialog no existe`); 10 return; 11 } 12 13 if (typeof window.ventana_wf !== `function`) 14 { 15 console.warn(`[WF Bridge] ventana_wf() no existe. Carga wf.js antes del bridge.`); 16 return; 17 } 18 19 const BD = window.BootstrapDialog; 20 21 if (BD.__WF_BRIDGE__) return; 22 BD.__WF_BRIDGE__ = true; 23 24 // ========================= 25 // DEPURACIÃN 26 // ========================= 27 let depuracion_en_consola = true; 28 let d = ``; 29 30 const dbg_print = () => 31 { 32 if (depuracion_en_consola && d) console.log(d); 33 }; 34 35 const dbg_reset = () => 36 { 37 if (!depuracion_en_consola) return; 38 d = ``; 39 }; 40 41 const dbg_add = (txt) => 42 { 43 if (!depuracion_en_consola) return; 44 d += `\n${txt}`; 45 }; 46 // ========================= 47 48 const size_map = (size) => 49 { 50 if (size === BD.SIZE_SMALL) return `w576`; 51 if (size === BD.SIZE_LARGE) return `w992`; 52 if (size === BD.SIZE_WIDE) return `w1500`; 53 if (size === BD.SIZE_EXTRAWIDE) return `wfull`; 54 55 return `w500`; // NORMAL (BS4 default) 56 }; 57 58 const mount_message = (root, message, api = null) => 59 { 60 if (!root) return; 61 62 const cont = root.querySelector(`.contenido`); 63 if (!cont) return; 64 65 cont.innerHTML = ``; 66 67 let m = message; 68 69 // 1) message como función (legacy BootstrapDialog) 70 if (typeof m === `function`) 71 { 72 try 73 { 74 m = m(api); 75 } 76 catch (e) 77 { 78 console.error(`[WF Bridge] message() error:`, e); 79 m = ``; 80 } 81 } 82 83 // 2) jQuery object 84 if (window.jQuery && m && m.jquery) 85 { 86 m.each(function(){ cont.appendChild(this); }); 87 return; 88 } 89 90 // 3) DOM element 91 if (m instanceof HTMLElement) 92 { 93 cont.appendChild(m); 94 return; 95 } 96 97 // 4) string / other 98 if (m !== undefined && m !== null) cont.innerHTML = String(m); 99 }; 100 101 const render_buttons = (root, buttons = [], api = null) => 102 { 103 if (!root) return; 104 105 const footer = root.querySelector(`.border-top`); 106 if (!footer) return; 107 108 // limpiamos todo menos el botón âCerrarâ final (que ya está en ventana_wf) 109 const cerrar = footer.querySelector(`.cerrar_ventana_wf`); 110 footer.innerHTML = ``; 111 112 if (Array.isArray(buttons) && buttons.length) 113 { 114 buttons.forEach(btn => 115 { 116 const b = document.createElement(`button`); 117 b.type = `button`; 118 b.className = btn.cssClass || `btn btn-sm btn-primary ml-2`; 119 b.innerHTML = btn.icon ? `${btn.icon} ${btn.label || ``}` : (btn.label || `Aceptar`); 120 121 b.addEventListener(`click`, (ev) => 122 { 123 if (typeof btn.action === `function`) btn.action(api, ev); 124 }); 125 126 footer.appendChild(b); 127 }); 128 } 129 130 if (cerrar) footer.appendChild(cerrar); 131 else 132 { 133 const c = document.createElement(`span`); 134 c.className = `btn btn-sm btn-light ml-2 cerrar_ventana_wf puntero`; 135 c.textContent = `Cerrar`; 136 footer.appendChild(c); 137 } 138 }; 139 140 const wf_bring_to_front = (root) => 141 { 142 // Mover al final del body suele arreglar stacking contexts raros (formulario por encima, etc.) 143 if (root && root.parentNode) document.body.appendChild(root); 144 145 // Z-index incremental 146 window.__wf_bd_z = (window.__wf_bd_z || 2000) + 2; 147 root.style.zIndex = window.__wf_bd_z; 148 149 // Focus âamableâ 150 const f = root.querySelector(`input,select,textarea,button,[tabindex]:not([tabindex="-1"])`); 151 if (f) f.focus({ preventScroll:true }); 152 }; 153 154 const wf_open = (root) => 155 { 156 if (!root) return; 157 158 wf_bring_to_front(root); 159 160 if (!root.classList.contains(`visible`)) 161 { 162 root.classList.add(`visible`); 163 document.body.style.overflow = `hidden`; 164 root.scrollTop = 0; 165 } 166 }; 167 168 const wf_close = (root) => 169 { 170 root.classList.remove(`visible`); 171 172 // si no quedan ventanas WF visibles, restauramos scroll 173 if (!document.querySelector(`.ventana_wf.visible`)) document.body.style.overflow = ``; 174 175 const eliminar = root.getAttribute(`data-eliminar_al_cerrar`); 176 document.querySelectorAll(`.espera`).forEach(n => n.remove()); 177 if (typeof window.eliminar_espera === `function`) window.eliminar_espera(); 178 if (eliminar === `1`) root.remove(); 179 }; 180 181 // Guardamos el show original por si quieres fallback 182 const original_show = BD.show; 183 184 BD.show = function(options = {}) 185 { 186 dbg_reset(); 187 188 // ID estable y único 189 const id = `wf_bd_${Date.now()}_${Math.floor(Math.random() * 1000000)}`; 190 const selector = `#${id}`; 191 192 const title = options.title || ``; 193 const clase = size_map(options.size); 194 const header = options.hasOwnProperty(`title`) ? true : true; 195 196 // crea ventana (si existiera, la reiniciamos) 197 const w = new wf_ventana(); 198 199 w.abrir({ 200 id: selector, 201 eliminar: true, 202 contenido_b64: null, 203 clase_ancho: clase, 204 titulo_ventana: title, 205 pintar_cabecera: header 206 }); 207 208 const root = document.getElementById(id); 209 210 if (!root) 211 {
212 console.warn(`[WF Bridge] No se pudo crear la ventana: ${selector}`); 213 return original_show ? original_show(options) : null; 214 } 215 216 if (root) root.setAttribute(`data-eliminar_al_cerrar`, `1`); 217 218 dbg_add(`=== DEBUG BD.show ===`); 219 dbg_add(`id: ${id}`); 220 dbg_add(`selector: ${selector}`); 221 dbg_add(`root?: ${!!root}`); 222 dbg_add(`root.isConnected: ${root ? root.isConnected : 'n/a'}`); 223 dbg_add(`root.visible: ${root ? root.classList.contains('visible') : 'n/a'}`); 224 dbg_add(`body.overflow: ${document.body.style.overflow || '(vacÃo)'}`); 225 dbg_add(`ventanas visibles: ${document.querySelectorAll('.ventana_wf.visible').length}`); 226 227 // API compatible mÃnima 228 const api = { 229 close: () => 230 { 231 const r = document.getElementById(id); 232 if (!r) return; 233 wf_close(r); 234 }, 235 236 open: () => 237 { 238 const r = asegurar_ventana(); 239 if (!r) return; 240 wf_open(r); 241 }, 242 243 getModal: () => 244 { 245 const r = document.getElementById(id); 246 return (window.jQuery ? window.jQuery(r) : r); 247 }, 248 249 getModalHeader: () => 250 { 251 return { 252 hide: function() 253 { 254 const r = document.getElementById(id); 255 if (!r) return this; 256 257 const cabecera = r.querySelector(`.cabecera`); 258 if (cabecera) cabecera.remove(); 259 260 return this; 261 } 262 }; 263 } 264 }; 265 266 const asegurar_ventana = () => 267 { 268 let r = document.getElementById(id); 269 270 if (!r) 271 { 272 const w = new wf_ventana(); 273 274 w.abrir({ 275 id: selector, 276 eliminar: true, 277 contenido_b64: null, 278 clase_ancho: clase, 279 titulo_ventana: title, 280 pintar_cabecera: header 281 }); 282 283 r = document.getElementById(id); 284 285 if (!r) return null; 286 287 mount_message(r, options.message, api); 288 render_buttons(r, options.buttons || [], api); 289 290 r.addEventListener(`click`, (ev) => 291 { 292 const btn = ev.target.closest(`.cerrar_ventana_wf`); 293 if (btn) api.close(); 294 }); 295 296 r.setAttribute(`data-eliminar_al_cerrar`, `1`); 297 } 298 299 return r; 300 }; 301 302 // contenido 303 mount_message(root, options.message, api); 304 305 // botones (si los hay) 306 render_buttons(root, options.buttons || [], api); 307 308 // callbacks similares 309 if (typeof options.onshow === `function`) 310 { 311 const ok = options.onshow(api); 312 if (ok === false) 313 { 314 dbg_add(`onshow devolvió false -> no abrir`); 315 dbg_print(); 316 return api; 317 } 318 } 319 320 wf_open(root); 321 322 if (typeof options.onshown === `function`) options.onshown(api); 323 324 // Cerrar con ESC (si quieres) 325 if (options.closable !== false) 326 {
327 const key = (ev) => 328 { 329 if (ev.key === `Escape`) 330 { 331 api.close(); 332 document.removeEventListener(`keydown`, key); 333 } 334 }; 335 document.addEventListener(`keydown`, key); 336 } 337 338 // click en .cerrar_ventana_wf 339 root.addEventListener(`click`, (ev) => 340 { 341 const btn = ev.target.closest(`.cerrar_ventana_wf`); 342 if (btn) api.close(); 343 }); 344 345 dbg_add(`OPEN ejecutado`); 346 dbg_add(`root.visible (post): ${root ? root.classList.contains('visible') : 'n/a'}`); 347 dbg_add(`[WF Bridge] BootstrapDialog.show -> ventana_wf OK`); 348 dbg_print(); 349 350 console.log(`[WF Bridge] BootstrapDialog.show -> ventana_wf OK`, selector); 351 352 return api; 353 }; 354 355 // marca para debugging 356 BD.USE_WF = true; 357 358})(window); 359 360/* ========================================================= 361 WF BRIDGE (2) · soportar: new BootstrapDialog(...).realize().open() 362 ========================================================= */ 363(function(window) 364{ 365 if (!window.BootstrapDialog) return; 366 if (typeof window.ventana_wf !== `function`) return; 367 368 // Si ya hemos âproxyadoâ el constructor, no repetimos 369 if (window.BootstrapDialog.__WF_PROXY_CONSTRUCTOR__) return; 370 371 const BD_ORIG = window.BootstrapDialog; 372 373 // ========================= 374 // DEPURACIÃN 375 // ========================= 376 let depuracion_en_consola = true; 377 let d = ``; 378 379 const dbg_print = () => 380 { 381 if (depuracion_en_consola && d) console.log(d); 382 }; 383 384 const dbg_reset = () => 385 { 386 if (!depuracion_en_consola) return; 387 d = ``; 388 }; 389 390 const dbg_add = (txt) => 391 { 392 if (!depuracion_en_consola) return; 393 d += `\n${txt}`; 394 }; 395 // ========================= 396 397 // Utilidad: mapear tamaños a TUS clases reales 398 const size_map = (size) => 399 { 400 if (size === BD_ORIG.SIZE_SMALL) return `w576`; 401 if (size === BD_ORIG.SIZE_LARGE) return `w992`; 402 if (size === BD_ORIG.SIZE_NORMAL) return `w992`; 403 if (size === BD_ORIG.SIZE_WIDE) return `w1500`; 404 if (size === BD_ORIG.SIZE_EXTRAWIDE) return `wfull`; 405 406 return `w500`; 407 }; 408 409 const mount_message = (root, message, api = null) => 410 { 411 const cont = root.querySelector(`.contenido`); 412 if (!cont) return; 413 414 cont.innerHTML = ``; 415 416 let m = message; 417 418 if (typeof m === `function`) 419 { 420 try { m = m(api); } 421 catch (e) { console.error(`[WF Bridge] message() error:`, e); m = ``; } 422 } 423 424 if (window.jQuery && m && m.jquery) 425 { 426 m.each(function(){ cont.appendChild(this); }); 427 return; 428 } 429 430 if (m instanceof HTMLElement) 431 { 432 cont.appendChild(m); 433 return; 434 } 435 436 if (m !== undefined && m !== null) cont.innerHTML = String(m); 437 }; 438 439 // âClaseâ WF compatible con el API mÃnimo que usa tu legacy 440 function WF_BootstrapDialog(options = {}) 441 { 442 this.__wf = { 443 id: `wf_bd_${Date.now()}_${Math.floor(Math.random() * 1000000)}`, 444 opts: options, 445 root: null, 446 opened: false 447 }; 448 } 449 450 WF_BootstrapDialog.prototype.realize = function() 451 { 452 dbg_reset(); 453 454 const o = this.__wf.opts || {}; 455 const selector = `#${this.__wf.id}`; 456 457 // crea ventana 458 const clase = size_map(o.size); 459 const title = o.title || ``; 460 461 const w = new wf_ventana(); 462 463 w.abrir({ 464 id: selector, 465 eliminar: true, 466 contenido_b64: null, 467 clase_ancho: clase, 468 titulo_ventana: title, 469 pintar_cabecera: true 470 }); 471 472 const root = document.getElementById(this.__wf.id); 473 this.__wf.root = root; 474 475 if (root) root.setAttribute(`data-eliminar_al_cerrar`, `1`); 476 477 // inyecta contenido 478 mount_message(root, o.message, this); 479 480 dbg_add(`=== DEBUG realize ===`); 481 dbg_add(`id: ${this.__wf.id}`); 482 dbg_add(`root?: ${!!root}`); 483 dbg_add(`root.isConnected: ${root ? root.isConnected : 'n/a'}`); 484 dbg_add(`root.visible: ${root ? root.classList.contains('visible') : 'n/a'}`); 485 dbg_add(`body.overflow: ${document.body.style.overflow || '(vacÃo)'}`); 486 dbg_add(`ventanas visibles: ${document.querySelectorAll('.ventana_wf.visible').length}`); 487 dbg_print(); 488 489 // onshown (tu legacy lo usa muchÃsimo) 490 // OJO: lo dispararemos en open(), no aquÃ, para que sea más fiel al plugin. 491 return this; 492 }; 493 494 WF_BootstrapDialog.prototype.open = function() 495 { 496 dbg_reset(); 497 498 const o = this.__wf.opts || {}; 499 500 let root = this.__wf.root || document.getElementById(this.__wf.id); 501 502 dbg_add(`=== DEBUG open (antes) ===`); 503 dbg_add(`id: ${this.__wf.id}`); 504 dbg_add(`this.__wf.root?: ${!!this.__wf.root}`); 505 dbg_add(`getElementById?: ${!!document.getElementById(this.__wf.id)}`); 506 dbg_add(`root?: ${!!root}`); 507 dbg_add(`root.isConnected: ${root ? root.isConnected : 'n/a'}`); 508 dbg_add(`root.visible: ${root ? root.classList.contains('visible') : 'n/a'}`); 509 dbg_add(`body.overflow: ${document.body.style.overflow || '(vacÃo)'}`); 510 dbg_add(`ventanas visibles: ${document.querySelectorAll('.ventana_wf.visible').length}`); 511 512 // si lo cerraron con remove(), el root guardado ya no está en DOM 513 if (root && !root.isConnected) root = null; 514 515 if (!root) 516 { 517 dbg_add(`root NO existe -> realize().open()`); 518 dbg_print(); 519 return this.realize().open(); 520 } 521 522 this.__wf.root = root; 523 524 if (!root.classList.contains(`visible`)) 525 { 526 if (root && root.parentNode) document.body.appendChild(root); 527 window.__wf_bd_z = (window.__wf_bd_z || 2000) + 2; 528 root.style.zIndex = window.__wf_bd_z; 529 530 root.classList.add(`visible`); 531 document.body.style.overflow = `hidden`; 532 this.__wf.opened = true; 533 } 534 535 // hook de cierre WF 536 root.addEventListener(`click`, (ev) => 537 { 538 if (ev.target.closest(`.cerrar_ventana_wf`)) this.close(); 539 }, { once:false }); 540 541 // callback compatible 542 if (typeof o.onshown === `function`) o.onshown(this); 543 544 dbg_add(`=== DEBUG open (después) ===`); 545 dbg_add(`root.visible: ${root.classList.contains('visible')}`); 546 dbg_add(`body.overflow: ${document.body.style.overflow || '(vacÃo)'}`); 547 dbg_add(`ventanas visibles: ${document.querySelectorAll('.ventana_wf.visible').length}`); 548 dbg_print(); 549 550 return this; 551 }; 552 553 WF_BootstrapDialog.prototype.close = function() 554 { 555 dbg_reset(); 556 557 const o = this.__wf.opts || {}; 558 const root = this.__wf.root || document.getElementById(this.__wf.id); 559 560 dbg_add(`=== DEBUG close (antes) ===`); 561 dbg_add(`id: ${this.__wf.id}`); 562 dbg_add(`root?: ${!!root}`); 563 dbg_add(`root.isConnected: ${root ? root.isConnected : 'n/a'}`); 564 dbg_add(`root.visible: ${root ? root.classList.contains('visible') : 'n/a'}`); 565 dbg_add(`body.overflow: ${document.body.style.overflow || '(vacÃo)'}`); 566 dbg_add(`ventanas visibles: ${document.querySelectorAll('.ventana_wf.visible').length}`); 567 568 if (!root) 569 { 570 dbg_add(`root NO existe -> return`); 571 dbg_print(); 572 return; 573 } 574 575 root.classList.remove(`visible`); 576 577 // Si no quedan ventanas visibles, devolvemos scroll 578 if (!document.querySelector(`.ventana_wf.visible`)) document.body.style.overflow = ``; 579 580 // autodestroy: por defecto sÃ, para âparecerseâ al modal 581 // si lo quieres configurable, usa o.autodestroy / o.removeOnHide 582 if (o.autodestroy === true || o.removeOnHide === true || o.autodestroy === undefined) 583 { 584 root.remove(); 585 this.__wf.root = null; 586 this.__wf.opened = false;
587 588 dbg_add(`root.remove() ejecutado`); 589 dbg_add(`root.isConnected (post): ${root ? root.isConnected : 'n/a'}`); 590 dbg_add(`getElementById (post): ${!!document.getElementById(this.__wf.id)}`); 591 } 592 593 if (typeof o.onhidden === `function`) o.onhidden(this); 594 595 dbg_add(`=== DEBUG close (después) ===`); 596 dbg_add(`body.overflow: ${document.body.style.overflow || '(vacÃo)'}`); 597 dbg_add(`ventanas visibles: ${document.querySelectorAll('.ventana_wf.visible').length}`); 598 dbg_print(); 599 }; 600 601 WF_BootstrapDialog.prototype.setTitle = function(t) 602 { 603 const root = this.__wf.root || document.getElementById(this.__wf.id); 604 if (!root) return; 605 606 const span = root.querySelector(`.cabecera .text-monospace`); 607 if (span) span.textContent = t || ``; 608 }; 609 610 WF_BootstrapDialog.prototype.setMessage = function(m) 611 { 612 const root = this.__wf.root || document.getElementById(this.__wf.id); 613 if (!root) return; 614 615 mount_message(root, m, this); 616 }; 617 618 /** 619 * Compatibilidad legacy BootstrapDialog 620 * ---------------------------------------------------------------------------------------------------- 621 * Este método existÃa en BootstrapDialog original, pero en WF no hay cabecera real. 622 * 623 * Se devuelve un objeto con método hide() vacÃo para evitar errores en código legacy: 624 * 625 * modal.getModalHeader().hide(); 626 * 627 * Resultado: 628 * - No rompe 629 * - No hace nada 630 * - Mantiene compatibilidad sin tocar código antiguo 631 */ 632 WF_BootstrapDialog.prototype.getModalHeader = function() 633 { 634 const self = this; 635 636 return { 637 hide: function() 638 { 639 const root = self.__wf?.root || document.getElementById(self.__wf?.id); 640 641 if (!root) return this; 642 643 const cabecera = root.querySelector(`.cabecera`); 644 645 if (cabecera) cabecera.remove(); 646 647 return this; 648 } 649 }; 650 }; 651 652 // Constructor proxy: cuando hagan `new BootstrapDialog(...)` devolvemos WF_BootstrapDialog 653 function BootstrapDialogProxy(options) 654 { 655 return new WF_BootstrapDialog(options); 656 } 657 658 // Copiamos todas las props/constantes estáticas del original (TYPE_PRIMARY, SIZE_EXTRAWIDE, etc.) 659 Object.keys(BD_ORIG).forEach(k => BootstrapDialogProxy[k] = BD_ORIG[k]); 660 661 // Marcadores 662 BootstrapDialogProxy.__WF_PROXY_CONSTRUCTOR__ = true; 663 BootstrapDialogProxy.__WF_BRIDGE__ = BD_ORIG.__WF_BRIDGE__ || true; 664 BootstrapDialogProxy.__BD_ORIG__ = BD_ORIG; 665 666 // Si ya habÃas secuestrado show(), lo respetamos; si no, creamos fallback 667 if (typeof BD_ORIG.show === `function`) 668 { 669 BootstrapDialogProxy.show = BD_ORIG.show; // si tu show ya es WF, perfecto 670 } 671 else 672 { 673 BootstrapDialogProxy.show = function(opts){ return new WF_BootstrapDialog(opts).realize().open(); }; 674 } 675 676 // Y ahora SÃ: sustituimos global 677 window.BootstrapDialog = BootstrapDialogProxy; 678 679 console.log(`[WF Bridge] Soporte constructor activado: new BootstrapDialog(...).realize().open()`); 680 681})(window);
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.