DrupalCon jQuery

9,246
-1

Published on

Presentation from DrupalCon 2011 in Chicago

Published in: Design

DrupalCon jQuery

  1. 1. CRAFTING APPINTERFACES WITH Presented by Nathan Smith
  2. 2. Carpal Tunnel ReliefNote: Don’t feel like you need to write all ofthis down. The slides are available here...http://www.slideshare.net/nathansmith/drupalcon-jquery
  3. 3. “Allow myself to... introduce myself” I work (from home) for HP as a front-end developer. I’m best known for making a helpful 5.6 KB CSS file.
  4. 4. Shh... My secret in-house code reviewer Note: This was shot hastily with a camera phone. I make no claims of being a decent photographer.
  5. 5. FYI – I don’t especially love CSSThe reason I create and use CSSframeworks is because I hate doingmundane tasks repeatedly (yawn).I’d rather be working in JavaScript.
  6. 6. JavaScript books I’ve worked on... Co-author Tech editor Tech editorjQueryEnlightenment.com JavaScriptEnlightenment.com oreilly.com/catalog/9780596159788
  7. 7. Our team at HP uses Sass to expedite writing CSS http://www.sass-lang.com
  8. 8. Sass compiles down to CSS...$blue: #3bbfce #foo {$margin: 20px border-color: #3bbfce; color: #2b9eab;#foo } border-color: $blue color: darken($blue, 9%) #foo .bar { .bar border-color: #3bbfce; border-color: $blue padding: 10px; margin: 10px; padding: $margin / 2 } margin: $margin / 2
  9. 9. But Sass isn’t a magic bullet (Because no framework is)Assuming you already know CSS,Sass can help you write CSS faster.But using Sass doesn’t magicallycreate “better” CSS. If you writebad code, Sass won’t remedy it.
  10. 10. The same principles apply to JavaScriptAn important discipline whenusing any framework is strivingto understand the underlyinglanguage. In other words, useit as a tool – Not a black box
  11. 11. Veteran “ninjas” master a variety of tools – Not just one. FRAMEWORK BY H AND Use a framework as an extension of yourself – Not just as a crutch. http://imdb.com/title/tt1046173
  12. 12. A day to learn, A lifetime to master“JavaScript is the only languagethat I’m aware of that peoplefeel they don’t need to learnbefore they start using it.”— Douglas Crockfordhttp://www.youtube.com/watch?v=hQVTIJBZook
  13. 13. Today, I’ll discuss two examples...jQuery Desktop Formalize.Me http://desktop.sonspring.com http://formalize.me
  14. 14. jQuery DesktopFun with z-index
  15. 15. jQuery DesktopFun with z-index
  16. 16. Demystifying z-index http://sonspring.com/journal/jquery-desktop
  17. 17. Demystifying z-indexThe default z-index value is 0, and itonly takes effect if an element isposition: fixed, relative, or absolute.The default is position: static.You don’t have to go overboard withz-index: 99999. Just +1 higher thananother element will suffice.
  18. 18. CDN & Local Fallback => Best of both worlds<body>...<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js"></script><script> if (!window.jQuery) { document.write(unescape(%3Cscript src="assets/javascripts/jquery.js"%3E%3C/script%3E)); document.write(unescape(%3Cscript src="assets/javascripts/jquery.ui.js"%3E%3C/script%3E)); }</script><script src="assets/javascripts/jquery.desktop.js"></script>...</body> http://desktop.sonspring.com
  19. 19. Singleton Pattern = Object-oriented JS Nested JS objects versus dot-notation => Same result, but different approaches var APP = {};var APP = { foo: function() { APP.foo = function() { // Do stuff. // Do stuff. }, }; bar: function() { // Do more stuff. APP.bar = function() { } // Do more stuff.} };I prefer the one on the left, but you would call methods byusing the same syntax either way: APP.foo() + APP.bar()
  20. 20. // Module pattern. Module Patternvar APP = (function($, window, document, undefined) { // For use only inside APP. var PRIVATE_CONSTANT_1 = foo; << init example var PRIVATE_CONSTANT_2 = bar; // Expose contents of APP. return { go: function() { for (var i in APP.init) { APP.init[i](); Using a module pattern exposes } }, only one global variable, in this // APP.init init: { case “APP” – with the rest of call_automatically: function() { // Called when DOM is ready. your methods within an object. // Can still be called individually, via: // APP.init.call_automatically(); }, // etc. }, It gives you the ability to use // APP.misc misc: { private “constant” variables call_specifically: function() { // Must be called individually, via: // APP.misc.call_specifically(); inside your appʼs function scope. }, // etc. } }; Nesting functions within an “init”// Alias window, document.})(jQuery, this, this.document); object allows them to be called// Automatically run all functions in APP.initjQuery(document).ready(function() { automatically on DOM ready. APP.go();});
  21. 21. .live() is Awesome. Use it. Love it.$(div.window).live(mousedown, function() { // Bring window to front. JQD.util.window_flat(); $(this).addClass(window_stack);}).live(mouseenter, function() { $(this).die(mouseenter).draggable({ // Confine to desktop. // Movable via top bar only. cancel: a, containment: parent, handle: div.window_top }).resizable({ containment: parent, minWidth: 400, minHeight: 200 }); // etc.});
  22. 22. Live (pun intended) example of .live()http://desktop.sonspring.com/ajax_load.htmlAll the event wire-ups are ready, beforethe page even has any content. Oncethe content is loaded remotely via Ajax,the elements respond to their respectivepredefined .live() event listeners.
  23. 23. Basic structure of jQuery Desktopvar JQD = (function($, window, document, undefined) { return { go: function() { for (var i in JQD.init) { JQD.init[i](); } }, init: { frame_breaker: function() {/* ... */}, clock: function() {/* ... */}, desktop: function() {/* ... */}, wallpaper: function() {/* ... */} }, util: { clear_active: function() {/* ... */}, window_flat: function() {/* ... */}, window_resize: function() {/* ... */} }})(jQuery, this, this.document);
  24. 24. Event listeners at the document level// Cancel mousedown, right-click.$(document).mousedown(function(ev) { var tags = [a, button, input, select, textarea]; if (!$(ev.target).closest(tags).length) { JQD.util.clear_active(); ev.preventDefault(); ev.stopPropagation(); }}).bind(contextmenu, function() { return false;});
  25. 25. External links open in a new window // Relative or remote links? $(a).live(click, function(ev) { var url = $(this).attr(href); this.blur(); if (url.match(/^#/)) { ev.preventDefault(); ev.stopPropagation(); } else { $(this).attr(target, _blank); } });
  26. 26. Top level drop-down menus// Make top menus active.$(a.menu_trigger).live(mousedown, function() { if ($(this).next(ul.menu).is(:hidden)) { JQD.util.clear_active(); $(this).addClass(active).next(ul.menu).show(); } else { JQD.util.clear_active(); }}).live(mouseenter, function() { // Transfer focus, if already open. if ($(ul.menu).is(:visible)) { JQD.util.clear_active(); $(this).addClass(active).next(ul.menu).show(); }});
  27. 27. Making desktop icons interactive // Desktop icons. $(a.icon).live(mousedown, function() { // Highlight the icon. JQD.util.clear_active(); $(this).addClass(active); }).live(dblclick, function() { // Get the links target. var x = $(this).attr(href); var y = $(x).find(a).attr(href); // Show the taskbar button. if ($(x).is(:hidden)) { $(x).remove().appendTo(#dock); $(x).show(fast); } // Bring window to front. JQD.util.window_flat(); $(y).addClass(window_stack).show(); }).live(mouseenter, function() { $(this).die(mouseenter).draggable({ revert: true, containment: parent }); });
  28. 28. Taskbar / Dock buttons// Taskbar buttons.$(#dock a).live(click, function() { // Get the links target. var x = $($(this).attr(href)); // Hide, if visible. if (x.is(:visible)) { x.hide(); } else { // Bring window to front. JQD.util.window_flat(); x.show().addClass(window_stack); }});
  29. 29. Manipulating the “windows”// Minimize the window.$(a.window_min).live(click, function() { $(this).closest(div.window).hide();});// Maximize or restore the window.$(a.window_resize).live(click, function() { JQD.util.window_resize(this);});// Close the window.$(a.window_close).live(click, function() { $(this).closest(div.window).hide(); $($(this).attr(href)).hide(fast);});
  30. 30. Clicking the Show Desktop button// Show desktop button, ala Windows OS.$(#show_desktop).live(click, function() { // If any windows are visible, hide all. if ($(div.window:visible).length) { $(div.window).hide(); } else { // Otherwise, reveal hidden windows that are open. $(#dock li:visible a).each(function() { $($(this).attr(href)).show(); }); }});
  31. 31. To prevent developers fromwasting countless hours onstyling dumb form elements
  32. 32. It’s been awhile in the making...“Future plans include a tutorial on howto use jQuery to add styling hooks toform elements, since I know fromexperience that is no cup of tea.”— Source = Me when announcing 960.gs in 2008!— Excuse = New HTML5 elements set me back :)
  33. 33. WebKit’s form styling secret sauceselect { -webkit-appearance: none;}This gives you back a bit of controlfor things like <select> drop-downs.
  34. 34. document.write(ad) with position:absolute
  35. 35. document.write(ad) with position:absolute
  36. 36. document.write(ad) with position:absolute<script> document.write(unescape(%3Cscr + ipt src="http://adn.fusionads.net/... + M</script><span id="fusion_link"> <a href="http://fusionads.net/">Ads by Fusion</a></span>...</body>
  37. 37. Base64 encode background imagesheader[role="banner"] h1 { background-repeat: no-repeat; background-position: center 20px; background-image: url(../images/logo.png); background-image: url(data:imagepng;base64, iVBORw0KGgoAAA...); color: transparent; font-size: 0; overflow: hidden; text-indent: -99999px; height: 130px;} http://formalize.me http://www.motobit.com/util/base64-decoder-encoder.asp
  38. 38. Pre-load JavaScript files<body>...<!-- Pre-load JavaScript libraries --><script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5.0/dojo/dojo.xd.js"></script><script src="http://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js"></script><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script><script src="http://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js"<script src="http://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script><script src="http://yui.yahooapis.com/3.3.0/build/simpleyui/simpleyui-min.js"></script><!-- Pre-load Formalize files --><script src="assets/javascripts/dojo.formalize.js"></script><script src="assets/javascripts/extjs.formalize.js"></script><script src="assets/javascripts/jquery.formalize.js"></script><script src="assets/javascripts/mootools.formalize.js"></script><script src="assets/javascripts/prototype.formalize.js"></script><script src="assets/javascripts/yui.formalize.js"></script></body>http://formalize.me/demo.html
  39. 39. Pre-load JavaScript files<body>...<!-- Pre-load JavaScript libraries --><script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5.0/dojo/dojo.xd.js"></script><script src="http://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js"></script><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script><script src="http://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js"<script src="http://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script><script src="http://yui.yahooapis.com/3.3.0/build/simpleyui/simpleyui-min.js"></script><!-- Pre-load Formalize files --><script src="assets/javascripts/dojo.formalize.js"></script><script src="assets/javascripts/extjs.formalize.js"></script><script src="assets/javascripts/jquery.formalize.js"></script><script src="assets/javascripts/mootools.formalize.js"></script><script src="assets/javascripts/prototype.formalize.js"></script><script src="assets/javascripts/yui.formalize.js"></script></body>http://formalize.me/demo.html
  40. 40. IE detection for Prototype.js Prevents false positives since Opera can be made to impersonate IE. Note: I did this because Prototype doesn’t detect IE version number.var IE6 = IE(6);var IE7 = IE(7);// Internet Explorer detection.function IE(version) { var b = document.createElement(b); b.innerHTML = <!--[if IE + version + ]><br><![endif]-->; return !!b.getElementsByTagName(br).length;} http://formalize.me/assets/javascripts/prototype.formalize.js
  41. 41. James Padolseys IE detection (whoa!)var ie = (function() { var undef, v = 3, div = document.createElement(div), all = div.getElementsByTagName(i); while ( div.innerHTML = <!--[if gt IE + (++v) + ]><i></i><![endif]-->, all[0] ); return v > 4 ? v : undef;}()); https://gist.github.com/527683
  42. 42. Line number counts in Formalize JS Dojo = 174 lines ExtJS = 168 lines jQuery = 158 lines MooTools = 163 linesPrototype = 171 lines YUI = 168 lines “Write Less, Do More” FTW! :)
  43. 43. Basic structure of Formalize JSvar FORMALIZE = (function($, window, document, undefined) { // Private constants.! var PLACEHOLDER_SUPPORTED = placeholder in document.createElement(input);! var AUTOFOCUS_SUPPORTED = autofocus in document.createElement(input);! var WEBKIT = webkitAppearance in document.createElement(select).style;! var IE6 = !!($.browser.msie && parseInt($.browser.version, 10) === 6);! var IE7 = !!($.browser.msie && parseInt($.browser.version, 10) === 7); // Expose innards of FORMALIZE. return { go: function() {/* ... */}, init: { detect_webkit: function() {/* ... */}, full_input_size: function() {/* ... */}, ie6_skin_inputs: function() {/* ... */}, autofocus: function() {/* ... */}, placeholder: function() {/* ... */} }, misc: { add_placeholder: function() {/* ... */} } };})(jQuery, this, this.document);
  44. 44. Detecting WebKit// FORMALIZE.init.detect_webkitdetect_webkit: function() {! if (!WEBKIT) {! ! return;! }! // Tweaks for Safari + Chrome.! $(html).addClass(is_webkit);},...
  45. 45. Basic structure of Formalize JS// FORMALIZE.init.full_input_sizefull_input_size: function() {! if (!IE7 || !$(textarea, input.input_full).length) {! ! return;! }! // This fixes width: 100% on <textarea> and class="input_full".! // It ensures that form elements dont go wider than container.! $(textarea, input.input_full) .wrap(<span class="input_full_wrap"></span>);},...
  46. 46. Adding styling// FORMALIZE.init.ie6_skin_inputsie6_skin_inputs: function() { // Test for Internet Explorer 6. if (!IE6 || !$(input, select, textarea).length) { // Exit if the browser is not IE6, // or if no form elements exist. return; hooks for IE6 } // For <input type="submit" />, etc. var button_regex = /button|submit|reset/; // For <input type="text" />, etc. var type_regex = /date|datetime|datetime-local|email|month|number|password|range|search|tel|text|time|url|week/; $(input).each(function() { var el = $(this); // Is it a button? if (this.getAttribute(type).match(button_regex)) { el.addClass(ie6_button); /* Is it disabled? */ if (this.disabled) { el.addClass(ie6_button_disabled); } } // Or is it a textual input? else if (this.getAttribute(type).match(type_regex)) { el.addClass(ie6_input); /* Is it disabled? */ if (this.disabled) { el.addClass(ie6_input_disabled); } } }); $(textarea, select).each(function() { /* Is it disabled? */ if (this.disabled) { $(this).addClass(ie6_input_disabled); } });},
  47. 47. Adding HTML5 autofocus support// FORMALIZE.init.autofocusautofocus: function() {! if (AUTOFOCUS_SUPPORTED || !$(:input[autofocus]).length) {! ! return;! }! $(:input[autofocus]:visible:first).focus();},...
  48. 48. Adding HTML5 placeholder support // FORMALIZE.init.placeholder placeholder: function() { ! if (PLACEHOLDER_SUPPORTED || !$(:input[placeholder]).length) { ! ! // Exit if placeholder is supported natively, ! ! // or if page does not have any placeholder. ! ! return; ! } ! FORMALIZE.misc.add_placeholder(); ! $(:input[placeholder]).each(function() { ! ! var el = $(this); ! ! var text = el.attr(placeholder); ! ! el.focus(function() { ! ! ! if (el.val() === text) { ! ! ! ! el.val().removeClass(placeholder_text); ! ! ! } ! ! }).blur(function() { ! ! ! FORMALIZE.misc.add_placeholder(); ! ! }); ! ! // Prevent <form> from accidentally ! ! // submitting the placeholder text. ! ! el.closest(form).submit(function() { ! ! ! if (el.val() === text) { ! ! ! ! el.val().removeClass(placeholder_text); ! ! ! } ! ! }).bind(reset, function() { ! ! ! setTimeout(FORMALIZE.misc.add_placeholder, 50); ! ! }); ! }); }
  49. 49. Moved outside of init, for easier reuse // FORMALIZE.misc misc: { ! // FORMALIZE.misc.add_placeholder ! add_placeholder: function() { ! ! if (PLACEHOLDER_SUPPORTED || !$(:input[placeholder]).length) { ! ! ! // Exit if placeholder is supported natively, ! ! ! // or if page does not have any placeholder. ! ! ! return; ! ! } ! ! $(:input[placeholder]).each(function() { ! ! ! var el = $(this); ! ! ! var text = el.attr(placeholder); ! ! ! if (!el.val() || el.val() === text) { ! ! ! ! el.val(text).addClass(placeholder_text); ! ! ! } ! ! }); ! } }
  50. 50. http://jeromeetienne.github.com/jquery-mobile-960
  51. 51. Additional ResourcesjQuery Companion LibrariesjQuery UI – http://jqueryui.comjQuery Mobile – http://jquerymobile.comAmplify – http://amplifyjs.comUnderscore – http://documentcloud.github.com/underscoreBackbone – http://documentcloud.github.com/backboneJS TestingJasmine – http://pivotal.github.com/jasmineQUnit – http://docs.jquery.com/QunitIf you want write Ruby-esque code that compiles to JS...CoffeeScript – http://jashkenas.github.com/coffee-script
  52. 52. Recommended BooksLearning jQuery – https://www.packtpub.com/learning-jquery-1.3jQuery Enlightenment – http://jqueryenlightenment.comDOM Scripting – http://domscripting.comJavaScript: The Good Parts – http://oreilly.com/catalog/9780596517748JavaScript: The Definitive Guide – http://oreilly.com/catalog/9780596101992High Performance JavaScript – http://oreilly.com/catalog/9780596802806Pro JavaScript Design Patterns – http://jsdesignpatterns.comObject-Oriented JavaScript – https://www.packtpub.com/object-oriented-javascript/bookThe Art and Science of JavaScript – http://www.sitepoint.com/books/jsdesign1Test-Driven JavaScript Development – http://tddjs.com
  53. 53. For questions – Or just to say hi :) Contact – http://sonspring.com/contact Twitter – http://twitter.com/nathansmithhttp://www.slideshare.net/nathansmith/drupalcon-jquery
  54. 54. What did you think?Locate this session on the DCC website:http://chicago2011.drupal.org/sessionsClick the “Take the Survey” link.Thanks!
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×