1.98k likes | 2.12k Views
Building Accessible User Interfaces with JavaScript and jQuery. Antranig Basman, Core Framework Architect, The Fluid Project Clayton Lewis , Professor of Computer Science, University of Colorado at Boulder. Our Goals. Guide to the ropes and pitfalls of JavaScript jQuery
E N D
Building Accessible User Interfaceswith JavaScript and jQuery Antranig Basman, Core Framework Architect, The Fluid Project Clayton Lewis, Professor of Computer Science, University of Colorado at Boulder
Our Goals • Guide to the ropes and pitfalls of • JavaScript • jQuery • A special emphasis on techniques appropriate for • Portals, Mashups and CMSs • Designing accessible, flexible apps • Finish by leading into the basics of Fluid Infusion
Portals, Mashups, and CMSs • These days, diverse code and markup coexists • Most JavaScript is written as if it owns the whole browser • As you combine stuff, things can break • Namespacing and privacy is essential
Schedule • Javascript 101 • 8:55 Break • jQuery • AJAX • Accessibility Basics • 9:55 Break • Accessibility Nuts and Bolts • 10:55 Break • Web 2.0 Accessibility and ARIA • Fluid Infusion • 11:55 Closing
Modus Operandi • Brief introductions, so get to know one another a little • We’ll ask you to discuss with your neighbors from time to time • Questions, comments, and especially arguments are urged at any time!
JavaScript is Different • Everything is an “object” • Extremely loose type system • - Only 6 types for values • - No types for references • No classes • Functions are first class • Some annoying quirks
Super-Quick History • Netscape rushed JS to market, bugs and all, and with a shabbily motivated name • Microsoft reverse-engineered it. • Standards committee enforced the bugs. • In recent years JS has become a crucial technology • Big efforts on improved implementations have delivered huge performance gains
Part 1: The Basics • Variables • null vs. undefined • Type coercion • Objects and Arrays
Defining Variables • Define variables with var • Types are not specified • var mango = "yum"; • mango = 12345; • mango = false;
Defining Variables • If you omit var, it will be defined as a global variable. • This is accident prone; JavaScript won't warn you! • rottenTomato = "gross!"; // This is global
Numbers and Strings • Numbers • lots of precision • no distinction between floats and ints • NaN !== NaN • Strings • Unicode (mostly) • Immutable • No character type
Null vs. Undefined • null is the "nothing" value • undefined is extremely nothing • Default value for uninitialized variables • Also the value of missing members of objects and arguments • exception thrown when the language encounters names which are not found in any scope • “typeof” expressions are safe and need to be used for detection here
Truthy and Falsey • JavaScript does a lot of automatic type coercion • A common case is in conditions • Shades of true and false • Use with care if (x) x? thing1: thing2
Falsey Values • false • null • undefined • "" • 0 (zero) • NaN • Everything else is truthy. Careful... • -1, "false", "0" are all true
Equal vs. Equivalent • Comparisons are coercive: • 1 == "1" // true • 0 == false // true • Non-coercive comparison: • 0 === false // false • 1 !== "1" // true • 1 === Number("1") // true Don’t use this operator! Use this operator!
Objects Are Containers • At their core, objects are just maps or “dictionaries” • new Object() or {} returns an empty container of key/value pairs • Keys can be any string, values can be anything • Two different ways to access members: • basketOfFruit.kiwis; // dot notation • basketOfFruit["figs"]; // subscript notation • You can add new members to any object at any time Don’t use this! Use this! Use this!
Objects Are Modifiable • var basketOfFruit = {}; • // New property • basketOfFruit.apples = "macintosh"; • // New method • basketOfFruit.eat = function () { • return “tasty”; • }
No Classes • JavaScript doesn't have any concept of classes • Methods (functions) are just properties in a container: • pass them around • modify them • delete them
Determining Types • JavaScript has a typeof keyword for determining type • var plum = "yum"; • if (typeof plum === "string") { • alert("Plum is a String!"); • }
typeof is Inaccurate • // Inaccurate results for some built-in types • typeof({}) // 'object' • typeof([]) // 'object' • typeof(function() {}) // 'function' • typeof(“”) // 'string' • typeof(3) // 'number' • typeof(false) // 'boolean' • typeof(null) // 'object' • typeof(undefined) // 'undefined'
Duck Typing • The best way to check for types: don’t. • Check for behaviour: • function countChickens (flock) { • if (flock.length && • typeof flock.length === “number”) { • //flock is ok to count. • } • } : fluid.isArrayable(eggs)
Part 2: Functions & Scope • Functions are first class • Determining types • Understanding this • Closures
First Class Functions • Functions are data (variable values) • You can assign them • You can pass them as arguments • You can return them as results • You can add members to a function(!) • convenient for managing names
Defining and Using Functions • function squeeze(aFruit) { // familiarish… • … • } • var puree = function (aFruit) { // more generally useful • … • }; • function popsicle(juiceMakerFn, fruit) { • var juice = juiceMakerFn(fruit); • return freeze(juice); • } • var goody = popsicle(puree, berries); • var goody2 = popsicle(squeeze, berries);
What Does This Mean? • No more anonymous inner classes! • You can pass bits of logic around and have them be invoked later • Callbacks are easy to write and ubiquitous • Functions are our basic building block
Context and this • JavaScript this pointer is wild and unpredictable • It points to different objects depending on the context • Subtle, confusing, and inexplicable
The Reason For This, We Will Not Discuss • this is part of a package of language features (new, prototype, instanceof, constructor, this) which we (Fluid) do not recommend • We will present a simpler subset of the language that lets you get all your work done • Other dangerous features: eval, with • Ask us in the break or afterwards if you want to know more
Coping With the Problems • this can be confusing and unstable • Constructor functions can accidentally clobber the global namespace • Prototypal inheritance can easily cause existing code to break • Can we simplify things?
Plain Old Functions & Objects • // Just use plain old functions and objects. • function orange () { • // Stable pointer to the current instance. • var that = {}; • // Anything private stays inside here. • // For public methods, just add properties. • that.squeeze = function () {...} • return that; • }
Closures • Functions can be defined inside other functions • Inner functions have access to the outer function's variables • A closure is formed by returning the inner function from the outer function • The inner function will still have access to all the variables from the outer function
A Simple Closure – Challenge #1 • function addNumbers (a, b) { • var sum = a + b; • function addEmUp (c) { • return sum + c; • } • return addEmUp; • } • var func = addNumbers(1, 2); • func(3); // Result is ??? • func(5); // Result is ???
A Simple Closure • function addNumbers (a, b) { • var sum = a + b; • function addEmUp (c) { • return sum + c; • } • return addEmUp; • } • var add3 = addNumbers(1, 2); • // result is an “add 3” Function • add3(3); // Result is 6 • add3(5); // Result is 8
Closures Simplify Event Handlers • function makeShowMessage(todaysPie) { • var messageToDisplay = “Today’s Pie is: ”; • return function(event) { • alert(messageToDisplay + " " + todaysPie); • showPictureOfPie(event.target, todaysPie); • } • } • var clickHandler = makeShowMessage(“Banana creme pie”); • $(element).click(clickHandler); //attach click handler using jQuery • // Shows an alert: "Today's pie is: Banana creme pie" • $(element).click(); //trigger event using jQuery
JavaScript Pitfall Challenge #2 • What is wrong with the following code? for (var i = 0; i < elements.length; i++) { var el = elements[i]; el.addEventListener('click', function() { doSomethingWith(i, el); }); }
“Creating functions in a loop” • A standard complaint from JSLint, a useful code quality tool • Sometimes this is OK • In this case it is not – the function body makes use of a variable held in the outer closure scope • Every listener will see i as n and el as undefined
Basic Remedy #1 – extra function • An extra function needs to be created somehow to store fixed values in a scope • What a mess! for (var i = 0; i < elements.length; i++) { (function(i, el) { el.addEventListener('click', function() { doSomethingWith(i, el); }); })(i, elements[i]); }
Basic Remedy #2 – Use Framework support for iteration $.each(elements, function(i, el) { el.addEventListener('click', function() { doSomethingWith(i, el); }); }); • Note that 2 functions are still needed OR fluid.each(elements, function(el, i) { el.addEventListener('click', function() { doSomethingWith(i, el); }); });
Advanced Remedy #3 – jQuery vectorisation • jQuery.click() is one of a large family of portable event binding methods provided by jQuery (mousemove, keydown, focus, etc.) • “A jQuery” wraps some collection of DOM elements • A jQuery be used to treat the wrapped collection homogeneously • Changes: • We don’t get to use the index “i” any more • Outer function level has disappeared, replaced by magic “this” $(elements).click(function(event) { doSomethingWith(event.target); }; );
Advanced Remedy #4 – jQuery.delegate() • Container is some DOM node containing the elements • “elementSelector” is some selector (from the CSS dialect) matching the elements • This is much more efficient, since it registers just ONE listener, no matter how many elements there are • event.target will differ from “this” which remains the container, but holds the element which received the event • Takes a bit more setting up, but is worthwhile in the long run $(container).delegate(“elementSelector”, “click”, function(event) { doSomethingWith(event.target); }; });
Coping With Bugs • this can be confusing and unstable • Constructor functions can accidentally clobber the global namespace • Prototypal inheritance can easily cause existing code to break • Can we simplify things?
Plain Old Functions & Objects • // Just use plain old functions and objects. • function orange () { • // Stable pointer to the current instance. • var that = {}; • // Anything private stays inside here. • // For public methods, just add properties. • that.squeeze = function () {...} • return that; • }
Writing Collision-Free JavaScript • Put code in a unique namespace • Use closures for privacy • Support more than one on the page • Scope all variables to an instance • Avoid hard-baking ID selectors • Constrain selectors within a specific element These are policies followed by Fluid Infusion
Keeping it to Ourselves • You should take namespacing seriously • Don’t steal global names • JavaScript globals • jQuery plugin names • HTML id values • others • Components are carefully scoped • Don’t expect control of the page
Start With a Unique Namespace • // Add on to the fluid object if it exists, • // otherwise initialize it as an empty object. • var fluid = fluid || {};