I have a form in which some elements are loaded by ajax according to user selection. I try to insert some symbols into the textarea in the form by javascript. I use last focused method with inserttext function. Function only insert symbols into the textarea but not dynamically loaded textarea.Javascript code is at the end of body.
Thanks in advance.
AJAX:
function fetch_no_answer_choice(val){
$.ajax({
type: 'POST',
url: 'fetch_no_answer_choice.php',
data: {'get_option' : val},
success: function (response) {document.getElementById("choice").innerHTML=response;}
});
}
fetch_no_answer_choice.php
<?php
if(isset($_POST['get_option'])){
$choice = $_POST['get_option'];
if ($choice !== 0){
$ans = array('A','B','C','D','E','F','G','H','I','J');
$no = 0;
for ($no = 0; $no<$choice; $no++){
echo'<textarea name = "textarea_'.$ans[$no].'" ></textarea> }
}
exit();
}
?>
JAVASCRIPT
var lastFocused;
$("textarea").focus(function() {
lastFocused = document.activeElement;
});
function insertText(text) {
var input = lastFocused;
console.log(input);
if (input == undefined) { return; }
var scrollPos = input.scrollTop;
var pos = 0;
var browser = ((input.selectionStart || input.selectionStart == "0") ?
"ff" : (document.selection ? "ie" : false ) );
if (browser == "ie") {
input.focus();
var range = document.selection.createRange();
range.moveStart ("character", -input.value.length);
pos = range.text.length;
}
else if (browser == "ff") { pos = input.selectionStart };
var front = (input.value).substring(0, pos);
var back = (input.value).substring(pos, input.value.length);
input.value = front+text+back;
pos = pos + text.length;
if (browser == "ie") {
input.focus();
var range = document.selection.createRange();
range.moveStart ("character", -input.value.length);
range.moveStart ("character", pos);
range.moveEnd ("character", 0);
range.select();
}
else if (browser == "ff") {
input.selectionStart = pos;
input.selectionEnd = pos;
input.focus();
}
input.scrollTop = scrollPos;
}
Related
I'm new to HTML/JS and I'm trying to make a text editor as a small project.
Please forgive me if I'm not explaining my thoughts clearly.
Let's say I have the following text in my contenteditable div environment, and let | represent the cursor (as it would look in most editors):
hi this is some text
here is some mor|e text
hello, world!
How would I be able to return the text "here is some more text"?
I'm using jQuery and I was thinking I want to use the onClick handler, but that doesn't respond to the arrow keys being used to navigate. What kind of event handler would I need? So far, I've parsed the text to replace the div separators, but I'm a bit lost on how to proceed.
What would you suggest doing? (General links/advice also work, I'm trying to learn more through this project)
Edit, here's my html:
<div id="editor" class="editor" contenteditable="true"></div>
here's the JS:
$(document).on('keydown', '.editor', function(e){
//detect 'tab' key
if(e.keyCode == 9){
//add tab
document.execCommand('insertHTML', false, '	');
//prevent focusing on next element
e.preventDefault()
}
var text = $("#editor").html();
console.log("MYLITERAL:" + text);
// parse the string :)
// for the div tags, replacing them with \n
var tmp = text.replace(/<div>/g, "");
tmp = tmp.replace(/<\/div>/g, "");
tmp = tmp.replace(/<br>/g, "\n");
console.log(tmp);
document.getElementById("demo").innerHTML = tmp;
});
You can try the following:
var strO, endO, lstEle;
function selectRange(start, end, this_){
var el = this_,sPos = start,ePos = end;
var charIndex = 0, range = document.createRange();
range.setStart(el, 0);
range.collapse(true);
var nodeStack = [el], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && sPos >= charIndex && sPos <= nextCharIndex) {
range.setStart(node, sPos - charIndex);
foundStart = true;
}
if (foundStart && ePos >= charIndex && ePos <= nextCharIndex) {
range.setEnd(node, ePos - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var s = (window.getSelection) ? window.getSelection() : document.selection;
if(window.getSelection) {
s.removeAllRanges();
s.addRange(range);
} else {
range.select();
}
}
// node_walk: walk the element tree, stop when func(node) returns false
function node_walk(node, func) {
var result = func(node);
for(node = node.firstChild; result !== false && node; node = node.nextSibling){
result = node_walk(node, func);
lstEle = node;
}
return result;
};
// getCaretPosition: return [start, end] as offsets to elem.textContent that
// correspond to the selected portion of text
// (if start == end, caret is at given position and no text is selected)
function getCaretPosition(elem) {
strO = 0, endO = 0, lstEle = elem;
var sel = window.getSelection();
var cum_length = [0, 0];
if(sel.anchorNode == elem)
cum_length = [sel.anchorOffset, sel.extentOffset];
else {
var nodes_to_find = [sel.anchorNode, sel.extentNode];
if(!elem.contains(sel.anchorNode) || !elem.contains(sel.extentNode))
return undefined;
else {
var found = [0,0];
var i;
node_walk(elem, function(node) {
for(i = 0; i < 2; i++) {
if(node == nodes_to_find[i]) {
found[i] = true;
if(found[i == 0 ? 1 : 0])
return false; // all done
}
}
if(node.textContent && !node.firstChild) {
for(i = 0; i < 2; i++) {
if(!found[i])
cum_length[i] += node.textContent.length;
}
}
});
strO = cum_length[0];
endO = strO + lstEle.textContent.length;
cum_length[0] += sel.anchorOffset;
cum_length[1] += sel.extentOffset;
}
}
if(cum_length[0] <= cum_length[1])
return cum_length;
return [cum_length[1], cum_length[0]];
}
var update = function() {
$('#test').html(getCaretPosition(this)+' '+strO+' '+endO);
selectRange(strO, endO, this);
$('#test').append('<br>'+window.getSelection().toString());
};
$('#editor').on("mouseup keydown keyup", update);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="editor" class="editor" contenteditable="true">hi this is some text<br>here is some more text<br>hello, world!</div>
<div id="test">test</div>
I have a small markdown editor
Demo
HTML:
<textarea id="txtarea">this is a **test**</textarea>
<button data-marker="**">Bold (toggle)</button>
<button data-marker="~~">Strike through (toggle)</button>
<button data-marker="*">Italics (toggle)</button>
JS:
function toggleMarker(marker, el) {
var markerLength = marker.length;
var startPos, endPos, selection, range;
if (document.selection != undefined) { // IE
el.focus();
range = document.selection.createRange();
selection = range.text;
} else if (el.selectionStart != undefined) { // Firefox
startPos = el.selectionStart;
endPos = el.selectionEnd;
selection = el.value.substring(startPos, endPos);
}
if (!selection.length){
return;
}
if (el.value.substring(startPos-markerLength,startPos) === marker
&& el.value.substring(endPos,endPos+markerLength) === marker
){
el.value = el.value.substring(0,startPos-markerLength) +
selection +
el.value.substring(endPos+markerLength);
}
else{
el.value = el.value.substring(0,startPos) + marker +
selection + marker + el.value.substring(endPos);
}
}
$(document).on('mousedown', 'button', function(e) {
toggleMarker( $(this).data('marker'), $('#txtarea').get(0) ).text;
});
Now I need to keep the highlighting of pasted text. How can I do that?
http://codepen.io/medinasod/pen/GoOrwq
JS:
var markerLength,
startPos,
endPos,
selection,
range;
function selectText(startPos, endPos, markerLength, marker) {
mytxtarea = document.getElementById("txtarea");
window.setTimeout(function() {
if (mytxtarea.value.substring(startPos-markerLength,startPos) === marker && mytxtarea.value.substring(endPos,endPos+markerLength) === marker) {
mytxtarea.setSelectionRange(startPos+markerLength, endPos+markerLength);
} else {
mytxtarea.setSelectionRange(startPos+markerLength, endPos+markerLength);
}
}, 0);
}
function toggleMarker(marker, el) {
markerLength = marker.length;
if (document.selection != undefined) { // IE
el.focus();
range = document.selection.createRange();
selection = range.text;
} else if (el.selectionStart != undefined) { // Firefox
startPos = el.selectionStart;
endPos = el.selectionEnd;
selection = el.value.substring(startPos, endPos);
}
if (!selection.length){
return;
}
if (el.value.substring(startPos-markerLength,startPos) === marker
&& el.value.substring(endPos,endPos+markerLength) === marker
){
el.value = el.value.substring(0,startPos-markerLength) +
selection +
el.value.substring(endPos+markerLength);
}
else{
el.value = el.value.substring(0,startPos) + marker +
selection + marker + el.value.substring(endPos);
}
selectText(startPos, endPos, markerLength, marker);
}
$(document).on('mousedown', 'button', function(e) {
toggleMarker( $(this).data('marker'), document.getElementById('txtarea'));
});
HTML:
<textarea id="txtarea">this is a test</textarea>
<button data-marker="**">Bold (toggle)</button>
<button data-marker="~~">Strike through (toggle)</button>
<button data-marker="*">Italics (toggle)</button>
When a user enters the URL of any image into the contenteditable div, the code below will automatically convert it into an image (through the img tag on the contenteditable div).
The problem with this is that it converts any URL that the user enters into an image tag.
http://example.com would be converted to `http://example.com
Is there a way to convert ordinary links into links (through the <a> tag) and image URL's inside image tags?
<script>
var saveSelection, restoreSelection;
if (window.getSelection && document.createRange) {
saveSelection = function(containerEl) {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
};
restoreSelection = function(containerEl, savedSel) {
var charIndex = 0, range = document.createRange();
range.setStart(containerEl, 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
} else if (document.selection) {
saveSelection = function(containerEl) {
var selectedTextRange = document.selection.createRange();
var preSelectionTextRange = document.body.createTextRange();
preSelectionTextRange.moveToElementText(containerEl);
preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
var start = preSelectionTextRange.text.length;
return {
start: start,
end: start + selectedTextRange.text.length
}
};
restoreSelection = function(containerEl, savedSel) {
var textRange = document.body.createTextRange();
textRange.moveToElementText(containerEl);
textRange.collapse(true);
textRange.moveEnd("character", savedSel.end);
textRange.moveStart("character", savedSel.start);
textRange.select();
};
}
function createLink(matchedTextNode) {
var el = document.createElement("img");
el.src = matchedTextNode.data;
el.appendChild(matchedTextNode);
return el;
}
function shouldLinkifyContents(el) {
return el.tagName != "A";
}
function surroundInElement(el, regex, surrounderCreateFunc, shouldSurroundFunc) {
var child = el.lastChild;
while (child) {
if (child.nodeType == 1 && shouldSurroundFunc(el)) {
surroundInElement(child, regex, createLink, shouldSurroundFunc);
} else if (child.nodeType == 3) {
surroundMatchingText(child, regex, surrounderCreateFunc);
}
child = child.previousSibling;
}
}
function surroundMatchingText(textNode, regex, surrounderCreateFunc) {
var parent = textNode.parentNode;
var result, surroundingNode, matchedTextNode, matchLength, matchedText;
while ( textNode && (result = regex.exec(textNode.data)) ) {
matchedTextNode = textNode.splitText(result.index);
matchedText = result[0];
matchLength = matchedText.length;
textNode = (matchedTextNode.length > matchLength) ?
matchedTextNode.splitText(matchLength) : null;
surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true));
parent.insertBefore(surroundingNode, matchedTextNode);
parent.removeChild(matchedTextNode);
}
}
var textbox = document.getElementById("text");
var urlRegex = /http(s?):\/\/($|[^ ]+)/;
function updateLinks() {
surroundInElement(textbox, urlRegex, createLink, shouldLinkifyContents);
}
var $textbox = $(textbox);
$(document).ready(function () {
$textbox.focus();
var keyTimer = null, keyDelay = 1000;
$textbox.keyup(function() {
if (keyTimer) {
window.clearTimeout(keyTimer);
}
keyTimer = window.setTimeout(function() {
updateLinks();
keyTimer = null;
}, keyDelay);
});
});
</script>
I would like to create a function that select a given text inside a HTML element.
For example calling selectText('world') would select world in a markup like <span>Hello </span><strong>world</strong>!
Lots of answers on similar questions suggests to use range and selection but none of them work in my case (some would select all the text, some won't work with such markup, ...).
For now this is what I have (it doesn't work):
function selectText ( element, textToSelect ) {
var text = element.textContent,
start = text.indexOf( textToSelect ),
end = start + textToSelect.length - 1,
selection, range;
element.focus();
if( window.getSelection && document.createRange ) {
range = document.createRange();
range.setStart( element.firstChild, start );
range.setEnd( element.lastChild, end );
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange( range );
} else if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText( element );
range.moveStart( 'character', start );
range.collapse( true );
range.moveEnd( 'character', end );
range.select();
}
}
Here is a jsfiddle so you see what is actually happening: http://jsfiddle.net/H2H2p/
Outputed error :
Uncaught IndexSizeError: Failed to execute 'setStart' on 'Range': The offset 11 is larger than or equal to the node's length (5).
P.S.: no jQuery please :)
You could use a combination of your approach of finding the text within the element's textContent and this function.
Demo: http://jsfiddle.net/H2H2p/3/
Code:
function selectText(element, textToSelect) {
var elementText;
if (typeof element.textContent == "string" && document.createRange && window.getSelection) {
elementText = element.textContent;
} else if (document.selection && document.body.createTextRange) {
var textRange = document.body.createTextRange();
textRange.moveToElement(element);
elementText = textRange.text;
}
var startIndex = elementText.indexOf(textToSelect);
setSelectionRange(element, startIndex, startIndex + textToSelect.length);
}
function getTextNodesIn(node) {
var textNodes = [];
if (node.nodeType == 3) {
textNodes.push(node);
} else {
var children = node.childNodes;
for (var i = 0, len = children.length; i < len; ++i) {
textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
}
}
return textNodes;
}
function setSelectionRange(el, start, end) {
if (document.createRange && window.getSelection) {
var range = document.createRange();
range.selectNodeContents(el);
var textNodes = getTextNodesIn(el);
var foundStart = false;
var charCount = 0, endCharCount;
for (var i = 0, textNode; textNode = textNodes[i++]; ) {
endCharCount = charCount + textNode.length;
if (!foundStart && start >= charCount
&& (start < endCharCount ||
(start == endCharCount && i < textNodes.length))) {
range.setStart(textNode, start - charCount);
foundStart = true;
}
if (foundStart && end <= endCharCount) {
range.setEnd(textNode, end - charCount);
break;
}
charCount = endCharCount;
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.selection && document.body.createTextRange) {
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(true);
textRange.moveEnd("character", end);
textRange.moveStart("character", start);
textRange.select();
}
}
I have a div tag in my page that could have an arbitrary amount of child nodes. But there is a certain length at which i need to slice it and only show the sliced text. This is the code i have:
var myDiv = document.getElementById("myDiv")
var range = document.body.createTextRange();
range.moveToElementText(myDiv);
range.move("character",150);
range.text = "!!!";
var html = myDiv.innerHTML;
html = html.slice(0,html.indexOf("!!!"));//+"...";
myDiv.innerHTML = html;
I am doing it this way so that i can conserve the html on the value of the div and at the same time i can make sure that i am not slicing in between a tag. This works fine in IE but obviously dosent so in firefox. Can anybody help me with giving me a equivalent code for firefox.
Thanks in advance!
Here's some code to extract the HTML for the first 150 characters of a <div>. It's based on this answer and the same caveats about the naivete of the implementation apply.
Live demo: http://jsfiddle.net/mrEme/2/
Code:
function getTextNodesIn(node) {
var textNodes = [];
if (node.nodeType == 3) {
textNodes.push(node);
} else {
var children = node.childNodes;
for (var i = 0, len = children.length; i < len; ++i) {
textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
}
}
return textNodes;
}
function copyCharacterRange(srcEl, destEl, start, end) {
if (document.createRange && window.getSelection) {
var range = document.createRange();
range.selectNodeContents(srcEl);
var textNodes = getTextNodesIn(srcEl);
var foundStart = false;
var charCount = 0, endCharCount;
for (var i = 0, textNode; textNode = textNodes[i++]; ) {
endCharCount = charCount + textNode.length;
if (!foundStart && start >= charCount
&& (start < endCharCount ||
(start == endCharCount && i < textNodes.length))) {
range.setStart(textNode, start - charCount);
foundStart = true;
}
if (foundStart && end <= endCharCount) {
range.setEnd(textNode, end - charCount);
break;
}
charCount = endCharCount;
}
destEl.appendChild(range.cloneContents());
range.detach();
} else if (document.selection && document.body.createTextRange) {
var textRange = document.body.createTextRange();
textRange.moveToElementText(srcEl);
textRange.collapse(true);
textRange.moveEnd("character", end);
textRange.moveStart("character", start);
destEl.innerHTML = textRange.htmlText;
}
}
var srcEl = document.getElementById("src");
var destEl = document.getElementById("dest");
copyCharacterRange(srcEl, destEl, 0, 150);