I have a jquery exapandable list, currently when i click a link it opens IN ADDITION to any open previously. How can I change this so if I had mobile open then i click Landline, it opens landline but also closes mobile? I only want one item to be open at any one time.
JS
$(document).ready(function() {
setTimeout(function() {
// Slide
$('#menu1 > li > a.collapsed + ul').slideToggle('medium');
$('#menu1 > li > a').click(function() {
$(this).toggleClass('expanded').toggleClass('collapsed').parent().find('> ul').slideToggle('medium');
});
$('#example1 .expand_all').click(function() {
$('#menu1 > li > a.collapsed').addClass('expanded').removeClass('collapsed').parent().find('> ul').slideDown('medium');
});
$('#example1 .collapse_all').click(function() {
$('#menu1 > li > a.expanded').addClass('collapsed').removeClass('expanded').parent().find('> ul').slideUp('medium');
});
}, 250);
});
HTML
<div id="example1">
<ul id="menu1" class="example_menu">
<li><a class="collapsed">Mobile</a>
<ul>
<li><h2>TEST1</h2><br>
</ul>
</li>
<li class="footer"><span> </span></li>
<li><a class="collapsed">Landline</a>
<ul>
<li><h2>TEST2</h2><br>
</ul>
</li>
jsfiddle http://jsfiddle.net/EfURx/1/
I have made something for you :) I hope that will helps you.
AUTO CLOSE COLLAPSIBLE
$('.openMe').each(function() {
var coll = $(this);
coll.trigger('expand');
});
$('.openMe').each(function() {
var coll = $(this);
coll.trigger('collapse');
});
Good work
solved by using the 'Accordion' option on these range of menus file:///Users/johnfarrell/Desktop/collapsible-menu/collapsible-menu.html
All I needed was an accordion menu, sorted!
Related
3 li items all are different.
If all li are the same it means duplicate and we have to automate this scenario
I expect that code should able to automate the process of finding duplicate li items
$runAction("org.getopentest.selenium.ReadElementText", {
locator: $data("locators/Profile").ClientsCSP,
$localData: {
description: "$output.text"
}
});
var str1 = $localData.abc;
$log(str1);
<div data-autoid="Clients" class="m-section ItemList__itemList___2dOxf m-body" style="" xpath="1">
<ul>
<li data-autoid="Clients_item_0" class="ItemList__label___1N5Nz">1-800 Contacts</li>
<li data-autoid="Clients_item_1" class="ItemList__label___1N5Nz">10 Advertising</li>
<li data-autoid="Clients_item_2" class="ItemList__label___1N5Nz">clients_23rd July</li>
</ul>
</div>
store li items in the array and if duplicate found log it
The best way to go about it is to use the GetElements action.
- description: Find all li elements
action: org.getopentest.selenium.GetElements
args:
locator: ... # This locator must match all li elements
- script: |
var listItems = $output.elements;
var itemsTextArray = listItems.map(function(li) {
return li.getText();
})
// Next, check itemsTextArray for duplicate items
<ul>
<li (click)="AddColor($event)">ONE</li>
<li (click)="AddColor($event)">TWO</li>
<li (click)="AddColor($event)">THREE</li>
</ul>
AddColor(e){
e.srcElement.style.color="blue"
}
I have the above list when i click any one of the li item out of 3, the clicked label color should be changed. when i click another all item colors should be revert back to original and change color of current clicked item.
#Mehdi said, you should not access DOM directly untill there is a need.
Always keep in mind, drive your view with data rather than accessing
DOM directly
I have forked and working snippet https://plnkr.co/edit/fgINMc?p=preview
When using Angular, you don't want to directly manipulate the DOM element. Rather let angular deal with it.
In your example, you can generate your list from an array you declare in the code like so
export class YourClass{
links:any;
activeLink = -1;
//...
constructor(){
this.links = ['ONE','TWO','THREE']
}
//...
}
and then in your template you could have :
<ul>
<li *ngFor="let link of links; let i = index"
(click)="activeLink = i"
[ngClass]="activeLink == i? 'blue' : '' " >
</li>
</ul>
and declare a css class blue :
.blue{
color:blue;
}
So in my bootstrap 3.3.6 I have a menu that includes links.
In smaller sizes the menu becomes a dropdown menu and I want , when a menu item is clicked , the menu to go away.
I guess I can do something like
function closeMenu(){
//? uhm, what?
}
document.getElementByClass ("menuLink").addEventListener("closeMenu",findit,false);
but I dont have a clue what to set inside my function, so the dropdown will go back up again
Any help?
Thanks
I figured a way.
Inside the div with the links, I set a controller and ng-click for every link.
<ul class="nav navbar-nav navbar-right" ng-controller="navCtrl" >
<li><a ng-click="menuLinkClicked()" href="#/"> Home </a></li>
<li><a ng-click="menuLinkClicked()" href="#jake"> Jake</a></li>
<li><a ng-click="menuLinkClicked()" href="#amir"> Amir</a></li>
</ul>
and in my controller
app.controller('navCtrl',['$scope',
function ($scope) {
$scope.menuLinkClicked = function () {
document.getElementById("navbar").className="navbar-collapse collapse";
};
}
]);
navbar is the id of the menu that collapses in smaller screens. I use document.getElementById("navbar") to get it and then change its class to make it dissappear.
In order to learn riot.js I started from well-known bootstrap navbar example. Then I added my custom tag using riot.js:
<script type="riot/tag">
<menu-item>
<li><a href={this.href}><yield/></a></li>
this.href = opts.href
</menu-item>
</script>
<script src="https://cdn.jsdelivr.net/g/riot#2.2(riot.min.js+compiler.min.js)"></script>
<script>
riot.mount('*')
</script>
Finally I tried to use my new tag, replacing
<li>JavaScript</li>
by
<menu-item href="http://getbootstrap.com/javascript">JavaScript</menu-item>
Result is broken. Why? (original non-broken example can be found here: jsfiddle.net/0hp9pwpu)
Your riot tag markup is inserted into your riot tag i.e. what happens is
ul
li
from your working example is actually
ul
menu-item
li
in your non-working example. Since bootstrap styles the navigation items expecting a certain hierarchy, your result is broken.
This was raised as an issue (https://github.com/riot/riot/issues/295) and closed using https://github.com/riot/riot/pull/569 i.e. instead of using the riot tags directly there is an option to add the riot tag as an attribute. So something like
<li riot-tag="menu-item" href="http://getbootstrap.com/javascript">JavaScript</li>
Admittedly, it is not as semantic
Fiddle - http://jsfiddle.net/86khqhwu/
Bootstrap is not adapted for use with Riot.js
Your resulted html is :
<menu-item href="http://getbootstrap.com/javascript">
<li>
JavaScript
</li>
</menu-item>
Bootstrap css is broken ...
Perhaps not so elegant, but in riot 2.3.13 I'm using something like this in a .tag file:
<menu-bar>
<ul list="<yield/>">
<li each={ item in items }>
{ titles[item] }
</li>
</ul>
<script>
this.titles = {
inventario: 'Inventario',
resguardos: 'Resguardos',
catalogos: 'Catálogos',
reportes: 'Reportes',
configurar: 'Configurar',
utilidades: 'Utilidades'
}
this.items = null
this.on('mount', function () {
var el = this.root.querySelector('ul')
this.items = el.getAttribute('list').trim().split(/,\s?/)
el.removeAttribute('list')
this.update()
})
</script>
</menu-bar>
Now, in the HTML page:
<menu-bar>
inventario,resguardos,catalogos,reportes
</menu-bar>
Works.
Update: I left the following javascript code in to show how the problem developed over time, but it turns out now this is NOT relevant as javascript is not the issue. Please take a look at the html/css code below.
For an overview page with a large menu, I implemented the following function (most of which I stole from here):
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
alert(elemBottom);
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
}
$(document).ready(function(){
var overview = $('#overview');
var active = $('#active-item');
if (!isScrolledIntoView(active))
{
$('#overview li.active-parent').each(function(index, value){
if (!isScrolledIntoView(active)) overview.scrollTo(value);
});
}
if (!isScrolledIntoView(active)) overview.scrollTo(active);
});
The idea is that after every page load, the containing the menu is scrolled into a position where the current #active-item is visible. Preferably by scrolling to its first parent (the menu items are in a tree) otherwise to the item itself.
Now this works fine in Firefox and Chrome (and none of the apple people have complained to me), but Opera does a really strange thing: it scrolls down to the correct element, then pauses very briefly before scrolling all the way up again
Does anybody have any idea
What's going on, and
How can I stop it?
Thanks,
Update: I'm testing with version 10.63 on linux (Fedora)
Update: it appears I was searching in the wrong direction entirely. The issue appears to be a css thing, and can be replicated with the following code:
<html>
<head>
<title>Opera scroll test</title>
<style>
.main:after
{
content: 'abc';
}
:focus
{
padding: 0px;
}
#overview
{
display: block;
float: left;
width: 219px;
height: 500px;
overflow: auto;
}
</style>
</head>
<body>
<div id="main" class="main">
<div id="overview">
<ul>
<?
for($i = 1; $i < 100; $i++)
echo '<li>'.$i.'</li>';
?>
</ul>
</div>
<div>
<p>123</p>
</div>
</div>
</body>
</html>
Now if you scroll down on the navigation pane, and the move your mouse to the right (over the content pane) the scroll of the navigation pane is reset.
Sorry for wasting everyone's time with a javascript hunt :(
If there are any css gurus out there who know how to fix it, or who can simply explain what's going on I'd be very grateful.
Update: tested the above code in windows on opera 10.63. The same strange behaviour occurs.
Update: have reported this to Opera as a bug. Wonder what will happen...
Not sure as to the why but the issue seems directly related to the .main:after content CSS setting. Can you use jQuery? If so, if you comment out or remove the .main:after CSS setting and replace it with the following script in your <head> tag you get the same visual result without the weird scrolling issue:
<script type="text/javascript">
$(document).ready(function(){
$(".main").append("abc");
});
</script>
I have an idea of whats going on, however I tried your code and so far I cant seem to replicate the problem. Chrome and Opera behave the same.
This is the HTML I tried with:
<div id="overview" style="height: 300px;overflow-y: scroll;">
<ul>
<li class="item" style="height: 400px;">item 1</li>
<li class="item" style="height: 400px;">item 2 </li>
<li class="active-parent" style="height: 400px;">active-parent<br/><br/>
<ul>
<li id="active-item" style="height: 300px;">active-item</li>
</ul>
</li>
</ul>
</div>
As to why it doesnt work in Opera: which version of Opera are you using? I tried 10.63 (the latest) and its fine on that one.
Since I cant reproduce the issue I'm going to take a blind shot at it:
Try introducing a slight delay so this code gets executed after everything else in the queue:
$(document).ready(function() {
window.setTimeout(function() {
// Your code goes here
}, 500);
});
LATER ADDITION:
In response to your statement: "I really would like to understand what's going on here though. Why a delay? And would the delay need to be longer on slower computers?":
If setting a delay fixes your problem then the reason is clear, there is some other piece of code interfering with the "scroll to top" functionality that was executing after it. By setting a delay of 500ms you are making sure your code runs after every other piece of Javascript that executes when a document loads, this could could either be something you explicitly added to the jQuery function queue when the document loads (using $(document).ready(function(){), or implicitly added by Opera in the form of a "Widget" (do you have any translation tools, google toolbars etc, installed?).
As to whether the delay needs to be longer for slower computers, I personally dont think so, the key is that the delay forces your code to execute AFTER EVERY OTHER SCRIPT triggered by the document.onload event. Since my suspicion is that whatever is intefering executes in direct succession after the document loads you don't really need a very long delay, even 50ms might do it, the key is that the delay forces your code to go at the back of the queue.
Hope this helps make things more clear.
As Steven de Salas mentioned, adding a delay helps -> $(window).scrollTop() returns 0 if not delayed!!
I played around a bit and came up with this example:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Scrolling Test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js" type="text/javascript"></script>
<style type="text/css">
.parent { margin-bottom:100px; border:1px solid red; }
</style>
<script type="text/javascript">
(function ($){
$.fn.extend({
viewport : function(){
if (this.length > 0) {
var element = $(this.get(0)),
pad = $.fn.viewport.PADDING,
vp = {
height : element.height() + 2 * pad,
top : element.offset().top - pad,
docHeight : $(window).height(),
docTop : $(window).scrollTop(),
completelyInViewport : false
};
vp.bottom = vp.top + vp.height + pad;
vp.docBottom = vp.docTop + vp.docHeight;
vp.fitsInViewport = vp.height <= vp.docHeight;
if (vp.top > vp.docTop && vp.bottom < vp.docBottom) {
vp.completelyInViewport = true;
}
return vp;
}
return null;
}
});
$.fn.extend($.fn.viewport, {
PADDING: 10, // ADJUST TO YOUR NEEDS
LARGE_PARENT_BEHAVIOR: "bottom" // if parent list is bigger than viewport and
// the active item is not in the first page of
// the parents list, where should it be shown
// possible: "bottom", "middle" or "top"
});
$.extend({
ensureViewport: function(element, parent) {
var e_vp = element.viewport(),
p_vp = parent.viewport();
if (null == e_vp || null == p_vp) {
return;
}
if (!p_vp.completelyInViewport) {
if (p_vp.fitsInViewport || e_vp.bottom - p_vp.top <= e_vp.docHeight) {
doScroll(p_vp.top);
} else {
switch($.fn.viewport.LARGE_PARENT_BEHAVIOR) {
case "top":
doScroll(e_vp.top);
break;
case "middle":
doScroll(e_vp.top - (e_vp.docHeight - e_vp.height)/2);
break;
case "bottom":
default:
doScroll(e_vp.bottom - e_vp.docHeight);
break;
}
}
}
function doScroll(y){
window.scrollTo(0, y);
// you could implement instead some sort of smooth scroling mechanism here
// e.g. http://github.com/kswedberg/jquery-smooth-scroll
}
}
});
$(function(){
window.setTimeout(function(){
var item = $("li.active-item");
if (item.size() > 0) {
$.ensureViewport(item, item.closest("li.parent"));
}
}, 0);
});
})(jQuery);
</script>
</head>
<body>
<div id="overview">
<ul>
<li class="parent">
parent 1
<ul class="item"><li>item 1</li><li>item 2</li></ul>
</li>
<li class="parent">
parent 2
<ul class="item"><li>item 1</li><li>item 2</li></ul>
</li>
<li class="parent">
parent 3
<ul class="item"><li>item 1</li><li>item 2</li></ul>
</li>
<li class="parent">
parent 4
<ul class="item"><li>item 1</li><li class="active-item">item 2</li></ul>
</li>
<li class="parent">
parent 5
<ul class="item"><li>item 1</li><li>item 2</li></ul>
</li>
<li class="parent">
parent 6
<ul class="item"><li>item 1</li><li>item 2</li></ul>
</li>
<li class="parent">
parent 7
<ul class="item"><li>item 1</li><li>item 2</li></ul>
</li>
</ul>
</div>
</body>
</html>
Tested it on Opera 10.63 and it's working there too.
Cheers
This is just a theory, but might get you started.
When you press back on a browser, it often takes you to the point in the page where you were last viewing.
Is it possible that opera is trying to take you to that point, which is interfering with your code?
I wonder if you clear your history / cache, kill the opera process and start with a new process. Does that make any difference.