I wich to replace a paragraph with a textarea tag when clicking on the paragraph, the textarea should contain the text that was in the paragraph:
<div id="right"><p><pre><?php echo $descri; ?></pre></p></div>
Jquery script :
$(function(){
$('#right').on('click', 'p', function(){
var $p = $(this);
var old = $p.html();
if(/<textarea rows="4" cols="40" id="descri" name="descri"/.test(old))
return;
$p.html('<textarea rows="4" cols="40" id="descri" name="descri" value="' + old + '"/>')
.find('textarea')
.focus()
.on('blur', function(){
var value = this.value;
$.post('listener_updates.php', {description: value})
.done(function(){
$p.html(value);
})
.fail(function(){
$p.html(old);
alert('Could not update title');
});
});
});
});
Now when I click on the paragraph text, nothing happens but when I click a little under the paragraph text, then the textarea appears and is empty.
Thank you for your help
This is because you can't put a pre element inside a p element, so the browser's correcting the invalid DOM. The content model of p is phrasing content, but pre isn't valid in phrasing content, only flow content.
When you give this to Chrome:
<div class="right"><p><pre>This is the text</pre></p></div>
...it actually creates this DOM:
<div class"right"><p></p><pre>This is the text</pre><p></p></div>
Note that the pre is no longer in any p.
If you want the pre, simply use pre on its own (without the p). pre is a lot like like p: They both have the same content model, they're both valid in the same places, and they're both display: block by default.
Alternately, if your only goal is not to have line wrapping and other such, on modern browsers you can get rid of the pre (keeping the p or using a div if the semantics of p aren't appropriate) and use the CSS white-space property (e.g., white-space: pre) instead.
Re your comment below:
but I can't get the text inside the pre tag to show on the textarea
Just put the pre's contents() into the textarea, put the textarea in the DOM where you want it, and remove or hide the pre. This removes it, for instance: Live Example
$(".right").on("click", "pre", function() {
var $pre = $(this);
var $textarea = $("<textarea>");
$textarea.append($pre.contents());
$pre.replaceWith($textarea);
return false;
});
Related
I am trying to make a content editable div that can be used to generate message templates for an app. Users can append placeholders for fields like names to a template by hitting a button. The placeholders can be removed by hitting an 'x' on them as well. Here's the working snippet.
var removePlaceholder = function(e){
e.parentNode.parentNode.removeChild(e.parentNode);
}
var appendPlaceHolder = function(field){
var e = document.getElementById("t");
e.innerHTML += ('<span class="tag">{'+field+'}<span onclick=removePlaceholder(this) class="remove">x</span></span>')
}
.tag {
background-color : blue;
color : white;
}
.remove {
color : red
}
<div id="t" contenteditable="true">Hello</div>
<button onclick=appendPlaceHolder("first_name")>Add first name</button>
The contenteditable part works just fine. But after I've added a placeholder using my appendPlaceHolder function, everything I type seem to get appended to the last inserted HTML element.
How can I prevent this. I have closed the tag properly. Is there any way to change this behaviour.
To recreate issue, run the snippet and hit the "Add First Name" Button, then continue typing in the area.
Update
Have added image to explain the situation
What you can do is add a space after the placeholder has been appended:
JavaScript
var removePlaceholder = function(e){
e.parentNode.parentNode.removeChild(e.parentNode);
}
var appendPlaceHolder = function(field){
var e = document.getElementById("t");
e.innerHTML += ('<span class="tag">{'+field+'}<span onclick=removePlaceholder(this) class="remove">x</span></span> ')
}
Note: The which has been added at the end of the span just creates a space.
Live Example
JSFiddle
I am building a simplistic and easy-to-use text editor in Javascript, basically a WYSIWYG editor. I will be using the contenteditable attribute to the main wrapper (.wrapper). When you press enter inside the .wrapper, a new <p> element with a unique id gets appended to the wrapper.
I need a way to fetch which child element of the .wrapper that is currently selected (i.e., being focused or having the caret/text marker inside of it).
I've searched for days without any results, and I've tried using document.elementFromPoint() but without any proper results.
When using $(":focus"), I get the entire .wrapper and not the specific child element.
Edit:
Example HTML structure:
<div class="container t-wrapper" contenteditable>
</div>
Example Javascript code:
$(document).ready(function() {
$currentElement = $("[contenteditable]");
$(".t-wrapper").each(function() {
var id = generateIdentifier(6); // Ignore this
/* This creates the initial <p> child element, where you start typing. */
$(this).html('<p class="t-empty t-first" id="' + id + '"></p>');
$(this).on("mouseup", function() {
/* $currentElement = whatever element the caret is inside. */
});
$(this).on("keyup", function() {
/* $currentElement = whatever element the caret is inside. */
});
));
});
Edit 2:
I managed to get it fairly working with the mouseup event, since you're actually clicking on something. But I need this to work when moving the caret using the keyboard. Alternatively, I need some way to get the position of the caret in pixels, and then use document.elementFromPoint() to get the specific element.
:focus doesn't select your elements because they are not focusable.
You can make them focusable by adding tabindex="-1" in HTML, or tabIndex = -1 in JS.
var generateIdentifier = Math.random;
var currentElement = document.querySelector("[contenteditable]");
[].forEach.call(document.querySelectorAll(".t-wrapper"), function(el) {
var first = document.createElement('p');
first.className = "t-empty t-first";
first.id = generateIdentifier(6);
first.textContent = 'Press enter to create new paragraphs';
first.tabIndex = -1;
el.appendChild(first);
});
.container > :focus {
border: 1px solid blue;
}
<div class="container t-wrapper" contenteditable></div>
It seems that if you add it to the first paragraph, new paragraphs obtain it automatically. But if you want to be sure, I guess you could use a mutation observer or a keyup event listener to detect paragraphs without tabindex, and add it:
el.addEventListener("keyup", function(e) {
var newChild = el.querySelector('p:not([tabindex])');
if(newChild) newChild.tabIndex = -1;
});
document.activeElement will return the currently focused element.
I created a function that adds text to an element called #textBox. I want the text to fade in the box so, here is my code.
var addText_3 = function(text) {
$("#textBox").append("<p><i>" + text + "</i></p>").hide().fadeIn(500);
};
So, my function appends to text and hides it so it can fade in. However, I just want the appended element to fade in. When I try this function, all of the other text in the element also fade. Is there a way to only make the element I am appending to fade in?
$("<p><i>" + text + "</i></p>").appendTo("#textbox").hide().fadeIn(500);
Create the new element, append it to #textbox, and fade it in.
var text = 'Stack Overflow';
$("<p><i>" + text + "</i></p>").appendTo("#textbox").hide().fadeIn(500);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="textbox">Some text</div>
The chaining of function does not return what you expect : it returns #textBox while you thought it'll returns your freshly created text node.
So, you have to call both the hide() and fadeIn() functions on your text node instead.
appendTo() is the function you'd rather use as it returns the caller (call it on your new node).
Example (with jQuery's clean node creation) :
var addText_3 = function(text) {
var text_node = $("<p>").append($("<i>", {html: text})).hide(); //Can use text instead of html
text_node.appendTo("#textBox").fadeIn(500);
};
This one's my personal pref
DEMO
var text = 'asdfasdfasdf';
$("<p><i>" + text + "</i></p>").fadeIn(500).appendTo($('#textBox'));
I have the following code,
$(document.getElementById('messages_message-wysiwyg-iframe').contentWindow.document).keydown(function() {
var iFrame = document.getElementById('messages_message-wysiwyg-iframe');
var iFrameBody;
if ( iFrame.contentDocument )
{ // FF
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0];
}
else if ( iFrame.contentWindow )
{ // IE
iFrameBody = iFrame.contentWindow.document.getElementsByTagName('body')[0];
}
console.info(iFrameBody.innerHTML);
});
What I am trying to do if get the content of an iframe, but remove all the html tags that are not,
b, strong, i, a, u, img
However I do not want to remove any of the of the text, for example if the in the iframe there is the following,
<div class="box segment panel">
<a href="http://www.google.com>hello world</a>
click this link and go far.
<img src="http://placehold.it/100x100" alt="Placeholder"/>
</div>
What would be return would be the following,
hello world
click this link and go far.
</a>
<img src="http://placehold.it/100x100" alt="Placeholder" />
Is this even possible?
Here's my pure JS solution:
function sanitize(el) {
if (el.nodeType !== 1) return;
if (!/^(B|STRONG|I|A|U|IMG)$/.test(el.tagName)) {
var p = el.parentNode;
// move all children out of the element, recursing as we go
var c = el.firstChild;
while (c) {
var d = c.nextSibling; // remember the next element
p.insertBefore(c, el);
sanitize(c);
c = d; // look at the next sibling
}
// remove the element
p.removeChild(el);
}
}
demo at http://jsfiddle.net/alnitak/WvJAx/
It works by (recursively) moving the child nodes of restricted tags out of their parent, and then removing those tags once they're empty.
With a regex:
iFrameBody.innerHTML=iFrameBody.innerHTML.replace(/<[^(b|strong|i|a|u|img)]\b[^>]*>/gi,"").replace(/<\/[^(b|strong|i|a|u|img)]>/gi,"");
The first replace removes the start tags, the second removes the end tags.
Note that there are a couple traps when using regex to match html. But in this specific case it seems like a reasonable choice (cf. my comments on the other answers).
For the record, this is what I use to access an iframe's content document:
var doc=ifr.contentWindow||ifr.contentDocument;
if (doc.document) doc=doc.document;
var iFrame = document.getElementById('messages_message-wysiwyg-iframe');
var iFrameDoc = iFrame.contentDocument || iFrame.contentWindow.document;
$(iFrameDoc).keydown(function() {
var iFrameBody = $("body", iFrameDoc);
var cleared = iFrameBody.clone();
cleared.find("*:not(b,strong,i,a,u,img)").each(function() {
var $this = $(this);
$this.replaceWith($this.contents());
});
console.log(cleared.html());
});
Demo at jsfiddle.net
I think you're a little confused about how to describe what you're trying to do. When you talk about "text", you're referring to the innerHTML/text node inside of a tag. What you're really looking to do, I think, is grab all of the specific content and the structure of the content, aka the children elements of the iFrame.
You can use jQuery's .text() method to get the text content of each element individually and save that before removing the actual tag from the DOM, if you want to lets say, get the text content of a span but you don't want the span to be in the DOM anymore, or you want to place it somewhere else in your document.
var elemText = $('span#mySpan').text();
$('span#mySpan').remove();
For what it looks like you're trying to do based on your sample HTML, you may want to look into jQuery's detach method: http://api.jquery.com/detach/
This will allow you to store the returned children elements to be appended somewhere else later.
How can we change the text data from except span text?
<h2 id="nameUser" >Muhammed <span> mobile :989 531 9991</span></h2>
Is there any solution to change h2 except span?
.contents() returns a collection of nodes, including text nodes. So in your case this would work:
$('#nameUser').contents()[0].nodeValue = 'Another name';
If you want to get every node except the SPAN, try:
$('#nameUser').contents().filter(function() {
return this.nodeName != 'SPAN';
}).each(function(i) {
// modify each text node
this.nodeValue = 'name '+i;
});
DEMO: http://jsfiddle.net/Vks82/
Search for the first textnode in childNodes of the h2 element. Change the value of the textnode.
var element = document.getElementById('nameUser');
element.childNodes[0].nodeValue = 'New String';
..should work. Only for this example, because the first childnode is the textnode you want, you don't have to search for it. Otherwise you do..
This example may help you to change father element without changing child elements:
var content= $('#nameUser').children();
$('#nameUser').text('Altered Text').append(content);
$('#nameUser').contents().each(function() {
if (this.nodeType == 3)
this.data = "The text you want here";
});
Live DEMO
You can do it by saving the children first here is a codepen of it working.
http://codepen.io/beckje01/pen/sGLot
var h2 = $('#nameUser');
var elmsToSave = h2.children();
h2.empty();
h2.text('bob');
h2.append(elmsToSave);
As pointed out in the comments this will only work if the text to change is first.
This will work not only for span but also for any other element which you want the text without the text of it's children.
$("#nameUser")
.clone()
.children()
.remove()
.end()
.text();
For change the text I've create a simple jQuery function:
replaceTextWith = function($element, $replacement){
$oldText = $element.clone().children().remove().end().text();
$element.text($element.text().replace($oldText, $replacement));
}
replaceTextWith($("#nameUser"), "Bruno"); //usage
Here's a live example working on fiddle
try this ...
<h2 id="nameUser" >Muhammed <span id="nameUserSpan"> mobile :989 531 9991</span></h2>
<script>
$(document).ready(function() {
var inspan= $("#nameUserSpan").html();
var newuser='New User';
$("#nameUser").html('');
$("#nameUser").html(newuser + '<span id="nameUserSpan">' + inspan + '</span>');
});
</script>