Javascript edit text in selection via Bookmarklet - javascript

I am trying to make a simple bookmarklet (bookmark with javascript applet) that will get the selected text, reverse it, and then change it on screen. For example, if the user selects some text, say, the word hello, and then activates this bookmarklet, the text would then turn into olleh. So far I have the following:
javascript:
function getSelectedText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
var selectedText = getSelectedText();
var textArray = selectedText.split("");
var reverseArray = textArray.reverse();
var reverseText = reverseArray.join("");
alert(reverseText);
I got the getSelectedText() function from here. At the end, the bookmarklet simply alerts the reversed text. How do you make it so that it actually replaces the text on the page? Thanks in advance for any possible help.

You can add this to the end:
var nodeValue = window.getSelection().baseNode.nodeValue;
window.getSelection().baseNode.nodeValue = nodeValue.replace(selectedText, reverseText);
EDIT
Use selection offset for reversing in the right place, str.replace only replaces the first occurrence of the word, and it can be wrong for common words such as "the".
var selection = window.getSelection();
var start = selection.anchorOffset;
var end = selection.focusOffset;
var nodeValue = selection.baseNode.nodeValue;
var newValue = nodeValue.slice(0, start) + reverseText + nodeValue.slice(end);
window.getSelection().baseNode.nodeValue = newValue;

Related

Add html tags around highligted text in contenteditable div

I have a contenteditable div and i would like to add some html tags around highlighted text, after user select the text and click the button..
Here is the sample code. It has some javascript codes but i couldnt make it work as desired. And i played with a lot actually.
https://codepen.io/anon/pen/ybzzXZ
P.S. I'm going to add , or like html tags after when we solve the how to add html tags around it.
Some of that js codes which i found in stackoverflow.
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().text;
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
and the other one is
function replaceSelectionWithHtml(html) {
var range;
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
range.deleteContents();
var div = document.createElement("div");
div.innerHTML = html;
var frag = document.createDocumentFragment(), child;
while ( (child = div.firstChild) ) {
frag.appendChild(child);
}
range.insertNode(frag);
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.pasteHTML(html);
}
}
There are several challenges with the problem you present.
First off you need to gather the selected text value. You have posted some examples of that - that is fairly well documented elsewhere so I will leave that up to you to isolate that issue.
Next you need to highlight the selected text. Often to highlight something in HTML we wrap that text that we wish to highlight in a simple element such as a span, then give that span some class - for example often this is used to give a background color to some text. <span style='background-color:yellow'>some text</span> - not so difficult to understand that portion.
The challenge with this then is to combine your "discovered text" with the highlight. Pretty easy to wrap that text as in the span example provided earlier. One issue however is that if that text is previously within some other HTML elements, we need to ensure that the text choice in the discovery is for example not contained within another element AND if so, handle that issue. Let's illustrate that with this span: Howdy <span style='background-color:yellow'>some text</span> Some more.
Now for this example suppose we wish to highlight the text "Howdy some" - a portion of that text is previously within a span with our desired markup, thus we must first extract that, remove that "highlight" and henceforth highlight the new text "choice" of "Howdy some".
To provide an illustration of that. Type the words "This I want" into the text box and see how it gets highlighted.
This is not exactly your problem however it provides the "highlight" which you could potentially combine with your selector. I have NOT fully vetted this for bugs such as typing in HTML in to "highlight".
/* highlight words */
function findStringLimit(searchChar, searchCharIndex, searchedString) {
return searchedString.substring(0, searchedString.lastIndexOf(searchChar, searchCharIndex));
};
function highlightWords(wordsy, text) { /* eliminate a bug with parenthesis */
wordsy = wordsy.replace("(", "");
wordsy = wordsy.replace(")", ""); /* escape other characters for bug */
text = text.replace(";", "");
text = text.replace("'", "'");
text = text.replace("<", "<");
text = text.replace(">", ">");
text = text.replace("<span", "<span");
text = text.replace('autoCompleteWord">', 'autoCompleteWord">');
text = text.replace("</span", "</span");
text = text.replace('span>', 'span>');
var re = '(' + wordsy + ')(?![^<]*(?:<\/span class=\"autoCompleteWord\"|>))';
var regExp = new RegExp(re, 'ig');
var sTag = '<span class="autoCompleteWord">';
var eTag = "</span>";
return text.replace(regExp, sTag + '$&' + eTag);
};
function parseAndHighlight(wordstring, htmlString) {
var htmlStringUn = htmlString;
var found = htmlStringUn.toLowerCase().indexOf(wordstring.toLowerCase(), 0);
if (found >= 0) {
htmlStringUn = highlightWords(wordstring, htmlStringUn);
}
else {
//split and parse the beast
var words = wordstring.split(/\W+/);
var allPhrases = [];
allPhrases.push(wordstring);
var i = 0;
i = words.length;
while (i--) {
allPhrases.push(findStringLimit(" ", allPhrases[(words.length - i) - 1].length, allPhrases[(words.length - i) - 1]));
};
i = allPhrases.length;
while (i--) {
if (allPhrases[i] != "") words = words.concat(allPhrases[i]);
};
i = words.length;
while (i--) {
htmlStringUn = highlightWords(words[i], htmlStringUn);
};
};
return htmlStringUn;
}
$(document).on('change', '#myInput', function() {
var myValue = $('#myInput').val(); //get what was typed
$('#found').text(myValue);
myValue = myValue.replace(/^\s+|\s+$/g, ""); //strip whitespace on ends
$('#found').text(myValue + ':stripped:');
var showText = $('#origshower').text();
var newShowString = parseAndHighlight(myValue, showText); //my original highlighter
$('#shower').html(newShowString);
});
#holder{border:red solid 2px; padding: 5px;}
#myInput{width:200px; background-color: aqua;}
span.autoCompleteWord /* this is the word(s) found */
{
font-weight: bold;
background-color: yellow;
}
#shower{border:lime 2px solid;}
<script
src="https://code.jquery.com/jquery-1.12.4.min.js"
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
crossorigin="anonymous"></script>
<div id='holder'>
<input id='myInput' type='text' cols='60' rows='2' />Enter Text to match
</div>
<div id='origshower'>This is the span thistle with the whistle that I want matched is this neat</div>
<div id='shower'>none</div>
<div id='found'>enter</div>
You can just call executeCommand with formatBlock. You can find more information here:
https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Add element w/ text node after user selection

I have the following function that creates a new text node at the end of a document when called, using the value of text within a text field:
function addAfter () {
var elem = document.getElementById('textfield').value;
var h = document.createElement('span');
var t = document.createTextNode(elem);
h.appendChild(t);
document.body.appendChild(h);
}
What I would like it to do would be to add the text immediately after user-selected text (like when you click and drag to select text). What needs to replace the document.body.appendChild(h); for this to work?
Try This JS Fiddle
This should do it on anything but IE edge(I believe)
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
document.body.addEventListener('mouseup', function() {
(window.getSelection()) ? addText(window.getSelection().toString(), window.getSelection().baseNode.parentNode) : addText(document.selection.toString(), document.selection.baseNode.parentNode);
});
function addText(text, parent) {
parent.appendChild(document.createTextNode(text));
}
The way that this works is it uses the mouseUp event to determine whether or not text MAY have been selected. Selected text is stored underneath window.getSelected() OR document.selected() - it then passes that value as well as the parent of the selected text to the addText function. It uses the document appendChild and createTextNode methods to append the captured text to the DOM.
In Previous Versions of IE they used document.select(), but in Edge they switched over to getSelection(like everyone else) BUT they didn't implement the same value that's returned when you get text, ergo you can't really grab the parentNode and easily append to that node.
So, in short, this will give you what you're looking for, but it's not cross-browser and there doesn't appear to be a way to do that easily.
I manipulated a solution that I found on another feed.
function addAfter (isBefore) {
var sel, range, node;
var changeText = document.getElementById('textfield').value;
var textAndCode = "<span class=\"correction\"> " + changeText + " </span>";
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = window.getSelection().getRangeAt(0);
range.collapse(isBefore);
// Range.createContextualFragment() would be useful here but was
// until recently non-standard and not supported in all browsers
// (IE9, for one)
var el = document.createElement("div");
el.innerHTML = textAndCode;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.collapse(isBefore);
range.pasteHTML(textAndCode);
}
}
You just have to pass in the value for isBefore as false if you want it to appear after.

Split div content at cursor position

I need to split an element after user clicks on it and the attr 'contenteditable' becomes 'true'. This fiddle works for the first paragraph but not second because the latter is in a p tag. Similary in this fiddle you will see that when the element has html tags in it, the counter loses accuracy and hence the text before and after the cursor is not what you'd expect.
The assumption here is that the users will split the data in a way that the help tags will stay intact. As pointed out by dandavis here, e.g. the div has <i>Hello</i> <b>Wo*rld</b>, the user will only need to split the div into two divs, first will have <i>Hello</i> and the second div will have <b>Wo*rld</b> in it.
Html:
<div><mark>{DATE}</mark><i>via email: </i><mark><i>{EMAIL- BROKER OR TENANT}</i></mark></div>
JS:
var $splitbut = $('<p class="split-but">Split</p>');
$(this).attr('contenteditable', 'true').addClass('editing').append($splitbut);
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
}
var start = userSelection.anchorOffset;
var end = userSelection.focusOffset;
var before = $(this).html().substr(0, start);
var after = $(this).html().substr(start, $(this).html().length);
The "Split" button is not working as generating the html is not an issue once I get proper "after" and "before" text. Any ideas as to what I am doing wrong here?
Something like this could work for the specific case you describe
$('div, textarea').on('click', function(e) {
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
}
var start = userSelection.anchorOffset,
end = userSelection.focusOffset,
node = userSelection.anchorNode,
allText = $(this).text(),
nodeText = $(node).text();
// before and after inside node
var nodeBefore = nodeText.substr(0, start);
var nodeAfter = nodeText.substr(start, nodeText.length);
// before and after for whole of text
var allExceptNode = allText.split(nodeText),
before = allExceptNode[0] + nodeBefore,
after = nodeAfter + allExceptNode[1];
console.log('Before: ', before);
console.log('------');
console.log('After: ', after);
});
Updated demo at https://jsfiddle.net/gaby/vaLz55fv/10/
It might exhibit issues if there are tags whose content is repeated in the whole text. (problem due to splitting)

How do I highlight and save text in HTML using JavaScript?

I want to highlight text and save the selection so that next time I view the page, it will display with the same text highlighted.
I tried to get the index of selected text but the index is related only to the HTML tag, not related to all the page text. This is what I have:
<script>
function highlight() {
range = window.getSelection();
var st = range.anchorOffset;
var en = range.focusOffset - range.anchorOffset;
alert(st);
alert(en);
}
</script>
I don't know how to get selected text attributes which can help me to save my highlight in the next open to the HTML file.
Here's what I found. For reference, here is a good post about this topic.
JSFiddle
JS:
var copiedText = "";
$(function(){
$("button").click(function(event){
getSelectionText();
alert(copiedText);
});
});
function getSelectionText() {
if (window.getSelection) {
copiedText = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
copiedText = document.selection.createRange().text;
}
}

Finding indices of highlighted text

I'm trying to save information about text that a user has highlighted in a webpage. Currently I'm using the getSelection method shown below:
var txt = '';
if (window.getSelection){txt = window.getSelection();}
else if (document.getSelection){txt = document.getSelection();}
else if (document.selection){txt = document.selection.createRange().text;}
else return;
to retrieve the highlighted text. Then I'm searching through the entire text body and storing the indices of the highlighted text. The getSelection method only returns what text is highlighted so the problem is that if the highlighted text appears multiple times in the text body, the search could find the wrong repeat of the text and thus save the wrong indices.
Any ideas how to ensure that I'm saving the right indices?
Thanks!
QuirksMode has an article about this.
You'd probably be interested in this code:
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
}
else if (document.selection) { // should come last; Opera!
userSelection = document.selection.createRange();
}
var rangeObject = getRangeObject(userSelection);
function getRangeObject(selectionObject) {
if (selectionObject.getRangeAt)
return selectionObject.getRangeAt(0);
else { // Safari!
var range = document.createRange();
range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode,selectionObject.focusOffset);
return range;
}
}

Categories

Resources