How to add characters before and after h2 innerhtml - javascript

I've scoured for ways to do this, I'm probably just missing something very obvious, and for that I am sorry.
I'm trying to add two characters to a h2 element. Which I have done, but if I do more than one h2 the first one is copied. I would like the unique innerHTML of each h2 to have these characters added before and after.
I am aware I could do this with css but I already have before and after on the element doing other things.
$(window).on("load", function() {
// On page load, add greater than and less than signs to all h2s
var regH2 = $('h2').html();
$('h2').html( '<' + regH2 + '>' );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<h2>header1</h2>
<h2>header2</h2>

Try like this
$('h2').each(function(){
var regH2 = $(this).html();
$(this).html( '<' + regH2 + '>' );
});

Try to use the callBack function of .html(),
$(window).on("load", function() {
$('h2').html(function(_,regH2){
return '<' + regH2 + '>';
});
});
In the above code, regH2 will receive the old html string every time.

My answer uses CSS instead of JS:
h2:before { content:'<'; }
h2:after { content:'>'; }
<h2>header1</h2>
<h2>header2</h2>
This renders the content with "<" and ">" even before your page has loaded completely.
If :before and :after is already in use, consider adding extra elements like this:
h2 span:before { content:'<'; }
h2 span:after { content:'>'; }
<h2><span>header1</span></h2>
<h2><span>header2</span></h2>
For me I alway weep when static content is added via JS. ;)

Related

How to get startOffset/endOffset of selected html text?

I'm trying to wrap selected text from a "contenteditable" div in a given tag. Below seems to be working ok but startOffset/endOffset doesn't include HTML text. My question is how do I get the Range object to count the html tags if they exist in the selection?
getSelectedText: function() {
var range;
if (window.getSelection) {
range = window.getSelection().getRangeAt(0);
return [range.startOffset, range.endOffset];
}
}
toggleTagOnRange: function(range, tag, closeTag) {
var removeExp, val;
if (closeTag == null) {
closeTag = tag;
}
val = this.get("value");
removeExp = RegExp("<" + tag + ">(.+)</" + closeTag + ">");
if (removeExp.test(val)) {
this.set("value", val.replace(removeExp, function(match, $1) {
return $1;
}));
} else {
if (range.length > 1) {
val = val.splice(range[1], "</" + closeTag + ">").splice(range[0], "<" + tag + ">");
this.set("value", val);
}
}
return this.get("val");
}
// this is called from a bold button click handler.
this.toggleTagOnSelection(this.getSelectedText(), 'strong');
Interested in other solutions if you've got them.
Honestly, things can get pretty nasty when trying to write code for this type of thing yourself. There are a lot of cases you need to cover, like when you're selecting text across multiple <p> tags for example. You don't need to reinvent the wheel. Look into a library like rangy where they have already taken care of the nitty gritty details. Specifically for your situation, if you can get by with using CSS styles instead of using tag elements like <strong>, look into the CSS Class Applier Module, which allows you to do this simply by doing:
var cssApplier = rangy.createCssClassApplier("someClass", {normalize: true});
cssApplier.toggleSelection();
Where .someClass is a CSS class containing whatever styles you need to apply.

Select characters and wrap

I'm looking to wrap the last 2 characters in a piece of text in a <sup> using jQuery. I can do a console.log that returns the text I want to wrap, but it never gets wrapped. The code I have is really simple:
// get text of heading
var plansBlockHeading = $('.first .sub .one h4').text();
// filter to last 2 chars
var sup = plansBlockHeading.substr(plansBlockHeading.length-2);
// Wrap in a <sup></sup>
$(sup).wrap("<sup />");
I'm obviously missing something simple, but I'm not sure what. Any pointers?
I would use a regexp
var text = $('.first .sub .one h4').text();
text = text.replace(/^(.*)(.{2,2})$/, "$1<sup>$2</sup>");
$('.first .sub .one h4').html(text);
http://jsfiddle.net/evPhf/
var elem = $('.first .sub .one h4'),
text = elem.text(),
html = text.slice(0,-2) + '<sup>' + text.slice(-2) + '</sup>';
elem.html(html);​
FIDDLE
An idiomatic jQuery solution could look like this:
$('.first .sub .one h4').html(function(i, html) {
// make sure there's no whitespace issues
html = $.trim(html);
return html.slice(0, -2) + "<sup>" + html.slice(-2) + "</sup>";
});
This assumes there's no HTML markup inside the h4 (really just at the end would be an issue).
This also handles properly if you have more than one h4.

Why would javascript add a random style tag?

I'm using a script I found online to add input prompts on an html form. I got it all working, but now the code is randomly generated a style tag that's throwing off my css. The code is supposed to produce span tags that look like this:
<span id="input-prompt-0" class="input-prompt">Company Name</span>
For every text input field. Instead it keeps giving me this:
<span id="input-prompt-0" class="input-prompt" style="display: block;">Company Name</span>
Any ideas why?
Here's the code:
$(document).ready(function(){
$('input[type=text][title],input[type=password][title],textarea[title]').each(function(i){
$(this).addClass('input-prompt-' + i);
var promptSpan = $('<span class="input-prompt"/>');
$(promptSpan).attr('id', 'input-prompt-' + i);
$(promptSpan).append($(this).attr('title'));
$(promptSpan).click(function(){
$(this).hide();
$('.' + $(this).attr('id')).focus();
});
if($(this).val() != ''){
$(promptSpan).hide();
}
$(this).before(promptSpan);
$(this).focus(function(){
$('#input-prompt-' + i).hide();
});
$(this).blur(function(){
if($(this).val() == ''){
$('#input-prompt-' + i).show();
}
});
});
});
The line $('#input-prompt-' + i).show(); is modifying the style. From the docs on jQuery.show:
The matched elements will be revealed immediately, with no animation.
This is roughly equivalent to calling .css('display', 'block'), except
that the display property is restored to whatever it was initially.
I guess the more prominent question is why this is "throwing off [your] css"?
This line of code adds the style attribute:
$('#input-prompt-' + i).show();
You can instead use:
$('#input-prompt-' + i).css("display", "");
That will show the span and eliminate the style attribute.
The problem is most likely related to you using .show() and .hide().
These functions alter the style of the element to do their magic.
JQuery show() and hide() functions modified the styles

Does div with certain content exist

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

Numbering in jQuery

How could I change the text below so that the text within it has a number appended to it.
<div class="right">This is some text</div>
<div class="right">This is some text</div>
<div class="right">This is some text</div>
So the code above would become,
This is some text
This is some text
This is some text
you should use an ordered list... ol
or else you will need use css and add the content property your selector with the :after pseudo element.
How about the following?
$("div.right").each(function(i){
$(this).prepend((i + 1) + ". ");
});
UPDATE:
Here is one way that should work.
"number" is a custom element (it can be anything you want) that will/should be ignored by browsers.
$("div.right").each(function(i){
$(this).find("number").remove().end()
.prepend("<number>(i + 1) + ". </number>");
});
OR use the following which is probably a little slower but semantically correct...
$("div.right").each(function(i){
$(this).find("span.number").remove().end()
.prepend("<span class='number'>" + (i + 1) + ". </span>");
});
OR an even better way would be to prepend span.number before your first drag:
$(function(){ // document ready...
// caching the "numbers" will only work if you use the DOM
// for updating div position (like jQuery's "append()", "prepend()", "before()", and "after()") and not "innerHTML" or "html()"
var numbers = $("div.right").each(function(i){
$(this).prepend("<span class='number'>" + (++i) + "</span>. ");
}).find("span.number");
function dragEnd(){
// do your drag end stuff here...
numbers.each(function(i){
this.innerHTML = ++i;
});
)};
});
This is really an elaboration on another comment. I can't format code in a comment, I guess. You could use jQuery core's each:
$('div.right').each(function(ii){
html = $(this).html();
$(this).html(ii + '. ' + html);
});
jQuery selectors are your friend...
Get your stuff and loop on through something like this:
texts = $("div.right");
for(i = 0;i < texts.length;i++)
{
node = $(texts[i]);
content = node.html();
number = i + 1;
node.html(number + ". " + content);
}
Update: Jeez, last time post untested code straight off the dome here (disclaimer: not actually the last time). In the interest of correctness, I've updated it to at least run (and work!) if you still want to do it this way. Although I admit the other solutions are cleaner and more elegant.
Does this have to be done dynamically through jquery? Can't you just combine all that text into one div and then make a ordered list around it?
Using [] notation with a result set will give you the raw DOM element which does not have the html() function. Use the eq() function to get each element wrapped in a jQuery object.
You can also use each() as mentioned above, but I prefer straight 'for loops' so I don't have to adjust for 'this' if I'm in an event handler.
var texts = $("div.right");
var elem;
for(i = 1; i < texts.length; i++) {
elem = texts.eq(i);
html = elem.html();
elem.html(i + '. ' + html);
}

Categories

Resources