Jquery ui shake effect keeps trigering - jquery-ui

Strange issue.
Using jquery ui effect like this:
<a href="in" style="position:absolute;" ><img src="images/img.png" id="perlabot" ></a>
$('#perlabot').on('mouseenter', function () {
$(this).effect("shake", { times:2, distance: 3}, 120);
});
And it works but on IE and Firefox the image keeps shaking all the time even if the mouse is right in the middle of the image. it seems that moving image trigers mouseenter event all the time??
Cannot fix this, strange issue. On chrome it trigers just once.

I didn't find a real solution to your problem but you could easily avoid it by checking if a variable has a certain value and reset it if the user leaves the area.
var active = false;
$('#perlabot').on('mouseenter', function () {
if (active === false) {
active = true;
$(this).effect("shake", {
times: 2,
distance: 3
}, 120);
}
}).mouseleave(function () {
active = false;
});
Might not be the smartest way to solve it but it works fine in every browser I tested it (Firefox, Chrome, Opera, IE 10 and 9)
jsfiddle

Try this option. Similar concept to the above answer, but I think more robust. (no global status variable for example)
function shakeIt(obj)
{
obj.mouseleave(function () {
obj.on("mouseenter", function () { shakeIt(obj); });
obj.off("mouseleave");
});
obj.off("mouseenter");
obj.effect("shake", { distance: "3", times: "2" }, 120);
}
$("#perlabot").on("mouseenter", function () { shakeIt($(this)); });

Related

Bootstrap Carousel Next/Prev controls stop responding when page is reloaded

I'm using the Bootstrap Carousel feature. On initial load of the page the Carousel next/prev controls work perfectly however when I simpy reload the page these controls no longer respond to clicks even though the interval for "auto" rotating the slides that I've configured continues to work.
I've done alot of research trying to troubleshoot this problems..including reviewing probably 30+ stackoverflow postings on Bootstrap Carousel but none of them offered any solutions for me. After two days of researching this problem I'm still stumped.
Environment/setup:
My browser is Chrome
Libraries included in the following order: a)jQuery 2.1.3, b)Bootstrap CSS 3.3.5, c)Bootsrap JS 3.3.5
Running in Ruby on Rails 4.2 environment
My solution is a pure bootstrap solution (e.g., no special JS other than including variants of $('#carousel-generic-example).carousel() type statement per examples I've seen online..apparently no change in behavior with or without this statement).
I'm a bit puzzled as to why it works properly on initial load but not on subsequent reloads. Perhaps something isn't being loaded properly when I do a re-load of the web page??? Maybe there is some behavior within Rails that is causing this behavior?
If anyone has any theories as to what might be causing this behavior I'd love to hear it (even if you don't have time to dig into the code). Or if you have any specific ideas on what I might be able to do troubleshoot this problem.
There is a lot of relevant code associated with my solution...rather than trying to copy and paste it all in this post I think the most effective and efficient way of "sharing" it with you is to point you to my public Github account where the code is located and provide a map to the relevant files within the project.
First the full set of code can be found on my Github account at: gitHub site
Within this project here is where you can find the relevant sections of code:
app/views/application.html.erb : List of external libraries (e.g., jQuery, bootstrap files, etc.)
app/views/portfolio_items/show.html.erb : HTML for page including Carousel
app/assets/javascripts/jet.js : see what I tried lines 17-20, 199-202. I'm not sure if I really need to include javascript as it didn't really seem to affect the behavior of the solution. So I ultimately commented it out.
app/assets/stylesheets/jet.css.erb : Lines 2332-2354
Note 1: you'll see that in my javascript file I'm using both $(window).load(function ()... and `$(document).ready(function() {' functions. I have to admit that I'm a bit fuzzy on what these two functions do other than generally make sure that the items on the page load before the javascript starts to run. I leveraged parts of my template from a theme and I noticed that they used both of these functions in their theme so I don't think this is the cause of my issues...but thought I would reference it just in case.
Note 2: I'm not sure it is relevant but I'm also using another Carousel solution (caroufredsel) on the same page with the Bootstrap Carousel. I don't think there is any conflict as the theme I borrowed from did the same thing...but I thought I would mention it.
UPDATE: I've continued to try and resolve my issue (i.e., Bootstrap Carousel next/prev buttons don't advance images) and stumbled upon something interesting that could be the key to fixing my issue. Specifically
When I "close" the $(document).ready" statement immediately as follows:
'$(document).ready(function() {});'
in my javascript "app/assets/javascripts/jet.js" the Bootstrap Carousel behaves as I would expect (prev/next controls advance images when clicked on).
Unfortunately making the change breaks the other carousel functionality (caroufredsel) at the bottom of the web page (i.e., instead of only showing 3 elements at a time in caroufredsel it shows all of the items and the controls for caroufredsel then don't work). I really need to wrap other jQuery code in the $(document).ready functionality...but when I do the Bootstrap prev/next controls don't work properly.
Anybody have any suggestions on what is going on here and how I could fix it?
Here is the full version of the jet.js file:
function scroll_to(clicked_link, nav_height) {
var element_class = clicked_link.attr('href').replace('#', '.');
var scroll_to = 0;
if(element_class != '.top-content') {
element_class += '-container';
scroll_to = $(element_class).offset().top - nav_height;
}
if($(window).scrollTop() != scroll_to) {
$('html, body').stop().animate({scrollTop: scroll_to}, 1000);
}
}
$(document).ready(function() {
// Bootstrap Carousel -- Tried each of the following lines but neither of them helped
// $('#carousel-generic-example').carousel()
// $('.carousel').carousel()
// $('#carousel-generic-example').carousel()});
// {
// 'prev'
// 'next'
// pause: true,
// interval: false,
// keyboard: true
// }
// jQuery('#carousel-generic-example').carousel();
// Pretty photo script
$("a[data-rel^='prettyPhoto']").prettyPhoto({
theme: 'light_square',
social_tools: false,
hook: 'data-rel'
});
// ------------------------------------------------------------------------------------------
// Code below attempted to dynamically change glyphicons used on web page separator
// to avoid having to distinct CSS code for every separator (e.g., blog-separator, project-separator, etc)
// Unfortunately I couldn't get this to work...this code displays the character string
// for the blog glyphicon (i.e., e043) rather than the actual glyphicon. StackOverflow (http://stackoverflow.com/questions/5041494/manipulating-css-pseudo-elements-such-as-before-and-after-using-jquery?lq=1) from Blazemonger (#3) suggest it may only work for strings (maybe not hex values)
// So I'm assuming i can't dynamically insert glyphicons.
// ------------------------------------------------------------------------------------------
// var regExp = /\#([a-z]+)/;
//
// $(".menu-items a").on('click', function () {
// var href = $(this).attr('href');
// var matches = regExp.exec(href);
// switch(matches[1]) {
// case "home":
// alert(href);
//
// break;
// case "about":
// alert(href);
// break;
// case "projects":
// alert(href);
// break;
// case "blog":
// $('.separator-line').attr('data-content', '\e043');
// // $(this).attr('data-content', '\e043');
// // $(".separator-line::after.content").attr('glyphicon-code',"\e043");
// var separatorCode = $(this).attr('data-content', '\e043').val();
// alert(separatorCode);
// break;
// case "contact":
// alert(href)
// break;
// }
// });
// -------------------------------------------------------------------------------
// Portfolio Javascript to load images
// var $container = $('.container');
//
// $container.imagesLoaded( function() {
// $container.masonry({
// itemSelector : '.post-box',
// columnWidth : '.post-box',
// transitionDuration : 0
// });
// });
$(".truncateIt").dotdotdot({
// configuration goes here
/* The text to add as ellipsis. */
ellipsis : '... ',
/* How to cut off the text/html: 'word'/'letter'/'children' */
wrap : 'word',
/* Wrap-option fallback to 'letter' for long words */
fallbackToLetter: true,
/* jQuery-selector for the element to keep and put after the ellipsis. */
after : 'a.next',
/* Whether to update the ellipsis: true/'window' */
watch : false,
/* Optionally set a max-height, if null, the height will be measured. */
height : 60,
/* Deviation for the height-option. */
tolerance : 0,
/* Callback function that is fired after the ellipsis is added,
receives two parameters: isTruncated(boolean), orgContent(string). */
callback : function( isTruncated, orgContent ) {},
lastCharacter : {
/* Remove these characters from the end of the truncated text. */
remove : [ ' ', ',', ';', '.', '!', '?' ],
/* Don't add an ellipsis if this array contains
the last character of the truncated text. */
noEllipsis : []
}
});
// Scroll location for buttons on banner page
$('a.scroll-link').on('click', function(e) {
e.preventDefault();
scroll_to($(this), $('nav').outerHeight());
});
// Link and activate WOW.js
new WOW().init();
$(".nav a").on("click", function(){
$(".nav").find(".active").removeClass("active");
$(this).parent().addClass("active");
});
// Smooth scrolling logic
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
|| location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
$(".cnbox").each(function () {
var nheight = $(this).find(".nbox").height();
$(this).find(".cbox").css("height", nheight + 50);
});
}); // /document.ready()
var caroufredsel = function () {
$('#caroufredsel-portfolio-container').carouFredSel({
responsive: true,
scroll: 1,
circular: false,
infinite: false,
items: {
visible: {
min: 1,
max: 3
}
},
prev: '#portfolio-prev',
next: '#portfolio-next',
auto: {
play: false
}
});
$('#caroufredsel-blog-posts-container').carouFredSel({
responsive: true,
scroll: 1,
circular: false,
infinite: false,
items: {
visible: {
min: 1,
max: 3
}
},
prev: '#blog-posts-prev',
next: '#blog-posts-next',
auto: {
play: false
}
});
};
// Isotope Portfolio
var $container = $('.portfolio-container');
var $blogcontainer = $('.posts-wrap');
var $filter = $('.portfolio-filter');
$(window).load(function () {
// Bootstrap Carousel -- Tried each of the following lines but neither of them helped
// jQuery('.carousel').carousel();
// jQuery('#carousel-generic-example').carousel();
caroufredsel();
// Initialize Isotope
$container.isotope({
itemSelector: '.portfolio-item-wrapper'
});
$blogcontainer.isotope({
itemSelector: '.article-wrap'
});
$('.portfolio-filter a').click(function () {
var selector = $(this).attr('data-filter');
$container.isotope({ filter: selector });
return false;
});
$filter.find('a').click(function () {
$filter.find('a').parent().removeClass('active');
$(this).parent().addClass('active');
});
});
$(window).smartresize(function () {
$container.isotope('reLayout');
$blogcontainer.isotope('reLayout');
});
$(window).resize(function () {
caroufredsel();
});
Cheers.
After much trial and error I found the solution through trial and error. As it turns out the $(document).ready(function() { had to be closed (i.e., }); immediately before the Smooth Scrolling logic (i.e., code that starts with $('a[href*=#]:not([href=#])').click(function() {).
I'm not completely sure why the "close" has to be placed there and not after the Smooth scrolling logic.
If anyone has an explanation I'd love to hear why...As I mentioned I discovered the solution largely by trial and error.
Bootstrap needs normally a JQuery file to overcome this error. So, better embed it in your file and it works when online.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

Input field prevents page from scrolling on iphone

Im working on a site that has a lot of forms. I have noticed that when you scroll/swipe the site on an iphone the page does not scroll if your finger is on an input field. To scroll you have to aim your finger on the body kind of.
Anyone having some ideas on what causes this strange behaviour?
Its just simple inputs wrapped in a form tag.
A workaround for this issue might be :
function setTextareaPointerEvents(value) {
var nodes = document.getElementsByTagName('textarea');
for(var i = 0; i < nodes.length; i++) {
nodes[i].style.pointerEvents = value;
}
}
document.addEventListener('DOMContentLoaded', function() {
setTextareaPointerEvents('none');
});
document.addEventListener('touchstart', function() {
setTextareaPointerEvents('auto');
});
document.addEventListener('touchmove', function() {
e.preventDefault();
setTextareaPointerEvents('none');
});
document.addEventListener('touchend', function() {
setTimeout(function() {
setTextareaPointerEvents('none');
}, 0);
});
This will make Mobile Safari (others not tested so far) ignore the textareas for scrolling but allows to set focus etc. as usual.

How to cause open event of jQuery UI tooltip to obey the show.delay property setting

The open event of the jQuery UI tooltip fires not when the popup opens visibly but as soon as the mouse enters the element. It does not obey the show.delay property setting. This is documented behavior so I suppose it is not a bug.
So if I have tooltip on adjacent cells of a table, and the user drags the mouse across these cells, the actions in my open and close handlers are taken multiple times -- three, four, five times -- as many times as the number of cells the mouse entered.
What's a good way to exit the open event if the show.delay has not yet transpired?
EDIT: Not knowing how much time has elapsed on the delay.show, I've had to choose an arbitrary duration for the setTimeout, and track whether a class-switch is in progress using a flag:
<snip> ...
show: {
delay: 666
},
open: function (event, ui) {
if (me.changingClass) return;
me.changingClass = true;
$("td.baz").switchClass("foo", "bar");
},
close: function (event, ui, dupids) {
$("td.baz").switchClass("bar", "foo");
setTimeout(function () { me.changingClass = false; }, 200);
}
I think this may do the trick, if I understand what you're after:
Working Example
var timer;
$('td').tooltip({
show: {
delay: 2000 //number of milliseconds to wait
},
open: function (event, ui) {
var xthis = this;
timer = setTimeout(function () {
$(xthis).siblings().switchClass("bar", "foo");
}, 2000); // number of milliseconds to wait
},
close: function (event, ui, dupids) {
clearTimeout(timer);
$(this).siblings().switchClass("foo", "bar");
}
});

How do I stop my fixed navigation from moving like this when the virtual keyboard opens in Mobile Safari?

I understand that mobile safari has a lot of bugs around fixed elements, but for the most part I've managed to get my layout working correctly until I added a much needed text input to the fixed navigation at the bottom. Now when the user focuses on the text input element and the virtual keyboard appears, my navigation, which is otherwise always fixed at the bottom of the page, jumps up to a really strange spot in the middle of the page.
I'd add some of my code to this post, but I wouldn't be sure where to start. That navigation is fixed at the bottom and positioned to the left and bottom 0, and 100% width. From there, I don't know what's going on, I can only assume it's a mobile safari bug.
It also appears to lose it's position fixed and become relative, only while the text input element is focused on and the virtual keyboard is open.
http://dansajin.com/2012/12/07/fix-position-fixed/ this is one of the solutions proposed. Seems worth a shot.
In short: set fixed elements to position:absolute when any input is focused and reset them when that element is blurred
.header {
position: fixed;
}
.footer {
position: fixed;
}
.fixfixed .header,
.fixfixed .footer {
position: absolute;
}
and
if ('ontouchstart' in window) {
/* cache dom references */
var $body = $('body');
/* bind events */
$(document)
.on('focus', 'input', function() {
$body.addClass('fixfixed');
})
.on('blur', 'input', function() {
$body.removeClass('fixfixed');
});
}
The solutions on the top are some ways to go and fix the problem, but I think adding extra css class or using moderniz we are complicating things.If you want a more simple solution, here is a non-modernizr non-extra-css but pure jquery solution and work on every device and browsers I use this fix on all my projects
if ('ontouchstart' in window) {
$(document).on('focus', 'textarea,input,select', function() {
$('.navbar.navbar-fixed-top').css('position', 'absolute');
}).on('blur', 'textarea,input,select', function() {
$('.navbar.navbar-fixed-top').css('position', '');
});
}
I had a similar problem, but I found a workaround by adding the following css class to the body element on input focus and then removing it again on unfocus:
.u-oh {
overflow: hidden;
height: 100%;
width: 100%;
position: fixed;
}
Taking from what sylowgreen did, the key is to fix the body on entering the input. Thus:
$("#myInput").on("focus", function () {
$("body").css("position", "fixed");
});
$("#myInput").on("blur", function () {
$("body").css("position", "static");
});
Add javascript like this:
$(function() {
var $body;
if ('ontouchstart' in window) {
$body = $("body");
document.addEventListener('focusin', function() {
return $body.addClass("fixfixed");
});
return document.addEventListener('focusout', function() {
$body.removeClass("fixfixed");
return setTimeout(function() {
return $(window).scrollLeft(0);
}, 20);
});
}
});
and add class like this:
.fixfixed header{
position: absolute;
}
you can reference this article: http://dansajin.com/2012/12/07/fix-position-fixed/
I really like the solution above. I packaged it up into a little jQuery plugin so I could:
Set which parent gets the class
Set which elements this applies to (don't forget "textarea" and "select").
Set what the parent class name is
Allow it to be chained
Allow it to be used multiple times
Code example:
$.fn.mobileFix = function (options) {
var $parent = $(this),
$fixedElements = $(options.fixedElements);
$(document)
.on('focus', options.inputElements, function(e) {
$parent.addClass(options.addClass);
})
.on('blur', options.inputElements, function(e) {
$parent.removeClass(options.addClass);
// Fix for some scenarios where you need to start scrolling
setTimeout(function() {
$(document).scrollTop($(document).scrollTop())
}, 1);
});
return this; // Allowing chaining
};
// Only on touch devices
if (Modernizr.touch) {
$("body").mobileFix({ // Pass parent to apply to
inputElements: "input,textarea,select", // Pass activation child elements
addClass: "fixfixed" // Pass class name
});
}
I use this jQuery script:
var focus = 0;
var yourInput = $(".yourInputClass");
yourInput.focusin(function(){
if(!focus) {
yourInput.blur();
$("html, body").scrollTop($(document).height());
focus = 1;
}
if(focus) {
yourInput.focus();
focus = 0;
}
});
Works perfectly for me.
The focusin and focusout events seem to be better suited to this problem than the focus and blur events since the former bubble up to the root element. See this answer on SO.
Personally I use AngularJS, so I implemented it like this:
$window.document.body.addEventListener('focusin', function(event) {
var element = event.target;
var tagName = element.tagName.toLowerCase();
if(!$rootScope.inputOverlay && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {
$rootScope.$apply(function() {
$rootScope.inputOverlay = true;
});
}
});
$window.document.body.addEventListener('focusout', function() {
if($rootScope.inputOverlay) {
$rootScope.$apply(function() {
$rootScope.inputOverlay = false;
});
}
});
Note: I am conditionally running this script if this is mobile Safari.
I put an ng-class attribute on my navbar:
<div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">
using the following CSS:
.navbar-absolute {
position: absolute !important;
}
You can read more about focusin here and focusout here.
Test this one. It works. I just test it.
$(document).on('focus','input', function() {
setTimeout(function() {
$('#footer1').css('position', 'absolute');
$('#header1').css('position', 'absolute');
}, 0);
});
$(document).on('blur','input', function() {
setTimeout(function() {
$('#footer1').css('position', 'fixed');
$('#header1').css('position', 'fixed');
}, 800);
});
None of these solutions worked for me because my DOM is complicated and I have dynamic infinite scroll pages, so I had to create my own.
Background: I am using a fixed header and an element further down that sticks below it once the user scrolls that far down. This element has a search input field. In addition, I have dynamic pages added during forward and backwards scroll.
Problem: In iOS, anytime the user clicked on the input in the fixed element, the browser would scroll all the way to the top of the page. This not only caused undesired behavior, it also triggered my dynamic page add at the top of the page.
Expected Solution: No scroll in iOS (none at all) when the user clicks on the input in the sticky element.
Solution:
/*Returns a function, that, as long as it continues to be invoked, will not
be triggered. The function will be called after it stops being called for
N milliseconds. If `immediate` is passed, trigger the function on the
leading edge, instead of the trailing.*/
function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function is_iOS() {
var iDevices = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
];
while (iDevices.length) {
if (navigator.platform === iDevices.pop()) { return true; }
}
return false;
}
$(document).on("scrollstop", debounce(function () {
//console.log("Stopped scrolling!");
if (is_iOS()) {
var yScrollPos = $(document).scrollTop();
if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
$('#searchBarDiv').css('position', 'absolute');
$('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header
}
else {
$('#searchBarDiv').css('position', 'inherit');
}
}
},250,true));
$(document).on("scrollstart", debounce(function () {
//console.log("Started scrolling!");
if (is_iOS()) {
var yScrollPos = $(document).scrollTop();
if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
$('#searchBarDiv').css('position', 'fixed');
$('#searchBarDiv').css('width', '100%');
$('#searchBarDiv').css('top', '50px'); //50 for fixed header
}
}
},250,true));
Requirements: JQuery mobile is required for the startsroll and stopscroll functions to work.
Debounce is included to smooth out any lag created by the sticky element.
Tested in iOS10.
I wasn't having any luck with the solution proposed by Dan Sajin. Perhaps the bug has changed since he wrote that blog post, but on iOS 7.1, the bug will always surface when the position is changed back to fixed after the input is blurred, even if you delay until the software keyboard is hidden completely. The solution I came to involves waiting for a touchstart event rather than the blur event since the fixed element always snaps back into proper position when the page is scrolled.
if (Modernizr.touch) {
var $el, focused;
$el = $('body');
focused = false;
$(document).on('focus', 'input, textarea, select', function() {
focused = true;
$el.addClass('u-fixedFix');
}).on('touchstart', 'input, textarea, select', function() {
// always execute this function after the `focus` handler:
setTimeout(function() {
if (focused) {
return $el.removeClass('u-fixedFix');
}
}, 1);
});
}
HTH

reposition the dragged div after dropping it

is it possible to change the left position of a div after dropping it?
i'm trying to do that using this code but it's not working, can anybody help me...
thanks a million in advance :)
$(function () {
$("#task_1").draggable({ revert: 'invalid' });
$("#Lina").droppable({
drop: function (ev, ui) {
var pos = $("#task_1").position();
// kolla(pos.left);
if (pos.left < 0) {
alert(pos.left);
$("#task_1").position().left = 0;
}
else {
// do something else
}
}
});
});
Just a quick idea, have you tried:
$("#task_1").css("left","0");
If the outer drop-area has relative positioning (not sure, have to check) that should work.
Basically, you want the dropped div to shift to the very left of the drop area, right?
Update
You have it so that the position is changed when the condition is pos < 0. Since the div won't be in the drop-area if it's outside of it, I think you mean pos > 0. Also, why bother checking, if it's already 0, it just changes it to what it already is.
For instance:
$(function () {
$("#task_1").draggable({ revert: 'invalid' });
$("#Lina").droppable({
drop: function (ev, ui) {
this.position().left = 0;
}
});
});
Notice I also made it "this" since you are changing the selector.

Resources