I'm trying to build an epub reader for android, every thing is fine and working as expected, BUT the problem I cannot solve is saving last seen page (or save position for bookmark).
A little background:
I use css multi column
to show epub, columnWidth
is set to windowWidth
and columnHeight
is set to windowHeight
.
To ensure each column will fill the entire screen.
Currently for saving position I pre process the html and wrap each element with a div
including a specific id
that represents the section number and tag position. For example a <p>
tag after process would be like this:
<div id="id__1__8"><p>some text</p></div>
The id__1__8
represents that this text belongs to section 1 and it is the 8th element in that body.
I have a full list of these ids, and for saving position I use jQuery to compare left of the current column with left of every id
so the nearest id
will be found and I know that this page belongs to where in epub.
The next step is to find offset (suppose a p
tag that fills 7 pages). With offset I know that I must load the 8th element of section 1 and go to page 5.
Look at the function in jQuery: (for finding nearest element and offset)
jqGetLastPosition = function(ids)
{
var tempColumn = _column; // _column is current page that is showing
if(tempColumn < 0)
{
tempColumn = -1 * tempColumn;
}
var realIds = ids.split("|");
var columnLeft = (tempColumn * (_windowWidth + _columnGap));
var currentLeft;
var currId = "#" + realIds[0];
var nearestId = realIds[0] + "__0";
var minDistance = 1000000;
var tempDistance = 0;
var exactColumn = 0;
for(i=0; i<realIds.length; i++)
{
try
{
currId = "#" + realIds[i];
currentLeft = $(currId).position().left;
if(currentLeft < 0)
{
currentLeft = -1 * currentLeft;
}
tempDistance = columnLeft - currentLeft;
if(tempDistance < 0)
{
//this id is after this page
continue;
}
else if(tempDistance < minDistance)
{
minDistance = tempDistance;
exactColumn = Math.floor(minDistance/(_windowWidth + _columnGap)); //this must compute the offset pages after nearest element
nearestId = realIds[i] + "__" + exactColumn;
}
}
catch(e)
{
}
}
jsSaveLastLocation(nearestId);
};
This code works fine for most of situations where page offset is zero, like id__1__8__0
.
The problem arises when there is offset, the offset page cannot be computed correctly, I can see that there is one page offset, but this code gives me 0 offset, or when there is 9 page offset it gives me 4.
So what is the problem with this code?
Or am I wrong doing this for saving location?
Is there any better method?
UPDATE:
If i add div
before any tag like <div id="id__1__8"></div><p>some text</p>
the result will be accurate in 90% of the time. so the updated question will be How achieve this goal (saving position in epub) with 100% accuracy?
UPDATE 2:
I'm putting the div
for every elements eg. head
, p
, link
, img
....
Is there any possibility that this makes the problem??
UPDATE 3:
I finally find what is causing the problem. consider a situation where the nearest element to the current page start at the middle of the previous page, I save the id of this element and the offset would be 1. when i want to load the saved location, the element load at top of the page, SO a little shift in text would happen, in the below image i show what is happening.
any idea would be appreciated
UPDATE 4:
CSS:
#container {
width: 100%;
height: 98%;
overflow: hidden;
}
#content {
position: relative;
height: 98%;
-moz-column-width: 200px;
-webkit-column-width: 200px;
column-width: 200px;
-moz-column-gap: 1px;
-webkit-column-gap: 1px;
column-gap: 1px;
}
img {
max-width: 100%;
max-height: 100%;
display:inline-block;
-webkit-column-break-inside : avoid;
}
the <span id=\"endMarker\"></span>
will add to the end of body so i have a marker at the end of html content.
the Jquery:
var _column = 0;
var _columnCount = 0;
var _windowWidth;
var _windowHeight;
var rtl = 0;
$(function() {
_columnWidth = $('#container').width();
_windowWidth = $('#container').width();
_windowHeight = $('#container').height();
$('#content').css('-webkit-column-width', _windowWidth);
$('#content').css('-moz-column-width', _windowWidth);
$('#content').css('column-width', _windowWidth);
$(document).ready(function(){
$(window).load(function(){
_columnCount = Math.floor($('#endMarker').position().left/(_windowWidth + _columnGap));
if(_columnCount < 0)
{
rtl = 1;
_columnCount = (_columnCount * -1);// + 2;
informRTL(rtl); //inform the java part that this doc is right to left
}
else
{
informRTL(rtl);
}
reportNumberOfPage(_columnCount); // this will report to java part
});
});
setColumn = function(i) {
if(rtl == 1)
{
_column = (i * -1);
}
else
{
_column = i;
}
$('#content').css({"-webkit-transform":"translate(" + (-1 * _column * (_windowWidth + _columnGap)) + "px,0px)"});
}
setColumn(0); //set the showing column to first
nextPage = function() {
if (_column==_columnCount -1 || (-1*_column)==_columnCount -1)
informEndPage();
else
{
if(rtl == 1)
{
_column = _column-1;
$('#content').css({"-webkit-transform":"translate(" + (-1 * _column * (_windowWidth + _columnGap)) + "px,0px)"});
}
else
{
_column = _column+1;
$('#content').css({"-webkit-transform":"translate(" + (-1 * _column * (_windowWidth + _columnGap)) + "px,0px)"});
}
}
};
prevPage = function() {
if (0==_column)
informStartPage();
else
{
if(rtl == 1)
{
_column = _column+1;
$('#content').css({"-webkit-transform":"translate(" + (-1 * _column * (_windowWidth + _columnGap)) + "px,0px)"});
updateCurrentPageText((_column * -1));
}
else
{
_column = _column-1;
$('#content').css({"-webkit-transform":"translate(" + (-1 * _column * (_windowWidth + _columnGap)) + "px,0px)"});
updateCurrentPageText(_column);
}
}
};
//this function add more html content to the end of current body
addString = function(s)
{
$(s).insertBefore('#endMarker');
$(window).load(addStringReport());
};
addStringReport = function()
{
_columnCount = Math.floor($('#endMarker').position().left/(_windowWidth + _columnGap));
if(_columnCount == 0)
{
requestMorePage();
}
if(_columnCount < 0)
{
rtl = 1;
_columnCount = (_columnCount * -1);
}
nextPage();
reportNumberOfPage(_columnCount);
}
//this function add more html content to the first of body
addStringToFirst = function(s)
{
$('#content').prepend(s);
$(window).load(addStringToFirstReport());
}
addStringToFirstReport = function()
{
maxColumn = Math.floor($('#endMarker').position().left/(_windowWidth + _columnGap));
if(maxColumn < 0)
{
rtl = 1;
maxColumn = (maxColumn * -1);
_column = (maxColumn - _columnCount + _column);
}
else
{
_column = maxColumn - _columnCount + _column;
}
_columnCount = maxColumn;
setColumn(_column);
reportNumberOfPage(_columnCount);
}
this is almost all of my code, if you need more please let me know.
I think I understand what you are asking. Are you trying to create a bunch of "fake" pages that are all one HTML file? I created a working example of what I think you want. It works by updating location.hash
with the current section as you scroll. When you reload it should appear on the same section ("fake" page). You need to download this for it to run properly so I put it in a gist.
This is because Stackoverflow and JSFiddle fun the code in a sandbox where location.hash
can not be updated.
This will update your browser history every time you scroll to a new page. I figured this was annoying so I have HTML5 push state setup. This will only work on a web server but every time you scroll to a new page it will replace the current url (and history) with the "fake" page in view so you do not have an infinite history. The code I posted will run locally on your computer or on a webserver but it will run better on a web server.
Gist: https://gist.github.com/Christianjuth/a4e6fad50da54818bbc3
Code:
$(document).scroll(function() {
//get current section
var $currentPage = $('.pages > section:onScreen').first();
var $title = $('.pages > section:onScreen').first().find('h1').first();
//update url
if (history && history.pushState && location.protocol !== "file:") {
history.pushState({}, $title.text(), "/#" + $currentPage.attr('id'));
} else {
location.hash = $currentPage.attr('id');
}
});
html,
body {
margin: 0;
padding: 0;
height: 101%;
width: 100%;
}
*,
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.pages {
display: inline-block;
width: 100%;
height: 100%;
}
.pages > section {
display: inline-block;
min-height: 100%;
padding: 10px;
font-family: Georgia;
}
.pages > section:nth-child(even) {
background-color: #000;
color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://benpickles.github.io/onScreen/jquery.onscreen.js"></script>
<div class="pages">
<section id="html5">
<h1>HTML5</h1>
<p>HTML5 is a core technology markup language of the Internet used for structuring and presenting content for the World Wide Web. As of October 2014 this is the final and complete fifth revision of the HTML standard of the World Wide Web Consortium (W3C).[3]
The previous version, HTML 4, was standardised in 1997.</p>
<p>Its core aims have been to improve the language with support for the latest multimedia while keeping it easily readable by humans and consistently understood by computers and devices (web browsers, parsers, etc.). HTML5 is intended to subsume not
only HTML 4, but also XHTML 1 and DOM Level 2 HTML.</p>
</section>
<section id="css3">
<h1>CSS3</h1>
<p>Cascading Style Sheets (CSS) is a style sheet language used for describing the look and formatting of a document written in a markup language. While most often used to change the style of web pages and user interfaces written in HTML and XHTML, the
language can be applied to any kind of XML document, including plain XML, SVG and XUL. Along with HTML and JavaScript, CSS is a cornerstone technology used by most websites to create visually engaging webpages, user interfaces for web applications,
and user interfaces for many mobile applications.</p>
</section>
<section id="bootstrap">
<h1>Bootstrap</h1>
<p>Bootstrap is a free and open-source collection of tools for creating websites and web applications. It contains HTML- and CSS-based design templates for typography, forms, buttons, navigation and other interface components, as well as optional JavaScript
extensions. The bootstrap framework aims to ease web development.</p>
<p>Bootstrap is a front end, that is an interface between the user and the server-side code which resides on the "back end" or server. And it is a web application framework, that is a software framework which is designed to support the development of
dynamic websites and web applications.</p>
</section>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With