• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CenterForOpenScience / ember-osf-web / 4137406804

pending completion
4137406804

Pull #1662

github

GitHub
Merge b8210344a into 342745e48
Pull Request #1662: [WIP][ENG-4048] Keyboard Navigation Skip Link - Main Home

2491 of 3799 branches covered (65.57%)

Branch coverage included in aggregate %.

147 of 147 new or added lines in 3 files covered. (100.0%)

5701 of 7910 relevant lines covered (72.07%)

228.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

11.97
/lib/osf-components/addon/components/carousel/component.ts
1
/* eslint-disable no-console */
2
import { tagName } from '@ember-decorators/component';
3
import Component from '@ember/component';
4
import { action, computed } from '@ember/object';
5

6
import { layout } from 'ember-osf-web/decorators/component';
7
import CarouselItem from 'osf-components/components/carousel/x-item/component';
8

9
import styles from './styles';
10
import template from './template';
11

12
@layout(template, styles)
13
@tagName('')
14
export default class Carousel extends Component {
15
    // Private properties
16
    carouselItems: CarouselItem[] = [];
7✔
17

18
    @computed('carouselItems.{length,@each.isActive}')
19
    get activeSlide() {
20
        return this.carouselItems.findBy('isActive');
×
21
    }
22

23
    @action
24
    register(item: CarouselItem) {
25
        this.carouselItems.pushObject(item);
21✔
26
    }
27

28
    @action
29
    changeSlide(direction: string) {
30
        const activeSlide = this.carouselItems.findBy('isActive');
8✔
31
        const activeIndex = activeSlide!.index;
8✔
32
        let newIndex = direction === 'previous' ? activeIndex - 1 : activeIndex + 1;
8✔
33

34
        if (newIndex > this.carouselItems.length - 1) {
8✔
35
            newIndex = 0;
1✔
36
        } else if (newIndex < 0) {
7✔
37
            newIndex = this.carouselItems.length - 1;
1✔
38
        }
39

40
        this.carouselItems[activeIndex].set('isActive', false);
8✔
41
        this.carouselItems[newIndex].set('isActive', true);
8✔
42
    }
43

44
    @action
45
    navClick(item: CarouselItem) {
46
        const activeSlide = this.carouselItems.findBy('isActive');
×
47
        const activeIndex = activeSlide!.index;
×
48
        const newIndex = item.index;
×
49

50
        this.carouselItems[activeIndex].set('isActive', false);
×
51
        this.carouselItems[newIndex].set('isActive', true);
×
52
    }
53

54
    // @action
55
    setUpLiveRegion(message: string) {
56
        const w = window || null;
×
57
        const document = w.document;
×
58
        console.log(document);
×
59
        const carousel = document.getElementById('carouselInner');
×
60
        const liveregion = document.createElement('div');
×
61
        liveregion.setAttribute('aria-live', 'polite');
×
62
        liveregion.setAttribute('aria-atomic', 'true');
×
63
        liveregion.setAttribute('class', 'liveregion visuallyhidden');
×
64
        if (carousel && liveregion) {
×
65
            let subject = 'You';
×
66
            let msg: string = subject + message;
×
67
            const data = document.createTextNode(msg);
×
68
            console.log('Spoken: ', msg);
×
69
            liveregion.appendChild(data);
×
70
            carousel.appendChild(liveregion);
×
71
        }
72
    }
73

74
    /** registerKeyboard() is a function that enables users to navigate certain
75
     *  components with a keyboard rather than using a mouse. The keybindings are
76
     *  designed for optimal ergonomic comfort as well as improving overall user
77
     *  experience while within the application.
78
     */
79
    registerKeyboard() {
80
        // set up voice over
81
        let msg = 'Keyboard navigation enabled. Press lower case h to hear more.';
×
82
        // this.setUpLiveRegion(msg);
83
        console.log('voice over set to: ', msg);
×
84

85
        // locate elements
86
        const dotNav = document.getElementById('dotNav');
×
87
        const leftNav = document.getElementById('leftNav');
×
88
        const rightNav = document.getElementById('rightNav');
×
89

90
        // set up event listener for keyboard input
91
        document.addEventListener('keydown', event => {
×
92
            const name = event.key;
×
93
            const code = event.code;
×
94
            const dotNav = document.getElementById('dotNav');
×
95
            // do not override native browser or SR controls
96
            if (name === 'Control' || name === 'Meta') {
×
97
                return;
×
98
            }
99

100
            // bind the current this context
101
            let THIS = (vm=this) => console.log(vm);
×
102
            THIS();
×
103

104
            // switch operand based on user input
105
            if (event.ctrlKey) {
×
106
                console.log(`Combination of ctrlKey + ${name} \n code: ${code}`);
×
107

108
                switch(name) {
×
109
                case('f'):
110
                    console.log('navigating to previous slide.');
×
111
                    if (leftNav) {
×
112
                        leftNav.click();
×
113
                    }
114
                    break;
×
115
                case('j'):
116
                    console.log('navigating to next slide.');
×
117
                    if (rightNav) {
×
118
                        rightNav.click();
×
119
                    }
120
                    break;
×
121
                case('d'):
122
                    console.log('inside carousel dot navigation.');
×
123
                    if (dotNav) {
×
124
                        dotNav.focus();
×
125
                    }
126
                    break;
×
127
                case('h'):
128
                    console.log('selecting help guide.');
×
129
                    break;
×
130
                default:
131
                    console.log('selected an unregistered command.');
×
132
                    break;
×
133
                }
134
            } else {
135
                console.log(`Other key registered: \n\tname ${name} \nt code: ${code}`);
×
136
            }
137
        }, true);
138

139
        if (dotNav) {
×
140
            const buttonElements = dotNav.children;
×
141
            console.log('can select from the following elements: ', buttonElements);
×
142
            const buttonOne: Element = buttonElements[0].children[0] || null;
×
143
            const buttonTwo : Element = buttonElements[1].children[0] || null;
×
144
            const buttonThree : Element = buttonElements[2].children[0] || null;
×
145

146
            document.addEventListener('keyup', event => {
×
147
                const eventType = typeof(event);
×
148
                console.log('initiating event type: ', eventType);
×
149
                console.log('event code is:', event.code);
×
150
                if (event.code === '49') {
×
151
                    buttonOne.click();
×
152
                    console.log('selecting the first slide.'); // TODO update with item data
×
153
                }
154
                if (event.code === '50') {
×
155
                    buttonTwo.click();
×
156
                    console.log('selecting the second slide.'); // TODO update with item data
×
157
                }
158
                if (event.code === '51') {
×
159
                    buttonThree.click();
×
160
                    console.log('selecting the third slide.'); // TODO update with item data
×
161
                }
162
            });
163
        }
164

165
        document.addEventListener('keyup', event => {
×
166
            const name = event.key;
×
167
            if (name === 'Control') {
×
168
                console.log('Control key released.');
×
169
            }
170
            if (name === 'Alt') {
×
171
                console.log('Alt key released.');
×
172
            }
173
            if (name === 'Shift') {
×
174
                console.log('Shift key released.');
×
175
            }
176
        }, false);
177
    }
178
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc