jQuery: Having trouble with not and multiple selectors for CSS - javascript

I've got a number of divs (CSS class 'group'), and when one is clicked in, the others are hidden and the clicked on one is expanded (gaining the 'detailed' CSS class). Then, when the expanded div ('.group .detailed) is clicked on, it should resize and lose the 'detailed' class. My problem is, I can't get click events on 'group' divs that also contain 'detailed' to be ignored by my first jquery function and activate my second jquery function. Here's my code:
$('.group:not(.detailed)').mousedown(function(){
var $self = $(this);
var speed = 3250;
var offset = {x : $self.offset().left, y : $self.offset().top};
readyAnimation();
$('.group').not($self).addClass('hide');
$self.animate({'width' : '100%', 'height' : '+=' + '300px'}, {left: 'offset.x' + 'px', top: 'offset.y' + 'px'}, speed);
function readyAnimation () {
$self.css({display : 'block'});
$self.css({'-webkit-box-sizing' : 'border-box', '-moz-box-sizing' : 'border-box', 'box-sizing' : 'border-box'});
$self.css({margin : '0px'});
};
$self.addClass('detailed');
});
$('.group.detailed').mousedown(function(){
var $self = $(this);
var size = '300px';
var speed = 3250;
console.log("it worked");
resetAnimation();
$self.animate({'width' : size, 'height' : size}, speed)
$('.group').removeClass('hide');
function resetAnimation () {
$self.css({display : ''}); //Empty quotes resets the CSS value to what it was originally (in the CSS file)
$self.css({'-webkit-box-sizing' : '', '-moz-box-sizing' : '', 'box-sizing' : ''});
$self.css({margin : ''});
};
$self.removeClass('detailed');
});
I don't think I need to post my HTML and CSS for this, but they can be seen here in a previous question I asked. Thanks for reading.
EDIT: Here's a link to the fiddle
EDIT 2: See vahapwns, Jonathan and giordanolima's answers for working demonstrations of the code. By combining the two functions togother and using an if statement checking for 'detailed', problems arising from the first function overriding the second are solved. Thanks everybody for your input.

take your two jQuery selections and merge them into one, use an if() to check if it's .detailed or not. you should also move those extra functions outside so that they're only defined once each.
i have rearranged the logic for you, now you need to fine tune the animation sequence: http://jsfiddle.net/V93dq/2/

#vahanpwns is correct, try this one:
http://jsfiddle.net/V93dq/1/
Basically you can use the hasClass jQuery method.
$('.group').mousedown(function(){
var $self = $(this);
if($self.hasClass("detailed")){
}else{
}
});

Take a look here...
I used the condition hassClass... I think was better... And i prevent the link Default...
Finddle
function readyAnimation (mySelf) {
mySelf.css({display : 'block'});
mySelf.css({'-webkit-box-sizing' : 'border-box', '-moz-box-sizing' : 'border-box', 'box-sizing' : 'border-box'});
mySelf.css({margin : '0px'});
};
function resetAnimation (mySelf) {
mySelf.css({display : ''});
mySelf.css({'-webkit-box-sizing' : '', '-moz-box-sizing' : '', 'box-sizing' : ''});
mySelf.css({margin : ''});
};
$('.group').mousedown(function(){
if(!$(this).hasClass("detailed")){
var $self = $(this);
var speed = 3250;
var offset = {x : $self.offset().left, y : $self.offset().top};
readyAnimation($self);
$('.group').not($self).addClass('hide');
$self.animate({'width' : '100%', 'height' : '+=' + '300px'}, {left: 'offset.x' + 'px', top: 'offset.y' + 'px'}, speed);
$self.addClass('detailed');
}else{
var $self = $(this);
var size = '300px';
var speed = 3250;
resetAnimation($self);
$self.animate({'width' : size, 'height' : size}, speed)
$('.group').removeClass('hide');
$self.removeClass('detailed');
}
}).find('a').click(function(e){e.preventDefault();});;

Related

Change javascript function

I have a function in theme.js file
$('.open_copy').click(function(){
var that = $(this);
var copy = that.prev();
that.parents('.asset').find('.cover').click();
copy.css('opacity', 0).show();
if (copy.children('.copy_content').data('jsp')) {
copy.children('.copy_content').data('jsp').destroy();
}
var height = copy.children('.copy_content').css({height: ''}).height();
if (height < that.parents('.asset').height() - 37) {
var top = (that.parents('.asset').height() - height)/2;
top = top < 37 ? 37 : top;
copy.children('.copy_content').css({'margin-top': top});
} else {
copy.children('.copy_content').css({'margin-top': '', height: that.parents('.asset').height() - 37}).jScrollPane();
}
if (!that.parents('.asset').find('.close_copy').length) {
that.prev().append('Close');
}
copy.animate({ 'opacity' : 1 }, 500);
that.fadeOut(500);
return false;
});
I need to change opacity value to 0.9 but i don't have access to the theme.js file. There is any way i can change/alter this function by adding a function in the html page?
copy.animate({ 'opacity' : 1 }, 500);
Yes. You can remove the click handler that code sets up, and then add your own with identical code except for the 1 => 0.9 change.
To remove that code's click handler (and all others), use off:
$('.open_copy').off('click');
...and then of course add your own, new click handler.
So in total, then, you'd want this code (after the script tag including theme.js, so this code runs after that code):
$('.open_copy').off('click').click(function(){ // <== Changed
var that = $(this);
var copy = that.prev();
that.parents('.asset').find('.cover').click();
copy.css('opacity', 0).show();
if (copy.children('.copy_content').data('jsp')) {
copy.children('.copy_content').data('jsp').destroy();
}
var height = copy.children('.copy_content').css({height: ''}).height();
if (height < that.parents('.asset').height() - 37) {
var top = (that.parents('.asset').height() - height)/2;
top = top < 37 ? 37 : top;
copy.children('.copy_content').css({'margin-top': top});
} else {
copy.children('.copy_content').css({'margin-top': '', height: that.parents('.asset').height() - 37}).jScrollPane();
}
if (!that.parents('.asset').find('.close_copy').length) {
that.prev().append('Close');
}
copy.animate({ 'opacity' : 0.9 }, 500); // <== Changed
that.fadeOut(500);
return false;
});
You'll want to check for side effects (for instance, if there's other code that also sets up click handlers on those elements, since the code above will remove them, too).
Javascript support override of variables and methods.
You should declare an overriding JS script AFTER import of Theme.js file.
So, you can exactly copy/paste that function changing only the values you need to.
Note that, as that function is an event binding, you may need to unbind the onclick event first.

cannot call method replace on undefined script issues

What I am trying to do below since I don't have access to the PHP to my site, I am using this code to work around it. It will search for any links containing the two listed below. one from youtube with the /watch? in it and the other from youtube with just the /v in the url. It also is searching the any embedded elements. Problem is when I run the script it breaks all the other codes because of the error.
Uncaught TypeError: Cannot call method 'replace' of undefined
Which is a pain in the butt! So I took it over to FF, says variable WT is not defined clearly it is though. Well it may not be since I used it outside the scope of the if statement. I'm not sure how to ensure if the link exist run the code. As well as if the Embed exist run the code too. These will be in my users post and want them automatically changed to work with my fancybox.
Here is a live example
Its the copied markup from my page with a quick linked CSS so don't mind the buggy look.
$(function() {
//if link contains /watch?
var t = $('.entry-content div div a[href*="youtube.com/watch?"]').attr('href');
if(typeof t !== "undefined") {
//do nothing don't run the script below
} else {
var d = $('.entry-content div div a[href*="youtube.com/watch?"]');
var newsrc = t.replace('watch?','');
var asrc = newsrc.replace('=','/');
var g = asrc.replace('http://www.','http://img.');
var s = g.replace('v','vi');
d.attr('class','ez_video');
d.attr('href', asrc).html('<img src="'+ s +'/0.jpg"/>');
}
//if link contains /v
var wt = $('.entry-content div div a[href*="youtube.com/v"]').attr('href');
if(typeof wt !== "undefined") {
//do nothing don't run script below
} else {
var wd = $('.entry-content div div a[href*="youtube.com/v"]');
var o = wt.replace('http://www.','http://img.');
var v = o.replace('v','vi');
wd.attr('class','ez_video');
wd.attr('href', v).html('<img src="'+ v +'/0.jpg"/>');
}
//if embeded file
var src = $('.entry-content').find('embed').attr('src');
if (typeof src !== "undefined") {
//do nothing again unless true run script below
} else {
var qload = src.replace('http://youtube.com/v/','');
var y = src.replace('http://','http://img.');
var imgsrc = y.replace('v','vi');
$('embed').before('<a class="ez_video" id="'
+ qload +'" href="'+ src +'"><img src="'
+ imgsrc +'/0.jpg" tile="" alt=""/></a>');
$('embed').remove();
}
//Now make all work with the fancybox
$('.ez_video').fancybox({
'autoScale' : false,
'transitionIn' : 'elastic',
'transitionOut' : 'elastic',
'width' : 854,
'height' : 480,
'type' : 'swf',
'swf' : {
'wmode' : 'transparent',
'allowfullscreen' : 'true'
}
});
});
You are comparing it to a string of undefined while you should compare it the actual reserved word:
if(typeof wt !== undefined)
You can also do:
if(wt !== "undefined")
BTW, what you are doing is, if it is not undefined - do nothing, else - do something, is this really what you want?

I have a huge set of elements and jQuery's each() function is killing my browser - How can I improve my code?

I'm using two plugins I wrote to find all the radio/checkbox inputs and select boxes in a form and them style them.
I now have a large form which a lot of checkboxes and Firefox is hanging as my plugin tries to style each of them.
Here's the plugin code:
(function($)
{
$.fn.stylecheck = function(options)
{
/*
Parameters:
image: the image to load in place of the checkboxes/radio buttons
offset: the Y offset (background-position) to show the 'on' position of the image
*/
return this.each(function()
{
if (!$(this).is(':checkbox') && !$(this).is(':radio'))
return;
var $input = $(this);
var $image = null;
var $contianer = null;
// Wrap the input and then hide it
$input.wrap('<div class="stylecheck-container" style="display: inline" />').addClass('stylecheck').hide();
$container = $input.parent('div.stylecheck-container');
$image = $container.append('<div class="stylecheck-image" />').children('div.stylecheck-image');
$image.css(
{
"width" : options['width'],
"height" : (options['height'] / 2),
"display" : "inline-block",
"background" : ($input.is(':checked')) ? ("url('" + options['image'] + "') no-repeat 0px -17px") : ("url('" + options['image'] + "') no-repeat 0px 0px")
});
if ($container.parent('label').length > 0)
{
$container.append('<label style="display: inline; position: relative; top: -2px">' + $container.parent('label').text() + '</label> ');
$container.parent('label').replaceWith($container);
}
$input.change(function()
{
if ($input.is(':checked'))
$image.css("background-position", "0px -" + (options['height'] / 2) + "px");
else
$image.css("background-position", "0px 0px");
});
$container.click(function()
{
if ($input.is(':checkbox'))
{
if (!$input.is(':checked'))
$input.attr('checked', true);
else
$input.removeAttr('checked');
}
if ($input.is(':radio') && !$input.is(':checked'))
{
$findme = $('input[name="' + $input.attr('name') + '"]:checked')
if ($findme.length > 0)
$findme.each(function() { $(this).attr('checked', false); $(this).trigger('change'); });
$input.attr('checked', true);
}
$input.trigger('change');
});
});
};
})(jQuery);
I'm guessing the problem is with jQuery's each() function searching over hundreds of my checkboxes...
Is there anyway to improve my plugin?
Not all checkboxes are visible on page load (display: hidden). So I'm thinking an alternative will be to style the checkboxes only when they're visibility is toggled - Though, I'd like to leave that as a last resort if my above code can be improved.
Cheers.
Here's one thing you can improve. You're creating two jQuery objects and calling .is() against both. Then on the next line, you're creating another one and caching it in a variable.
Either cache in the variable before the if() statement, and use the cached version, or ditch jQuery objects for the if() statement altogether, and do something like this:
var type = this.type.toLowerCase();
if (type != 'checkbox' && type != 'radio')
return;
The rest here will be documentation of #Nick Craver's posted jsFiddle.
Overall, don't use jQuery when you can avoid it. It is simply faster to use the native API. When you do use jQuery, use it in the most minimal manner possible.
You can change this line:
$container = $input.parent('div.stylecheck-container');
to this:
$container = $input.parent();
since you wrapped the $input, no need to test the parent with a selector.
Change this line:
"background" : ($input.is(':checked')) ? ("url('" + options['image'] + "') no-repeat 0px -17px") : ("url('" + options['image'] + "') no-repeat 0px 0px")
to this in order to avoid a call to .is(). Doing this.checked returns a boolean value:
"background" : this.checked ? ("url('" + options['image'] + "') no-repeat 0px -17px") : ("url('" + options['image'] + "') no-repeat 0px 0px")
In the handlers you assign, change $input.is('checked') to $input[0].checked. This gets the DOM element, and gets the checked attribute. This won't speed up the plugin execution, but will improve the handlers.
Also, change $input.is(':checkbox') to $input[0].type == "checkbox" (and likewise with radio). You could even cache the type in a variable as I did at the top of this answer, and use that value. As in type == "checkbox".

jQuery Gallery - Webkit problems

Okay. So I've got a a little jQuery gallery scroller I wrote to work with WordPress. It works beautifully in Firefox, but it doesn't work in Chrome or Safari.
Here's the link:
http://thehousinggroup.info/our-gallery/bathroom-renovations/gallery-1/
Here's the jQuery:
var imageQuantity = $('.galleryBox img').size() //finds the number of images
var wrapWidth = imageQuantity * 610 + 'px' //sets inner wrapper to image width*no. of images
//Formating
$('.galleryBox img')
.hide()
.unwrap()
.wrapAll('<ul></ul>')
.wrapAll('<div id="innerWrap"></div>')
.wrap('<li></li>');//wraps images in ul and div, strips off the <p> that WordPress adds
$('#innerWrap').css({
'width' : wrapWidth,
'position' : 'relative'
});
$('.galleryBox').css({'overflow' : 'hidden'}); //this css will be relegated to the stylesheet eventually...
$('.galleryBox ul').css({'list-style' : 'none'});
$('.galleryBox li').css({
'float' : 'left',
'margin-right' : '10px'
});
$('.galleryBox img').show(); //shows the images once the formatting is complete
//Scroll Controls
var currentNumber = 1; //this is for the "1 of 4" counter
var fullNumber = imageQuantity;
$('#innerWrap').before('<p id="scroller"><a id="prevButton" href="">previous</a> <span id="currentNumber">' + currentNumber + '</span> of ' + fullNumber +' <a id="nextButton" href="#">next</a></p>'); //this places the next, previous, and 1 of # counter buttons
$('#nextButton').click(function(event){
event.preventDefault();
var wrapPosition = parseInt($('#innerWrap').css('right'));
var stopPoint = (fullNumber-1)*610;
if(wrapPosition < stopPoint) { //sets the scrolling to stop at last image
$('#innerWrap').animate({'right' : "+=610px"});
++currentNumber;
$('#currentNumber').empty().html(currentNumber); //sets the counter to the proper number
}
});
$('#prevButton').click(function(event){ //same as above, reversed out for the previous button
event.preventDefault();
var wrapPosition = parseInt($('#innerWrap').css('right'));
var stopPoint = (fullNumber-1)*610;
if(wrapPosition > 0) {
$('#innerWrap').animate({'right' : "-=610px"});
--currentNumber;
$('#currentNumber').empty().html(currentNumber);
}
});
I'm going to be setting the css to be in the stylesheets, but this is how it's set up for now. If you've got any further critiques, I'm open!
Thanks.
This line catches my attention:
$('#innerWrap').animate({'right' : "-=610px"});
Specially because there is no "right" property initially set up on WebKit.
Try to have the calculation done one step above:
right_pos = doTheMathHere;
$('#innerWrap').animate({'right' : rigt_pos});
This code is breaking in Chrome : var wrapPosition = parseInt($('#innerWrap').css('right'));
So it's skipping over this block:
if(wrapPosition < stopPoint) {
$('#innerWrap').animate({'right' : "+=610px"});
++currentNumber;
$('#currentNumber').empty().html(currentNumber);
}
Sorry to answer my own question
I think I figured it out. It has to do with the wrapAll() order. I intended for the <ul> to be wrapped inside the <div>, but the opposite is happening. This isn't a problem with Webkit. It's more one of those..."wait...why does this work in Firefox" sorts of issues.

Different background position every click

Im trying to build sort of slide where when click on link ".animate" will change it position ( every time 100px more)
This:
$(function(){
$('#m-main').click(function(){
$('slide').animate({top : "100px"}, {duration:500})
})
});
will work only once.
How can I make this working?
Many thanks for your help.
$(function() {
$('#m-main').click(function(){
$(this).data($(this).data('pos') + 100);
$('slide').animate({top : $(this).data('pos') + 'px'}, {duration:500})
})
});
When it runs it sets the top padding to 100px, so after the first time it's just setting it to the same value it already has. You need to increment the value each time.
$(function(){
$('#m-main').click(function(){
var current = $('slide').css('top');
current = current + 100;
$('slide').animate({top : current+"px"}, {duration:500})
})
});
code above untested
Try using a counter instead of just top : "100px". It is just doing it once because essentially your setting top to 100px and then setting top to 100px again which is just keeping it where it is. You want it to move to 200px and then to 300px, etc.
Try this:
var fromTop = 100;
$(function() {
fromTop = fromTop + 100;
$('#m-main').click(function() {
$('slide').animate({top : '"' + fromTop + 'px"'}, {duration:500})
})
});
It looks like you've got some error in the query string in the click handler. $('slide') will select all <slide> elements, which I assume you have none, perhaps $('.slide') or $('#slide') is what you're after?
If you just keep a reference of the position you'd like the element to move to and increase that by 100 each time (see chaos's answer) then you should be right.
$(function(){
var pos=100;
$('#m-main').click(function(){
$('slide').animate({top : pos+'px'}, {duration:500});
pos=pos+100;
});
});
Try this:
$('#m-main').click(function(){
var slide = $('.slide', this),
posY = parseInt(slide.css("background-position").split(" ")[1]);
slide.stop().animate({backgroundPosition: "0 "+(Math.ceil(posY/100)*100 + 100)+"px"}, {duration:500});
});

Categories