Upload
nathan-hammond
View
4.555
Download
2
Tags:
Embed Size (px)
Citation preview
Designing
Is This Designing?
http://www.adobe.com/inspire/2013/11/photoshop-reflow-generator.html
Is This Designing?
http://thisoldcity.com/advocacy/photos-what-snow-tells-us-about-creating-better-public-spaces-e-passyunk-avenue
Yes.
@nathanhammond nathanhammond.com
nathanhammond
http://www.unicode.org/reports/tr51/tr51-2.html#Emoji_Modifiers
Good Design
https://flic.kr/p/die16e, https://flic.kr/p/99ad9q
Universal Design
Stokke Tripp Trapp
Universal?
Designing for Accessibility
http://www.istockphoto.com/photo/group-of-business-men-and-women-in-a-meeting-37790018
https://commons.wikimedia.org/wiki/File:US_House_Committee.jpg
https://flic.kr/p/9ZA2Jx
Demo
Learnings• Screen readers start reading from the top of the
page on each page load.
• Dynamically updating the DOM results in no information being passed to the user by default.
• Markup is still important. Ember's real links and the code you write in your templates is important.
• ARIA roles still do what we expect.
Building for Accessibility
Page LoadingWe want to emulate the page load behavior
demonstrated with static pages.
End-User Goals• Have the screen reader automatically start reading
the content of the page.
• Have it start reading the content from the best point in the application hierarchy.
• Make it clear to the user that the content on the page has changed.
• Follow other recommended patterns that screen reader users are familiar with.
Ember Goals• Have the solution work with current idiomatic
Ember code or minimize migration cost.
• Make the change in a backwards compatible way to meet Ember's stability without stagnation goal.
• The default approach should be accessible, API design is a feature.
• Provide for extensibility with hooks enabling enhancement of this higher-level feature.
Exploration
InventoryRouter, Transitions, Routes,
Templates, Outlets, HTMLBars
Outlet FocusingWhat if we set the focus on the route's outlet immediately
after the transition completes?
Research
Screen Readers• It's like the Internet Explorer and Netscape HTML/
CSS/JS compatibility workarounds all over again.
• Screen readers tend to read whatever you focus.
• Nobody likes being dumped into forms mode.
• Screen readers are aware of content on the page changing, but don't present that to the user until it is asked for.
Ember• The top level outlet is generated and wrapped in a
containing DIV.
• All other outlets are populated by their templates without first being wrapped in a containing DIV.
• Routes have no reference to their rendered output.
• You can have multiple outlets in a single route.
• No-op transitions trigger no route hooks.
Solution Design
API DesignIt'd be nice if every route had a `focus` hook that was
called with the outlet contents.
Ember.Route.reopen({! focus(morph) {! var elem = morph.firstNode;!! try {! if (!elem.getAttribute('tabindex')) {! if (isInteractive(elem)) {! elem.setAttribute('tabindex', 0);! } else {! elem.setAttribute('tabindex', -1);! }! }!! elem.focus();! } catch (e) {}! }!});
DevelopmentHow do we call the `focus` hook?
Ember.Route.reopen({! enter(transition) {! var route = this;!! // Focus "up one level" for index routes.! if (! transition.pivotHandler &&! this.routeName === transition.pH.routeName + '.index'! ) {! transition.pivot = transition.pivotHandler.routeName;! route = transition.pivotHandler;! this._focus(route, transition);! }!! // Handle fresh entries.! if (!transition.pivot) {! transition.pivot = this.routeName;! this._focus(route, transition)! }!! return this._super(...arguments);! }!});
Ember.Route.reopen({! _focus(route, transition, parent) {! var focus = new Ember.RSVP.Promise(function(resolve, reject) {! this.focusPromiseResolve = resolve;! }.bind(route));!! // Set up our context for after the transition completes.! var transitionResolve = (function(transition, route) {! return function(result) {! delete transition.pivot;!! Ember.run.scheduleOnce('afterRender', route, function() {! route.focus(result.focus)! });! };! })(transition, route);!! // Clean up after ourselves in case there is a transition.retry() call.! var transitionReject = (function(transition, route) {! return function() {! delete transition.pivot;! };! })(transition, route);!! Ember.RSVP.hash({ focus, transition })! .then(transitionResolve)! .catch(transitionReject);! }!});
IntegrationWhat happens when Ember needs to be modified.
diff --git a/packages/ember-htmlbars/lib/keywords/outlet.js b/packages/ember-htmlbars/lib/keywords/outlet.js!index 317e899..6b01753 100644!--- a/packages/ember-htmlbars/lib/keywords/outlet.js!+++ b/packages/ember-htmlbars/lib/keywords/outlet.js!@@ -17,6 +17,10 @@ export default function(morph, env, scope, params, hash, template, inverse, visi!+ if (env.outletState.main.render.focusPromiseResolve) {!+ env.outletState.main.render.focusPromiseResolve(morph);!+ delete env.outletState.main.render.focusPromiseResolve;!+ }! keyword('@real_outlet', morph, env, scope, params, hash, template, inverse, visitor);!!diff --git a/packages/ember-routing/lib/system/router.js b/packages/ember-routing/lib/system/router.js!index bb157c1..5600f99 100644!--- a/packages/ember-routing/lib/system/router.js!+++ b/packages/ember-routing/lib/system/router.js!@@ -202,10 +202,18 @@ var EmberRouter = EmberObject.extend(Evented, {! for (var j = 0; j < connections.length; j++) {!+ delete connections[j].focusPromiseResolve;! var appended = appendLiveRoute(liveRoutes, defaultParentState, connections[j]);! liveRoutes = appended.liveRoutes;! if (appended.ownState.render.name === route.routeName || appended.ownState.render.outlet === 'main') {! ownState = appended.ownState;!+ // Pass forward the focus promise resolve hook from the route to the appropriate connection.!+ if (route.focusPromiseResolve) {!+ ownState.render.focusPromiseResolve = route.focusPromiseResolve;!+ delete route.focusPromiseResolve;!+ }
Contributing Back
Write an RFC!You've created and tested a feature!
It's time to get it shipped!
http://bit.ly/rfc66
Usage Notes• You can use this today! http://bit.ly/outletfocusing
• All template content must be wrapped in a `<div>`. Child outlets must also appear inside that `<div>`.
• Automatically generated templates are just `{{outlet}}` and will thus have problems.
• Provide feedback on RFC #66!
Demo
Learnings
• It's a different experience from the static site.
• We have programmatic control over the focusing behavior.
• Setting the focus has additional consequences in terms of scrolling behavior.
Challenge