How to parse editable DIV's text with browser compatibility - javascript

I make div as editable. while i tried to parse div's text, i was needed to do the below regular expression.
innerDOM = "<div style="cursor: text;">I had downloaded all the material from the Intern,<br>You will find</div><div style="cursor: text;"> </div><div style="cursor: text;">dfvdfvdvdfvdfvdvdvdf</div><div style="cursor: text;"> </div><div style="cursor: text;">dfvdfvdvdfvdfvdfvdfvd</div>"
innerDOM.replace(/<div style="cursor: text">/g, "<br>").replace(/<\/div>/g, "");
Above regular expression works good in firefox and chrome. But not in IE. What changes should i do?
See this FIDDLE for better understanding...

DOM manipulation is one of the things jQuery was made for. Investing in learning jQuery will take you a long way towards writing DOM traversal and modification.
$("div[style='cursor: text']").unwrap().prepend("<br>");
unwrap deletes the element but keeps the children intact. The jQuery Attribute Equals Selector is used to select all divs with the cursor style attribute. You can run it live here.
You could make this more robust as currently you would not select a div with more or less whitespace or with other trivial differences. For example: <div style="cursor:text;"> is not matched by the above selector. You can work around this shortcoming by introducing a CSS class that sets the cursor. In this case <div style="cursor: text"> becomes <div class='textCursor'> and you can use the class selector: $("div.textCursor")

//FINAL ANSWER
var domString = "", temp = "";
$("#div-editable div").each(function()
{
temp = $(this).html();
domString += "<br>" + ((temp == "<br>") ? "" : temp);
});
alert(domString);
see this fiddle for answer.

i found this solution in this site:
$editables = $('[contenteditable=true'];
$editables.filter("p,span").on('keypress',function(e){
if(e.keyCode==13){ //enter && shift
e.preventDefault(); //Prevent default browser behavior
if (window.getSelection) {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement("br"),
textNode = document.createTextNode($("<div> </div>").text()); //Passing " " directly will not end up being shown correctly
range.deleteContents();//required or not?
range.insertNode(br);
range.collapse(false);
range.insertNode(textNode);
range.selectNodeContents(textNode);
selection.removeAllRanges();
selection.addRange(range);
return false;
}
}
});

Related

How to robustly underline a letter in a HTML snippet via the DOM

I'm building a keyboard access library for my web app. To hint at what keys should be pressed i want to underline the key in links. E.g.
Orders --- Invoices --- Open Incidents
For pure text snippets this is easy (jQuery used here):
part.html(part.html().replace(new RegExp(key, 'i'), '<u>$&</u>'));
But this breaks horribly if there is any html markup inside part. Is there an elegant way to just update text nodes and never markup?
Clarification: My use case is hundreds of nested templates server side generating the HTML. Currently accesskey attributes are added by hand. Resulting in something like <i class="fa fa-fw fa-podcast"></i>Ange<b>bote</b>. A Javascript Front-End Script then among other things adds keybindings and trying to underline the bound keys.
To get to the text nodes only, and make the replacement there, you could use a tree walker. I would also create a function that isolates the found letter in a span element and returns that. Then you can use jQuery (or whatever methods) to decorate that element as you wish:
function getLetter(elem, letter){
if (elem.get) elem = elem.get(0); // remove jQuery wrapper
var nodes = document.createTreeWalker(elem, NodeFilter.SHOW_TEXT, null, null),
$node, text, pos, $span;
letter = letter.toLowerCase();
while ($node = $(nodes.nextNode())) {
text = $node.text();
pos = text.toLowerCase().indexOf(letter);
if (pos > -1) {
$span = $('<span>').text(text[pos]);
$node.replaceWith( // separate the letter from the other text
text.substr(0, pos),
$span,
text.substr(pos+1)
);
return $span; // return the element that just has that one letter
}
}
}
getLetter($('#orders'), 'o').addClass('underline');
getLetter($('#invoices'), 'i').addClass('underline');
getLetter($('#incidents'), 'n').addClass('underline');
.underline { text-decoration: underline }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Some mix of HTML:</h3>
<div id="orders">
<span style="color: purple">Order<i>(s)</i></span>
</div>
<div id="invoices">
<ul><li><b>!!</b>Invoices <i>(urgent)</i></li></ul>
</div>
<div id="incidents">
<table style="border: 1px solid"><tr><td>Open</td><td>incidents</td></tr></table>
</div>
Explanation of the Function
The function takes two arguments:
elem: the container element which has the text that needs to be searched. This element may or may not have nested HTML mark up.
letter: the letter to identify within that element: only the first occurrence of that letter will play a role.
The function returns:
undefined when there is no match, i.e. the provided letter does not occur in any text contained by the provided element.
A new span element that the function has created: it will contain the letter that was found. The remaining text is put in separate text nodes before and after that new element.
For single letters it should be trivial with the range API, since they won't be split over multiple nested nodes.
let range = document.createRange();
let div = document.createElement("div")
div.textContent = "Orders --- Invoices --- Open Incidents"
let textNode = div.firstChild
let underline = document.createElement("u")
range.setStart(textNode, 0);
range.setEnd(textNode, 1);
range.surroundContents(underline);
console.log(div.outerHTML)
// <div><u>O</u>rders --- Invoices --- Open Incidents</div>
[].forEach.call(document.getElementsByTagName('a'),function(el){
el.innerHTML=el.innerHTML.replace(el.getAttribute('acceskey'),
'<u>'+el.getAttribute('acceskey')+'</u>')
})
Try it here: JS FIddle

Javascript add class to selected text, not first occurrence of the selected text

I want to add a class (and later on to send that string to php) to a text with javascript. Whenever I try to do that, the code is adding the class to the first occurrence of my selection, not to the actual selection. Keep in mind that I want to send that EXACT selection to php (and put it in a database as well so it keep that class even after refresh).
JQ
$("#highlight").click(function(){
paraval = $('#para').html();
sel = window.getSelection();
newst = '<a class="selectedText">' + sel + '</a>';
newvalue = paraval.replace(sel, newst);
$('#para').html(newvalue);
});
HTML
<p>Will only highlight if text is selected from comment class div only</p>
<div class="comment" id="para" contenteditable="true">Here goes some text Here goes some text Here goes some text Here goes some text
Some other text</div>
<input type="button" value="Highlight" id="highlight"/>
CSS
.selectedText{
background-color:yellow;
}
.comment{
border: solid 2px;
}
.comment::selection {
background-color: yellow;
}
example here: http://jsfiddle.net/zq1dqu3o/3/
try to select the last occurrence of the word "text". the first one will get the class "selectedText"...
thanks
Call me lazy, but if you don't mind span being you selection marker tag, you can use rangy's cssApplier class.
var cssApplier;
$(document).ready(function() {
rangy.init();
cssApplier = rangy.createCssClassApplier(
"selectedText", {normalize: true,
applyToEditableOnly:true});
});
$("#highlight").click(function(){
if(cssApplier != undefined)
{
cssApplier.toggleSelection();
}
});
I use applyToEditableOnly here to make it only work in that specific div. (I'm not sure how cross-browser compatible that particular setting is. Worked in Chrome and Firefox though.) This uses position rather than selection text to decide what to mark.
JS Fiddle Here: http://jsfiddle.net/zq1dqu3o/7/
You can get the last occurence with lastIndexOf() and proceed like this:
$("#highlight").click(function(){
paraval = $('#para').text();
sel = "text";
var n = paraval.lastIndexOf(sel);
var before = paraval.substring(0,n);
newst = before + '<a class="selectedText">' + sel + '</a>';
newvalue = paraval.replace(paraval, newst);
$('#para').html(newvalue);
});
Just created a fiddle for it: Replacing last occurence
Note: This quick example is only working because the word you want to highlight is at the last position of the text, but you can check out if this solution is ok for your request. In case the last occurence of the word is elsewhere, just create a variable "after" that contains the text following the last occurence of the word to the end.
Have just provided an example for this in updated fiddle: Replacing last occurence update
with following update to previous code:
var after = paraval.substring(n + sel.length, paraval.length);
newst = before + '<a class="selectedText">' + sel + '</a>' + after;

How to use jquery to remove extra whitespace before content in <textarea> without changing html

I want to use jquery append() to add content to a textbox without having to consider newline characters that show up in the html markup and indent the content. How do I get jquery to ignore newline characters in regards to textarea?
<div id = "content-frame">
<div id = "remove-frame">
<div id = "content">
here is the content, click this content
</div>
</div>
</div>
$("#remove-frame").click(function () {
var divContents = $("#content").text();
$("#content").remove();
$("#remove-frame").append(function() {
return '<textarea id = "edit-textarea">' + divContents + "</textarea>";
});
});
http://jsfiddle.net/8KA8q/3/
You missed to trim the content value. Also you can use JQuery.trim() to keep browser compatibility. Try to modify your code as bellow:
$("#remove-frame").click(function () {
var divContents = $("#content").text().trim();
$("#content").remove();
$("#remove-frame").append(function() {
return '<textarea id = "edit-textarea">' + divContents + "</textarea>";
});
});
I think what you want is .prepend() instead of .append();
append places it as a last child, prepend as a first child.
also if that doesnt work play with .appendto() and .prependto().
Good luck
Take a Look

How to select the text of a span on click?

I am looking for a way to select the text inside a span using jquery when the text is clicked on.
For example in the html snippet below, I want the text "\apples\oranges\pears" to become selected when it is clicked on.
<p>Fruit <span class="unc_path">\\apples\oranges\pears</span></p>
I've tried implementing this myself to no avail.
It could be implemented with native JavaScript. A working demonstration on jsFiddle. Your code could be like this:
$('.unc_path').click(function (){
var range, selection;
if (window.getSelection && document.createRange) {
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(this);
selection.removeAllRanges();
selection.addRange(range);
} else if (document.selection && document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(this);
range.select();
}
});
You can use CSS to do this more easily than JS with style="user-select: all;"
add cursor: pointer; so its obvious they can click...
See code snippet:
<p>
Fruit
<span style="user-select: all; cursor: pointer;">\\apples\oranges\pears</span>
</p>
A working demonstration : http://jsfiddle.net/dystroy/V97DJ/
$('.unc_path').click(function (){
var text = $(this).text();
var $input = $('<input type=text>');
$input.prop('value', text);
$input.insertAfter($(this));
$input.focus();
$input.select();
$(this).hide();
});​
The idea (see comment above) is to dynamically replace the span with an input, only cross-browser way I know to have selected text.
Note that this is only half the road, as you probably want to deselect, style to remove border, etc.
And I must also precise that an input, contrary to a span, cannot span on multiple lines.
I don't think this could/should be used in a real application except in a very specific point.
EDIT : new version : http://jsfiddle.net/dystroy/A5ZEZ/
In this version the text comes back to normal when focus is lost.
$('.unc_path').click(function (){
var text = $(this).text();
var $this = $(this);
var $input = $('<input type=text>');
$input.prop('value', text);
$input.insertAfter($(this));
$input.focus();
$input.select();
$this.hide();
$input.focusout(function(){
$this.show();
$input.remove();
});
});​
To select the specific Span you need a id to be provided to that span. Else you need to loop through the list of all available span to get it.
Lets take this as Example (have added id attribute)
<p>Fruit <span class="unc_path" id="span1">\\apples\oranges\pears</span></p>
The JQuery will be like this
$('span1').text() // if you want to take the text
$('span1').html() // if you want to take the html

change backcolor of part of text using javascript?

i have some part of text with html tags , for example
<b>something</b>
i select some part of text for example "some".
with getSelection().getRangeAt(0); i get position of caret (textcursor), so i know which part of text i've selected.
i have startOffset and endOffset. but problem is, that startOffset and endOffset ignores html tags, so numbers which it returns are not bad, and then i don't know on which part of text i have to apply
<span style="background-color: somecolor ">some</span>
any ides how to solve this ? thanks
<b id='str1'>something</b>
<script>
function jsReplace()
{
var elem = document.getElementById('str1')
elem .innerHTML = elem .innerHTML.replace('some', '<span style="background-color: somecolor ">some</span>')
}
</script>

Categories