File indexing completed on 2025-05-04 05:31:15

0001 import React, { useState } from 'react';
0002 import {isMobile} from 'react-device-detect';
0003 
0004 function BookReaderWrapper(props){
0005 
0006   const [ loading, setLoading ] = useState(true);
0007   const [ renditionState , setRenditionState ] = useState();
0008   const [ currentPage, setCurrentPage ] = useState();
0009   const [ totalPages, setTotalPages ] = useState();
0010   const [ showBookMenu, setShowBookMenu ] = useState(false);
0011   const [ showPrevButton, setShowPrevButton ] = useState(false);
0012   const [ showNextButton, setShowNextButton ] = useState(false);
0013   const [ viewedPagesCount, setViewedPagesCount ] = useState(0);
0014   const [ bookReadIsReported, setBookReadIsReported ] = useState(false);
0015 
0016   React.useEffect(() => {initBookReader()},[])
0017   
0018   React.useEffect(() => { 
0019     if (window.book) window.book.destroy()
0020     initBookReader()
0021   },[props.cinemaMode,props.width])
0022 
0023   React.useEffect(() => {
0024     if (totalPages === 0){
0025         hackBookPageCount();
0026     }
0027   },[totalPages,window.book])
0028 
0029   React.useEffect(() => {
0030     if (viewedPagesCount > 3 && bookReadIsReported === false){
0031       reportBookRead();
0032     }
0033   },[viewedPagesCount])
0034 
0035   function hackBookPageCount(){
0036     const newTotalPageCount = window.book.locations.total;
0037     if (newTotalPageCount === 0){
0038       setTimeout(() => {
0039         hackBookPageCount();
0040       }, 200);
0041     } else {
0042       setTotalPages(newTotalPageCount)
0043     }
0044   }
0045 
0046   function initBookReader(){
0047     // Initialize the book
0048     window.book = ePub(props.slide.url, {});
0049     window.rendition = book.renderTo('viewer', {
0050         flow: 'paginated',
0051         manager: 'default',
0052         spread: 'always',
0053         width: (props.width - 20),
0054         height: (props.height - 35)
0055     });
0056 
0057     setRenditionState(rendition)
0058 
0059     // Display the book
0060     window.displayed = window.rendition.display(window.location.hash.substr(1) || undefined);
0061     displayed.then(function() {
0062         // console.log('rendition.currentLocation():', rendition.currentLocation());
0063     });
0064 
0065     // Generate location and pagination
0066     window.book.ready.then(function() {
0067         const stored = localStorage.getItem(book.key() + '-locations');
0068         // console.log('metadata:', book.package.metadata);
0069         if (stored) {
0070             return window.book.locations.load(stored);
0071         } else {
0072             return window.book.locations.generate(1024); // Generates CFI for every X characters (Characters per/page)
0073         }
0074 
0075     }).then(function(location) { // This promise will take a little while to return (About 20 seconds or so for Moby Dick)
0076         localStorage.setItem(book.key() + '-locations', book.locations.save());
0077     });
0078 
0079     // When navigating to the next/previous page
0080     window.rendition.on('relocated', function(locations) {
0081 
0082         setCurrentPage(book.locations.locationFromCfi(locations.start.cfi));
0083         setTotalPages(book.locations.total)
0084         
0085         if (loading === true) setLoading(false);
0086 
0087         if (rendition.currentLocation().atStart === true) setShowPrevButton(false)
0088         else setShowPrevButton(true)
0089 
0090         if (rendition.currentLocation().atEnd === true) setShowNextButton(false)
0091         else setShowNextButton(true)
0092     })
0093   }
0094 
0095   function goPrev(){
0096     renditionState.prev();
0097   }
0098 
0099   function goNext(){
0100     const newViewedPagesCountValue = viewedPagesCount + 1;
0101     setViewedPagesCount(newViewedPagesCountValue);
0102     renditionState.next();
0103   }
0104 
0105   function onStartClick(){
0106     const lastPageCfi = renditionState.book.locations._locations[0];
0107     renditionState.display(lastPageCfi);
0108   }
0109 
0110   function onEndClick(){
0111     const lastPageCfi = renditionState.book.locations._locations[renditionState.book.locations._locations.length - 1];
0112     renditionState.display(lastPageCfi);
0113   } 
0114   
0115   function onPageNumberInput(val){
0116     const cfiFromNumber = renditionState.book.locations._locations[val];
0117     renditionState.display(cfiFromNumber);
0118   }
0119 
0120   function toggleMenu(){
0121     const newShowBookMenu = showBookMenu === true ? false : true;
0122     setShowBookMenu(newShowBookMenu)
0123   }
0124 
0125   function goToTocItem(item){
0126     renditionState.display(item.href);
0127     toggleMenu();
0128   }
0129 
0130   function reportBookRead(){
0131     console.log('report book reading')
0132     console.log(props);
0133     const bookReadReportUrl = "https://" + window.location.hostname + "/p/" + props.product.project_id + '/startmediaviewajax?collection_id='+props.slide.collection_id+'&file_id='+props.slide.file_id+'&type_id=3';
0134     $.ajax({url: bookReadReportUrl}).done(function(res) { 
0135       console.log(res);
0136       setBookReadIsReported(true);
0137     });
0138   }
0139 
0140   let loadingDisplay = <div id="ajax-loader"></div>
0141   let bookNavigation;
0142   if (loading === false){
0143     loadingDisplay = "";
0144     let prevButtonDisplay;
0145     if (showPrevButton === true){
0146       prevButtonDisplay = (
0147         <span><a onClick={() => goPrev()}>{"< previous"}</a></span>
0148       )
0149     }
0150     let nextButtonDisplay;
0151     if (showNextButton === true && totalPages !== 0){
0152       nextButtonDisplay = (
0153         <span><a id="next-page-button" onClick={() => goNext()}>{"next >"}</a></span>
0154       )
0155     }
0156     let bookNavigationMidDisplay;
0157     if (totalPages !== 0){
0158       bookNavigationMidDisplay = (
0159         <span>
0160           <input type="number" className="form-control" placeholder={currentPage} min="0" max={totalPages} onChange={(e) => onPageNumberInput(e.target.value)}/>
0161           {" / " + totalPages}
0162         </span>
0163       )
0164     }
0165     bookNavigation = (
0166       <div id="book-pager">
0167         <div>
0168           {prevButtonDisplay}
0169           {bookNavigationMidDisplay}
0170           {nextButtonDisplay}
0171         </div>
0172       </div>
0173     )
0174   }
0175 
0176   let bookMenuDisplay, tocMenuToggleDisplay;
0177   if (renditionState){
0178     if (renditionState.book.navigation){
0179       tocMenuToggleDisplay = (
0180         <div id="toc-menu-toggle" onClick={toggleMenu}>
0181           <span className="glyphicon glyphicon-menu-hamburger"></span>
0182         </div>
0183       )
0184     }    
0185     if (showBookMenu === true){
0186       const items = renditionState.book.navigation.toc.map((item,index) => (
0187         <BookMenuItem key={index} goToTocItem={goToTocItem} item={item}/>
0188       ));
0189       bookMenuDisplay = <ul id="book-menu">{items}</ul>
0190     }
0191   }
0192 
0193   let bookReaderWrapperCssClass = isMobile === true ? "is-mobile" : "is-desktop";
0194 
0195   return (
0196     <div id="book-reader-wrapper" className={bookReaderWrapperCssClass}>
0197       {loadingDisplay}
0198       {tocMenuToggleDisplay}
0199       <div id="viewer" className="spreads">
0200       </div>
0201       {bookNavigation}
0202       {bookMenuDisplay}
0203     </div>
0204   )
0205 }
0206 
0207 function BookMenuItem(props){
0208 
0209   function onGoToTocItem(){
0210     props.goToTocItem(props.item);
0211   }
0212 
0213   let subItemsDisplay;
0214   if (props.item.subitems && props.item.subitems.length > 0){
0215     const items = props.item.subitems.map((subitem,index) => (
0216       <BookMenuItem goToTocItem={props.goToTocItem} key={index} item={subitem}/>
0217     ));
0218     subItemsDisplay = <ul> {items} </ul>
0219   }
0220 
0221   return (
0222     <li>
0223       <a onClick={() => onGoToTocItem()}>{props.item.label}</a>
0224       {subItemsDisplay}
0225     </li>
0226   )
0227 }
0228 
0229 export default BookReaderWrapper;