Firefox select text range - javascript

A quick question: how do I programatically select the text fragment of the page in FireFox? For example, there's a paragraph of text, user clicks the button and symbols from 10-th to 15-th are selected as if user dragged a mouse in a regular way.

In Firefox, you can use the Range object, as specified by W3C.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Range test</title>
<style>
#trigger { background: lightgreen }
</style>
</head>
<body>
<p id="test">This is some (rather short) text.</p>
<span id="trigger">→ Click here! ←</span>
<!-- Yes, I know, ‘Click here!’ is an evil message -->
<script>
var testCase = function () {
var userSelection;
if (window.getSelection) { // W3C default
userSelection = window.getSelection();
} // an extra branch would be necessary if you want to support IE
var textNode = document.getElementById('test').firstChild;
var theRange = document.createRange();
// select 10th–15th character (counting starts at 0)
theRange.setStart(textNode, 9);
theRange.setEnd(textNode, 14);
// set user selection
userSelection.addRange(theRange);
};
window.onload = function () {
var el = document.getElementById('trigger');
el.onclick = testCase;
};
</script>
</body>
</html>
Note that you have to get the TextNode to set the selection, which is the firstChild of the <p> element. Also note that this example will not work in IE, you have to use some proprietary methods. A nice introduction is on QuirksMode.

I'm not sure if there's a way to do it for arbitrary DOM elements like paragraphs, but for textarea elements, I believe you need to use the selectionStart and selectionEnd properties and specify where to start and end.
var textarea = document.getElementsByTagName('textarea')[0];
textarea.selectionStart = 10;
textarea.selectionEnd = 15;
Hope this helps!

Related

Is it possible to select text from multiple elements?

Using a java script, you can make a selection. This will be equivalent to selecting with the mouse cursor. The code that I added to the question makes a selection of each element inside the container you click on, but the previous selection disappears. Can this be changed?
const selectElement = (element) =>
{
const range = document.createRange();
range.selectNode(element);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
const container = document.getElementById("container");
container.addEventListener('click', (event) =>
{
const x = event.pageX;
const y = event.pageY;
selectElement(document.elementFromPoint(x, y));
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Code snippet</title>
</head>
<body>
<div id="container">
<div id="firstElement">
First element text
</div>
<div id="secondElement">
Second element text
</div>
</div>
</body>
</html>
EDIT:
For better understanding, I added a second snippet that does what I would like to get, but without using a window.getSelection().addRange().
const selectElement = (element) =>
{
element.style.backgroundColor = 'blue';
element.style.color = 'white';
}
const container = document.getElementById("container");
container.addEventListener('click', (event) =>
{
const x = event.pageX;
const y = event.pageY;
selectElement(document.elementFromPoint(x, y));
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Code snippet</title>
</head>
<body>
<div id="container">
<div id="firstElement">
First element text
</div>
<div id="secondElement">
Second element text
</div>
</div>
</body>
</html>
Accpording to the other answer and MDN it only works in FF.
https://stackoverflow.com/a/70175542/4860688
https://developer.mozilla.org/en-US/docs/Web/API/Selection/addRange#example
But, here is how to do it in FF:
Moving focus and/or clicking on elements typically (always?) removes the previous selection as per pretty standard UI selection behaviour.
If you wanted to retain the previous selection range(s) then you will need to store them separately and re-add them to the window's selection ranges.
Obviously this is counter intuitive to any user expectation but I'm not going to presume anything about why you want this :)
var ranges = [];
const selectElement = (element) =>
{
const range = document.createRange();
range.selectNode(element);
ranges.push(range);
const selection = window.getSelection();
ranges.forEach(r => selection.addRange(r));
}
const container = document.getElementById("container");
container.addEventListener('click', (event) =>
{
selectElement(event.target);
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Code snippet</title>
</head>
<body>
<div id="container">
<div id="firstElement">
First element text
</div>
<div id="secondElement">
Second element text
</div>
</div>
</body>
</html>
Note that if you click outside your container div, the selections are cleared - this is the standard behaviour and since your event listener is only on the div, the selections are not restored. If you want to change that, move your event listener to the body.

Summernote how to focus at end of text

I'm currently using summernote 0.8.2, and I'm using a note which is preloaded with text. When the text loads, I would like it to focus but focus at the end of the line. I tried doing focusing based on the API. However, I tried focusing but it doesn't start at the end of the line. Below is an example of what I tried doing based on this question. Please help. (I would like the cursor to be after "item 2")
$("#myNote").summernote({
toolbar: [
['para', ['ul']]
],
focus: true
});
$('.note-editor [data-event="insertUnorderedList"]').tooltip('disable');
$('.note-btn.btn.btn-default.btn-sm').attr('data-original-title','');
var html = "<ul><li>item 1</li><li>item 2<br></li></ul>";
$("#myNote").summernote('code',html);
$("#myNote").focus();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.2/summernote.js"></script>
<script>
$(document).ready(function () {
$.fn.extend({
placeCursorAtEnd: function () {
// Places the cursor at the end of a contenteditable container (should also work for textarea / input)
if (this.length === 0) {
throw new Error("Cannot manipulate an element if there is no element!");
}
var el = this[0];
var range = document.createRange();
var sel = window.getSelection();
var childLength = el.childNodes.length;
if (childLength > 0) {
var lastNode = el.childNodes[childLength - 1];
var lastNodeChildren = lastNode.childNodes.length;
range.setStart(lastNode, lastNodeChildren);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
return this;
}
});
});
</script>
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.2/summernote.css" rel="stylesheet"/>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet"/>
<div id="myNote"></div>
Instead of calling the focus method on the initialized Summernote editor, try calling the custom jQuery method placeCursorAtEnd instead.
I'm doing something along these lines myself:
var $el = this.$el;
$el.find('.inline-preview .component-text-editor')
.summernote(this.advancedEditor)
$el.find('[contenteditable]').placeCursorAtEnd();
Where this.advancedEditor is an options object which is passed to our summernote initialization method.
placeCursorAtEnd() as recommended in the answers is the custom module in the question.
We created a webdesigner based on Summernote with another integration of the functionality.
Sommernote uses a DIV element instead of a TEXTAREA and this restricts otherwise possible solutions for the cursor positioning.
For placeCursorAtEnd() please
Focus on the element.
lastNode may not have childNodes. In this case use the length of lastNode.
Use range.collapse(false) for end and not true for start.
Use scrollTop = 999999 for the element to scroll the end into view.

assign selected text to a variable in designMode

I have a piece of code that sets the document to designMode and then operates on pieces of selected text using the document.execCommand() function.
It provides various functionality - for example it allows the user to turn a selected line of text to bold or italic (essentially the functionality of a text editor like this one that I am typing into now).
Here is a simplified example of the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div>
This is some text - highlight a section of it and press h1 then li
</div>
<button onclick="setToHeader()" id="h1" style="width:100px" unselectable="on">h1</button>
<button onclick="setToList()" id="li" style="width:100px" unselectable="on">li</button>
<script>
document.designMode = 'on';
function setToHeader() {
document.execCommand('formatBlock', false, 'h1');
}
function setToList() {
document.execCommand('insertUnorderedList', false, null);
}
</script>
</body>
</html>
My problem here is that I do not want to be able to use the li button - i.e. convert the selected text to list format, when it is already converted into heading format with the h1 button.
I think I want to be able to read the selected text and simply check it with something like:
// var selectedText = ???
var isHeading = selectedText.search('h1') > -1
Is this the way, or is there a better approach?
How can I get hold of the relevant selected text and assign it to a variable?
You need a little bit more effort. Need to use jquery also, check it out:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div>This is some text - highlight a section of it and press h1 then li </div>
<div>This is some other text - highlight a section of it and press h1 then li </div>
<button onclick="setToHeader()" id="h1" style="width:100px" unselectable="on">h1</button>
<button onclick="setToList()" id="li" style="width:100px" unselectable="on">li</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
document.designMode = 'on';
setInterval(function () {
var el = getSelectionContainerElement();
if($(el).is('h1')){
$("#li").attr("disabled", true);
}
else
{
$("#li").attr("disabled", false);
}
}, 100);
function setToHeader() {
document.execCommand('formatBlock', false, 'h1');
}
function setToList() {
document.execCommand('insertUnorderedList', false, null);
}
function getSelectionContainerElement() {
var range, sel, container;
if (document.selection && document.selection.createRange) {
// IE case
range = document.selection.createRange();
return range.parentElement();
} else if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt) {
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0);
}
} else {
// Old WebKit selection object has no getRangeAt, so
// create a range from other selection properties
range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
// Handle the case when the selection was selected backwards (from the end to the start in the document)
if (range.collapsed !== sel.isCollapsed) {
range.setStart(sel.focusNode, sel.focusOffset);
range.setEnd(sel.anchorNode, sel.anchorOffset);
}
}
if (range) {
container = range.commonAncestorContainer;
// Check if the container is a text node and return its parent if so
return container.nodeType === 3 ? container.parentNode : container;
}
}
}
</script>
</body>
</html>
You can get hold of the selected text using the selection object.
e.g. in IE11:
getSelection()
Full documentation can be found here:
https://msdn.microsoft.com/en-us/library/ms535869(v=vs.85).aspx

selected text editing

I am a iPhone app developer.I am changing the color of selected text. This is working fine for me. But when there are few repeated words for example
Hi All.Hello world.I am iPhone app developer.Hello world.Stack overflow.Hello world.
Here 'Hello' text is repeating. When i am selecting last 'Hello' text it is giving me first 'Hello' text index. I tried indexOf(),search() and anchorOffset() but this is not working.
Following is my code.
function heighlightText(data) {
var selectedText = window.getSelection();
var textd=$("#data").html(); // this will give me whole text.
var normalText = $("#data").text();
var startPosition = normalText.search(selectedText); // this will give selected text start position.
var getPosition = selectedText.toString();
var endPosition = parseInt(getPosition.length) + parseInt(startPosition); // this will give selected text end position.
var textToReplace = "<span id='" + startPosition + "' class='highlightedText' onclick=\"myOnclikFunction('"+selectedText+"')\"> "+selectedText+"</span>";
var startPart = textd.substr(0,startPosition);
var lastPart = textd.substr(endPosition,textd.length);
var reT = startPart + textToReplace + lastPart;
$("#data").html(reT);
}
Hy HTML:
<style type = "text/css">
#data {
font-size : 20px;
color : black;
}
.highlightedText {
background-color : red;
}
</style>
<body>
<div id = "data" >Lots of text here...
<div/>
</body>
Can any one suggest solution for this.
Thanks in advance.
If you're just colouring the text, then Stefan's answer is the most reliable and easiest way:
document.execCommand("ForeColor", false, "#0000FF");
However, it looks as though you're adding a class and a click handler, so you need more flexibility.
First, there is no way to get a selection as offsets within an HTML representation of the DOM reliably. You can get the selection as offsets within nodes directly via anchorOffset, anchorNode, focusOffset and focusNode, or as a DOM range. If the selection is completely contained within a single text node, you can use the range's surroundContents() method:
Demo: http://jsfiddle.net/UvBTq/
Code:
function highlightText(data) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
var selectedText = range.toString();
var span = document.createElement("span");
span.id = "span_" + range.startOffset + "_" + range.endOffset;
span.className = "highlightedText";
span.onclick = function() {
myOnclikFunction(selectedText);
};
range.surroundContents(span);
// Restore selection
selection.removeAllRanges();
selection.addRange(range);
}
}
However, this is very brittle and will only work when the selection is completely contained within a single text node. Depending on what you're trying to do, you may need a more flexible solution.
To get the selected text, you have to use the getSelection javascript method. i don't know if that method is available on iphone browser, but here is a general function that combines the methods for all browsers.
function getSelected() {
var text = "";
if (window.getSelection
&& window.getSelection().toString()
&& $(window.getSelection()).attr('type') != "Caret") {
text = window.getSelection();
return text;
}
else if (document.getSelection
&& document.getSelection().toString()
&& $(document.getSelection()).attr('type') != "Caret") {
text = document.getSelection();
return text;
}
else {
var selection = document.selection && document.selection.createRange();
if (!(typeof selection === "undefined")
&& selection.text
&& selection.text.toString()) {
text = selection.text;
return text;
}
}
return false;
}
found here
Use contenteditable="true" and document.execCommand('ForeColor', false, 'YOURCOLOR'); instead
Example:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>- jsFiddle demo</title>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>
<script type='text/javascript'>
$(function () {
$('#color').click(function () {
document.execCommand('ForeColor', false, '0000FF');
});
});
</script>
</head>
<body>
<p contenteditable="true">Hello world</p>
<button id="color">Change Color</button>
</body>
</html>
Fiddler: http://jsfiddle.net/WQKCw/1/

Detect if text is bold

I'm trying to make a WYSIWYG editor, and so far I have it so you can select text and click 'Make Bold' to make the selected text bold. It literally just wraps < b> (no space) tags around the selected text. But my problem is that if I want to un-bold that, my script has some trouble...
So far, here is my script:
<script language="javascript">
function format(tag) //defines function format
{
var editor = document.getElementById('editor');
var txt = '';
var tester = document.getElementById('tester');
if (window.getSelection) //if your browser uses this method of text selection
{
txt = window.getSelection();
}
else if (document.getSelection) //if your browser uses this method of text selection
{
txt = document.getSelection();
}
else if (document.selection) //if your browser uses this method of text selection
{
txt = document.selection.createRange().text;
}
else return; //Return this
matched = editor.innerHTML.match(txt); //Find the selected text in the editor
// if (matched.style.font-weight = "600") {tester.innerHTML = "already bold";} //if the selected text is bold, say 'already bold' DOES NOT WORK
// else {tester.innerHTML = "not bold";} //if it doesn't...
editor.innerHTML = editor.innerHTML.replace(matched,"<"+tag+">"+matched+"</"+tag+">");//Wrap <b> tags around it
}
</script>
<input type="button" value="Make Bold" onmousedown="format('b')">
<input type="button" value="Make Italic" onmousedown="format('i')">
<div id='editor' onclick="javascript:this.designMode='on';" designmode="on" contenteditable="true">Edit Box</div>
<span id="tester">testing span</span>
If you try it out you can type in that box and select text and click Make Bold and it will be bold. Now click Make Bold again but nothing happens. It's just adding another < b> tag around the selected text. I want it to make it un-bold; normal.
How do I do that?
Thanks :)
Messing with the HTML as a string is a bad idea. There are two better options: the first is to obtain the element containing the current user selection and use DOM methods and properties such as parentNode to test if it's bold. This is tricky to do cross-browser. Much easier is to use the execCommand method of document, which will automatically toggle boldness. It's supported in recent versions of all major browsers.
document.execCommand("bold", false, null);
UPDATE
Note that in Firefox (and possibly other browsers), this has no effect unless the document has designMode switched on. Here's a full example. Highlight some text and press Ctrl-B:
<html>
<head>
<title>Test</title>
<script type="text/javascript">
window.onload = function() {
document.designMode = "on";
};
function keyDown(evt) {
if (evt.keyCode == 66 && evt.ctrlKey) {
document.execCommand("bold", false, "");
}
return false;
}
</script>
</head>
<body onkeydown="return keyDown(event);">
<div>I like tea <b>with milk</b></div>
</body>
</html>

Categories

Resources