mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-02 14:49:16 +02:00
Merge d215eed12d
into f09089cf77
This commit is contained in:
commit
184520769d
14 changed files with 1024 additions and 21196 deletions
325
espark_reader/reader.css
Normal file
325
espark_reader/reader.css
Normal file
|
@ -0,0 +1,325 @@
|
|||
body {
|
||||
margin: 0;
|
||||
background: #fafafa;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #333;
|
||||
|
||||
/*position: absolute;*/
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
/*min-height: 800px;*/
|
||||
}
|
||||
|
||||
#title {
|
||||
width: 900px;
|
||||
min-height: 18px;
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #E2E2E2;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#title:hover {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
#viewer {
|
||||
width: 900px;
|
||||
height: 600px;
|
||||
box-shadow: 0 0 4px #ccc;
|
||||
padding: 10px 10px 0px 10px;
|
||||
margin: 5px auto;
|
||||
background: white;
|
||||
}
|
||||
|
||||
#viewer.spreads {
|
||||
width: 900px;
|
||||
height: 600px;
|
||||
box-shadow: 0 0 4px #ccc;
|
||||
border-radius: 5px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
margin: 10px auto;
|
||||
background: white;
|
||||
top: calc(50vh - 400px);
|
||||
}
|
||||
|
||||
/* Smartphone - Portrait */
|
||||
@media only screen and (min-width: 320px) and (max-width: 667px) and (orientation: portrait) {
|
||||
#viewer {
|
||||
width: 320px;
|
||||
height: 667px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Smartphone - Landscape */
|
||||
@media only screen and (min-width: 320px) and (max-width: 667px) and (orientation: landscape) {
|
||||
#viewer {
|
||||
width: 667px;
|
||||
height: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tablet - Portrait and Landscape */
|
||||
@media only screen and (min-width: 667px) and (max-width: 1024px) {
|
||||
#viewer {
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
}
|
||||
}
|
||||
|
||||
#viewer.spreads .epub-view>iframe {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#viewer.scrolled {
|
||||
overflow: hidden;
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
background: url('ajax-loader.gif') center center no-repeat;
|
||||
box-shadow: 0 0 4px #ccc;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
#viewer.scrolled .epub-view>iframe {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#prev {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#next {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#toc {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
/*#viewer.spreads:after {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
border-right: 1px #000 solid;
|
||||
height: 90%;
|
||||
z-index: 1;
|
||||
left: 50%;
|
||||
margin-left: -1px;
|
||||
top: 5%;
|
||||
opacity: .15;
|
||||
box-shadow: -2px 0 15px rgba(0, 0, 0, 1);
|
||||
content: "";
|
||||
}
|
||||
|
||||
#viewer.spreads.single:after {
|
||||
display: none;
|
||||
}*/
|
||||
|
||||
#prev {
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
#next {
|
||||
right: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
margin-top: -32px;
|
||||
font-size: 64px;
|
||||
color: #E2E2E2;
|
||||
font-family: arial, sans-serif;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navlink {
|
||||
margin: 14px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.arrow:hover,
|
||||
.navlink:hover {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.arrow:active,
|
||||
.navlink:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#book-wrapper {
|
||||
width: 480px;
|
||||
height: 640px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #ccc;
|
||||
margin: 28px auto;
|
||||
background: #fff;
|
||||
border-radius: 0 5px 5px 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#book-viewer {
|
||||
width: 480px;
|
||||
height: 660px;
|
||||
margin: -30px auto;
|
||||
-moz-box-shadow: inset 10px 0 20px rgba(0, 0, 0, .1);
|
||||
-webkit-box-shadow: inset 10px 0 20px rgba(0, 0, 0, .1);
|
||||
box-shadow: inset 10px 0 20px rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
#book-viewer iframe {
|
||||
padding: 40px 40px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 50%;
|
||||
width: 400px;
|
||||
margin-left: -200px;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#controls>input[type=range] {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
width: 400px;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #777;
|
||||
-webkit-transition: -webkit-transform .25s ease-out;
|
||||
-moz-transition: -moz-transform .25s ease-out;
|
||||
-ms-transition: -moz-transform .25s ease-out;
|
||||
transition: transform .25s ease-out;
|
||||
|
||||
}
|
||||
|
||||
#navigation.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#navigation h1 {
|
||||
width: 200px;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#navigation h2 {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
color: #B0B0B0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#navigation ul {
|
||||
padding-left: 36px;
|
||||
margin-left: 0;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
#navigation ul li {
|
||||
list-style: decimal;
|
||||
margin-bottom: 10px;
|
||||
color: #cccddd;
|
||||
font-size: 12px;
|
||||
padding-left: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#navigation ul li a {
|
||||
color: #ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#navigation ul li a:hover {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#navigation ul li a.active {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#navigation #cover {
|
||||
display: block;
|
||||
margin: 24px auto;
|
||||
}
|
||||
|
||||
#navigation #closer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 12px;
|
||||
color: #cccddd;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
#navigation.closed {
|
||||
-webkit-transform: translate(-400px, 0);
|
||||
-moz-transform: translate(-400px, 0);
|
||||
-ms-transform: translate(-400px, 0);
|
||||
transform: translate(-400px, 0);
|
||||
}
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.close-x {
|
||||
stroke: #cccddd;
|
||||
fill: transparent;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 5;
|
||||
}
|
||||
|
||||
.close-x:hover {
|
||||
stroke: #fff;
|
||||
}
|
||||
|
||||
#opener {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 10px;
|
||||
stroke: #E2E2E2;
|
||||
fill: #E2E2E2;
|
||||
|
||||
}
|
||||
|
||||
#opener:hover {
|
||||
stroke: #777;
|
||||
fill: #777;
|
||||
}
|
||||
|
||||
#audioPlayer {
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #E2E2E2;
|
||||
font-weight: 400;
|
||||
}
|
38
espark_reader/reader.html
Normal file
38
espark_reader/reader.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>EPUB.js Input Example</title>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
|
||||
<script src="../dist/epub.js"></script>
|
||||
<script src="../howler.js/src/howler.core.js"></script>
|
||||
<script src="reader.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="reader.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="title">
|
||||
<input type="file" id="input">
|
||||
<div id="audioplayer"><button id="playButton" onclick="playPause()">Play</button><button id="resetButton"
|
||||
onclick="resetAudioToStart()">Reset</button></div>
|
||||
</div>
|
||||
|
||||
<div id="viewer"></div>
|
||||
<a id="prev" href="#prev" class="arrow">‹</a>
|
||||
<a id="next" href="#next" class="arrow">›</a>
|
||||
|
||||
<script>
|
||||
|
||||
init();
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
186
espark_reader/reader.js
Normal file
186
espark_reader/reader.js
Normal file
|
@ -0,0 +1,186 @@
|
|||
var book = ePub();
|
||||
var rendition;
|
||||
|
||||
var inputElement;
|
||||
var audioClips = [];
|
||||
var currentWord = 0;
|
||||
var isPlaying = false;
|
||||
function init() {
|
||||
inputElement = document.getElementById("input");
|
||||
|
||||
inputElement.addEventListener('change', function (e) {
|
||||
var file = e.target.files[0];
|
||||
if (window.FileReader) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = openBook;
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openBook(e) {
|
||||
var bookData = e.target.result;
|
||||
var title = document.getElementById("title");
|
||||
var next = document.getElementById("next");
|
||||
var prev = document.getElementById("prev");
|
||||
|
||||
book.open(bookData, "binary");
|
||||
/* console.log("opened book")
|
||||
console.log(book) */
|
||||
|
||||
var rendition = book.renderTo("viewer", {
|
||||
//manager: "continuous",
|
||||
flow: "paginated",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
snap: true
|
||||
});
|
||||
|
||||
rendition.display();
|
||||
var keyListener = function (e) {
|
||||
|
||||
// Left Key
|
||||
if ((e.keyCode || e.which) == 37) {
|
||||
rendition.prev();
|
||||
}
|
||||
|
||||
// Right Key
|
||||
if ((e.keyCode || e.which) == 39) {
|
||||
rendition.next();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
rendition.on("keyup", keyListener);
|
||||
rendition.on("relocated", function (location) {
|
||||
console.log(location);
|
||||
initAudio();
|
||||
});
|
||||
|
||||
next.addEventListener("click", function (e) {
|
||||
rendition.next();
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
prev.addEventListener("click", function (e) {
|
||||
rendition.prev();
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("keyup", keyListener, false);
|
||||
|
||||
|
||||
}
|
||||
function initAudio() {
|
||||
var iframeList = document.getElementsByTagName("iframe");
|
||||
audioClips = [];
|
||||
for (let iframe of iframeList) {
|
||||
var iframeDoc = iframe.contentDocument;
|
||||
|
||||
//get audio information
|
||||
iframeDoc.querySelectorAll('par').forEach(par => {
|
||||
var text = par.getElementsByTagName("text")[0]; //should only be one
|
||||
var audio = par.getElementsByTagName("audio")[0]; //should only be one
|
||||
var textId = text.getAttribute("src").split("#")[1];//text source format is page.xhtml#word
|
||||
var textRef = iframeDoc.getElementById(textId);
|
||||
var audioSrc = audio.getAttribute("src");
|
||||
const contentType = "audio/mp3";
|
||||
/*var sound = new Howl({
|
||||
src: [`data:${contentType};base64,${audioSrc}`]
|
||||
});*/
|
||||
audioClips.push({
|
||||
textId: textId,
|
||||
text: textRef,
|
||||
audio: audio,
|
||||
clipBegin: parseFloat(audio.getAttribute("clipbegin")),
|
||||
clipEnd: parseFloat(audio.getAttribute("clipend"))
|
||||
//duration: 1000 * (parseFloat(audio.getAttribute("clipend")) - parseFloat(audio.getAttribute("clipbegin")))
|
||||
})
|
||||
});
|
||||
//add next clip's start to the duration to account for pauses
|
||||
for (let i = 0; i < audioClips.length - 1; i++) {
|
||||
audioClips[i].duration = 1000 * (audioClips[i + 1].clipBegin - audioClips[i].clipBegin);
|
||||
}
|
||||
if (audioClips.length > 0) {
|
||||
document.getElementById("audioplayer").style.visibility = "visible";
|
||||
resetAudioToStart();
|
||||
}
|
||||
else {
|
||||
document.getElementById("audioplayer").style.visibility = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* This is where the audio play/pause function should load and play everything on the page.
|
||||
* Needs to loop through all available iframes because there may be 1-2 pages loaded separately on the page.
|
||||
* I believe the audio tags will be in order per epub spec. Could look at play start and check if that's not the case.
|
||||
* To play audio and go through highlighting the text and stopping at the right point, need to look at the clipBegin/clipEnd properties
|
||||
* You could go through each audio tag and play/stop for each one but I think that'd cause some choppy behavior. Probably would be smoother to get the start/end for the page,
|
||||
* and then track the time so that you can track the word for highlighting and pausing.
|
||||
*
|
||||
*
|
||||
* Something to consider: will tracking the pages like this get messed up if the device rotates and only shows one page?
|
||||
*/
|
||||
function playPause() {
|
||||
if (audioClips.length > 0) {
|
||||
if (isPlaying) {
|
||||
pauseAudio();
|
||||
}
|
||||
else {
|
||||
playAudio();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The audio is the same for the whole book, need to play/pause the same audio tag
|
||||
*/
|
||||
function playAudio() {
|
||||
isPlaying = true;
|
||||
highlightWord();
|
||||
audioClips[0].audio.play();
|
||||
document.getElementById("playButton").textContent = "Pause";
|
||||
}
|
||||
function pauseAudio() {
|
||||
isPlaying = false;
|
||||
audioClips[0].audio.pause();
|
||||
document.getElementById("playButton").textContent = "Play";
|
||||
}
|
||||
function resetAudioToStart() {
|
||||
if (currentWord > 0)
|
||||
audioClips[currentWord - 1].text.setAttribute("style", "");
|
||||
currentWord = 0;
|
||||
pauseAudio();
|
||||
audioClips[0].audio.currentTime = audioClips[currentWord].clipBegin;
|
||||
}
|
||||
function resetAudioToWord() {
|
||||
audioClips[0].audio.currentTime = audioClips[currentWord].clipBegin;
|
||||
}
|
||||
/**
|
||||
* To highlight text with audio, search for the span with the id that matches the #id in the text src wrapping the audio. Each par tag has a text with source and the audio.
|
||||
* Add a css highlight class to the span, then remove when moving to the next word.
|
||||
*/
|
||||
function highlightWord() {
|
||||
//don't increment words if the audio is ended
|
||||
if (currentWord >= audioClips.length) {
|
||||
resetAudioToStart();
|
||||
return;
|
||||
}
|
||||
if (!isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* note: using class add/remove doesn't work with iframes because the css is separate
|
||||
*/
|
||||
|
||||
//highlight current word
|
||||
if (currentWord > 0)
|
||||
audioClips[currentWord - 1].text.setAttribute("style", "");
|
||||
|
||||
audioClips[currentWord].text.setAttribute("style", "background-color:yellow;");
|
||||
//setup timer for when word is done being read
|
||||
const myTimeout = setTimeout(highlightWord, audioClips[currentWord].duration);
|
||||
//increment word index
|
||||
currentWord++;
|
||||
}
|
3
espark_reader/view.css
Normal file
3
espark_reader/view.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.highlight {
|
||||
background: yellow;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
@ -11,6 +12,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="examples.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="title"><input type="file" id="input"></div>
|
||||
<div id="viewer" class="spreads"></div>
|
||||
|
@ -43,7 +45,7 @@
|
|||
|
||||
rendition = book.renderTo("viewer", {
|
||||
width: "100%",
|
||||
height: 600
|
||||
height: "100%"
|
||||
});
|
||||
|
||||
rendition.display();
|
||||
|
@ -88,4 +90,5 @@
|
|||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
20921
package-lock.json
generated
20921
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -59,6 +59,7 @@
|
|||
"@xmldom/xmldom": "^0.7.5",
|
||||
"core-js": "^3.18.3",
|
||||
"event-emitter": "^0.3.5",
|
||||
"howler": "^2.2.3",
|
||||
"jszip": "^3.7.1",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
|
|
|
@ -53,7 +53,7 @@ class Packaging {
|
|||
this.coverPath = this.findCoverPath(packageDocument);
|
||||
|
||||
this.spineNodeIndex = indexOfElementNode(spineNode);
|
||||
|
||||
//KEM: spine creation/reading
|
||||
this.spine = this.parseSpine(spineNode, this.manifest);
|
||||
|
||||
this.uniqueIdentifier = this.findUniqueIdentifier(packageDocument);
|
||||
|
|
|
@ -176,6 +176,7 @@ class Rendition {
|
|||
// If manager is a string, try to load from imported managers
|
||||
if (typeof manager === "string" && manager === "default") {
|
||||
viewManager = DefaultViewManager;
|
||||
|
||||
} else if (typeof manager === "string" && manager === "continuous") {
|
||||
viewManager = ContinuousViewManager;
|
||||
} else {
|
||||
|
@ -331,7 +332,7 @@ class Rendition {
|
|||
if (this.book.locations.length() && isFloat(target)) {
|
||||
target = this.book.locations.cfiFromPercentage(parseFloat(target));
|
||||
}
|
||||
|
||||
//KEM: Section display
|
||||
section = this.book.spine.get(target);
|
||||
|
||||
if (!section) {
|
||||
|
|
|
@ -40,6 +40,7 @@ class Resources {
|
|||
this.replacementUrls = [];
|
||||
|
||||
this.html = [];
|
||||
//KEM: assets and urls are where the urls in items from the manifest are replaced by "blobs"
|
||||
this.assets = [];
|
||||
this.css = [];
|
||||
|
||||
|
@ -110,7 +111,7 @@ class Resources {
|
|||
createUrl(url) {
|
||||
var parsedUrl = new Url(url);
|
||||
var mimeType = mime.lookup(parsedUrl.filename);
|
||||
|
||||
//KEM: based on the printout of the parsedUrl here, the url is correct, but the smil file is referring to it differently. May need to modify the replacement to include the ../
|
||||
if (this.settings.archive) {
|
||||
return this.settings.archive.createUrl(url, { "base64": (this.settings.replacements === "base64") });
|
||||
} else {
|
||||
|
@ -257,12 +258,16 @@ class Resources {
|
|||
*/
|
||||
relativeTo(absolute, resolver) {
|
||||
resolver = resolver || this.settings.resolver;
|
||||
|
||||
// Get Urls relative to current sections
|
||||
return this.urls.
|
||||
map(function (href) {
|
||||
var resolved = resolver(href);
|
||||
var relative = new Path(absolute).relative(resolved);
|
||||
//KEM: hardcoding to fix audio links for testing
|
||||
//KEM: these are the links that are searched for in the content
|
||||
if (relative.includes("audio")) {
|
||||
relative = "../" + relative;
|
||||
}
|
||||
return relative;
|
||||
}.bind(this));
|
||||
}
|
||||
|
@ -300,6 +305,12 @@ class Resources {
|
|||
} else {
|
||||
relUrls = this.urls;
|
||||
}
|
||||
//KEM: this seems to be where the audio urls are going wrong, but it could be that there's a problem with the original file.
|
||||
//KEM: The smil files have relative paths to the resources with an extra folder jump like ../, and the regular pages don't do that
|
||||
//KEM: so there may need to be some kind of check to see where the files actually are before replacing them?
|
||||
/**
|
||||
* Goes through the content and replaces any instances of relUrls with this.replacementUrls
|
||||
*/
|
||||
return substitute(content, relUrls, this.replacementUrls);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class Section {
|
|||
this.canonical = item.canonical;
|
||||
this.next = item.next;
|
||||
this.prev = item.prev;
|
||||
|
||||
this.overlay = item.overlay;
|
||||
this.cfiBase = item.cfiBase;
|
||||
|
||||
if (hooks) {
|
||||
|
@ -38,6 +38,7 @@ class Section {
|
|||
this.document = undefined;
|
||||
this.contents = undefined;
|
||||
this.output = undefined;
|
||||
this.mediaOverlay = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,25 +51,56 @@ class Section {
|
|||
var loading = new defer();
|
||||
var loaded = loading.promise;
|
||||
|
||||
//KEM: this is where the file is loaded and turned into xml
|
||||
//KEM: add in a load to the smil file and append it?
|
||||
|
||||
//KEM: try to load overlay
|
||||
if (this.overlay) {
|
||||
if (this.contents) {
|
||||
loading.resolve(this.contents);
|
||||
} else {
|
||||
request(this.url)
|
||||
.then(function(xml){
|
||||
// var directory = new Url(this.url).directory;
|
||||
|
||||
request(this.overlay.url).then(function (overlayXml) {
|
||||
var div = document.createElement("div");
|
||||
div.classList.add("audioContainer");
|
||||
//overlay is returning as a string? possibly because xml instead of xhtml
|
||||
var start = overlayXml.search("<smil");
|
||||
var xmlStr = overlayXml.substring(start);
|
||||
div.insertAdjacentHTML('beforeend', xmlStr);
|
||||
this.mediaOverlay = div;
|
||||
return request(this.url).then(function (xml) {
|
||||
this.document = xml;
|
||||
this.contents = xml.documentElement;
|
||||
|
||||
this.contents.appendChild(div);
|
||||
return this.hooks.content.trigger(this.document, this);
|
||||
}.bind(this))
|
||||
.then(function(){
|
||||
|
||||
}.bind(this)).then(function () {
|
||||
loading.resolve(this.contents);
|
||||
}.bind(this))
|
||||
.catch(function(error){
|
||||
}.bind(this)).catch(function (error) {
|
||||
loading.reject(error);
|
||||
});
|
||||
}
|
||||
.bind(this)).catch(function (error) {
|
||||
loading.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.contents) {
|
||||
loading.resolve(this.contents);
|
||||
} else {
|
||||
request(this.url).then(function (xml) {
|
||||
// var directory = new Url(this.url).directory;
|
||||
this.document = xml;
|
||||
this.contents = xml.documentElement;
|
||||
return this.hooks.content.trigger(this.document, this);
|
||||
|
||||
}.bind(this)).then(function () {
|
||||
loading.resolve(this.contents);
|
||||
}.bind(this)).catch(function (error) {
|
||||
loading.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
@ -90,7 +122,7 @@ class Section {
|
|||
var rendering = new defer();
|
||||
var rendered = rendering.promise;
|
||||
this.output; // TODO: better way to return this from hooks?
|
||||
|
||||
//console.log("rendering section");
|
||||
this.load(_request).
|
||||
then(function (contents) {
|
||||
var userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';
|
||||
|
@ -299,6 +331,7 @@ class Section {
|
|||
this.document = undefined;
|
||||
this.contents = undefined;
|
||||
this.output = undefined;
|
||||
this.mediaOverlay = undefined;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
|
12
src/spine.js
12
src/spine.js
|
@ -45,7 +45,7 @@ class Spine {
|
|||
this.spineNodeIndex = _package.spineNodeIndex;
|
||||
this.baseUrl = _package.baseUrl || _package.basePath || "";
|
||||
this.length = this.items.length;
|
||||
|
||||
//KEM: unpacking opf file
|
||||
this.items.forEach((item, index) => {
|
||||
var manifestItem = this.manifest[item.idref];
|
||||
var spineItem;
|
||||
|
@ -59,10 +59,16 @@ class Spine {
|
|||
}
|
||||
|
||||
if (manifestItem) {
|
||||
//KEM: This is where spine items get the URL from the manifest, this is where to connect the manifest media-overlay and get SMIL URL
|
||||
item.href = manifestItem.href;
|
||||
item.url = resolver(item.href, true);
|
||||
item.canonical = canonical(item.href);
|
||||
|
||||
//KEM: added overlay so can load later in section
|
||||
item.overlay = this.manifest[manifestItem.overlay];
|
||||
if (item.overlay) {
|
||||
item.overlay.url = resolver(item.overlay.href, true);
|
||||
item.overlay.canonical = canonical(item.overlay.href);
|
||||
}
|
||||
if (manifestItem.properties.length) {
|
||||
item.properties.push.apply(item.properties, manifestItem.properties);
|
||||
}
|
||||
|
@ -100,7 +106,7 @@ class Spine {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//KEM: section creation
|
||||
spineItem = new Section(item, this.hooks);
|
||||
|
||||
this.append(spineItem);
|
||||
|
|
85
src/test.html
Normal file
85
src/test.html
Normal file
|
@ -0,0 +1,85 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="en-US">
|
||||
|
||||
<head>
|
||||
|
||||
|
||||
<title>Me and My Cat</title>
|
||||
|
||||
<link href="CSS/default.css" rel="stylesheet" type="text/css" />
|
||||
<link href="CSS/css_1.css" rel="stylesheet" type="text/css" />
|
||||
|
||||
<meta name="viewport" content="width=1400, height=1685" />
|
||||
|
||||
</head>
|
||||
|
||||
<body epub:type="frontmatter" lang="en-US" xml:lang="en-US">
|
||||
<div class="pg1">
|
||||
<section epub:type="titlepage">
|
||||
<img src="images/1.jpg" class="img" alt="written " />
|
||||
<p id="para1">
|
||||
|
||||
<span id="p1s1"><span id="written">written</span></span>
|
||||
<span id="Me"></span>
|
||||
<span id="and"></span>
|
||||
<span id="My"></span>
|
||||
<span id="Cat"></span>
|
||||
<span id="p1s2"><span id="by">by</span></span> <br />
|
||||
<span id="p1s4"><span id="Michael">Michael</span></span>
|
||||
<span id="p1s5"><span id="Dahl">Dahl</span></span> <br />
|
||||
<span id="p1s6"><span id="art">art</span></span>
|
||||
<span id="p1s7"><span id="by1">by</span></span> <br />
|
||||
<span id="p1s9"><span id="Zoe">Zoe</span></span>
|
||||
<span id="p1s10"><span id="Persico">Persico</span></span> <br />
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
<smil xmlns="http://www.w3.org/ns/SMIL" xmlns:epub="http://www.idpf.org/2007/ops" version="3.0">
|
||||
|
||||
<body>
|
||||
<par id="id0">
|
||||
<text src="../P1.xhtml#Me">
|
||||
</text>
|
||||
<audio clipBegin="4.15" clipEnd="4.479" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
<par id="id1">
|
||||
<text src="../P1.xhtml#and">
|
||||
</text>
|
||||
<audio clipBegin="4.479" clipEnd="4.674" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
<par id="id2">
|
||||
<text src="../P1.xhtml#My">
|
||||
</text>
|
||||
<audio clipBegin="4.674" clipEnd="4.895" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
<par id="id3">
|
||||
<text src="../P1.xhtml#Cat">
|
||||
</text>
|
||||
<audio clipBegin="4.895" clipEnd="5.31" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
<par id="id4">
|
||||
<text src="../P1.xhtml#by">
|
||||
</text>
|
||||
<audio clipBegin="5.76" clipEnd="5.919" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
<par id="id5">
|
||||
<text src="../P1.xhtml#Michael">
|
||||
</text>
|
||||
<audio clipBegin="5.919" clipEnd="6.37" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
<par id="id6">
|
||||
<text src="../P1.xhtml#Dahl">
|
||||
</text>
|
||||
<audio clipBegin="6.371" clipEnd="6.778" src="../audio/mmp_mecat_f16_masteraudio.mp3">
|
||||
</audio>
|
||||
</par>
|
||||
</body>
|
||||
</smil>
|
||||
|
||||
</html>
|
|
@ -79,7 +79,6 @@ export function replaceLinks(contents, fn) {
|
|||
if (!links.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var base = qs(contents.ownerDocument, "base");
|
||||
var location = base ? base.getAttribute("href") : undefined;
|
||||
var replaceLink = function (link) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue