2

I'm working on a JavaScript extension that is supposed to wrap the selected text somehow and send it to my server. The "wrapping" is done so that the server can identify the exact position of the highlighted text, even if there were duplicates.

I followed this link, How to change CSS of selected text using Google Chrome Extension, to be able to obtain the selected text. Afterwards I followed this approach, How to get selected html text with javascript?, specifically the chosen answer, to obtain the innerHTML. The problem is that when the selection is across different divs, it breaks the DOM, or just as zyklus said in that answer "WILL have side effects from breaking nodes in half and creating an extra span".

As an example,

    <div id="IntroDiv">
        <p>
            <img src="http://localhost:9000/Theme/Images/Intro/logo.png">
            <br><br>
            A neat th<f5e975aa551d1ae4e91e8ce9><div id="IntroDiv"><p>eme for start-ups and small corporations.
        </p>
    </div>

    <div id="ProjectsSlider">
        <div id="ProjectsSliderContent">

            <p class="Title">Projects</p>
            <p class="Subtitle">Samples O</p></div></div></f5e975aa551d1ae4e91e8ce9>eme for start-ups and small corporations.
        </p>
    </div>

    <div id="ProjectsSlider">
        <div id="ProjectsSliderContent">

            <p class="Title">Projects</p>
            <p class="Subtitle">Samples Of Our Work</p>

            <div id="SliderContainer">
                <div class="LeftArrow"></div>
                <div class="RightArrow"></div>
                <div class="ThreeD swiper-container stop-swiping">
                    <div class="swiper-wrapper swiper-no-swiping" style="width: 2365px; height: 285px; transform: translate3d(-430px, 0px, 0px); -webkit-transform: translate3d(-430px, 0px, 0px); transition-duration: 0s; -webkit-transition-duration: 0s;"><div class="swiper-slide swiper-slide-duplicate" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -336px) rotateX(0deg) rotateY(-75deg); -webkit-transform: translate3d(0px, 0px, -336px) rotateX(0deg) rotateY(-75deg); z-index: -2; background-image: url(http://placehold.it/215x270/);">Project 3</div><div class="swiper-slide swiper-slide-duplicate" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -224px) rotateX(0deg) rotateY(-50deg); -webkit-transform: translate3d(0px, 0px, -224px) rotateX(0deg) rotateY(-50deg); z-index: -1; background-image: url(http://placehold.it/215x270/);">Project 4</div><div class="swiper-slide swiper-slide-duplicate swiper-slide-visible swiper-slide-active" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -112px) rotateX(0deg) rotateY(-25deg); -webkit-transform: translate3d(0px, 0px, -112px) rotateX(0deg) rotateY(-25deg); z-index: 0; background-image: url(http://placehold.it/215x270/);">Project 5</div> <!-- Add your slides here. You're free to have different styles or content -->
                        <div class="swiper-slide swiper-slide-visible" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, 0px) rotateX(0deg) rotateY(0deg); -webkit-transform: translate3d(0px, 0px, 0px) rotateX(0deg) rotateY(0deg); z-index: 1; background-image: url(http://placehold.it/215x270/);">Project 1</div>
                        <div class="swiper-slide swiper-slide-visible" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -112px) rotateX(0deg) rotateY(25deg); -webkit-transform: translate3d(0px, 0px, -112px) rotateX(0deg) rotateY(25deg); z-index: 0; background-image: url(http://placehold.it/215x270/);">Project 2</div>
                        <div class="swiper-slide" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -224px) rotateX(0deg) rotateY(50deg); -webkit-transform: translate3d(0px, 0px, -224px) rotateX(0deg) rotateY(50deg); z-index: -1; background-image: url(http://placehold.it/215x270/);">Project 3</div>
                        <div class="swiper-slide" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -336px) rotateX(0deg) rotateY(75deg); -webkit-transform: translate3d(0px, 0px, -336px) rotateX(0deg) rotateY(75deg); z-index: -2; background-image: url(http://placehold.it/215x270/);">Project 4</div>
                        <div class="swiper-slide" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -448px) rotateX(0deg) rotateY(100deg); -webkit-transform: translate3d(0px, 0px, -448px) rotateX(0deg) rotateY(100deg); z-index: -3; background-image: url(http://placehold.it/215x270/);">Project 5</div>
                    <div class="swiper-slide swiper-slide-duplicate" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -560px) rotateX(0deg) rotateY(125deg); -webkit-transform: translate3d(0px, 0px, -560px) rotateX(0deg) rotateY(125deg); z-index: -4; background-image: url(http://placehold.it/215x270/);">Project 1</div><div class="swiper-slide swiper-slide-duplicate" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -672px) rotateX(0deg) rotateY(150deg); -webkit-transform: translate3d(0px, 0px, -672px) rotateX(0deg) rotateY(150deg); z-index: -5; background-image: url(http://placehold.it/215x270/);">Project 2</div><div class="swiper-slide swiper-slide-duplicate" style="width: 215px; height: 285px; transition-duration: 0ms; -webkit-transition-duration: 0ms; transform: translate3d(0px, 0px, -784px) rotateX(0deg) rotateY(175deg); -webkit-transform: translate3d(0px, 0px, -784px) rotateX(0deg) rotateY(175deg); z-index: -6; background-image: url(http://placehold.it/215x270/);">Project 3</div></div>

                    <div class="SeePhotos"></div>
                </div>
            </div>

            <ul id="ThreeDSwiperBullets"><li id="0" class="active"></li><li id="1"></li><li id="2"></li><li id="3"></li><li id="4"></li></ul> <!-- Where slider bullets are automatically added according to the slider by JavaScript, Index.js file -->
        </div>
    </div>

I use f5e975aa551d1ae4e91e8ce9 here to identify the text, just as any kind of unique text that most probably will not exist in a usual web page. As you see above, "IntroDiv" is there twice, as well as "ProjectsSlider". That's the same part of the page before calling any functions.

    <div id="IntroDiv">
        <p>
            <img src="Theme/Images/Intro/logo.png">
            <br/><br/>
            A neat theme for start-ups and small corporations.
        </p>
    </div>

    <div id="ProjectsSlider">
        <div id="ProjectsSliderContent">

            <p class="Title">Projects</p>
            <p class="Subtitle">Samples Of Our Work</p>

            <div id="SliderContainer">
                <div class="LeftArrow"></div>
                <div class="RightArrow"></div>
                <div class="ThreeD swiper-container stop-swiping">
                    <div class="swiper-wrapper swiper-no-swiping">  <!-- Add your slides here. You're free to have different styles or content -->
                        <div class="swiper-slide" style="background-image:url('http://placehold.it/215x270/');">Project 1</div>
                        <div class="swiper-slide" style="background-image:url('http://placehold.it/215x270/');">Project 2</div>
                        <div class="swiper-slide" style="background-image:url('http://placehold.it/215x270/');">Project 3</div>
                        <div class="swiper-slide" style="background-image:url('http://placehold.it/215x270/');">Project 4</div>
                        <div class="swiper-slide" style="background-image:url('http://placehold.it/215x270/');">Project 5</div>
                    </div>

                    <div class="SeePhotos"></div>
                </div>
            </div>

            <ul id="ThreeDSwiperBullets"></ul> <!-- Where slider bullets are automatically added according to the slider by JavaScript, Index.js file -->
        </div>
    </div>

That's my code.

//save_last_element.js    
document.body.addEventListener('contextmenu', function(e) {
    LAST_SELECTION = window.getSelection().getRangeAt(0);
}, false);


//script.js
if (LAST_SELECTION) {
    var mySelection = LAST_SELECTION.cloneRange();

    var selectionContents = mySelection.cloneContents();
    var div = document.createElement("f5e975aa551d1ae4e91e8ce9");
    div.appendChild(selectionContents);
    mySelection.insertNode(div);
}

Is there a way to avoid messing up the DOM? Can I somehow identify the position of the selected text by a completely different approach?

Community
  • 1
  • 1
TheNavigat
  • 864
  • 10
  • 30

2 Answers2

3

So, after a lot of trying, I could do it.

    var myAnchorNodeValue = window.getSelection().anchorNode.nodeValue;
    var myAnchorOffset = window.getSelection().anchorOffset
    var myFocusOffset =  window.getSelection().focusOffset

    var myFocusNodeLength = window.getSelection().focusNode.nodeValue.length;

    window.getSelection().anchorNode.nodeValue = myAnchorNodeValue.slice(0, myAnchorOffset) + "[IDENTIFY]" + myAnchorNodeValue.slice(myAnchorOffset);

    var myFocusNodeValue = window.getSelection().focusNode.nodeValue;

    if(window.getSelection().focusNode.nodeValue.length - myFocusNodeLength > 0) {
        myFocusOffset += window.getSelection().focusNode.nodeValue.length - myFocusNodeLength;
    }

    window.getSelection().focusNode.nodeValue = myFocusNodeValue.slice(0, myFocusOffset) + "[/IDENTIFY]" + myFocusNodeValue.slice(myFocusOffset);

    LAST_SELECTION = window.getSelection().getRangeAt(0);
    myDocument = document.documentElement.innerHTML;

That worked perfectly.

TheNavigat
  • 864
  • 10
  • 30
  • 1
    Nice one! Though I think it is important to mention that [`Selection.anchorNode` is not part of an official spec as of yet](https://developer.mozilla.org/en-US/docs/Web/API/Selection.anchorNode) and to this day only supported by Firefox and Chrome. – Lukas Bünger Jan 27 '15 at 20:04
1

To extract the selected text, you could walk the selection for text nodes only and concatenate them.

var content = window.getSelection().getRangeAt(0).cloneContents();
var treeWalker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT);
var text = '';

while (treeWalker.nextNode()) { 
    text = text.concat(treeWalker.currentNode.nodeValue);
}
console.log(text);

EDIT

How to wrap a selection with an identifier string:

String.prototype.splice = function( idx, rem, s ) {
    return (this.slice(0,idx) + s + this.slice(idx + Math.abs(rem)));
};

var range = window.getSelection().getRangeAt(0);
range.startContainer.nodeValue = range.startContainer.nodeValue.splice(range.startOffset, 0, '[highlight]');
range.endContainer.nodeValue = range.endContainer.nodeValue.splice(range.endOffset, 0, '[/highlight]');

splice courtesy of this post

Community
  • 1
  • 1
Lukas Bünger
  • 4,257
  • 2
  • 30
  • 26
  • Again, "The whole problem is with identifying the text inside the DOM. Using the text only approach, if the user selected a word that was there multiple times in the DOM, I want to identify the one he actually selected, and not a wrong one, and not all of them." – TheNavigat Jan 27 '15 at 16:21
  • Now I really don't get it. This one would only extract all text within the selection and not all text in the DOM. Whether "a word is in the DOM (or the selection) multiple times" or not kind of doesn't have anything to do with selections IMHO. – Lukas Bünger Jan 27 '15 at 16:24
  • Well, the point is that I need to send the whole DOM to the server. It should add a background/border/or whatever to the selected text and host the whole MHTML page. Right now sending the MHTML page works and the only problem is identifying the place of the selected text itself so that I can style it the way I want to. Sorry for being a bit confusing. – TheNavigat Jan 27 '15 at 16:29
  • Does the identifying wrapper have to be a DOM node? Otherwise you just could use string identifiers. In the mean time I'll think on something to wrap the selected text/nodes with an actual node. – Lukas Bünger Jan 27 '15 at 16:41
  • No, it doesn't have to be. By "string identifiers", what do you mean exactly? – TheNavigat Jan 27 '15 at 16:44
  • Like wrapping the selection with something like `[highlight]...[/highlight]`. That wouldn't trouble the DOM and could still be processed by the server. – Lukas Bünger Jan 27 '15 at 16:46
  • Can you try showing how can that be done in code? The point is that by extracting it, it becomes messed up, and I don't know how can I add some identification strings without extracting it. – TheNavigat Jan 27 '15 at 16:49