Feature detection for parallax / background-position - javascript

Ok, so I've created my own parallaxing jQuery/JS script, but I just don't know how to target browsers that will support the following (needs the following):
Supports transition for background-position
The site (preview) I'm trying this at is:
My Test Site
How can I detect whether a browser will support this though?
Can I run media queries bases on window width?
Do I have to browser sniff?
I can't see anything on the WWW that gives me clues as to how I can feature-detect for this.
Any help would be greatly appreciated.
My JS code is here: (please feel free to use it if you like it)
var goTop = 0;
var thisGoTop = 0;
var thisHeight = 0;
var thisWinH = 0;
var bottomIntrusion = 0;
var thisMax = 0;
var bgPos = 0;
function parallax(){
goTop = $(window).scrollTop();
thisWinH = $(window).height();
$('div.para').each(function(){
thisGoTop = $(this).offset().top;
thisHeight = $(this).height();
thisMax = Math.floor(thisHeight * 0.3);
bottomIntrusion = (thisGoTop + (thisHeight / 2) - goTop) / thisWinH;
if (bottomIntrusion > 0) {
bgPos = 0 - (Math.floor(thisMax * bottomIntrusion));
$(this).css('background-position','center ' + bgPos + 'px');
}
});
}
parallax();
$(window).scroll(function(){
parallax();
});
Edit:
I've looked into the Modernizr library, and I haven't found anything that gives me clues about background-position transform support for CSS3. I'm getting real close to brower sniffing at this point, and I'd hate to go there.

<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
$( document ).ready( function() {
var Compatibility = function()
{
var context = this;
context.TestObject = function( id )
{
function CreateObject( id )
{
$('body').prepend('<div id="CompatibilityTestObject_' + id + '"></div>');
}
// Constructor
CreateObject( id );
return {
GetObject: function( id )
{
try
{
// Fetch with raw Javascript so if the javascript method does not exist it will throw an error
var fetchedDomElement = document.getElementById( "CompatibilityTestObject_" + id );
return fetchedDomElement;
}
catch( e )
{
// Failed to fetch DOM Element
return false;
}
},
DeleteObject: function( id )
{
try
{
$( "#CompatibilityTestObject_" + id ).remove();
return true;
}
catch( e )
{
// Failed to remove object
return false;
}
}
}
}
context.Factory = function()
{
return {
CreateTestObject: function( id )
{
var m_TestObject = new context.TestObject( id );
return m_TestObject.GetObject( id );
},
DeleteTestObject: function( id )
{
return context.DeleteObject( id );
}
}
}();
var CSS = function()
{
return {
BackgroundPosition: function()
{
var testObject = context.Factory.CreateTestObject( "BackgroundPosition" );
try
{
// My first try at testing for background positioning
testObject.style.backgroundPosition = "center";
return true;
}
catch( e )
{
// Implement the handling of this error
//alert( "Does not support backgroundPosition: " + e.message );
return false;
}
}
}
}();
return {
CheckCSS: CSS
}
}();
} );
</script>
Take a copy of the above script... place it in your code there, then call upon it like so:
if( Compatibility.CheckCSS.BackgroundPostion() )
{
// Compatible browser
}
else
{
// Not compatible
}

Related

JavaScript integer storing as undefined for some reason

basically I have a number stored within my javascript structure, something like the following:
MyProgram.data.main.padding;
console.log(MyProgram.data.main.padding); // will output the number, something like 34.
However, I need to store that number in a struct I have set up in
MyProgram.data.tests.main.padding; // this is a struct " {'width':0, 'padding':0, 'acceptable' //etc...}
The problem is when I do this:
MyProgram.data.tests.main.padding = MyProgram.data.main.padding;
console.log(MyProgram.data.tests.main.padding); // shows undefined
any ideas why I can't store the number?
I really appreciate any help...
Can someone load this example on jsfiddle please? I don't know how:
http://jsfiddle.net/hdnj52Lp/2/
RESULT OUTPUT ON MY LOCAL TEST: 0) acceptable: true fontSize undefined padding: undefined
function MyProgram() {
var mp = this;
this.main = {
'data' : {
'padding': 50,
'fontSize': 10,
'tests' : {
'padding':null,
'fontSize':null,
'results':new Array()
}
},
'test' : function () {
console.log('running');
var testResult = {'acceptable':false,
'fontSize':0,
'padding':0}
//after some testing:
var newComputedPadding = 100;
var newComputedFontSize = 32;
var acceptable = true;
testResult.acceptable = acceptable;
testResult.fontSize = newComputedFontSize;
testResult.padding = newComputedPadding;
mp.main.data.tests.results.push(testResult);
mp.main.outputResults();
},
'outputResults' : function () {
for(var i = 0; i < mp.main.data.tests.results.length; i++) {
console.log( i + ') acceptable: ' + mp.main.data.tests.results[i].acceptable + ' fontSize ' + mp.main.data.tests.results.fontSize + ' paddingSides: ' + mp.main.data.tests.results.padding);
}
}
}
}
var Load;
if (window.attachEvent) {
Load =function ( elem, event, handler ) {
elem.attachEvent( 'on'+event, function load() {
handler();
elem.detachEvent( 'on'+event, load );
});
};
} else {
Load =function ( elem, event, handler ) {
elem.addEventListener( event, function load() {
handler();
elem.removeEventListener( event, load, false );
}, false);
};
}
Load(window, 'load', function() {
var MP = new MyProgram();
MP.main.test();
});
You are simply printing
mp.main.data.tests.results.fontSize
instead of
mp.main.data.tests.results[i].fontSize
The code is correct for acceptable but you forgot the [i] part for fontSize and padding.

responsive top-bar navigation with mootools

i am working with mootools , and with foundation as my css "framework".
i am using the navigation top-bar from foundation and its great. yet the responsive design was ruined.
since i am not working with jquery ....
http://jsfiddle.net/idanhen/3LXQb/ <-- this is the foundation code.
http://foundation.zurb.com/docs/navigation.php <- navigation documentation
i cant understand the jquery script they did to convert it.
anyone know of a mootools responsive navigation bar ?
Made it myself , thought i would share if someone will ever need it .
original file is : "jquery.foundation.topbar.js"
new file is : "mootools.foundation.topbar.js"
just add foundation.css
mootools-core-1.4.5 , mootools-more-1.4.0.1 ( i have both cause its a huge project , but i guess u can only use the core ... )
mootools.foundation.topbar.js
and ofcourse run the following command :
<script type="text/javascript">
window.addEvent('domready', function() {
window.foundationTopBar();
});
</script>
"mootools.foundation.topbar.js" :
`
/**
* mootools.foundation.topbar
*
* taken from foundation.topbar.js
* http://foundation.zurb.com
*
* Written by Idan Hen : idandush#gmail.com
*/
;(function ($, window, undefined) {
'use strict';
/* just create settings object */
var settings = {
index : 0,
breakPoint : 940, // Set to to 9999 to force it into responsive always
initialized : false
};
var methods = {
init : function (options) {
return function () {
settings = Object.merge(settings, options); //settings = $.extend(settings, options);
settings.window = window;
settings.topbar = $$('nav.top-bar');
settings.titlebar = settings.topbar.getChildren('ul')[0]; // getElement() just return #
if (!settings.initialized) {
methods.assemble();
settings.initialized = true;
}
if (!settings.height) {
methods.largestUL();
}
$$('.top-bar .toggle-topbar').getParent().addEvent('click.fndtn:relay(.top-bar .toggle-topbar)', function (e) { //live switched to addEvent
e.preventDefault();
if (methods.breakpoint()) {
settings.topbar.toggleClass('expanded');
settings.topbar.setStyle('min-height', ''); //css
}
});
// Show the Dropdown Levels on Click
$$('.top-bar .has-dropdown>a').getParent().addEvent('click.fndtn:relay(.top-bar .has-dropdown>a)', function (e) {
e.preventDefault();
if (methods.breakpoint()) {
var anchor = $(this),
selectedLi = anchor.getParent('li'), // closest -> getParent
section = anchor.getParents('section')[0],// closest -> getParents
largestUl;
settings.index += 1;
selectedLi.addClass('moved');
section.setStyle('left', -(100 * settings.index) + '%');
section.getElements('>.name').setStyle('left', 100 * settings.index + '%');
//outerHeight
anchor.getSiblings('ul').setStyle('height', (settings.height + settings.titlebar.getSize().y));
settings.topbar.setStyle('min-height', settings.height + settings.titlebar.getSize().y * 2) //outerHeight
}
});
// Go up a level on Click
$$('.top-bar .has-dropdown .back').getParent().addEvent('click.fndtn:relay(.top-bar .has-dropdown .back)', function (e) {
e.preventDefault();
var anchor = $(this),
movedLi = anchor.getParent('li.moved'),
section = anchor.getParents('section')[0],
previousLevelUl = movedLi.getParent();
settings.index -= 1;
section.setStyle('left', -(100 * settings.index) + '%'); //css
section.getElements('>.name').setStyle('left', 100 * settings.index + '%'); // find
if (settings.index === 0) {
settings.topbar.setStyle('min-height', 0); // changed topbar from $topbar
}
setTimeout(function () {
movedLi.removeClass('moved');
}, 300);
});
}.call(window.document.HTMLDocument);
},
breakpoint : function () {
return settings.window.getSize().x < settings.breakPoint; //width()
},
assemble : function assemble() {
var section = settings.topbar.getElements('section')[0];
// Pull element out of the DOM for manipulation
section = section.dispose(); //detach
//console.log('section.getElements.n>a : ', section.getElements('.has-dropdown>a'));
section.getElements('.has-dropdown>a').each(function(e){
e.each(function (e) {
//console.log('section' , section);
var link = $(e),
dropdown = link.getSiblings('.dropdown'), //siblings
//<li class="title back js-generated"><h5></h5></li>
a = new Element('a', {
href: '#'
}),
h5 = new Element('h5', {}),
titleLi = new Element('li', {
'class': 'title back js-generated'
});//section.getChildren('ul li');// back js-generated');
// console.log('dropdown: ', dropdown);
h5.grab(a);
titleLi.grab(h5);
// Copy link to subnav
titleLi.getElements('h5>a').set('html', (link.get('html') ) ); // find -> getElements
dropdown.grab(titleLi, 'top');
});
});
// Put element back in the DOM
settings.topbar[0].grab(section[0]); // section.appendTo(settings.topbar);
},
largestUL : function () {
var uls = settings.topbar[0].getElements('section ul ul'), // find -> getElements
largest = uls.getFirst(),
total = 0;
uls.each(function(ul){
if (ul.getChildren('li').length > largest.getChildren('li').length) { //length -> getSize().x
largest = ul;
}
});
largest.getChildren('li').each(function (li) { total += li.getComputedSize().height; }); //outerHeight(true); -> getSize().y
settings.height = total;
}
};
/**
* this function is added to the window -> need to add it myself
* apply is call ...
*/
window.foundationTopBar = function (method)
{
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.foundationTopBar');
}
};
}($, this));
`

Javascript “confirm” in IE6 and IE7

Why doesn't this code work in IE6 or IE7?
$('a').click(
function()
{
var urlIsExternal = true;
var urlMedicareDir = '/medicare/';
var urlMedicareHost = 'health.healthcare.com';
var urlMedicare = 'https://' + urlMedicareHost + urlMedicareDir;
var urlAppsHost = 'apps.healthcare.com';
var urlCurrent = String( window.location );
var urlCurrentPrefix = urlCurrent.substring( 0, urlMedicare.length );
var urlCurrentURL = $.url( urlCurrent );
var urlClicked = $(this).attr('href');
var urlClickedURL = $.url( $(this).attr('href') );
var urlHost = urlClickedURL.attr('host');
if( !urlHost.length )
{
urlHost = urlCurrentURL.attr('host');
}
var urlConfirmMessage = 'You are now leaving the Medicare website.';
if( urlCurrentPrefix == urlMedicare )
{
if( urlClicked.substring( 0, 1 ) == '/' ) // starts with slash
{
if( urlClicked.substring( 0, urlMedicareDir.length ) == urlMedicareDir )
{
urlIsExternal = false;
}
}
if( urlClicked.substring( 0, urlMedicare.length ) == urlMedicare )
{
urlIsExternal = false;
}
if (
urlClicked.substring( 0, 1 ) != '/' &&
urlClicked.substring( 0, 4 ) != 'http' &&
urlClicked.substring( 0, 4 ) != 'file'
)
{
urlIsExternal = false;
}
if( urlAppsHost == urlHost )
{
urlIsExternal = false;
}
if( urlClicked.substring(urlClicked.length-4) == '.pdf' )
{
urlIsExternal = false;
}
}
else
{
urlIsExternal = false;
}
if( urlIsExternal )
{
if( confirm( urlConfirmMessage ) )
{
window.open( urlClicked );
return false;
}
else
{
return false;
}
}
else
{
return true;
}
}
);
For some reason when the links are clicked in IE6 or IE7, they do not direct the user to the link and it does not prompt a confirm dialog. It should prompt a confirm dialog, but for some reason, it is not.
I don't think you're preventing the default action of the anchor ("a").
You should start $('a').click( function( event ) { so that when you get here:
if( urlIsExternal ) {
// This tells jQuery to NOT follow the hyperlink
event.preventDefault();
if( confirm( urlConfirmMessage ) ) {
window.open( urlClicked );
}
}
However, what's really missing is that this code needs to run after the document has loaded. So you just need to wrap your function with
$(document).ready(function(){
$('a').click( function( event ) {
/* your code */
}
});
Without the call to $(document).ready(), the JavaScript runs before the body of the document is rendered, so it doesn't find any <a> tags to which it can attach the click event.
It seems that if the user clicks on a link that has an href starting with some value other than the current host, you want offer a confirm dialog. That is a realy annoying strategy, why doesn't the user know before clicking on the link that it wil take them elsewhere?
Anyway, a simple version of what you are trying to do is:
function showPrompt() {
return confirm('Do you really want to leaving ' + window.location.host +
'?\nPress OK to continue or Cancel to stay on this page.');
}
window.onload = function() {
// The links collection is live and available as a property of window
var link, links = document.links;
// Include criteria for host, hostName, protocol, whatever as required
var re = new RegExp(window.location.host || 'no host');
for (var i=0, iLen=links.length; i<iLen; i++) {
link = links[i];
// Only add the listener to links that need it
if (!re.test(link.href)) {
// Add the listener however you want, this way is simple and robust
link.onclick = showPrompt;
}
}
}

"$.______ is not a function" error. What is wrong?

I'm trying to add an image rotator to my site but for some reason firebug tells me the function I need to call to start the rotator isn't defined. My jQuery file is loading just fine and the image rotator script is loading so I'm not sure what is wrong. The site is heritage.newcoastmedia.com but I'll go ahead and post the script:
;(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options) {
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 5000;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
});
And here is the script to start the image rotator:
<script language="javascript">
$(document).ready(function() {
$.featureList(
$("#tabs li a"),
$("#output li"), {
start_item : 1
}
);
});
</script>
Your code creates an anonymous function, but doesn't call it.
You need to call the function by adding (jQuery) at the end.
You cannot do $.featureList(
See Chrome error:
The plugin needs to applied to an object
You've just slightly missed out on the right syntax for creating a plugin. What you really want is:
(function($) {
$.fn.featureList = function() { // etc; }
$.featureList = function() { // yet more etc; }
})(jQuery);

stand-alone lazy loading images (no framework based)

I look after a site which by nature has to load quite a lot of images and content on the page. We have decreased the number of elements and graphical layout images as much as we can, so we are now looking at ways to increase the page load in the browser.
Does anyone know any code for lazy loading images that doesn't require a framework such as jQuery?
Here is my own. Have Fun.
Tested: IE 5.5+, FF 2+, Chrome, Opera 9.6+
Usage:
your lazyloaded images should have their real src in a thumb attribute
Just include the javascript file inline or externally.
If you don't want to use it on your entire page, you can do:
LazyImg().destroy(); // stop global fetching
LazyImg("watch-only-this-div");
Note: when you include the file a global instance is already created watchin the whole document. You need to stop that first and start you own instance.
set a custom offset for prefetching (how far below the fold the image should be fetched)
// watch the whole document
// prefetch offset: 300px
LazyImg(document, 300);
Code:
//
// LAZY Loading Images
//
// Handles lazy loading of images in one or more targeted divs,
// or in the entire page. It also keeps track of scrolling and
// resizing events, and removes itself if the work is done.
//
// Licensed under the terms of the MIT license.
//
// (c) 2010 Balázs Galambosi
//
(function(){
// glocal variables
var window = this,
instances = {},
winH;
// cross browser event handling
function addEvent( el, type, fn ) {
if ( window.addEventListener ) {
el.addEventListener( type, fn, false );
} else if ( window.attachEvent ) {
el.attachEvent( "on" + type, fn );
} else {
var old = el["on" + type];
el["on" + type] = function() { old(); fn(); };
}
}
// cross browser event handling
function removeEvent( el, type, fn ) {
if ( window.removeEventListener ) {
el.removeEventListener( type, fn, false );
} else if ( window.attachEvent ) {
el.detachEvent( "on" + type, fn );
}
}
// cross browser window height
function getWindowHeight() {
if ( window.innerHeight ) {
winH = window.innerHeight;
} else if ( document.documentElement.clientHeight ) {
winH = document.documentElement.clientHeight;
} else if ( document.body && document.body.clientHeight ) {
winH = document.body.clientHeight;
} else { // fallback:
winH = 10000; // just load all the images
}
return winH;
}
// getBoundingClientRect alternative
function findPos(obj) {
var top = 0;
if (obj && obj.offsetParent) {
do {
top += obj.offsetTop || 0;
top -= obj.scrollTop || 0;
} while (obj = obj.offsetParent); //
return { "top" : top };
}
}
// top position of an element
var getTopPos = (function() {
var dummy = document.createElement("div");
if ( dummy.getBoundingClientRect ) {
return function( el ) {
return el.$$top || el.getBoundingClientRect().top;
};
} else {
return function( el ) {
return el.$$top || findPos( el ).top;
};
}
})();
// sorts images by their vertical positions
function img_sort( a, b ) {
return getTopPos( a ) - getTopPos( b );
}
// let's just provide some interface
// for the outside world
var LazyImg = function( target, offset ) {
var imgs, // images array (ordered)
last, // last visible image (index)
id, // id of the target element
self; // this instance
offset = offset || 200; // for prefetching
if ( !target ) {
target = document;
id = "$document";
} else if ( typeof target === "string" ) {
id = target;
target = document.getElementById( target );
} else {
id = target.id || "$undefined";
}
// return if this instance already exists
if ( instances[id] ) {
return instances[id];
}
// or make a new instance
self = instances[id] = {
// init & reset
init: function() {
imgs = null;
last = 0;
addEvent( window, "scroll", self.fetchImages );
self.fetchImages();
return this;
},
destroy: function() {
removeEvent( window, "scroll", self.fetchImages );
delete instances[id];
},
// fetches images, starting at last (index)
fetchImages: function() {
var img, temp, len, i;
// still trying to get the target
target = target || document.getElementById( id );
// if it's the first time
// initialize images array
if ( !imgs && target ) {
temp = target.getElementsByTagName( "img" );
if ( temp.length ) {
imgs = [];
len = temp.length;
} else return;
// fill the array for sorting
for ( i = 0; i < len; i++ ) {
img = temp[i];
if ( img.nodeType === 1 && img.getAttribute("thumb") ) {
// store them and cache current
// positions for faster sorting
img.$$top = getTopPos( img );
imgs.push( img );
}
}
imgs.sort( img_sort );
}
// loop through the images
while ( imgs[last] ) {
img = imgs[last];
// delete cached position
if ( img.$$top ) img.$$top = null;
// check if the img is above the fold
if ( getTopPos( img ) < winH + offset ) {
// then change the src
img.src = img.getAttribute("thumb");
last++;
}
else return;
}
// we've fetched the last image -> finished
if ( last && last === imgs.length ) {
self.destroy();
}
}
};
return self.init();
};
// initialize
getWindowHeight();
addEvent( window, "load", LazyImg().fetchImages );
addEvent( window, "resize", getWindowHeight );
LazyImg();
window.LazyImg = LazyImg;
}());
"thumb" does not validate when using XHTML. I changed it to "title" and it seems to be working ok.

Categories

Resources