Change jQuery code to JavaScript - javascript

I have jquery function to control page menu elements with dynamic screen size. But this code requires jquery lib's. But this effecting my loading performance.
I can't use async loading attribute for jquery because this function requires this library. But if I could change to pure JavaScript then loading performance will be high. (Progressive Web Apps)
But when I really struggling with this conversions. Anyone knows how to convert to pure JavaScript?
function calcWidth() {
var navwidth = 0;
var morewidth = $('#main .more').outerWidth(true);
$('#main > li:not(.more)').each(function() {
navwidth += $(this).outerWidth( true );
});
var availablespace = $('nav').outerWidth(true) - morewidth;
if (navwidth > availablespace) {
var lastItem = $('#main > li:not(.more)').last();
lastItem.attr('data-width', lastItem.outerWidth(true));
lastItem.prependTo($('#main .more ul'));
calcWidth();
} else {
var firstMoreElement = $('#main li.more li').first();
if (navwidth + firstMoreElement.data('width') < availablespace) {
firstMoreElement.insertBefore($('#main .more'));
}
}
if ($('.more li').length > 0) {
$('.more').css('display','inline-block');
} else {
$('.more').css('display','none');
}
}
$(window).on('resize load',function(){
calcWidth();
});

Try this:
function calcWidth() {
var navwidth = 0;
var morewidth = document.querySelectorAll('#main .more')[0].width;
document.querySelectorAll('#main > li:not(.more)').forEach(function(item,index) {
navwidth += item.width;
});
var availablespace = document.querySelectorAll('nav')[0].width - morewidth;
if (navwidth > availablespace) {
var arr = document.querySelectorAll('#main > li:not(.more)');
var lastItem = arr[arr.length-1];
lastItem.setAttribute('data-width', lastItem.width);
document.querySelectorAll('#main .more ul')[0].appendChild(lastItem);
lastItem.parentNode.removeChild(lastItem);
calcWidth();
} else {
var firstMoreElement = document.querySelectorAll('#main li.more li')[0];
if (navwidth + firstMoreElement.width < availablespace) {
firstMoreElement.parentnode.insertBefore(firstMoreElement,document.querySelectorAll('#main .more')[0]);
firstMoreElement.parentNode.removeChild(firstMoreElement);
}
}
if (document.querySelectorAll('.more li').length > 0) {
document.querySelectorAll('.more').forEach(function(item,index){item.style.display='inline-block';});
} else {document.querySelectorAll('.more').forEach(function(item,index){item.style.display='none';});
}
}
window.onload=calcWidth;
window.onresize=calcWidth;
Answer if worked :)

Related

Clone and fix banner with jQuery/ES5

I have to improve my code, especially looking for performance (in this project I can use jQuery and ES5).
What I want to achieve is that I have to mark the banner (injected from the external website) and when the banner hides after scrolling, then a smaller version will flow smoothly, and when the window reaches its top, it will be fixed to the top.
What I managed to do is that jsFiddle:
var bannerDA = $('div[class*="-a--katalog"]');
var bannerClone = $();
var clone = $();
var CLONE_HEIGHT = 100;
var bannerDABottom = bannerDA.offset().top + 200; // bannerDA.height() not working for iframe ??
$(document).ready(function() {
if (bannerDA.length !== 0) {
$(window).on('scroll', function() {
if ($(window).scrollTop() > bannerDABottom && bannerClone.length == 0) {
bannerClone = bannerDA.clone()
// avoid paragraphs and insert before first div:
.insertBefore('.subcontent-body div:eq(0)')
.addClass('clone')
.animate({height: CLONE_HEIGHT}, 500);
} else if ($(window).scrollTop() <= bannerDABottom && bannerClone.length > 0) {
bannerClone.animate({height: '0'}, 200, function() {
bannerClone.remove();
bannerClone = $();
});
} else if ($(window).scrollTop() > bannerClone.offset().top && clone.length == 0) {
clone = bannerClone.clone()
.css('opacity', '1')
.css('height', CLONE_HEIGHT)
.appendTo('.subcontent-body')
.addClass('clone--fixed');
} else if ($(window).scrollTop() <= bannerClone.offset().top && clone.length > 0) {
clone.remove();
clone = $();
}
}).trigger('scroll');
}
});
How I can refactor it?
/edited:
Is it a good practice to create an empty jQuery object when declaring variables? // I'm doing this to be able to check if the object exists (length).
Maybe it would be better to clone a banner once and then just show it and hide it, instead of processing everything on scrolls?
Should I clone a banner twice? Maybe there should be one copy, static or fixed depending on the scrollTop. How can you prevent the page from jumping?
After many attempts I managed to write a similarly working code but it does not work in 100% as I want and I have no idea if it is more effective:
jsFiddle. Should I provide more information? I am waiting for your help.
With help from friend this is solution:
$(document).ready(function() {
var bannerDA = $('div[class*="-a--katalog"]');
var bannerClone = $();
var clone = $();
var CLONE_HEIGHT = 100;
if (bannerDA.length !== 0) {
const bannerDABottom = bannerDA.offset().top + 200; // bannerDA.height() not working for iframe ??
$(window).on('scroll', function() {
const scrollTop = $(window).scrollTop();
if (scrollTop > bannerDABottom && bannerClone.length === 0) {
bannerClone = bannerDA.clone()
// avoid paragraphs and insert before first div:
.insertBefore('.subcontent-body div:eq(0)')
.addClass('clone')
.animate({
height: CLONE_HEIGHT
}, 500);
return;
}
if (scrollTop <= bannerDABottom && bannerClone.length > 0) {
bannerClone.animate({
height: '0'
}, 200, function() {
bannerClone.remove();
bannerClone = $();
});
return;
}
if (scrollTop > bannerClone.offset().top && clone.length === 0) {
clone = bannerClone.clone()
.css('opacity', '1')
.css('height', CLONE_HEIGHT)
.appendTo('.subcontent-body')
.addClass('clone--fixed');
return;
}
if (scrollTop <= bannerClone.offset().top && clone.length > 0) {
clone.remove();
clone = $();
return;
}
}).trigger('scroll');
}
});
jsFiddle

How to select between a list css classes

I have a div with a next and previous button
<div class="b1"></div>
<input type="button" class="btnP" value="Prev"/>
<input type="button" class="btnN" value="Next"/>
and a list of css classes
.b1 { background-color:#fff;}
.b2 { background-color:#000;}
.b3 { background-color:#123;}
.b4 { background-color:#444;}
.b5 { background-color:#bbb;}
which i want to use for that div when the user press the next or previous button by that numbering order.
This is what i did so far:
http://jsfiddle.net/51dq5num/
var size_ini = 1;
$(".btnN").click(function () {
var size_increase = size_ini++;
var size_increase1 = size_ini;
$("#content").html("<span>" + size_increase + "</span>").removeClass().addClass("b" + size_increase);
if (size_increase > 4) {
size_ini = 1;
}
});
I manage to get the next button working but i'm not sure how to do it for the previous button
Is there a better way to do this rather then adding and removing css classes from the div?
Try this :
$(".btnP").click(function () {
var size_increase = $("#content").attr("class").substring(2, 1);
size_increase--;
if (size_increase < 1) {
size_increase = 5;
}
$("#content").html("<span>" + size_increase + "</span>").removeClass().addClass("b" + size_increase);
});
jsFiddle : http://jsfiddle.net/51dq5num/7/
You can do something like this:
var newClass = function(div, next) {
div[0].className = div[0].className.replace(/b\d+/, "b" + newClass[next ? 'next' : 'prev']());
};
newClass.atual = 1;
newClass.last = 5;
newClass.next = function(){
this.atual = (this.atual == this.last ? 1 : this.atual + 1);
return this.atual;
};
newClass.prev = function(){
this.atual = (this.atual == 1 ? this.last : this.atual - 1);
return this.atual;
};
var myDiv = $("#content");
$(".btnN").click(function () {
newClass(myDiv, true);
});
$(".btnP").click(function () {
newClass(myDiv, false);
});
Jsfiddle here.
This is a combined solution for both buttons.
var size_ini = 0;
$("input[type='button']").click(function () {
if($(this).hasClass("btnN"))
{
size_ini=size_ini+1;
var c="b"+size_ini;
$("#content").removeClass().addClass(c).html("TG"+size_ini);
}
else
{
size_ini=size_ini-1;
var c="b"+size_ini;
$("#content").removeClass().addClass(c).html("TG"+size_ini);
}
});
Note as it is not mentioned i have not checked on the max condition thus btnP can increase the counter infinitely.You can put it in a condn and limit it to a max value.
http://jsfiddle.net/n8dLgh3L/1/
Here is js code to increase and decrease.
var size_ini = 0;
$(".btnN").click(function () {
if (size_ini > 4) {
size_ini = 1;
} else {
size_ini++
}
$("#content").html("<span>" + size_ini + "</span>").removeClass().addClass("b" + size_ini);
});
$(".btnP").click(function () {
var size_decrease = $("#content").attr("class").substring(1, 2);
if (size_decrease <= 1) {
size_decrease = 5;
} else {
size_decrease--;
}
$("#content").html("<span>" + size_decrease + "</span>").removeClass().addClass("b" + size_decrease);
});
You ca achieve this with the help of .substr() for incrementing the number of class. Have a look.
function Getnumber(classNumber,nav)
{
var no=0;
if(nav=="P")
{
no=parseInt(classNumber.substr(1,2))-1;
}
else
{
no=parseInt(classNumber.substr(1,2))+1;
}
return no;
}
$(".btnN").on("click",function(){
var oldClass=$('div').attr("class");
var num=Getnumber(oldClass,"N");
if(num<6)
$('div').addClass("b"+num).removeClass(oldClass);
});
$(".btnP").on("click",function(){
var oldClass=$('div').attr("class");
var num=Getnumber(oldClass,"P");
if(num>0)
$('div').addClass("b"+num).removeClass(oldClass);
});
Feel free to ask.

Auto Increment width of an input tag

I am trying to code an counter.
Here is my JsFiddle
$('.substract-value').click(function(){
val = $('#how-many').val();
if (val == 1)
{ }
else
$('#how-many').val(val-1);
});
$('.add-value').click(function(){
val = $('#how-many').val();
$('#how-many').val(parseInt(val)+1);
});
I want the size of the input tag to auto-increment when the content inside the input tag will become 2digit or 3digit.
is it possible only with css.
I think the best solution in this case would be not to use input tag, instead replace it with span tag. span is an inline element and the width will auto increment based on its content.
As i am moving to span, the jquery will change. and instead of val() we should use text()
Demo fiddle http://jsfiddle.net/ssxx8/11/
You can do something roughly similar to this:
$(function() {
var $howMany = $('#how-many'); // cache that
$('.substract-value').click(function(){
var val = $howMany.val();
if (val == 1) { }
else {
$howMany.val(val-1);
checkSize(val);
}
});
$('.add-value').click(function(){
var val = $('#how-many').val();
$howMany.val(parseInt(val)+1);
checkSize(val);
});
function checkSize(v) {
if ( v > 9 ) {
$howMany.css('width', '80px');
} else if ( v < 9 ) {
$howMany.css('width', '20px');
};
}
});
Try this
$('.substract-value').click(function(){
val = $('#how-many').val();
if (val == 1) { }
else
$('#how-many').val(val-1);
setWidth();
});
$('.add-value').click(function(){
val = $('#how-many').val();
$('#how-many').val(parseInt(val)+1);
setWidth();
});
var oneLetterWidth = 10;
var minCharacters = 2;
function setWidth() {
var len = $("#how-many").val().length;
if (len > minCharacters) {
// increase width
$("#how-many").width(len * oneLetterWidth);
} else {
// restore minimal width;
$("#how-many").width(50);
}
}
DEMO
Try this
$('.substract-value').click(function(){
val = $('#how-many').val();
if (val == 1) { }
else
$('#how-many').val(val-1);
updateWidth();
});
$('.add-value').click(function(){
val = $('#how-many').val();
$('#how-many').val(parseInt(val)+1);
updateWidth();
});
function updateWidth(){
size = $('#how-many').val().length;
size = size*7; // average width of a char is 7px
$('#how-many').css('width',size);
}
JSFIDDLE : http://jsfiddle.net/ssxx8/9/
You need to approach this way:
var obj = $('#how-many');
$('.substract-value').click(function () {
var content = obj.val();
if (content > 1)
obj.val(parseInt(obj.val()) - 1);
obj.css("width", (obj.val().length * 10) + "px");
});
$('.add-value').click(function () {
obj.val(parseInt(obj.val()) + 1);
obj.css("width", (obj.val().length * 10) + "px");
});
Refer LIVE DEMO

get interval ID from else statement when set in IF

I am attempting to create a responsive slider, that will change to a simple set of dot points when in mobile mode (< 940).
The issue I am facing is in my else statement I am unable to clearintervals that were made in the if statement, because t comes up as undefined. I have resorted to using
for (var i = 1; i < 99999; i++) window.clearInterval(i); to clear the interval which works, but I don't like it because it's ugly and cumbersome, is there another way of accomplishing this?
$(document).ready(function() {
function rePosition() {
//get responsive width
var container_width = $('.container').width();
//Slider for desktops only
if(container_width >= 940) {
//get variables
var slide_width = $('.slider_container').width();
var number_of_slides = $('.slider_container .slide').length;
var slider_width = slide_width*number_of_slides;
//set element dimensions
$('.slide').width(slide_width);
$('.slider').width(slider_width);
var n = 1;
var t = 0;
$('.slider_container').hover(function() {
clearInterval(t);
}, function() {
t = setInterval(sliderLoop,6000);
});
var marginSize = i = 1;
//Called in Doc Load
function sliderLoop(trans_speed) {
if (trans_speed) {
var trans_speed = trans_speed;
}
else
{
var trans_speed = 3000;
}
if (i < number_of_slides) {
marginSize = -(slide_width * i++);
}
else
{
marginSize = i = 1;
}
$('.slider').animate({ marginLeft: marginSize }, trans_speed);
}
t = setInterval(sliderLoop,6000);
$('.items li').hover(function() {
$('.slider').stop();
clearInterval(t);
var item_numb = $(this).index();
i = item_numb;
sliderLoop(500);
}, function() {
t = setInterval(sliderLoop,6000);
});
}
else
{
for (var i = 1; i < 99999; i++)
window.clearInterval(i);
$('.slider').stop(true, true);
$('.slider').css('margin-left', '0px');
//rearrange content
if($('.slider .slide .slide_title').length < 1) {
$('.items ul li').each(function() {
var item_numb = $(this).index();
var content = $(this).text();
$('.slider .slide:eq(' + item_numb + ')').prepend('<div class="title slide_title">' + content + '</div>')
});
}
}
}
rePosition();
$(window).resize(function() {
rePosition();
});
});
Teemu's comment is correct. I'll expand on it. Make an array available to all of the relevant code (just remember that globals are bad).
$(document).ready(function() {
var myIntervalArray = [];
Now, whenever you create an interval you will need to reference later, do this:
var t = setInterval();//etc
myIntervalArray.push(t); //or just put the interval directly in.
Then to clear them, just loop the array and clear each interval.
for (var i=0; i<myIntervalArray.length; i++)
clearInterval(myIntervalArray[i]);
}
Umm, wouldn't t only be defined when the if part ran... as far as I can tell, this is going to run and be done... the scope will be destroyed. If you need to maintain the scope across calls, you'll need to move your var statements outside of reposition(), like so:
$(document).ready(function() {
var t = 0;
...
function rePosition() { ... }
});

JQuery: Fade In Only Specific Element (IE and Opera)

I'm facing a bit of a jQuery conundrum, and I'd appreciate someone helping me to solve it.
I want to fade in a web page, using jQuery, after all the text and images have loaded. So I set body style inline as "display:none" and then fade in the body using this basic snippet:
<script type="text/javascript">
$(window).load(function() {
$('body').fadeIn(300);
});
</script>
This achieves exactly what I want in Firefox, Safari and Chrome. However, Internet Explorer and Opera present a challenge: when the body fades in, all the elements of the JQuery gallery, included in the page, appear simultaneously, instead of rotating, as they do in "normal" browsers.
I'm posting the entire gallery script here:
/* Gallery */
jQuery.fn.gallery = function(_options){
// defaults options
var _options = jQuery.extend({
duration: 600,
autoSlide: false,
slideElement: 1,
effect: false,
fadeEl: 'ul',
switcher: 'ul > li',
disableBtn: false,
next: 'a.link-next, a.btn-next, a.next',
prev: 'a.link-prev, a.btn-prev, a.prev',
circle: true
},_options);
return this.each(function(){
var _hold = $(this);
if (!_options.effect) var _speed = _options.duration;
else var _speed = $.browser.msie ? 0 : _options.duration;
var _timer = _options.autoSlide;
var _sliderEl = _options.slideElement;
var _wrap = _hold.find(_options.fadeEl);
var _el = _hold.find(_options.switcher);
var _next = _hold.find(_options.next);
var _prev = _hold.find(_options.prev);
var _count = _el.index(_el.filter(':last'));
var _w = _el.outerWidth(true);
var _wrapHolderW = Math.ceil(_wrap.parent().width()/_w);
if (((_wrapHolderW-1)*_w + _w/2) > _wrap.parent().width()) _wrapHolderW--;
if (_timer) var _t;
var _active = _el.index(_el.filter('.active:eq(0)'));
if (_active < 0) _active = 0;
var _last = _active;
if (!_options.effect) var rew = _count - _wrapHolderW + 1;
else var rew = _count;
if (!_options.effect) _wrap.css({marginLeft: -(_w * _active)});
else {
_wrap.css({opacity: 0}).removeClass('active').eq(_active).addClass('active').css({opacity: 1}).css('opacity', 'auto');
_el.removeClass('active').eq(_active).addClass('active');
}
if (_options.disableBtn) {
if (_count < _wrapHolderW) _next.addClass(_options.disableBtn);
_prev.addClass(_options.disableBtn);
}
function fadeElement(){
_wrap.eq(_last).animate({opacity:0}, {queue:false, duration: _speed});
_wrap.removeClass('active').eq(_active).addClass('active').animate({
opacity:1
}, {queue:false, duration: _speed, complete: function(){
$(this).css('opacity','auto');
}});
_el.removeClass('active').eq(_active).addClass('active');
_last = _active;
}
function scrollEl(){
_wrap.animate({marginLeft: -(_w * _active)}, {queue:false, duration: _speed});
}
function toPrepare(){
if ((_active == rew) && _options.circle) _active = -_sliderEl;
for (var i = 0; i < _sliderEl; i++){
_active++;
if (_active > rew) {
_active--;
if (_options.disableBtn &&(_count > _wrapHolderW)) _next.addClass(_options.disableBtn);
}
};
if (_active == rew) if (_options.disableBtn &&(_count > _wrapHolderW)) _next.addClass(_options.disableBtn);
if (!_options.effect) scrollEl();
else fadeElement();
}
function runTimer(){
_t = setInterval(function(){
toPrepare();
}, _timer);
}
_next.click(function(){
if(_t) clearTimeout(_t);
if (_options.disableBtn &&(_count > _wrapHolderW)) _prev.removeClass(_options.disableBtn);
toPrepare();
return false;
});
_prev.click(function(){
if(_t) clearTimeout(_t);
if (_options.disableBtn &&(_count > _wrapHolderW)) _next.removeClass(_options.disableBtn);
if ((_active == 0) && _options.circle) _active = rew + _sliderEl;
for (var i = 0; i < _sliderEl; i++){
_active--;
if (_active < 0) {
_active++;
if (_options.disableBtn &&(_count > _wrapHolderW)) _prev.addClass(_options.disableBtn);
}
};
if (_active == 0) if (_options.disableBtn &&(_count > _wrapHolderW)) _prev.addClass(_options.disableBtn);
if (!_options.effect) scrollEl();
else fadeElement();
return false;
});
if (_options.effect) _el.click(function(){
_active = _el.index($(this));
if(_t) clearTimeout(_t);
fadeElement();
return false;
});
if (_timer) runTimer();
});
}
$(document).ready(function(){
$('div#gallery').gallery({
duration: 2000,
effect: 'fade',
fadeEl: 'ul.gall-inner > li',
next: 'a#next-btn',
prev: 'a#prev-btn',
autoSlide: 6000,
switcher: '.brands-list ul > li'
});
});
Could some knowledgeable person please help me to find a solution or a workaround? I'd be truly grateful!

Categories

Resources