drupalcon jquery

Post on 28-Jan-2015

123 Views

Category:

Design

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Presentation from DrupalCon 2011 in Chicago

TRANSCRIPT

CRAFTING APPINTERFACES WITH

Presented by Nathan Smith

Note: Don’t feel like you need to write all of this down. The slides are available here...

http://www.slideshare.net/nathansmith/drupalcon-jquery

Carpal Tunnel Relief

“Allow myself to... introduce myself”

I work (from home) for HPas a front-end developer.

I’m best known for making a helpful 5.6 KB CSS file.

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.

FYI – I don’t especially love CSS

The reason I create and use CSS frameworks is because I hate doing mundane tasks repeatedly (yawn).

I’d rather be working in JavaScript.

Co-author

JavaScript books I’ve worked on...

Tech editor Tech editor

jQueryEnlightenment.com

oreilly.com/catalog/9780596159788

JavaScriptEnlightenment.com

Our team at HP uses Sassto expedite writing CSS

http://www.sass-lang.com

Sass compiles down to CSS...

$blue: #3bbfce$margin: 20px

#foo border-color: $blue color: darken($blue, 9%) .bar border-color: $blue padding: $margin / 2 margin: $margin / 2

#foo { border-color: #3bbfce; color: #2b9eab;}

#foo .bar { border-color: #3bbfce; padding: 10px; margin: 10px;}

Assuming you already know CSS,Sass can help you write CSS faster.

But using Sass doesn’t magically create “better” CSS. If you write bad code, Sass won’t remedy it.

But Sass isn’t a magic bullet(Because no framework is)

The same principlesapply to JavaScript

An important discipline when using any framework is striving to understand the underlying language. In other words, useit as a tool – Not a black box

Veteran “ninjas” master a variety of tools – Not just one.

Use a framework as an extensionof yourself – Not just as a crutch.

BY HAND

FRAMEWORK

http://imdb.com/title/tt1046173

“JavaScript is the only language that I’m aware of that people feel they don’t need to learn before they start using it.”

— Douglas Crockford

http://www.youtube.com/watch?v=hQVTIJBZook

A day to learn, A lifetime to master

Today, I’ll discuss two examples...

jQuery Desktop Formalize.Me

http://desktop.sonspring.com http://formalize.me

jQuery DesktopFun with z-index

jQuery DesktopFun with z-index

Demystifying z-index

http://sonspring.com/journal/jquery-desktop

Demystifying z-index

The default z-index value is 0, and it only takes effect if an element is position: fixed, relative, or absolute. The default is position: static.

You don’t have to go overboard with z-index: 99999. Just +1 higher than another element will suffice.

<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>

CDN & Local Fallback=> Best of both worlds

http://desktop.sonspring.com

Singleton Pattern = Object-oriented JS

Nested JS objects versus dot-notation=> Same result, but different approaches

var APP = { foo: function() { // Do stuff. }, bar: function() { // Do more stuff. }}

var APP = {};

APP.foo = function() { // Do 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()

// Module pattern.var APP = (function($, window, document, undefined) { // For use only inside APP. var PRIVATE_CONSTANT_1 = 'foo'; var PRIVATE_CONSTANT_2 = 'bar';

// Expose contents of APP. return { go: function() { for (var i in APP.init) { APP.init[i](); } }, // APP.init init: { call_automatically: function() { // Called when DOM is ready. // Can still be called individually, via: // APP.init.call_automatically(); }, // etc. }, // APP.misc misc: { call_specifically: function() { // Must be called individually, via: // APP.misc.call_specifically(); }, // etc. } };// Alias window, document.})(jQuery, this, this.document);

// Automatically run all functions in APP.initjQuery(document).ready(function() { APP.go();});

Module Pattern << init example

Using a module pattern exposes

only one global variable, in this case “APP” – with the rest of

your methods within an object.

It gives you the ability to use private “constant” variables

inside your appʼs function scope.

Nesting functions within an “init” object allows them to be called

automatically on DOM ready.

.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.});

All the event wire-ups are ready, before the page even has any content. Once the content is loaded remotely via Ajax, the elements respond to their respective predefined .live() event listeners.

Live (pun intended) example of .live()

http://desktop.sonspring.com/ajax_load.html

var 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);

Basic structure of jQuery Desktop

// 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;});

Event listeners at the document level

// 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'); }});

External links open in a new window

// 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(); }});

Top level drop-down menus

// Desktop icons.$('a.icon').live('mousedown', function() { // Highlight the icon. JQD.util.clear_active(); $(this).addClass('active');}).live('dblclick', function() { // Get the link's 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' });});

Making desktop icons interactive

// Taskbar buttons.$('#dock a').live('click', function() { // Get the link's 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'); }});

Taskbar / Dock buttons

// 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');});

Manipulating the “windows”

// 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(); }); }});

Clicking the Show Desktop button

To prevent developers fromwasting countless hours onstyling dumb form elements

“Future plans include a tutorial on how to use jQuery to add styling hooks to form elements, since I know from experience that is no cup of tea.”

— Source = Me when announcing 960.gs in 2008!

— Excuse = New HTML5 elements set me back :)

It’s been awhile in the making...

select { -webkit-appearance: none;}

WebKit’s form styling secret sauce

This gives you back a bit of control for things like <select> drop-downs.

document.write(ad) with position:absolute

document.write(ad) with position:absolute

document.write(ad) with position:absolute

<script> document.write(unescape('%3Cscr' + 'ipt src="http://adn.fusionads.net/...' + Math.floor(Math.random() * 99999999999) + '"%3E%3C/script%3E'))</script><span id="fusion_link"> <a href="http://fusionads.net/">Ads by Fusion</a></span>...</body>

header[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;}

Base64 encode background images

http://formalize.me http://www.motobit.com/util/base64-decoder-encoder.asp

<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> <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>

Pre-load JavaScript files

http://formalize.me/demo.html

<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> <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>

Pre-load JavaScript files

http://formalize.me/demo.html

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;}

IE detection for Prototype.js

http://formalize.me/assets/javascripts/prototype.formalize.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 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;}());

James Padolsey's IE detection (whoa!)

https://gist.github.com/527683

Line number counts in Formalize JS

Dojo = 174 lines ExtJS = 168 lines

jQuery = 158 lines MooTools = 163 lines

Prototype = 171 lines YUI = 168 lines

“Write Less, Do More” FTW! :)

var 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);

Basic structure of Formalize JS

// FORMALIZE.init.detect_webkitdetect_webkit: function() {! if (!WEBKIT) {! ! return;! }

! // Tweaks for Safari + Chrome.! $('html').addClass('is_webkit');},

...

Detecting WebKit

// 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 don't go wider than container.! $('textarea, input.input_full') .wrap('<span class="input_full_wrap"></span>');},

...

Basic structure of Formalize JS

// 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; }

// 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'); } });},

Adding stylinghooks for IE6

// FORMALIZE.init.autofocusautofocus: function() {! if (AUTOFOCUS_SUPPORTED || !$(':input[autofocus]').length) {! ! return;! }

! $(':input[autofocus]:visible:first').focus();},

...

Adding HTML5 autofocus support

// FORMALIZE.init.placeholderplaceholder: 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);! ! });! });}

Adding HTML5 placeholder support

// FORMALIZE.miscmisc: {! // 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');! ! ! }! ! });! }}

Moved outside of init, for easier reuse

jQuery Companion Libraries

jQuery UI – http://jqueryui.comjQuery Mobile – http://jquerymobile.com

Amplify – http://amplifyjs.comUnderscore – http://documentcloud.github.com/underscore

Backbone – http://documentcloud.github.com/backbone

JS TestingJasmine – http://pivotal.github.com/jasmine

QUnit – http://docs.jquery.com/Qunit

If you want write Ruby-esque code that compiles to JS...CoffeeScript – http://jashkenas.github.com/coffee-script

Additional Resources

Learning jQuery – https://www.packtpub.com/learning-jquery-1.3

jQuery Enlightenment – http://jqueryenlightenment.comDOM Scripting – http://domscripting.com

JavaScript: The Good Parts – http://oreilly.com/catalog/9780596517748JavaScript: The Definitive Guide – http://oreilly.com/catalog/9780596101992

High Performance JavaScript – http://oreilly.com/catalog/9780596802806Pro JavaScript Design Patterns – http://jsdesignpatterns.com

Object-Oriented JavaScript – https://www.packtpub.com/object-oriented-javascript/bookThe Art and Science of JavaScript – http://www.sitepoint.com/books/jsdesign1

Test-Driven JavaScript Development – http://tddjs.com

Recommended Books

For questions – Or just to say hi :)

Contact – http://sonspring.com/contact

Twitter – http://twitter.com/nathansmith

http://www.slideshare.net/nathansmith/drupalcon-jquery

What did you think?

Locate this session on the DCC website:http://chicago2011.drupal.org/sessions

Click the “Take the Survey” link.

Thanks!

top related