I have been working with some JavaScript to change display properties for my website. it works fine for Firefox and IE, but Chrome and Safari do not respond at all. I am trying to change the display from "none" to "block", or the reverse. Here is the code:
function setStyleClass (classesOff,classesOn) {
var classOn;
if (document.all) {
for (var s = 0; s < document.styleSheets.length; s++) {
for (var r = 0; r < document.styleSheets[s].rules.length; r++){
if (document.styleSheets[s].rules[r].selectorText.indexOf(classesOff,0) > -1) {
document.styleSheets[s].rules[r].style.display = "none";
}
for(var j = 0; j < classesOn.length; j++){
classOn = classesOn[j];
if (document.styleSheets[s].rules[r].selectorText == '.' + classOn) {
document.styleSheets[s].rules[r].style.display = "block";
}
}
}
}
}
else if (document.getElementById) {
for (var s = 0; s < document.styleSheets.length; s++) {
for (var r = 0; r < document.styleSheets[s].cssRules.length; r++) {
if (document.styleSheets[s].cssRules[r].selectorText.indexOf(classesOff,0) > -1) {
document.styleSheets[s].cssRules[r].style.display = "none";
}
for(var j = 0; j < classesOn.length; j++){
classOn = classesOn[j];
if (document.styleSheets[s].cssRules[r].selectorText == '.' + classOn) {
document.styleSheets[s].cssRules[r].style.display = "block";
}
}
}
}
}
}
When this is called, it is given a list of style id's to turn off, and styles to turn "on".
Here is the call:
onClick="setStyleClass('book','book2_nl','book3_nl','book4_nl','B1_List_01_20','B1_Link_21_40']);
The way this works is to turn "off" any styles with "book" in the name, as well as, book2_nl, book3_nl, and book4_nl. The last two styles get turned "on". So I am replacing one "list of links to pages" with another, different list. The code above works fine in IE and FF, but does nothing at all that I can see in Chrome and Safari.
the styles all look like this coming in:
.B4_Link_21_40 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B4_List_21_40 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
I want to get these styles to turn on when I click the appropriate link. Are there any obvious errors in my code that could be causing this?
OK, you have seen the above question, now I have figured out how to go back and add html to this for your benefit :)
<html>
<head></head>
<title></title>
<script> //the script posted above </script>
<style>
.book1 {
position: absolute;
left:0px;
top:410px;
width:200px;
height:40px;
display: block;
}
.book2 {
position:absolute;
left:0px;
top:450px;
width:200px;
height:40px;
}
.B1_Link_01_20 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B1_List_01_20 {
display: block;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B1_Link_21_40 {
display: block;
color: #f8fb24;
font : 90% Book Antiqua;
}
.B1_List_21_40 {
display: none;
color: #f8fb24;
font : 90% Book Antiqua;
}
</style>
<div align="justify" align="center" class="mainBody"
<p>Here's some content...</p>
</div>
<div class="book1">
<a href="#" target="_self"
onClick="setStyleClass('book',['B1_List_01_20','B1_Link_21_40']);
switchStyleClass('B2_Li');
onMouseOut="window.status=''; return true;">
</a>
</div>
<div class="book2">
<a href="#" target="_self"
onClick="setStyleClass('book',['B2_List_01_20','B2_Link_21_40']);
switchStyleClass('B1_Li');
onMouseOut="window.status=''; return true;">
</a>
</div>
<div class="B1_List_01_20">
<a href=Link To Page 1.shtml>1. Link To Page 1</a><br>
<a href=Link To Page 2.shtml>2. Link To Page 2</a><br>
<br></div>
<div class="B1_List_21_40">
<a href=Link To Page 21.shtml>21. Link To Page 21</a><br>
<a href=Link To Page 22.shtml>22. Link To Page 22</a><br>
<br></div>
<div class="B1_Link_01_20">
<a ONCLICK="setStyleClass('B1_Li',['B1_List_01_20','B1_Link_21_40']);" href="#">List of Links 1 - 20</a><br><br>
</div>
<div class="B1_Link_21_40">
<a ONCLICK="setStyleClass('B1_Li',['B1_List_21_40','B1_Link_01_20','B1_Link_41_60']);" href="#">List of Links 21 - 40</a><br><br>
</div>
</html>
First if your just trying to change links then I would put the different links in 2 containers positioned in the same place via position: absolute then I would have one with a default style none. When the button is clicked then you don't even have to pass anything to your method since your only dealing with 2 containers and you know both their id's.
Then instead of going though the style sheets, just use document.getElementById('container_1').style.display = 'block';
document.getElementById('container_2').style.display = 'none';
As long as your container is a block level, such as a div, then this will change their display property in every browser.
if you want to do it through changing their class names then you could do this.
function changeStyles(){
document.getElementById('container_1').className = 'classOn';
document.getElementById('container_2').className = 'classOff';
//rest of your javascript
}
*This is still assuming you go with two containers instead of trying to change every link's individual style
Edit:
So not knowing what html you actually have makes it harder to answer your comment but here goes.
Your html could look something like this:
<div class='classOn' id='container_1'>
<a href='some_link'>some link</a>
<a href='some_link2'>some link2</a>
<a href='some_link3'>some link3</a>
<a href='some_link4'>some link4</a>
</div>
<div class='classOff' id='container_2'>
<a href='different_link'>different link</a>
<a href='different_link2'>different link2</a>
<a href='different_link3'>different link3</a>
<a href='different_link4'>different link4</a>
</div>
<button onclick='changeStyles()>See new Links!</button>
Then your css:
.classOn{
display: block;
position:absolute;
margin: 10px 10px 10px 10px;
//rest of your css
}
.classOff{
display: none;
position: absolute;
margin: 10px 10px 10px 10px;
//rest of your css
}
Notice how both classes have the exact same margin, they can have this because of the absolute position attribute. It effectively takes the space they would be using out of the page. now when the function changeStyles() is called by pressing the button the first div is hidden and the second div shows up with the new links in the exact same position. hope that helps.
Ok so my example above works fine with what you have just make class='classOn' your class='B1_List_01_20' and make class='classOff' your class='B1_Link_21_40' and use the function above and it should switch between them just fine.
Related
I am learning JS, but still have some troubles. I managed to edit a WYSIWYG editor to allow users to click a button "footnote" that inserts the following HTML:
<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
With some CSS I can place a number inside the element which counts upwards:
body {
counter-reset: footnotecounter;
}
span.footnote:before {
counter-increment: footnotecounter;
content: counter(footnotecounter);
position: relative;
top: -0.4em;
visibility: visible;
}
span.footnote {
color: #0389b9;
font-size: 0.875rem;
}
And example of some HTML:
Here is a text with a note.<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> And there will be a second one too!<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
I actually use Popper and Twitter Bootstrap to show the content of the 'footnote' in a tooltip.
Now what I try to do, is to remove [FN] from all the span elements that have the class footnote with the following javascript:
footnotes = document.getElementsByClassName('footnote');
for (var i = 0; i < length; i++){
footnotes[i].replace("[FN]", " ");
}
This does not seem to work, but I don't know where my mistake is. Also, I guess, that since I am going to use JS to alter the footnotes, I might as well leave the CSS out of it altogether and use JS to create an increasing number in all elements, right?
Here is a JSFiddle to show a live example.
You have to check the length property of footnotes node list. You are trying to replace the element itself not the text inside of it. You have to replace the textContent or innerText property of the element.
Try the following way:
var footnotes = document.getElementsByClassName('footnote');
for (var i = 0; i < footnotes.length; i++){
footnotes[i].textContent = footnotes[i].textContent.replace("[FN]", " ");
}
body {
counter-reset: footnotecounter;
}
span.footnote:before {
counter-increment: footnotecounter;
content: counter(footnotecounter);
position: relative;
top: -0.4em;
visibility: visible;
}
span.footnote {
color: #0389b9;
font-size: 0.875rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
Here is a text with a note.<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> And there will be a second one too!<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
</p>
Update: As per the discussion in the comments
var footnotes = document.getElementsByClassName('footnote');
for (var i = 0; i < footnotes.length; i++){
footnotes[i].innerHTML = footnotes[i].textContent.replace("[FN]", "<span class='new'>"+ (i+1) +"</span> ");
}
body {
counter-reset: footnotecounter;
}
span.new{
position: relative;
top: -0.4em;
visibility: visible;
}
span.footnote {
color: #0389b9;
font-size: 0.875rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>
Here is a text with a note.<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> And there will be a second one too!<span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>
Here's the number 3 thanks to CSS: <span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span> and number 4 <span class="footnote" data-toggle="tooltip" title="footnote">[FN]</span>. All of this thanks to the CSS counter
</p>
Pretty simple problem, but I can't find a solution. This plugin claims to do it, but I can't get it to work on my site at all, not as a called script, not inline, nothing. So, I have two columns of divs, the ones on one side larger than the other. I have set it up so the second column container will match the height of the first (which is determined elsewhere and thus varies) and set it to overflow:hidden, but what I want to do do is to remove the overflowing divs entirely so it always ends on the last complete div. Here's the fiddle: https://jsfiddle.net/bw2v39ru/2/
This is the JS to equalize the heights $('.row2').css('height', $('.row1').height()+'px');
In that example, only two of he block2 spans should be visible and the overflowing ones removed completely instead of leaving half a block.
Try this: https://jsfiddle.net/bw2v39ru/9/
Besides the code below - you will have to e.g. insert a <br style="clear:both;" /> in the parent DIV since the children has float: left
$('.row2').css('height', $('.row1').height());
var maxHeight = $("#main").outerHeight();
$("#main span").each(function() {
var elm = $(this);
if (elm.offset().top + elm.height() > maxHeight)
elm.remove();
});
as promised, here is my answer. Custom build jsfiddle from pure JavaScript.
https://jsfiddle.net/www139/vjgnsrpg/
Here is a code snippit for you. It assumes that all of your block2 elements have a fixed height. Also I changed the .row1 and .row2 classes to ids to make the solution easier to create. Feel free to change it back but remember to use document.getElementsByClassName('class')[i] instead.
//make sure you execute this script onload inside a jquery document ready or window.onload
//get the rendered height of both rows
//enter margin for blocks here
//this also assumes that the height of your block1 and block2 elements are fixed
var margin = 5;
var rowOneHeight = document.getElementById('row1').offsetHeight;
//get height of block2 element including vertical margin (multiplied twice)
var blockTwoHeight = document.getElementById('row2').getElementsByClassName('block2')[0].offsetHeight + 2 * margin;
var howManyBlocksCanFit = Math.floor(rowOneHeight / blockTwoHeight);
var numberOfBlocks = document.getElementById('row2').getElementsByClassName('block2').length;
for (var i = 0; i != numberOfBlocks - howManyBlocksCanFit; i++) {
document.getElementById('row2').removeChild(document.getElementById('row2').lastElementChild);
}
#main {
width: 240px;
}
#row1 {
float: left;
}
#row2 {
float: right;
overflow: hidden;
}
.block1 {
display: block;
margin: 5px;
width: 100px;
height: 50px;
border: 1px solid red;
}
.block2 {
display: block;
margin: 5px;
width: 100px;
height: 100px;
border: 1px solid red;
}
<div id="main">
<div id="row1">
<span class="block1"></span>
<span class="block1"></span>
<span class="block1"></span>
<span class="block1"></span>
<span class="block1"></span>
</div>
<div id="row2">
<span class="block2"></span>
<span class="block2"></span>
<span class="block2"></span>
<span class="block2"></span>
<span class="block2"></span>
</div>
</div>
Hope this helps you, please tell me if there was something I didn't understand in your question to improve my answer.
I programmed it for you, this works after your existing JS code line:
var row2 = $('div.row2'),
block2elements = row2.children('span.block2');
// Function to use also for other situations
function calculateElementsHeight(elements) {
var height = 0;
$.each(elements, function(i, elementRaw ){
height += $(elementRaw).height();
})
return height;
}
for(var i = 0; block2elements.length > i; i++) {
block2elements = row2.children('span.block2'); // Get new state of the block2 elements
if(row2.height() < calculateElementsHeight(block2elements)) {
block2elements.last().remove();
}
}
I have trouble in writing a script to change the appearance of the clicked tab in a webpage navigation list. In other words, I want to make the clicked tab appear as the selected (in code). I tried to do that by changing its id to selected_link and restoring the id of the previously selected tab.
EDIT: Following jamespaned's suggestion, I replaced element IDs with classes.
My tabs appear like in this picture:
So, when I click to "bio", I want it to appear as "home" and "home" to appear as the other tabs.
As I'm a newbie in JavaScript coding, I didn't managed to accomplish that. Here is what I've done:
The HTML code for the (inline) navigation list:
<nav>
<ul id="navlist">
<li class="selected"> home </li>
<li class=""> bio </li>
<li class=""> publications </li>
<li class=""> software </li>
<li class=""> contact </li>
</ul>
</nav>
its respective CSS:
nav ul {
list-style:none;
padding:0;
margin:0;
}
nav li {
background-color:black;
display:inline;
border:solid;
border-width:1px 1px 0 1px;
margin:0 5px 0 0;
}
nav li a {
color:white;
padding:0 10px;
}
.selected {
background-color:white;
padding-bottom: 1px;
}
.selected_link{
color:blue;
}
and the JavaScript which I've designed to accomplish this task, but it didn't worked:
function changeSelected(clickedId)
{
var ulist = document.getElementById("navlist");
var elems = ulist.getElementsByTagName("class");
for (var i = 0; i < elems.length - 1; i++)
{
var sel = elems[i].getAttribute("class");
if (sel == selected)
{
var selli = elems[i];
break;
}
}
selli.setAttribute("class", "");
selli.lastElementChild.setAttribute("class", "");
var clicked = document.getElementById(clickedId);
clicked.setAttribute("class", "selected_link");
clicked.parentNode.setAttribute("class", "selected");
}
How could I do that using only plain JavaScript?
This Javascript will do what you want:
function changeSelected(clickedId)
{
var selli = document.getElementById("selected");
var sela = document.getElementById("selected_link");
sela.setAttribute("id", "");
selli.setAttribute("id", "");
var clicked = document.getElementById(clickedId);
clicked.setAttribute("id", "selected_link");
clicked.parentNode.setAttribute("id", "selected");
}
That said, here are some ideas that might help your Javascript education:
You are using Javascript to set your IDs, but the Javascript won't work on the next page after you've clicked on one of the links. You'll probably need to do some backend (PHP/Ruby, etc) coding to get your styles to change.
IDs are normally used to refer to a unique element on the page that doesn't change, such as a #header or #sidebar_banner. You might want to use a class instead, such as ".selected_link".
You don't need both #selected_link and #selected. You could do ".selected" and ".selected a" to change the CSS so you only need to change one element.
Hope that helps!
I'm working on modifying a website which has a chart of FAQs which have has a question link.
If question link is clicked, it reveals the answer in a drop down.
My goal is to swap out a plus icon image with a minus icon next to the linked text for the drop down reveal action.
the FAQs use Spry Collapsible Panel (sprycollapsiblepanel.js) to manage the show/hiding from the link. before I go about modifying the code in the javascript source code, I was wondering if there was an easier way of doing this through dreamweaver someone might be aware of.
thanks in advance.
UPDATE:
the html calling the show/reveal actions are:
<div class="CollapsiblePanel">
<div id="CollapsiblePanel1" class="CollapsiblePanel">
<div class="CollapsiblePanelTab" tabindex="1">Fax to E-Mail</div>
<div class="CollapsiblePanelContent">Here is the text content as it relates to Fax to E-Mail</div>
</div>
</div>
The construct the actions for the drop down, Spry requires the following at the bottom of the page:
<script type="text/javascript">
var CollapsiblePanel1 = new Spry.Widget.CollapsiblePanel("CollapsiblePanel1", {contentIsOpen:false});
var CollapsiblePanel2 = new Spry.Widget.CollapsiblePanel("CollapsiblePanel2", {contentIsOpen:false});
var CollapsiblePanel3 = new Spry.Widget.CollapsiblePanel("CollapsiblePanel3", {contentIsOpen:false});
</script>
In SpryCollapsiblePanel.css, amend the following style rules:
.CollapsiblePanelTab {
font: bold 0.7em sans-serif;
background-color: #DDD;
border-bottom: solid 1px #CCC;
margin: 0px;
padding: 2px 2px 2px 25px;
cursor: pointer;
-moz-user-select: none;
-khtml-user-select: none;
}
This increases the padding on the left to make room for the image.
Then add the images to the following rules:
.CollapsiblePanelOpen .CollapsiblePanelTab {
background-color: #EEE;
background-image: url(images/plus.gif);
background-position:left top;
background-repeat: no-repeat;
}
.CollapsiblePanelClosed .CollapsiblePanelTab {
background-image: url(images/minus.jpg);
background-position:left top;
background-repeat: no-repeat;
/* background-color: #EFEFEF */
}
THe plug ins adds a class to each panel title when is opened and when is closed, these are "CollapsiblePanelOpen" and "CollapsiblePanelClosed" accordingly. With that you can use CSS to add the +- effect with a background image perhaps.
onclick switch an image then onclick of something else switch back to + sign
If it's an image, and you don't want to change the source code, and you want to use javascript, you'll need to change the src property of the image.
// Grab the img object from the DOM
var img = document.getElementById("theImageId");
// If it's the plus pic, switch for minus, and vice versa.
if(img.src == "plus.png") {
img.src = "minus.png";
}
else {
img.src = "plus.png";
}
You can put this code in wherever you need (in an onclick or a function or whatever). Also, the URLs for the images will obviously need to be updated.
Easy fix with some simple JavaScript.
Add the following script:
<script type="text/javascript">
<!--
function name ()
{
var img = document.getElementById("imgid");
if (img.src == "plus.png") {
img.src = "minus.png";
}
else {
img.src = "plus.png";
}
}
//-->
</script>
When that's done look at the div defining the collapsible panel. It looks something like this:
<div id="CollapsiblePanel1" class="CollapsiblePanel">
<div class="CollapsiblePanelTab" tabindex="0">Name <img src="url.com/minus.png" id="imgid"></div>
<div class="CollapsiblePanelContent">content</div>
All you need for this to work is to add onclick="name();" to the syntax:
<div id="CollapsiblePanel1" class="CollapsiblePanel">
<div class="CollapsiblePanelTab" tabindex="0" onclick="name();">Name <img src="url.com/minus.png" id="imgid"></div>
<div class="CollapsiblePanelContent">content</div>
On facebook for example - when you put your mouseover a news item, a remove button appears. How can I go about making this happen?
Thanks,
Elliot
Modern Browsers
In modern browsers, you can leverage the :hover pseudo class in our selector. As an example, consider the following markup:
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
By default, we would want the .adminControls to be hidden. They should, however, become visible once the user has hovered the .item element:
.item .adminControls {
display: none;
}
.item:hover .adminControls {
display: block;
}
JavaScript and jQuery
If you're using jQuery, you can accomplish this rather easily using the $.hover() method. If you're using Prototype, you can get the protoHover plugin to achieve the same result, or view this blog post.
$("div.item").hover(
function () { $(this).find(".adminControls").show(); },
function () { $(this).find(".adminControls").hide(); }
);
That would accomplish the show/hide effect for the following:
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
If you don't need to support IE6, you can use the :hover pseudoclass like so:
CSS:
.link { display: none; }
.item:hover > .link { display: inline; }
HTML:
<div class="item">
Remove
Lorem Ipsum...
</div>
Position the link as you'd like it to appear on hover, then hide it with JavaScript and use the onmouseover event to show it. (i.e., it's display: none; and then turns to display: block; when the onmouseover event is triggered).
Something like this:
window.onload = function(){
document.getElementById('mylink').style.display = 'none';
document.getElementById('mydiv').onmouseover = function(){
document.getElementById('mylink').style.display = 'block';
}
}
You need to write a Javascript function that manipulates the DOM and you need to associate the OnMouseOver attribute of your HTML element with that function. For example, on my home page a picture of my face changes every time the mouse rolls over it. The Javascript function is defined in the HTML page itself.
<script type="text/javascript">
<!--
faceCnt = 7;
var faces = new Array( faceCnt );
var faceDates = new Array( "1982", "1986", "1991", "1999", "2004", "2006", "2009" );
var faceIdx = 7; /* So that first change is to earliest one. */
for( var idx = 0 ; idx < faceCnt ; idx++ )
(faces[idx] = new Image(150, 116)).src = "david/david" + (idx + 1) + ".jpg";
function nextFace( ref )
{
faceIdx = faceIdx >= faceCnt - 1 ? 0 : faceIdx + 1;
ref.src = faces[ faceIdx ].src;
ref.title = "David-" + faceDates[ faceIdx ];
}
//-->
</script>
<img id="myface" src="david/david7.jpg" alt="david" title="David-2009"
width="150" height="116"
style="margin: 0 0 5px 15px; /* -10px -5px 10px 10px; */
padding: 0;
border: solid black;
border-width: 1px;
float: right;"
onMouseOver="nextFace( this )"
onClick="nextFace( this )" >