jquery feature detection - how can I implement this? - javascript

I need to prevent IE from recognizing the fadeIn/Out effect in this plugin. How can I add a line of jquery feature detection code to this:
$(function() {
var newHash = "",
$mainContent = $("#main-content"),
$pageWrap = $("#page-wrap"),
baseHeight = 0,
$el;
$("nav#footer").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
$mainContent
.find("#guts")
.fadeOut(200, function() {
$mainContent.show().load(newHash + " #guts", function() {
$mainContent.fadeIn(200, function() {
});
$("nav#footer a").removeClass("current");
$("nav#footer a[href="+newHash+"]").addClass("current");
});
});
};
});
$(window).trigger('hashchange');
});
I had some code like
var FADE_TIME = 500; if(!($.support.opacity)) { FADE_TIME = 0}
$('element').fadeOut(FADE_TIME)
Where would I add this in the code? can someone help me get this working for real?please!!

Can't figure out why somebody didn't just edit the code and answer the question.
All you needed to do was create a new variable with it's value determined by the $.support.Opacity property then reference that in the fade in/out sections of the code.
$(function() {
var newHash = "",
$mainContent = $("#main-content"),
$pageWrap = $("#page-wrap"),
baseHeight = 0,
$el,
// new fadeTime property.
fadeTime = $.support.opacity ? 500 : 0;
$("nav#footer").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
$mainContent
.find("#guts")
.fadeOut(fadeTime, function() {
$mainContent.show().load(newHash + " #guts", function() {
$mainContent.fadeIn(fadeTime, function() {
});
$("nav#footer a").removeClass("current");
$("nav#footer a[href="+newHash+"]").addClass("current");
});
});
};
});
$(window).trigger('hashchange');
});

You just want to run something if the user isn't using Internet Explorer?
Try this:
if ($.browser.msie) {
return false;
} else {
//do something
}

I presume you're talking the support for the CSS opacity property and not the slightly buggy -ms-filter and filter which IE8 and below uses. In that case, the best method would be to test for the existence of the property in the style object of an element:
if('opacity' in document.createElement('div').style) {
// Do something that requires native opacity support
}
(You might want to cache the test element there if you want to test multiple properties)

Related

Convert jQuery view handler to Angular Controller

Trying to convert a lot of jQuery and JS to an Angular controller so that it works the "NG" way. I've looked at the docs and it looks like I can setup a document ready function in Angular using something like angular.element(document).ready to initialize the jQuery variable. What I am confused on is "this" and it's place in the angular world. Anyone have an idea of where to start?
Here is a Pen of what I am trying to accomplish:
CodePen
And I know that there is ng-show/ng-hide and that ngAria shows up around 1.3 but I am just trying to grasp the basis for converting a lot of jQuery to angular.
Here is my current script:
$(document).ready(function() {
var hs1 = new hideShow('open1', 'close1');
var hs2 = new hideShow('open2', 'close2');
var hs3 = new hideShow('open3', 'close3');
var hs4 = new hideShow('open4', 'close4');
});
function hideShow(toggleID, closeID) {
this.$toggle = $('#' + toggleID);
this.$close = $('#' + closeID);
this.$region = $('#' + this.$toggle.attr('aria-controls'));
this.keys = {
enter: 13,
space: 32
};
this.toggleSpeed = 100;
this.bindHandlers();
}
hideShow.prototype.bindHandlers = function() {
var thisObj = this;
this.$toggle.click(function(e) {
thisObj.toggleRegion();
e.stopPropagation();
return false;
});
this.$close.click(function(e) {
thisObj.hideRegion();
e.stopPropagation();
return false;
});
}
hideShow.prototype.hideRegion = function() {
this.$region.hide().attr('aria-expanded', 'false');
this.$toggle.find('span').html('Show');
this.$toggle.focus();
}
hideShow.prototype.toggleRegion = function() {
var thisObj = this;
this.$region.slideToggle(this.toggleSpeed, function() {
if ($(this).attr('aria-expanded') == 'false') { // region is collapsed
$(this).attr('aria-expanded', 'true');
$(this).focus();
thisObj.$toggle.find('span').html('Hide');
} else {
$(this).attr('aria-expanded', 'false');
thisObj.$toggle.find('span').html('Show');
}
});
}
Any suggestions or examples are appreciated.

Jquery code doesn't work well on firefox/ie

I have the following code (on jsfiddle here)
$(function(){
var $container = $('#gallery');
$container.isotope({
filter: '*',
animationOptions: {
duration: 750,
easing: 'linear',
queue: false
}
});
var $optionSets = $('ul.nav'),
$optionLinks = $optionSets.find('a');
$optionLinks.click(function () {
var $this = $(this);
if ($this.hasClass('selected')) {
return false;
}
var $optionSet = $this.parents('ul.nav');
$optionSet.find('.selected').removeClass('selected');
$this.addClass('selected');
});
// HASH HISTORY WITH JQUERY BBQ
$('ul.nav a').click(function () {
// get href attr, remove leading #
var href = $(this).attr('href').replace(/^#/, ''),
// convert href into object
// i.e. 'filter=.inner-transition' -> { filter: '.inner-transition' }
option = $.deparam(href, true);
// set hash, triggers hashchange on window
$.bbq.pushState(option);
return false;
});
//just a function to quickly add and remove .selected
function changeSelectedLink($elem) {
$elem.addClass('selected');
}
$(window).bind('hashchange', function (event) {
//checks if there is a hash in the url and puts hashes in hashOptions
$(".selected").removeClass("selected");
var hashOptions = window.location.hash ? $.deparam.fragment(window.location.hash, true) : {}, options = $.extend({}, hashOptions);
$('#gallery').isotope(options);
var hrefObj, hrefValue, $selectedLink;
//go over each hashOption and convert it to a variable
for (var key in options) {
hrefObj = {};
hrefObj[key] = options[key];
hrefValue = $.param(hrefObj);
$selectedLink = $('ul.nav').find('a[href="#' + hrefValue + '"]');
changeSelectedLink($selectedLink);
}
}).trigger('hashchange'); //this continues the hashchange event
});
This code works well on chrome. But in firefox 22 and ie 10 it behaves strange
When clicking on colors it all works. When going back, the code should behave in such a way that .selected is cleared and only added to the correct node. The result is that the .selected is cleared in the DOM (if I inspect the element) but on screen it doesn't. The class is removed once I click anywhere on the screen.
Furthermore, if I debug with firebug,etc this doesn't happen!
Am I missing anything in the code?
remove a:focus in css or add blur to $('.selected').removeClass('selected').blur(); in hashchange
http://jsfiddle.net/Q6SbU/7/
there is only one .selected

jquery ajax navigation within ajax navigation

I'm using this code for my main site navigation which loads each page via ajax and has fallback.
$(function() {
var newHash = '',
$contentWrap = $("#content-wrap");
$("nav").on("click", "a", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).on('hashchange', function() {
newHash = window.location.hash.substring(1);
$contentWrap.load(newHash + " #content");
});
$(window).trigger('hashchange');
});​
this works fine but when i load in the content from another page for example about.html i am also loading in some more buttons for navigation within #content-wrap.
so #content-wrap now contains a data box and some more buttons for navigation. when i click on the new navigation it needs to load new data in the data box.
first i tried just pretty much copying the script above but with new anchors however i get a conflict.
i figure i need some sort of if statement, i have looked into something like if (function !== undefined) but cannot figure out what to do.
I'm not sure how well i have explained myself, i'm confused explaining it but basically i want to combine the code above with basically the same code below without a conflict.
$(function() {
var newHash = '',
$contentWrap = $("#content-wrap"),
$aboutWrap = $("#a-wrap");
$("#content-wrap").on("click", "a", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).on('hashchange', function() {
newHash = window.location.hash.substring(1);
$aboutWrap.load(newHash + " #a-content");
});
$(window).trigger('hashchange');
});​
Update: kind of works a bit but changed my plan
$(function() {
var newHash = '',
$nav = $("nav a"),
$boxBtn = '',
$aboutWrap = '',
$contentWrap = $("#content-wrap");
$("nav").on("click", "a", function() {
$(this).addClass("nav-click");
window.location.hash = $(this).attr("href");
return false;
});
$contentWrap.on("click", "a", function() {
$(this).addClass("btn-click");
window.location.hash = $(this).attr("href");
return false;
});
$(window).on('hashchange', function() {
var $aboutWrap = $("#a-wrap"),
$boxBtn = $("div.btn a");
newHash = window.location.hash.substring(1);
if ($nav.hasClass("nav-click")){
$contentWrap.load(newHash + " #content");
$nav.removeClass("nav-click");
};
if ($boxBtn.hasClass("btn-click")){
$aboutWrap.load(newHash + " #a-content");
$boxBtn.removeClass("btn-click");
};
});
$(window).trigger('hashchange');
}); /*/end*/
I had a similar problem, basically in most cases the problem is with conflicting element ID's. In the DOM you can use an ID only once. You can workaround that by using classNames and ID's for only unique elements like wrappers.

setInterval with other jQuery events - Too many recursions

I'm trying to build a Javascript listener for a small page that uses AJAX to load content based on the anchor in the URL. Looking online, I found and modified a script that uses setInterval() to do this and so far it works fine. However, I have other jQuery elements in the $(document).ready() for special effects for the menus and content. If I use setInterval() no other jQuery effects work. I finagled a way to get it work by including the jQuery effects in the loop for setInterval() like so:
$(document).ready(function() {
var pageScripts = function() {
pageEffects();
pageURL();
}
window.setInterval(pageScripts, 500);
});
var currentAnchor = null;
function pageEffects() {
// Popup Menus
$(".bannerMenu").hover(function() {
$(this).find("ul.bannerSubmenu").slideDown(300).show;
}, function() {
$(this).find("ul.bannerSubmenu").slideUp(400);
});
$(".panel").hover(function() {
$(this).find(".panelContent").fadeIn(200);
}, function() {
$(this).find(".panelContent").fadeOut(300);
});
// REL Links Control
$("a[rel='_blank']").click(function() {
this.target = "_blank";
});
$("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
$("#content").fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
}
}
This works fine for a while but after a few minutes of the page being loaded, it drags to a near stop in IE and Firefox. I checked the FF Error Console and it comes back with an error "Too many Recursions." Chrome seems to not care and the page continues to run more or less normally despite the amount of time it's been open.
It would seem to me that the pageEffects() call is causing the issue with the recursion, however, any attempts to move it out of the loop breaks them and they cease to work as soon as setInterval makes it first loop.
Any help on this would be greatly appreciated!
I am guessing that the pageEffects need added to the pageURL content.
At the very least this should be more efficient and prevent duplicate handlers
$(document).ready(function() {
pageEffects($('body'));
(function(){
pageURL();
window.setTimeout(arguments.callee, 500);
})();
});
var currentAnchor = null;
function pageEffects(parent) {
// Popup Menus
parent.find(".bannerMenu").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
subMenu: $(this).find("ul.bannerSubmenu"),
handlerIn: function() {
this.subMenu.slideDown(300).show();
},
handlerOut: function() {
this.subMenu.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
parent.find(".panel").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
content: panel.find(".panelContent"),
handlerIn: function() {
this.content.fadeIn(200).show();
},
handlerOut: function() {
this.content.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
// REL Links Control
parent.find("a[rel='_blank']").each(function() {
$(this).target = "_blank";
});
parent.find("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
var content = $("#content");
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
content.fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
pageEffects(content);
}
}
Thanks for the suggestions. I tried a few of them and they still did not lead to the desirable effects. After some cautious testing, I found out what was happening. With jQuery (and presumably Javascript as a whole), whenever an AJAX callback is made, the elements brought in through the callback are not binded to what was originally binded in the document, they must be rebinded. You can either do this by recalling all the jQuery events on a successful callback or by using the .live() event in jQuery's library. I opted for .live() and it works like a charm now and no more recursive errors :D.
$(document).ready(function() {
// Popup Menus
$(".bannerMenu").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find("ul.bannerSubmenu").slideDown(300);
} else {
$(this).find("ul.bannerSubmenu").slideUp(400);
}
});
// Rollover Content
$(".panel").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find(".panelContent").fadeIn(200);
} else {
$(this).find(".panelContent").fadeOut(300);
}
});
// HREF Events
$("a[rel='_blank']").live("click", function(event) {
var target = $(this).attr("href");
window.open(target, "_blank");
event.preventDefault();
});
$("a[rel='share']").live("click", function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
setInterval("checkAnchor()", 500);
});
var currentAnchor = null;
function checkAnchor() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn(200);
$("#content").fadeOut(200).html(data).fadeIn(200);
$("#load").fadeOut(200);
});
}
}
Anywho, the page works as intended even in IE (which I rarely check for compatibility). Hopefully, some other newb will learn from my mistakes :p.

jQuery plugin feedback

I'm new to building jQuery plugins.
I have seen and used a lot of tooltip plugins, and today I've decided to build my own.
Can I get some feedback on the code?
What work, what doesn't.
Optimizations.
Caching.
What can I do to make it faster and better?
This would be really helpful for my learning and hopefully for others too.
Heres my plugin:
;(function($) {
$.fn.jTooltip = function(options) {
opts = $.extend({}, $.fn.jTooltip.defaults, options);
return this.each(function() {
var $this = $(this);
var content;
var showTimeout;
$tip = $('#jTooltip');
if($tip.size() == 0){
$('body').append('<div id="jTooltip" style="display:none;position:absolute;"><div></div></div>');
$tipContent = $('#jTooltip div');
}
$this.mouseover(function(event) {
content = $this.attr('title');
$this.attr('title', '');
$tipContent.html(content);
$body.bind('mousemove', function(event){
$tip.css({
top: $(document).scrollTop() + (event.pageY + opts.yOffset),
left: $(document).scrollLeft() + (event.pageX + opts.xOffset)
});
});
showTimeout = setTimeout('$tip.fadeIn(' + opts.fadeTime + ')', opts.delay);
});
$this.mouseout(function(event) {
clearTimeout(showTimeout);
$this.attr('title', content);
$('body').unbind('mousemove');
$tip.hide();
});
});
};
$.fn.jTooltip.defaults = {
delay: 0,
fadeTime: 300,
yOffset: 10,
xOffset: 10
};
})(jQuery);
Updated code
;(function($) {
$.fn.jTooltip = function(options) {
opts = $.extend({}, $.fn.jTooltip.defaults, options);
return this.each(function() {
var $this = $(this);
var showTimeout;
$this.data('title',$this.attr('title'));
$this.removeAttr('title');
$document = $(document);
$body = $('body');
$tip = $('#jTooltip');
$tipContent = $('#jTooltip div');
if($tip.length == 0){
$body.append('<div id="jTooltip" style="display:none;position:absolute;"><div></div></div>');
}
$this.hover(function(event){
$tipContent.html($this.data('title'));
$body.bind('mousemove', function(event){
$tip.css({
top: $document.scrollTop() + (event.pageY + opts.yOffset),
left: $document.scrollLeft() + (event.pageX + opts.xOffset)
});
});
showTimeout = setTimeout(function(){
$tip.fadeIn(opts.fadeTime);
}, opts.delay);
}, function(){
clearTimeout(showTimeout);
$body.unbind('mousemove');
$tip.hide();
});
});
};
$.fn.jTooltip.defaults = {
delay: 0,
fadeTime: 300,
yOffset: 10,
xOffset: 10
};
})(jQuery);
Let me know if you have some more feedback ;)
Use .length rather than .size(). Internally size() calls length so just saves the extra call.
Consider removing the title attribute when you create the tip and storing the tip on the element using .data('tip', title). This will avoid the need for you to constantly blank the title and then add it back again.
Create a function for the work you do inside the setTimeout. Implied eval is considered bad which is what happends when you pass a string to setTimeout/Interval.
window.setTimeout( yourFadeTipFunc , opts.fadeTime);
Cache the $(document) in a var rather than calling it twice.
You could chain the mouseout to the mouseover.
Other than that it is a really good, clean first effort.
Can't say there's anything horribly wrong (others correct me if I'm wrong) but if I were to nitpick I would say use this:
$this.removeAttr('title'); //slightly more readable
instead of this:
$this.attr('title', '');
I just think it's prettier to call removeAttr instead of setting the attribute to the empty string - also, it allows other code to conditionally check for the existence of that attribute, rather than testing it's currently set value against the empty string.

Categories