1(function () { 2 'use strict'; 3 4 var pdfModulePromise = null; 5 var minimumZoom = 0.75; 6 var maximumZoom = 4; 7 var zoomStep = 0.25; 8 9 function loadPdfModule() { 10 if (!pdfModulePromise) { 11 pdfModulePromise = import(aipArchive.pdfJsUrl).then(function (pdfjs) { 12 pdfjs.GlobalWorkerOptions.workerSrc = aipArchive.pdfWorkerUrl; 13 return pdfjs; 14 }).catch(function (error) { 15 pdfModulePromise = null; 16 throw error; 17 }); 18 } 19 20 return pdfModulePromise; 21 } 22 23 function initializeArchive(archive) { 24 var form = archive.querySelector('[data-aip-search-form]'); 25 var results = archive.querySelector('[data-aip-results]'); 26 var dateArchive = archive.querySelector('[data-aip-date-archive]'); 27 var datePanel = archive.querySelector('[data-aip-date-panel]'); 28 var dateToggle = archive.querySelector('[data-aip-date-toggle]'); 29 var modal = archive.querySelector('[data-aip-modal]'); 30 var viewerWindow = archive.querySelector('.aip-viewer-window'); 31 var modalTitle = archive.querySelector('[data-aip-modal-title]'); 32 var openNew = archive.querySelector('[data-aip-open-new]'); 33 var embedButton = archive.querySelector('[data-aip-embed]'); 34 var embedDialog = archive.querySelector('[data-aip-embed-dialog]'); 35 var embedCode = archive.querySelector('[data-aip-embed-code]'); 36 var embedCopyButton = archive.querySelector('[data-aip-embed-copy]'); 37 var shareButton = archive.querySelector('[data-aip-share]'); 38 var shareFeedback = archive.querySelector('[data-aip-share-feedback]'); 39 var viewerSearchToggle = archive.querySelector('[data-aip-viewer-search-toggle]'); 40 var viewerSearchPanel = archive.querySelector('[data-aip-viewer-search-panel]'); 41 var viewerSearchForm = archive.querySelector('[data-aip-viewer-search-form]');
42 var viewerSearchInput = viewerSearchForm ? viewerSearchForm.elements.edition_query : null; 43 var viewerSearchResult = archive.querySelector('[data-aip-viewer-search-result]'); 44 var viewerSearchStatus = archive.querySelector('[data-aip-viewer-search-status]'); 45 var viewerSearchSnippet = archive.querySelector('[data-aip-viewer-search-snippet]'); 46 var viewerSearchPrevious = archive.querySelector('[data-aip-viewer-search-prev]'); 47 var viewerSearchNext = archive.querySelector('[data-aip-viewer-search-next]'); 48 var loading = archive.querySelector('[data-aip-reader-loading]'); 49 var loadProgress = archive.querySelector('[data-aip-load-progress]'); 50 var progressBar = archive.querySelector('[data-aip-progress-bar]'); 51 var stage = archive.querySelector('[data-aip-flip-stage]'); 52 var bookShell = archive.querySelector('[data-aip-book-shell]'); 53 var book = archive.querySelector('[data-aip-book]'); 54 var controls = archive.querySelector('[data-aip-reader-controls]'); 55 var pageStatus = archive.querySelector('[data-aip-page-status]'); 56 var pageRange = archive.querySelector('[data-aip-page-range]'); 57 var zoomOutButton = archive.querySelector('[data-aip-zoom-out]'); 58 var zoomInButton = archive.querySelector('[data-aip-zoom-in]'); 59 var zoomLevel = archive.querySelector('[data-aip-zoom-level]'); 60 var errorPanel = archive.querySelector('[data-aip-reader-error]'); 61 var errorMessage = archive.querySelector('[data-aip-reader-error-message]'); 62 var nativeFrame = archive.querySelector('[data-aip-frame]'); 63 var previousButtons = archive.querySelectorAll('[data-aip-prev]'); 64 var nextButtons = archive.querySelectorAll('[data-aip-next]'); 65 var fullscreenButton = archive.querySelector('[data-aip-fullscreen]'); 66 var nativeButton = archive.querySelector('[data-aip-use-native]'); 67 var lastFocused = null; 68 var activeYear = ''; 69 var activeMonth = ''; 70 var currentPdfUrl = ''; 71 var currentEdition = ''; 72 var currentEditionTitle = ''; 73 var currentEditionDate = ''; 74 var currentStartPage = 1; 75 var shareFeedbackTimer = null; 76 var pageFlip = null; 77 var pdfDocument = null; 78 var loadingTask = null; 79 var renderJobs = {}; 80 var renderedPages = {}; 81 var readerGeneration = 0; 82 var zoom = 1; 83 var panX = 0; 84 var panY = 0; 85 var isPanning = false; 86 var panStartX = 0; 87 var panStartY = 0; 88 var panOriginX = 0; 89 var panOriginY = 0; 90 var isEmbedded = document.body.classList.contains('aip-embed-page'); 91 var editionSearchMatches = []; 92 var editionSearchIndex = -1; 93 var editionSearchRequest = 0; 94 95 function search(page) { 96 var data = new FormData(); 97 data.append('action', 'aip_search_editions'); 98 data.append('nonce', aipArchive.nonce); 99 data.append('query', form.elements.query.value.trim()); 100 data.append('year', activeYear); 101 data.append('month', activeMonth); 102 data.append('page', page || 1); 103 data.append('per_page', archive.getAttribute('data-per-page')); 104 105 results.setAttribute('aria-busy', 'true'); 106 archive.classList.add('is-loading'); 107 108 fetch(aipArchive.ajaxUrl, { 109 method: 'POST', 110 credentials: 'same-origin', 111 body: data 112 }) 113 .then(function (response) { 114 if (!response.ok) { 115 throw new Error('Network response was not successful.'); 116 } 117 return response.json(); 118 }) 119 .then(function (payload) { 120 if (!payload.success || !payload.data || typeof payload.data.html !== 'string') { 121 throw new Error('Invalid response.'); 122 } 123 results.innerHTML = payload.data.html; 124 results.focus({ preventScroll: true }); 125 }) 126 .catch(function () { 127 results.innerHTML = '<div class="aip-error" role="alert">' + escapeHtml(aipArchive.error) + '</div>'; 128 }) 129 .finally(function () { 130 results.setAttribute('aria-busy', 'false'); 131 archive.classList.remove('is-loading'); 132 }); 133 } 134 135 function setDateFilter(year, month, selectedButton) { 136 activeYear = year || ''; 137 activeMonth = month || ''; 138 139 if (dateArchive) { 140 dateArchive.querySelectorAll('[data-aip-date-filter]').forEach(function (button) { 141 var isSelected = button === selectedButton; 142 button.classList.toggle('is-active', isSelected); 143 button.setAttribute('aria-pressed', isSelected ? 'true' : 'false'); 144 }); 145 } 146 147 search(1); 148 149 if (window.matchMedia('(max-width: 760px)').matches && datePanel && dateToggle) { 150 datePanel.hidden = true; 151 dateToggle.setAttribute('aria-expanded', 'false'); 152 } 153 } 154 155 function toggleYear(button) { 156 var group = button.closest('[data-aip-year-group]'); 157 var months = group ? group.querySelector('[data-aip-year-months]') : null; 158 var willOpen = button.getAttribute('aria-expanded') !== 'true'; 159 160 if (!group || !months) { 161 return; 162 } 163 164 button.setAttribute('aria-expanded', willOpen ? 'true' : 'false'); 165 group.classList.toggle('is-open', willOpen); 166 months.hidden = !willOpen; 167 } 168 169 function buildEditionUrl(edition, pageNumber) { 170 var url = new URL(window.location.href); 171 url.searchParams.delete('edicion'); 172 url.searchParams.delete('pagina'); 173 url.hash = ''; 174 175 if (edition) { 176 url.searchParams.set('edicion', edition); 177 if (pageNumber && pageNumber > 1) { 178 url.searchParams.set('pagina', pageNumber); 179 } 180 } 181 182 return url.toString(); 183 } 184 185 function updateEditionUrl(edition, method, pageNumber) { 186 if (!window.history || typeof window.history[method] !== 'function') { 187 return; 188 } 189 190 var targetUrl = buildEditionUrl(edition, pageNumber); 191 if (targetUrl !== window.location.href) { 192 window.history[method]({ aipEdition: edition || '' }, '', targetUrl); 193 } 194 } 195 196 function showShareFeedback(message) { 197 if (!shareFeedback) { 198 return; 199 } 200 201 window.clearTimeout(shareFeedbackTimer); 202 shareFeedback.textContent = message; 203 shareFeedback.classList.add('is-visible'); 204 shareFeedbackTimer = window.setTimeout(function () { 205 shareFeedback.classList.remove('is-visible'); 206 shareFeedback.textContent = ''; 207 }, 2600); 208 } 209 210 function copyText(value) { 211 if (navigator.clipboard && window.isSecureContext) { 212 return navigator.clipboard.writeText(value); 213 } 214 215 return new Promise(function (resolve, reject) { 216 var field = document.createElement('textarea'); 217 field.value = value; 218 field.setAttribute('readonly', ''); 219 field.style.position = 'fixed'; 220 field.style.opacity = '0'; 221 document.body.appendChild(field); 222 field.select(); 223 224 try { 225 if (!document.execCommand('copy')) { 226 throw new Error('Copy failed.'); 227 } 228 resolve(); 229 } catch (error) { 230 reject(error); 231 } finally { 232 field.remove(); 233 } 234 }); 235 } 236 237 function currentPageNumber() { 238 return pageFlip ? pageFlip.getCurrentPageIndex() + 1 : currentStartPage; 239 } 240 241 function escapeAttribute(value) { 242 return String(value || '') 243 .replace(/&/g, '&') 244 .replace(/"/g, '"') 245 .replace(/</g, '<') 246 .replace(/>/g, '>'); 247 } 248 249 function buildEmbedCode() { 250 var embedUrl = new URL(aipArchive.embedBaseUrl, window.location.href); 251 var pageNumber = currentPageNumber(); 252 embedUrl.searchParams.set('aip_embed', '1'); 253 embedUrl.searchParams.set('edicion', currentEdition); 254 embedUrl.searchParams.delete('pagina'); 255 if (pageNumber > 1) { 256 embedUrl.searchParams.set('pagina', pageNumber); 257 } 258 259 return '<iframe src="' + escapeAttribute(embedUrl.toString()) + '" title="' + escapeAttribute(currentEditionTitle) + '" width="100%" height="720" style="border:0" loading="lazy" allowfullscreen></iframe>'; 260 } 261 262 function openEmbedDialog() { 263 if (!currentEdition || !embedDialog || !embedCode) { 264 return; 265 } 266 267 embedCode.value = buildEmbedCode(); 268 embedDialog.hidden = false;
269 embedCode.focus(); 270 embedCode.select(); 271 } 272 273 function closeEmbedDialog() { 274 if (!embedDialog) { 275 return; 276 } 277 embedDialog.hidden = true; 278 if (embedButton) { 279 embedButton.focus(); 280 } 281 } 282 283 function copyEmbedCode() { 284 if (!embedCode || !embedCopyButton) { 285 return; 286 } 287 288 copyText(embedCode.value).then(function () { 289 embedCopyButton.textContent = aipArchive.embedCopied; 290 }).catch(function () { 291 embedCopyButton.textContent = aipArchive.embedCopyError; 292 }).finally(function () { 293 window.setTimeout(function () { 294 embedCopyButton.textContent = aipArchive.embedCopy; 295 }, 2200); 296 }); 297 } 298 299 function shareEdition() { 300 if (!currentEdition) { 301 return; 302 } 303 304 var sharePage = currentPageNumber(); 305 var shareUrl = buildEditionUrl(currentEdition, sharePage); 306 var shareData = { 307 title: currentEditionTitle, 308 text: currentEditionDate ? aipArchive.shareDatedText.replace('%s', currentEditionDate) : aipArchive.shareText, 309 url: shareUrl 310 }; 311 312 if (navigator.share) { 313 navigator.share(shareData).catch(function (error) { 314 if (error && error.name !== 'AbortError') { 315 copyText(shareUrl).then(function () { 316 showShareFeedback(aipArchive.linkCopied); 317 }).catch(function () { 318 showShareFeedback(aipArchive.copyError); 319 }); 320 } 321 }); 322 return; 323 } 324 325 copyText(shareUrl).then(function () { 326 showShareFeedback(aipArchive.linkCopied); 327 }).catch(function () { 328 showShareFeedback(aipArchive.copyError); 329 }); 330 } 331 332 function closeViewerSearch(returnFocus) { 333 if (!viewerSearchPanel || !viewerSearchToggle) { 334 return; 335 } 336 337 viewerSearchPanel.hidden = true; 338 viewerSearchToggle.setAttribute('aria-expanded', 'false'); 339 if (returnFocus) {
340 viewerSearchToggle.focus(); 341 } 342 } 343 344 function openViewerSearch() { 345 if (!viewerSearchPanel || !viewerSearchToggle || !viewerSearchInput) { 346 return; 347 } 348 349 viewerSearchPanel.hidden = false; 350 viewerSearchToggle.setAttribute('aria-expanded', 'true'); 351 viewerSearchInput.focus(); 352 viewerSearchInput.select(); 353 } 354 355 function resetViewerSearch() { 356 editionSearchRequest += 1; 357 editionSearchMatches = []; 358 editionSearchIndex = -1; 359 if (viewerSearchInput) { 360 viewerSearchInput.value = ''; 361 viewerSearchInput.removeAttribute('aria-invalid'); 362 } 363 if (viewerSearchResult) { 364 viewerSearchResult.hidden = true; 365 viewerSearchResult.classList.remove('is-busy'); 366 } 367 if (viewerSearchStatus) { 368 viewerSearchStatus.textContent = ''; 369 } 370 if (viewerSearchSnippet) { 371 viewerSearchSnippet.hidden = true; 372 viewerSearchSnippet.textContent = ''; 373 } 374 closeViewerSearch(false); 375 } 376 377 function setViewerSearchMessage(message, busy) { 378 if (!viewerSearchResult || !viewerSearchStatus || !viewerSearchSnippet) { 379 return; 380 } 381 382 viewerSearchResult.hidden = false; 383 viewerSearchResult.classList.toggle('is-busy', Boolean(busy)); 384 viewerSearchResult.classList.remove('has-matches'); 385 viewerSearchStatus.textContent = message; 386 viewerSearchSnippet.hidden = true; 387 viewerSearchSnippet.textContent = ''; 388 if (viewerSearchPrevious) {
389 viewerSearchPrevious.disabled = true; 390 } 391 if (viewerSearchNext) { 392 viewerSearchNext.disabled = true; 393 } 394 } 395 396 function nativePdfUrl(pageNumber) { 397 return currentPdfUrl.split('#')[0] + '#page=' + Math.max(1, pageNumber || 1); 398 } 399 400 function goToEditionSearchResult(index) { 401 if (!editionSearchMatches.length) { 402 return; 403 } 404 405 editionSearchIndex = (index + editionSearchMatches.length) % editionSearchMatches.length; 406 var match = editionSearchMatches[editionSearchIndex]; 407 var pageNumber = Math.max(1, parseInt(match.page, 10) || 1); 408 var status = aipArchive.insideResult 409 .replace('%1$d', editionSearchIndex + 1) 410 .replace('%2$d', editionSearchMatches.length) 411 .replace('%3$d', pageNumber); 412 413 viewerSearchResult.hidden = false; 414 viewerSearchResult.classList.remove('is-busy'); 415 viewerSearchResult.classList.add('has-matches'); 416 viewerSearchStatus.textContent = status; 417 viewerSearchSnippet.textContent = match.snippet || ''; 418 viewerSearchSnippet.hidden = !match.snippet; 419 viewerSearchPrevious.disabled = editionSearchMatches.length < 2; 420 viewerSearchNext.disabled = editionSearchMatches.length < 2; 421 currentStartPage = pageNumber; 422 423 if (pageFlip && pdfDocument) { 424 var pageIndex = clamp(pageNumber - 1, 0, pdfDocument.numPages - 1); 425 renderPagesAround(pageIndex + 1, readerGeneration); 426 pageFlip.turnToPage(pageIndex); 427 } else if (nativeFrame && !nativeFrame.hidden) { 428 nativeFrame.src = nativePdfUrl(pageNumber); 429 } 430 } 431 432 function searchInsideEdition(event) { 433 if (event) { 434 event.preventDefault(); 435 } 436 if (!viewerSearchInput || !currentEdition) { 437 return; 438 } 439 440 var query = viewerSearchInput.value.trim(); 441 if (query.length < 2) {
442 viewerSearchInput.setAttribute('aria-invalid', 'true'); 443 setViewerSearchMessage(aipArchive.insideShortQuery, false); 444 return; 445 } 446 447 viewerSearchInput.removeAttribute('aria-invalid'); 448 var request = ++editionSearchRequest; 449 var data = new FormData(); 450 data.append('action', 'aip_search_inside_edition'); 451 data.append('nonce', aipArchive.nonce); 452 data.append('edition', currentEdition); 453 data.append('query', query); 454 setViewerSearchMessage(aipArchive.insideSearching, true); 455 456 fetch(aipArchive.ajaxUrl, { 457 method: 'POST', 458 credentials: 'same-origin', 459 body: data 460 }) 461 .then(function (response) { 462 if (!response.ok) { 463 throw new Error('Network response was not successful.'); 464 } 465 return response.json(); 466 }) 467 .then(function (payload) { 468 if (request !== editionSearchRequest) { 469 return; 470 } 471 if (!payload.success || !payload.data || !Array.isArray(payload.data.matches)) { 472 throw new Error('Invalid response.'); 473 } 474 475 editionSearchMatches = payload.data.matches; 476 editionSearchIndex = -1; 477 if (editionSearchMatches.length) { 478 goToEditionSearchResult(0); 479 } else if (payload.data.indexStatus === 'no_text') { 480 setViewerSearchMessage(aipArchive.insideNoText, false); 481 } else if (payload.data.indexStatus !== 'indexed') { 482 setViewerSearchMessage(aipArchive.insideNotIndexed, false); 483 } else { 484 setViewerSearchMessage(aipArchive.insideNoResults, false); 485 } 486 }) 487 .catch(function () { 488 if (request === editionSearchRequest) { 489 setViewerSearchMessage(aipArchive.insideSearchError, false); 490 } 491 }); 492 } 493 494 function clamp(value, minimum, maximum) { 495 return Math.min(maximum, Math.max(minimum, value)); 496 } 497 498 function getPanLimits() { 499 return { 500 x: Math.max(0, (bookShell.offsetWidth * zoom - bookShell.offsetWidth) / 2), 501 y: Math.max(0, (bookShell.offsetHeight * zoom - bookShell.offsetHeight) / 2) 502 }; 503 } 504 505 function applyZoom(refreshPages) { 506 var limits = getPanLimits(); 507 508 if (zoom <= 1) { 509 panX = 0; 510 panY = 0; 511 } else { 512 panX = clamp(panX, -limits.x, limits.x); 513 panY = clamp(panY, -limits.y, limits.y); 514 } 515 516 bookShell.style.transform = 'translate3d(' + panX + 'px, ' + panY + 'px, 0) scale(' + zoom + ')'; 517 stage.classList.toggle('is-zoomed', zoom > 1); 518 zoomLevel.textContent = Math.round(zoom * 100) + '%'; 519 zoomOutButton.disabled = zoom <= minimumZoom; 520 zoomInButton.disabled = zoom >= maximumZoom; 521 522 if (refreshPages && pageFlip && pdfDocument) { 523 var currentPage = pageFlip.getCurrentPageIndex() + 1; 524 if (zoom >= 3) { 525 renderPdfPage(currentPage, readerGeneration); 526 renderPdfPage(currentPage + 1, readerGeneration); 527 releaseDistantPages(currentPage); 528 } else { 529 renderPdfPage(currentPage - 1, readerGeneration); 530 renderPdfPage(currentPage, readerGeneration); 531 renderPdfPage(currentPage + 1, readerGeneration); 532 } 533 } 534 } 535 536 function setZoom(nextZoom) { 537 var previousZoom = zoom; 538 zoom = clamp(Math.round(nextZoom * 100) / 100, minimumZoom, maximumZoom); 539 applyZoom(zoom > previousZoom); 540 } 541 542 function resetZoom() { 543 zoom = 1; 544 panX = 0; 545 panY = 0; 546 isPanning = false; 547 stage.classList.remove('is-panning'); 548 applyZoom(false); 549 } 550 551 function finishPanning(event) { 552 if (!isPanning) { 553 return; 554 } 555 556 isPanning = false; 557 stage.classList.remove('is-panning'); 558 if (event && stage.hasPointerCapture && stage.hasPointerCapture(event.pointerId)) { 559 stage.releasePointerCapture(event.pointerId); 560 } 561 if (event) { 562 event.preventDefault(); 563 event.stopPropagation(); 564 } 565 } 566 567 function createBookElement() { 568 book = document.createElement('div'); 569 book.className = 'aip-book'; 570 book.setAttribute('data-aip-book', ''); 571 bookShell.appendChild(book); 572 } 573 574 function disposeFlipbook() { 575 Object.keys(renderJobs).forEach(function (pageNumber) { 576 var job = renderJobs[pageNumber]; 577 if (job && job.task && typeof job.task.cancel === 'function') { 578 job.task.cancel(); 579 } 580 }); 581 renderJobs = {}; 582 renderedPages = {}; 583 584 if (pageFlip) { 585 try { 586 pageFlip.destroy(); 587 } catch (error) { 588 // The viewer may be only partially initialized. 589 } 590 pageFlip = null; 591 } 592 593 if (!bookShell.querySelector('[data-aip-book]')) { 594 createBookElement(); 595 } else { 596 book = bookShell.querySelector('[data-aip-book]'); 597 book.innerHTML = ''; 598 book.classList.remove('is-cover-centered'); 599 book.style.removeProperty('--aip-book-offset'); 600 } 601 602 if (loadingTask) { 603 try { 604 loadingTask.destroy(); 605 } catch (error) { 606 // A completed task may already have released its worker. 607 } 608 } 609 loadingTask = null; 610 pdfDocument = null; 611 } 612 613 function resetReader() { 614 readerGeneration += 1; 615 disposeFlipbook(); 616 resetZoom(); 617 resetViewerSearch(); 618 currentPdfUrl = ''; 619 currentStartPage = 1; 620 stage.hidden = true; 621 controls.hidden = true; 622 errorPanel.hidden = true; 623 loading.hidden = false;
624 nativeFrame.hidden = true; 625 nativeFrame.src = 'about:blank'; 626 progressBar.style.width = '0%'; 627 loadProgress.textContent = ''; 628 } 629 630 function openViewer(button, updateAddress, requestedPage) { 631 var url = button.getAttribute('data-pdf'); 632 var title = button.getAttribute('data-title') || ''; 633 var edition = button.getAttribute('data-edition') || ''; 634 var editionDate = button.getAttribute('data-date') || ''; 635 var pageNumber = parseInt(requestedPage || button.getAttribute('data-page') || '1', 10); 636 if (!url) { 637 return; 638 } 639 640 resetReader(); 641 currentPdfUrl = url; 642 currentEdition = edition; 643 currentEditionTitle = title; 644 currentEditionDate = editionDate; 645 currentStartPage = Math.max(1, pageNumber || 1); 646 lastFocused = button.hidden ? null : button; 647 modalTitle.textContent = title; 648 openNew.href = url; 649 shareButton.disabled = !edition; 650 if (viewerSearchToggle) { 651 viewerSearchToggle.disabled = !edition; 652 } 653 if (embedButton) { 654 embedButton.disabled = !edition; 655 } 656 if (embedDialog) { 657 embedDialog.hidden = true; 658 } 659 if (updateAddress !== false && edition) { 660 updateEditionUrl(edition, 'pushState', currentStartPage); 661 } 662 modal.setAttribute('aria-hidden', 'false'); 663 modal.classList.add('is-open'); 664 document.body.classList.add('aip-modal-open'); 665 modal.querySelector('.aip-viewer-close').focus(); 666 startFlipbook(url, readerGeneration); 667 } 668 669 function closeViewer(updateAddress) { 670 if (isEmbedded) { 671 return; 672 } 673 if (updateAddress !== false) { 674 updateEditionUrl('', 'replaceState'); 675 } 676 modal.setAttribute('aria-hidden', 'true'); 677 modal.classList.remove('is-open'); 678 document.body.classList.remove('aip-modal-open'); 679 if (document.fullscreenElement && document.exitFullscreen) { 680 document.exitFullscreen(); 681 } 682 resetReader(); 683 currentEdition = ''; 684 currentEditionTitle = ''; 685 currentEditionDate = ''; 686 shareFeedback.textContent = ''; 687 shareFeedback.classList.remove('is-visible'); 688 if (embedDialog) { 689 embedDialog.hidden = true; 690 } 691 if (lastFocused) { 692 lastFocused.focus(); 693 } 694 } 695 696 function startFlipbook(url, generation) { 697 loadProgress.textContent = aipArchive.loadingPage + ' 1'; 698 699 loadPdfModule() 700 .then(function (pdfjs) { 701 if (generation !== readerGeneration) { 702 return null; 703 } 704 705 loadingTask = pdfjs.getDocument({ 706 url: url, 707 cMapUrl: aipArchive.cMapUrl, 708 cMapPacked: true, 709 standardFontDataUrl: aipArchive.standardFontUrl, 710 wasmUrl: aipArchive.wasmUrl, 711 iccUrl: aipArchive.iccUrl, 712 isEvalSupported: false 713 }); 714 715 loadingTask.onProgress = function (progress) { 716 if (generation !== readerGeneration || !progress.total) { 717 return; 718 } 719 var percent = Math.min(100, Math.round((progress.loaded / progress.total) * 100)); 720 progressBar.style.width = percent + '%'; 721 loadProgress.textContent = percent + '%'; 722 }; 723 724 return loadingTask.promise; 725 }) 726 .then(function (documentProxy) { 727 if (!documentProxy || generation !== readerGeneration) { 728 return null; 729 } 730 pdfDocument = documentProxy; 731 return buildFlipbook(documentProxy, generation); 732 }) 733 .catch(function () { 734 if (generation === readerGeneration) { 735 showReaderError(); 736 } 737 }); 738 } 739 740 function buildFlipbook(documentProxy, generation) { 741 return documentProxy.getPage(1).then(function (firstPage) { 742 if (generation !== readerGeneration) { 743 return; 744 } 745 746 var viewport = firstPage.getViewport({ scale: 1 }); 747 var ratio = viewport.height / viewport.width; 748 var baseWidth = 900; 749 var baseHeight = Math.round(baseWidth * ratio); 750 var initialPage = clamp(currentStartPage, 1, documentProxy.numPages); 751 var initialPages = [1, initialPage - 1, initialPage, initialPage + 1].filter(function (pageNumber, index, pages) { 752 return pageNumber >= 1 && pageNumber <= documentProxy.numPages && pages.indexOf(pageNumber) === index; 753 }); 754 755 createPdfPages(documentProxy.numPages); 756 stage.hidden = false; 757 758 return Promise.all(initialPages.map(function (pageNumber) { 759 return renderPdfPage(pageNumber, generation); 760 })).then(function () { 761 if (generation !== readerGeneration || !window.St || !window.St.PageFlip) { 762 throw new Error('Page flip library is unavailable.'); 763 } 764 765 pageFlip = new window.St.PageFlip(book, { 766 startPage: initialPage - 1,
767 width: baseWidth, 768 height: baseHeight, 769 size: 'stretch', 770 minWidth: 260, 771 maxWidth: 1100, 772 minHeight: Math.round(260 * ratio), 773 maxHeight: Math.round(1100 * ratio), 774 showCover: true, 775 usePortrait: true, 776 autoSize: true, 777 drawShadow: true, 778 maxShadowOpacity: 0.5, 779 flippingTime: 700, 780 mobileScrollSupport: false, 781 clickEventForward: true, 782 useMouseEvents: true, 783 swipeDistance: 25 784 }); 785 786 pageFlip.on('flip', function (event) { 787 var pageNumber = Number(event.data) + 1; 788 currentStartPage = pageNumber; 789 updateReaderControls(); 790 renderPagesAround(pageNumber, generation); 791 setTimeout(function () { 792 releaseDistantPages(pageNumber); 793 }, 800); 794 }); 795 796 pageFlip.on('changeOrientation', function () { 797 updateReaderControls(); 798 }); 799 800 pageFlip.on('changeState', function (event) { 801 if (event.data === 'flipping' && pageFlip.getCurrentPageIndex() === 0 && pageFlip.getOrientation() === 'landscape') { 802 book.classList.remove('is-cover-centered'); 803 book.style.setProperty('--aip-book-offset', '0px'); 804 } 805 }); 806 807 pageFlip.loadFromHTML(book.querySelectorAll('[data-aip-pdf-page]')); 808 if (currentStartPage !== initialPage) { 809 var requestedIndex = clamp(currentStartPage - 1, 0, documentProxy.numPages - 1); 810 renderPagesAround(requestedIndex + 1, generation); 811 pageFlip.turnToPage(requestedIndex); 812 } 813 pageRange.max = documentProxy.numPages; 814 loading.hidden = true; 815 controls.hidden = false; 816 updateReaderControls(); 817 window.requestAnimationFrame(updateBookAlignment); 818 renderPagesAround(initialPage, generation); 819 }); 820 }); 821 } 822 823 function createPdfPages(total) { 824 var fragment = document.createDocumentFragment(); 825 826 for (var pageNumber = 1; pageNumber <= total; pageNumber += 1) { 827 var page = document.createElement('div'); 828 var inner = document.createElement('div'); 829 var canvas = document.createElement('canvas'); 830 var placeholder = document.createElement('span'); 831 832 page.className = 'aip-pdf-page'; 833 page.setAttribute('data-aip-pdf-page', pageNumber); 834 page.setAttribute('aria-label', aipArchive.page + ' ' + pageNumber); 835 if (pageNumber === 1 || pageNumber === total) { 836 page.setAttribute('data-density', 'hard'); 837 } 838 839 inner.className = 'aip-pdf-page-inner'; 840 canvas.setAttribute('aria-hidden', 'true'); 841 placeholder.className = 'aip-pdf-page-placeholder'; 842 placeholder.textContent = aipArchive.loadingPage + ' ' + pageNumber + 'â¦'; 843 inner.appendChild(canvas); 844 inner.appendChild(placeholder); 845 page.appendChild(inner); 846 fragment.appendChild(page); 847 } 848 849 book.appendChild(fragment); 850 } 851 852 function renderPdfPage(pageNumber, generation) { 853 if (!pdfDocument || pageNumber < 1 || pageNumber > pdfDocument.numPages || generation !== readerGeneration) { 854 return Promise.resolve(); 855 } 856 857 var desiredZoom = Math.max(1, zoom); 858 if (renderedPages[pageNumber] && renderedPages[pageNumber] >= desiredZoom) { 859 return Promise.resolve(); 860 } 861 if (renderJobs[pageNumber]) { 862 return renderJobs[pageNumber].promise.then(function () { 863 return renderPdfPage(pageNumber, generation); 864 }); 865 } 866 867 var pageElement = book.querySelector('[data-aip-pdf-page="' + pageNumber + '"]'); 868 if (!pageElement) { 869 return Promise.resolve(); 870 } 871 872 var nextCanvas = document.createElement('canvas'); 873 var context = nextCanvas.getContext('2d', { alpha: false }); 874 var job = { task: null, promise: null, zoom: desiredZoom }; 875 nextCanvas.setAttribute('aria-hidden', 'true'); 876 877 job.promise = pdfDocument.getPage(pageNumber) 878 .then(function (pdfPage) { 879 if (generation !== readerGeneration) { 880 return false; 881 } 882 883 var naturalViewport = pdfPage.getViewport({ scale: 1 }); 884 var deviceScale = Math.min(window.devicePixelRatio || 1, 1.75); 885 var availableWidth = window.innerWidth < 760 ? window.innerWidth - 32 : (window.innerWidth - 190) / 2; 886 var targetWidth = Math.min(2600, Math.max(560, availableWidth * deviceScale * desiredZoom));
887 var scale = targetWidth / naturalViewport.width; 888 var viewport = pdfPage.getViewport({ scale: scale }); 889 890 nextCanvas.width = Math.floor(viewport.width); 891 nextCanvas.height = Math.floor(viewport.height); 892 job.task = pdfPage.render({ canvasContext: context, viewport: viewport }); 893 return job.task.promise.then(function () { return true; }); 894 }) 895 .then(function (wasRendered) { 896 if (wasRendered && generation === readerGeneration) { 897 var previousCanvas = pageElement.querySelector('canvas'); 898 if (previousCanvas) { 899 previousCanvas.replaceWith(nextCanvas); 900 } 901 renderedPages[pageNumber] = desiredZoom; 902 pageElement.classList.add('is-rendered'); 903 pageElement.classList.remove('has-render-error'); 904 } 905 }) 906 .catch(function (error) { 907 if (!error || error.name !== 'RenderingCancelledException') { 908 pageElement.classList.add('has-render-error'); 909 } 910 }) 911 .finally(function () { 912 if (renderJobs[pageNumber] === job) { 913 delete renderJobs[pageNumber]; 914 } 915 }); 916 917 renderJobs[pageNumber] = job; 918 return job.promise; 919 } 920 921 function renderPagesAround(pageNumber, generation) { 922 var firstOffset = zoom >= 3 ? 0 : (zoom > 1 ? -1 : -2); 923 var lastOffset = zoom >= 3 ? 1 : (zoom > 1 ? 2 : 4); 924 for (var offset = firstOffset; offset <= lastOffset; offset += 1) { 925 renderPdfPage(pageNumber + offset, generation); 926 } 927 } 928 929 function releaseDistantPages(pageNumber) { 930 var retainedDistance = zoom >= 3 ? 4 : 7; 931 Object.keys(renderedPages).forEach(function (key) { 932 var number = Number(key); 933 if (number === 1 || Math.abs(number - pageNumber) <= retainedDistance) { 934 return; 935 } 936 937 var pageElement = book.querySelector('[data-aip-pdf-page="' + number + '"]'); 938 var canvas = pageElement ? pageElement.querySelector('canvas') : null; 939 if (canvas) { 940 canvas.width = 1; 941 canvas.height = 1; 942 pageElement.classList.remove('is-rendered'); 943 } 944 delete renderedPages[number]; 945 }); 946 } 947 948 function updateBookAlignment() { 949 if (!pageFlip || !book) { 950 return; 951 } 952 953 var shouldCenterCover = pageFlip.getOrientation() === 'landscape' && pageFlip.getCurrentPageIndex() === 0; 954 var cover = shouldCenterCover ? book.querySelector('[data-aip-pdf-page="1"]') : null; 955 var coverWidth = cover ? cover.getBoundingClientRect().width / Math.max(zoom, 0.01) : 0; 956 var offset = Math.round(coverWidth / 2); 957 958 book.classList.toggle('is-cover-centered', shouldCenterCover); 959 book.style.setProperty('--aip-book-offset', shouldCenterCover ? '-' + offset + 'px' : '0px'); 960 } 961 962 function updateReaderControls() { 963 if (!pageFlip || !pdfDocument) { 964 return; 965 } 966 967 var index = pageFlip.getCurrentPageIndex(); 968 var current = index + 1; 969 var orientation = pageFlip.getOrientation(); 970 var end = orientation === 'landscape' && current > 1 ? Math.min(current + 1, pdfDocument.numPages) : current; 971 972 if (end > current) { 973 pageStatus.textContent = aipArchive.pages + ' ' + current + 'â' + end + ' ' + aipArchive.of + ' ' + pdfDocument.numPages; 974 } else { 975 pageStatus.textContent = aipArchive.page + ' ' + current + ' ' + aipArchive.of + ' ' + pdfDocument.numPages; 976 } 977 978 pageRange.value = current; 979 previousButtons.forEach(function (button) { 980 button.disabled = index <= 0; 981 }); 982 nextButtons.forEach(function (button) { 983 button.disabled = index >= pdfDocument.numPages - 1; 984 }); 985 updateBookAlignment(); 986 } 987 988 function showReaderError() { 989 disposeFlipbook(); 990 loading.hidden = true; 991 stage.hidden = true; 992 controls.hidden = true; 993 errorMessage.textContent = aipArchive.readerError; 994 errorPanel.hidden = false; 995 } 996 997 function showNativeViewer() { 998 readerGeneration += 1; 999 disposeFlipbook(); 1000 loading.hidden = true; 1001 stage.hidden = true; 1002 controls.hidden = true; 1003 errorPanel.hidden = true; 1004 nativeFrame.hidden = false; 1005 nativeFrame.src = nativePdfUrl(currentStartPage); 1006 } 1007 1008 function flipPrevious() { 1009 if (pageFlip) { 1010 pageFlip.flipPrev(); 1011 } 1012 } 1013 1014 function flipNext() { 1015 if (pageFlip) { 1016 pageFlip.flipNext(); 1017 } 1018 } 1019 1020 form.addEventListener('submit', function (event) { 1021 event.preventDefault(); 1022 search(1); 1023 }); 1024 1025 if (dateArchive) { 1026 dateArchive.addEventListener('click', function (event) { 1027 var yearToggleButton = event.target.closest('[data-aip-year-toggle]'); 1028 var filterButton = event.target.closest('[data-aip-date-filter]'); 1029 1030 if (yearToggleButton) { 1031 toggleYear(yearToggleButton); 1032 return; 1033 } 1034 1035 if (filterButton) { 1036 setDateFilter(filterButton.getAttribute('data-year'), filterButton.getAttribute('data-month'), filterButton); 1037 } 1038 }); 1039 1040 if (dateToggle && datePanel) { 1041 dateToggle.addEventListener('click', function () { 1042 var willOpen = dateToggle.getAttribute('aria-expanded') !== 'true'; 1043 dateToggle.setAttribute('aria-expanded', willOpen ? 'true' : 'false'); 1044 datePanel.hidden = !willOpen; 1045 }); 1046 1047 if (window.matchMedia('(max-width: 760px)').matches) { 1048 dateToggle.setAttribute('aria-expanded', 'false'); 1049 datePanel.hidden = true; 1050 } 1051 } 1052 } 1053 1054 results.addEventListener('click', function (event) { 1055 var pageButton = event.target.closest('[data-aip-page]'); 1056 var openButton = event.target.closest('[data-aip-open]'); 1057 if (pageButton && !pageButton.disabled) { 1058 search(parseInt(pageButton.getAttribute('data-aip-page'), 10));
1059 archive.scrollIntoView({ behavior: 'smooth', block: 'start' }); 1060 } 1061 if (openButton) { 1062 openViewer(openButton, true); 1063 } 1064 }); 1065 1066 modal.addEventListener('click', function (event) { 1067 if (event.target.closest('[data-aip-embed-close]')) { 1068 closeEmbedDialog(); 1069 return; 1070 } 1071 if (event.target.closest('[data-aip-close]')) { 1072 closeViewer(true); 1073 } 1074 }); 1075 1076 shareButton.addEventListener('click', shareEdition); 1077 if (viewerSearchToggle) { 1078 viewerSearchToggle.addEventListener('click', function () { 1079 if (viewerSearchPanel.hidden) { 1080 openViewerSearch(); 1081 } else { 1082 closeViewerSearch(true); 1083 } 1084 }); 1085 } 1086 if (viewerSearchForm) { 1087 viewerSearchForm.addEventListener('submit', searchInsideEdition); 1088 } 1089 if (viewerSearchPanel) { 1090 viewerSearchPanel.addEventListener('click', function (event) { 1091 if (event.target.closest('[data-aip-viewer-search-close]')) { 1092 closeViewerSearch(true); 1093 } 1094 }); 1095 } 1096 if (viewerSearchPrevious) { 1097 viewerSearchPrevious.addEventListener('click', function () { 1098 goToEditionSearchResult(editionSearchIndex - 1); 1099 }); 1100 } 1101 if (viewerSearchNext) { 1102 viewerSearchNext.addEventListener('click', function () { 1103 goToEditionSearchResult(editionSearchIndex + 1); 1104 }); 1105 } 1106 if (embedButton) { 1107 embedButton.addEventListener('click', openEmbedDialog); 1108 } 1109 if (embedCopyButton) { 1110 embedCopyButton.addEventListener('click', copyEmbedCode); 1111 } 1112 1113 zoomOutButton.addEventListener('click', function () { 1114 setZoom(zoom - zoomStep); 1115 }); 1116 1117 zoomInButton.addEventListener('click', function () { 1118 setZoom(zoom + zoomStep); 1119 }); 1120 1121 stage.addEventListener('pointerdown', function (event) { 1122 if (zoom <= 1 || (typeof event.button === 'number' && event.button !== 0) || event.target.closest('button, input, a')) { 1123 return; 1124 } 1125 1126 isPanning = true; 1127 panStartX = event.clientX; 1128 panStartY = event.clientY; 1129 panOriginX = panX; 1130 panOriginY = panY; 1131 stage.classList.add('is-panning'); 1132 if (stage.setPointerCapture) { 1133 stage.setPointerCapture(event.pointerId); 1134 } 1135 event.preventDefault(); 1136 event.stopPropagation(); 1137 }, true); 1138 1139 stage.addEventListener('pointermove', function (event) { 1140 if (!isPanning) { 1141 return; 1142 } 1143 1144 panX = panOriginX + event.clientX - panStartX; 1145 panY = panOriginY + event.clientY - panStartY; 1146 applyZoom(false); 1147 event.preventDefault(); 1148 event.stopPropagation(); 1149 }, true); 1150 1151 stage.addEventListener('pointerup', finishPanning, true); 1152 stage.addEventListener('pointercancel', finishPanning, true); 1153 1154 previousButtons.forEach(function (button) { 1155 button.addEventListener('click', flipPrevious); 1156 }); 1157 1158 nextButtons.forEach(function (button) { 1159 button.addEventListener('click', flipNext); 1160 }); 1161 1162 pageRange.addEventListener('change', function () { 1163 if (pageFlip) { 1164 var pageIndex = Math.max(0, parseInt(pageRange.value, 10) - 1); 1165 renderPagesAround(pageIndex + 1, readerGeneration); 1166 pageFlip.flip(pageIndex); 1167 } 1168 }); 1169 1170 nativeButton.addEventListener('click', showNativeViewer); 1171 1172 fullscreenButton.addEventListener('click', function () { 1173 if (!document.fullscreenElement && viewerWindow.requestFullscreen) { 1174 viewerWindow.requestFullscreen(); 1175 } else if (document.fullscreenElement && document.exitFullscreen) { 1176 document.exitFullscreen(); 1177 } 1178 }); 1179 1180 document.addEventListener('fullscreenchange', function () { 1181 if (pageFlip) { 1182 setTimeout(function () { 1183 pageFlip.update(); 1184 updateBookAlignment(); 1185 }, 100); 1186 } 1187 }); 1188 1189 window.addEventListener('resize', function () { 1190 if (zoom !== 1) { 1191 applyZoom(false); 1192 } 1193 if (pageFlip) { 1194 window.setTimeout(updateBookAlignment, 80); 1195 } 1196 }); 1197 1198 document.addEventListener('keydown', function (event) { 1199 if (!modal.classList.contains('is-open')) { 1200 return; 1201 } 1202 1203 if (event.key === 'Escape') { 1204 if (embedDialog && !embedDialog.hidden) { 1205 closeEmbedDialog(); 1206 } else if (viewerSearchPanel && !viewerSearchPanel.hidden) { 1207 closeViewerSearch(true); 1208 } else { 1209 closeViewer(true); 1210 } 1211 } else if (event.key === 'ArrowLeft' && !event.target.closest('input, textarea')) { 1212 event.preventDefault(); 1213 flipPrevious(); 1214 } else if (event.key === 'ArrowRight' && !event.target.closest('input, textarea')) { 1215 event.preventDefault(); 1216 flipNext(); 1217 } else if (event.key === 'Tab') { 1218 trapFocus(event, modal); 1219 } 1220 }); 1221 1222 window.addEventListener('popstate', function () { 1223 var currentUrl = new URL(window.location.href); 1224 var requestedEdition = currentUrl.searchParams.get('edicion') || ''; 1225 var requestedPage = Math.max(1, parseInt(currentUrl.searchParams.get('pagina') || '1', 10) || 1); 1226 1227 if (!requestedEdition && modal.classList.contains('is-open')) { 1228 closeViewer(false); 1229 return; 1230 } 1231 1232 if (requestedEdition && requestedEdition === currentEdition && pageFlip) { 1233 currentStartPage = requestedPage; 1234 pageFlip.turnToPage(Math.min(pdfDocument.numPages - 1, requestedPage - 1)); 1235 return; 1236 } 1237 1238 if (requestedEdition && requestedEdition !== currentEdition) { 1239 var matchingButton = Array.prototype.find.call( 1240 archive.querySelectorAll('[data-aip-open][data-edition]'), 1241 function (button) { 1242 return button.getAttribute('data-edition') === requestedEdition; 1243 } 1244 ); 1245 1246 if (matchingButton) { 1247 openViewer(matchingButton, false, requestedPage); 1248 } 1249 } 1250 }); 1251 1252 var autoOpenButton = archive.querySelector('[data-aip-auto-open]'); 1253 if (autoOpenButton) { 1254 window.setTimeout(function () { 1255 openViewer(autoOpenButton, false); 1256 }, 80); 1257 } 1258 } 1259 1260 function trapFocus(event, container) { 1261 var items = Array.prototype.filter.call( 1262 container.querySelectorAll('a[href], button:not([disabled]), iframe, input, [tabindex]:not
1262([tabindex="-1"])'), 1263 function (item) { 1264 return !item.hidden && item.offsetParent !== null; 1265 } 1266 ); 1267 if (!items.length) { 1268 return; 1269 } 1270 var first = items[0]; 1271 var last = items[items.length - 1]; 1272 if (event.shiftKey && document.activeElement === first) { 1273 event.preventDefault(); 1274 last.focus(); 1275 } else if (!event.shiftKey && document.activeElement === last) { 1276 event.preventDefault(); 1277 first.focus(); 1278 } 1279 } 1280 1281 function escapeHtml(value) { 1282 var node = document.createElement('div'); 1283 node.textContent = value || ''; 1284 return node.innerHTML; 1285 } 1286 1287 function boot() { 1288 document.querySelectorAll('[data-aip-archive]').forEach(initializeArchive); 1289 } 1290 1291 if (document.readyState === 'loading') { 1292 document.addEventListener('DOMContentLoaded', boot); 1293 } else { 1294 boot(); 1295 } 1296})();
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.