I have a contentEditable DIV where I would like to replace any user typed URL (by matching the string with regular expression) with blue color text wrapped inside a span tag.
However, different browsers return different results. Besides, replacing the matched text with span puts cursor at the beginning of the text.
Here is the link: jsfiddle
CSS
.class{
position:relative;
outline:none;
border:5px solid #96C;
font-size:16px;
width:500px;
height:60px;
padding:0px 2px;
word-wrap:break-word;
}
HTML
<div class='class' id='div' contentEditable='true'></div>
JavaScript
var regExUrl = /https?:\/\/([\w\d-\.]+)?[\w\d-\.]+\.{1}[\w]{1,4}(\/{1})?([a-zA-Z0-9&-#_\+.~#?\/=]*)?/gi;
var div = document.getElementById('div');
div.onkeyup = function () {
if (div.innerHTML.match(regExUrl)) {
st = div.innerHTML.match(regExUrl);
div.innerHTML = div.innerHTML.replace(regExUrl, "<span style='color:blue;text-decoration:underline'>" + st[0] + "</span>");
}
}
How can I set the cursor at the end of the replaced text and continue typing with the default color (black)?
Not a direct answer but a suggestion of another way of achieving the same user experience in a simpler way:
http://jsbin.com/EZizIge/1/
var regExUrl = /https?:\/\/([\w\d-\.]+)?[\w\d-\.]+\.{1}[\w]{1,4}((\/{1})?)([a-zA-Z0-9&-#_\+.~#?\/=]*)?/gi;
var div = document.getElementById('div');
div.onkeyup = function(){
if(div.innerHTML.match(regExUrl)){
$("div").addClass("link");
} else {
$("div").removeClass("link");
}
}
With css:
.link{
text-decoration: underline;
color: blue;
}
Related
I need to sanitize HTML in a WYSIWYG editor. The output must not contain any <div>s. All <div> elements must be replaced with <br> elements. This original text MUST render the same as the sanitized text.
This is my attempt so far (notice the unwanted extra whitespace in the output) – thanks to Nimit for the rendering containers:
let text = `<div>aoeu</div><div><ul><li>eu</li><li>a</li></ul><div><br></div></div><div>eu</div>`;
// let text = 'aoeu<ul><li>aoeu</li><ul><li>aoue</li></ul></ul><div><br></div></div></div><div><br></div><div><br></div><div><br></div><div>oe</div><div><ul><li>u</li></ul></div>'
document.getElementById("pre1").innerHTML = "<strong>With Div</strong> </br>" + text;
text = text
.replace(/<div><div>(.*)<\/div><\/div>/g, '<div>$1</div>') // meaningless directly double wrapped divs
.replace(/<div><br><\/div>/g, '<br>') // div with a br is only one newline
.replace(/<div>(?!<div>)(.*?)<\/div>/g, '$1<br>') // divs always make a newline after
document.getElementById("pre2").innerHTML = "<strong>Without Div</strong> </br>" + text;
.preContainer {
display:inline-block;
width:200px;
vertical-align:top;
}
.preContainer:first-child{
border-right:1px solid black;
}
<div class="preContainer"><pre id="pre1"></pre></div>
<div class="preContainer"><pre id="pre2"></pre></div>
So basically I can't seem to figure out how to perfectly convert from <div> to <br>. Any help much appreciated.
I think you can achieve your result with below replace script.
.replace("<div>", "<br>").replace("</div>", "");
Check below snippet, you can inspect both pre, second pre doesn't have any div tag:
function showItInPre(text){
//let text = `aoeua<div><ul><li>oe</li><li>a</li><li>oeu</li></ul><div><br></div></div><div><br></div><div><br></div><div>aoe</div><div><ul><li>u</li></ul><div><br></div></div><div><br></div><div>u</div><div><div><br></div></div><div>o</div><div><ul><li>o</li><li>o</li><li>a</li><li><br></li></ul></div>`;
document.getElementById("pre1").innerHTML = "<strong>With Div</strong> </br>" + text;
text = text
.replace(/<div><br><\/div>/ig, '<br>')
.replace(/<\/div><\/div>/ig, '<br>')
.replace(/<div>/ig, "").replace(/<\/div>/ig, "<br>");
document.getElementById("pre2").innerHTML = "<strong>Without Div</strong> </br>" + text;
}
document.getElementById("testit").addEventListener("click", function(){showItInPre(document.getElementById("textarea").value)});
.preContainer {
display:inline-block;
width:200px;
vertical-align:top;
}
#pre1{
border-right:1px solid black;
}
#textarea {
width:500px; height:50px;
}
<div><textarea id="textarea"></textarea><button id="testit">Test</button></div>
<div class="preContainer"><pre id="pre1"></pre></div>
<div class="preContainer"><pre id="pre2"></pre></div>
I have some application that adds elements to contentEditable div.
Something like this:
<div id="div" contentEditable="true"></div>
<button id='appendBtn'>append</button>
<style>
.bracket {
color: blue;
}
.template-content {
color: green;
}
#div {
border: solid 1px gray;
margin-bottom: 10px;
}
</style>
<script>
function appendContent() {
var content = "<span class='template-block'>" +
"<span class='bracket'>{</span>" +
"<span class='template-content'>param</span>" +
"<span class='bracket'>}</span>" +
"</span>";
$("#div").append(content);
}
document.getElementById ("appendBtn").addEventListener ("click", appendContent, false);
</script>
I wrote a working example in jsfiddle.
The problem is that when I click append and continue typing after added element all next text comes green. It happens because all next text pasts into last span tag (of class bracket with green color)...
<span class="bracket">}some text</span>
The solution is adding a after last closing span tag. Like this:
var content = "<span class='template-block'>" +
"<span class='bracket'>{</span>" +
"<span class='template-content'>param</span>" +
"<span class='bracket'>}</span>" +
"</span> ";
But it brings a lot of unwanted staff I have to do with the text after. How can I solve this?
Thats a default behaviour of content editable setting the pointer behind the last character inside. In Your case the pointer is set
<span class='bracket'>}--> pointer <--</span>
You could try a workaround with entity (zero width space)
if you dont want the
I appended a few divs with inside img tags. Every tag has own unique id = "theImg"+i where "i" is number. I want to mouseover on specific img and show the content of span (which also have specific id with number). Here is my code so far but not working.
var j;
document.onmouseover = function(r) {
console.log(r.target.id);
j = r.target.id;
}
$(document).on({
mouseover: function(e){
$("span").show();
},
mouseleave: function(e){
$("span").hide();
}
}, "img#"+j);
If you have a span after every img, maybe it's a good idea to not use JavaScript at all? ;-)
You could use :hover pseudoclass in CSS, making your thing always work reliably.
Consider the following example:
img + span {
display: none;
}
img:hover + span {
display: block;
}
/*/ Optional styles /*/
div {
position: relative;
float: left;
}
div img + span {
position: absolute;
color: #fff;
background: #27ae60;
border: solid 1px #2ecc71;
border-radius: 50px;
z-index: 1;
bottom: 1em;
width: 80%;
left: 50%;
margin-left: -43%;
padding: 2% 3%;
text-align: center;
}
<div>
<img src="https://placehold.it/400x200">
<span>This is an image of a gray rectangle!</span>
</div>
<div>
<img src="https://placehold.it/200x200">
<span>This is an image of a gray square!</span>
</div>
<div>
<img src="https://placekitten.com/g/400/200">
<span>This is an image of a cute kitten inside a rectangle!</span>
</div>
<div>
<img src="https://placekitten.com/g/200/200">
<span>This is an image of even cuter kitten inside a square!</span>
</div>
So the issue is that you are trying to set your handler on a dynamic selector ("img#"+j) but this will not work. For one thing, that equation will be evaluated only once, on page load, when j is undefined.
So you want to do this instead:
target only img tags for your mouse over... Better yet, give your special images all the same css class so you can attach the event handlers only to those. That will be more efficient.
When an image is moused over or out of, grab it's id attribute, extract the number from it, then use that to build a selector for the appropriate span to show.
var get_span_from_image = function(image) {
var image_id = image.attr("id");
var matches = image_id.match(/theImg(\d+)/);
if(matches) return $("theSpan" + matches[1]);
return $(); // nothing found, return an empty jQuery selection
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Note: There are better ways to "link" two nodes together, but this is just to answer your question with the current structure you have.
UPDATE: Some ideas to link two nodes together
So instead of trying to extract a number from an id attribute, a better way would be to tell either one of the image or span about it's sibling. You could output your html like this, for instance:
<img id="theImg1" data-target="theSpan1" class="hoverable" src="..."/>
....
<span id="theSpan1">...</span>
Of course now your ideas could be anything - you don't have to use numbered values or anything.
Then your hover code becomes quite simply:
var get_span_from_image = function(image) {
var span_id = image.data("target");
return $("#" + span_id);
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Hope this helps!
I am new to jquery. What I want to create is a Jquery Filter in Unordered list with links and input field on the top. As I type letters in the input field I want the letters of links inside the li items to change color. Without link it is achievable but I need it for links(a href). for eg: If I type 'Mum' of Mumbai then the letters in the list having MUM should change to red color. Have a look at the Jsfiddle
HTML
<div id="location-search">
<p id="header">Select Your Prefered Location</p>
<ul id="list">
<li>Mumbai</li>
<li>Bangalore</li>
<li>Goa</li>
<li>Navi Mumbai</li>
<li>Pune</li>
<li>Thane</li>
</ul>
</div>
CSS
body {background:#f3f3f3;}
#location-search {float:left; display:inline; width:280px; background:#fff; padding:20px;}
p#header {font:bold 15px Arial;}
input {
border:1px solid #ccc;
font-size:1em;
height:2.10em;
*height:1.0em;
line-height:1.0em;
padding:0.10em 0;
width:100%;
}
.filterform {
width:220px;
font-size:12px;
display:block;
}
ul#list {float:left; display:inline; width:224px; padding:10px 0;}
ul#list li {font:bold 13px Arial; padding:5px 0 5px 10px;}
ul#list li a {color:#646464;}
Javascript
(function ($) {
jQuery.expr[':'].Contains = function(a,i,m){
return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
function listFilter(header, list) {
var form = $("<form>").attr({"class":"filterform","action":"#"}),
input = $("<input>").attr({"class":"filterinput","type":"text"});
$(form).append(input).appendTo(header);
$(input)
.change( function () {
var filter = $(this).val();
if(filter) {
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(list).find("a:Contains(" + filter + ")").parent().slideDown();
} else {
$(list).find("li").slideDown();
}
return false;
})
.keyup( function () {
$(this).change();
});
}
$(function () {
listFilter($("#header"), $("#list"));
});
}(jQuery));
And here's what I want to achieve:
Screenshot
Any help would be appreciated I am just stuck at this step. N all other stuff I have done it.
Here is another solution Demo http://jsfiddle.net/MF4Tn/28/
I have made some in-line changes using substring and then span is added to change color
Here is the working Demo http://jsfiddle.net/MF4Tn/12/
I have added two javascript functions: jQuery.fn.removeHighlight and jQuery.fn.highlight and little css code. javascript I took from the link that I posted below.
Here is written useful code example
thanks to #dzordz
i created a fiddle that may suit your needs:
http://jsfiddle.net/MF4Tn/29/
Basicly it does:
$(list).find("li>a").each(function(id,el){
var a=$(el);
if(a.text().toLowerCase().indexOf(filter.toLowerCase()) >= 0){
a.html(a.text().split(filter).join("<span style='color:red;'>"+filter+"</span>" ));
}else{
a.html(a.text());
}
});
This is how it is done:
I iterate over all achors and than check weather the content is in line with the filter
If so I insert a span that makes this text red
I removed all the slideDown and slideUp things in order to have this example clean.
One may even change the .split() and .join() thing into some string replace funktion.
I want to add background color to particular selected text from Text area into div?
var elem=document.getElementById("askQuestionDescription");
var start=elem.value.substring(0,elem.selectionStart);
var selection = elem.value.substring(elem.selectionStart,elem.selectionEnd);
var end=elem.value.substring(elem.selectionEnd,elem.length);
// alert(start + ","+selection+","+end);
document.getElementById("askQuestionCodePreview").innerHTML=start+selection+end;
I want to set background on selection portion only.
Why don't you use this to change the background color of the selected text?
http://www.quirksmode.org/css/selection.html
#askQuestionDescription::selection {
background:red;
color:white;
}
#askQuestionDescription::-moz-selection {
background:red;
color:white;
}
#askQuestionDescription::-webkit-selection {
background:red;
color:white;
}