<div id="tab1" class="nav left">
<ul>
<li>Home</li>
......
</ul>
</div>
Now, i want to remove the class="now" or set the class value empty. If the url not on mangento, I using the following code. But the I don't know how to write the last part.
window.onload = function removeNow() {
var div = document.getElementById("tab1").getElementsByTagName("a");
if (window.location.pathname != '/magento/') {
div.removeClass();
}
}
Thank you.
In modern browsers you can use the classList API:
div.classList.remove( 'now' );
But a problem specific to your code: You must loop in order to remove the class. So try this:
for ( var i = 0; i < div.length; i++ ) {
div[i].classList.remove( 'now' );
}
If your browser doesn't support classList, use this removeClass shim:
function removeClass( elem, name ) {
var classlist = elem.className.split( /\s/ ),
newlist = [],
idx = 0;
for ( ; idx < classlist.length; idx++ ) {
if ( classlist[ idx ] !== name ) {
newlist.push( classlist[ idx ] );
}
}
elem.className = newlist.join(" ");
return true;
}
or with jQuery (with which we are not required to use classList or className):
$('a').each(function() {
if (window.location.pathname != '/magento/')
$(this).removeClass();
});
Set the className property:
div.className = '';
Note that getElementsByTagName returns a (possibly empty) NodeList, so:
var div = document.getElementById("tab1").getElementsByTagName("a");
is a collection of all the A element descendents of the element with ID "tab1" (and so 'div' is probably not a good name).
If all you want to do is remove all class values of the first such A element, then:
div[0].className = '';
will do the job. But since the NodeList might be empty, the following would be more robust:
if (div[0]) {
div[0].className = '';
}
or perhaps
div[0] && div[0].className = '';
it depends on your coding style and maintainability requirements.
Related
I want to add only one css style in JS. I don't want to include jQuery for only one thing.
My code:
document.addEventListener('DOMContentLoaded', function() {
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var productAttr = document.getElementsByClassName('product-attributes');
productAttr.style.top = "-90px";
}
});
The error from console is:
TypeError: 'undefined' is not an object (evaluating 'productAttr.style.top = "-90px"')
If I want change other styles f.e. opacity or color, I get the same problem.
How can I fix this ?
Thanks in advance for help.
You need to loop through your results because getElementsByClassName() returns a collection of elements:
for(var i = 0; i < productAttr.length; i++)
{
productAttr[i].style.top = "-90px";
}
Maybe it's because you can not give negative values in CSS
top:"-90px" === bottom "90px"
Maybe now it would work
document.addEventListener('DOMContentLoaded', function() {
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var productAttr = document.getElementsByClassName('product-attributes');
productAttr.style.bottom = "90px";
}
});
It's preferred to have an id assigned to the targeted element then target using getElementById() as there cannot be elements with the same id, hence getElementByClassName() will return an array if there are multiple elements with the same className. If you need to target multiple elements, you should for-loop through them while applying the change to the nth item being looped:
for(x = 0; x < array.length; x++){
array[x].style.top = '-90px';
}
Gentle reminder: also remember to have position: relative|absolute|fixed to ensure 'top' attribute works
edited with thanks to Sebastien Daniel
When selecting a class you have to indicate what number is as an Tag, it is not like the id that there is only one.
It would be something like this code depending on which of the classes you want to apply it:
document.addEventListener('DOMContentLoaded', function() {
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var productAttr = document.getElementsByClassName('product-attributes');
productAttr[0].style.top = "-90px";
productAttr[1].style.top = "-90px";
productAttr[2].style.top = "-90px";
}
});
Given an element and any selector, I need to find the closest element which matches it, not matter if it's inside the element or outside of it.
Currently jQuery doesn't provide such traversing functionality, but there is a need. Here is the scenario:
A list of many items where the <button> element reside inside <a>
<ul>
<li>
<a>
<button>click me</button>
<img src="..." />
</a>
</li>
<li>
<a>
<button>click me</button>
<img src="..." />
</a>
</li>
...
</ul>
Or the <button> element might reside outside of the <a> element
<ul>
<li>
<a>
<img src="..." />
</a>
<button>click me</button>
</li>
<li>
<a>
<img src="..." />
</a>
<button>click me</button>
</li>
...
</ul>
The very very basic code would look like this:
$('a').closest1('button'); // where `closest1` is a new custom function
// or
$('a').select('> button') // where `select` can parse any selector relative to the object, so it would also know this:
$('a').select('~ button') // where the button is a sibling to the element
the known element is <a> and anything else can change. I want to locate the nearest <button> element for a given <a> element, no matter if that button is inside or outside of <a>'s DOM tree.
It would be very logical that native jQuery function "closest" would do as the name suggests and find the closest, but it only searches upwards as you all know. (it should have been named differently IMO).
Does anyone know any custom traversing function which does the above?
Thanks. (i'm asking you people because someone must have written this for sure but I was unlucky to find a lead on the internet)
Here is another attempt using the idea I mentioned in comment:
$(this).parents(':has(button):first').find('button').css({
"border": '3px solid red'
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/z3vwk1ko/40/
It basically looks for the first ancestor that contains both the elements (clicked and target), then finds the target.
Performance:
With regard to speed, this is used at human interaction speeds, i.e. a few times per second maximum, so being a "slow selector" is irrelevant if it solves the problem, in a reasonably obvious way, with minimal code. You would have to click 100s of times per second to notice any different compared to a fast selector :)
None of the built-in selectors allow searching up and down the tree. I did create a custom findThis extension that allows you to do things like $elementClicked.('li:has(this) button') which would allow you to do something similar.
// Add findThis method to jQuery (with a custom :this check)
jQuery.fn.findThis = function (selector) {
// If we have a :this selector
if (selector.indexOf(':this') > 0) {
var ret = $();
for (var i = 0; i < this.length; i++) {
var el = this[i];
var id = el.id;
// If not id already, put in a temp (unique) id
el.id = 'id' + new Date().getTime();
var selector2 = selector.replace(':this', '#' + el.id);
ret = ret.add(jQuery(selector2, document));
// restore any original id
el.id = id;
}
ret.selector = selector;
return ret;
}
// do a normal find instead
return this.find(selector);
}
// Test case
$(function () {
$('a').click(function () {
$(this).findThis('li:has(:this) button').css({
"border": '3px solid red'
});
});
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/z3vwk1ko/38/
note: Click the images/links to test.
A while ago I wanted to do the same for a completely DOM-based text editor, and needed to find the previous (ARR LEFT) and next (ARR RIGHT) text nodes, both up and down the tree. Based on this code I have made an adaptation suiting this question. Be warned, it's quite performance-heavy, but it is adapted to any scenario. There are two functions findPrevElementNode and findNextElementNode which both return an object with properties:
match - returns the closest matching node for the search or FALSE if none is found
iterations - returns the number of iterations done to find the node. This allows you to check whether the previous node is closer than the next or vice-versa.
The parameters are as follows:
//#param {HTMLElement} referenceNode - The node from which to start the search
//#param {function} truthTest - A function that returns true for the given element
//#param {HTMLElement} [limitNode=document.body] - The limit up to which to search to
var domUtils = {
findPrevElementNode: function(referenceNode, truthTest, limitNode) {
var element = 1,
iterations = 0,
limit = limitNode || document.body,
node = referenceNode;
while (!truthTest(node) && node !== limit) {
if (node.previousSibling) {
node = node.previousSibling;
iterations++;
if (node.lastChild) {
while (node.lastChild) {
node = node.lastChild;
iterations++;
}
}
} else {
if (node.parentNode) {
node = node.parentNode;
iterations++;
} else {
return false;
}
}
}
return {match: node === limit ? false : node, iterations: iterations};
},
findNextElementNode: function(referenceNode, truthTest, limitNode) {
var element = 1,
iterations = 0,
limit = limitNode || document.body,
node = referenceNode;
while (!truthTest(node) && node !== limit) {
if (node.nextSibling) {
node = node.nextSibling;
iterations++;
if (node.firstChild) {
while (node.firstChild) {
node = node.firstChild;
iterations++;
}
}
} else {
if (node.parentNode) {
node = node.parentNode;
iterations++;
} else {
return false;
}
}
}
return {match: node === limit ? false : node, iterations: iterations};
}
};
In your case, you could do:
var a = domUtils.findNextElementNode(
document.getElementsByTagName('a')[0], // known element
function(node) { return (node.nodeName === 'BUTTON'); }
);
var b = domUtils.findPrevElementNode(
document.getElementsByTagName('a')[0], // known element
function(node) { return (node.nodeName === 'BUTTON'); }
);
var result = a.match ? (b.match ? (a.iterations < b.iterations ? a.match :
(a.iterations === b.iterations ? fnToHandleEqualDistance() : b.match)) : a.match) :
(b.match ? b.match : false);
See it in action.
DEMO PAGE / GIST
I have solved working by logic, so I would first look inside the elements, then their siblings, and last, if there are still unfound items, I would do a recursive search on the parents.
JS CODE:
jQuery.fn.findClosest = function (selector) {
// If we have a :this selector
var output = $(),
down = this.find(selector),
siblings,
recSearch,
foundCount = 0;
if(down.length) {
output = output.add(down);
foundCount += down.length;
}
// if all elements were found, return at this point
if( foundCount == this.length )
return output;
siblings = this.siblings(selector);
if( siblings.length) {
output = output.add(siblings);
foundCount += siblings.length;
}
// this is the expensive search path if there are still unfound elements
if(foundCount < this.length){
recSearch = rec(this.parent().parent());
if( recSearch )
output = output.add(recSearch);
}
function rec(elm){
var result = elm.find(selector);
if( result.length )
return result;
else
rec(elm.parent());
}
return output;
};
// Test case
var buttons = $('a').findClosest('button');
console.log(buttons);
buttons.click(function(){
this.style.outline = "1px solid red";
})
I think using sibling selector (~) or child selector (>) will solve your purpose(What ever your case is!!).
This is my javascript and it works great except that if you click the same link twice it toggles. How can I keep that from happening? Ultimately I just want to show a psection based on item clicked... but if you click it twice it toggles.
current = "intersitial"; // div with id="m0" is currently diplayed
function show_or_hide ( id )
{
if ( current ) //if something is displayed
{
document.getElementById ( current ).style.display = "none";
if ( current == id ) //if <div> is already diplayed
{
current = 0;
}
else
{
document.getElementById ( id ).style.display = "block";
current = id;
}
}
else //if nothing is displayed
{
document.getElementById ( id ).style.display = "block";
current = id;
}
}
My HTML is:
<ul>
<li onclick="show_or_hide('intersitial')"><span>intersitial</span></li>
<li onclick="show_or_hide('advancedDetail')"><span>advancedDetail</span></li>
<li onclick="show_or_hide('ultimateDetail')"><span>ultimateDetail</span></li>
</ul>
<div class="megamenu" id="intersitial">intersitial</div>
<div class="megamenu" id="advancedDetail" style="display: none">advancedDetail</div>
<div class="megamenu" id="ultimateDetail" style="display: none">ultimateDetail</div>
I'd suggest changing from the obtrusive JavaScript (using in-line event-handlers, onclick, onfocus, onblur and so on), and instead using JavaScript to bind the events:
// use a function-name that's descriptive of what it does:
function showOnly() {
// or you could use `document.getElementsByClassName('megamenu'):
var divs = document.querySelectorAll('div.megamenu'),
// gets the text from the 'span' of the clicked 'li' (the 'id' for later):
id = this.firstChild.textContent;
// iterates over each of the found '.megamenu' elements:
for (var i = 0, len = divs.length; i < len; i++){
/* if the id of the current 'div' is the same as the text in the 'span'
display = block, otherwise display = none:
*/
divs[i].style.display = divs[i].id === id ? 'block' : 'none';
}
}
// get the 'li' elements:
var lis = document.querySelectorAll('li');
// iterate over those elements and bind an event-handler to them:
for (var i = 0, len = lis.length; i < len; i++) {
lis[i].addEventListener('click', showOnly);
}
JS Fiddle demo.
This approach also avoids littering the global namespace with variables (which are easily over-written inside of other functions, particularly (but not exclusively) when multiple developers work on the same project).
References:
Element.addEventListener().
document.querySelectorAll().
Node.firstChild.
Node.textContent.
function show_or_hide(id)
{
if (current == id) return;
if (current) // if something is displayed
{
document.getElementById ( current ).style.display = "none";
}
document.getElementById ( id ).style.display = "block";
current = id;
}
I need an regular expression or something else to remove all tags in a contentEditable div, but to keep img tag with specific class or id, how I can do this?
Now I use:
.replace(/(<\/?.*?>)/gi, '');
but it removes all tags.
I made this :
var element = document.getElementById("myDiv").children;
for(var i=0; i<element .length;i++)
{
if(element[i].tagName != "IMG" || element[i].className != "requiredClassName")
{
element[i].parentNode.removeChild(element[i]);
}
}
var child=document.getElementById('editableDIV').firstChild;
while(child) {
var removeNode=null;
if(child.tagName&&(child.tagName.toUpperCase()!=='IMG'||
child.id!=='myid'||
child.className!=='myclass')) removeNode=child;
child=child.nextSibling;
if(removeNode)removeNode.parentNode.removeChild(removeNode);
}
( if you need plain JS ): Maybe the better way is to collect all elements then after check their class/id and perform action. Good idea is to use DOM, not regexp. DOM is for HTML elements manipulation.
( or use jQuery ): Simple code can do that thing. Just collect all div's children and check their class in .each() loop;
For e.g.:
$('#contentEditable').each( function( index ) {
if( !this.is( 'img' ) && ( this.is('.someclass') || this.is('#someid') ) ) {
this.remove();
}
});
Hope it helps you.
P.S.:
Be careful when you are using greedy quantification .*
It will get all text between any < >, so if you have code listed below regexp (<\/?.*?>) will collect whole code.
<div class="container">
<div id="header">
<div id="portalLink">
<a class="genu" href="http://stackexchange.com">Stack Exchange</a>
</div>
</div>
</div>
var editableDiv = document.getElementById("MyEditableDiv")
var editableDivImgs = editableDiv.getElementsByTagName("img")
for (var i = 0; i < editableDivImgs.length; i++) {
if(editableDivImgs[i].className != "safe")
{
editableDivImgs[i].parentNode.removeChild(editableDivImgs[i])
}
}
have you tried something like that?
Instead of removing all other elements extract all imgs and concatenate them into a new string:
var regex = /<img.*?>/gmi;
var imgsOnly = '';
var img;
while( ( img = regex.exec(str) ) !== null ) {
imgsOnly += img;
}
alert( imgsOnly );
I'd like to use Javascript (not jquery) to access all items in a <ul> list and remove the active class from everything except my chosen menu item.
Here is the list:
<ul id='flash-menu'>
<li id="menu1" class='something active'>item 1</li>
<li id="menu2" class='somethingelse'>item 2</li>
<li id="menu3" class='somethingelse'>item 3</li>
</ul>
This is my javascript:
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0 ; i<list_items.length ; i++){
list_items[i].className = list_items[i].className.replace('/\bactive\b/','');
}
document.getElementById(view_name).className += " active";
}
The last line of the Javascript (adding the active class) works, but I don't think I'm accessing the list items right to remove the classes from the other items. Any suggestions? - thanks!
First off, your regex is wrong:
list_items[i].className.replace(/\bactive\b/, '');
Note: No quotes on regex'es in JavaScript. A slighty altered, working version is available on JsFiddle.
Furthermore, I get a few instances of HTMLTextElements in list_items. They're breaking the loop (Fx3.6/Win7) when trying to access the non-existing className attribute. You can avoid this by either using:
var list_items = document.getElementById('flash-menu').getElementsByTagName('li');
// Selecting _all_ descendant <li> elements
or by checking for the existence of .className before read/write within the loop body (example). The latter is probably the cleanest choice since it still only affects direct children (you may have several levels of <ul>s in each <li>).
I.e.,
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0, j=list_items.length; i<j; i++){
var elm = list_items[i];
if (elm.className) {
elm.className = elm.className.replace(/\bactive\b/, '');
}
}
document.getElementById(view_name).className += ' active';
}
You can use javascript function getElementsByTagName:
var listitems = document.getElementsByTagName("li");
this would return an array of all the lists and can be iterated for each list element and processed as required.
You can try:
In the case that you can have more than ul, first you have to get all references to them and then process each ul:
var uls = document.getElementsByTagName("ul");
for (uli=0;uli<uls.length;uli++) {
ul = uls[uli];
if (ul.nodeName == "UL" && ul.className == "classname") {
processUL(ul);
}
}
An illustration of proccessUL can be:
function processUL(ul) {
if (!ul.childNodes || ul.childNodes.length == 0) return;
// Iterate LIs
for (var itemi=0;itemi<ul.childNodes.length;itemi++) {
var item = ul.childNodes[itemi];
if (item.nodeName == "LI") {
// Iterate things in this LI
in the case that you need it put your code here
.....
}
}
}
Of course you can also use: item.className = "classname"; if you dont need to iterate between childs of LI
document.getElementById('flash-menu').childNodes will also include white space nodes.
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').getElementsByTagName('li'), i;
for (i=0 ; i<list_items.length ; i++){
if (list_items[i].className.indexOf('active') > -1) {
list_items[i].className = list_items[i].className.replace(/\bactive\b/,'');
}
}
document.getElementById(view_name).className += " active";
}
i agree with jensgram,and you'd better code like this:
list_items[i].className.replace(/\bactive\b/g, '');
add the regex string a 'g'
g is for Global ,using ‘/g’ can replace all the same Which Match the regex ,but if you don't use '/g',you just replace the first string .
like this :
var test= "testeetest" ;
alert(test.replace(/e/,"")) ;//result
: tsteetest but using 'g' var
test= "testeetest" ;
alert(test.replace(/e/g,"")) ;//result
: tsttst
Have a look at this here: https://developer.mozilla.org/en-US/docs/Web/API/element.classList
It helped me a lot with finding class elements!
This is my solution, maybe not the best, but for my works fine.
window.addEventListener('load', iniciaEventos, false);
function iniciaEventos(e)
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++ )
{
menu[i].addEventListener('mousedown', clickMenu);
}
}
function clickMenu()
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++)
menu[i].classList.remove('active');
this.classList.add('active');
}