title: Javascript / JQuery save location in epub
body: <p>I'm trying to build an epub reader for android, every thing is fine and working as expected, <strong>BUT</strong> the problem I cannot solve is <em>saving last seen page</em> (or save position for bookmark).</p>
  
  <p><em>A little background:</em></p>
  
  <p>I use <code>css multi column</code> to show epub, <code>columnWidth</code> is set to <code>windowWidth</code> and <code>columnHeight</code> is set to <code>windowHeight</code>.
  <em>To ensure each column will fill the entire screen</em>.</p>
  
  <p>Currently for saving position I <em>pre process</em> the html and wrap each element with a <code>div</code> including a specific <code>id</code> that represents the section number and tag position. For example a <code>&lt;p&gt;</code> tag after process would be like this:</p>
  
  <pre><code>&lt;div id="id__1__8"&gt;&lt;p&gt;some text&lt;/p&gt;&lt;/div&gt;
  </code></pre>
  
  <p>The <code>id__1__8</code> represents that this text belongs to <em>section 1</em> and it is the <em>8th element</em> in that body.</p>
  
  <p>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 <code>id</code> so the nearest <code>id</code> will be found and I know that this page belongs to where in epub.</p>
  
  <p>The next step is to find offset (suppose a <code>p</code> tag that fills 7 pages). With offset I know that I must load the 8th element of section 1 and go to page 5.</p>
  
  <p>Look at the function in jQuery: (for finding nearest element and offset)</p>
  
  <pre><code>jqGetLastPosition = function(ids)
      {
          var tempColumn = _column; // _column is current page that is showing
          if(tempColumn &lt; 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&lt;realIds.length; i++)
          {
              try
              {
                  currId = "#" + realIds[i];
                  currentLeft = $(currId).position().left;
                  if(currentLeft &lt; 0)
                  {
                      currentLeft = -1 * currentLeft;
                  }
                  tempDistance = columnLeft - currentLeft;
                  if(tempDistance &lt; 0)
                  {
                      //this id is after this page
                      continue;
                  }
                  else if(tempDistance &lt; 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);
      };
  </code></pre>
  
  <p>This code works fine for most of situations where page offset is <strong>zero</strong>, like <code>id__1__8__0</code>.</p>
  
  <p>The problem arises when there is <em>offset</em>, 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.</p>
  
  <p><strong>So what is the problem with this code?</strong></p>
  
  <p><em>Or am I wrong doing this for saving location?</em></p>
  
  <p><em>Is there any better method?</em></p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>If i add <code>div</code> before any tag like <code>&lt;div id="id__1__8"&gt;&lt;/div&gt;&lt;p&gt;some text&lt;/p&gt;</code> the result will be accurate in 90% of the time. so the updated question will be <strong>How achieve this goal (saving position in epub) with 100% accuracy?</strong></p>
  
  <p><strong>UPDATE 2:</strong></p>
  
  <p>I'm putting the <code>div</code> for every elements eg. <code>head</code>, <code>p</code>, <code>link</code>, <code>img</code> ....</p>
  
  <p>Is there any possibility that this makes the problem?? </p>
  
  <p><strong>UPDATE 3:</strong></p>
  
  <p>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.</p>
  
  <p><em>any idea would be appreciated</em></p>
  
  <p><img src="https://i.stack.imgur.com/ZYrzU.jpg" alt="enter image description here"></p>
  
  <p><strong>UPDATE 4:</strong></p>
  
  <p><em>CSS:</em></p>
  
  <pre><code>#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;
      }
  </code></pre>
  
  <p>the <code>&lt;span id=\"endMarker\"&gt;&lt;/span&gt;</code> will add to the end of body so i have a marker at the end of html content.</p>
  
  <p>the <em>Jquery</em>:</p>
  
  <pre><code>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 &lt; 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 &lt; 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 &lt; 0)
          {
              rtl = 1;
              maxColumn = (maxColumn * -1);
              _column = (maxColumn - _columnCount + _column);
          }
          else
          {
              _column = maxColumn - _columnCount + _column;
          }
  
          _columnCount = maxColumn;
          setColumn(_column);
          reportNumberOfPage(_columnCount);
      }
  </code></pre>
  
  <p>this is almost all of my code, if you need more please let me know.</p>