Search for div classes with regex - javascript

Sounds simple, huh. Lot's of answers i found but all use jQuery or ProtoType. I want plain JavaScript. It shouldn't be that hard, but JavaScript is not my thing; no central documentation means searching for ages and not finding what i want.
Consider the following HTML code snippet:
<div class="central_0"> .. </div>
<div class="central_1"> .. </div>
<div class="central_2"> .. </div>
Now I want to use JavaScript to do things with those DIVs.
function processDivElements()
{
// search for relevant DIV classes
var divArray = document.getElementsByClass.regex('/^central_.*$/');
// do stuff with the DIV elements found
foreach (divArray as divElement)
{
divElement.style.background = '#f00';
};
}
Can anyone help me translate this to proper plain JavaScript? I use classes, not IDs. I prefer using a regular expression.

The jQuery solution is really nice:
var $divs = $('div[class^="central_"]');
If you only want to support newer browsers, you can use document.querySelectorAll() to do essentially the same thing:
var divs = document.querySelectorAll('div[class^="central_"]');
If you want to support older browsers, the code gets horrible:
var all_divs = document.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < all_divs.length; i++) {
var div = all_divs[i];
if (div.className.match(/^central_\d+$/) {
divs.push(div);
}
}
Also:
I use classes, not IDs. I prefer using a regular expression.
Your classes are unique and are really functioning like IDs, which isn't really the intended use of classes. Structure your HTML like this instead:
<div id="central_0" class="central">...</div>
<div id="central_1" class="central">...</div>
<div id="central_2" class="central">...</div>
Now, the JavaScript becomes simpler:
var $divs = $('.central'); // jQuery
var divs = document.querySelectorAll('.central'); // Newer browsers
var divs = document.getElementsByClassName('central'); // Older browsers

As the others have mentioned you can't directly support a regex select on the getElementsByClassName method call.
But I will point out these other issues with your code, since you are new to javascript.
Using classes is fine, but your making more work for yourself by writing up your html like that.
Instead of the central_0....central_2 if they are all basically operating on the same css rules, you should write them like this central zero....central two then your central class can have identical rules, while you can assign any differences to the # classes. This way your also adhering to the DRY principle.
Also you should really consider sticking to the best practices for the language. If your not assigning css rules to your elements with those classes then you should be using id's, plus it makes your life much easier.

There is no way to get the matched elements by regex directly, the only thing you could do is to get all the elements by something (like: TagName, Name, etc..) and then filter the elements by regex.
With your html sample, you could only get all the element by TagName, and use regex to check the className by regex.

One quicker way to do so is to create a simple <style> as follows:
<style>
div[class^="central_"] {
background-color: #f00;
}
</style>
Therefore, as you look for plain javascript, useless to say that you can add <style> tags at will, by using javascript. A whole HTML example as follows:
<html>
<head>
</head>
<body>
<div class= "central_1">
central 1
</div>
<script>
var css = "<style>div[class^=\"central_\"] {background-color: #f00;}</style>";
var list = document.querySelector("head"); list.innerHTML += css;
</script>
</body>
</html>

Related

Is it a good practice to put html code with plain text as a value of an attribute?

Is it considered a good or a bad practice to put text and html code as a value of an attribute, here is an example :
<script>
var name = '<h3>name</h3>Here goes a description about the name attribute';
var elem = document.getElementById('monElem');
elem.innerHTML = name;
</script>
knowing the fact that the text between html tags is a static text not a dynamic one.
If it is a bad practice then is the solution to use a template engine ?
If the purpose is to show/hide this static HTML on demand, then it might be even better not to dynamically add and remove it from your HTML document, but to show/hide it via CSS:
<body>
<div id="hoverMe" onmouseout="showHelp(0)" onmousemove="showHelp(1)">
Hover me to learn about "name"
</div>
<div id="monElem" style="display:none">
<h3>name</h3>
Here goes a description about the name attribute
</div>
</body>
<script>
var elem = document.getElementById('monElem');
function showHelp(show) {
elem.style.display = show ? '' : 'none';
}
</script>
This will also have better performance than adding the elements to the DOM at the moment of need.
Unless you are using this code to generate a lot of DOM content, i.e. execute it a few hundred or thousand times, you'll be good.
Just for completeness I'd like to mention that there's a few other ways of generating HTML content from Javascript:
document.createElement
document.createDocumentFragment
<template> element
The performance of these three is generally higher than using innerHTML, but the differences between the three are currently pretty inconsistent between browsers and browser versions.
Also, <template> isn't fully supported in all browsers yet and won't be supported in older browsers.
It depends on styleguide in your team, but in most cases it's a bad practice.
The better solution is when you'll create new element throught javascript:
var h3 = document.createElement("h3");
var text = document.createTextNode("Any name … .");
h3.appendChild(text);
var elem = document.getElementById('monElem');
elem.insertBefore(h3, elem.firstChild);
Why is it better? Just because it's faster, more conviniet and predictable.
Read more about document methods on w3schools.

JSF Set CSS Style Using Javascript?

I have been looking with no success to see if I can dynamically apply a css style to JSF component or div using javascript. Is this possible.
This is pseudo code
<div style="myJSStyleFunction("#{myBean.value}")"> stuff </div>
And the function would return something like "position:relative;left:25px;"
I've had no luck and maybe it can't be done but would like a second opinion.
Edit:
I'm trying to see if I can keep a separation / reduce the coupling between the presentation/view and the model/controller. This is for indenting commenting or product reviews (to nest replies to comments or reviews). The most I really want to track is an integer on how deep a reply is. First level = 0 second level = 1, and so on. So a comment or product review would be 0 deep, a reply to the comment or review would be 1 and so on.
Then in the EL I wanted to call a javascript function and do something like
<script>
myJSStyleFunction(depth){
if(depth<=5){
var nest=20*depth;
var style="position:relative;left:" + nest + "px;";
return style;
}
}
</script>
And then then say for a third level comment (a reply to a reply) it would look like this:
<div style="position:relative;left:40px;"> stuff </div>
where
#{myBean.value}
evaluates to 2
I suspect like Daniel says I'll have to tightly couple the view but I'd rather not have to. I'd think there has to be a way. But maybe not.
I don't know where there are cleaner solutions for this. However this is one suggestion.
Assume your page looks like below and myBean.getValue() method returns an integer.
<h:form id="frm">
<div style="#{myBean.value}"> div1 </div>
<div style="#{myBean.value}"> div2 </div>
</h:form>
So you can do something like this at 'window.onload'.
<head>
<script>
window.onload = function() {
var childList = document.forms['frm'].childNodes;
for(var i = 0; i < childList.length; i++) {
if(childList[i].nodeName == 'DIV') {
var _div = childList[i];
var depth = _div.getAttribute('style');
_div.setAttribute('style', 'position:relative;left:' +(depth *20)+ 'px;');
}
}
}
</script>
</head>
Note: 1. In above sample code I assume all the DIVs inside the form should be indented.
2. For IE you may need to use _div.style.setAttribute('cssText','position:relative;left:' +(depth *20)+ 'px;')
3. Another solution for your question is using <script> tags immediately after your divs and putting the js part inside them. In this way you don't have to use fake styling style="#{myBean.value}" or window.onload event because you can directly call #{myBean.value} in your script.
I decided to skip the javascript approach and settled on a simpler and I think cleaner method to create the dynamic css classes for my situation. I already capture/calculate the depth value for each comment when it is entered. So I am just returning that value in EL and concatenating it to a 'base name' for the css class like so:
<div class="indent_#{(comment.commentDepth le 5) ? comment.commentDepth : 5}" >
comment comment blah blah blah
</div>
"indent_" is the base name for the css class. So for a 0 level comment it will have a class="indent_0". A reply to that comment will have class="indent_1".
I use the ternary so that if there are lot of replies under a given comment it doesn't indent right off the right hand side of the page. Even though you can keep going deeper, it will only indent up to 5 levels.
For my case at the moment, this is a simpler and cleaner method of adding some dynamically generated css class names. Right now I have to define 6 classes for this in the css file, but perhaps I'll figure out how to nest the boxes but it isn't a priority this works just fine for me for now.

Master element attribute? (or technique)

Is there any way you can set an element to be a master and have all other elements on a page appear and behave in exactly the same, same style, same code, same attributes, same values?
<input id="btnBack" name="btnBack" type="button" value="Back" disabled="disabled" style="margin-right: 10px" />
$('#btnBack').click(...do stuff);
<input master="btnBack" />
Or failing this is there any technique to concisely achieve the same result?
I'm half expecting there to be a Javascript library out there that copies all the attributes.
Same style = css
Same attributes, values, etc = JS
See this fiddle for an example to get you started or this code snippet...
The CSS
input {
width: 200px;
background-color: yellow;
}
The JS
var value = 'myval';
var disabled = 'disabled';
var myElements = document.getElementsByTagName('input');
for(var i = 0; i < myElements.length; i++){
myElements[i].value = value;
myElements[i].disabled = disabled;
}
Yes with CSS classes. Create a master class and then use the class="master" on all your elements.
However I think you'll find you don't really want to do this once you get into it. But it will be easy to change the class on the elements you want to change so it won't hurt you to get started this way.
You can read about CSS here: http://www.w3schools.com/css/ though there are better resources w3schools covers a lot of ground.
If you're interested in building a consistent feel to a site and don't mind using jquery (which I love!) then you should checkout the jquery UI themeroller:
http://jqueryui.com/themeroller/
I don't know if this is what you're referring to, but best bet is use a class on all the elements you want to style and behave the same.
E.g.
File: index.html
Awesome Link
<button class="master-class">Awesome Button</a>
File: style.css
.master-class {
color: black;
background: white;
more of your styles...
}
File: scripts.js
$(function() {
$(".master-class").click(function() {
alert("This is from one of the many elements with the class 'master-class'");
});
});
Team Treehouse is a great place to really learn all about everything web. I've been using them for a while even though I knew most of the stuff on there, but I always pick up a few new things. http://teamtreehouse.com/
W3Schools ( http://www.w3schools.com ) is also great. It's where I learnt a lot of stuff in the beginning.
There is also a large amount of podcasts and vodcasts out there to teach you too, just search iTunes for web design.

Need Javascript syntax to reference a CSS class instead of HTML element

I searched online for the correct syntax to reference a CSS class, instead of an HTML element, but was unable to find anything helpful.
I would like to modify the code below to reference any DIV of class buy_content "div.buy_content" instead of the body element.
Small Text
Medium Text
Large Text
There is no "JavaScript syntax" for what you're asking for. Newer browsers support an API called "getElementsByClassName", so you could do this:
function setSize(sz) {
var elements = document.getElementsByClassName('buy_content');
for (var i = 0; i < elements.length; ++i) {
if (elements[i].tagName === 'DIV')
elements[i].style.fontSize = sz;
}
}
<a href='#' onclick='setSize("1em"); set_cookie(...);'>Small</a>
You can find a "patch" for "getElementsByClassName" support here.
<a href="#" class="clickie size-1" >Small text </a>
<a href="#" class="clickie size-2" >Medium text </a>
<a href="#" class="clickie size-3" >Large text </a>
You should change the markup not to rely on inline javascript.
// bind the event handler to all <a> tags
var as = document.getElementsByTagNames("a");
for (var i = 0, ii = as.length; i < ii; i++) {
as[i].onclick = setText;
}
function setText(ev) {
// get the em size from the class
var size = /[.]*text-([\d][.]*)/.exec(ev.target.className)[1]
var divs = document.querySelectorAll("div.buy_content");
// set the style on all divs.
for (var i = 0, ii = divs.length; i < ii; i++) {
divs[i].style.fontSize = size + "em";
}
}
There are issues with browser support (mainly IE7 and lower) so you need some more boilerplate to make it work.
You can't really do this (easily/readably/cleanly) with inline and stock JavaScript because the JavaScript DOM API doesn't provide a way to reference a CSS class since this isn't part of the DOM. You would have to populate an array or list with HTML elements that have that class applied to them and then iterate over the collection.
JQuery provides selectors and iterators to make this very simple, but if you can't use libraries then doing this inline isn't a good idea. Put it in a function in a script block or an external .js file.
EDIT:
A few people pointed out querySelectorAll, which will select by class but from what I have read isn't completely cross platform (doesn't work on IE below IE 8).
Further, to clarify on my original post, when I said that the DOM API doesn't allow you to access an element by class, what I meant was that it couldn't be done with DOM traversal. querySelectAll or the JQuery selectors perform DOM traversal with functions that inspect elements and their properties, retrieve the objects, and populate collections. Even getElementById performs attribute inspection. I suppose, in retrospect, it's a moot point, but since he wasn't using selectors or attribute queries in his original code I thought that he was asking if there was JS syntax that was as simple as what he was currently using. That's why I mentioned functions. In my head, even something like getElementById is a function since, well, it is a function.
I believe what you are looking for is insertRule (this is exactly what you asked for... kinda):
document.styleSheets[document.styleSheets.length-1].insertRule('div.buy_content {font-size: 1em}',document.styleSheets[document.styleSheets.length-1].length)
document.styleSheets[document.styleSheets.length-1] is your last stylesheet.
the new rule will go at index document.styleSheets[document.styleSheets.length].length
http://www.quirksmode.org/dom/w3c_css.html#t22
also... deleteRule:
http://www.quirksmode.org/dom/w3c_css.html#t21
BUT, a better way to go would be to getElementsByClassName, loop through em, check their nodeName for "DIV", then apply the styles the old fashioned way.
Leverage CSS to do the selection work for you:
body.smalltext .buy_content { font-size: 1em; }
body.mediumtext .buy_content { font-size: 2em; }
body.largetext .buy_content { font-size: 3em; }
...
<input type="button" value="Small text" id="smalltext"/>
<input type="button" value="Medium text" id="mediumtext"/>
<input type="button" value="Large text" id="largetext"/>
...
document.getElementById('smalltext').onclick= function() {
document.body.className= 'smalltext';
};
document.getElementById('mediumtext').onclick= function() {
document.body.className= 'mediumtext';
};
document.getElementById('largetext').onclick= function() {
document.body.className= 'largetext';
};
My first suggestion to answer your exact question:
If your project is bigger in scope than just this one thing:
Download jQuery
Use code:
$('div.buy_content')
Which returns a jQuery array object of all the divs which you can further manipulate.
My second suggestion based on thinking more deeply about what you're trying to do:
Either completely replace the stylesheet in script or modify the existing stylesheet to change the style. Don't loop through all the DIVs in the document and change their style assignment, instead change the meaning of their already-assigned style.

Is there a cross-browser css way to decorate only last word in a span block?

I need to show user's list which should look like in the example below:
Helen Burns Edward
Fairfax Rochester Bertha
Antoinetta Mason Adèle
Varens
Is there a way to achieve this without using javascript? Each row should be one span, i.e. <span>Helen</span><span>Burns</span> is not acceptable.
No, there is not. You are going to have to use some form of scripting to accomplish this if you don't want your last names to be in their own tags.
To the browser, each row is an element, and the "words" themselves have no separate meaning as far as CSS is concerned. You must place the words in different tags in order to do what you want.
The browser does not automagically know what part of the name is the last name so you have to add extra markup to achieve what you want.
There's no solution for common used browser for know using only CSS. You should use javascript or HTML + CSS as you already made.
without pure css this is impossible (as you don't want a separation in the markup)...
<span>Monty Burns</span><br />
<span>Bart Simpson</span>
<script type="text/javascript">
$(document).ready(function() {
var spans = $('span');
spans.each(function(index, element) {
var span = $(element);
var spanText = span.text();
var spanTextArray = spanText.split(' ');
var spanTextArrayLength = spanTextArray.length;
var lastName = spanTextArray[spanTextArrayLength -1];
spanTextArray.pop();
var firstName = spanTextArray.join(' ');
span.text(firstName);
var spanLastName = $('<span/>');
spanLastName.css('font-weight', 'bold');
spanLastName.css('margin-left', '5px');
spanLastName.appendTo(span);
spanLastName.text(lastName);
});
});
</script>
working demo.
edit: if you do not want an extra span-tag in there, just change
var spanLastName = $('<span/>');
spanLastName.css('font-weight', 'bold');
to
var spanLastName = $('<strong/>');
I don't think this is possible with CSS because your example doesn't show any order:
Helen Burns
Edward Fairfax Rochester
Bertha Antoinetta Mason
Adèle Varens
I don't know why you might desire not to have an extra tag surrounding the last name (as other answers and comments have suggested), but if you are looking simply for minimalist mark-up, this works (no span even used):
Html:
<body>
First Middle <strong>Last</strong>
First Middle <strong>Last</strong>
First Middle <strong>Last</strong>
</body>
Css:
strong:after {content:' '; display: block;}
Which creates "rows" with your desired styling without anything more than a single tag (which could be a span rather than a strong if you desired).
Edit: Of course, this will not work for IE7 or under.

Categories

Resources