discovery-media-player 0.1.122 → 0.1.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discovery-media-player",
3
- "version": "0.1.122",
3
+ "version": "0.1.123",
4
4
  "description": "Self-hosted document viewer: per-recipient tracked links, reading analytics, live presentation. The core knows nothing about the application hosting it — everything it borrows arrives through an injected context.",
5
5
  "keywords": [
6
6
  "pdf-viewer",
@@ -309,8 +309,23 @@ ${LEGAL_CSS}
309
309
  get onePage(){return onePage;},
310
310
  get soloOffered(){return soloOffered;},set soloOffered(v){soloOffered=!!v;}};
311
311
  var pdfDoc=null, zoom=1, firstAspect=1.35, rendered={}, io=null, ioCur=null;
312
+ // ATTENTION : LE LECTEUR GARDAIT TOUTES LES PAGES RENDUES (P1 audit externe).
313
+ //
314
+ // rendered[n] n etait jamais evince, les canvas restaient dans le DOM, et un build() de refit
315
+ // n annulait pas les taches deja lancees. Sur un ecran haute densite un seul canvas pese
316
+ // plusieurs dizaines de mega-octets : un document long parcouru en entier faisait exploser la
317
+ // memoire de l onglet. rendered[n] etait aussi pose AVANT le succes — un echec laissait donc la
318
+ // page definitivement consideree comme rendue, sans nouvelle tentative possible.
319
+ //
320
+ // Note de forme : ce script vit dans un litteral de gabarit — pas d accent grave ici.
321
+ var renderGen=0; // invalide les callbacks d un build() precedent
322
+ var taches={}; // n -> RenderTask, pour pouvoir ANNULER
323
+ var enCours={}; // n -> 1 tant que la page n a pas abouti
324
+ var MARGE_PAGES=2; // on garde la page courante et deux de chaque cote
325
+ var DPR_MAX=2; // au-dela, le gain visuel est nul et le cout quadratique
326
+ var PIXELS_MAX=4e6; // plafond par canvas : ~4 M pixels = ~16 Mo de tampon
312
327
  var onePage=false, soloOffered=false; // mode « une seule page » (présentation guidée) + offre de découverte solo
313
- function setCur(p){ if(!p||p===cur)return; cur=p; T.setPage(p); try{ if(window.__soloEnd)window.__soloEnd(p); }catch(e){} var pg=document.getElementById('pg'); if(pg&&numPages)pg.textContent='Page '+p+' / '+numPages; if(PRES) pushPage(); }
328
+ function setCur(p){ if(!p||p===cur)return; cur=p; try{ evincerLoin(p); }catch(e){} T.setPage(p); try{ if(window.__soloEnd)window.__soloEnd(p); }catch(e){} var pg=document.getElementById('pg'); if(pg&&numPages)pg.textContent='Page '+p+' / '+numPages; if(PRES) pushPage(); }
314
329
  // Bouton « Partager » : re-partage tracé (forward) → crée un lien ENFANT et propose de l'envoyer par email.
315
330
  function wireShare(){
316
331
  var pop=document.getElementById('pop'), btn=document.getElementById('shareBtn'), err=document.getElementById('shErr');
@@ -690,7 +705,12 @@ ${LEGAL_CSS}
690
705
  }).catch(function(){ loadError("Impossible d'afficher ce document."); });
691
706
  }
692
707
  function build(){
693
- rendered={};
708
+ // Une nouvelle construction invalide tout ce qui etait en vol : sans cela, les rendus lances
709
+ // par la precedente peignent dans des elements DETACHES (pagesEl a ete vide) et le travail est
710
+ // fait deux fois. C est le meme mecanisme de generation que la page audience.
711
+ renderGen++;
712
+ annulerTout();
713
+ rendered={}; enCours={};
694
714
  if(io) io.disconnect();
695
715
  if(ioCur) ioCur.disconnect();
696
716
  // PRÉ-RENDU : marge de 500px → on rend les pages un peu avant qu'elles arrivent (fluide).
@@ -727,27 +747,78 @@ ${LEGAL_CSS}
727
747
  var top=avg(2,3), bot=avg(Math.max(0,h-5),3);
728
748
  scrollEl.style.background='linear-gradient(180deg,'+top+' 0%,'+top+' 42%,'+bot+' 58%,'+bot+' 100%)';
729
749
  }catch(e){ /* canvas indisponible → fond par défaut */ } }
730
- function renderPage(n,el){ if(rendered[n])return; rendered[n]=1;
750
+ function annulerTout(){
751
+ for(var k in taches){ try{ taches[k].cancel(); }catch(e){} }
752
+ taches={};
753
+ }
754
+ // Rend une page a l etat de reserve : on retire le canvas et la couche texte, on remet la boite
755
+ // avec sa hauteur estimee. Le defilement ne bouge pas, et la page se re-rendra si on y revient.
756
+ function libererPage(n){
757
+ var el=pagesEl.querySelector('.page[data-p="'+n+'"]'); if(!el)return;
758
+ if(taches[n]){ try{ taches[n].cancel(); }catch(e){} delete taches[n]; }
759
+ var w=Math.round(targetWidth());
760
+ el.innerHTML=''; el.className='page ph'; el.textContent='Page '+n;
761
+ el.style.width=w+'px'; el.style.height=Math.round(w*firstAspect)+'px';
762
+ delete rendered[n]; delete enCours[n];
763
+ }
764
+ // ATTENTION : ON BORNE PAR UN BUDGET DE PIXELS, PAS SEULEMENT PAR UN NOMBRE DE PAGES.
765
+ // Deux pages A4 sur un ecran ×3 pesent plus que dix vignettes : compter les pages laisserait
766
+ // passer le cas qui fait tomber l onglet. On garde donc la fenetre courante, et on evince
767
+ // au-dela — le nombre de canvas reste borne quel que soit le parcours du document.
768
+ function evincerLoin(centre){
769
+ if(onePage) return; // une seule page affichee : rien a evincer
770
+ for(var k in rendered){
771
+ var n=+k;
772
+ if(n<centre-MARGE_PAGES || n>centre+MARGE_PAGES) libererPage(n);
773
+ }
774
+ }
775
+ function renderPage(n,el){
776
+ if(rendered[n]||enCours[n])return;
777
+ // ATTENTION : ON NE MARQUE PAS « RENDUE » AVANT DE L AVOIR FAIT. rendered[n]=1 etait pose ici,
778
+ // donc un echec de getPage ou de render laissait la page marquee pour toujours : elle ne se
779
+ // retentait jamais et restait vide. On distingue « en cours » de « aboutie ».
780
+ enCours[n]=1;
781
+ var gen=renderGen;
731
782
  if(IS_IMG){
732
783
  var w=Math.round(targetWidth());
733
784
  var im=document.createElement('img');
734
785
  im.src=imgSrc; im.alt=''; im.style.width=w+'px'; im.style.display='block';
735
786
  el.style.height=''; el.classList.remove('ph'); el.textContent=''; el.style.width=w+'px';
736
787
  el.appendChild(im);
737
- im.onload=function(){ hideLoader(); };
738
- if(im.complete) hideLoader();
788
+ im.onload=function(){ if(gen!==renderGen)return; delete enCours[n]; rendered[n]=1; hideLoader(); };
789
+ im.onerror=function(){ delete enCours[n]; }; // reessayable
790
+ if(im.complete){ delete enCours[n]; rendered[n]=1; hideLoader(); }
739
791
  return;
740
792
  }
741
793
  pdfDoc.getPage(n).then(function(page){
742
- var dpr=window.devicePixelRatio||1;
794
+ if(gen!==renderGen){ delete enCours[n]; return; } // un build() est passe : ce rendu n est plus attendu
795
+ // ATTENTION : LE DPR N ETAIT PAS PLAFONNE. Sur un ecran ×3, une page de 900 px de large fait
796
+ // pres de 10 M pixels, soit environ 39 Mo de tampon pour UNE page — le gain visuel au-dela de
797
+ // ×2 est nul, le cout est quadratique. On plafonne le DPR, puis on plafonne le NOMBRE DE
798
+ // PIXELS du canvas : deux bornes, parce que le zoom peut faire grandir la page independamment
799
+ // de la densite de l ecran.
800
+ var dpr=Math.min(DPR_MAX, window.devicePixelRatio||1);
743
801
  var scale=Math.min(5,targetWidth()/page.getViewport({scale:1}).width);
744
802
  var v=page.getViewport({scale:scale});
803
+ var pixels=Math.floor(v.width*dpr)*Math.floor(v.height*dpr);
804
+ if(pixels>PIXELS_MAX) dpr=Math.max(1, dpr*Math.sqrt(PIXELS_MAX/pixels));
745
805
  var c=document.createElement('canvas');
746
806
  c.setAttribute('role','img'); c.setAttribute('aria-label','Page '+n);
747
807
  c.width=Math.floor(v.width*dpr); c.height=Math.floor(v.height*dpr); // backing store HD → net comme du natif
748
808
  c.style.width=v.width+'px'; c.style.height=v.height+'px';
749
809
  el.style.height=''; el.classList.remove('ph'); el.textContent=''; el.style.width=v.width+'px'; el.appendChild(c); // classList.remove (PAS className=) : ne pas écraser .cur — en mode une-page la page disparaissait une fois rendue (refit après réduction/réouverture du chat)
750
- page.render({canvasContext:c.getContext('2d'),viewport:v,transform:dpr!==1?[dpr,0,0,dpr,0,0]:null}).promise.then(function(){ hideLoader(); if(n===cur)setTimeout(vsplitTint,60); });
810
+ var tache=page.render({canvasContext:c.getContext('2d'),viewport:v,transform:dpr!==1?[dpr,0,0,dpr,0,0]:null});
811
+ taches[n]=tache;
812
+ tache.promise.then(function(){
813
+ if(taches[n]===tache) delete taches[n];
814
+ if(gen!==renderGen){ delete enCours[n]; return; }
815
+ delete enCours[n]; rendered[n]=1; // AVEREE, pas seulement demandee
816
+ hideLoader(); if(n===cur)setTimeout(vsplitTint,60);
817
+ },function(){
818
+ // Annule ou en echec : on retire la marque pour que la page puisse etre retentee.
819
+ if(taches[n]===tache) delete taches[n];
820
+ delete enCours[n];
821
+ });
751
822
  // Couche texte (sélection). En pdf.js v3, les spans utilisent font-size:calc(var(--scale-factor)*Npx)
752
823
  // → SANS --scale-factor, taille nulle = pas de sélection. On le pose sur le conteneur.
753
824
  try{ page.getTextContent().then(function(tc){
@@ -758,7 +829,7 @@ ${LEGAL_CSS}
758
829
  catch(e){ try{ pdfjsLib.renderTextLayer({textContentSource:tc,container:tl,viewport:v}); }
759
830
  catch(e2){ try{ pdfjsLib.renderTextLayer({textContent:tc,container:tl,viewport:v}); }catch(e3){} } }
760
831
  }); }catch(e){}
761
- }); }
832
+ },function(){ delete enCours[n]; }); }
762
833
  // ── Assistant IA « présentateur » : chat requête/réponse (bot-start/bot-say) + saut de page piloté ──
763
834
  ${botOn && botBrowser ? botBrowser.botViewerJs(ICONS) : ""}
764
835
  })();