Hide content inside brackets using pure JavaScript - javascript

I want to use pure JavaScript to hide all content inside brackets in a document. For example, this:
Sometext [info]
would be replaced with this:
Sometext
With jQuery I can do this with:
<script type="text/javascript">
jQuery(document).ready(function(){
var replaced = jQuery("body").html().replace(/\[.*\]/g,'');
jQuery("body").html(replaced);
});
</script>

The document's DOMContentLoaded event will fire at the same time as the callback you pass to jQuery(document).ready(...).
You can access the body of the page through document.body instead of jQuery("body"), and modify the HTML using the .innerHTML property instead of jQuery's .html() method.
document.addEventListener("DOMContentLoaded", function(event) {
var replaced = document.body.innerHTML.replace(/\[.*\]/g,'');
document.body.innerHTML = replaced;
});

If you use, document.body.innerHTML to replace, it is going to replace everything between [], even valid ones like input names. So I think what you need is to grab all of the textnodes and then run the regex on them. This question looks like it will do the trick.
function recurse(element)
{
if (element.childNodes.length > 0)
for (var i = 0; i < element.childNodes.length; i++)
recurse(element.childNodes[i]);
if (element.nodeType == Node.TEXT_NODE && /\S/.test(element.nodeValue)){
element.nodeValue = element.nodeValue.replace(/\[.*\]/g,'');
}
}
document.addEventListener('DOMContentLoaded', function() {
// This hits the entire document.
// var html = document.getElementsByTagName('html')[0];
// recurse(html);
// This touches only the elements with a class of 'scanME'
var nodes = document.getElementsByClassName('scanME');
for( var i = 0; i < nodes.length; i++) {
recurse(nodes[i]);
}
});

You already have the solution, try "Sometext [info]".replace(/\[.*\]/g,'');

Basically what your doing is this
document.addEventListener('DOMContentLoaded', function() {
var replaced = document.body.innerHTML.replace(/\[.*\]/g,'');
document.body.innerHTML = replaced
});
That would be a silly idea though (speaking for myself)
Make your life easier & your site better by doing something like this
<p> Sometext <span class="tag-variable"> [info] </span> </p>
document.addEventListener('DOMContentLoaded', function(){
var tags = document.getElementsByClassName('tag-variable');
for( var i = 0; i < tags.length; i++) {
var current = tags[i]; // Work with tag here or something
current.parentNode.removeChild( current );
}
});

Related

select html element by its full html tag - JS

I am looking for a way to be able to select an HTML element by its tag, like:
document.querySelector("<div id='myDiv'\>hello world</div\>")
//instead of: document.querySelector("#myDiv")
However, this code returns an error. The code should return the HTML element.
Does anybody know a way to achieve this? (vanilla JS preferred)
It seems a bit odd that you wouldn't want to select element via ID. But regardless one way of selecting the element in your example would be to look for its innerHTML.
e.g
var div = document.getElementsByTagName('div');
for (var i=0;i<div.length;i++){
console.log(div[i].innerHTML)
if(div [i].innerHTML == 'hello world'){
var element = div[i].parentElement
console.log(element)
break;
}
}
You could use outerHTML to search for it, however this only works if the element has a parent element.
var els = Array.from(document.querySelector('body *')); //this selects all elements in the body
var el;
for(var i = 0; i < els.length; i++) {
if(els.outerHTML === "<div id='myDiv'\>hello world</div\>") {
el = els[i];
}
}
//Use the el variable for your element

Formatting a href link with appendChild, setAttribute, etc

I am attempting to populate a list with href links via javascript.
Here is an example of the html I would like to create:
<li> Complete blood count</li>
Where "#modal-one" displays a pop up.
I have used the following and several other iterations to try and create this dynamically:
<script>
var listItem = [];
function createTestList() {
var tests = results.tests; //an array to tests to populate list
var i;
var j;
for (i = 0; i < tests.length ; i++ ){
listItem[i] = document.createElement("li");
var node = document.createTextNode(tests[i].name);
listItem[i].appendChild(node);
listItem[i].setAttribute("href", "#modal-one");
addOnClick(i);
//var element = document.getElementById("div1");
//element.appendChild(listItem[i]);
document.body.appendChild(listItem[i]);
console.log(listItem[i]);
};
};
function addOnClick(j) { //this is separate to handle the closure issue
listItem[j].onclick = function() {loadModal(j)};
};
</script>
However, this code (and several others) produce:
<li href='#modal-one'>Complete Blood Count</li> //note missing <a>...</a>
It appears there are several ways to achieve this, but nothing seems to work for me...
You are never actually adding in an anchor tag. You are creating a list-item (li), but you are adding an href to that list-item rather than adding an anchor node to it with that href. As such, the browser just thinks you have a list-item with an href attribute.
Consider using the following instead:
<script>
var listItem = [];
function createTestList() {
var tests = results.tests; //an array to tests to populate list
var i;
var j; // Never actually used in function. Consider omitting
for (i = 0; i < tests.length ; i++ ){
// create the list item
listItem[i] = document.createElement("li");
// Create the anchor with text
var anchor = document.createElement("a");
var node = document.createTextNode(tests[i].name);
anchor.appendChild(node);
anchor.setAttribute("href", "#modal-one");
// Set the onclick action
addOnClick(i, anchor);
// Add the anchor to the page
listItem[i].appendChild(anchor);
document.body.appendChild(listItem[i]);
console.log(listItem[i]);
};
};
// Modified "addOnClick" to include the anchor that needs the onclick
function addOnClick(j, anch) { //this is separate to handle the closure issue
anch.onclick = function() {loadModal(j)};
};
</script>
A couple things to note:
I have modified your addOnClick() function because it is the anchor element that needs the onclick, not the list item.
I have added in the creation of an anchor element rather than simply creating a list item and adding the href to that.
I do not see creating a element, change code to:
var aNode=document.createElement("a");
aNode.innerText=tests[i].name;
aNode.setAttribute("href", "#modal-one");
listItem[i].appendChild(aNode);
You can change also click method, to use it on a not on li
function addOnClick(j) {
listItem[j].querySelector("a").addEventListener("click",function(e) {
e.preventDefault();//this prevent for going to hash in href
loadModal(j);
});
};
Okay. I missed the anchor tag. My bad...
Spencer's answer came close, but I had to make few changes to get it work in my instance.
The final working code (and honestly I am not sure why it works) is:
<script>
var listItem = [];
function createTestList() {
var tests = results.tests;
var i;
//var j;
for (i = 0; i < tests.length ; i++ ){
// create the list item
listItem[i] = document.createElement("li");
// Create the anchor with text
var anchor = document.createElement("a");
anchor.setAttribute("href", "#modal-one");
var node = document.createTextNode(tests[i].name);
anchor.appendChild(node);
// Set the onclick action
addOnClick(i);
// Add the anchor to the page
listItem[i].appendChild(anchor);
document.getElementById("demo").appendChild(listItem[i]); //added the list to a separate <div> rather than body. It works fine like this.
console.log(listItem[i]);
};
};
function addOnClick(j) { //this is separate to handle the closure issue
//didn't need the additional code beyond this
listItem[j].onclick = function() {loadModal(j)};
};
</script>
Thanks to all and Spencer thanks for the thoroughly commented code. It helps!!!

(jquery) change nested same html tag to other bbcode tag

ok here is what i have:
<div id="mydiv">
<font color="green"><font size="3"><font face="helvetica">hello world</font></font></font>
</div>
I know the tags are strange, but that's what produced by the website.
So basically I want to change the font tag to bbcdoe tag, the jquery code I wrote:
$("#mydiv").find("font").text(function(){
var text = $(this).text();
var size = $(this).attr("size");
var color = $(this).attr("color");
var face = $(this).attr("face");;
if(size!=undefined){
return '[size="'+size+'"]'+text+'[/size]';
}
if(color!=undefined){
return '[color="'+color+'"]'+text+'[/color]';
}
if(face!=undefined){
return '[type="'+face+'"]'+text+'[/type]';
}
});
so what I got is only: [color="green"] hello world [/color]. always only the first tag. any idea?
ps: I tried each, replaceWith, html(), all the same result. only the first tag is change.
The reason it doesn't work is because when you call
$("#mydiv").find("font").text("New text")
For each font tag, starting from the first tag, it will replace the text within that tag.
Here is an example to show you what's going on.
Example | Code
$fonts = $("font","#mydiv");
console.log($fonts.text());
$fonts.text(function(){
return "New text";
});
console.log($fonts.text());
Here is an example of how you could do it instead
Example | Code
jQuery.fn.reverse = [].reverse;
var attributes= ["size", "color", "face"];
var text = $.trim($("#mydiv").text());
$("font","#mydiv").reverse().each(function(i, e) {
for (var i = 0; i < attributes.length; ++i){
var attr = $(e).attr(attributes[i]);
if( typeof attr != "undefined")
text = "["+attributes[i]+"="+attr+"]"+text+"[/"+attributes[i]+"]";
}
});
$("#mydiv").text(text);
A room full of sad, wailing kittens wishes that you'd get rid of those <font> tags, but you could probably make it work by explicitly working your way down through the nested tags.
It does what it does now because the outer call to .text() runs for the very first <font> tag, and it obliterates the other tags.
edit — to clarify, when you call
$('#mydiv').find('font')
jQuery will find 3 font tags. The library will therefore call the function you passed into .text() for each of those elements. However, the first call will have the effect of removing the other two <font> elements from the DOM. Even though the library proceeds to call your callback for those elements, there's no effect because they're not on the page anymore.
Here's what could work:
var $fonts = $('#mydiv').find('font');
var text = $fonts.text();
var attrs = {};
$fonts.each(function(_, font) {
var names = ["size", "color", "face"];
for (var i = 0; i < names.length; ++i)
if (font[names[i]]) attrs[names[i]] = font[names[i]];
});
var newText = "";
for (var name in attrs) {
if (attrs.hasOwnProperty(name))
newText += '[' + name + '=' + attrs[name] + ']';
}
newText += text;
for (var name in attrs) {
if (attrs.hasOwnProperty(name))
newText += '[/' + name + ']';
}
$('#mydiv').text(newText);
Note that I'm not really sure why you want to put the BBCode onto the page like that, but it seems to be the intention.
Seems to me your first line should be:
$("#mydiv").find("font").each(function(){

jQuery/javascript replace tag type

Is there an easy way to loop through all td tags and change them to th? (etc).
My current approach would be to wrap them with the th and then remove the td, but then I lose other properties etc.
jQuery.replaceTagName
The following is a jQuery plugin to replace the tag name of DOM elements.
Source
(function($) {
$.fn.replaceTagName = function(replaceWith) {
var tags = [],
i = this.length;
while (i--) {
var newElement = document.createElement(replaceWith),
thisi = this[i],
thisia = thisi.attributes;
for (var a = thisia.length - 1; a >= 0; a--) {
var attrib = thisia[a];
newElement.setAttribute(attrib.name, attrib.value);
};
newElement.innerHTML = thisi.innerHTML;
$(thisi).after(newElement).remove();
tags[i] = newElement;
}
return $(tags);
};
})(window.jQuery);
Minified Source
(function(e){e.fn.replaceTagName=function(t){var n=[],r=this.length;while(r--){var i=document.createElement(t),s=this[r],o=s.attributes;for(var u=o.length-1;u>=0;u--){var a=o[u];i.setAttribute(a.name,a.value)}i.innerHTML=s.innerHTML;e(s).after(i).remove();n[r]=i}return e(n)}})(window.jQuery);
Usage
Include the above minified source in your javascript after jQuery.
Then you can use the plugin like this:
$('div').replaceTagName('span'); // replace all divs with spans
Or in your case this:
$('td').replaceTagName('th');
jQuery selectors work as expected
$('.replace_us').replaceTagName('span'); // replace all elements with "replace_us" class with spans
$('#replace_me').replaceTagName('div'); // replace the element with the id "replace_me"
More resources
jsFiddle with Qunit tests
Completely untested, but giving this a whirl:
$("td").each(function(index) {
var thisTD = this;
var newElement = $("<th></th>");
$.each(this.attributes, function(index) {
$(newElement).attr(thisTD.attributes[index].name, thisTD.attributes[index].value);
});
$(this).after(newElement).remove();
});
I'm looking and looking at it, and I can't think of a reason why it wouldn't work!
1) loop through each td element
2) create a new th element
3) for each of those td's, loop over each of its attributes
4) add that attribute and value to the new th element
5) once all attributes are in place, add the element to the DOM right after the td, and remove the td
Edit: works fine: http://jsbin.com/uqofu3/edit
$("td").each(function() {
var tmp = $('<div/>').append($(this).clone(true)).html().replace(/td/i,'th');
$(this).after(tmp).remove();
});
or pure DOM
function replaceElm(oldTagName, newTagName, targetElm) {
var target = targetElm || window.document;
var allFound = target.getElementsByTagName(oldTagName);
for (var i=0; i<allFound.length; i++) {
var tmp = document.createElement(newTagName);
for (var k=0; k<allFound[i].attributes.length; k++) {
var name = allFound[i].attributes[k].name;
var val = allFound[i].attributes[k].value;
tmp.setAttribute(name,val);
}
tmp.innerHTML = allFound[i].innerHTML;
allFound[i].parentNode.insertBefore(tmp, allFound[i]);
allFound[i].parentNode.removeChild(allFound[i]);
}
}
replaceElm('td','th',document.getElementsByTagName('table')[0]);
DOM is always faster: http://jsperf.com/replace-tag-names
This might work, but I haven't tested it extensively:
var tds = document.getElementsByTagName("td");
while(tds[0]){
var t = document.createElement("th");
var a = tds[0].attributes;
for(var i=0;i<a.length;i++) t.setAttribute(a[i].nodeName,a[i].nodeValue);
t.innerHTML = tds[0].innerHTML;
tds[0].parentNode.insertBefore(t,tds[0]);
tds[0].parentNode.removeChild(tds[0]);
}
I hope it helps in some way.
Slight addition to #GlenCrawford answer, to also preserve inner text with the line:
newElement.text($(value).text());
All together now:
$("td").each(function(index) {
var thisTD = this;
var newElement = $("<th></th>");
newElement.text($(value).text());
$.each(this.attributes, function(index) {
$(newElement).attr(thisTD.attributes[index].name, thisTD.attributes[index].value);
});
$(this).after(newElement).remove();
});
Well this question is pretty old but this could help anyway: the only jQuery plugin that actually works as expected (you can't reuse the returned object in the other one, to add attributes for example):
jQuery.fn.extend({
replaceTagName: function(replaceWith) {
var tags=[];
this.each(function(i,oldTag) {
var $oldTag=$(oldTag);
var $newTag=$($("<div />").append($oldTag.clone(true)).html().replace(new RegExp("^<"+$oldTag.prop("tagName"),"i"),"<"+replaceWith));
$oldTag.after($newTag).remove();
tags.push($newTag.get(0));
});
return $(tags);
}
});
Besides the basic $("td").replaceTagName("th"); you can also chain calls like $("td").replaceTagName("th").attr("title","test");
Minified version:
jQuery.fn.extend({replaceTagName:function(a){var b=[];this.each(function(d,c){var e=$(c);var f=$($("<div />").append(e.clone(true)).html().replace(new RegExp("^<"+e.prop("tagName"),"i"),"<"+a));e.after(f).remove();b.push(f.get(0))});return $(b)}});
This is a bit cleaner than #GlenCrawford's answer and additionally copies the children of the replaced element.
$('td').each(function(){
var newElem = $('<th></th>', {html: $(this).html()});
$.each(this.attributes, function() {
newElem.attr(this.name, this.value);
});
$(this).replaceWith(newElem);
});

get element after page loads

how do i call a function to count the number of divs with an id of 'd1' after the page loads. right now i have it in my section but doesnt that execute the script before anything in the loads? because it works if i put the code below the div tags...
Firstly there should be at most one because IDs aren't meant to be repeated.
Second, in straight Javascript you can call getElementById() to verify it exists or getElementsByTagName() to loop through all the divs and count the number that match your criteria.
var elem = document.getElementById("d1");
if (elem) {
// it exists
}
or
var divs = document.getElementsByTagName("div");
var count = 0;
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
if (div.id == "d1") {
count++;
}
}
But I can't guarantee the correct behaviour of this because like I said, IDs are meant to be unique and when they're not behaviour is undefined.
Use jQuery's document.ready() or hook up to the onLoad event.
well an ID should be unique so the answer should be one.
you can use <body onload='myFunc()'> to call a script once the DOM is loaded.
You need to have the function tied to the onload event, like so:
window.onload = function() {
var divElements = document.getElementById("d1");
var divCount = divElements.length;
alert(divCount);
};
For the record, you should only have one div with that ID, as having more than one is invalid and may cause problems.

Categories

Resources