This is dynamic. The nav changes based upon the page. The code here adds a class to the nav as you scroll to the section and then removes it as you scroll past. The problem is it only removes as you scroll down not up past the section. How do I do my condition to remove classes as you scroll up while achieving adding the class and removing it as you scroll down??
jQuery( document ).ready(function() {
var sectionelements = jQuery('.nav li');
(function(jQuery) {
var scrolling = function(){
jQuery(sectionelements).each(function(){
var object=jQuery('#'+this);
var wh = jQuery(window).height();
var st = jQuery(document).scrollTop();
var ot = jQuery(object).offset().top;
var eh = jQuery(object).height();
var href="a[href*=#"+object.attr('id')+"]";
if(st>ot){
jQuery(href).addClass('posreached');
}
if (st>ot+eh) {
jQuery(href).removeClass('posreached');
};
})
};
jQuery(window).scroll(scrolling);
jQuery(window).bind('resize orientationchange',scrolling);
//fire initial scroll
jQuery(window).scroll();
})(jQuery);
});
this:
if(st>ot){
jQuery(href).addClass('posreached');
}
if (st>ot+eh) {
jQuery(href).removeClass('posreached');
};
even in the second state the first will be true, so u need to add:
if(st>ot || st<ot+eh){
jQuery(href).addClass('posreached');
}
give it a try
I used these for my conditions and it worked
if(st>ot){
jQuery(href).addClass('posreached');
}
if (st<ot) {
jQuery(href).removeClass('posreached');
}
if (st>ot+eh) {
jQuery(href).removeClass('posreached');
}
I have two pages. The first has a slideshow that allows me to add links for each slide. The second page has numerous expanding div's that are expandable/collapsible onclick using this show/hide function:
function showtxt(divID) {
var item = document.getElementById(divID);
if (item) {
item.className=(item.className=='hidetxt')?'showtxt':'hidetxt';
}
}
Then each expanding/collapsing div on that page has its own function to call it when clicked:
function ANCHORbutton() {
var img = document.getElementById('expANCHORbutton').src;
if (img.indexOf('plus.png')!=-1) {
document.getElementById('expANCHORbutton').src = 'minus.png';
}
else {
document.getElementById('expANCHORbutton').src = 'plus.png';
}
}
What I'd like to do, if possible, is link each slide from that slideshow to the second page, expand the corresponding div, and then jump down the page to the specified anchor.
If I didn't have everything collapsed, it'd be a simple href="http://domain.com/page2.html#ANCHOR", but I'm struggling with how to expand the appropriate section before jumping to my anchor.
Problem 1: Collapsed divs all show so no need for browser to scroll
Problem 2: Hidden divs are not being scrolled to since they are hidden.
Solution could be this at the bottom of the page (onload does not trigger on reload on some browsers)
<script>
var hash = location.hash;
if (hash) {
var divID = hash.substring(1); // remove the #
showtxt(divID);
document.getElementById(divID).scrollIntoView();
}
</script>
</body>
Update to add 100px:
var hash = location.hash;
if (hash) {
var divID = hash.substring(1); // remove the #
showtxt(divID);
var div = document.getElementById(divID);
div.scrollIntoView();
div.style.top=(parseInt(div.style.top,10)+100)+"px";
}
I have this jquery code that adds a class to a div(#menu) after the user scrolled that far on a page. But I am searching for a way to change that code into adding that class when the div(#menu) is on top of another div with the class(.remove) and remove the class again when it's on a div with the class(.add). Here is my code:
jQuery(window).scroll(function(){
var fromTopPx = 400; // distance to trigger
var scrolledFromtop = jQuery(window).scrollTop();
if(scrolledFromtop > fromTopPx){
jQuery('#menu').addClass('scrolled');
}else{
jQuery('#menu').removeClass('scrolled');
}
});
You need to find the position of the div that you want to "be on top of".
To do that you can use
$('.remove').offset().top;
Hope this helps.
I'm probably in deep water here, and I'm new to JavaScript and jQuery,
But I would like to attempt to create a panel system sort of like how spotify has it done.
Have a look at this picture:
On the Spotify player website, when you click on something such as an artist or song/album,
It slides in a topmost panel onto the right side of the screen, if you click something else,
A new one will appear in its place, and the previous panel will get added to what I call the panel stack on the left side of the screen.
Here is a look at Spotify:
I'd like to understand how to do this in JavaScript/jquery, does anyone have some input to share?
What I've tried: (http://jsfiddle.net/k0Lh3ama/)
I understand my attempt was pretty poor, this is why I'm here
var idx = 0;
var panels = [];
var numpanels = 0;
function panel () {
this.id = 0;
this.active = false;
this.container = {};
}
var panelmgr = new function () {
this.Create = function (lpPanel) {
//set all current panels to inactive
//and then push them left
for (var i = 0; i < panels.length; i++) {
panels[i].active = false;
panels[i].container.css("left", "10%");
}
//set the newest panel to Active and Top Most
lpPanel.container.css("z-index", 10000);
lpPanel.container.css("left", "25%");
//setup some info for the new panel
lpPanel.id = numpanels++;
lpPanel.active = true;
//add it to array
panels.push(lpPanel);
};
}
$(".box").click(function (e) {
var id = $(this).attr("id");
var selected = -1;
//find the panel we've selected and retrieve the index
for (var i = 0; i < panels.length; i++) {
if (id == panels[i].container.attr("id")) {
selected = I;
break;
}
}
//do we have a valid selected panel?
if (selected >= 0) {
//Make all panels not selected
for (var i = 0; i < panels.length; i++) {
panels[i].active = false;
panels[i].container.css("left", "10%");
}
//now make the panel we selected
//the top most panel
panels[selected].active = true;
panels[selected].container.css("z-index", 10000);
panels[selected].container.css("left", "25%");
}
});
$(document).ready(function () {
var p1 = new panel();
var p2 = new panel();
var p3 = new panel();
var p4 = new panel();
var p5 = new panel();
p1.container = $("#panel1");
p2.container = $("#panel2");
p3.container = $("#panel3");
p4.container = $("#panel4");
p5.container = $("#panel5");
panelmgr.Create(p1);
panelmgr.Create(p2);
panelmgr.Create(p3);
panelmgr.Create(p4);
panelmgr.Create(p5);
});
In short there are several issues with your original code. Below are my attempts at getting the current code set working (with suggestions for improvement at the bottom. Please see my original fiddle for working code without changing to much of your original code. I also modified the original fiddle (with sliding) to use css transitions to give a slide effect)
1) You are constantly writing over your panels because their css top value is set to zero for all. You can get around this by setting the top value for all non-active panels. (I assumed you wanted the item to dissappear from the stack, since you were moving it over to the current when it was selected)
//Increment height
var ii = 0;
for (var i = 0; i < panels.length; i++) {
if(panels[i].active == false){
panels[i].container.css("top", ii*30+"px");
ii++;
}
}
2) Your Z-index and width are causing the panel stack panels and the current panel to overlap, defaulting to whatever dom element was created last.
you can get around this by setting the z-index value to a lower value in the `//make all panels not selected`` loop
panels[i].container.css("z-index", "1");
3) You'd likely also want to hide the current panels contents when it is in the stack, otherwise your stack is going to get rather messy. You can get around this by splitting up your DOM panel's into something like:
<div id="panel5" class="box">
<div class="panelTitle">Panel 4</div>
<div class="contents">Stuff to display</div>
</div>
and adding the following code to the following loops:
//Make all panels not selected
for (var i = 0; i < panels.length; i++) {
//other code emitted for space...
//hide the contents
panels[i].container.find(".contents").css("display","none");
}
//now make the panel we selected
//the top most panel
panels[selected].active = true;
panels[selected].container.css("z-index", 2);
panels[selected].container.css("left", "25%");
panels[selected].container.css("top","0px");
//it's active, so display the contents
panels[selected].container.find(".contents").css("display","block");
4) In the event you want the panels to slide around on the clicks, I added CSS transitions - only in the second fiddle I added a transition rule to your .box selector that will put a second delay on all css changes for elements that have the class box. Please see css3 transitions for more on customizing transitions.
transition: all 1s;
-webkit-transition: all 1s;
-moz-transition: all 1s;
-o-transition: all 1s;
Suggestions for improvement/better development
To be honest I'd probably do a large rewrite. DOM manipulation gets the job done and is a fair start, but if things get complex it'd be much easier to track the data you need for each panel in the javascript and generate the DOM elements fresh when they are needed. I'd probably do something along the lines of the following disclaimer, I didn't test the following code as a whole, meant to be a guideline:
1) Define your data structure containing all relevant information to a panel and implement it in the javascript. This is similar to what you already have, but at a minimum I'd add a panel title and panel contents of sort.
Similar to what you have but I would add to it and do some parameter checking and remove the container
function Panel (jobj) {
if(typeof jobj === "undefined") throw new ReferenceError("Bad value passed to constructor");
if(typeof jobj.id === "undefined") throw new ReferenceError("Missing an id");
this.id = 0;
this.active = false;
if(typeof jobj.title === "undefined") throw new ReferenceError("Missing panel title");
this.title = jobj.title;
//set to passed value, or if doesn't exist, default to empty array;
this.tracks = jobj.tracks || [];
}
as a bonus you could make use of prototyping and construct different types of panels with different forms of parameter checking... I'm pretty sure there are other ways of doing this, but I've found the following works for me.
var DiscoverPanel = function(jsonObj){
if(typeof jsonObj === "undefined")throw new ReferenceError("Expecting a JSON object but received none");
var panel = new Panel(jsonObj);
if(typeof jsonObj.genre === "undefined") throw new ReferenceError("Missing genre!")
panel.genre = jsonObj.genre;
return panel;
}
2) create the HTML for a stack and a current panel, so instead of the 5 div elements you currently have, I'd narrow it down to 2. Don't forget to style it to your liking
<ul id="stack"></ul>
<div id="current"></div>
3) Define your panels in the javascript instead of the html. Once you have working examples of the underlying json objects that you pass to the constructors, you might find it beneficial to write a server side service that you call via AJAX that returns the necessary JSON.
the constructor would be called like so:
//there are plenty of ways to generate the id within the constructor if hard coding
//it bugs you, your post showed a means of doing so.
var p1 = new Panel({title:"Panel 1",id:"p1"});
var p2 = new Panel({title:"Panel 2",id:"p2"});
var dp = new DiscoverPanel({title:"discover",id:"dp",genre:"rock"});
//etc.
var pn = new Panel({title:"Panel n"});
var panels = [p1,p2,dp,...,pn];
4) Onload/domready generate the innerHTML for the inactive panels, from potentially the panel titles.
$(document).ready(function () {
generateList();
}
function generateList(){
var stack = document.getElementById("stack");
stack.innerHTML = "";
panels.forEach(function(panel){
var item = document.createElement("li");
item.setAttribute("id",panel.id)
item.innerHTML = panel.title;
item.onclick = function(){
//load this specific panel to the current
loadCurrent(panel);
//regenerate the stack
generateList();
}
stack.appendChild(item);
});
}
5) Proceed to generate the innerHTML for the current panel. This would be very similar to the above method of creating the element and the generating it's content off of the panel's data.
function loadCurrent(panel){
panel.active = true;
var cur = document.getElementById("current");
//Figured table was a good example, but you could get as creative as you want
//using floats, divs, etc. Could also check the types and handle different types of panels
var table = document.createElement("table");
panel.tracks.forEach(function(track){
var row = document.createElement("tr");
var td = document.createElement("td");
td.innerHTML = track.number;
row.appendChild(td);
//repeat for whatever other values you have for a track
//you'd likely add a play function or something of that sort to each.
table.appendChild(row);
});
table.appendChild(cur);
}
This isn't exactly what you're looking for, nor is it at all related to the code you posted. But heres something I threw together that might be a good resource for you to look at. It doesn't implement the stack, but you could apply the concepts fairly easily. Check it out.
You could get rid of the createPanel function and pre-create/assign all the panels in an init function, and then have controllers that use those panels as a base. Then it's just a matter of controlling whats showing in the DOM
display: none
will effectively remove an element from the DOM remember, and can be used to hide certain panels.
Check this fiddle : http://jsfiddle.net/k0Lh3ama/1/
Do the css stuff. I am not master in it..
Your CSS ::
.sidebar{
width:10%;
background-color:#000;
color:#FFF;
height:800px;
float:left;
}
.box{
width:7%;
float:left;
height:800px;
background-color:red;
border:1px solid #000;
}
.active{
width:64%;
float:right !important;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all 1s ease-in-out;
}
Your Html Code
SideBar
<div id="panel2" class="box active">Panel 1 </div>
<div id="panel3" class="box">Panel 2 </div>
<div id="panel4" class="box">Panel 3</div>
<div id="panel5" class="box">Panel 4 </div>
Jquery
$(function(){
$(".box").click(function(){
$(".box").removeClass("active");
$(this).addClass("active");
});
});
You probably shouldn't be changing the CSS. Basically, what you want are two divs, one that holds a list of "panels" and one that holds a detailed view of a single "panel". I see this problem as breaking down into a number of sub-problems:
1) Get a list of panel objects from the server, and dynamically populate the left div, more than likely with sub-divs that hold the panel info. In other words, at page load some code will need to run that will loop through the list and add divs to the left div, one for each panel, and CSS for those pieces should handle how they get laid out and everything. A simple place to start might be to just add a single button for each item in the list, or a single image, etc.
2) Event handler so that when you click on a panel in the list it loads the detailed view into the right div. This may also remove the panel from the list, or change it visually in some way (gray it out), or whatever.
3) Code to display detailed info in the right div if an item has been loaded into it, and doing some other default if not.
One way to cheat a little to simplify all this might be to have the panels and detailed views be pre-built pages, and load them into the main page in iframes or the like.
I'm trying to append a div to the bottom of a another div, by clicking a button in javascript, but once the height of the outer container is reached, it no longer scrolls the list to the bottom, after an insert.
Please see the fiddle here
If you click the red add button until you get to about 13 items in the list, it seems something goes wrong with the scrollTop function, and it it no longer functions correctly (hovers around the same spot in).
I'm pretty lost on this, and have tried a bunch of different combinations of css settings for both the container and side div. Please help me.
I've reformatted your code to be more jQuery-esque. The main change, however, was to change the list.scrollTop() function so that it just scrolls to the bottom of list:
$(document).ready(function() {
var list = $("#q-d-list");
$(document).on('click', '#add', function() {
$('.active', list).removeClass("active");
var count = list.children().length + 1;
var active = $('<div />', {
'data-qid': count,
'class': 'mli active'
}).text('q' + count).appendTo(list);
list.scrollTop(list[0].scrollHeight);
});
});
Demo: http://jsfiddle.net/MrvcB/19/
Use
list.scrollTop(list.get(0).scrollHeight);
rather than
list.scrollTop($(".active").offset().top);
Try:
$(document).ready(function () {
var count = 2;
$("#add").live("click", function () {
var list= $("#q-d-list");
// remove the active class from the old item
var $clone = $(list.find("div:last-child").removeClass("active").clone());
count+=1;
var str_count = "q"+count.toString();
$clone.addClass("active").attr("data-qid",str_count).text(str_count);
list.append($clone);
list.scrollTop(list.get(0).scrollHeight);
});
});
http://jsfiddle.net/H4Kb3/