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;