UNPKG

2.97 kBJavaScriptView Raw
1import Ember from 'ember';
2import getOwner from 'ember-a11y/ember-get-owner';
3
4const {
5 get,
6 Mixin
7} = Ember;
8
9let scrollLeft = 0;
10let scrollTop = 0;
11let handler = function() {
12 window.scrollTo(scrollLeft, scrollTop);
13 window.removeEventListener('scroll', handler);
14};
15
16export default Mixin.create({
17 tagName: 'div',
18 classNames: ['focusing-outlet'],
19
20 shouldFocus: false,
21 currentOutletRouteKeyPrefix: null,
22
23 didReceiveAttrs() {
24 this._super(...arguments);
25 this.set('outletName', this.attrs.inputOutletName || 'main');
26 },
27
28 didInsertElement() {
29 this._super(...arguments);
30 this.setFocus();
31 },
32
33 setFocus() {
34 if (!this.element) { return; }
35
36 let shouldFocus = this.get('shouldFocus');
37
38 if (shouldFocus) {
39 // One shouldn't set an attribute when they mean to set a property.
40 // Except when a property is only settable if the attribute is present.
41 // We have to make the element interactive prior to focusing it.
42 this.element.setAttribute('tabindex', '-1');
43 this.element.setAttribute('role', 'group');
44
45 // If we don't do this, the scroll triggered by the focus will be unfortunate.
46 // This effectively swallows one scroll event.
47 // TODO: Investigate setting focus to something inside of overflow: auto;
48 scrollLeft = document.body.scrollLeft;
49 scrollTop = document.body.scrollTop;
50 window.addEventListener('scroll', handler);
51
52 // Set the focus to the target outlet wrapper.
53 Ember.run.schedule('afterRender', this, function() { this.element.focus(); });
54 } else {
55 this.element.removeAttribute('tabindex');
56 this.element.removeAttribute('role');
57 }
58 },
59
60 actions: {
61 checkFocus(outletState) {
62 let application = getOwner(this).lookup('application:main');
63 let pivotHandler = application.get('_stashedHandlerInfos.pivotHandler.handler.routeName');
64
65 let outletName = this.get('outletName');
66
67 let pathPrefix = '';
68 let currentOutletRouteKeyPrefix = get(this, 'currentOutletRouteKeyPrefix');
69 if (currentOutletRouteKeyPrefix) {
70 pathPrefix = `${currentOutletRouteKeyPrefix}.`;
71 }
72
73 let currentRoute = get(outletState, `${pathPrefix}${outletName}.render.name`);
74 if (!currentRoute) {
75 return;
76 }
77
78 let handled = application.get('_stashedHandlerInfos.pivotHandler.handled');
79 let isFirstVisit = pivotHandler === undefined;
80 let isPivot = (pivotHandler === currentRoute);
81 let isChildState = ~['loading', 'error'].indexOf(currentRoute.split('.').pop());
82 let isSubstate = ~currentRoute.indexOf('_loading') || ~currentRoute.indexOf('_error');
83
84 let shouldFocus = !handled && !isFirstVisit && (isPivot || isChildState || isSubstate);
85 this.set('shouldFocus', shouldFocus);
86
87 if (pivotHandler) {
88 application.set('_stashedHandlerInfos.pivotHandler.handled', handled || shouldFocus);
89 }
90
91 this.setFocus();
92 }
93 }
94});
95
\No newline at end of file