return character position on page?

J

jen_designs

Is there a way to return the character position on a page? Not the x
and y coordinates, but the number of characters on a page. For
instance i have a html page with the following text: This is my string.
Then character postion for m would be 9. Any thoughts?
 
Y

Yann-Erwan Perio

Is there a way to return the character position on a page? Not the x
and y coordinates, but the number of characters on a page. For
instance i have a html page with the following text: This is my string.
Then character postion for m would be 9.

What a strange request:)

To answer straightly, yes you can do it, first by retrieving the text of
the document, then by searching the chars within the text.

You have many ways to retrieve the text:
- documents are represented by trees of nodes (elements), which kind of
mirror the structure of your HTML page. What you can do is therefore to
identify the "text" elements, retrieve their value and concatenate all
values;
- some browsers (IE, Opera) offer an "innerText" property, which
directly gives the text contained in an element;
- some browsers (IE, Mozilla) support "text ranges", which are also a
good way to get the text from nodes.

Once you've retrieved the text you just have to apply string methods or
regular expressions to find your chars, but you won't be able to do much
afterwards (like highlighting or whatever).

Just out of curiosity, why do you exactly need the positions? Given the
structure of the DOM I cannot really think of a practical application.


<div>Hello, World!</div>
<div>This is my string</div>

<form action="">
<input type="text">
<input
type="button"
value="getCharPosition()"
onclick="alert(getCharPosition(this.form.elements[0].value));">
</form>

<script type="text/javascript">
var getCharPosition = (function(){
function getTextFromNode(node){
if(typeof node.innerText!="undefined") return node.innerText;
else
return function(N){
for(var ii=0, s="", c=N.childNodes;ii<c.length;ii++) {
if(c[ii].nodeType==3) s+=c[ii].nodeValue;
else if(
c[ii].nodeType==1 &&
c[ii].nodeName.toLowerCase()!="script"
) s+=arguments.callee(c[ii]);
}
return s;
}(node);
}

return function(token) {
if(
token.length>0 &&
document.body && (
typeof document.body.innerText!="undefined" ||
document.body.childNodes &&
document.body.nodeName
)
){
var txt=getTextFromNode(document.body).replace(/\r|\n/g,"");
var match;
var re=new RegExp(token, "gi");
var positions=[];
while((match=re.exec(txt))!=null) {
positions[positions.length]=match.index+1;
}
return positions.length==0 ?
"No char found." :
"Char(s) found at " + positions.join(" - ");
} else {
return "Cannot find char position!";
}
}
})();
</script>


HTH,
Yep.
 
J

jen_designs

I am using it to store what a users selects or highlights within a html
page. That position plus the length of the highlight will then be
passed to an application to be stored so that when they revisit the
page, what the user selected will still be highlighted. The app needs
the postion on the page, as well as the length of the highlight.
 
L

Lee

(e-mail address removed) said:
I am using it to store what a users selects or highlights within a html
page. That position plus the length of the highlight will then be
passed to an application to be stored so that when they revisit the
page, what the user selected will still be highlighted. The app needs
the postion on the page, as well as the length of the highlight.

And you're absolutely sure the page contents will never change?
Nobody will ever correct a typo, throwing off the character count?
 
Y

Yep

(e-mail address removed) wrote:

Hi,
I am using it to store what a users selects or highlights within a html
page. That position plus the length of the highlight will then be
passed to an application to be stored so that when they revisit the
page, what the user selected will still be highlighted. The app needs
the postion on the page, as well as the length of the highlight.

I'm starting to see what you want, however I'm afraid you won't be be
able to do it the way you want, given the way the page is parsed
client-side: basically you manipulate nodes, not text.

What I can suggest is the following: capture the user selection, alter
the tree, store the altered tree in a DB with the username, and send
the altered tree back when requested by the user. The code below should
work in IE/Mozilla (slightly tested only, I'm on my way to holidays).

Given the nature fo the text to be highlighted, then you might consider
sending only a part of the tree, or even adopt a text-based highlight
(is there's no more than 1 occurrence of the text in your page - you
still don't tell the "real" why:)).


---
<script type="text/javascript">
var SelectionManager = (function() {
var MARKER_CLASS="markerClass";

function getSel(){
var sel=null;
if(
typeof document.selection!="undefined" &&
document.selection &&
document.selection.type=="Text"
){
sel=document.selection;
} else if(
window.getSelection &&
window.getSelection().rangeCount>0
){
sel=window.getSelection();
}
return sel;
}

function createRange(){
var rng=null;
if(document.body && document.body.createTextRange) {
rng=document.body.createTextRange();
} else if(document.createRange) {
rng=document.createRange();
}
return rng;
}

function moveRange(rng, el){
var moved=false;
if(rng.moveToElementText){
rng.moveToElementText(el);
moved=true;
} else if(rng.selectNodeContents) {
rng.selectNodeContents(el);
moved=true;
}
return moved;
}

function selectRange(rng){
if(rng.select){
rng.select();
} else if(window.getSelection) {
var sel=window.getSelection();
if(sel && sel.removeAllRanges && sel.addRange) {
sel.removeAllRanges();
sel.addRange(rng);
}
}
}

function createRangeFromSel(sel){
var rng=null;
if(sel.createRange) {
rng=sel.createRange();
} else if(sel.getRangeAt) {
rng=sel.getRangeAt(0);
if(rng.toString()=="") rng=null;
}
return rng;
}

function markRange(rng){
var marked=false;
if(rng.pasteHTML){
rng.pasteHTML(
"<span class='"+MARKER_CLASS+"'>"+rng.text+"<\/span>"
);
marked=true;
} else if(rng.extractContents){
var span=document.createElement("span");
span.className=MARKER_CLASS;
span.appendChild(rng.extractContents());
rng.insertNode(span);
marked=true;
}
return marked;
}

function createSelectionFromNode(node){
var rng=createRange();
if(rng){
if(moveRange(rng, node)){
selectRange(rng);
}
}
}

document.onmouseup = function(evt){
var sel=getSel(), rng;
if(sel) {
rng=createRangeFromSel(sel);
if(rng) {
SelectionManager.lastSelection=rng;
}
}
}

return {
lastSelection : null,
markLastSelection : function() {
return this.lastSelection && markRange(this.lastSelection);
},
highlightSelection : function() {
if(document.getElementsByTagName){
var span=document.getElementsByTagName("span");
for(var ii=span.length; ii--;) {
if(span[ii].className.indexOf(MARKER_CLASS)!=-1) {
createSelectionFromNode(span[ii]);
break;
}
}
}
}
};
})();

function submitHandler(frm){
frm.elements['SelectionInfo'].value=
SelectionManager.markLastSelection()?document.body.innerHTML:"";
return true;
}

window.onload = function(evt){
SelectionManager.highlightSelection();
}
</script>

<div>Hello, World!</div>

<form action="foo" onsubmit="return submitHandler(this)">
<input type="hidden" name="SelectionInfo">
<input type="submit" value="Send selection">
</form>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top