setting document position
- 12 replies.
- This is not yet resolved.
- This question was started by Trevor.
- Last post by Trevor.
|
member
May 11th 2010
|
I have a Xopus Editor html page which contains an edit frame into which the xml document to edit is loaded. This is done by calling
editFrame.contentWindow.Editor.getActiveCanvas().loadDocument(myurl); If myurl is something like "myfile.xml#Links" I would like to open myfile.xml in the edit frame, and scroll immediately to the anchor named "Links". The anchor does exist; the XSL transform from xml to html generates named anchors for all id'ed elements. How can I implement this? Thanks |
|
Xopus Team
May 12th 2010
|
Interesting idea!
The following code does this: var originalLoadXMLFunction = IO.getLoadXMLFunction(); var hashPart; function getHashPart(uri) { var hashPos = uri.indexOf("#"); if (hashPos > -1) { hashPart = uri.substr(hashPos); uri = uri.substr(0, hashPos); } return originalLoadXMLFunction(uri); } IO.setLoadXMLFunction(getHashPart); function scrollToId() { if (hashPart) setTimeout(function () { document.location = hashPart; }, 100); Editor.removeEventListener("afterRedraw", scrollToId); } Editor.addEventListener("afterRedraw", scrollToId); However, when testing this I noticed that it would be easier if the cursor would jump to the node with the id. (And scrolling then happens automatically.) Replace the last part of the above code with this: function scrollToId(evt) { Editor.removeEventListener("xmlContextChange", scrollToId); var node = Editor.getActiveCanvas().getDocument().selectSingleNode("/ if (node) { var rng = Editor.Selection.getRange(); rng.selectNode(node); rng.collapse(true); Editor.Selection.setRange(rng); } } Editor.addEventListener("xmlContextChange", scrollToId); |
|
member
May 12th 2010
|
Cool, thanks!
I am having two problems with this, though. Firstly, the code causes Xopus to think that the document has been modified, because the save button is already enabled when the document is displayed, and if the user navigates away the "unsaved edits" dialog appears. Secondly, if the user navigates away and then requests to edit again - either the same document and location, or a different location, or even a different document entirely, the scroll/redraw doesn't happen. I've checked the code very carefully and it matches yours precisely - and it is working the first time in, of course. Is there something we have overlooked? |
|
member
May 12th 2010
|
One more thing; the display is scrolling so that the given element (an anchor placed immediately before a title, normally) is at the very bottom of the window. Is there a method that would position it at the top instead?
Sorry to be tiresome; this would be a neat feature if we could get it right. Cheers T |
|
member
May 14th 2010
|
OK, here's the relevant part of my config.js as of today:
var originalLoadXMLFunction = IO.getLoadXMLFunction(); var hashPart; function getHashPart( uri ) { var hashPos = uri.indexOf( "#" ); if ( hashPos > -1 ) { hashPart = uri.substr( hashPos ); uri = uri.substr( 0, hashPos ); } else { // without next line get null object error on opening xopus.html hashPart = "#"; } return originalLoadXMLFunction( uri ); } IO.setLoadXMLFunction( getHashPart ); function scrollToId( evt ) { // only scroll once on load Editor.removeEventListener( "xmlContextChange", scrollToId ); // this is the element AFTER the id var node = Editor.getActiveCanvas().getDocument().selectSingleNode("/ if ( node ) { var rng = Editor.Selection.getRange(); rng.selectNode( node ); rng.collapse( true ); Editor.Selection.setRange( rng ); } } Editor.addEventListener( "load", myLoadHandler ); function myLoadHandler( evt ) { // re-establish scroll on each new load Editor.addEventListener( "xmlContextChange", scrollToId ); } This code has the following problems: 1. On the first document load the scroll happens, but the save button is enabled in the Xopus toolbar before the user types anything. A ctrl-Z clears the breadcrumb trail in the status line and disables the button, but I'm not sure why Xopus thinks the document has changed. 2. Load a different document (or reload the same document) and scrolling does not happen, instead the user sees a scripting error which says: Line: 1 Char: 1 Error: 'null' is null or not an object Code: 0 URL: ../xopus/xopus.html 3. Strangely, if the url passed to xopus's load includes a non-existent #anchor, this error doesn't happen! 4. Not an error, but a quibble; the method used here to show more than a few pixels of the given id is a bit unsatisfactory, but I can't see a better way to achieve what I would like (which is to position the fragment corresponding to the given id at the top of the window). Thank you for your help so far! Cheers T |
|
Xopus Team
May 14th 2010
|
1. This is an Xopus bug. You can work around it by doing the setRange in a setTimeout.
2/3. Then the getRange probably returns null. 4. This can be fixed by getting the corresponding html node, and calling scrollIntoView on it. This code has these fixes applied: var originalLoadXMLFunction = IO.getLoadXMLFunction(); var hashPart; function getHashPart(uri) { var hashPos = uri.indexOf("#"); if (hashPos > -1) { hashPart = uri.substr(hashPos); uri = uri.substr(0, hashPos); Editor.addEventListener("xmlContextChange", scrollToId); } return originalLoadXMLFunction(uri); } IO.setLoadXMLFunction(getHashPart); function scrollToId(evt) { Editor.removeEventListener("xmlContextChange", scrollToId); var node = Editor.getActiveCanvas().getDocument().selectSingleNode("//*[@id='" + hashPart.substr(1) + "']"); if (node) { var rng = Editor.Selection.getRange(); if (!rng) { // try again Editor.addEventListener("xmlContextChange", scrollToId); return; } rng.selectNode(node); rng.collapse(true); setTimeout(function() { Editor.Selection.setRange(rng); var htmlNode = Editor.getHTMLElementsForXMLNode(node)[0]; if (htmlNode) htmlNode.scrollIntoView(true); }, 0); } } |
|
member
May 14th 2010
|
Editor.getHTMLElementsForXMLNodeAha! This method needs to be documented :-)Thanks very much T |
|
member
May 14th 2010
|
need to redraw or somethingworking brilliantly - with one caveat.On the load of the initial url everything is perfect. The document opens and immediately scrolls to the correct location. However when a second url is loaded the xml context change (the event we listen for to trigger the scroll-into-view) doesn't happen until the user clicks in this new document. At that point they suddenly find the document redrawn (and if they were trying to select a word they find they have selected a huge chunk of the document!) Thus: on the initial load the xml context change is fired without user input, but on subsequent loads it is not. What do you suggest as a solution here? |
|
Xopus Team
May 15th 2010
|
Documented, you mean like this?
http:/ The only reason I used xmlContextChange is that the API really is missing a createRange method, and the only way to get one is getRange, which in this case apparently often returns null. It works the first time, so the script could be adapted to reuse that range. I'll give it a shot when I'm back at work on Tuesday, unless you get it working before then. |
|
member
May 17th 2010
|
> Documented, you mean like this?
Sorry, I must have missed it. Intuitively "context change" isn't the right event to use for this feature, but "load" (which makes more sense to me) didn't seem to work when I tried it. The redraw event has empty documentation so I've no idea whether it is a sensible option or not - but I'll try it next :-) |
|
Xopus Team
May 18th 2010
|
Another tryvar originalLoadXMLFunction = IO.getLoadXMLFunction();var hashPart; var range; function getHashPart(uri) { var hashPos = uri.indexOf("#"); if (hashPos > -1) { hashPart = uri.substr(hashPos); uri = uri.substr(0, hashPos); Editor.addEventListener("xmlContextChange", scrollToId); } return originalLoadXMLFunction(uri); } IO.setLoadXMLFunction(getHashPart); function scrollToId(evt) { if (!range) { range = Editor.Selection.getRange(); if (!range) return; } Editor.removeEventListener("xmlContextChange", scrollToId); var node = Editor.getActiveCanvas().getDocument().selectSingleNode("//*[@id='" + hashPart.substr(1) + "']"); if (node) { range.selectNode(node); range.collapse(true); setTimeout(function() { Editor.Selection.setRange(range); var htmlNode = Editor.getHTMLElementsForXMLNode(node)[0]; if (htmlNode) htmlNode.scrollIntoView(true); }, 0); } } |
|
member
May 18th 2010
|
:-)Brilliant!Thank you so much T |
|
member
May 26th 2010
|
minor issue with thisXopus opens the document for editing and scrolls to the specified anchor. If the user clicks anywhere in the visible area of the document Xopus behaves correctly. However if the user drags the scrollbar up or down to display a different region and then clicks in the document, Xopus jumps and displays the cursor (or the highlight) somewhere else. For example, if I scroll up a page and click at the beginning of a line in the middle of the view, Xopus will redisplay the document so that the line I clicked in is the very first visible line - but the cursor will be near the end of the line. If instead of clicking in the line I double click a word in a line Xopus will suddenly scroll up and highlight a completely different word several paragraphs below where I was clicking.It is not the scrollToId listener that is doing this, because an alert in the listener is displayed when the document opens, and not displayed when the user clicks. It appears to be one of the default listeners which is generating this wrong behaviour after we have scrolled our anchor into view. Any ideas? |
- Support
- › Forum
- › How To ...
- › setting document position
React
Write a comment