In my html page I have 2 divs with toggle function.
I need to modify this js to let it close other div when one is open
my js
jQuery( "div.bk-toggle-header" ).click(function(){
jQuery(this).siblings('div.bk-toggle-content-outer-wrap').animate({
height: 'toggle'
}, 'slow', function() {
});
jQuery(this).parents('div.bk-toggle').toggleClass('bk-toggle-closed');
});
My html
<div class="bk-toggle bk-toggle-closed">
<div class="bk-toggle-header content-separator">
<span class="title">First Tab</span>
<span class="bk-header-button"></span>
</div>
<div class="bk-toggle-content-outer-wrap"> content
</div></div>
<div class="bk-toggle bk-toggle-closed">
<div class="bk-toggle-header content-separator">
<span class="title">Second Tab</span>
<span class="bk-header-button"></span>
</div>
<div class="bk-toggle-content-outer-wrap" > content
</div></div>
I would appreciate some help to toggle divs one at a time.
Working demo http://jsfiddle.net/f492H/
Solution below will toggle div one at a time. you could play around with other Jquery ways as well !like is(':visible')
API used:
.slideToggle: http://api.jquery.com/slideToggle/
.parents : http://api.jquery.com/parents/
Hope it fits your needs :)
Code
$('.bk-toggle-content-outer-wrap').hide();
$('.title').on('click', function (e) {
$('.bk-toggle-content-outer-wrap').hide();
$(this).parents('.bk-toggle').find('.bk-toggle-content-outer-wrap').slideToggle();
});
I can offer you an accordion class I've written for a previous project. It's fairly flexible and should accomplish what you're asking and more. Documentation is... non-existent, but I'm happy to answer any implementation questions if you choose to use it.
Here it is in a fiddle: http://jsfiddle.net/YjAgb/1/
UPDATE:
Here is another fiddle working with your html structure: http://jsfiddle.net/WfWEP/
And, for the sake of being thorough, here's the demo code.
HTML
<div id='accordion'>
<div class='accHead'>Head 1</div>
<div class='accBody'>Body 1</div>
<div class='accHead'>Head 2</div>
<div class='accBody'>Body 2</div>
<div class='accHead'>Head 3</div>
<div class='accBody'>Body 3</div>
</div>
JavaScript
function accordion(options){
this.index = options.index;
var openChild = false;
var self = this;
var cEvent = {};
var slideSpeed = 200;
var headClass = '.accHead';
var bodyClass = '.accBody';
var $parent = options.parent;
var $heads = $parent.find(headClass);
var $bodies = $parent.find(bodyClass)
$heads.on('click', function(e){
var headClicked = $heads.index($(this)) + 1;
var wasTriggered = (!e.clientX);
var previousOpen = (headClicked == openChild) ? headClicked : openChild;
var newOpen = (headClicked == openChild) ? false : headClicked;
$heads.add($bodies).removeClass('on');
if (!openChild) {
var type = 'open';
} else if(headClicked == openChild) {
var type = 'close';
} else {
var type = 'swap';
}
cEvent = { clicked: headClicked,
triggered: wasTriggered,
previousOpen: previousOpen,
openChild: newOpen,
headElement: $(this),
bodyElement: $bodies.index(headClicked - 1),
type: type,
accordion: self
};
options.click_callback(cEvent);
if (openChild) closeLevel((headClicked == openChild) ? headClicked : openChild);
if ((!openChild) || (headClicked != openChild)) openLevel(headClicked);
openChild = newOpen;
});
var openLevel = function(levelId)
{
var $bodyEl = $bodies.eq(levelId - 1);
var $headEl = $heads.eq(levelId - 1);
cEvent.bodyElement = $bodyEl;
cEvent.headElement = $headEl;
$headEl.addClass('on');
$bodyEl.addClass('on').slideDown(slideSpeed, function(){
options.open_callback(cEvent);
})
}
var closeLevel = function(levelId)
{
var $bodyEl = $bodies.eq(levelId - 1);
var $headEl = $heads.eq(levelId - 1);
cEvent.bodyElement = $bodyEl;
cEvent.headElement = $headEl;
$bodyEl.slideUp(slideSpeed, function(){
options.close_callback(cEvent);
});
}
this.closeAll = function()
{
$heads.add($bodies).removeClass('on');
$bodies.slideUp(0);
return this;
}
this.click = function(levelId, caller)
{
if(caller.index != this.index) $heads.eq(levelId - 1).trigger('click');
}
this.getHead = function(levelId)
{
return $heads.eq(levelId - 1);
}
this.getBody = function(levelId)
{
return $bodies.eq(levelId - 1);
}
this.getParentAcc = function()
{
return $parent;
}
}
newAcc = new accordion({
parent: $('#accordion'),
click_callback: function(){},
open_callback: function(){},
close_callback: function(){},
})
.closeAll();
Related
I am a beginner in jQuery. As willing to develop a mobile website, I would like to implement sticky header for enhancing the user experiences.
Here are some codes of my work but it seems not work as calculation of the "top".
HTML:
<div class="fixed-header">
<div class="header_item" id="head_a"> A </div>
<div class="header_item" id="head_b"> B </div>
<div class="header_item" id="head_c"> C </div>
<div class="header_item" id="head_d"> D </div>
<div class="header_item" id="head_e"> E </div>
</div>
javascript and jQuery:
var $totalImageHeight;
$(window).on("load", function() { //Fires when DOM is loaded
getImageSizes();
$(window).resize(function() { //Fires when window is resized
getImageSizes();
});
});
function getImageSizes() {
$(".insurance_item img").each(function(count) {
var $this = $(this);
$imageHeight = $this.height();
$totalImageHeight = $imageHeight * (count + 1);
});
}
var stickyHeaders = (function() {
var $window = $(window),
$stickies;
var load = function(stickies) {
if (typeof stickies === "object" && stickies instanceof jQuery && stickies.length > 0) {
$stickies = stickies.each(function() {
var $thisSticky = $(this).wrap('<div class="followWrap" style="height: 0;"/>');
$thisSticky
.data('originalPosition', $thisSticky.offset().top)
.data('originalHeight', $thisSticky.outerHeight( 75 ))
.parent().height($thisSticky.outerHeight( 75 ));
});
$window.off("scroll.stickies").on("scroll.stickies", function() {
_whenScrolling();
});
}
};
var _whenScrolling = function() {
$stickies.each(function(i) {
var $thisSticky = $(this),
$stickyPosition = $thisSticky.data('originalPosition');
if ($stickyPosition <= $window.scrollTop()) {
var $nextSticky = $stickies.eq(i + 1);
$nextStickyPosition = $totalImageHeight - $nextSticky.data('originalPosition') - $thisSticky.data('originalHeight');
$thisSticky.addClass("fixed").css("top", $nextStickyPosition);
if ($nextSticky.length > 0 && $thisSticky.offset().top >= $nextStickyPosition) {
$thisSticky.addClass("absolute").css("top", $nextStickyPosition);
}
}else{ //scroll up and disable the fixed header
var $prevSticky = $stickies.eq(i - 1);
$thisSticky.removeClass("fixed");
if($prevSticky.length>0&&$window.scrollTop()<=
$thisSticky.data('originalPosition') -
$thisSticky.data('originalHeight')){
$prevSticky.removeClass("absolute").removeAttr("style");
}
}
});
};
return {
load: load
};
})();
$(function() {
stickyHeaders.load($(".header_item"));
});
Sorry for the late answer. I create an new javascript for implementing this function.
Code:
var $window = $(window);
var imageArr = [];
var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
console.log(iOS);
$(window).on("load", function() { //Fires when DOM is loaded
getImageSizes();
window.requestAnimationFrame(tick);
$(window).resize(function() { //Fires when window is resized
getImageSizes();
scrollDetect(imageArr);
});
});
function getImageSizes() { //get the numbers of images and its outerHeight
var $items = $(".insurance_item");
for(var c = 0; c < $items.length; c++){
imageArr[c] = $($items[c]).outerHeight();
}
}
function scrollDetect(imageArr){ //show the title header of image once the image is offscreen.
var $items = $('.header_item');
for(var c = 0; c < imageArr.length; c++){
if($window.scrollTop() >= (imageArr[c] * (c+1)) - $('#fixed-header').outerHeight()){
$items.eq(c).show();
}else{
$items.eq(c).hide();
}
}
window.requestAnimationFrame(tick); //prevent the frame lost and make a incorrect calculation
}
function tick(){
scrollDetect(imageArr);
};
May be some better solution for solving this situation, thanks for everyone.
I'm trying to write some JS that will allow HTML such as this:
<div class="box" data-vert-speed="7">ContentDiv1</div>
<div class="box" data-hori-speed="10">ContentDiv2</div>
<div class="box" data-rota-speed="5">ContentDiv3</div>
<div class="box" data-vert-speed="2.4">ContentDiv4</div>
<div class="box" data-hori-speed="1.3">ContentDiv5</div>
<div class="box" data-rota-speed="2.3">ContentDiv6</div>
to perform a CSS transform on each div on page scroll (the rate of which dictated by the attribute value.
where "vert" "hori" and "rota", are the CSS transforms vertical, horizontal and a rotation respectively.
The JS I have works for one of these types but I can't get it to detect all three types of attributes and execute them.
$.fn.moveItrota = function(){
var $windowr = $(window);
var instancesr = [];
$(this).each(function(){
instancesr.push(new moveItItemrota($(this)));
});
window.onscroll = function(){
var scrollTopr = $windowr.scrollTop();
instancesr.forEach(function(instr){
instr.updater(scrollTopr);
});
}
}
$.fn.moveItvert = function(){
var $windowv = $(window);
var instancesv = [];
$(this).each(function(){
instancesv.push(new moveItItemvert($(this)));
});
window.onscroll = function(){
var scrollTopv = $windowv.scrollTop();
instancesv.forEach(function(instv){
instv.updatev(scrollTopv);
});
}
}
$.fn.moveIthori = function(){
var $windowh = $(window);
var instancesh = [];
$(this).each(function(){
instancesh.push(new moveItItemhori($(this)));
});
window.onscroll = function(){
var scrollToph = $windowh.scrollTop();
instancesr.forEach(function(insth){
insth.updateh(scrollToph);
});
}
}
//Rotation Scrolling ------------------------------------------------
if ($('.box').attr('data-rota-speed')){
console.log("found a rota");
var moveItItemrota = function(elr){
this.elr = $(elr);
this.speedr = parseInt(this.elr.attr('data-rota-speed'));
console.log(this.speedr);
};
moveItItemrota.prototyper.updater = function(scrollTopr){
var posr = scrollTopr / this.speedr;
this.elr.css('transform', 'rotate(' + -posr + 'deg)');
};
$(function(){
$('[data-rota-speed]').moveItrota();
});
};
//Horizontal Scrolling ------------------------------------------------
if ($('.box').attr('data-hori-speed')){
console.log("found a hori");
var moveItItemhori = function(elh){
this.elh = $(elh);
this.speedh = parseInt(this.elh.attr('data-hori-speed'));
console.log(this.speedh);
};
moveItItemhori.prototypeh.updateh = function(scrollToph){
var posh = scrollToph / this.speedh;
this.elh.css('transform', 'translateX(' + -posh + 'px)');
};
$(function(){
$('[data-hori-speed]').moveIthori();
});
};
//Vertical Scrolling ------------------------------------------------
if ($('.box').attr('data-vert-speed')){
console.log("found a vert");
var moveItItemvert = function(elv){
this.elv = $(elv);
this.speedv = parseInt(this.elv.attr('data-vert-speed'));
console.log(this.speedv);
};
moveItItemvert.prototype.updatev = function(scrollTopv){
var posv = scrollTopv / this.speedv;
this.elv.css('transform', 'translateY(' + -posv + 'px)');
};
$(function(){
$('[data-vert-speed]').moveItvert();
});
};
What I can tell from your code is that you have 2 data points on the same attribute, I would suggest separate them (if possible). From your code, I assume every element has a single movement type and the movement speed. If there is more than one, this may require a bit of tweaking. If my assumption is correct, you could do something like:
<div class="box" data-movement="vertical" data-speed="7">ContentDiv1</div>
<div class="box" data-movement="horizontal" data-speed="10">ContentDiv2</div>
<div class="box" data-movement="rotation" data-speed="5">ContentDiv3</div>
<div class="box" data-movement="vertical" data-speed="2.4">ContentDiv4</div>
<div class="box" data-movement="horizontal" data-speed="1.3">ContentDiv5</div>
<div class="box" data-movement="rotation" data-speed="2.3">ContentDiv6</div>
Then on js, get the items and apply the css
var boxItems = $(".box");
$.map(boxItems, function(item, i) {
var movement = $(item).data("movement");
var speed = $(item).data("speed");
switch(movement) {
case "horizontal": {
// move horizontally (not sure if this is done with transforms)
break;
}
case "vertical": {
// move vertically (not sure if this is done with transforms)
break;
}
case "rotation": {
// rotate (not sure if this is done with transforms)
break;
}
}
});
I did not write the movement code since not sure if you are using css transform ... but just in case, here is a link that describes how to apply this.
http://www.w3schools.com/jsref/prop_style_transform.asp
Hope this helps.
I have one problem with click function. I have created this demo from jsfiddle.net.
In this demo you can see there are smile buttons. When you click those buttons then a tab will be opening on that time. If you click the red button from tab area then the tab is not working there are something went wrong.
Anyone can help me here what is the problem and what is the solution?
The tab is normalize like this working demo
var response = '<div class="icon_b">
<div class="clickficon"></div>
<div class="emicon-menu MaterialTabs">
<ul>
<li class="tab active"> TAB1</li>
<li class="tab"> TAB2</li>
<li class="tab"> TAB3<span></span></li>
</ul>
<div class="panels">
<div id="starks-panel1" class="panel pactive"> a </div>
<div id="lannisters-panel1" class="panel"> b </div>
<div id="targaryens-panel1" class="panel"> c </div>
</div>
</div>
</div>';
$(document).ready(function () {
function showProfileTooltip(e, id) {
//send id & get info from get_profile.php
$.ajax({
url: '/echo/html/',
data: {
html: response,
delay: 0
},
method: 'post',
success: function (returnHtml) {
e.find('.user-container').html(returnHtml).promise().done(function () {
$('.emoticon').addClass('eactive');
});
}
});
}
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
$(this).on( "click", function() {
$(this).find('.user-container').html("");
});
var componentHandler = function() {
'use strict';
var registeredComponents_ = [];
var createdComponents_ = [];
function findRegisteredClass_(name, opt_replace) {
for (var i = 0; i < registeredComponents_.length; i++) {
if (registeredComponents_[i].className === name) {
if (opt_replace !== undefined) {
registeredComponents_[i] = opt_replace;
}
return registeredComponents_[i];
}
}
return false;
}
function upgradeDomInternal(jsClass, cssClass) {
if (cssClass === undefined) {
var registeredClass = findRegisteredClass_(jsClass);
if (registeredClass) {
cssClass = registeredClass.cssClass;
}
}
var elements = document.querySelectorAll('.' + cssClass);
for (var n = 0; n < elements.length; n++) {
upgradeElementInternal(elements[n], jsClass);
}
}
function upgradeElementInternal(element, jsClass) {
if (element.getAttribute('data-upgraded') === null) {
element.setAttribute('data-upgraded', '');
var registeredClass = findRegisteredClass_(jsClass);
if (registeredClass) {
createdComponents_.push(new registeredClass.classConstructor(element));
} else {
createdComponents_.push(new window[jsClass](element));
}
}
}
function registerInternal(config) {
var newConfig = {
'classConstructor': config.constructor,
'className': config.classAsString,
'cssClass': config.cssClass
};
var found = findRegisteredClass_(config.classAsString, newConfig);
if (!found) {
registeredComponents_.push(newConfig);
}
upgradeDomInternal(config.classAsString);
}
return {
upgradeDom: upgradeDomInternal,
upgradeElement: upgradeElementInternal,
register: registerInternal
};
}();
function MaterialTabs(element) {
'use strict';
this.element_ = element;
this.init();
}
MaterialTabs.prototype.Constant_ = {
MEANING_OF_LIFE: '42',
SPECIAL_WORD: 'HTML5',
ACTIVE_CLASS: 'pactive'
};
MaterialTabs.prototype.CssClasses_ = {
SHOW: 'materialShow',
HIDE: 'materialHidden'
};
MaterialTabs.prototype.initTabs_ = function(e) {
'use strict';
this.tabs_ = this.element_.querySelectorAll('.tab');
this.panels_ = this.element_.querySelectorAll('.panel');
for (var i=0; i < this.tabs_.length; i++) {
new MaterialTab(this.tabs_[i], this);
}
};
MaterialTabs.prototype.resetTabState_ = function() {
for (var k=0; k < this.tabs_.length; k++) {
this.tabs_[k].classList.remove('pactive');
}
};
MaterialTabs.prototype.resetPanelState_ = function() {
for (var j=0; j < this.panels_.length; j++) {
this.panels_[j].classList.remove('pactive');
}
};
function MaterialTab (tab, ctx) {
if (tab) {
var link = tab.querySelector('a');
link.addEventListener('click', function(e){
e.preventDefault();
var href = link.href.split('#')[1];
var panel = document.querySelector('#' + href);
ctx.resetTabState_();
ctx.resetPanelState_();
tab.classList.add('pactive');
panel.classList.add('pactive');
});
}
};
MaterialTabs.prototype.init = function() {
if (this.element_) {
this.initTabs_();
}
}
window.addEventListener('load', function() {
componentHandler.register({
constructor: MaterialTabs,
classAsString: 'MaterialTabs',
cssClass: 'MaterialTabs'
});
});
});
There is updated and working version.
What we have to do, is to move the target on the same level as the icon is (almost like tab and content). Instead of this:
<div class="emoticon">
<div class="emoticon_click" data-id="1">
<img src="http://megaicons.net/static/img/icons_sizes/8/178/512/emoticons-wink-icon.png" width="30px" height="30px">
<div class="user-container" data-upgraded></div>
</div>
</div>
We need this
<div class="emoticon">
<div class="emoticon_click" data-id="1">
<img src="http://megaicons.net/static/img/icons_sizes/8/178/512/emoticons-wink-icon.png" width="30px" height="30px">
// not a child
<!--<div class="user-container" data-upgraded></div>-->
</div>
// but sibling
<div class="user-container" data-upgraded></div>
</div>
And if this is new HTML configuration, we can change the handlers
to target click on div "emoticon_click"
change the content of the sibling (not child) div "user-container"
The old code to be replaced
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
$(this).on( "click", function() {
$(this).find('.user-container').html("");
});
will now be replaced with this:
//$('body').on('click', '.emoticon', function(e) {
$('body').on('click', '.emoticon_click', function(e) {
// clear all user container at the begining of this click event
$('body').find('.user-container').html("");
// find id
var id = $(this).attr('data-id');
// find the parent, which also contains sibling
// user-container
var parent = $(this).parent()
// let the target be initiated
showProfileTooltip($(parent), id);
});
$(this).on( "click", function() {
//$(this).find('.user-container').html("");
});
Check it in action here
NOTE: the really interesting note was in this Answer by pinturic
If we want to extend the first and complete answer with a feature:
close all tabs if clicked outside of the area of tabs or icons
we just have to
add some event e.g. to body
and do check if the click was not on ".emoticon" class elements
There is a working example, containing this hook:
$('body').on( "click", function(e) {
// if clicked in the EMOTICON world...
var isParentEmotion = $(e.toElement).parents(".emoticon").length > 0 ;
if(isParentEmotion){
return; // get out
}
// else hide them
$('body').find('.user-container').html("");
});
I have been debugging your code and this is the result:
you are adding the "tab" under ; any time you click within that div this code is intercepting it:
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
and thus the "tab" are built again from scratch.
I'm trying to connect previous and fwd buttons to a gallery and I want the previous button to be hidden on first image of the gallery but javascript doesn't seem to be working at all.
Javascript
var imageGallery = new Array();
imageGallery[0] = '1.png';
imageGallery[1] = '2.png';
imageGallery[2] = '3.png';
imageGallery[3] = '4.png';
imageGallery[4] = '5.png';
var imgCount = 0;
function next() {
imgCount++ ;
document.getElementById("gallery").src = imageGallery[imgCount] ;
}
function previous() {
imgCount--;
document.getElementById("gallery").src = imageGallery[imgCount] ;
}
if(document.getElementById("gallery").getAttribute("src") == "1.png")
{
document.getElementById("previous").style.visibility = 'hidden';
}
else
{
document.getElementById("previous").style.visibility = 'visible';
}
HTML
<div id="img">
<img id="gallery" src="1.png" style="height:420px; width:744px" >
<div id="imgNav">
<a id="previous" href onclick="previous(); return false;">previous</a>
<span style="color:#666; font-size:0.9em"> | </Span>
<a id="next" href onclick="next(); return false;">next</a>
</div>
</div>
Actually the logic is if 'src' attribute of id 'gallery' is '1.png' then 'visibility' of element with id 'previous' is 'hidden' else not but doesn't seem to be working. Can anyone help figuring it out.
You're probably trying to check on an image that's not totally loaded yet. Did you remember to place your code to run just when the page is fully loaded (in case it's placed in the page headers - you didn't mention whether it is or not)?
UPDATED
var imageGallery = new Array();
imageGallery[0] = '1.png';
imageGallery[1] = '2.png';
imageGallery[2] = '3.png';
imageGallery[3] = '4.png';
imageGallery[4] = '5.png';
var imgCount = 0;
function checkNav() {
var previousLnk = document.getElementById("previous");
var nextLnk = document.getElementById("next");
previousLnk.style.visibility = imgCount == 0 ? 'hidden' : 'visible';
nextLnk.style.visibility = imgCount >= (imageGallery.length - 1) ? 'hidden' : 'visible';
}
function setImg() {
var gallery = document.getElementById("gallery");
gallery.src = imageGallery[imgCount];
}
function next() {
imgCount++;
setImg();
checkNav();
}
function previous() {
imgCount--;
setImg();
checkNav();
}
window.onload = function () {
checkNav();
}
Demo: http://jsfiddle.net/N7V9E/
HTML:
<div class="promo_tumbs col_12">
<div data-dir="prev" class="prev"></div>
<div data-dir="next" class="next"></div>
<div class="promo_tumbs_centar">
<div class="promo_tumb promo_tumb_current">Test</div>
<div class="promo_tumb">Test</div>
<div class="promo_tumb">Test</div>
<div class="promo_tumb">Test</div>
<div class="promo_tumb">Test</div>
<div class="promo_tumb">Test</div>
<div class="promo_tumb">Test</div>
</div>
</div>
JavaScript:
function Slider(container, nav) {
this.container = container;
this.nav = nav;
this.li = this.container.find('li');
this.li_width = this.li.first().width();
this.li_len = this.li.length;
this.thumbs = this.nav.find('a');
this.current = 0;
}
Slider.prototype.transition = function(coords) {
this.container.stop().animate({
'margin-left': coords || -(this.current * this.li_width)
})
}
Slider.prototype.set_current = function(dir) {
var pos = this.current;
if (dir === 'next') {
pos++
}
else if (dir === 'prev') {
pos--
}
this.current = (pos < 0) ? this.li_len - 1 : pos % this.li_len;
return pos;
}
var slider = new Slider($('div.promo_inner ul'), $('div.promo_tumbs'));
slider.nav.find('div').on('click', function() {
if ($(this).attr("data-dir") === undefined) {
var index = slider.thumbs.index($(this).parent('a'));
console.log(index)
} else {
slider.set_current($(this).data('dir'));
}
slider.transition();
})
Fiddle link
When I click on element I am getting two values - index of clicked element and -1. What is going on here? How can I loose -1 and get only index value?
Call event.stopPropagation(); in order to stop the propagation of event Demo on JsFiddle
This will give you more idea what elements causing double event Reason for multiple events JsFiddle
nav.find() also matches <div class="promo_tumbs_centar">. Try find(".promo_tumb")
When clicking on a .promo_tumb div, you're also clicking on .promo_tumbs_centar.
You should use this :
slider.nav.find('.promo_tumb')
instead of
slider.nav.find('div')