What I'm trying to do is add a [+] or [-] sign to an expandable heading so that once the user clicks on the heading, its content part will be shown and its sign part will change from + to - and vice versa. Since there are multiple headings, I used jQuery's next(). So far the .content toggling works well, but for some reason the sign is not changing.
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery(".content").hide();
jQuery(".heading").click(function()
{
jQuery(this).next(".content").toggle();
if (jQuery(this).next(".sign").text()=="[+]")
{jQuery(this).next(".sign").text("[-]");}
else
{jQuery(this).next(".sign").text("[+]");}
});
});
</script>
for (int i = 0; i < nodes.getLength(); i++)
{
Element element = (Element) nodes.item(i);
NodeList title = element.getElementsByTagName("Title");
Element ttl = (Element) title.item(0);
String linkTitle = getCharacterDataFromElement(ttl);
htmlReturn += "<a href='#' class='heading'><h4>" + linkTitle + " <span class='sign'>[+]</span></h4></a>";
htmlReturn += "<div class='content'>";
...
}
Because the sign is a descendant element of the heading, not a sibling, use find instead of next:
var sign = jQuery(this).find(".sign");
sign.text(sign.text() === "[+]" ? "[−]" : "[+]");
// Note: A minus sign (−) has the same width as a plus sign (+),
// whereas a hyphen (-) is typically narrower.
if (jQuery(".sign").text()=="[+]")
{jQuery(".sign").text("[-]");}
else
{jQuery(".sign").text("[+]");}
Well, next() only gets the immediate sibling. Try using closest() instead.
Related
Here I'm trying to create a calling pad that reads a maximum of 10 numbers at a time, and displays the numbers as a maximum of 6 numbers in a row. It's working functionally. I want to remove the last number when the user presses the clear button.
I used $("#calling-pad").last().remove(); to try to remove the last number, but it removes the whole contents and doesn't allow to enter a new number. How can I fix it?
var key = 1;
$("#nine").click(function(){
if (p === 1) {
$("#mini-screen").css("display","none");
$("#number-screen").css("display","block");
if (key < 11) {
if ((key % 7) !== 0) {
$("#calling-pad").append("9");
key = key + 1;
}
else {
$("#calling-pad").append("<br>");
$("#calling-pad").append("9");
key = key + 1;
}
}
}
});
$("#inner-icon-one").click(function(){
if (p === 1) {
$("#mini-screen").css("display","none");
$("#number-screen").css("display","block");
if (key > 1) {
if ((key%6) !== 0) {
$("#calling-pad").last().remove();
key = key - 1;
if ( key === 1) {
$("#number-screen").css("display","none");
$("#mini-screen").css("display","block");
}
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="calling-pad"> </span>
You are just appending numbers to a span tag and are not really keeping track of user input.
$("#calling-pad").last().remove();
Is telling jQuery to remove the full contents because you are not inserting any child elements to the calling-pad span.
Therefore you could use an array to keep track of the users numbers or use a counter as I have shown below.
var totalInputs = 0;
$("#insert").on("click", function() {
totalInputs++;
var inputText = $("#input").val();
var id = "calling_" + totalInputs;
$("#calling-pad").append("<span id='" + id + "'>" + inputText + "</span>");
});
$("#remove").on("click", function() {
$("#calling_" + totalInputs).remove();
totalInputs--;
});
span {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" id="input" />
<button id="insert">Insert</button>
<div id="calling-pad">
</div>
<button id="remove">Remove last element</button>
Problem - Using 'last' instead of ':last-child'
The jQuery last method does not find child elements. Instead, given a collection of elements matching a selector, it filters that collection to include only the last element. Combining this with an id-selector (i.e. $("#element-id").last()) is always redundant, since $("#element-id") only matches a single element, and the resulting jQuery object is always of size 1. If there's only one element, it's always the last one.
Therefore $("#calling-pad").last().remove(); is effectively the same as saying $("#calling-pad").remove();.
Solution
Instead, when you're appending data to the #calling-pad element, ensure they're included as new elements (e.g. wrapped in <span></span> tags):
$('#calling-pad').append("<span>9</span>");
Then, when you want to remove the last element in the #calling-pad, you simply have to do this:
$('#calling-pad > span:last-child').remove();
This finds all span elements that are direct children of the #calling-pad, filters that to only include the last element (using :last-child), and then removes that element.
$("#calling-pad").contents().last().remove();
if ($("#calling-pad").contents().last().is("br")) {
$("#calling-pad").contents().last().remove();
}
As you're dealing with textNodes, you need to use .contents() - the <br> split them up so no need to parse things, and if you're deleting the last node, you need to delete the last break at the same time...
You need one line to remove last comment... no need to count ids ...
here is snippet ... Cheers Man
$("#insert").on("click", function() {
var inputText = $("#input").val();
$("#calling-pad").append("<span>" + inputText + "</br></span>");
});
$("#remove").click(function(){
$("#calling-pad").children("span:last").remove()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" id="input" />
<button id="insert">Insert</button>
<div id="calling-pad">
</div>
<button id="remove">Remove last one</button>
Problem
Suppose that in the backend of my Web application I have a generic string of letters:
seq = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
and an array of positions in such a string:
pos = [(0, 2), (4, 8)]
I need to render this sequence in the frontend by splitting it every n characters. Then when a user clicks a button I need to highlight the sequence between two parameters (taken from pos) for which the button refers to.
My solution
I solve this by implementing a Javascript function formatSequence which splits seq every n characters and iterates through the pos array in order to wrap each substring inside a span tag. The result is something like this:
<pre>
<span class="A">AA</span>AA<span class="B">A</span>
<span class="B">AAA</span>AA
AAAAA
</pre>
When the user clicks the button referring to the class A I simply change the CSS background rule for class A.
It works :) But the function formatSequence is way too complicated imho. It was a pain dealing with multiple lines. I prefer not posting the code since I am looking for other approaches not changing the code of such function.
A better solution?
I think that a (better?) solution would be to implement a function that given two parameters start and end it dynamically highlights the text between them. But it appears to be even more complicated than the previous one (remember that the sequence must be split every n characters and thus the highlight must be multilines).
Any suggestions? Better approach to solve this?
One simple solution would be just to print the full seq multiple times into the HTML and hide every row you don't need at the time. When a user clicks on a button, another row would be displayed (and the first one would be hidden).
HTML:
<div class="rows"></div>
<div class="buttons"></div>
JavaScript (depending on jQuery):
(function generateRowsAndButtons() {
var sequence = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
var position = [ [0,2], [4,8] ];
var $rows = $('.rows');
var $buttons = $('.buttons');
for(var i = 0; i < position.length; i++) {
if(position[i].length !== 2 || position[i][0] > position[i][1]) {
console.log("every position array needs exactly two values with the second larger than the first one");
continue;
}
// the index is used for mapping the button the highlight position
var row = '<div class="row" data-index="' + i + '" style="display: none;">';
// you should add some checks here, if position larger then the length of the string to avoid some misbehaviors. this is of course only necessary if you aren't validating the values on another place.
row += sequence.substring(0, position[i][0]);
row += '<span class="highlighted">';
row += sequence.substring(position[i][0], position[i][1]);
row += '</span>';
row += sequence.substring(position[i][1]);
row += '</div>';
var $row = $(row);
$rows.append($row);
// a button needs the index to find the link the highlighted value
var $button = $('<button data-index="' + i + '">' + position[i] + '</button>');
$buttons.append($button);
}
$buttons.find('button').click(function() {
var index = $(this).data('index');
// hide every row, except the one with the correct index
$rows.find('.row').hide().filter('[data-index="' + index + '"]').show();
});
})();
CSS:
.row .highlighted {
background: yellow;
}
Here is a jsFiddle: https://jsfiddle.net/y8uoou1L/2
On a random break I found myself wondering if it would be possible to use jQuery to determine a single character within a sentence when it is clicked on.
For example:
This
When the user clicks on first h, jQuery would return this to me.
The only way I could think of doing this would be to wrap each character within the sentence in a span with a class of its letter such as the following example:
<span class="clickable T">T</span>
<span class="clickable h">h</span>
<span class="clickable i">i</span>
<span class="clickable s">s</span>
Followed by a $('.clickable').click(function()) that would return its second class.
My question is: is this the most efficient way to do this?
Obviously wrapping every single letter of the document in span tags is not efficient.
I was able to spin something up that works in Chrome at least. Basically, when you click on a letter, it then triggers a double clicks which selects the word. We get the selection which actually gives us the text of the entire target element. From that, we get the letter that was clicked. We remove the selection and do what we want with the letter.
Fiddle here
$(function(){
$(document).click(function(e){
var target = e.target;
$(target).dblclick();
}).dblclick(function(){
var selection,
node,
text,
start,
end,
letter;
if (window.getSelection) {
selection = document.getSelection();
node = selection.anchorNode;
if (node.nodeType === 3) {
text = node.data;
start = selection.baseOffset;
end = selection.extentOffet;
if (!isNaN(start)) {
letter = text.substr(start, 1);
}
}
window.getSelection().removeAllRanges()
} else if(document.selection) {
//continue work here
}
if (letter) {
alert(letter);
}
});
});
You could return the innerHTML as well with:
$('.clickable').on('click', function(){
alert($(this).html());
});
As for a more efficient way to do it...maybe try this:
in Javascript/jQuery, how to check a specific part of a string and determine if it is a whitespace or letter?
You can do it with this script
$('.clickable').on('click', function(){
var html = $(this).text(); // if you want the text inside the span
var index = $(this).index(); // if you want the position among siblings
var classes = $(this).attr('class').split(" ");
var secondClass = getSecondClass(classes);
});
function getSecondClass(classArray){
if(classArray.length<2){
return null;
}else{
return classArray[1];
}
}
I've also included the html and index variables if you want to do something else with the clicked element.
Basically you split the classes of the element by spaces and then check if the array has less than two elements, in that case it returns null, otherwise it returns the second element.
jsFiddle
Well wrapping all text dyanamically with span tag , it is possible what you were looking for
JS
$(function(){
var lengthText = $('#singlecharacter').text().length;
var textValue = $('#singlecharacter').text();
var textArray = textValue.split('');
var newText = new Array();
for (var i = lengthText - 1; i >= 0; i--) {
newText[i] = "<span class='sp'>"+textArray[i]+"</span>";
};
$('#singlecharacter').html(newText);
$('.sp').click(function()
{
alert($(this).text());
});
});
HTML
<div id='singlecharacter'>THIS</div>
DEMO JSFIDDLE
The Html that I'm getting ideally looks like this:
<span class="RapidLink1-H">See the more detailed areas of what not</span>
Next my aim is to change the span tag into an anchor tag. With the ideal Html, I have done it this way:
// Walk through each link tag on this page and replace the content with an actual link
thisLink.each(function() {
linkRefTarget = '';
// Get only the identifier number of the link
linkId = ($(this).attr('class')).replace(/[A-Za-z$-]/g, '');
// Match this link with the list of link references
if (thisLinkRef) {
for (var key in thisLinkRef) {
if (key == 'link' + linkId) linkRefTarget = thisLinkRef[key];
}
}
output = '';
output+= '<a href="#' + linkRefTarget + '" id="link' + linkId + '" class="rapidLink">';
output+= $(this).html();
output+= '</a>';
}).replaceWith(output);
Now, the problem comes when I'm actually getting this sort of Html (please note, I can't change the Html input):
<span class="RapidLink1-H">See the</span><span class="RapidLink1-H">more detailed areas of</span><span class="RapidLink1-H">what not</span></span>
The question is:
How could I get it to work with such a broken set of spans?
I'm thinking the following:
Find an expected link span
Check whether the immediate next element is also a span with the same class
and then check whether the immediate next element is also...,
and then check...
if none is found, combine the innerHtml of each span into a single anchor tag
How could I achieve such a loop?
Thanks.
There is the + selector which selects consecutive elements: http://jsfiddle.net/NWWYC/1/.
$(".RapidLink1-H + .RapidLink1-H").each(function() {
// move contents to previous span, remove this span afterwards
$(this).prev(".RapidLink1-H").append(
$(this).contents()
).end().remove();
});
If I have a container div called #container which has a bunch of .inside divs in it, how would I go about checking whether a certain .inside div with a specified content (just a string of English text) exists or not? I'm doing this to prevent duplicates in a notification system I'm setting up for a website. I don't need the actual text - just whether it exists. Also, being able to modify the content of the .inside div if it's found would be good, so I can increment and show the number of times that message has occurred (grouping, if you like).
Thanks,
James
I like using selectors (others have used .filter, which is equally an option).
$(".inside:contains('waldo')").css({color: 'red'});
This is case sensitive.
Use the contains-selector[docs], then the length[docs] property to see how many were found.
var some_string = "test";
var els_with_string = $('#container .inside:contains(' + some_string + ')');
// use .length to check to see if there was at least one
if( els_with_string.length ) {
alert( "at least one already exists" );
}
From the docs:
Description: Select all elements that contain the specified text.
The matching text can appear directly within the selected element, in any of that element's descendants, or a combination thereof. As with attribute value selectors, text inside the parentheses of :contains() can be written as bare words or surrounded by quotation marks. The text must have matching case to be selected.
With respect to modifying the content if found, it would depend on what sort of modification you want to do. I don't know exactly what you mean by grouping.
EDIT: With respect to your comment, you could accomplish what you need like this:
var error = "ERROR:SomeError ";
var el_with_error = $('#container .inside:contains(' + error + ')');
if (el_with_error.length) {
var text = el_with_error.text();
if (/\(\d+\)/.test(text)) {
var new_text = text.replace(/\((\d+)\)/, function(s, g1) {
g1++;
return "(" + g1 + ")";
});
el_with_error.text(new_text);
} else {
el_with_error.text(text + " (2)");
}
} else {
$('#container').append('<div class="inside">' + error + '</div>');
}
Live Example: http://jsfiddle.net/ScZbV/
We could get by without the regular expression if you were able to wrap the grouping quantity in a <span> element.
var error = "ERROR:SomeError ";
var el_with_error = $('#container .inside:contains(' + error + ')');
if (el_with_error.length) {
var span = el_with_error.find('span');
if (span.length) {
var num = +span.text();
span.text( ++num );
} else {
el_with_error.append(" (<span>2</span>)");
}
} else {
$('#container').append('<div class="inside">' + error + '</div>');
}
Example: http://jsfiddle.net/ScZbV/1/
To check existence
$("#container .inside:contains('old text')").size() > 0
To modify the text
$("#container .inside:contains('old text')").text('new text');
Here's a slightly different way of looking at it...
Apply a class name for each "type" of notification. So your notification markup looks like:
<div class="inside error">Error</div>
Then inside of looking for a string inside these divs, use these new class names to your advantage and make use of .find(). If jQuery returns an object then its exists, so do something with it. But if it returns nothing then add it.
Example: http://jsbin.com/imexi4