I made a website where there are a bunch of links that load into an iframe. There are buttons that allow the user to navigate to the next and previous links in the list. I used this to do that.
var i = 0, links = $('a').toArray();
$('.next').click(function() {
i++;
if(i === links.length){ i = links.length - 1; }
$('.frame').attr('src', links[i]);
});
//loads next link in iframe
$('.prev').click(function() {
i--;
if(i < 0){ i = 0; }
$('.frame').attr('src', links[i]);
});
//loads previous link in iframe
The problem is that if a user clicks on say the 3rd link, and then clicks the next button, it does not go to the 4th link, but rather to the 2nd link, since the click function just changes the value of i which is set to 0 by default.
To solve this I thought of creating another variable that stored the current link loaded in the iframe as such:
var current = $('.frame').contents().get(0).location.href
and then setting the value of i according to the index value of the current link as such:
var i = links.indexOf(current)
Note: I am aware that
$('.frame').contents().get(0).location.href
will cause cross-domain errors. The links I am using are from the same domain so this won't be a problem.
Sadly, this doesn't work. Any clue where I'm going wrong? Here's a fiddle.
JSFiddle
I have to use only Javascript (Jquery is fine). Please keep in mind that creating an array with the links inserted manually is not an option since there are a large number of links and more being added.
Your problem is that your i variable keep the previous index from the previous clicking on the next/prev buttons. You should fixc your code, that when the user clicks any link, i will update, as follows:
var i = 0, links = $('a').toArray();
$('.next').click(function() {
i++;
if(i === links.length){ i = links.length - 1; }
$('.frame').attr('src', links[i].href); // To get the src you must get href attribute
});
//loads next lesson in iframe
$('.prev').click(function() {
i--;
if(i < 0){ i = 0; }
$('.frame').attr('src', links[i].href); // To get the src you must get href attribute
});
//loads previous lesson in iframe
$('a').click(function() {
i = links.indexOf(this);
});
.nav {
top: 0;
z-index: 2;
width: 100%;
background: #212121;
}
.nav button {
font-size: 25px;
color: white;
padding: 10px;
width: 100px;
border-color: white;
border-radius: 8px;
background-color: #212121;
margin: 5px;
}
/*nav menu buttons*/
.frame {
height: 50vh;
width: 100%;
border: solide white 1px;
}
body {
background: #212121;
color: white;
font-family: 'Nanum Gothic', 'calibri';
margin: 5px;
}
/*body view*/
a {
padding: 5px 0px 5px 30px;
display: block;
font-size: 20px;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class= "nav">
<button class="prev">Prev</button>
<!--previous lesson button-->
<button class="next">Next</button>
<!--next lesson button-->
</div>
<iframe name="content" class="frame" src=""></iframe>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
</ul>
Related
I want to show two items when using scrollIntoView() with navigating buttons (up and down) to let the user know there are items to navigate, but the first and last items should have default behavior, So the user knows it is end of list.
I hope this image helps:
here is my code:
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
.myList{
width: 100px;
height: 100px;
margin: 5px;
overflow: scroll;
display: flex;
flex-direction: column;
background-color: gray;
list-style: none;
}
button{
width: 40px;
margin: 0 5px;
}
.myList>*{
display: block;
padding: 5px;
}
.focused{
background-color: yellow;
color: black;
}
<html>
<body>
<ul class="myList">
<li data-nav="0">Item 1</li>
<li data-nav="1">Item 2</li>
<li data-nav="2">Item 3</li>
<li data-nav="3">Item 4</li>
<li data-nav="4">Item 5</li>
<li data-nav="5">Item 6</li>
<li data-nav="6">Item 7</li>
</ul>
<button onclick="move(true)">UP</button>
<button onclick="move(false)">down</button>
<script>
let nav = document.querySelectorAll("[data-nav]");
nav.forEach(el=>{
el.classList.remove("focused");
})
nav[0].classList.add("focused");
let focusedIndex = 0;
function move(dir){
if(dir && focusedIndex > 0) focusedIndex--;
else if(!dir && focusedIndex < 6) focusedIndex++;
nav.forEach(elem =>{
elem.classList.remove("focused");
})
nav[focusedIndex].classList.add("focused");
nav[focusedIndex].scrollIntoView(true);
}
</script>
</body>
</html>
First you need when appear the previous element
if we click in up button and the current index not the first element, in this statue we need to scroll to previous element and add focused class to current element
let nav = document.querySelectorAll("[data-nav]");
nav.forEach((el) => {
el.classList.remove("focused");
});
nav[0].classList.add("focused");
let focusedIndex = 0;
function move(dir) {
if (dir && focusedIndex > 0) focusedIndex--;
else if (!dir && focusedIndex < 6) focusedIndex++;
nav.forEach((elem) => {
elem.classList.remove("focused");
});
/*
check if we click in up button and will not arrive to last one
[1] add foucs to current index
[2] scroll to prev current index
*/
if(dir && nav[focusedIndex].dataset.nav != 0) {
nav[focusedIndex].classList.add("focused");
nav[focusedIndex-1].scrollIntoView(true);
}
/*
if we click in down button dont do any thing differnt because we already can see
another items or the first condition return flase because this already the
first element
*/
else {
nav[focusedIndex].classList.add("focused");
nav[focusedIndex].scrollIntoView(true);
}
}
TL;DR: Detect item change from the actual <ul> list and persist the data
Howdy everyone?
I'm currently doing a Trello-like based web-application using PHP as a backend and jQueryUI as a front-end.
The front-end part is made using sortable(), by defining three UL elements. One is a container / wrapper with the id Nav and the other two are actual boards that hold the items.
Case scenarios are simple:
You can reorder boards
You can move order of items inside the single board
You can move item from one board to another
The included code supports all three of them but the data should persist to the back-end powered database (I'm currently on SQLite since the project is in early phase).
Problem
The method setSortAction currently detects all three use case but once you move the item from one board to another the order of the list can't be properly detected (since they are in incremented value).
Getting the bodyContent like this: action=updateMenuItemListings&record=2&record=1&record=3
by moving the second item to the first place in the board is fine, and I can persist that change through the POST request on back-end and then onto the database.
What happens when you move the first item from the second board on the first board? You'd get value of bodyContent similar to this:
action=updateMenuItemListings&record=1&record=2&record=1&record=3
As you can see the record with value 1 duplicates.
That means I can't detect the item moved is from the second board and I have duplicate items in the order of the board.
How would you go about designing this? Can it be done by the given code or have I totally missed the logic that one should apply in this scenario?
Thank you.
$(function() {
var debugMode = true;
$("ul.droptrue").sortable({
connectWith: "ul"
});
//Set common sort settings for all lists
$(".sortable").sortable({
opacity: 0.6,
cursor: 'move'
});
//Function used to configure update calls for each sort
function setSortAction(selector, updatePage, updateAction, itemLabel) {
$(selector).sortable({
update: function() {
var itemList = $(this).sortable(
"serialize", {
attribute: "id",
key: itemLabel
});
//Create POST request to persist the update
var bodyContent = "action=" + updateAction + "&" + itemList;
if (debugMode) {
alert("DEBUG: bodyContent = \n" + bodyContent);
}
//$.post(updatePage, bodyContent, function (postResult)
//{ alert(postResult); });
}
});
}
//Set sort update action for top level and second level
setSortAction(".navLevel1",
"reorder.php",
"updateMenuListings",
"record");
setSortAction(".navLevel2",
"reorder.php",
"updateMenuItemListings",
"record");
});
#import url( 'https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css' );
#sortable_1,
#sortable_2,
#sortable_3 {
list-style-type: none;
margin: 0;
float: left;
margin-right: 10px;
background: #eee;
padding: 5px;
width: 143px;
}
#sortable_1 li,
#sortable_2 li,
#sortable_3 li {
margin: 5px;
padding: 5px;
font-size: 1.2em;
width: 120px;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
table {
font-size: 1em;
}
.ui-draggable,
.ui-droppable {
background-position: top;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<ul id="Nav" class="sortable navLevel1">
<ul id="sortable_1" class="droptrue navLevel2">
<li class="ui-state-disabled" style="opacity: 1; pointers-event: none; background: yellow">Classes</li>
<li id="item_1" class="ui-state-default">Some class</li>
<li id="item_2" class="ui-state-default">Another one!</li>
<li id="item_3" class="ui-state-default">Yep, thats enough</li>
</ul>
<ul id="sortable_2" class="droptrue navLevel2">
<li class="ui-state-disabled" style="opacity: 1; pointers-event: none; background: yellow">Presentation</li>
<li id="item_1" class="ui-state-default">Tom</li>
<li id="item_2" class="ui-state-default">Jessica</li>
<li id="item_3" class="ui-state-default">Kevin</li>
</ul>
</ul>
<br style="clear:both">
Unlike classes HTML ID's should be unique, in this way you can identify which items are from which columns.
Knowing for example that column one has 4 slots and column two has 6 would mean that a request array of 7,3,9,3,2,5,6,1,4,8,10 gets split into 4 and 6 hence
Column one: 7, 3, 9, 10,
Column two: 2, 5, 6, 1, 4, 8
$(function() {
var debugMode = true;
$("ul.droptrue").sortable({
connectWith: "ul"
});
//Set common sort settings for all lists
$(".sortable").sortable({
opacity: 0.6,
cursor: 'move'
});
//Function used to configure update calls for each sort
function setSortAction(selector, updatePage, updateAction, itemLabel) {
$(selector).sortable({
update: function() {
var itemList = $(this).sortable(
"serialize", {
attribute: "id",
key: itemLabel
});
//Create POST request to persist the update
var bodyContent = "action=" + updateAction + "&" + itemList;
if (debugMode) {
$('#report').text("DEBUG: bodyContent = \n" + bodyContent);
}
//$.post(updatePage, bodyContent, function (postResult)
//{ alert(postResult); });
}
});
}
//Set sort update action for top level and second level
setSortAction(".navLevel1",
"reorder.php",
"updateMenuListings",
"record");
setSortAction(".navLevel2",
"reorder.php",
"updateMenuItemListings",
"record");
});
#import url( 'https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css' );
#sortable_1,
#sortable_2,
#sortable_3 {
list-style-type: none;
margin: 0;
float: left;
margin-right: 10px;
background: #eee;
padding: 5px;
width: 143px;
}
#sortable_1 li,
#sortable_2 li,
#sortable_3 li {
margin: 5px;
padding: 5px;
font-size: 1.2em;
width: 120px;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
table {
font-size: 1em;
}
.ui-draggable,
.ui-droppable {
background-position: top;
}
#report {
position: fixed;
font-size: 0.5em;
bottom: 2em;
left: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<ul id="Nav" class="sortable navLevel1">
<ul id="sortable_1" class="droptrue navLevel2">
<li class="ui-state-disabled" style="opacity: 1; pointers-event: none; background: yellow">Classes</li>
<li id="item_1" class="ui-state-default">Some class</li>
<li id="item_2" class="ui-state-default">Another one!</li>
<li id="item_3" class="ui-state-default">Yep, thats enough</li>
</ul>
<ul id="sortable_2" class="droptrue navLevel2">
<li class="ui-state-disabled" style="opacity: 1; pointers-event: none; background: yellow">Presentation</li>
<li id="item_4" class="ui-state-default">Tom</li>
<li id="item_5" class="ui-state-default">Jessica</li>
<li id="item_6" class="ui-state-default">Kevin</li>
</ul>
</ul>
<div id="report"></div>
<br style="clear:both">
I'm looking to learn how to do this left menu :
http://js.devexpress.com/New/15_2/#HTML_5_JS_Core
When you scroll down the page, the "active" menu item change.
p.s.
Is there a name for this type of menu?
regards,
yaniv
Scroll Navigation
That is how we call these type of navigation bars. Basically you have to listen to the scroll event and calculate which element is in the viewport at the moment than you add a class to your navigation that marks the current menu element.
There is a nice demo built in jQuery but because jQuery is a thing of the past, I built one in Vanilla JS. See comments for explanations.
There are different ways to define which is the current element. In my Example it is the last one whose top line just passed the top line of the browser.
Working demo
window.onscroll = onScroll;
function onScroll() {
var removeActiveClass = function (elements) {
for (var i = 0; i < elements.length; ++i) {
elements[i].classList.remove('active');
}
}
var anchors = document.querySelectorAll('#menu-center a');
var previousRefElement = null;
for (var i = 0; i < anchors.length; ++i) {
// Get the current element by the id from the anchor's href.
var currentRefElement = document.getElementById(anchors[i].getAttribute('href').substring(1));
var currentRefElementTop = currentRefElement.getBoundingClientRect().top;
// Searching for the element whose top haven't left the top of the browser.
if (currentRefElementTop <= 0) {
//The browser's top line haven't reached the current element, so the previous element is the one we currently look at.
previousRefElement = anchors[i];
// Edge case for last element.
if (i == anchors.length - 1) {
removeActiveClass(anchors);
anchors[i].classList.add("active");
}
} else {
removeActiveClass(anchors);
previousRefElement.classList.add("active");
break;
}
}
}
body, html {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
.menu {
width: 100%;
height: 75px;
position: fixed;
background-color:rgba(4, 180, 49, 0.6);
}
#menu-center {
width: 980px;
height: 75px;
margin: 0 auto;
}
#menu-center ul {
margin: 15px 0 0 0;
}
#menu-center ul li {
list-style: none;
margin: 0 30px 0 0;
display: inline;
}
.active {
font-size: 14px;
color: #fff;
text-decoration: none;
line-height: 50px;
}
a {
font-size: 14px;
color: black;
text-decoration: none;
line-height: 50px;
}
.content {
height: 100%;
width: 100%;
}
#portfolio {background-color: grey;}
#about {background-color: blue;}
#contact {background-color: red;}
<div class="menu">
<div id="menu-center">
<ul>
<li><a class="active" href="#home">Home</a></li>
<li>Portfolio</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
</div>
<div id="home" class="content"></div>
<div id="portfolio" class="content"></div>
<div id="about" class="content"></div>
<div id="contact" class="content"></div>
This is not exactly menu type, it is the way how you can position objects by html.
You can use position:Abosule property to achieve this effect:
http://www.w3schools.com/css/tryit.asp?filename=trycss_position_fixed
By this given divs are "flying" above the res of the page. In your case it could be a menu.
EDIT:
To sync this you need to detect when given anchor is currently seen.
It can be done by jQuery, this is sample draft of code, should explain clue of solution:
// list of header on page
var positions = [
$("#anchor1").offset().top,
$("#anchor2").offset().top,
$("#anchor3").offset().top,
];
var menu_objects= [
"#menu1",
"#menu2",
"#menu3"
];
var $w = $(window).scroll(function(){
// clear old
for(var v in menu_objects)
$(v).css({"color","white"});
for(var i=positions.length-1;i>=0;i--)
{
if(positions[i]>=$w.scrollTop())
{
$(menu_objects[i]).css({"color","red"});
break;
}
}
});
I am doing a functionality for my website, where I want a functionality as same here.
In detail: When I hover on navigation, I want to make the background light.
Do let me know if needed anything else.
I hope I understand your question. See the example below:
$(document).ready(function() {
$("ul li").mouseover(function () {
$(this).addClass('light-bg', 1000);
$('body').addClass('new-body-bg', 1000);
});
$("ul li").mouseleave(function () {
$(this).removeClass('light-bg', 1000);
$('body').removeClass('new-body-bg', 1000);
}); });
ul {
background-color: #ddd; /* Choose the color of your choice */
height: 40px;
}
li {
display: inline-block;
font-size: 18px;
padding: 10px;
line-height: 20px;
text-align: center;
margin-right: 15px;
}
.light-bg {
background-color: #fff; /* Choose the color of your choice */
line-height: 20px;
}
.new-body-bg {
background-color: #ccc; /* Choose the color of your choice */
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li> One </li>
<li> Two </li>
<li>Three </li>
<li> Four</li>
</ul>
It works perfectly on JsFiddle
See: http://jsfiddle.net/snlacks/tekokmke/1/
Without using jQuery,
you want to find all of the elements you want to do this to
then you want to loop through them
You'll apply two listeners to each one, one for entering and one for leaving.
js:
var mes = document.querySelectorAll(".me");
function changeIn(){
document.body.style.backgroundColor = "lightgray";
}
function changeOut(){
document.body.style.backgroundColor = "darkgray";
}
for(i = 0; i < mes.length; i++){
mes[i].onmouseenter = changeIn;
mes[i].onmouseleave = changeOut;
}
I have a horizontal tab menu. These tabs are all li elements. I show always 5 of them at once. To the left and right I have buttons which scrolls these tabs to either side. I am just not sure how to achieve that. Can I put the next 5 tabs in a different div which will be shown on click? That wouldnt be the best solution, would it? Can I do this somehow with JavaScript or jQuery?
Thanks.
You can do this w/ jQuery. Easier if all of the tabs are the same width. You can position the UL inside a DIV that has overflow: hidden and position: relative. Then the UL can slide around inside the DIV using the animate() method (or the css() method). Check them out on http://api.jquery.com.
Here's an example:
<!DOCTYPE HTML>
<html>
<head>
<style>
* { margin: 0; padding: 0; }
body { padding: 30px; }
div#tabs { width: 360px; height: 30px; overflow: hidden; position: relative; }
ul { display: block; float: left; width: 1080px; position: absolute; left: -360px; }
li { display: block; float: left; width: 70px; height: 30px; font-size: 12px; border: 1px solid #333; }
button { float: left; width: 100px; margin: 20px; }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script>
$(document).ready(function()
{
$("button").click(function()
{
var tabs_list = $("div#tabs > ul");
if($(this).is("#left"))
{
tabs_list.animate({ left: "-=360" }, 500);
}
else if($(this).is("#right"))
{
tabs_list.animate({ left: "+=360" }, 500);
}
});
});
</script>
</head>
<body>
<div id="tabs">
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
<li>four</li>
<li>five</li>
<li>six</li>
<li>seven</li>
<li>eight</li>
<li>nine</li>
<li>ten</li>
<li>eleven</li>
<li>twelve</li>
<li>thirteen</li>
<li>fourteen</li>
<li>fifteen</li>
</ul>
</div>
<button id="left">scroll left</button>
<button id="right">scroll right</button>
</body>
</html>
This would need some more work in order to de-activate or hide the scroll buttons when you've reached the beginning or end of the tabs list, but this should get you started.
I like Elliot's solution. I have another one, which will work if the tabs are of different lengths. It does it by hiding and showing the individual "li"s as you click the "right" and "left" buttons. The code also takes care of moving the tabs 5 at a time, both left and right, and handles the end cases.
<!DOCTYPE HTML>
<html>
<head>
<style>
#left, #right {float: left; position: relative; margin: 0; padding: 0;}
#tabs {float: left; position: relative; list-style: none; margin: 0; padding: 0;}
#tabs li {float: left; display: none; border: 2px solid #000; width: 50px; text-align: center;};
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var tabs = $('#tabs li'), number_of_tabs = tabs.length;
var tabs_visible = Math.min(5, number_of_tabs), low_tab = 0, high_tab = (tabs_visible - 1);
$(tabs).filter(function(index){return (index < tabs_visible);}).show();
$('#left, #right').each(function(){
$(this).click(function(){
if ($(this).is('#right')) {
var high_tab_new = Math.min((high_tab + tabs_visible), (number_of_tabs - 1));
var low_tab_new = high_tab_new - tabs_visible + 1;
$(tabs).filter(function(index){
return (index >= low_tab) && (index < low_tab_new);
}).hide();
$(tabs).filter(function(index){
return (index > high_tab) && (index <= high_tab_new);
}).show();
low_tab = low_tab_new;
high_tab = high_tab_new;
} else {
var low_tab_new = Math.max((low_tab - tabs_visible), 0);
var high_tab_new = low_tab_new + tabs_visible - 1;
$(tabs).filter(function(index){
return (index > high_tab_new) && (index <= high_tab);
}).hide();
$(tabs).filter(function(index){
return (index >= low_tab_new) && (index < low_tab);
}).show();
low_tab = low_tab_new;
high_tab = high_tab_new;
}
});
});
</script>
</head>
<div id="nav3">
<button id="left">left</button>
<ul id="tabs">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<li>E</li>
<li>F</li>
<li>G</li>
<li>H</li>
<li>I</li>
</ul>
<button id="right">right</button>
</div>
</body>
</html>
Though I am not sure how would the tab look like, I am assuming that with the 5 tabs you are showing different set of page content.
I am suggesting a simple solution (Design) with Javascript. See if it works.
Have a variable to store the current View index. e.g. _currentView.
Place the content of 5 tabs in 5 views (When I say views there are many ways to establish it, ranging from using div object to using .net multiview control).
By default keep their visibility off.
Create a method, that'll accept the _currentView as the parameter. In this method, just make the current view visible.
On the click of left and right arrow, increment or decrement the _currentView value and call the method that activates the current view.
Please see if this helps you.