From dd019fed64d41909772eed3ee2ae4869944c9256 Mon Sep 17 00:00:00 2001 From: Markus Amalthea Magnuson Date: Sun, 3 Mar 2013 15:10:15 +0100 Subject: [PATCH 1/3] Code style adherence, mostly whitespace changes. * Spaces to tabs. * Some removal of empty lines where code is a bit to sparse, and insertion where a bit too dense. * Reflow a couple of code comments. * Remove any trailing whitespace. --- .../beware-anonymous-functions.md | 45 +-- page/code-organization/concepts.md | 302 ++++++++---------- page/code-organization/deferreds.md | 36 +-- page/code-organization/deferreds/examples.md | 275 ++++++++-------- .../deferreds/jquery-deferreds.md | 48 +-- .../code-organization/dont-repeat-yourself.md | 28 +- .../feature-browser-detection.md | 26 +- 7 files changed, 355 insertions(+), 405 deletions(-) diff --git a/page/code-organization/beware-anonymous-functions.md b/page/code-organization/beware-anonymous-functions.md index 8ce056b9..2532a69f 100644 --- a/page/code-organization/beware-anonymous-functions.md +++ b/page/code-organization/beware-anonymous-functions.md @@ -13,44 +13,33 @@ your handlers and callbacks. // BAD $( document ).ready(function() { - $("#magic").click(function( event ) { + $( "#magic" ).click(function( event ) { + $( "#yayeffects" ).slideUp(function() { + // ... + }); + }); - $("#yayeffects").slideUp(function() { - - // ... - - }); - - }); - - $("#happiness").load( url + " #unicorns", function() { - - // ... - - }); + $( "#happiness" ).load( url + " #unicorns", function() { + // ... + }); }); // BETTER var PI = { - onReady : function() { - - $("#magic").click( PI.candyMtn ); - - $("#happiness").load( PI.url + " #unicorns", PI.unicornCb ); - - }, - - candyMtn : function( event ) { - - $("#yayeffects").slideUp( PI.slideCb ); + onReady: function() { + $( "#magic" ).click( PI.candyMtn ); + $( "#happiness" ).load( PI.url + " #unicorns", PI.unicornCb ); + }, - }, + candyMtn: function( event ) { + $( "#yayeffects" ).slideUp( PI.slideCb ); + }, - slideCb : function() { ... }, + slideCb: function() { ... }, - unicornCb : function() { ... } + unicornCb: function() { ... } }; diff --git a/page/code-organization/concepts.md b/page/code-organization/concepts.md index 612a479b..fb61e41a 100644 --- a/page/code-organization/concepts.md +++ b/page/code-organization/concepts.md @@ -51,16 +51,21 @@ options, and easing the path to reuse and refactoring. ``` // An object literal var myFeature = { - myProperty: "hello", - myMethod: function() { - console.log( myFeature.myProperty ); - }, - init: function( settings ) { - myFeature.settings = settings; - }, - readSettings : function() { - console.log( myFeature.settings ); - } + + myProperty: "hello", + + myMethod: function() { + console.log( myFeature.myProperty ); + }, + + init: function( settings ) { + myFeature.settings = settings; + }, + + readSettings: function() { + console.log( myFeature.settings ); + } + }; myFeature.myProperty === "hello"; // true @@ -68,7 +73,7 @@ myFeature.myProperty === "hello"; // true myFeature.myMethod(); // "hello" myFeature.init({ - foo: "bar" + foo: "bar" }); myFeature.readSettings(); // { foo: "bar" } @@ -84,28 +89,18 @@ How would we apply this pattern to jQuery code? Let's say that we had this code written in the traditional jQuery style: ``` -// clicking on a list item loads some content -// using the list item's ID and hides content -// in sibling list items +// clicking on a list item loads some content using the +// list item's ID, and hides content in sibling list items $( document ).ready(function() { - $("#myFeature li").append("
").click(function() { - - var $this = $( this ); - - var $div = $this.find("div"); - - $div.load( "foo.php?item=" + $this.attr("id"), function() { - - $div.show(); - - $this.siblings().find("div").hide(); - - } - - ); - - }); + $( "#myFeature li" ).append( "
" ).click(function() { + var $this = $( this ); + var $div = $this.find( "div" ); + $div.load( "foo.php?item=" + $this.attr( "id" ), function() { + $div.show(); + $this.siblings().find( "div" ).hide(); + }); + }); }); ``` @@ -121,76 +116,53 @@ functionality later. // Using an object literal for a jQuery feature var myFeature = { - init : function( settings ) { - - myFeature.config = { - $items : $("#myFeature li"), - $container : $("
"), - urlBase : "/foo.php?item=" - }; - - // allow overriding the default config - $.extend( myFeature.config, settings ); - - myFeature.setup(); - - }, - - setup : function() { - - myFeature.config.$items.each( myFeature.createContainer ).click( myFeature.showItem ); - - }, - - createContainer : function() { - - var $i = $( this ); - - var $c = myFeature.config.$container.clone().appendTo( $i ); - - $i.data( "container", $c ); - - }, - - buildUrl : function() { - - return myFeature.config.urlBase + myFeature.$currentItem.attr("id"); - - }, - - showItem : function() { - - var myFeature.$currentItem = $( this ); - - myFeature.getContent( myFeature.showContent ); - - }, - - getContent : function( callback ) { - - var url = myFeature.buildUrl(); - - myFeature.$currentItem.data("container").load( url, callback ); - - }, - - showContent : function() { - - myFeature.$currentItem.data("container").show(); - - myFeature.hideContent(); - - }, - - hideContent : function() { - - myFeature.$currentItem.siblings().each(function() { - - $( this ).data("container").hide(); - - }); - - } + init: function( settings ) { + myFeature.config = { + $items: $( "#myFeature li" ), + $container: $( "
" ), + urlBase: "/foo.php?item=" + }; + + // allow overriding the default config + $.extend( myFeature.config, settings ); + + myFeature.setup(); + }, + + setup: function() { + myFeature.config.$items.each( myFeature.createContainer ).click( myFeature.showItem ); + }, + + createContainer: function() { + var $i = $( this ); + var $c = myFeature.config.$container.clone().appendTo( $i ); + $i.data( "container", $c ); + }, + + buildUrl: function() { + return myFeature.config.urlBase + myFeature.$currentItem.attr( "id" ); + }, + + showItem: function() { + var myFeature.$currentItem = $( this ); + myFeature.getContent( myFeature.showContent ); + }, + + getContent: function( callback ) { + var url = myFeature.buildUrl(); + myFeature.$currentItem.data( "container" ).load( url, callback ); + }, + + showContent: function() { + myFeature.$currentItem.data( "container" ).show(); + myFeature.hideContent(); + }, + + hideContent: function() { + myFeature.$currentItem.siblings().each(function() { + $( this ).data( "container" ).hide(); + }); + } }; @@ -227,31 +199,30 @@ desired. // The module pattern var feature = (function() { - // private variables and functions - var privateThing = "secret"; - var publicThing = "not secret"; - var changePrivateThing = function() { - privateThing = "super secret"; - }; + // private variables and functions + var privateThing = "secret"; + var publicThing = "not secret"; - var sayPrivateThing = function() { - console.log( privateThing ); - changePrivateThing(); - }; + var changePrivateThing = function() { + privateThing = "super secret"; + }; - // public API - return { - publicThing: publicThing, - sayPrivateThing: sayPrivateThing - }; + var sayPrivateThing = function() { + console.log( privateThing ); + changePrivateThing(); + }; + + // public API + return { + publicThing: publicThing, + sayPrivateThing: sayPrivateThing + }; })(); feature.publicThing; // "not secret" - -// logs "secret" and changes the value -// of privateThing +// logs "secret" and changes the value of privateThing feature.sayPrivateThing(); ``` @@ -276,47 +247,56 @@ of the module, `showItemByIndex()`. // Using the module pattern for a jQuery feature $( document ).ready(function() { - var feature = (function() { - - var $items = $("#myFeature li"); - var $container = $("
"); - var $currentItem = null; - var urlBase = "/foo.php?item="; - var createContainer = function() { - var $i = $( this ); - var $c = $container.clone().appendTo( $i ); - $i.data( "container", $c ); - }, - buildUrl = function() { - return urlBase + $currentItem.attr("id"); - }, - showItem = function() { - $currentItem = $( this ); - getContent( showContent ); - }, - showItemByIndex = function( idx ) { - $.proxy( showItem, $items.get( idx ) ); - }, - getContent = function( callback ) { - $currentItem.data("container").load( buildUrl(), callback ); - }, - showContent = function() { - $currentItem.data("container").show(); - hideContent(); - }, - hideContent = function() { - $currentItem.siblings().each(function() { - $( this ).data("container").hide(); - }); - }; - $items.each( createContainer ).click( showItem ); - - return { - showItemByIndex: showItemByIndex - }; - - })(); - - feature.showItemByIndex( 0 ); + var feature = (function() { + + var $items = $( "#myFeature li" ); + var $container = $( "
" ); + var $currentItem = null; + var urlBase = "/foo.php?item="; + + var createContainer = function() { + var $i = $( this ); + var $c = $container.clone().appendTo( $i ); + $i.data( "container", $c ); + }, + + buildUrl = function() { + return urlBase + $currentItem.attr( "id" ); + }, + + showItem = function() { + $currentItem = $( this ); + getContent( showContent ); + }, + + showItemByIndex = function( idx ) { + $.proxy( showItem, $items.get( idx ) ); + }, + + getContent = function( callback ) { + $currentItem.data( "container" ).load( buildUrl(), callback ); + }, + + showContent = function() { + $currentItem.data( "container" ).show(); + hideContent(); + }, + + hideContent = function() { + $currentItem.siblings().each(function() { + $( this ).data( "container" ).hide(); + }); + }; + + $items.each( createContainer ).click( showItem ); + + return { + showItemByIndex: showItemByIndex + }; + + })(); + + feature.showItemByIndex( 0 ); + }); ``` diff --git a/page/code-organization/deferreds.md b/page/code-organization/deferreds.md index 5e10b597..bed7d934 100644 --- a/page/code-organization/deferreds.md +++ b/page/code-organization/deferreds.md @@ -42,11 +42,11 @@ may look like: promise = callToAPI( arg1, arg2, ...); promise.then(function( futureValue ) { - /* handle futureValue */ + /* handle futureValue */ }); promise.then(function( futureValue ) { - /* do something else */ + /* do something else */ }); ``` @@ -62,11 +62,11 @@ promise was resolved, another for when the promise was rejected. If we get back to pseudo-code, we may do things like: ``` -promise.then( function( futureValue ) { - /* we got a value */ -} , function() { - /* something went wrong */ -} ); +promise.then(function( futureValue ) { + /* we got a value */ +}, function() { + /* something went wrong */ +}); ``` In the case of certain applications, it is necessary to have several @@ -78,11 +78,11 @@ action once all the promises have been fully fulfilled: ``` when( - promise1, - promise2, - ... + promise1, + promise2, + ... ).then(function( futureValue1, futureValue2, ... ) { - /* all promises have completed and are resolved */ + /* all promises have completed and are resolved */ }); ``` @@ -96,14 +96,14 @@ of this means it's a trivial process to execute a single callback once the animations are done. For example: ``` -var promise1 = $("#id1").animate().promise(); -var promise2 = $("#id2").animate().promise(); +var promise1 = $( "#id1" ).animate().promise(); +var promise2 = $( "#id2" ).animate().promise(); when( - promise1, - promise2 -).then(function(){ - /* once both animations have completed - we can then run our additional logic */ + promise1, + promise2 +).then(function() { + /* once both animations have completed + we can then run our additional logic */ }); ``` diff --git a/page/code-organization/deferreds/examples.md b/page/code-organization/deferreds/examples.md index 5ab68e62..e969992b 100644 --- a/page/code-organization/deferreds/examples.md +++ b/page/code-organization/deferreds/examples.md @@ -37,12 +37,12 @@ system to properly handle both complete and inbound requests. var cachedScriptPromises = {}; $.cachedGetScript = function( url, callback ) { - if ( !cachedScriptPromises[ url ] ) { - cachedScriptPromises[ url ] = $.Deferred(function( defer ) { - $.getScript( url ).then( defer.resolve, defer.reject ); - }).promise(); - } - return cachedScriptPromises[ url ].done( callback ); + if ( !cachedScriptPromises[ url ] ) { + cachedScriptPromises[ url ] = $.Deferred(function( defer ) { + $.getScript( url ).then( defer.resolve, defer.reject ); + }).promise(); + } + return cachedScriptPromises[ url ].done( callback ); }; ``` @@ -66,15 +66,15 @@ when a key isn't in the cache yet: ``` $.createCache = function( requestFunction ) { - var cache = {}; - return function( key, callback ) { - if ( !cache[ key ] ) { - cache[ key ] = $.Deferred(function( defer ) { - requestFunction( defer, key ); - }).promise(); - } - return cache[ key ].done( callback ); - }; + var cache = {}; + return function( key, callback ) { + if ( !cache[ key ] ) { + cache[ key ] = $.Deferred(function( defer ) { + requestFunction( defer, key ); + }).promise(); + } + return cache[ key ].done( callback ); + }; } ``` @@ -83,7 +83,7 @@ as follows: ``` $.cachedGetScript = $.createCache(function( defer, url ) { - $.getScript( url ).then( defer.resolve, defer.reject ); + $.getScript( url ).then( defer.resolve, defer.reject ); }); ``` @@ -96,16 +96,16 @@ A cache can be used to ensure that the same image is not loaded multiple times. ``` $.loadImage = $.createCache(function( defer, url ) { - var image = new Image(); - function cleanUp() { - image.onload = image.onerror = null; - } - defer.then( cleanUp, cleanUp ); - image.onload = function() { - defer.resolve( url ); - }; - image.onerror = defer.reject; - image.src = url; + var image = new Image(); + function cleanUp() { + image.onload = image.onerror = null; + } + defer.then( cleanUp, cleanUp ); + image.onload = function() { + defer.resolve( url ); + }; + image.onerror = defer.reject; + image.src = url; }); ``` @@ -126,15 +126,15 @@ page are also perfect candidates. For instance, the following: ``` $.searchTwitter = $.createCache(function( defer, query ) { - $.ajax({ - url: "http://search.twitter.com/search.json", - data: { - q: query - }, - dataType: "jsonp", - success: defer.resolve, - error: defer.reject - }); + $.ajax({ + url: "http://search.twitter.com/search.json", + data: { + q: query + }, + dataType: "jsonp", + success: defer.resolve, + error: defer.reject + }); }); ``` @@ -161,21 +161,21 @@ following caching system: ``` var readyTime; - + $(function() { - readyTime = jQuery.now(); + readyTime = jQuery.now(); }); - + $.afterDOMReady = $.createCache(function( defer, delay ) { - delay = delay || 0; - $(function() { - var delta = $.now() - readyTime; - if ( delta >= delay ) { - defer.resolve(); - } else { - setTimeout( defer.resolve, delay - delta ); - } - }); + delay = delay || 0; + $(function() { + var delta = $.now() - readyTime; + if ( delta >= delay ) { + defer.resolve(); + } else { + setTimeout( defer.resolve, delay - delta ); + } + }); }); ``` @@ -196,13 +196,13 @@ dealing with such a situation, one usually end up with code like this: ``` var buttonClicked = false; - + $( "#myButton" ).click(function() { - if ( !buttonClicked ) { - buttonClicked = true; - initializeData(); - showPanel(); - } + if ( !buttonClicked ) { + buttonClicked = true; + initializeData(); + showPanel(); + } }); ``` @@ -211,7 +211,7 @@ opened: ``` if ( buttonClicked ) { - /* perform specific action */ + /* perform specific action */ } ``` @@ -228,18 +228,18 @@ multiple event types): ``` $.fn.bindOnce = function( event, callback ) { - var element = $( this[ 0 ] ), - defer = element.data( "bind_once_defer_" + event ); - if ( !defer ) { - defer = $.Deferred(); - function deferCallback() { - element.unbind( event, deferCallback ); - defer.resolveWith( this, arguments ); - } - element.bind( event, deferCallback ) - element.data( "bind_once_defer_" + event , defer ); - } - return defer.done( callback ).promise(); + var element = $( this[ 0 ] ), + defer = element.data( "bind_once_defer_" + event ); + if ( !defer ) { + defer = $.Deferred(); + function deferCallback() { + element.unbind( event, deferCallback ); + defer.resolveWith( this, arguments ); + } + element.bind( event, deferCallback ) + element.data( "bind_once_defer_" + event , defer ); + } + return defer.done( callback ).promise(); }; ``` @@ -258,7 +258,7 @@ But let's define a helper method first: ``` $.fn.firstClick = function( callback ) { - return this.bindOnce( "click", callback ); + return this.bindOnce( "click", callback ); }; ``` @@ -266,7 +266,7 @@ Then the logic can be re-factored as follows: ``` var openPanel = $( "#myButton" ).firstClick(); - + openPanel.done( initializeData ); openPanel.done( showPanel ); ``` @@ -275,7 +275,7 @@ If an action should be performed only when a panel is opened later on: ``` openPanel.done(function() { - /* perform specific action */ + /* perform specific action */ }); ``` @@ -296,13 +296,13 @@ the helpers defined earlier, it could be defined as: ``` $( "#myButton" ).firstClick(function() { - var panel = $( "#myPanel" ); - $.when( - $.get( "panel.html" ), - panel.slideDownPromise() - ).done(function( ajaxResponse ) { - panel.html( ajaxResponse[ 0 ] ).fadeIn(); - }); + var panel = $( "#myPanel" ); + $.when( + $.get( "panel.html" ), + panel.slideDownPromise() + ).done(function( ajaxResponse ) { + panel.html( ajaxResponse[ 0 ] ).fadeIn(); + }); }); ``` @@ -315,10 +315,10 @@ The html code for this would look something like: ```
- - - - + + + +
``` @@ -327,31 +327,30 @@ The code to handle our use case using our promise helpers is as follows: ``` $( "#myButton" ).firstClick(function() { - - var panel = $( "#myPanel" ), - promises = []; - - $( "img", panel ).each(function() { - var image = $( this ), - src = element.attr( "data-src" ); - if ( src ) { - promises.push( - $.loadImage( src ).then( function() { - image.attr( "src", src ); - }, function() { - image.attr( "src", "error.png" ); - } ) - ); - } - }); - - promises.push( - panel.slideDownPromise() - ); - - $.when.apply( null, promises ).done(function() { - panel.fadeIn(); - }); + var panel = $( "#myPanel" ), + promises = []; + + $( "img", panel ).each(function() { + var image = $( this ), + src = element.attr( "data-src" ); + if ( src ) { + promises.push( + $.loadImage( src ).then(function() { + image.attr( "src", src ); + }, function() { + image.attr( "src", "error.png" ); + }) + ); + } + }); + + promises.push( + panel.slideDownPromise() + ); + + $.when.apply( null, promises ).done(function() { + panel.fadeIn(); + }); }); ``` @@ -367,10 +366,10 @@ In order to implement deferred image display on the entire page, the following format in HTML can be used. ``` - - - - + + + + ``` What it says is pretty straight-forward: @@ -383,21 +382,21 @@ What it says is pretty straight-forward: ``` $( "img" ).each(function() { - var element = $( this ), - src = element.attr( "data-src" ), - after = element.attr( "data-after" ); - if ( src ) { - $.when( - $.loadImage( src ), - $.afterDOMReady( after ) - ).then(function() { - element.attr( "src", src ); - }, function() { - element.attr( "src", "error.png" ); - } ).done(function() { - element.fadeIn(); - }); - } + var element = $( this ), + src = element.attr( "data-src" ), + after = element.attr( "data-after" ); + if ( src ) { + $.when( + $.loadImage( src ), + $.afterDOMReady( after ) + ).then(function() { + element.attr( "src", src ); + }, function() { + element.attr( "src", "error.png" ); + }).done(function() { + element.fadeIn(); + }); + } }); ``` @@ -405,20 +404,20 @@ In order to delay the loading of the images themselves: ``` $( "img" ).each(function() { - var element = $( this ), - src = element.attr( "data-src" ), - after = element.attr( "data-after" ); - if ( src ) { - $.afterDOMReady( after, function() { - $.loadImage( src ).then(function() { - element.attr( "src", src ); - }, function() { - element.attr( "src", "error.png" ); - } ).done(function() { - element.fadeIn(); - }); - } ); - } + var element = $( this ), + src = element.attr( "data-src" ), + after = element.attr( "data-after" ); + if ( src ) { + $.afterDOMReady( after, function() { + $.loadImage( src ).then(function() { + element.attr( "src", src ); + }, function() { + element.attr( "src", "error.png" ); + }).done(function() { + element.fadeIn(); + }); + }); + } }); ``` diff --git a/page/code-organization/deferreds/jquery-deferreds.md b/page/code-organization/deferreds/jquery-deferreds.md index e37c5a19..1f9e3ba0 100644 --- a/page/code-organization/deferreds/jquery-deferreds.md +++ b/page/code-organization/deferreds/jquery-deferreds.md @@ -46,17 +46,17 @@ conjunction with .then(): ``` function successFunc(){ - console.log( "success!" ); -} + console.log( "success!" ); +} function failureFunc(){ - console.log( "failure!" ); + console.log( "failure!" ); } $.when( - $.ajax( "/main.php" ), - $.ajax( "/modules.php" ), - $.ajax( "/lists.php" ) + $.ajax( "/main.php" ), + $.ajax( "/modules.php" ), + $.ajax( "/lists.php" ) ).then( successFunc, failureFunc ); ``` @@ -79,34 +79,34 @@ reactions. ``` function getLatestNews() { - return $.get( "latestNews.php", function(data){ - console.log( "news data received" ); - $( ".news" ).html(data); - } ); + return $.get( "latestNews.php", function( data ) { + console.log( "news data received" ); + $( ".news" ).html( data ); + }); } function getLatestReactions() { - return $.get( "latestReactions.php", function(data){ - console.log( "reactions data received" ); - $( ".reactions" ).html(data); - } ); + return $.get( "latestReactions.php", function( data ) { + console.log( "reactions data received" ); + $( ".reactions" ).html( data ); + }); } function prepareInterface() { - return $.Deferred(function( dfd ) { - var latest = $( ".news, .reactions" ); - latest.slideDown( 500, dfd.resolve ); - latest.addClass( "active" ); - }).promise(); + return $.Deferred(function( dfd ) { + var latest = $( ".news, .reactions" ); + latest.slideDown( 500, dfd.resolve ); + latest.addClass( "active" ); + }).promise(); } $.when( - getLatestNews(), - getLatestReactions(), - prepareInterface() + getLatestNews(), + getLatestReactions(), + prepareInterface() ).then(function(){ - console.log( "fire after requests succeed" ); + console.log( "fire after requests succeed" ); }).fail(function(){ - console.log( "something went wrong!" ); + console.log( "something went wrong!" ); }); ``` diff --git a/page/code-organization/dont-repeat-yourself.md b/page/code-organization/dont-repeat-yourself.md index 320575dd..1fe45dea 100644 --- a/page/code-organization/dont-repeat-yourself.md +++ b/page/code-organization/dont-repeat-yourself.md @@ -9,34 +9,24 @@ Don't repeat yourself; if you're repeating yourself, you're doing it wrong. ``` // BAD -if ( $eventfade.data("currently") !== "showing" ) { - - $eventfade.stop(); - +if ( $eventfade.data( "currently" ) !== "showing" ) { + $eventfade.stop(); } -if ( $eventhover.data("currently") !== "showing" ) { - - $eventhover.stop(); - +if ( $eventhover.data( "currently" ) !== "showing" ) { + $eventhover.stop(); } -if ( $spans.data("currently") !== "showing" ) { - - $spans.stop(); - +if ( $spans.data( "currently" ) !== "showing" ) { + $spans.stop(); } // GOOD!! var $elems = [ $eventfade, $eventhover, $spans ]; $.each( $elems, function( i, elem ) { - - if ( elem.data("currently") !== "showing" ) { - - elem.stop(); - - } - + if ( elem.data( "currently" ) !== "showing" ) { + elem.stop(); + } }); ``` diff --git a/page/code-organization/feature-browser-detection.md b/page/code-organization/feature-browser-detection.md index 58f5d095..b31484ee 100644 --- a/page/code-organization/feature-browser-detection.md +++ b/page/code-organization/feature-browser-detection.md @@ -61,16 +61,12 @@ Let's take a look at how to check whether or not a `` element exists in ``` // We want to show a graph in browsers that support canvas, // but a data table in browsers that don't. -var elem = document.createElement("canvas"); - -if ( elem.getContext && elem.getContext("2d") ) { - - showGraph(); +var elem = document.createElement( "canvas" ); +if ( elem.getContext && elem.getContext( "2d" ) ) { + showGraph(); } else { - - showTable(); - + showTable(); } ``` @@ -96,13 +92,9 @@ For example, utilizing Modernizr, we are able to do the same canvas detection te ``` if ( Modernizr.canvas ) { - - showGraphWithCanvas(); - + showGraphWithCanvas(); } else { - - showTable(); - + showTable(); } ``` @@ -116,9 +108,9 @@ The Modernizr object exposes a `load()` method that many prefer over the syntax ``` Modernizr.load({ - test: Modernizr.canvas, - yep : "canvas.js", - nope: "canvas-polyfill.js" + test: Modernizr.canvas, + yep: "canvas.js", + nope: "canvas-polyfill.js" }); ``` From f76b194fb2f4278cbeea8a14cf14ea9b0d9f20a5 Mon Sep 17 00:00:00 2001 From: Markus Amalthea Magnuson Date: Sun, 3 Mar 2013 15:13:59 +0100 Subject: [PATCH 2/3] Style and typography fixes. * Curly apostrophes and quotation marks. * Em dashes. * Remove any trailing whitespace. * Some capitalization. * Additional inline code Markdown for mentions of function names etc. --- .../beware-anonymous-functions.md | 4 +- page/code-organization/concepts.md | 50 +++++++-------- page/code-organization/deferreds.md | 32 +++++----- page/code-organization/deferreds/examples.md | 61 +++++++++---------- .../deferreds/jquery-deferreds.md | 41 ++++++------- .../code-organization/dont-repeat-yourself.md | 4 +- .../feature-browser-detection.md | 44 ++++++------- 7 files changed, 117 insertions(+), 119 deletions(-) diff --git a/page/code-organization/beware-anonymous-functions.md b/page/code-organization/beware-anonymous-functions.md index 2532a69f..ac8222c2 100644 --- a/page/code-organization/beware-anonymous-functions.md +++ b/page/code-organization/beware-anonymous-functions.md @@ -2,11 +2,11 @@ title: Beware Anonymous Functions level: beginner source: http://jqfundamentals.com/legacy -attribution: +attribution: - jQuery Fundamentals --- -Anonymous functions bound everywhere are a pain. They're difficult to debug, +Anonymous functions bound everywhere are a pain. They’re difficult to debug, maintain, test, or reuse. Instead, use an object literal to organize and name your handlers and callbacks. ``` diff --git a/page/code-organization/concepts.md b/page/code-organization/concepts.md index fb61e41a..4bd3a039 100644 --- a/page/code-organization/concepts.md +++ b/page/code-organization/concepts.md @@ -2,30 +2,30 @@ title: Code Organization Concepts level: beginner source: http://jqfundamentals.com/legacy -attribution: +attribution: - jQuery Fundamentals --- When you move beyond adding simple enhancements to your website with jQuery and start developing full-blown client-side applications, you need to consider how -to organize your code. In this chapter, we'll take a look at various code +to organize your code. In this chapter, we’ll take a look at various code organization patterns you can use in your jQuery application and explore the RequireJS dependency management and build system. ## Key Concepts -Before we jump into code organization patterns, it's important to understand +Before we jump into code organization patterns, it’s important to understand some concepts that are common to all good code organization patterns. -- Your code should be divided into units of functionality — modules, services, +- Your code should be divided into units of functionality — modules, services, etc. Avoid the temptation to have all of your code in one huge `$( document ).ready()` block. This concept, loosely, is known as encapsulation. -- Don't repeat yourself. Identify similarities among pieces of functionality, +- Don’t repeat yourself. Identify similarities among pieces of functionality, and use inheritance techniques to avoid repetitive code. -- Despite jQuery's DOM-centric nature, JavaScript applications are not all - about the DOM. Remember that not all pieces of functionality need to — or - should — have a DOM representation. +- Despite jQuery’s DOM-centric nature, JavaScript applications are not all + about the DOM. Remember that not all pieces of functionality need to — or + should — have a DOM representation. - Units of functionality should be [loosely coupled](http://en.wikipedia.org/wiki/Loose_coupling), that is, a unit of functionality should be able to exist on its own, and communication between units should be handled via a messaging system such as custom events or @@ -34,7 +34,7 @@ some concepts that are common to all good code organization patterns. The concept of loose coupling can be especially troublesome to developers making their first foray into complex applications, so be mindful of this as -you're getting started. +you’re getting started. ## Encapsulation @@ -44,7 +44,7 @@ into distinct pieces; sometimes, even just this effort is sufficient to lend ### The Object Literal An object literal is perhaps the simplest way to encapsulate related code. It -doesn't offer any privacy for properties or methods, but it's useful for +doesn’t offer any privacy for properties or methods, but it’s useful for eliminating anonymous functions from your code, centralizing configuration options, and easing the path to reuse and refactoring. @@ -82,10 +82,10 @@ myFeature.readSettings(); // { foo: "bar" } The object literal above is simply an object assigned to a variable. The object has one property and several methods. All of the properties and methods are public, so any part of your application can see the properties and call methods -on the object. While there is an init method, there's nothing requiring that it +on the object. While there is an init method, there’s nothing requiring that it be called before the object is functional. -How would we apply this pattern to jQuery code? Let's say that we had this code +How would we apply this pattern to jQuery code? Let’s say that we had this code written in the traditional jQuery style: ``` @@ -106,7 +106,7 @@ $( document ).ready(function() { ``` If this were the extent of our application, leaving it as-is would be fine. On -the other hand, if this was a piece of a larger application, we'd do well to +the other hand, if this was a piece of a larger application, we’d do well to keep this functionality separate from unrelated functionality. We might also want to move the URL out of the code and into a configuration area. Finally, we might want to break up the chain to make it easier to modify pieces of the @@ -169,23 +169,23 @@ var myFeature = { $( document ).ready( myFeature.init ); ``` -The first thing you'll notice is that this approach is obviously far longer -than the original -- again, if this were the extent of our application, using an -object literal would likely be overkill. Assuming it's not the extent of our -application, though, we've gained several things: +The first thing you’ll notice is that this approach is obviously far longer +than the original — again, if this were the extent of our application, using an +object literal would likely be overkill. Assuming it’s not the extent of our +application, though, we’ve gained several things: -- We've broken our feature up into tiny methods. In the future, if we want to - change how content is shown, it's clear where to change it. In the original +- We’ve broken our feature up into tiny methods. In the future, if we want to + change how content is shown, it’s clear where to change it. In the original code, this step is much harder to locate. -- We've eliminated the use of anonymous functions. -- We've moved configuration options out of the body of the code and put them in +- We’ve eliminated the use of anonymous functions. +- We’ve moved configuration options out of the body of the code and put them in a central location. -- We've eliminated the constraints of the chain, making the code easier to +- We’ve eliminated the constraints of the chain, making the code easier to refactor, remix, and rearrange. For non-trivial features, object literals are a clear improvement over a long stretch of code stuffed in a `$( document ).ready()` block, as they get us -thinking about the pieces of our functionality. However, they aren't a whole +thinking about the pieces of our functionality. However, they aren’t a whole lot more advanced than simply having a bunch of function declarations inside of that `$( document ).ready()` block. @@ -228,7 +228,7 @@ feature.sayPrivateThing(); In the example above, we self-execute an anonymous function that returns an object. Inside of the function, we define some variables. Because the variables -are defined inside of the function, we don't have access to them outside of the +are defined inside of the function, we don’t have access to them outside of the function unless we put them in the return object. This means that no code outside of the function has access to the `privateThing` variable or to the `changePrivateThing` function. However, `sayPrivateThing` does have access to @@ -237,7 +237,7 @@ scope as `sayPrivateThing`. This pattern is powerful because, as you can gather from the variable names, it can give you private variables and functions while exposing a limited API -consisting of the returned object's properties and methods. +consisting of the returned object’s properties and methods. Below is a revised version of the previous example, showing how we could create the same feature using the module pattern while only exposing one public method diff --git a/page/code-organization/deferreds.md b/page/code-organization/deferreds.md index bed7d934..03ae841e 100644 --- a/page/code-organization/deferreds.md +++ b/page/code-organization/deferreds.md @@ -2,14 +2,14 @@ title: Deferreds level: advanced source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx -attribution: +attribution: - Julian Aubourg - Addy Osmani - Andree Hansson --- At a high-level, deferreds can be thought of as a way to represent -asynchronous operations which can take a long time to complete. They're the +asynchronous operations which can take a long time to complete. They’re the asynchronous alternative to blocking functions and the general idea is that rather than your application blocking while it awaits some request to complete before returning a result, a deferred object can instead be @@ -18,22 +18,22 @@ object: they will be called once the request has actually completed. ##Promises -In its most basic form, a 'promise' is a model that provides a solution +In its most basic form, a “promise” is a model that provides a solution for the concept of deferred (or future) results in software engineering. -The main idea behind it is something we've already covered: rather than +The main idea behind it is something we’ve already covered: rather than executing a call which may result in blocking, we instead return a promise for a future value that will eventually be satisfied. If it helps to have an example here, consider that you are building a web application which heavily relies on data from a third party API. A -common problem that's faced is having an unknown knowledge of the API -server's latency at a given time so it's possible that other parts of +common problem that’s faced is having an unknown knowledge of the API +server’s latency at a given time so it’s possible that other parts of your application may be blocked from running until a result from it is returned. Deferreds provide a better solution to this problem, one which -is void of 'blocking' effects and completely decoupled. +is void of “blocking” effects and completely decoupled. The [Promise/A](http://wiki.commonjs.org/wiki/Promises/A) proposal -defines a method called 'then' that can be used to register callbacks to +defines a method called “then” that can be used to register callbacks to a promise and, thus, get the future result when it is available. The pseudo-code for dealing with a third party API that returns a promise may look like: @@ -44,7 +44,7 @@ promise = callToAPI( arg1, arg2, ...); promise.then(function( futureValue ) { /* handle futureValue */ }); - + promise.then(function( futureValue ) { /* do something else */ }); @@ -53,11 +53,11 @@ promise.then(function( futureValue ) { Furthermore, a promise can actually end up being in two different states: -- resolved: in which case data is available -- rejected: in which case something went wrong and no value is +- Resolved: in which case data is available +- Rejected: in which case something went wrong and no value is available -Thankfully, the 'then' method accepts two parameters: one for when the +Thankfully, the “then” method accepts two parameters: one for when the promise was resolved, another for when the promise was rejected. If we get back to pseudo-code, we may do things like: @@ -73,7 +73,7 @@ In the case of certain applications, it is necessary to have several results returned before your application can continue at all (for example, displaying a dynamic set of options on a screen before a user is able to select the option that interests them). Where this is the -case, a method called 'when' exists, which can be used to perform some +case, a method called “when” exists, which can be used to perform some action once all the promises have been fully fulfilled: ``` @@ -89,10 +89,10 @@ when( A good example is a scenario where you may have multiple concurrent animations that are being run. Without keeping track of each callback firing on completion, it can be difficult to truly establish once all -your animations have finished running. Using promises and 'when' however +your animations have finished running. Using promises and “when” however this is very straightforward as each of your animations can effectively -say 'we promise to let you know once we're done'. The compounded result -of this means it's a trivial process to execute a single callback once +say “we promise to let you know once we’re done”. The compounded result +of this means it’s a trivial process to execute a single callback once the animations are done. For example: ``` diff --git a/page/code-organization/deferreds/examples.md b/page/code-organization/deferreds/examples.md index e969992b..fbe36e59 100644 --- a/page/code-organization/deferreds/examples.md +++ b/page/code-organization/deferreds/examples.md @@ -2,7 +2,7 @@ title: Deferred examples level: advanced source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx -attribution: +attribution: - Julian Aubourg - Addy Osmani - Andree Hansson @@ -10,7 +10,7 @@ attribution: ##Further Deferreds examples -Deferreds are used behind the hood in Ajax but it doesn't mean they can't also +Deferreds are used behind the hood in Ajax but it doesn’t mean they can’t also be used elsewhere. This section describes situations where deferreds will help abstract away asynchronous behaviour and decouple our code. @@ -21,16 +21,16 @@ abstract away asynchronous behaviour and decouple our code. When it comes to asynchronous tasks, caching can be a bit demanding since you have to make sure a task is only performed once for a given key. As a consequence, the code has to somehow keep track of inbound -tasks. +tasks. ``` $.cachedGetScript( url, callback1 ); $.cachedGetScript( url, callback2 ); ``` -The caching mechanism has to make sure the url is only requested once -even if the script isn't in cache yet. This shows some logic -to keep track of callbacks bound to a given url in order for the cache +The caching mechanism has to make sure the URL is only requested once +even if the script isn’t in cache yet. This shows some logic +to keep track of callbacks bound to a given URL in order for the cache system to properly handle both complete and inbound requests. ``` @@ -46,7 +46,7 @@ $.cachedGetScript = function( url, callback ) { }; ``` -One promise is cached per url. If there is no promise for the given url yet, +One promise is cached per URL. If there is no promise for the given URL yet, then a deferred is created and the request is issued. If it already exists, however, the callback is attached to the existing deferred. The big advantage of this solution is that it will handle both complete and inbound requests @@ -62,7 +62,7 @@ $.cachedGetScript( url ).then( successCallback, errorCallback ); It is also possible to make the code completely generic and build a cache factory that will abstract out the actual task to be performed -when a key isn't in the cache yet: +when a key isn’t in the cache yet: ``` $.createCache = function( requestFunction ) { @@ -78,7 +78,7 @@ $.createCache = function( requestFunction ) { } ``` -Now that the request logic is abstracted away, cachedGetScript can be rewritten +Now that the request logic is abstracted away, `cachedGetScript` can be rewritten as follows: ``` @@ -87,7 +87,7 @@ $.cachedGetScript = $.createCache(function( defer, url ) { }); ``` -This will work because every call to createCache will create a new cache +This will work because every call to `createCache` will create a new cache repository and return a new cache-retrieval function. #### Image loading @@ -116,7 +116,7 @@ $.loadImage( "my-image.png" ).done( callback1 ); $.loadImage( "my-image.png" ).done( callback2 ); ``` -will work regardless of whether my-image.png has already been loaded or +will work regardless of whether `my-image.png` has already been loaded or not, or if it is actually in the process of being loaded. #### Caching Data API responses @@ -152,10 +152,10 @@ This deferred-based cache is not limited to network requests; it can also be used for timing purposes. For instance, you may need to perform an action on the page after a -given amount of time so as to attract the user's attention to a specific +given amount of time so as to attract the user’s attention to a specific feature they may not be aware of or deal with a timeout (for a quiz -question for instance). While setTimeout is good for most use-cases it -doesn't handle the situation when the timer is asked for later, even +question for instance). While `setTimeout` is good for most use-cases it +doesn’t handle the situation when the timer is asked for later, even after it has theoretically expired. We can handle that with the following caching system: @@ -179,7 +179,7 @@ $.afterDOMReady = $.createCache(function( defer, delay ) { }); ``` -The new afterDOMReady helper method provides proper timing after the DOM +The new `afterDOMReady` helper method provides proper timing after the DOM is ready while ensuring the bare minimum of timers will be used. If the delay is already expired, any callback will be called right away. @@ -216,9 +216,9 @@ if ( buttonClicked ) { ``` This is a very coupled solution. If you want to add some other action, -you have to edit the bind code or just duplicate it all. If you don't, -your only option is to test for buttonClicked and you may lose that new -action because the buttonClicked variable may be false and your new code +you have to edit the bind code or just duplicate it all. If you don’t, +your only option is to test for `buttonClicked` and you may lose that new +action because the `buttonClicked` variable may be false and your new code may never be executed. We can do much better using deferreds (for simplification sake, the @@ -245,7 +245,7 @@ $.fn.bindOnce = function( event, callback ) { The code works as follows: -- check if the element already has a deferred attached for the given +- Check if the element already has a deferred attached for the given event - if not, create it and make it so it is resolved when the event is fired the first time around @@ -254,7 +254,7 @@ The code works as follows: While the code is definitely more verbose, it makes dealing with the problem at hand much simpler in a compartmentalized and decoupled way. -But let's define a helper method first: +But let’s define a helper method first: ``` $.fn.firstClick = function( callback ) { @@ -279,7 +279,7 @@ openPanel.done(function() { }); ``` -Nothing is lost if the panel isn't opened yet, the action will just get +Nothing is lost if the panel isn’t opened yet, the action will just get deferred until the button is clicked. ### Combining helpers @@ -291,7 +291,7 @@ mix them together. #### Requesting panel content on first click and opening said panel Following is the code for a button that, when clicked, opens a panel. -It requests its content over the wire and then fades the content in. Using +It requests its content over the wire and then fades the content in. Using the helpers defined earlier, it could be defined as: ``` @@ -308,10 +308,10 @@ $( "#myButton" ).firstClick(function() { #### Loading images in a panel on first click and opening said panel -Another possible goal is to have the panel fade in, only after the button +Another possible goal is to have the panel fade in, only after the button has been clicked and after all of the images have been loaded. -The html code for this would look something like: +The HTML code for this would look something like: ```
@@ -322,7 +322,7 @@ The html code for this would look something like:
``` -We use the data-src attribute to keep track of the real image location. +We use the `data-src` attribute to keep track of the real image location. The code to handle our use case using our promise helpers is as follows: ``` @@ -354,9 +354,9 @@ $( "#myButton" ).firstClick(function() { }); ``` -The trick here is to keep track of all the loadImage promises. We later -join them with the panel slideDown animation using $.when. So when the -button is first clicked, the panel will slideDown and the images will +The trick here is to keep track of all the `loadImage` promises. We later +join them with the panel `slideDown` animation using `$.when`. So when the +button is first clicked, the panel will slide down and the images will start loading. Once the panel has finished sliding down and all the images have been loaded, then, and only then, will the panel fade in. @@ -374,12 +374,11 @@ the following format in HTML can be used. What it says is pretty straight-forward: -- load image1.png and show it immediately for the third image and +- Load `image1.png` and show it immediately for the third image and after one second for the first one -- load image2.png and show it after one second for the second image +- Load `image2.png` and show it after one second for the second image and after two seconds for the fourth image - ``` $( "img" ).each(function() { var element = $( this ), diff --git a/page/code-organization/deferreds/jquery-deferreds.md b/page/code-organization/deferreds/jquery-deferreds.md index 1f9e3ba0..94d2c63e 100644 --- a/page/code-organization/deferreds/jquery-deferreds.md +++ b/page/code-organization/deferreds/jquery-deferreds.md @@ -2,7 +2,7 @@ title: jQuery Deferreds level: advanced source: http://msdn.microsoft.com/en-us/magazine/gg723713.aspx -attribution: +attribution: - Julian Aubourg - Addy Osmani - Andree Hansson @@ -11,38 +11,38 @@ attribution: ##jQuery Deferreds Deferreds were added as a part of a large rewrite of the ajax module, -led by Julian Auborg following the CommonJS Promises/A design. Whilst 1.5 and +led by Julian Aubourg following the CommonJS Promises/A design. Whilst 1.5 and above include deferred capabilities, former versions of jQuery had -jQuery.ajax() accept callbacks that would be invoked upon completion or -error of the request, but suffered from heavy coupling - the same +`jQuery.ajax()` accept callbacks that would be invoked upon completion or +error of the request, but suffered from heavy coupling — the same principle that would drive developers using other languages or toolkits to opt for deferred execution. -In practice what jQuery's version provides you with are several +In practice what jQuery’s version provides you with are several enhancements to the way callbacks are managed, giving you significantly more flexible ways to provide callbacks that can be invoked whether the original callback dispatch has already fired or not. It is also worth -noting that jQuery's Deferred object supports having multiple callbacks +noting that jQuery’s Deferred object supports having multiple callbacks bound to the outcome of particular tasks (and not just one) where the task itself can either be synchronous or asynchronous. -At the heart of jQuery's implementation is jQuery.Deferred - a chainable +At the heart of jQuery’s implementation is `jQuery.Deferred` — a chainable constructor which is able to create new deferred objects that can check for the existence of a promise to establish whether the object can be observed. It can also invoke callback queues and pass on the success of -synchronous and asynchronous functions. It's quite essential to note -that the default state of any Deferred object is unresolved. Callbacks -which may be added to it through .then() or .fail() are queued up and get +synchronous and asynchronous functions. It’s quite essential to note +that the default state of any Deferred object is unresolved. Callbacks +which may be added to it through `.then()` or `.fail()` are queued up and get executed later on in the process. You are able to use Deferred objects in conjunction with the promise concept of -when(), implemented in jQuery as $.when() to wait for all of the Deferred -object's requests to complete executing (ie. for all of the promises to be -fulfilled). In technical terms, $.when() is effectively a way to execute +when(), implemented in jQuery as `$.when()` to wait for all of the Deferred +object’s requests to complete executing (i.e. for all of the promises to be +fulfilled). In technical terms, `$.when()` is effectively a way to execute callbacks based on any number of promises that represent asynchronous events. -An example of $.when() accepting multiple arguments can be seen below in -conjunction with .then(): +An example of `$.when()` accepting multiple arguments can be seen below in +conjunction with `.then()`: ``` function successFunc(){ @@ -60,23 +60,22 @@ $.when( ).then( successFunc, failureFunc ); ``` -The $.when() implementation offered in jQuery is quite interesting as it not +The `$.when()` implementation offered in jQuery is quite interesting as it not only interprets deferred objects, but when passed arguments that are not deferreds, it treats these as if they were resolved deferreds and executes any -callbacks (doneCallbacks) right away. It is also worth noting that jQuery's +callbacks (doneCallbacks) right away. It is also worth noting that jQuery’s deferred implementation, in addition to exposing deferred.then(), a jQuery promise also supports the deferred.done() and deferred.fail() methods which can -also be used to add callbacks to the deferred's queues. +also be used to add callbacks to the deferred’s queues. We will now take a look at a code example that utilizes many of the deferred features mentioned in the table presented earlier. Here is a very basic application that consumes (1) an external news feed and (2) a reactions feed -for pulling in the latest comments via $.get() (which will return a promise). -The application also has a function (prepareInterface()) which returns a +for pulling in the latest comments via `$.get()` (which will return a promise). +The application also has a function (`prepareInterface()`) which returns a promise to complete animating our containers for both the news and reactions. - ``` function getLatestNews() { return $.get( "latestNews.php", function( data ) { diff --git a/page/code-organization/dont-repeat-yourself.md b/page/code-organization/dont-repeat-yourself.md index 1fe45dea..ac6c0466 100644 --- a/page/code-organization/dont-repeat-yourself.md +++ b/page/code-organization/dont-repeat-yourself.md @@ -1,11 +1,11 @@ --- title: Keep Things DRY level: beginner -attribution: +attribution: source: http://jqfundamentals.com/legacy - jQuery Fundamentals --- -Don't repeat yourself; if you're repeating yourself, you're doing it wrong. +Don’t repeat yourself; if you’re repeating yourself, you’re doing it wrong. ``` // BAD diff --git a/page/code-organization/feature-browser-detection.md b/page/code-organization/feature-browser-detection.md index b31484ee..fb184839 100644 --- a/page/code-organization/feature-browser-detection.md +++ b/page/code-organization/feature-browser-detection.md @@ -5,34 +5,34 @@ level: beginner ### Can I Use This Browser Feature? -There are a couple of common ways to check whether or not a particular feature is supported by a user's browser: +There are a couple of common ways to check whether or not a particular feature is supported by a user’s browser: * Browser Detection * Specific Feature Detection -In general, we recommend specific feature detection. Let's look at why. +In general, we recommend specific feature detection. Let’s look at why. ### Browser Detection -Browser detection is a method where the browser's User Agent (UA) string is checked for a particular pattern unique to a browser family or version. For example, this is Chrome 18's UA string on Mac OS X Lion: +Browser detection is a method where the browser’s User Agent (UA) string is checked for a particular pattern unique to a browser family or version. For example, this is Chrome 18’s UA string on Mac OS X Lion: ``` Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19 ``` -Browser UA detection may check this string for something like "Chrome" or "Chrome/18" or any other part the developer feels identifies the browser they intend to target. +Browser UA detection may check this string for something like “Chrome” or “Chrome/18” or any other part the developer feels identifies the browser they intend to target. While this seems to be an easy solution, there are several problems: #### Other browsers other than your target may have the same issue. -If we target a specific browser for different functionality, we implicitly exclude any browser we did not account for. This is also not future-proof. If the browser we target receives a bug fix or change, we may not be able to discern between a 'working' and 'non-working' UA string. We may also need to update our test for each new release. This isn't a maintainable solution. +If we target a specific browser for different functionality, we implicitly exclude any browser we did not account for. This is also not future-proof. If the browser we target receives a bug fix or change, we may not be able to discern between a “working” and “non-working” UA string. We may also need to update our test for each new release. This isn’t a maintainable solution. #### User Agents are unreliable. -User Agents are set by the client browser. In the early days of the web, browsers would mimic each others' UA strings in order to bypass exactly this type of detection. It is still possible that a browser with very different capabilities may mimic just the portion of the UA string you're targeting. +User Agents are set by the client browser. In the early days of the web, browsers would mimic each others’ UA strings in order to bypass exactly this type of detection. It is still possible that a browser with very different capabilities may mimic just the portion of the UA string you’re targeting. -The UA string is also user-configurable. While the user may change this string, the browser's feature support remains the same. +The UA string is also user-configurable. While the user may change this string, the browser’s feature support remains the same. In general, we do not recommend UA string-based feature detection. @@ -51,12 +51,12 @@ Now how would you go about doing that? There are several ways to go about feature detection: * Straight JavaScript -* $.support +* `$.support` * A Helper Library #### Straight JavaScript -Let's take a look at how to check whether or not a `` element exists in a specific browser, without using a helper library. We do this by specifically querying whether the method or property exists: +Let’s take a look at how to check whether or not a `` element exists in a specific browser, without using a helper library. We do this by specifically querying whether the method or property exists: ``` // We want to show a graph in browsers that support canvas, @@ -70,19 +70,19 @@ if ( elem.getContext && elem.getContext( "2d" ) ) { } ``` -This is a very simple way to provide conditional experiences, depending on the features present in the user's browser. We can extract this into a helper function for reuse, but still have to write a test for every feature we're concerned about. This can be time-consuming and error-prone. +This is a very simple way to provide conditional experiences, depending on the features present in the user’s browser. We can extract this into a helper function for reuse, but still have to write a test for every feature we’re concerned about. This can be time-consuming and error-prone. What if someone else wrote all of that for us? #### $.support -jQuery performs many tests to determine feature support to allow cross-browser use of many of the features we've come to love. jQuery's internal feature detection can be accessed through [jQuery.support](http://api.jquery.com/jQuery.support/). +jQuery performs many tests to determine feature support to allow cross-browser use of many of the features we’ve come to love. jQuery’s internal feature detection can be accessed through [jQuery.support](http://api.jquery.com/jQuery.support/). However, we do not recommend this for general use. As the API page says: > Since jQuery requires these tests internally, they must be performed on every page load. Although some of these properties are documented below, they are not subject to a long deprecation/removal cycle and may be removed once internal jQuery code no longer needs them. -This detection may be removed from jQuery without notice. That's reason enough not to use it. What other options do we have? +This detection may be removed from jQuery without notice. That’s reason enough not to use it. What other options do we have? #### A Helper Library @@ -98,13 +98,13 @@ if ( Modernizr.canvas ) { } ``` -That's it. Easy. +That’s it. Easy. ### Performance Considerations -So, while the Modernizr syntax is great, it can end up being quite cumbersome to have several conditionals. Secondly, we're sending the code for both conditions to every browser, regardless if we'll need it or not. +So, while the Modernizr syntax is great, it can end up being quite cumbersome to have several conditionals. Secondly, we’re sending the code for both conditions to every browser, regardless if we’ll need it or not. -The Modernizr object exposes a `load()` method that many prefer over the syntax mentioned previously. This is due to the another library that Modernizr now uses internally: [yepnope](http://yepnopejs.com/). Testing for canvas can now become something like this: +The `Modernizr` object exposes a `load()` method that many prefer over the syntax mentioned previously. This is due to the another library that Modernizr now uses internally: [yepnope](http://yepnopejs.com/). Testing for canvas can now become something like this: ``` Modernizr.load({ @@ -116,21 +116,21 @@ Modernizr.load({ Using the `load` method allows us to send only the required polyfills and code over the wire. You can also pass an array of objects as an argument to `.load()`, and it will serve the correct files to the correct audience. -Additionally, Modernizr has a [production build configurator](http://modernizr.com/download/) that allows you to specify exactly what parts of Modernizr you want to include and exclude the parts you don't. +Additionally, Modernizr has a [production build configurator](http://modernizr.com/download/) that allows you to specify exactly what parts of Modernizr you want to include and exclude the parts you don’t. ### Other Resources #### Feature Detection Tools -- [modernizr](http://modernizr.com/) - conditionally check to see if a specific feature is available in a browser -- [html5please](http://html5please.com/) - use the new and shiny responsibly -- [html5please api](http://api.html5please.com/) - an API you can query to see how good (or bad) support for a specific feature is. -- [caniuse](http://caniuse.com/) - browser compatibility tables for HTML5, CSS3, SVG, etc… -- [yepnope](http://yepnopejs.com/) - conditional polyfill loader +- [modernizr](http://modernizr.com/) — Conditionally check to see if a specific feature is available in a browser. +- [html5please](http://html5please.com/) — Use the new and shiny responsibly. +- [html5please api](http://api.html5please.com/) — An API you can query to see how good (or bad) support for a specific feature is. +- [caniuse](http://caniuse.com/) — Browser compatibility tables for HTML5, CSS3, SVG, etc. +- [yepnope](http://yepnopejs.com/) — Conditional polyfill loader. #### Helpful Articles - [Browser Feature Detection](https://developer.mozilla.org/en-US/docs/Browser_Feature_Detection) - [Using Modernizr to detect HTML5 and CSS3 browser support](http://www.adobe.com/devnet/dreamweaver/articles/using-modernizr.html) - [polyfilling the html5 gap](http://addyosmani.com/polyfillthehtml5gaps/slides/#1) by Addy Osmani -- [Feature, Browser, and Form Factor Detection: It's Good for the Environment](http://www.html5rocks.com/en/tutorials/detection/index.html) by Michael Mahemoff +- [Feature, Browser, and Form Factor Detection: It’s Good for the Environment](http://www.html5rocks.com/en/tutorials/detection/index.html) by Michael Mahemoff From b3a3dc6af98e47982fc78f80f6db66c14539e2b4 Mon Sep 17 00:00:00 2001 From: Markus Amalthea Magnuson Date: Tue, 5 Mar 2013 01:05:08 +0100 Subject: [PATCH 3/3] No entities. --- .../beware-anonymous-functions.md | 2 +- page/code-organization/concepts.md | 48 +++++++++---------- page/code-organization/deferreds.md | 24 +++++----- page/code-organization/deferreds/examples.md | 16 +++---- .../deferreds/jquery-deferreds.md | 16 +++---- .../code-organization/dont-repeat-yourself.md | 2 +- .../feature-browser-detection.md | 40 ++++++++-------- 7 files changed, 74 insertions(+), 74 deletions(-) diff --git a/page/code-organization/beware-anonymous-functions.md b/page/code-organization/beware-anonymous-functions.md index ac8222c2..5890b408 100644 --- a/page/code-organization/beware-anonymous-functions.md +++ b/page/code-organization/beware-anonymous-functions.md @@ -6,7 +6,7 @@ attribution: - jQuery Fundamentals --- -Anonymous functions bound everywhere are a pain. They’re difficult to debug, +Anonymous functions bound everywhere are a pain. They're difficult to debug, maintain, test, or reuse. Instead, use an object literal to organize and name your handlers and callbacks. ``` diff --git a/page/code-organization/concepts.md b/page/code-organization/concepts.md index 4bd3a039..4de26973 100644 --- a/page/code-organization/concepts.md +++ b/page/code-organization/concepts.md @@ -8,24 +8,24 @@ attribution: When you move beyond adding simple enhancements to your website with jQuery and start developing full-blown client-side applications, you need to consider how -to organize your code. In this chapter, we’ll take a look at various code +to organize your code. In this chapter, we'll take a look at various code organization patterns you can use in your jQuery application and explore the RequireJS dependency management and build system. ## Key Concepts -Before we jump into code organization patterns, it’s important to understand +Before we jump into code organization patterns, it's important to understand some concepts that are common to all good code organization patterns. -- Your code should be divided into units of functionality — modules, services, +- Your code should be divided into units of functionality — modules, services, etc. Avoid the temptation to have all of your code in one huge `$( document ).ready()` block. This concept, loosely, is known as encapsulation. -- Don’t repeat yourself. Identify similarities among pieces of functionality, +- Don't repeat yourself. Identify similarities among pieces of functionality, and use inheritance techniques to avoid repetitive code. -- Despite jQuery’s DOM-centric nature, JavaScript applications are not all - about the DOM. Remember that not all pieces of functionality need to — or - should — have a DOM representation. +- Despite jQuery's DOM-centric nature, JavaScript applications are not all + about the DOM. Remember that not all pieces of functionality need to — or + should — have a DOM representation. - Units of functionality should be [loosely coupled](http://en.wikipedia.org/wiki/Loose_coupling), that is, a unit of functionality should be able to exist on its own, and communication between units should be handled via a messaging system such as custom events or @@ -34,7 +34,7 @@ some concepts that are common to all good code organization patterns. The concept of loose coupling can be especially troublesome to developers making their first foray into complex applications, so be mindful of this as -you’re getting started. +you're getting started. ## Encapsulation @@ -44,7 +44,7 @@ into distinct pieces; sometimes, even just this effort is sufficient to lend ### The Object Literal An object literal is perhaps the simplest way to encapsulate related code. It -doesn’t offer any privacy for properties or methods, but it’s useful for +doesn't offer any privacy for properties or methods, but it's useful for eliminating anonymous functions from your code, centralizing configuration options, and easing the path to reuse and refactoring. @@ -82,10 +82,10 @@ myFeature.readSettings(); // { foo: "bar" } The object literal above is simply an object assigned to a variable. The object has one property and several methods. All of the properties and methods are public, so any part of your application can see the properties and call methods -on the object. While there is an init method, there’s nothing requiring that it +on the object. While there is an init method, there's nothing requiring that it be called before the object is functional. -How would we apply this pattern to jQuery code? Let’s say that we had this code +How would we apply this pattern to jQuery code? Let's say that we had this code written in the traditional jQuery style: ``` @@ -106,7 +106,7 @@ $( document ).ready(function() { ``` If this were the extent of our application, leaving it as-is would be fine. On -the other hand, if this was a piece of a larger application, we’d do well to +the other hand, if this was a piece of a larger application, we'd do well to keep this functionality separate from unrelated functionality. We might also want to move the URL out of the code and into a configuration area. Finally, we might want to break up the chain to make it easier to modify pieces of the @@ -169,23 +169,23 @@ var myFeature = { $( document ).ready( myFeature.init ); ``` -The first thing you’ll notice is that this approach is obviously far longer -than the original — again, if this were the extent of our application, using an -object literal would likely be overkill. Assuming it’s not the extent of our -application, though, we’ve gained several things: +The first thing you'll notice is that this approach is obviously far longer +than the original — again, if this were the extent of our application, using an +object literal would likely be overkill. Assuming it's not the extent of our +application, though, we've gained several things: -- We’ve broken our feature up into tiny methods. In the future, if we want to - change how content is shown, it’s clear where to change it. In the original +- We've broken our feature up into tiny methods. In the future, if we want to + change how content is shown, it's clear where to change it. In the original code, this step is much harder to locate. -- We’ve eliminated the use of anonymous functions. -- We’ve moved configuration options out of the body of the code and put them in +- We've eliminated the use of anonymous functions. +- We've moved configuration options out of the body of the code and put them in a central location. -- We’ve eliminated the constraints of the chain, making the code easier to +- We've eliminated the constraints of the chain, making the code easier to refactor, remix, and rearrange. For non-trivial features, object literals are a clear improvement over a long stretch of code stuffed in a `$( document ).ready()` block, as they get us -thinking about the pieces of our functionality. However, they aren’t a whole +thinking about the pieces of our functionality. However, they aren't a whole lot more advanced than simply having a bunch of function declarations inside of that `$( document ).ready()` block. @@ -228,7 +228,7 @@ feature.sayPrivateThing(); In the example above, we self-execute an anonymous function that returns an object. Inside of the function, we define some variables. Because the variables -are defined inside of the function, we don’t have access to them outside of the +are defined inside of the function, we don't have access to them outside of the function unless we put them in the return object. This means that no code outside of the function has access to the `privateThing` variable or to the `changePrivateThing` function. However, `sayPrivateThing` does have access to @@ -237,7 +237,7 @@ scope as `sayPrivateThing`. This pattern is powerful because, as you can gather from the variable names, it can give you private variables and functions while exposing a limited API -consisting of the returned object’s properties and methods. +consisting of the returned object's properties and methods. Below is a revised version of the previous example, showing how we could create the same feature using the module pattern while only exposing one public method diff --git a/page/code-organization/deferreds.md b/page/code-organization/deferreds.md index 03ae841e..5317fa53 100644 --- a/page/code-organization/deferreds.md +++ b/page/code-organization/deferreds.md @@ -9,7 +9,7 @@ attribution: --- At a high-level, deferreds can be thought of as a way to represent -asynchronous operations which can take a long time to complete. They’re the +asynchronous operations which can take a long time to complete. They're the asynchronous alternative to blocking functions and the general idea is that rather than your application blocking while it awaits some request to complete before returning a result, a deferred object can instead be @@ -18,22 +18,22 @@ object: they will be called once the request has actually completed. ##Promises -In its most basic form, a “promise” is a model that provides a solution +In its most basic form, a "promise" is a model that provides a solution for the concept of deferred (or future) results in software engineering. -The main idea behind it is something we’ve already covered: rather than +The main idea behind it is something we've already covered: rather than executing a call which may result in blocking, we instead return a promise for a future value that will eventually be satisfied. If it helps to have an example here, consider that you are building a web application which heavily relies on data from a third party API. A -common problem that’s faced is having an unknown knowledge of the API -server’s latency at a given time so it’s possible that other parts of +common problem that's faced is having an unknown knowledge of the API +server's latency at a given time so it's possible that other parts of your application may be blocked from running until a result from it is returned. Deferreds provide a better solution to this problem, one which -is void of “blocking” effects and completely decoupled. +is void of "blocking" effects and completely decoupled. The [Promise/A](http://wiki.commonjs.org/wiki/Promises/A) proposal -defines a method called “then” that can be used to register callbacks to +defines a method called "then" that can be used to register callbacks to a promise and, thus, get the future result when it is available. The pseudo-code for dealing with a third party API that returns a promise may look like: @@ -57,7 +57,7 @@ states: - Rejected: in which case something went wrong and no value is available -Thankfully, the “then” method accepts two parameters: one for when the +Thankfully, the "then" method accepts two parameters: one for when the promise was resolved, another for when the promise was rejected. If we get back to pseudo-code, we may do things like: @@ -73,7 +73,7 @@ In the case of certain applications, it is necessary to have several results returned before your application can continue at all (for example, displaying a dynamic set of options on a screen before a user is able to select the option that interests them). Where this is the -case, a method called “when” exists, which can be used to perform some +case, a method called "when" exists, which can be used to perform some action once all the promises have been fully fulfilled: ``` @@ -89,10 +89,10 @@ when( A good example is a scenario where you may have multiple concurrent animations that are being run. Without keeping track of each callback firing on completion, it can be difficult to truly establish once all -your animations have finished running. Using promises and “when” however +your animations have finished running. Using promises and "when" however this is very straightforward as each of your animations can effectively -say “we promise to let you know once we’re done”. The compounded result -of this means it’s a trivial process to execute a single callback once +say "we promise to let you know once we're done". The compounded result +of this means it's a trivial process to execute a single callback once the animations are done. For example: ``` diff --git a/page/code-organization/deferreds/examples.md b/page/code-organization/deferreds/examples.md index fbe36e59..31ddce78 100644 --- a/page/code-organization/deferreds/examples.md +++ b/page/code-organization/deferreds/examples.md @@ -10,7 +10,7 @@ attribution: ##Further Deferreds examples -Deferreds are used behind the hood in Ajax but it doesn’t mean they can’t also +Deferreds are used behind the hood in Ajax but it doesn't mean they can't also be used elsewhere. This section describes situations where deferreds will help abstract away asynchronous behaviour and decouple our code. @@ -29,7 +29,7 @@ $.cachedGetScript( url, callback2 ); ``` The caching mechanism has to make sure the URL is only requested once -even if the script isn’t in cache yet. This shows some logic +even if the script isn't in cache yet. This shows some logic to keep track of callbacks bound to a given URL in order for the cache system to properly handle both complete and inbound requests. @@ -62,7 +62,7 @@ $.cachedGetScript( url ).then( successCallback, errorCallback ); It is also possible to make the code completely generic and build a cache factory that will abstract out the actual task to be performed -when a key isn’t in the cache yet: +when a key isn't in the cache yet: ``` $.createCache = function( requestFunction ) { @@ -152,10 +152,10 @@ This deferred-based cache is not limited to network requests; it can also be used for timing purposes. For instance, you may need to perform an action on the page after a -given amount of time so as to attract the user’s attention to a specific +given amount of time so as to attract the user's attention to a specific feature they may not be aware of or deal with a timeout (for a quiz question for instance). While `setTimeout` is good for most use-cases it -doesn’t handle the situation when the timer is asked for later, even +doesn't handle the situation when the timer is asked for later, even after it has theoretically expired. We can handle that with the following caching system: @@ -216,7 +216,7 @@ if ( buttonClicked ) { ``` This is a very coupled solution. If you want to add some other action, -you have to edit the bind code or just duplicate it all. If you don’t, +you have to edit the bind code or just duplicate it all. If you don't, your only option is to test for `buttonClicked` and you may lose that new action because the `buttonClicked` variable may be false and your new code may never be executed. @@ -254,7 +254,7 @@ The code works as follows: While the code is definitely more verbose, it makes dealing with the problem at hand much simpler in a compartmentalized and decoupled way. -But let’s define a helper method first: +But let's define a helper method first: ``` $.fn.firstClick = function( callback ) { @@ -279,7 +279,7 @@ openPanel.done(function() { }); ``` -Nothing is lost if the panel isn’t opened yet, the action will just get +Nothing is lost if the panel isn't opened yet, the action will just get deferred until the button is clicked. ### Combining helpers diff --git a/page/code-organization/deferreds/jquery-deferreds.md b/page/code-organization/deferreds/jquery-deferreds.md index 94d2c63e..9b59237e 100644 --- a/page/code-organization/deferreds/jquery-deferreds.md +++ b/page/code-organization/deferreds/jquery-deferreds.md @@ -14,30 +14,30 @@ Deferreds were added as a part of a large rewrite of the ajax module, led by Julian Aubourg following the CommonJS Promises/A design. Whilst 1.5 and above include deferred capabilities, former versions of jQuery had `jQuery.ajax()` accept callbacks that would be invoked upon completion or -error of the request, but suffered from heavy coupling — the same +error of the request, but suffered from heavy coupling — the same principle that would drive developers using other languages or toolkits to opt for deferred execution. -In practice what jQuery’s version provides you with are several +In practice what jQuery's version provides you with are several enhancements to the way callbacks are managed, giving you significantly more flexible ways to provide callbacks that can be invoked whether the original callback dispatch has already fired or not. It is also worth -noting that jQuery’s Deferred object supports having multiple callbacks +noting that jQuery's Deferred object supports having multiple callbacks bound to the outcome of particular tasks (and not just one) where the task itself can either be synchronous or asynchronous. -At the heart of jQuery’s implementation is `jQuery.Deferred` — a chainable +At the heart of jQuery's implementation is `jQuery.Deferred` — a chainable constructor which is able to create new deferred objects that can check for the existence of a promise to establish whether the object can be observed. It can also invoke callback queues and pass on the success of -synchronous and asynchronous functions. It’s quite essential to note +synchronous and asynchronous functions. It's quite essential to note that the default state of any Deferred object is unresolved. Callbacks which may be added to it through `.then()` or `.fail()` are queued up and get executed later on in the process. You are able to use Deferred objects in conjunction with the promise concept of when(), implemented in jQuery as `$.when()` to wait for all of the Deferred -object’s requests to complete executing (i.e. for all of the promises to be +object's requests to complete executing (i.e. for all of the promises to be fulfilled). In technical terms, `$.when()` is effectively a way to execute callbacks based on any number of promises that represent asynchronous events. @@ -63,10 +63,10 @@ $.when( The `$.when()` implementation offered in jQuery is quite interesting as it not only interprets deferred objects, but when passed arguments that are not deferreds, it treats these as if they were resolved deferreds and executes any -callbacks (doneCallbacks) right away. It is also worth noting that jQuery’s +callbacks (doneCallbacks) right away. It is also worth noting that jQuery's deferred implementation, in addition to exposing deferred.then(), a jQuery promise also supports the deferred.done() and deferred.fail() methods which can -also be used to add callbacks to the deferred’s queues. +also be used to add callbacks to the deferred's queues. We will now take a look at a code example that utilizes many of the deferred features mentioned in the table presented earlier. Here is a very basic diff --git a/page/code-organization/dont-repeat-yourself.md b/page/code-organization/dont-repeat-yourself.md index ac6c0466..71881083 100644 --- a/page/code-organization/dont-repeat-yourself.md +++ b/page/code-organization/dont-repeat-yourself.md @@ -5,7 +5,7 @@ attribution: source: http://jqfundamentals.com/legacy - jQuery Fundamentals --- -Don’t repeat yourself; if you’re repeating yourself, you’re doing it wrong. +Don't repeat yourself; if you're repeating yourself, you're doing it wrong. ``` // BAD diff --git a/page/code-organization/feature-browser-detection.md b/page/code-organization/feature-browser-detection.md index fb184839..67d7040d 100644 --- a/page/code-organization/feature-browser-detection.md +++ b/page/code-organization/feature-browser-detection.md @@ -5,34 +5,34 @@ level: beginner ### Can I Use This Browser Feature? -There are a couple of common ways to check whether or not a particular feature is supported by a user’s browser: +There are a couple of common ways to check whether or not a particular feature is supported by a user's browser: * Browser Detection * Specific Feature Detection -In general, we recommend specific feature detection. Let’s look at why. +In general, we recommend specific feature detection. Let's look at why. ### Browser Detection -Browser detection is a method where the browser’s User Agent (UA) string is checked for a particular pattern unique to a browser family or version. For example, this is Chrome 18’s UA string on Mac OS X Lion: +Browser detection is a method where the browser's User Agent (UA) string is checked for a particular pattern unique to a browser family or version. For example, this is Chrome 18's UA string on Mac OS X Lion: ``` Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19 ``` -Browser UA detection may check this string for something like “Chrome” or “Chrome/18” or any other part the developer feels identifies the browser they intend to target. +Browser UA detection may check this string for something like "Chrome" or "Chrome/18" or any other part the developer feels identifies the browser they intend to target. While this seems to be an easy solution, there are several problems: #### Other browsers other than your target may have the same issue. -If we target a specific browser for different functionality, we implicitly exclude any browser we did not account for. This is also not future-proof. If the browser we target receives a bug fix or change, we may not be able to discern between a “working” and “non-working” UA string. We may also need to update our test for each new release. This isn’t a maintainable solution. +If we target a specific browser for different functionality, we implicitly exclude any browser we did not account for. This is also not future-proof. If the browser we target receives a bug fix or change, we may not be able to discern between a "working" and "non-working" UA string. We may also need to update our test for each new release. This isn't a maintainable solution. #### User Agents are unreliable. -User Agents are set by the client browser. In the early days of the web, browsers would mimic each others’ UA strings in order to bypass exactly this type of detection. It is still possible that a browser with very different capabilities may mimic just the portion of the UA string you’re targeting. +User Agents are set by the client browser. In the early days of the web, browsers would mimic each others' UA strings in order to bypass exactly this type of detection. It is still possible that a browser with very different capabilities may mimic just the portion of the UA string you're targeting. -The UA string is also user-configurable. While the user may change this string, the browser’s feature support remains the same. +The UA string is also user-configurable. While the user may change this string, the browser's feature support remains the same. In general, we do not recommend UA string-based feature detection. @@ -56,7 +56,7 @@ There are several ways to go about feature detection: #### Straight JavaScript -Let’s take a look at how to check whether or not a `` element exists in a specific browser, without using a helper library. We do this by specifically querying whether the method or property exists: +Let's take a look at how to check whether or not a `` element exists in a specific browser, without using a helper library. We do this by specifically querying whether the method or property exists: ``` // We want to show a graph in browsers that support canvas, @@ -70,19 +70,19 @@ if ( elem.getContext && elem.getContext( "2d" ) ) { } ``` -This is a very simple way to provide conditional experiences, depending on the features present in the user’s browser. We can extract this into a helper function for reuse, but still have to write a test for every feature we’re concerned about. This can be time-consuming and error-prone. +This is a very simple way to provide conditional experiences, depending on the features present in the user's browser. We can extract this into a helper function for reuse, but still have to write a test for every feature we're concerned about. This can be time-consuming and error-prone. What if someone else wrote all of that for us? #### $.support -jQuery performs many tests to determine feature support to allow cross-browser use of many of the features we’ve come to love. jQuery’s internal feature detection can be accessed through [jQuery.support](http://api.jquery.com/jQuery.support/). +jQuery performs many tests to determine feature support to allow cross-browser use of many of the features we've come to love. jQuery's internal feature detection can be accessed through [jQuery.support](http://api.jquery.com/jQuery.support/). However, we do not recommend this for general use. As the API page says: > Since jQuery requires these tests internally, they must be performed on every page load. Although some of these properties are documented below, they are not subject to a long deprecation/removal cycle and may be removed once internal jQuery code no longer needs them. -This detection may be removed from jQuery without notice. That’s reason enough not to use it. What other options do we have? +This detection may be removed from jQuery without notice. That's reason enough not to use it. What other options do we have? #### A Helper Library @@ -98,11 +98,11 @@ if ( Modernizr.canvas ) { } ``` -That’s it. Easy. +That's it. Easy. ### Performance Considerations -So, while the Modernizr syntax is great, it can end up being quite cumbersome to have several conditionals. Secondly, we’re sending the code for both conditions to every browser, regardless if we’ll need it or not. +So, while the Modernizr syntax is great, it can end up being quite cumbersome to have several conditionals. Secondly, we're sending the code for both conditions to every browser, regardless if we'll need it or not. The `Modernizr` object exposes a `load()` method that many prefer over the syntax mentioned previously. This is due to the another library that Modernizr now uses internally: [yepnope](http://yepnopejs.com/). Testing for canvas can now become something like this: @@ -116,21 +116,21 @@ Modernizr.load({ Using the `load` method allows us to send only the required polyfills and code over the wire. You can also pass an array of objects as an argument to `.load()`, and it will serve the correct files to the correct audience. -Additionally, Modernizr has a [production build configurator](http://modernizr.com/download/) that allows you to specify exactly what parts of Modernizr you want to include and exclude the parts you don’t. +Additionally, Modernizr has a [production build configurator](http://modernizr.com/download/) that allows you to specify exactly what parts of Modernizr you want to include and exclude the parts you don't. ### Other Resources #### Feature Detection Tools -- [modernizr](http://modernizr.com/) — Conditionally check to see if a specific feature is available in a browser. -- [html5please](http://html5please.com/) — Use the new and shiny responsibly. -- [html5please api](http://api.html5please.com/) — An API you can query to see how good (or bad) support for a specific feature is. -- [caniuse](http://caniuse.com/) — Browser compatibility tables for HTML5, CSS3, SVG, etc. -- [yepnope](http://yepnopejs.com/) — Conditional polyfill loader. +- [modernizr](http://modernizr.com/) — Conditionally check to see if a specific feature is available in a browser. +- [html5please](http://html5please.com/) — Use the new and shiny responsibly. +- [html5please api](http://api.html5please.com/) — An API you can query to see how good (or bad) support for a specific feature is. +- [caniuse](http://caniuse.com/) — Browser compatibility tables for HTML5, CSS3, SVG, etc. +- [yepnope](http://yepnopejs.com/) — Conditional polyfill loader. #### Helpful Articles - [Browser Feature Detection](https://developer.mozilla.org/en-US/docs/Browser_Feature_Detection) - [Using Modernizr to detect HTML5 and CSS3 browser support](http://www.adobe.com/devnet/dreamweaver/articles/using-modernizr.html) - [polyfilling the html5 gap](http://addyosmani.com/polyfillthehtml5gaps/slides/#1) by Addy Osmani -- [Feature, Browser, and Form Factor Detection: It’s Good for the Environment](http://www.html5rocks.com/en/tutorials/detection/index.html) by Michael Mahemoff +- [Feature, Browser, and Form Factor Detection: It's Good for the Environment](http://www.html5rocks.com/en/tutorials/detection/index.html) by Michael Mahemoff