Skip to content

Instantly share code, notes, and snippets.

@nathanhammond
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathanhammond/f48a793042d5100fbe89 to your computer and use it in GitHub Desktop.
Save nathanhammond/f48a793042d5100fbe89 to your computer and use it in GitHub Desktop.
Ember Outlet Focusing
function isInteractive(elem) {
var interactive = [
'input',
'textarea',
'select'
];
return interactive.indexOf(elem.tagName.toLowerCase()) !== -1;
}
// FIXME: Deal with repeated attempts to route to the same route.
// TODO: Remove previous tabindex state.
Ember.Route.reopen({
focus(morph) {
// The elements we need are in the DOM.
// ViewNodeManager for the primary outlet of the route.
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) {}
},
enter(transition) {
var route = this;
// Focus "up one level" for index routes.
// FIXME: Pathing for non-index routes.
if (transition.pivotHandler && this.routeName == transition.pivotHandler.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);
},
_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() {
// The elements we need are in the DOM.
// The ViewNodeManager for the specific connection is at result.focus.
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);
}
});
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
Ember.deprecate("Passing `view` or `viewClass` to {{outlet}} is deprecated.");
keyword('@customized_outlet', morph, env, scope, params, hash, template, inverse, visitor);
} else {
+ 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);
}
return true;
diff --git a/packages/ember-routing/lib/system/router.js b/packages/ember-routing/lib/system/router.js
index b2b330c..a73da8f 100644
--- a/packages/ember-routing/lib/system/router.js
+++ b/packages/ember-routing/lib/system/router.js
@@ -215,10 +215,18 @@ var EmberRouter = EmberObject.extend(Evented, {
var connections = route.connections;
var ownState;
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;
+ }
}
}
if (connections.length === 0) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment