I'm using a WordPress plugin (open source) that will allow you to add an expandable widget for a WooCommerce product category.
This is the JS:
// mtree.js
// Requires jquery.js and velocity.js (optional but recommended).
// Copy the below function, add to your JS, and simply add a list <ul class=mtree> ... </ul>
;(function ($, window, document, undefined) {
// Only apply if mtree list exists
if($('ul.mtree').length) {
// Settings
var collapsed = true; // Start with collapsed menu (only level 1 items visible)
var close_same_level = true; // Close elements on same level when opening new node.
var duration = mtree_options.duration; // Animation duration should be tweaked according to easing.
var listAnim = true; // Animate separate list items on open/close element (velocity.js only).
var easing = mtree_options.easing_type; // Velocity.js only, defaults to 'swing' with jquery animation.
// Set initial styles
$('.mtree ul').css({'overflow':'hidden', 'height': (collapsed) ? 0 : 'auto', 'display': (collapsed) ? 'none' : 'block' });
// Get node elements, and add classes for styling
var node = $('.mtree li:has(ul)');
node.each(function(index, val) {
$(this).children(':first-child').css('cursor', 'pointer')
$(this).addClass('mtree-node mtree-' + ((collapsed) ? 'closed' : 'open'));
$(this).children('ul').addClass('mtree-level-' + ($(this).parentsUntil($('ul.mtree'), 'ul').length + 1));
});
// Set mtree-active class on list items for last opened element
$('.mtree li > *:first-child').on('click.mtree-active', function(e){
if($(this).parent().hasClass('mtree-closed')) {
$('.mtree-active').not($(this).parent()).removeClass('mtree-active');
$(this).parent().addClass('mtree-active');
} else if($(this).parent().hasClass('mtree-open')){
$(this).parent().removeClass('mtree-active');
} else {
$('.mtree-active').not($(this).parent()).removeClass('mtree-active');
$(this).parent().toggleClass('mtree-active');
}
});
// Set node click elements, preferably <a> but node links can be <span> also
node.children(':first-child').on('click.mtree', function(e){
// element vars
var el = $(this).parent().children('ul').first();
var isOpen = $(this).parent().hasClass('mtree-open');
// close other elements on same level if opening
if((close_same_level || $('.csl').hasClass('active')) && !isOpen) {
var close_items = $(this).closest('ul').children('.mtree-open').not($(this).parent()).children('ul');
// Velocity.js
if($.Velocity) {
close_items.velocity({
height: 0
}, {
duration: duration,
easing: easing,
display: 'none',
delay: 100,
complete: function(){
setNodeClass($(this).parent(), true)
}
});
// jQuery fallback
} else {
close_items.delay(100).slideToggle(duration, function(){
setNodeClass($(this).parent(), true);
});
}
}
// force auto height of element so actual height can be extracted
el.css({'height': 'auto'});
// listAnim: animate child elements when opening
if(!isOpen && $.Velocity && listAnim) el.find(' > li, li.mtree-open > ul > li').css({'opacity':0}).velocity('stop').velocity('list');
// Velocity.js animate element
if($.Velocity) {
el.velocity('stop').velocity({
//translateZ: 0, // optional hardware-acceleration is automatic on mobile
height: isOpen ? [0, el.outerHeight()] : [el.outerHeight(), 0]
},{
queue: false,
duration: duration,
easing: easing,
display: isOpen ? 'none' : 'block',
begin: setNodeClass($(this).parent(), isOpen),
complete: function(){
if(!isOpen) $(this).css('height', 'auto');
}
});
// jQuery fallback animate element
} else {
setNodeClass($(this).parent(), isOpen);
el.slideToggle(duration);
}
// We can't have nodes as links unfortunately
e.preventDefault();
});
// Function for updating node class
function setNodeClass(el, isOpen) {
if(isOpen) {
el.removeClass('mtree-open').addClass('mtree-closed');
} else {
el.removeClass('mtree-closed').addClass('mtree-open');
}
}
// List animation sequence
if($.Velocity && listAnim) {
$.Velocity.Sequences.list = function (element, options, index, size) {
$.Velocity.animate(element, {
opacity: [1,0],
translateY: [0, -(index+1)]
}, {
delay: index*(duration/size/2),
duration: duration,
easing: easing
});
};
}
// Fade in mtree after classes are added.
// Useful if you have set collapsed = true or applied styles that change the structure so the menu doesn't jump between states after the function executes.
if($('.mtree').css('opacity') == 0) {
if($.Velocity) {
$('.mtree').css('opacity', 1).children().css('opacity', 0).velocity('list');
} else {
$('.mtree').show(200);
}
}
}
}(jQuery, this, this.document));
I've added a background image using CSS and :before but the image is not clickable.
Is there a way to add it on the JS so that it can be clicked as well?
I've tried to see where to add some code but actually I'm clueless, should it be between lines 29 and 37?
You can see it in: https://tester.medicalfa.gr/test/katastima/
Ok I fixed it via css, the arrows now appears like they are clickable.
The solution is to remove the code I had added:
ul.mtree.default li.mtree-open:before {
display: inline-block;
margin-left: 200px;
background: url("../images/arrow-down.svg") no-repeat center center;
background-size: 20px 20px;
}
I removed the :before as it adds the arrow behind the text and now appears after the text as it's supposed to.
The code looks like this now:
ul.mtree.default li.mtree-open {
display: block ;
background: url("../images/arrow-down.svg") no-repeat center center;
background-size: 15px 15px;
background-position:top right;
}
Related
If you visit this code pen and click anywhere on the home page it cycles through three boxes. If you scroll down you will see the content changes too.
I want to underline the correct nav bar word depending on the box currently being displayed.
Box 2 is the default at page load, and then the nav-bar should have the underline class active on the id="home". Then you click and it moves to box 3, which should apply the underline class to id="blog".
It is using left values to cycle through the elements. How can I check which box is active just by looking at the left value?
$('.box').click(function() {
$('.box').each(function() {
if ($(this).offset().left < 0)
{
$(this).css("left", "150%");
}
else if ($(this).offset().left > $('#container').width())
{
$(this).animate({
left: '0%',
}, 500 );
}
else
{
$(this).animate({
left: '-150%',
}, 500 );
}
});
});
The class I want to apply
.underline-active {
border-bottom: 2px solid white;
}
to the corresponding nav-bar ID:
#box1 {
left: -150%;
}
#box2 {
}
#box3 {
left: 150%;
}
Also, is there a way to animate the underline sliding from one nav item to the next?
Your navbar elements might be a little too big since whenever I add the .underline-active class to the them it extends past the edge of the element (at the same time, this would probably make creating a css animation easier since they seem to be equidistant this way).
In any event, you can do this with another $().each() call. Just look for whichever element has offset.left == 0. JQuery provides plenty of methods to add/remove CSS classes to an item so from there it's simply figuring out which navbar element gets the .underline-active class which I did using a switch statement. Your new js should look like this:
$(document).ready(function() {
$('#home').addClass('underline-active');
$('.box').click(function() {
$('.box').each(function() {
if ($(this).offset().left < 0)
{
$(this).css("left", "150%");
}
else if ($(this).offset().left > $('#container').width())
{
$(this).animate({
left: '0%',
}, 500 );
}
else
{
$(this).animate({
left: '-150%',
}, 500 );
}
});
$('.nav-button').each(function() {
$(this).removeClass('underline-active');
});
$(".box").each(function() {
if ($(this).offset().left == 0) {
switch($(this).attr('id')) {
case 'box1':
$('#home').addClass('underline-active');
break;
case 'box2':
$('#blog').addClass('underline-active');
break;
case 'box3':
$('#about').addClass('underline-active');
break;
}
}
})
});
});
If you want to animate the movement of the underline then you should alter this process slightly to use transitions instead of removing/adding it from elements. I'd imagine you can use the same animation that scrolls the page to move the underline since the navbar elements seem to be a consistent distance apart.
I have a strange behaviour using a certain menu effect with Bootstrap carousel in the same page.
Basically, if I hover over the menu, Bootstrap carousel brakes, and give me the following error:
Chrome:
Cannot read property 'offsetWidth' of undefined
Firefox:
$next[0] is undefined
This is the Js Updated code i'm using for the effect:
var marker = $('#marker'),
current = $('.current');
// Initialize the marker position and the active class
current.addClass('active');
marker.css({
// Place the marker in the middle of the border
bottom: -(marker.height() / 2),
left: current.position().left,
width: current.outerWidth(),
display: "block"
});
if (Modernizr.csstransitions) {
console.log("using css3 transitions");
$('li.list').mouseover(function () {
var self = $(this),
offsetLeft = self.position().left,
// Use the element under the pointer OR the current page item
width = self.outerWidth() || current.outerWidth(),
// Ternary operator, because if using OR when offsetLeft is 0, it is considered a falsy value, thus causing a bug for the first element.
left = offsetLeft == 0 ? 0 : offsetLeft || current.position().left;
// Play with the active class
$('.active').removeClass('active');
self.addClass('active');
marker.css({
left: left,
width: width,
});
});
// When the mouse leaves the menu
$('ul.UlList').mouseleave(function () {
// remove all active classes, add active class to the current page item
$('.active').removeClass('active');
current.addClass('active');
// reset the marker to the current page item position and width
marker.css({
left: current.position().left,
width: current.outerWidth()
});
});
} else {
console.log("using jquery animate");
$('li.list').mouseover(function () {
var self = $(this),
offsetLeft = self.position().left,
// Use the element under the pointer OR the current page item
width = self.outerWidth() || current.outerWidth(),
// Ternary operator, because if using OR when offsetLeft is 0, it is considered a falsy value, thus causing a bug for the first element.
left = offsetLeft == 0 ? 0 : offsetLeft || current.position().left;
// Play with the active class
$('.active').removeClass('active');
self.addClass('active');
marker.stop().animate({
left: left,
width: width,
}, 300);
});
// When the mouse leaves the menu
$('ul.UlList').mouseleave(function () {
// remove all active classes, add active class to the current page item
$('.active').removeClass('active');
current.addClass('active');
// reset the marker to the current page item position and width
marker.stop().animate({
left: current.position().left,
width: current.outerWidth()
}, 300);
});
};
And here is a codepen that recreates the issue:
http://codepen.io/florinsimion/pen/AXaaOK
This is happening because $('li') will match all the li tags on your page, including the carousel ones. You need to select li tags of your menu:
$('ul > li').mouseover(....)
//^ add UL as parent for all your events
A better solution would be using a specific class for your menu:
current = $('.my-menu .current');
$('.my-menu li').mouseover(....);
$('ul.my-menu').mouseleave(....);
$('.my-menu .active').removeClass('active');
Don't forget your CSS, please take a look at this demo: http://codepen.io/anon/pen/AXaaap
<script language="javascript">
$(document).ready(function($) {
var methods = {
init: function(options) {
this.children(':first').stop();
this.marquee('play');
},
play: function() {
var marquee = this,
pixelsPerSecond = 100,
firstChild = this.children(':first'),
totalHeight = 0,
difference,
duration;
// Find the total height of the children by adding each child's height:
this.children().each(function(index, element) {
totalHeight += $(element).innerHeight();
});
// The distance the divs have to travel to reach -1 * totalHeight:
difference = totalHeight + parseInt(firstChild.css('margin-top'), 10);
// The duration of the animation needed to get the correct speed:
duration = (difference/pixelsPerSecond) * 1000;
// Animate the first child's margin-top to -1 * totalHeight:
firstChild.animate(
{ 'margin-top': -1 * totalHeight },
duration,
'linear',
function() {
// Move the first child back down (below the container):
firstChild.css('margin-top', marquee.innerHeight());
// Restart whole process... :)
marquee.marquee('play');
}
);
},
pause: function() {
this.children(':first').stop();
}
};
$.fn.marquee = function(method) {
// Method calling logic
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.marquee');
}
};
})(jQuery);
var marquee = $('#marquee');
marquee.marquee();
marquee.hover(function() {
marquee.marquee('pause');
}, function() {
marquee.marquee('play');
});
</script>
<style type="text/css">
#marquee {
margin:inherit;
width:auto;
height:inherit
}
</style>
I would like to create a scroller using jquery but I fail. The above code is the marquee I use to scroll up my items. And I am using it as below,
<html>
<body>
<div class="content">
<div id="marquee">
<ul>
<li>...</li>
....
</ul>
</div>
</div></body>
</html>
But it doesn't scroll at all, is there something incorrect in the code I am using you can find for me ?
Not sure if margin-top should work for this at all.
Try using position:relative for holder block(marquee) and position:absolute for content (ul). And update top instead of margin top. But in this case you may need to specify height and overflow:hidden for marquee div. Another options is to set height and oveflow:hidden for marquee, but leave position default. And scroll content using scrollTop or with some similar jquery functions.
_createInput: function(){
var self = this;
var input = document.createElement("input");
input.setAttribute('type', 'file');
input.setAttribute('name', this._settings.name);
if(this._settings.multiple) input.setAttribute('multiple', 'multiple');
addStyles(input, {
'position' : 'absolute',
// in Opera only 'browse' button
// is clickable and it is located at
// the right side of the input
'right' : 0,
'margin' : 0,
'padding' : 0,
'fontSize' : '480px',
// in Firefox if font-family is set to
// 'inherit' the input doesn't work
'fontFamily' : 'sans-serif',
'cursor' : 'pointer'
});
var div = document.createElement("div")
div.className = 'tooltip';
div.id = 'ajaxupload-div';
div.title = 'Attach a picture';
addStyles(div, {
'display' : 'block',
'position' : 'absolute',
'overflow' : 'hidden',
'margin' : 0,
'padding' : 0,
'opacity' : 0,
// Make sure browse button is in the right side
// in Internet Explorer
'direction' : 'ltr',
//Max zIndex supported by Opera 9.0-9.2
'zIndex': 2147483583
});
// Make sure that element opacity exists.
// Otherwise use IE filter
if ( div.style.opacity !== "0") {
if (typeof(div.filters) == 'undefined'){
throw new Error('Opacity not supported by the browser');
}
div.style.filter = "alpha(opacity=0)";
}
addEvent(input, 'change', function(){
if ( ! input || input.value === ''){
return;
}
// Get filename from input, required
// as some browsers have path instead of it
var file = fileFromPath(input.value);
if (false === self._settings.onChange.call(self, file, getExt(file))){
self._clearInput();
return;
}
// Submit form when value is changed
if (self._settings.autoSubmit) {
self.submit();
}
});
addEvent(input, 'mouseover', function(){
addClass(self._button, self._settings.hoverClass);
});
addEvent(input, 'mouseout', function(){
removeClass(self._button, self._settings.hoverClass);
removeClass(self._button, self._settings.focusClass);
if (input.parentNode) {
// We use visibility instead of display to fix problem with Safari 4
// The problem is that the value of input doesn't change if it
// has display none when user selects a file
input.parentNode.style.visibility = 'hidden';
}
});
addEvent(input, 'focus', function(){
addClass(self._button, self._settings.focusClass);
});
addEvent(input, 'blur', function(){
removeClass(self._button, self._settings.focusClass);
});
div.appendChild(input);
document.body.appendChild(div);
this._input = input;
},
This JS starting at var div = document.createElement("div") produces this div tag:
<div style="display: block; position: absolute; overflow: hidden; margin: 0pt; padding: 0pt; opacity: 0; direction: ltr; z-index: 2147483583; left: 102px; top: 323.5px; width: 102px; height: 28px; visibility: hidden;">
I see where all the other attributes get changed, but how the heck can I change 'visibility: hidden;" ???
It's making me crazy please help.
Find the below section in your code i have star commented where you can modify:
addStyles(div, {
'display' : 'block', /*You cane set display none here to hide the div.*/
'position' : 'absolute',
'overflow' : 'hidden',
'margin' : 0,
'padding' : 0,
'opacity' : 0,
// Make sure browse button is in the right side
// in Internet Explorer
'direction' : 'ltr',
//Max zIndex supported by Opera 9.0-9.2
'zIndex': 2147483583,
'visibility':'hidden' /* If you don't set display none , you can set your style attribute you want to change like visibility here also */
});
Ok, to make it visible find the below code and try setting visibility there:
if (input.parentNode) {
// We use visibility instead of display to fix problem with Safari 4
// The problem is that the value of input doesn't change if it
// has display none when user selects a file
input.parentNode.style.visibility = 'hidden'; /* try setting visibility='visible' here */
}
If that doesn't work then check if any css is overriding the style property of the div by inspecting the div in your browser.
if jQuery is an option, I know there's the command $('#div').css('attribute','value');
visibility hidden is set when you "mouseout" off that input
addEvent(input, 'mouseout', function(){
removeClass(self._button, self._settings.hoverClass);
removeClass(self._button, self._settings.focusClass);
if (input.parentNode) {
// We use visibility instead of display to fix problem with Safari 4
// The problem is that the value of input doesn't change if it
// has display none when user selects a file
input.parentNode.style.visibility = 'hidden';
}
});
you can either remove that event binding or change the statement to input.parentNode.style.visibility = 'visible';
This is the first time I visited stack overflow and I saw a beautiful header message which displays a text and a close button.
The header bar is fixed one and is great to get the attention of the visitor. I was wondering if anyone of you guys know the code to get the same kind of header bar.
Quick pure JavaScript implementation:
function MessageBar() {
// CSS styling:
var css = function(el,s) {
for (var i in s) {
el.style[i] = s[i];
}
return el;
},
// Create the element:
bar = css(document.createElement('div'), {
top: 0,
left: 0,
position: 'fixed',
background: 'orange',
width: '100%',
padding: '10px',
textAlign: 'center'
});
// Inject it:
document.body.appendChild(bar);
// Provide a way to set the message:
this.setMessage = function(message) {
// Clear contents:
while(bar.firstChild) {
bar.removeChild(bar.firstChild);
}
// Append new message:
bar.appendChild(document.createTextNode(message));
};
// Provide a way to toggle visibility:
this.toggleVisibility = function() {
bar.style.display = bar.style.display === 'none' ? 'block' : 'none';
};
}
How to use it:
var myMessageBar = new MessageBar();
myMessageBar.setMessage('hello');
// Toggling visibility is simple:
myMessageBar.toggleVisibility();
Update:
Check out the DEMO
Code Used:
$(function(){
$('#smsg_link').click(function(){
showMessage('#9BED87', 'black', 'This is sample success message');
return false;
});
$('#imsg_link').click(function(){
showMessage('#FFE16B', 'black', 'This is sample info message');
return false;
});
$('#emsg_link').click(function(){
showMessage('#ED869B', 'black', 'This is sample error message');
return false;
});
});
/*
showMessage function by Sarfraz:
-------------------------
Shows fancy message on top of the window
params:
- bgcolor: The background color for the message box
- color: The text color of the message box
- msg: The message text
*/
var interval = null;
function showMessage(bgcolor, color, msg)
{
$('#smsg').remove();
clearInterval(interval);
if (!$('#smsg').is(':visible'))
{
if (!$('#smsg').length)
{
$('<div id="smsg">'+msg+'</div>').appendTo($('body')).css({
position:'fixed',
top:0,
left:0,
width:'98%',
height:'30px',
lineHeight:'30px',
background:bgcolor,
color:color,
zIndex:1000,
padding:'10px',
fontWeight:'bold',
fontSize:'18px',
textAlign:'center',
opacity:0.8,
margin:'auto',
display:'none'
}).slideDown('show');
interval = setTimeout(function(){
$('#smsg').animate({'width':'hide'}, function(){
$('#smsg').remove();
});
}, 3000);
}
}
}
If you want to create your own, check out the slideToggle function of jQuery.
The relevant css would include:
position: fixed;
top: 0;
width: 100%;
More information about position:fixed:
An element with position: fixed is positioned at the specified coordinates relative to the browser window. The element's position is specified with the "left", "top", "right", and "bottom" properties. The element remains at that position regardless of scrolling. Works in IE7 (strict mode)
If IE6 support is important to you, you may wish to research workarounds.
Here is an alternative method using jQuery which would also slide up/down on show/hide.
Add the following HTML right after the <body> tag in your page:
<div id="msgBox">
<span id="msgText">My Message</span>
<a id="msgCloseButton" href='#'>close</a>
</div>
Add this CSS to your stylesheet
#msgBox {
padding:10px;
background-color:Orange;
text-align:center;
display:none;
font:bold 1.4em Verdana;
}
#msgCloseButton{
float:right;
}
And finally here is the javascript to setup the close button and functions to show and hide the message bar:
/* Document Ready */
$(function () {
SetupNotifications();
});
SetupNotifications = function () {
//setup close button in msgBox
$("#msgCloseButton").click(function (e) {
e.preventDefault();
CloseMsg();
});
}
DisplayMsg = function (sMsg) {
//set the message text
$("#msgText").text(sMsg);
//show the message
$('#msgBox').slideDown();
}
CloseMsg = function () {
//hide the message
$('#msgBox').slideUp();
//clear msg text
$("#msgtText").val("");
}
To perform a simple test you could try this:
Show Message!
Something like this?
$("#bar").slideUp();
However, here I think they fade out first the bar then they bring the main container up, so that'd be something like that:
$("#bar").fadeOut(function(){
$("#container").animate({"top":"0px"});
});