Getting highlighted text + position in document

Discussion in 'Javascript' started by JE, Jul 24, 2004.

  1. JE

    JE Guest

    Hi!


    I am snooping around all sorts of websites and faqs, in search of a way to
    pick up any selected (mouse-highlighted) text in a HTML page, and store it
    in a JavaScript variable.

    I have found an excellent site which actually has a great cross-platform
    script for doing just this;

    http://www.quirksmode.org/js/selected.html

    My problem is that I also need the position of the selected text within
    the document. I am finishing a Perl program for editing HTML content, and
    I'd like to use such a script to submit words/paragraphs back to the
    program, requesting HTML formatting tags. E.g. user selects "very
    important", clicks the BOLD button. Then JS gets the text and its
    position which is submitted to the Perl program, which adds <B></B> tags,
    and refreshes the document.

    Without the positions, I naturally get all occurrences of "very important"
    in the document in boldface...

    Please have a look at the two-liner script snippet in the Quirksmode
    document. Is there any way to access position info without losing
    cross-platform stability?


    Your help would be greatly appreciated! I would love to see this idea
    work.



    Sincerely,

    Joakim Knudsen

    Norway

    --


    Remove nospam to reply!
    JE, Jul 24, 2004
    #1
    1. Advertising

  2. JE wrote:

    > My problem is that I also need the position of the selected text within
    > the document. I am finishing a Perl program for editing HTML content, and
    > I'd like to use such a script to submit words/paragraphs back to the
    > program, requesting HTML formatting tags. E.g. user selects "very
    > important", clicks the BOLD button. Then JS gets the text and its
    > position which is submitted to the Perl program, which adds <B></B> tags,
    > and refreshes the document.


    This is not a simple problem; the position you're looking for in your
    Perl program is a text-based one. However, you only have access to a
    serialized source on the client, which means that the position defined
    in regards of text isn't really an interesting one, and can vary across
    user agents.

    If it is acceptable to you to have the "bold" part be done client side
    (and it should be since you rely on client objects to start the whole
    process), then you could go for a client-side solution, using ranges -
    submitting the serialized source to the Perl program afterwards, if
    history is needed.

    Ranges' models differ between IE and W3C models; IE's model is
    text-oriented, offering a great deal of useful methods to directly
    manipulate the text, while the W3C's one is more node-oriented, thus
    requiring more code to achieve similar results (reorganizing, splitting
    nodes etc).


    ---

    <pre style="text-align:center">
    Trois allumettes une à une allumées dans la nuit
    La première pour voir ton visage tout entier
    La seconde pour voir tes yeux
    La dernière pour voir ta bouche
    Et l'obscurité tout entière pour me rappeler tout cela
    En te serrant dans mes bras
    </pre>

    <input type="button" value="Make Bold" onclick="makeBold()">

    <script type="text/javascript">
    var makeBold = function() {

    function getSel() {
    if(window.getSelection) return window.getSelection();
    else if(typeof document.selection!="undefined")
    return document.selection;
    }

    function getSelectionRange() {
    var sel=getSel();
    if(sel) {
    if(sel.getRangeAt && sel.rangeCount) return sel.getRangeAt(0);
    else if(sel.createRange) return sel.createRange();
    }
    }

    function emptySelection(){
    var sel=getSel();
    if(sel) {
    if(sel.empty) sel.empty();
    else if(sel.removeAllRanges) sel.removeAllRanges();
    }
    }

    function _makeBold(){
    var rng=getSelectionRange();

    if(rng) {
    if(rng.execCommand) {
    rng.execCommand("bold");
    } else if(rng.extractContents){
    var endc=rng.endContainer;
    var action=1; // make bold
    var b, src=rng.extractContents();

    do {
    if(endc.nodeName.toLowerCase()=="b") {
    action=0; // unbold
    break;
    }
    } while((endc=endc.parentNode));

    if(action==1){
    b=document.createElement("b");
    b.appendChild(src);
    rng.insertNode(b);
    } else {
    rng.insertNode(
    function(nodeList, parent){
    parent=parent||document.createDocumentFragment();
    for(var ii=0;ii<nodeList.length;ii++)
    parent.appendChild(
    arguments.callee(
    nodeList[ii].childNodes,
    nodeList[ii].nodeName.toLowerCase()=="b" ?
    null : nodeList[ii--]
    )
    );
    return parent;
    }(src.childNodes)
    );
    }
    emptySelection();
    }
    }
    return true;
    }

    function doNothing() {
    return false;
    }

    return typeof getSel()!="undefined" ? _makeBold : doNothing;
    }();
    </script>

    ---


    HTH
    Yep.
    Yann-Erwan Perio, Jul 25, 2004
    #2
    1. Advertising

  3. JE

    JE Guest

    Hi!

    I looked at your solution, and it worked!
    Still, I have trouble understanding your code, with all the DOM tree
    manipulations. Plus I need to save the changes in style in a database, so
    I would like to do the change at server-side; i.e. inserting <b></b>
    tags...


    - Joakim



    In article <4102f3f9$0$29382$>,
    wrote:

    > JE wrote:
    >
    > > My problem is that I also need the position of the selected text within
    > > the document. I am finishing a Perl program for editing HTML content, and
    > > I'd like to use such a script to submit words/paragraphs back to the
    > > program, requesting HTML formatting tags. E.g. user selects "very
    > > important", clicks the BOLD button. Then JS gets the text and its
    > > position which is submitted to the Perl program, which adds <B></B> tags,
    > > and refreshes the document.

    >
    > This is not a simple problem; the position you're looking for in your
    > Perl program is a text-based one. However, you only have access to a
    > serialized source on the client, which means that the position defined
    > in regards of text isn't really an interesting one, and can vary across
    > user agents.
    >
    > If it is acceptable to you to have the "bold" part be done client side
    > (and it should be since you rely on client objects to start the whole
    > process), then you could go for a client-side solution, using ranges -
    > submitting the serialized source to the Perl program afterwards, if
    > history is needed.
    >
    > Ranges' models differ between IE and W3C models; IE's model is
    > text-oriented, offering a great deal of useful methods to directly
    > manipulate the text, while the W3C's one is more node-oriented, thus
    > requiring more code to achieve similar results (reorganizing, splitting
    > nodes etc).
    >
    >
    > ---
    >
    > <pre style="text-align:center">
    > Trois allumettes une à une allumées dans la nuit
    > La première pour voir ton visage tout entier
    > La seconde pour voir tes yeux
    > La dernière pour voir ta bouche
    > Et l'obscurité tout entière pour me rappeler tout cela
    > En te serrant dans mes bras
    > </pre>
    >
    > <input type="button" value="Make Bold" onclick="makeBold()">
    >
    > <script type="text/javascript">
    > var makeBold = function() {
    >
    > function getSel() {
    > if(window.getSelection) return window.getSelection();
    > else if(typeof document.selection!="undefined")
    > return document.selection;
    > }
    >
    > function getSelectionRange() {
    > var sel=getSel();
    > if(sel) {
    > if(sel.getRangeAt && sel.rangeCount) return sel.getRangeAt(0);
    > else if(sel.createRange) return sel.createRange();
    > }
    > }
    >
    > function emptySelection(){
    > var sel=getSel();
    > if(sel) {
    > if(sel.empty) sel.empty();
    > else if(sel.removeAllRanges) sel.removeAllRanges();
    > }
    > }
    >
    > function _makeBold(){
    > var rng=getSelectionRange();
    >
    > if(rng) {
    > if(rng.execCommand) {
    > rng.execCommand("bold");
    > } else if(rng.extractContents){
    > var endc=rng.endContainer;
    > var action=1; // make bold
    > var b, src=rng.extractContents();
    >
    > do {
    > if(endc.nodeName.toLowerCase()=="b") {
    > action=0; // unbold
    > break;
    > }
    > } while((endc=endc.parentNode));
    >
    > if(action==1){
    > b=document.createElement("b");
    > b.appendChild(src);
    > rng.insertNode(b);
    > } else {
    > rng.insertNode(
    > function(nodeList, parent){
    > parent=parent||document.createDocumentFragment();
    > for(var ii=0;ii<nodeList.length;ii++)
    > parent.appendChild(
    > arguments.callee(
    > nodeList[ii].childNodes,
    > nodeList[ii].nodeName.toLowerCase()=="b" ?
    > null : nodeList[ii--]
    > )
    > );
    > return parent;
    > }(src.childNodes)
    > );
    > }
    > emptySelection();
    > }
    > }
    > return true;
    > }
    >
    > function doNothing() {
    > return false;
    > }
    >
    > return typeof getSel()!="undefined" ? _makeBold : doNothing;
    > }();
    > </script>
    >
    > ---
    >
    >
    > HTH
    > Yep.


    --


    Remove nospam to reply!
    JE, Jul 25, 2004
    #3
  4. JE wrote:

    > Plus I need to save the changes in style in a database, so
    > I would like to do the change at server-side; i.e. inserting <b></b>
    > tags...


    I can understand the feeling, however doing the change server-side would
    be highly difficult, since the position has some sense on the client
    only, in the DOM. You could of course do some text analysis on a
    serialized DOM (say, obtained by innerHTML) also taking into account
    nesting issues, or transmit a node/offset object then rebuild the
    position server-side using a DOM parser, but as you can see this would
    be a real pain to implement.

    Actually, you don't need to do the change server-side to keep the
    history; once the user has highlighted the text as required, he just has
    to submit a form which will retrieve the source client-side (be it the
    serialized source from innerHTML or, maybe better, a manually built
    source from the DOM tree) and post it to the server.


    Slightly tested only:

    ---
    <pre id="text">
    <b>He<i>ll</i>o</b>, World!
    </pre>

    <form action="foo" method="post" onsubmit="return saveChanges(this)">
    <input type="hidden" name="textModified" value="">
    <input type="submit" value="Save changes">
    </form>

    <script type="text/javascript">
    function saveChanges(frm){
    if(document.getElementById &&
    document.body &&
    document.body.childNodes &&
    typeof document.body.nodeValue!="undefined") {

    var root=document.getElementById("text");
    var txt=[];
    var getHTML = function(node) {
    var buf=[];
    if(node.nodeType==1){
    buf.push("<"+node.nodeName+">");
    for(var ii=0; ii<node.childNodes.length; ii++)
    buf.push(arguments.callee(node.childNodes[ii]));
    buf.push("<\/"+node.nodeName+">");
    } else if(node.nodeType==3){
    buf.push(node.nodeValue);
    }
    return buf.join("");
    }

    //frm.elements["textModified"].value=root.innerHTML;
    for(var j=0; j<root.childNodes.length; j++)
    txt.push(getHTML(root.childNodes[j]));
    frm.elements["textModified"].value=txt.join("");
    return true;
    }
    return false;
    }
    </script>
    ---
    Yann-Erwan Perio, Jul 25, 2004
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. MARTIN Herve \(EXT\)

    Text editor with keywords highlighted

    MARTIN Herve \(EXT\), Nov 3, 2003, in forum: Java
    Replies:
    2
    Views:
    339
    MARTIN Herve \(EXT\)
    Nov 3, 2003
  2. wcc
    Replies:
    3
    Views:
    326
  3. Replies:
    35
    Views:
    1,207
    Mark A. Boyd
    Aug 31, 2008
  4. msngirgi
    Replies:
    1
    Views:
    484
    msngirgi
    Aug 10, 2009
  5. studen771
    Replies:
    3
    Views:
    109
    studen771
    Mar 31, 2005
Loading...

Share This Page