Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Extended moveTo() #20

Closed
wants to merge 14 commits into from

2 participants

@aronwoost

The xpath extension was fabulous. However, it does not work with textnodes.

I added the ability to jump not only to element nodes (achievable with xpath) but also to text nodes.

BTW: This is the first and only change we made to monocle so far. :) Very robust framework you build there. Let's keep it up!

@joseph
Owner

Hey, thanks Aron.

Can you give me an example of what this offers over and above XPath?

My primary reasons for not using objects in loci are that they are ephemeral and document-specific. So you run in to big problems if the locus refers to a component that is no longer active, or in the case where you have two or more pageDivs in a flipper — since the object will only be in one of those pages.

Essentially, XPath is a component-neutral and state-neutral string description of a document location. You can reach text nodes in XPath with text(). I think we should perhaps concentrate on a way to simply and correctly derive the XPath of a given object (at the moment I just assign the node or its parent element an id), rather than attempting to work directly with object coordinates.

@aronwoost

Hi Joseph,

Anything you said makes sense. And yes, you're right, xpath does (of course) finds textnodes. Also with node().

However, another important thing I maybe didn't point out is that we need to have the ability to jump to a certain offset inside a textnode. (See range stuff in component.pageForClientRect() )

Since we need to pass the offset somehow, we can not use a simple string.

Any suggestions welcome.

@joseph
Owner

In that scenario for Booki.sh search, I've just split the text node.

Assuming the text node has been assigned to 'leftNode', and assuming we are looking for the first instance of the string assigned to 'query':

  var idx = leftNode.nodeValue.toLowerCase().indexOf(query.toLowerCase());
  var midNode = leftNode.splitText(idx);
  var rightNode = midNode.splitText(query.length);

You can then construct the XPath to point to midNode. (In fact, what I do for Booki.sh search is insert a yellow span element after leftNode and append midNode to it. Then I give the span an id, making the XPath trivial.)

I do this minor DOM manipulation on all the flipper's visiblePages(), so that the XPath will work for all of them.

Though there's no real problem with fragmentation of text nodes, you can subsequently repair the containing element (after going to the locus via XPath) with:

  leftNode.parentNode.normalize();

In short: I'm not completely against objects in loci, but I'm just wondering if it can't be done more simply with the existing locus options. What do you think?

@aronwoost

The advantage of our approach is that it's very exact. You don't need a query to jump to a certain position. Say you want to save a position for later use. You would have to make sure, that the query is unique enough. No "and" or " " etc.

Also you don't have to rely on XPath. I read that XPath is kinda slow in iOS devices (although I havent made hardcore tests yet).

Don't worry, it's totally fine if you decide to leave this feature out of the framework for now. Maybe I'll come back on a later point. I only thought since you was begging for a pull request... ;)

@joseph
Owner

Well of course there's no reason not to split the text node on some other criteria — such as a precise character offset:

var index = 132;
var length = 14;
var midNode = leftNode.splitText(index);
var rightNode = midNode.splitText(length);

I guess the thing I'm trying to avoid is having loci that refer to the contents of a particular component frame. At the moment, when you jump by locus, it reuses the top component frame (visiblePages[0] or whatever) — but there's no guarantee it will always do this.

In fact, if it were to mimic the behaviour of iBooks, for eg, it would use the underneath frame (something that's been on my list for a while with the Slider flipper). I think that would break this patch, unless I'm missing something?

@aronwoost aronwoost closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
12 README.md
@@ -11,6 +11,18 @@ Contributions welcome - fork the repository on
[GitHub](http://github.com/joseph/monocle).
+## Staying up to date
+
+Monocle tries to keep the master branch on Github fairly stable. This means
+it tracks a long way behind the bleeding edge — currently the master is
+1.0, from March 2010.
+
+If you want to work with the edge version of Monocle (and I'd encourage this
+for any new projects), check out the 'componentry' branch:
+
+ http://github.com/joseph/monocle/tree/componentry
+
+
## Getting started
Here's the simplest thing that could possibly work.
View
2  src/book.js
@@ -123,6 +123,8 @@ Monocle.Book = function (dataSource) {
result.page = component.pageForChapter(locus.anchor, pageDiv);
} else if (typeof(locus.xpath) == "string") {
result.page = component.pageForXPath(locus.xpath, pageDiv);
+ } else if (typeof(locus.nodeObj) == "object") {
+ result.page = component.pageForClientRect(locus.nodeObj, pageDiv);
} else if (typeof(locus.position) == "string") {
if (locus.position == "start") {
result.page = 1;
View
29 src/component.js
@@ -228,12 +228,12 @@ Monocle.Component = function (book, id, index, chapters, source) {
// Correct the body lineHeight to use a number, not a percentage, which
// causes the text to jump upwards.
- var doc = frame.contentDocument;
+ /*var doc = frame.contentDocument;
var win = doc.defaultView;
var currStyle = win.getComputedStyle(doc.body, null);
var lh = parseFloat(currStyle.getPropertyValue('line-height'));
var fs = parseFloat(currStyle.getPropertyValue('font-size'));
- doc.body.style.lineHeight = lh / fs;
+ doc.body.style.lineHeight = lh / fs;*/
p.pageLength = pageDiv.m.dimensions.measure();
frame.style.visibility = "visible";
@@ -318,7 +318,28 @@ Monocle.Component = function (book, id, index, chapters, source) {
var percent = pageDiv.m.dimensions.percentageThroughOfNode(node);
return percentToPageNumber(percent);
}
-
+
+ function pageForClientRect(nodeObj, pageDiv) {
+ if (!nodeObj) {
+ return 1;
+ }
+ var doc = pageDiv.m.activeFrame.contentDocument;
+ node = nodeObj.getNode(nodeObj.node, doc);
+ if(!node){
+ return 1;
+ }
+ if(node.getBoundingClientRect) { // it's not a text node
+ var perc = pageDiv.m.dimensions.percentageThroughOfNode(node);
+ return percentToPageNumber(perc);
+ }
+ // has to be a textnode, let's create a range
+ var offset = parseInt(nodeObj.offset || 0);
+ var range = doc.createRange();
+ range.setStart(node, offset);
+ range.setEnd(node, offset + 1);
+ var percent = pageDiv.m.dimensions.percentageThroughOfNode(range);
+ return percentToPageNumber(percent);
+ }
function pageForXPath(xpath, pageDiv) {
var doc = pageDiv.m.activeFrame.contentDocument;
@@ -333,7 +354,6 @@ Monocle.Component = function (book, id, index, chapters, source) {
return percentToPageNumber(percent);
}
-
function percentToPageNumber(pc) {
return Math.floor(pc * p.pageLength) + 1;
}
@@ -350,6 +370,7 @@ Monocle.Component = function (book, id, index, chapters, source) {
API.updateDimensions = updateDimensions;
API.chapterForPage = chapterForPage;
API.pageForChapter = pageForChapter;
+ API.pageForClientRect = pageForClientRect;
API.pageForXPath = pageForXPath;
API.lastPageNumber = lastPageNumber;
View
1  src/monocle.css
@@ -35,6 +35,7 @@ div.monelem_sheaf {
/* The iframe within the page that loads the content of the book. */
div.monelem_component {
+
}
View
113 test/locus_nodeobj/index.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <title>Columns test</title>
+
+ <link rel="stylesheet" type="text/css" href="../../src/monocle.css" />
+ <style type="text/css">
+ #reader {
+ position: relative;
+ width: 300px;
+ height: 400px;
+ border: 1px solid #000;
+ background-color: #CCC;
+ overflow: hidden;
+ }
+ </style>
+
+ <!-- MONOCLE CORE -->
+ <script type="text/javascript" src="../../src/monocle.js"></script>
+ <script type="text/javascript" src="../../src/compat.js"></script>
+ <script type="text/javascript" src="../../src/factory.js"></script>
+ <script type="text/javascript" src="../../src/events.js"></script>
+ <script type="text/javascript" src="../../src/styles.js"></script>
+ <script type="text/javascript" src="../../src/reader.js"></script>
+ <script type="text/javascript" src="../../src/book.js"></script>
+ <script type="text/javascript" src="../../src/component.js"></script>
+ <script type="text/javascript" src="../../src/place.js"></script>
+ <script type="text/javascript" src="../../src/framer.js"></script>
+
+ <!-- MONOCLE FLIPPERS -->
+ <script type="text/javascript" src="../../src/controls/panel.js"></script>
+ <script type="text/javascript" src="../../src/panels/twopane.js"></script>
+ <script type="text/javascript" src="../../src/dimensions/columns.js"></script>
+ <script type="text/javascript" src="../../src/flippers/slider.js"></script>
+
+
+ <script>
+ var bd = {
+ getComponents: function () { return ['pt1.html']; },
+ getComponent: function (cmptId) { return { url: cmptId } },
+ getContents: function () { return []; },
+ getMetaData: function (key) { return null; }
+ }
+
+ function getElementByIdWraper(id, doc) {
+ var e = doc.getElementById(id);
+ return e;
+ }
+
+ function getTextnodeInElementById(id, doc) {
+ var e = doc.getElementById("5");
+ return e.childNodes[id];
+ }
+
+ function goElementInComp(compId, id) {
+ var nodeObj = {};
+ nodeObj.node = id;
+ nodeObj.getNode = getElementByIdWraper;
+
+ window.reader.moveTo({ componentId: compId, nodeObj: nodeObj });
+ }
+
+ function goTextnodeInElementInComp(compId, id, offset) {
+ var nodeObj = {};
+ nodeObj.node = id;
+ nodeObj.getNode = getTextnodeInElementById;
+ nodeObj.offset = offset;
+
+ window.reader.moveTo({ componentId: compId, nodeObj: nodeObj });
+ }
+
+ function goToXPath(cmptId, xpath) {
+ window.reader.moveTo({ componentId: cmptId, xpath: xpath });
+ }
+
+ Monocle.Events.listen(
+ window,
+ 'load',
+ function () {
+ window.reader = Monocle.Reader('reader', bd);
+
+ // you can also pass this in init object
+ //window.reader = Monocle.Reader('reader', bd, {place:{ componentId: "p1.html", nodeObj: {node:4, offset:972, getNode:getTextnodeInElementById} }});
+ }
+ );
+ </script>
+ </head>
+ <body>
+
+ <div id="reader"></div>
+
+ <ul>
+ <li>
+ <a href="javascript:goElementInComp('pt1.html', '1');">Headline of Part I</a>
+ </li>
+ <li>
+ <a href="javascript:goElementInComp('pt1.html', '4');">Forth paragraph of Part I</a>
+ </li>
+ <li>
+ <a href="javascript:goTextnodeInElementInComp('pt1.html', 2);">Second textnode in fifth paragraph of Part I</a>
+ </li>
+ <li>
+ <a href="javascript:goTextnodeInElementInComp('pt1.html', 4);">Third textnode in fifth paragraph of Part I</a>
+ </li>
+ <li>
+ <a href="javascript:goTextnodeInElementInComp('pt1.html', 4, 972);">Last word in third textnode in fifth paragraph of Part I</a>
+ </li>
+ </ul>
+
+ </body>
+</html>
View
23 test/locus_nodeobj/pt1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Lorem Ipsum</title>
+ </head>
+ <body>
+ <h3 id="1">
+ I
+ </h3>
+ <p id="2">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer neque neque, varius volutpat cursus vel, tristique vel mi. Etiam tincidunt metus sed libero fringilla venenatis. Suspendisse interdum, neque sit amet fringilla consectetur, nunc nulla accumsan est, vitae porta ligula eros non felis. Donec volutpat viverra metus, eu tincidunt lectus dapibus ac.
+ </p>
+ <p id="3">
+ Sed porttitor tristique libero, at feugiat ligula feugiat ut. Morbi cursus ornare blandit. Suspendisse sit amet sapien metus, sagittis condimentum elit. Sed mollis turpis sed turpis viverra venenatis. Ut viverra dignissim orci, sed egestas nisi lobortis quis. Nulla mi lacus, dictum quis interdum fringilla vitae, pretium sit amet sem. Phasellus vitae ante in mauris varius imperdiet volutpat sed felis. Donec mollis felis vitae magna luctus ut gravida augue luctus. Maecenas suscipit purus id odio euismod porttitor at volutpat purus.
+ </p>
+ <p id="4">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer neque neque, varius volutpat cursus vel, tristique vel mi. Etiam tincidunt metus sed libero fringilla venenatis. Suspendisse interdum, neque sit amet fringilla consectetur, nunc nulla accumsan est, vitae porta ligula eros non felis. Donec volutpat viverra metus, eu tincidunt lectus dapibus ac.
+ </p>
+ <p id="5">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut eget magna tortor, eget ullamcorper orci. Morbi vel odio et enim vestibulum varius. Praesent consequat porttitor augue, et vehicula mi venenatis eu. Curabitur dignissim dictum nulla in dignissim. Etiam et mauris nulla, at gravida augue. Donec quis nulla urna. Donec et diam eu arcu mollis blandit at a libero. Fusce iaculis, neque vitae hendrerit faucibus, odio orci euismod nisi, ut mattis lacus est ac dolor. Proin dictum pellentesque augue, ac lobortis tellus dignissim eget. Suspendisse nec nisl sapien, sit amet imperdiet lorem. Praesent vel lectus et risus mollis aliquet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce nec imperdiet elit. Ut rhoncus purus id leo lobortis faucibus. Maecenas at nulla nibh, vitae vulputate magna. Ut id eleifend tortor. Ut mollis tortor at nisl blandit elementum iaculis metus placerat. <i>Cras sed risus erat. Cras tincidunt massa et tellus rutrum consequat.</i> Pellentesque imperdiet augue sit amet turpis porta quis volutpat tortor mattis. Nunc non arcu quis nisl faucibus tempor. Nullam fringilla nisl et dolor convallis et imperdiet nunc ornare. In dictum fringilla enim, sed ultricies dolor ultrices et. Vestibulum consectetur eleifend viverra. Phasellus tempor tristique erat pharetra viverra. Aliquam varius nulla id risus egestas quis interdum nisi dapibus. Phasellus porttitor, lectus a bibendum feugiat, mi tellus pulvinar augue, a tempor orci urna vitae sapien. Suspendisse ante elit, dictum ut sodales nec, dictum ac sem. Curabitur et porttitor tellus. Morbi dapibus elementum placerat. Sed dui nisl, condimentum non faucibus sed, commodo in sem. Suspendisse non ipsum turpis, et suscipit massa. <i>Proin varius ante quis urna sollicitudin sollicitudin.</i> Vestibulum lectus elit, sagittis sit amet tincidunt eu, rutrum sed urna. Praesent pellentesque mi quis est interdum in congue erat congue. Ut nec felis sed orci sagittis dapibus. Proin orci lorem, viverra non porttitor nec, euismod elementum nunc. Mauris non scelerisque velit. Suspendisse potenti. Cras iaculis dictum elit ut ullamcorper. Integer sed urna pharetra odio semper vulputate eu in elit. Phasellus mollis lectus non nisl rutrum molestie. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut eget magna tortor, eget ullamcorper orci. Morbi vel odio et enim vestibulum varius. Praesent consequat porttitor augue, et vehicula mi venenatis eu. Curabitur dignissim dictum nulla in dignissim. Etiam et mauris nulla, at gravida augue. Donec quis nulla urna. Donec et diam eu arcu mollis blandit at a libero. Fusce iaculis, neque vitae hendrerit faucibus, odio orci euismod nisi, ut mattis lacus est ac dolor.
+ </p>
+ </body>
+</html>
View
25 test/locus_nodeobj/pt2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Lorem Ipsum</title>
+ </head>
+ <body>
+ <h3 id="a">
+ II
+ </h3><p id="b">
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
+</p><p id="c">
+Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
+</p><p id="d">
+Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
+</p><p id="e">
+Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
+</p><p id="f">
+Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
+</p><p id="g">
+At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.
+</p><p id="h">
+Et harum quidem rerum facilis est et expedita distinctio gremlins.
+</p>
+ </body>
+</html>
Something went wrong with that request. Please try again.