Merge two paragraphs together and deleting an element in middle - javascript

I have a div contentEditable with paragraphs and appended after each p is a span telling me the length of the paragraph the user can edit the line & thus update the number shown in the span, (done with something on these lines .each(fu..(){ p append '<span>'+ this.length ..)
Let's say something like this:
<div contenteditable="true">
<p>abc<span contenteditable="false" style="position:absolute;right:-2em;backg...">3</span></p>
<p>abce<span ...>4</span></p>
<p>abcfoo<span ...>6</span></p>
<p>abcbar<span ...>6</span></p>
</div>
Have made all the spans uneditable in order to protect the spans and the text, on hitting return a new <p> is created on the next line - all sparky! However I have no way of deleting a new paragraph as the back button on the first letter of a p acts as the browser back button! because its hitting the non editable span.
So I would like to add a button (perhaps on the span) which when clicked will 1. remove the span (not too difficult), 2. merge the 2 paragraphs together.

I hope that's the effect you're looking for: http://jsfiddle.net/AwKkB/
JS
$('span').click(function () {
var parent = $(this).parent(), container = parent.parent();
$(this).remove();
if (container.children().length > 1) {
if (parent[0] === container.children()[0]) {
$(container.children()[1]).prepend(parent.text());
} else {
parent.prev().append(parent.text());
}
}
parent.remove();
});
HTML
<div contenteditable="true" style="width: 180px">
<p>abc<span contenteditable="false" style="position:absolute;right:0em;background: red;">3</span></p>
<p>defg<span contenteditable="false" style="position:absolute;right:0em;background: red;">4</span></p>
<p>hijklm<span contenteditable="false" style="position:absolute;right:0em;background: red;">6</span></p>
<p>nopqrs<span contenteditable="false" style="position:absolute;right:0em;background: red;">6</span></p>
</div>
Best regards!

Something like this should do it:
$(document).on('click', 'span', function() {
$(this)
.prev().append($(this).next().text()).end()
.next().remove().end()
.remove()
;
});
See Fiddle.

I'm not sure whether the paragraphs contain only plain text, but a generalised way would be using .append, so that all elements are left intact: http://jsfiddle.net/tb7xk/.
$("<input>")
.attr({ type: "button", value: "Remove" })
.click(function() {
var $span = $(this).parent();
var c = $span.next().contents().get(); // contents
$.fn.append.apply($span.prev(), c); // pass all contents to .append
$span.next().andSelf().remove(); // remove next paragraph that's left over
})
.appendTo("span");

Related

Iterate over every element and get only the content that is directly in the node

let's assume I have this code
<p>FirstLevelP
<span>SecondLevelSpan</span>
</p>
<p>FirstLevelP
<span>SecondLevelSpan
<p>ThirdLevelP</p>
</span>
</p>
Is it possible to iterate through every element that I have right now, but only get the content, that's in the direct node of it, modify the text and then have it in the original content?
Example, If I go through every $('p').each and would extract the text I would also get the text inside the span.
Basically this:
FirstelElement: FirstLevelPSecondLevelSpan
SecondElement: SecondLevelSpanSecondLevelSpanThirdLevelP
But I want to have it like this
FirstelElement: FirstLevelP
SecondElement: SecondLevelSpan
ThirdElement: FirstLevelP
FourthElement: SecondLevelSpan
FifthElement: ThirdLevelP
Is this possible?
In my research I already found this answer here
$("#foo")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
But this would only solve half of my problems. I would still need to modify the text in the original content! Thanks in advance guys.
EDIT FOR CLARIFICATION
So basically, want I want to achieve is something like this:
For every element, I want to check if there is a dot at the end. If not I want to add one. I already managed to do this for headlines, like this:
foreach (pq($content)->filter(':header') as $headline) {
if (substr(pq($headline)->text(), 0, -1) != '.') {
$content = preg_replace('#(' . pq($headline) . ')#', pq($headline) . '.', pq($content));
}
}
The problem, as I stated, is, that when I have nested elements it would add the dot after the whole element, and not after each sub element if neccessary.
To work with my "assumed" code, it should look like this
<p>FirstLevelP.
<span>SecondLevelSpan.</span>
</p>
<p>FirstLevelP.
<span>SecondLevelSpan.
<p>ThirdLevelP.</p>
</span>
</p>
But unfortunatley, it currently looks like this
<p>FirstLevelP
<span>SecondLevelSpan</span>.
</p>
<p>FirstLevelP
<span>SecondLevelSpan
<p>ThirdLevelP</p>
</span>.
</p>
Note the dots.
finding and changing text without child elements works this ways:
// search every element
$("body *").each(function(index, el) {
// find first text node
var node = $(el).contents().filter(function() {
return this.nodeType === 3;
})[0];
// change text
node.textContent = "new text";
});
Edit, Updated
Try
$("body *").each(function (i, el) {
if ($(el).is("p, span")) {
$(el).text(function (idx, text) {
var t = text.split("\n")[0];
// if `text` string's last character is not `.`
// concat `.` to `text` string ,
// return `text` original string's with `.` added
return t.slice(-1) !== "." ? t + "." : t
})
}
})
$("body *").each(function (i, el) {
if ($(el).is("p, span")) {
$(el).text(function (idx, text) {
var t = text.split("\n")[0];
return t.slice(-1) !== "." ? t + "." : t
})
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>FirstLevelP
<span>SecondLevelSpan</span>
</p>
<p>FirstLevelP
<span>SecondLevelSpan
<p>ThirdLevelP</p>
</span>
</p>

Catch the onClick event on `span` tags

I have got a lot of span tags inside my div elements. Each div has a unique id.I want to add an onclick event to the span elements in each div uniquley. How can i do that?
<div class="bootstrap-tagsinput"id="1">
<span class="tag label label-info">Access control lists</span>
<span class="tag label label-info">Network firewall</span>
</div>
<div class="bootstrap-tagsinput"id="2">
<span class="tag label label-info">Access control lists</span>
<span class="tag label label-info">Network firewall</span>
</div>
My current script which catches all the span elements irrespective of the div.
$('span.label-info').click(function() {
var news=$('input[type=text][id="vuln<?php echo $model->v_id;?>"]').val()+','+$(this).text();
$('input[type=text][id="vuln<?php echo $model->v_id;?>"]').val(news);
return false;
});
How can i catch click on span elements inside each div separately?
I think you're looking at it the wrong way. Instead of having a separate click handler for each div, you can keep the shared click handler, but find out which div is the parent, and use its ID in the subsequent selectors.
$('span.label-info').click(function() {
// find the parent/ansector that is a div and has the class
var divId = $(this).closest('div.bootstrap-tagsinput').prop('id');
var news=$('input[type=text][id="vuln' + divId + '"]').val()+','+$(this).text();
$('input[type=text][id="vuln' + divId + '"]').val(news);
return false;
});
Your code should work to add a click even handler to each span.
$('span.label-info').click(function() {
$(this).attr('id'); //<--$(this) is a handle to the clicked span
$(this).parent().attr('id'); //<-- $(this).parent() references the parent div
});
It's worth mentioning, consider changing .click() to .on('click').
Also - if you wanted to bind once without rebinding after spans were dynamically added to the div, you could bind it like this:
$('div').on('click', 'span.label-info').click(function() {
/* <-- do stuff with $(this) or $(this).parent() here --> */
});
http://jsfiddle.net/GZVdL/3/
Hi.
in your span click event you can find parent div and then get its attribute id to find which div it is.
Below is the code
$(document).ready(function(){
$(".tag").click(function(){
alert($(this).parent().attr("id"));
});
});

How do I remove HTML in a content editable div if it is under a cursor position?

I'm trying to remove the class .words from this HTML, whenever it's clicked on it or if a keypress happens over it.
<div id="content" contenteditable="true"> Here are <span class="words" id="whatever">some</span> words </div>
I've tried
$('.words').click(function() { $(this).remove(); });
and more, which work except when I click on another word and cycle over .words using left or right key (since it is content editable). I'd like it to be removed as soon as the the cursor is over the class. Thanks.
Something like this?
var words = $('.words')[0]
$('#content').keyup(function(){
if (words == getSelectionStart()){
$(words).remove()
}
})
function getSelectionStart() {
var node = document.getSelection().anchorNode;
return (node.nodeType == 3 ? node.parentNode : node);
}
Example: http://jsfiddle.net/nickg1/ttMJW/1/

remove the hidden values and <br> when replacing via .html

I have a code which allows me to add certain "absentees", along with their ID's through a hidden form, to the absentees list when I click on them. When I click on it again, the "absentee" is removed from the absentees list. However, when I click on it again, the list seems to extend further because of a br
in my code plus the hidden form value doesn't seem to be removed. I need the hidden value removed so that the removed absentee from the list will not be recorded in the database. I need the br
so that the absentee listing will be presentable.
Here's my code: http://jsfiddle.net/gk5pV/8/
I wholeheartedly agree with #charlietfl, just use a block level element. Also, use a single hidden input to track your absentees. Example fiddle, code below:
$(function() {
$("td").click(function() {
var $this = $(this);
var user = $this.attr('id');
var p = $('<p />').attr('user', user).text($this.text());
var absentees = [];
if ($('#absentees').val().length > 0) {
absentees = $('#absentees').val().split(',')
}
if ($(this).hasClass('on')) {
//console.log("Already marked absent");
//remove from collection
$("#collect").children('p[user="' + user + '"]').remove();
absentees.splice(absentees.indexOf(user), 1);
}
else {
//console.log(user);
//add to collection
$("#collect").append(p);
absentees.push(user);
}
$this.toggleClass('on');
$('#absentees').val(absentees.join(','));
});
$("#clicky").click(function() {
$('td').removeClass('on');
$("#collect").empty();
$('#absentees').val('');
});
});​
Solution is fairly simple. Wrap the text you want to append and hidden input in a block level element ( div, p, li etc) and you won't need a <br tag. WHen you remove the absentee from list you remove the block element and the input will be part of it so it will no longer exist. If you give the new block level element a class name you can simply attach your event handler to the class

Show elements depending on html value of a tag

I would like to accomplish the following with jquery :
When I click on this link
Cars
I would like all divs like those
<div class="product">
<div class="category">Cars</div>
</div>
to do something.
You get the idea, I have a menu with a list of categories, and a list of products, each containing a div with the category name, and I would like to make them hide/show.
I am not sure if i fully understand your question, but if you want the div class="category" cars to appear when cars link is clicked, follow this:
$("#menu a").click(function() {
var value = $(this).html();
$.each($(".category"), function(i, item) {
if ($(item).html() == value) {
$(item).parent().hide();
}
});
});
if you want to hide the div just replace $(item).show(); with $(item).hide();
Assuming:
Cars
then:
$("a.highlight").click(function() {
$("div.category").removeClass("category")
.filter(":contains(" + $(this).text() + ")").addClass("highlight");
return false;
});
What this does is add the category class to any category dvis that contain the text of the link. This can be modified to modify the parent product div if you want to do it that way too.
It works by first removing the class highlight from all category divs and then adding it to the ones that require it.
DEMO: http://jsbin.com/ucewo3/11 SOURCE: http://jsbin.com/ucewo3/11/edit
$('a').click( function(e) {
var search_term = $.trim($(this).text()); //trim text
$('.category').each(function() {
($(this).text().search(new RegExp( search_term , 'i')) < 0 )//upper & lower
? $(this).parent().hide() : $(this).parent().show();
});
});
This keep the text inside the <a> tag and make a search into the <div class="category"> if the <a> text match with .category text it show the related .product content!
NOTE:
the script match both Uppercase and Lowercase chars
example match Cars as well as cars and CARS
also match spaced text like <a> cars </a> as well as <a>cars</a> and <a>cars </a>
match also tagged text like <div class="category"><span>cars</span></div>
​
​

Categories

Resources