User A gets on my online magazine. She starts reading a very long article, then in the middle of it she decides to pause. She closes the browser and only comes back to the site many hours later. Now when she opens again the same article I would like the page to start from where she had left it.
Imaging User A is actually a registered user, how can I achieve this? More specifically, I would like to store the character number (as an int) of the first character of the first visible line on the screen (basically the top-left corner).
Edit: Just to clarify even further, you can think of apps like Instapaper or Pocket to be facing a similar issue (both the mobile and web apps).
I am not really sure how that can be done. I would recommend storing how much the document has been scrolled using localStorage
.
You can get how far the document was scrolled and the dimensions of the document at the time it was closed, If the width of the document is the same when it gets reloaded then you can just scroll to the same point. If not you can estimate the point where the user left off by calculating the volume read width * scrollTop
and dividing that by the current width.
Here is a pseudo-code to help you understand the concept:
if oldWidth == currentWidth
set scroll = oldScroll
else
set scroll = oldScroll * oldWidth / currentWidth
Here is a JavaScript example of the above pseudo-code, but some notes first:
localStorage
is not allowed on snippets so the current code will not work here, if you want to test you will have to copy it elsewhereleavePage()
method has a return null
statement at the end, this is because some browsers will not run a function without a return statement on beforeunload
if (document.readyState === "complete") enterPage();
else addEventListener("load", enterPage);
addEventListener("beforeunload", leavePage);
function enterPage() {
var magazineDom = document.querySelector("#magazine");
if (magazineDom instanceof HTMLElement) {
magazineDom.textContent = "Lorem Ipsum".repeat(800);
//onRender();
}
}
function onRender() {
var magazineContainerDom = document.querySelector("#magazine-container");
var magazineDom = document.querySelector("#magazine");
if (magazineContainerDom instanceof HTMLElement && magazineDom instanceof HTMLElement) {
var info = getMagazineInfo(magazineDom.getAttribute("magazine"));
if (info) {
var currentWidth = magazineDom.scrollWidth;
if (currentWidth == info.width) magazineContainerDom.scrollTop = info.top;
else magazineContainerDom.scrollTop = info.top * info.width / currentWidth;
}
}
}
function leavePage() {
var magazineContainerDom = document.querySelector("#magazine-container");
var magazineDom = document.querySelector("#magazine");
if (magazineContainerDom instanceof HTMLElement && magazineDom instanceof HTMLElement) {
setMagazineInfo(magazineDom.getAttribute("magazine"), magazineContainerDom.scrollTop, magazineDom.scrollWidth);
}
return null;
}
function getMagazineInfo(name) {
return JSON.parse(localStorage.magazines || "{}")[name];
}
function setMagazineInfo(name, top, width) {
var magazines = JSON.parse(localStorage.magazines || "{}");
magazines[name] = {
top: top,
width: width
};
localStorage.magazines = JSON.stringify(magazines);
}
body {
position: fixed;
bottom: 0;
right: 0;
left: 0;
top: 0;
}
#magazine-container {
overflow-y: auto;
height: 100%;
width: 100%;
}
#magazine {
max-width: 500px;
margin: auto;
}
<body>
<div id="magazine-container">
<div id="magazine" magazine="First Document">
</div>
</div>
</body>
I had some fun with this. The script is creating an array of lines. The array may be searched for a term, that is stored in a Cookie or better the local storage.
See
function findLine4(str)
Hope you find some ideas for your issue below. Please don't mind, its only some dirty script yet.
<html>
<body>
<div id="containerWrapper"></div>
<div id="testWrapper"></div>
<div id="originDiv" style="background:#fee;">
Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Aenean commodo ligula eget dolor. Aenean massa
<strong>strong</strong>. Cum sociis natoque penatibus
et magnis dis parturient montes, nascetur ridiculus
mus. Donec quam felis, ultricies nec, pellentesque
eu, pretium quis, sem. Nulla consequat massa quis
enim. Donec pede justo, fringilla vel, aliquet nec,
vulputate eget, arcu. In enim justo, rhoncus ut,
imperdiet a, venenatis vitae, justo. Nullam dictum
felis eu pede <a class="external ext" href="#">link</a>
mollis pretium. Integer tincidunt. Cras dapibus.
Vivamus elementum semper nisi. Aenean vulputate
eleifend tellus. Aenean leo ligula, porttitor eu,
consequat vitae, eleifend ac, enim. Aliquam lorem ante,
dapibus in, viverra quis, feugiat a, tellus. Phasellus
viverra nulla ut metus varius laoreet. Quisque rutrum.
Aenean imperdiet. Etiam ultricies nisi vel augue.
Curabitur ullamcorper ultricies nisi.
<br /><br /><br />
Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Aenean commodo ligula eget dolor. Aenean massa
<strong>strong</strong>. Cum sociis natoque penatibus
et magnis dis parturient montes, nascetur ridiculus
mus. Donec quam felis, ultricies nec, pellentesque
eu, pretium quis, sem. Nulla consequat massa quis
enim. Donec pede justo, fringilla vel, aliquet nec,
vulputate eget, arcu. In enim justo, rhoncus ut,
imperdiet a, venenatis vitae, justo. Nullam dictum
felis eu pede <a class="external ext" href="#">link</a>
mollis pretium. Integer tincidunt. Cras dapibus.
Vivamus elementum semper nisi. Aenean vulputate
eleifend tellus. Aenean leo ligula, porttitor eu,
consequat vitae, eleifend ac, enim. Aliquam lorem ante,
dapibus in, viverra quis, feugiat a, tellus. Phasellus
viverra nulla ut metus varius laoreet. Quisque rutrum.
Aenean imperdiet. Etiam ultricies nisi vel augue.
Curabitur ullamcorper ultricies nisi.
</div>
</body>
<script>
(function init() {
var i;
var originDiv = document.getElementById("originDiv");
var allowedWidth = originDiv.scrollWidth;
function testBreak(testDiv, strTest) {
testDiv.innerHTML = strTest + "..."; // Yepp, that's the point. No clue, how to fix this.
return testDiv.scrollWidth > allowedWidth;
}
function tokenizeText() {
return originDiv.innerHTML.trim()
.split(/([\s]*<[a-zA-Z]+.*>.*<\/.*>[.,;:-]*[\s]*)|[\s]+/ig)
.filter(function(a){return typeof(a) != 'undefined'})
.map(function(a){return a.trim()});
}
function createLineArray() {
var testDiv = originDiv.cloneNode(true);
testDiv.innerHTML = "";
testDiv.setAttribute("style", "white-space:nowrap;background:#ccc;visibility:hidden;");
document.getElementById("testWrapper").appendChild(testDiv);
var htmlWords = tokenizeText();
var lines = [];
var currLine = '';
for(i = 0; i < htmlWords.length; i++) {
currLine += htmlWords[i] + ' ';
if(testBreak(testDiv, currLine)) {
lines.push(currLine.substr(0, currLine.length - htmlWords[i].length - 1));
currLine = '';
i--;
}
}
lines.push(currLine);
return lines;
}
function createNewDiv(html) {
var newDiv = document.createElement("DIV");
newDiv.setAttribute("style", "background:#ddf");
newDiv.setAttribute("id", "newContainer");
newDiv.innerHTML = html;
return newDiv;
}
(function doInit() {
var lines = createLineArray();
var formattedText = '';
for (i = 0; i < lines.length; i++) {
formattedText += '<div class="line'+i+'">' + lines[i] + '</div>';
}
document.getElementById("containerWrapper").appendChild(createNewDiv(formattedText));
// originDiv.style.display="none";
})();
(function findLine4(str) {
//TODO: tokenize str and search for matching tokens.
var nodes = document.getElementById("newContainer").childNodes;
for(i = 0; i < nodes.length; i++) {
if(nodes[i].textContent.indexOf(str) != -1) {
setTimeout(function() {
window.scrollTo(0, nodes[i].offsetTop);
},1);
break;
}
}
})("elementum semper");
/*
I personally would prefer a timer instead of a listener here.
*/
window.addEventListener("scroll", function(evt) {
var sct = window.scrollY;
var nodes = document.getElementById("newContainer").childNodes;
for(var i = 0; i < nodes.length; i++) {
if(nodes[i].offsetTop > sct) {
console.log("line " + i + ": " + nodes[i].innerHTML);
break;
}
}
}, true);
})();
</script>
</html>
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