Created
March 8, 2011 13:26
-
-
Save mklabs/860253 to your computer and use it in GitHub Desktop.
new version with (nearly) detailled information of albumtable script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Script for albumtable.html template | |
| */ | |
| $(document).ready(function() { | |
| $("#voteInfo").hide(); | |
| $('#albumList').dataTable(); | |
| //album covers | |
| $.each($('.cover'), function(){ | |
| var album = $(this).parent().parent().attr("id"); | |
| //album id | |
| var id = album.substring(6); | |
| //displayCover(id, $(this)); | |
| }); | |
| //vote link | |
| $('a.voteLink').click(function(){ | |
| var albumId = parseInt(this.id); | |
| clickVote(albumId); | |
| //only one vote is possible for an album | |
| $('#'+albumId+'-clickVote').hide(); | |
| }); | |
| }); | |
| var clickVote = function(id) { | |
| $.ajax({ | |
| url: '/vote', | |
| type: "POST", | |
| data: 'id=' + id, | |
| complete: function(req) { | |
| //success | |
| if (req.status == 200) { | |
| var newTotal = req.responseText; | |
| $('#nbVotes'+id).text(newTotal); | |
| $("#voteInfo").slideDown("slow").delay(3000).slideUp("slow"); | |
| } | |
| } | |
| }); | |
| }; | |
| var displayCover = function(id, albumMarkup){ | |
| var root = '/public/shared/covers'; | |
| var markup = '<img src="' + root + '/' + id + '" width="200" height="197">'; | |
| albumMarkup.bt(markup, | |
| { | |
| width: 200, | |
| fill: 'white', | |
| cornerRadius: 20, | |
| padding: 20, | |
| strokeWidth: 1, | |
| trigger: ['mouseover', 'click'] | |
| }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * albumtable.js refactored | |
| * | |
| * 1. No need to define those function (clickVote, displayCover) globally. This is an anti-pattern. Use the closure block scope | |
| * to not pollute the global namespace. | |
| * - prefer using var name = function() {} rather than function name() {} due to js hoisting behaviour. It's preferable | |
| * to declare functions this way and prior use. Always a good idea to follows the single var pattern, as it mades clear | |
| * which variables are used within the scope of this function. | |
| * 2. Beware of how scopes work in javascript. Blocks don't have scope (unlike java), only functions does. Declaring var in an if | |
| * or for statement for instance is considered an anti-pattern. | |
| * 3. IDs versus Classes | |
| * - always a confusing thing for most of web developpers. | |
| * - IDs should only be used where there is only one kind of element in a page (#header, #footer, #main, ...) | |
| * - Classes are preferable since they allow simpler modular code and promotes re-usability. | |
| * 4. parseInt function | |
| * - never forget the often unknown second parameter which is radix (var intValue = parseInt(string[, radix]);). While this | |
| * parameter is optional, always specify it to eliminate reader confusion and to guarantee predictable behavior. Different | |
| * implementations produce different results when a radix is not specified. Javascript does funny assumption depending on | |
| * the input string (try with something beginning with 0x, 0X , 0, aha) | |
| * | |
| * | |
| * jQuery | |
| * 1. One of the first thing we should understand with jQuery is how it works and behaves. | |
| * - ($ is an alias to the jQuery function) the $ functions is not magic! It does pretty good stuff but it does | |
| * not prevent you from doing non-optimal stuff (like re-querying the dom for something we juste have already). | |
| * - each time $ is invoked against a selector, it could return you an instance of jQuery that is a "collection" (an array) of | |
| * 0, 1 or more elements. The value returned by the $ method could and should be "cached" in a variable for further use. Even though | |
| * jQuery is pretty efficient, it is a performance costly to unnecessary query the dom again and again (just like it is when you deal with | |
| * db operation). | |
| * - | |
| * 2. Hiding on page load is considered bad practice as the use could see it before js even begin to execute, use css class instead in the | |
| * server-side generated markup(really just a display: none). | |
| * 3. $.each / $.fn.each: http://api.jquery.com/each | |
| * | |
| * | |
| * | |
| * General | |
| * 1. Mixing html markup and JS is considered bad practice. | |
| * 2. Always defined your script in a wrapping closure. use parameters to enforce the identity of $ (and possibly munging others) | |
| * | |
| */ | |
| (function($, global) { | |
| $(document).ready(function() { | |
| var voteInfo = $('#voteInfo'), | |
| voteLink = $('a.voteLink'), | |
| list = $('#albumList'), | |
| covers = $('.cover'), | |
| nbVotes = $('span[id^="nbVotes"]'), | |
| clickVote = function(e) { | |
| /* * / | |
| function(){ | |
| var albumId = parseInt(this.id, 10); // do not forget radix, btw why bother parseInt? | |
| clickVote(albumId); | |
| // only one vote is possible for an album | |
| $('#'+albumId+'-clickVote').hide(); | |
| } | |
| /* */ | |
| // in this context, e.target is the same as this | |
| var t = $(e.target), | |
| id = t.attr('id').split('-')[0], | |
| voteTarget = nbVotes.filter("[id$=" + id + "]"); | |
| // only one vote is possible for an album | |
| // why requery the dom???? You already have a reference to that this bro.. | |
| // $('#'+albumId+'-clickVote').hide(); | |
| t.hide(); // $(this).hide() or $(e.target) | |
| $.ajax({ | |
| url: '/vote', | |
| type: "POST", | |
| // use hash object instead | |
| // data: 'id=' + id, | |
| data: {id: id}, | |
| complete: function(req) { | |
| // beware of js particular scope | |
| var newTotal = req.responseText; | |
| if (req.status === 200) { | |
| voteTarget.text(newTotal); | |
| // even better, use css3 anims to do that | |
| voteInfo.slideDown("slow").delay(3000).slideUp("slow"); | |
| } | |
| } | |
| }); | |
| }, | |
| displayCover = function(id, albumMarkup){ | |
| var root = '/public/shared/covers'; | |
| // Mixing html markup and JS is considered bad practice. | |
| var markup = '<img src="' + root + '/' + id + '" width="200" height="197">'; | |
| albumMarkup.bt(markup, { | |
| width: 200, | |
| fill: 'white', | |
| cornerRadius: 20, | |
| padding: 20, | |
| strokeWidth: 1, | |
| trigger: ['mouseover', 'click'] | |
| }); | |
| }; | |
| // Hiding on page load is considered bad practice as the use could see it before js even begin to execute, use css instead. | |
| // voteInfo.hide(); | |
| list.dataTable(); | |
| covers.each(function(i, val) { | |
| // same there always cache, especially in a loop | |
| var t = $(this); | |
| // ids are bad, especially to store app's data (used to determine img src path). | |
| // prefer using html5 data-attribute. Since jQuery 1.4, $.data method handle them gracefully. | |
| // also. prefer using the super nifty closest method | |
| // var album = t.parent().parent().attr("id"); | |
| var album = t.closest('tr').attr("id"); | |
| // get album id: regex ftw. substring is so ... | |
| //var id = album.substring(6); | |
| var id = album.match(/album-(\d)/)[1]; | |
| displayCover(id, t); | |
| }); | |
| /** jQuery plugin version of the previous stuff... since we're iterating on a collection and doing some stuff (calling another plugin..) ** / | |
| $.fn.displayCover = function(o) { | |
| // default options, merge in with user defined options (o) | |
| var options = $.extend({ | |
| root: '/public/shared/covers', | |
| imgTmpl: '<img src="/public/shared/covers/${id}" width="200" height="197">' | |
| }, o); | |
| if(!this.length) { | |
| return; // don't act on absent element | |
| } | |
| return this.each(function(i, el) { | |
| var t = $(this), // = el | |
| albumId = t.closest('tr').attr('id').match(/album-(\d+)/)[1]; | |
| t.bt(options.imgTmpl.replace("${id}", albumId), { | |
| width: 200, | |
| fill: 'white', | |
| cornerRadius: 20, | |
| padding: 20, | |
| strokeWidth: 1, | |
| trigger: ['mouseover', 'click'] | |
| }); | |
| }); | |
| }; | |
| Use: $('.cover').displayCover(); //... use it (or not!) | |
| /* */ | |
| // vote link | |
| // why not considering clickVote as the event handler? | |
| /* * / | |
| voteLink.click(function(){ | |
| var albumId = parseInt(this.id, 10); // do not forget radix | |
| clickVote(albumId); | |
| // only one vote is possible for an album | |
| $('#'+albumId+'-clickVote').hide(); | |
| }); | |
| /* */ | |
| // Use it with $.proxy for even more flexibility (and possibly get some organization) | |
| voteLink.click(clickVote); | |
| // even more cool, use event delegation to handle links (especially links in a table) | |
| // voteLink.live('click', clickVote) | |
| // even more cool, use the new delegate event | |
| // $(".my-super-awesome-table").deleaget('a.voteLink', 'click', clickVote) | |
| }); | |
| })(this.jQuery, this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment