Javascript/JQuery сохранить местоположение в epub

Я пытаюсь создать epub-ридер для Android, все прекрасно и работает, как ожидалось, НО проблема, которую я не могу решить, - это сохранение последней просмотренной страницы (или сохранение позиции для закладки).

Немного фона:

Я использую css multi column, чтобы показать epub, columnWidth установлен на windowWidth, а columnHeight установлен на windowHeight. Чтобы каждый столбец заполнил весь экран.

В настоящее время для сохранения позиции я предварительно обрабатываю html и обертываю каждый элемент с помощью div, включая конкретный id, который представляет номер раздела и позицию тега. Например, тег <p> после процесса будет выглядеть следующим образом:

<div id="id__1__8"><p>some text</p></div>

id__1__8 означает, что этот текст относится к разделу 1, и это 8-й элемент в этом теле.

У меня есть полный список этих идентификаторов, и для сохранения позиции я использую jQuery для сравнения слева от текущего столбца слева от каждого id, поэтому ближайший id будет найден, и я знаю, что эта страница принадлежит где в epub.

Следующий шаг - найти смещение (предположим, тег p, который заполняет 7 страниц). Со смещением я знаю, что я должен загрузить восьмой элемент раздела 1 и перейти на страницу 5.

Посмотрите на функцию в jQuery: (для поиска ближайшего элемента и смещения)

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);
    };

Этот код отлично подходит для большинства ситуаций, когда смещение страницы ноль, например id__1__8__0.

Проблема возникает, когда есть смещение, страница смещения не может быть вычислена правильно, я вижу, что есть одно смещение страницы, но этот код дает мне 0, или когда есть 9-страничное смещение, это дает мне 4.

В чем проблема с этим кодом?

Или я ошибаюсь, делая это для сохранения местоположения?

Есть ли лучший способ?

UPDATE:

Если я добавлю div перед тем, как любой тег, например <div id="id__1__8"></div><p>some text</p>, результат будет точным в 90% случаев. поэтому обновленный вопрос будет Как достичь этой цели (сохранение позиции в epub) со 100-процентной точностью?

ОБНОВЛЕНИЕ 2:

Я помещаю div для каждого элемента, например. head, p, link, img....

Есть ли какая-то возможность, что это создает проблему?

ОБНОВЛЕНИЕ 3:

Наконец-то я обнаружил, что вызывает проблему. рассмотрите ситуацию, когда ближайший элемент к текущей странице начинается в середине предыдущей страницы, я сохраняю идентификатор этого элемента, и смещение будет равным 1. Когда я хочу загрузить сохраненное местоположение, загрузка элемента вверху page, SO немного изменится в тексте, в приведенном ниже изображении я покажу, что происходит.

любая идея будет оценена

enter image description here

ОБНОВЛЕНИЕ 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;
    }

<span id=\"endMarker\"></span> добавит к концу тела, поэтому у меня есть маркер в конце содержимого html.

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);
    }

это почти весь мой код, если вам нужно больше, пожалуйста, дайте мне знать.

Ответ 1

Думаю, я понимаю, о чем вы спрашиваете. Вы пытаетесь создать кучу "поддельных" страниц, которые представляют собой один HTML файл? Я создал рабочий пример того, что, я думаю, вы хотите. Он работает, обновляя location.hash текущим разделом по мере прокрутки. Когда вы перезагружаетесь, он должен появиться в том же разделе ( "поддельная" страница). Вам нужно загрузить это для правильной работы, поэтому я помещаю его в суть.

Это связано с тем, что Stackoverflow и JSFiddle забавляют код в песочнице, где location.hash не может быть обновлен.

Это обновит историю вашего браузера каждый раз, когда вы перейдете на новую страницу. Я решил, что это раздражает, поэтому у меня есть настройка состояния HTML5. Это будет работать только на веб-сервере, но каждый раз, когда вы переходите на новую страницу, он заменяет текущий URL (и историю) на "поддельную" страницу, поэтому у вас нет бесконечной истории. Код, который я опубликовал, будет выполняться локально на вашем компьютере или на веб-сервере, но он будет работать лучше на веб-сервере.

Суть: https://gist.github.com/Christianjuth/a4e6fad50da54818bbc3

код:

$(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>