PageSourceSearch

https://horacemann.com/-/media/Base-Themes/Components-Theme/Scripts/accessibility.js

js horacemann.com collected 2026-09-24 18:23:33 UTC 9,355 bytes, 259 lines download raw bytes

1/**
2 * Component accessibility
3 * makes content more accessible to people with disabilities.
4 * @module Accessibility
5 * @param  {jQuery} $ Instance of jQuery
6 */
7XA.component.accessibility = (function ($) {
8    /**
9    * This object stores all public api methods
10    * @type {Object.<Methods>}
11    * @memberOf module:Accessibility
12    * */
13    var api = {};
14    /**
15        * getAllIndexedElement - returns elements that have tab index attribute
16        * @returns {jQuery<DOMElement>} elements that have tab index attribute
17    */
18    var getAllIndexedElement = function () {
19        return $("body").find("[tabindex]");
20    };
21
22    /**
23        * activateFirstElement - activate first element on a page that have tab index attribute
24        * active element
25        * @returns {String} component name 
26    */
27    api.activateFirstElement = function () {
28        api.indexedElements.eq(0).attr("tabindex", "0");
29    };
30    /**
31       * getComponentName - helper that provides component name based on 
32       * active element
33       * @returns {String} component name 
34   */
35    var getComponentName = function () {
36        var $activeElement = $(document.activeElement),
37            currComponent = $activeElement.closest(".initialized"),
38            componentName = currComponent.length
39                ? currComponent.attr("class").split(" ")[1]
40                : "";
41        return componentName;
42    };
43    /**
44        * getWrapper - helper that provides wrapper element for
45        * active element
46        * @param {String} selector selector of parent wrapper
47        * @returns {jQuery<DOMElement>} 
48    */
49    var getWrapper = function (selector) {
50        var $activeElement = $(document.activeElement);
51        return $activeElement.closest(selector);
52    };
53
54    /**
55        * activateTab - helper for Tabs component
56    */
57    var activateTab = function (direction, currTab) {
58        var activatedTab = currTab;
59        if (direction == "left" && currTab.prev()) {
60            currTab.attr("tabindex", "-1");
61            activatedTab = currTab.prev();
62        } else if (direction == "right" && currTab.next()) {
63            currTab.attr("tabindex", "-1");
64            activatedTab = currTab.next();
65        }
66        activatedTab
67            .attr("tabindex", "0")
68            .trigger("click")
69            .focus();
70    };
71
72    /**
73     * activateItem - helper for Accordion component
74    */
75    var activateItem = function (direction, currItem, event) {
76        var itemWrapper = currItem.closest("li.item"),
77            activatedTab = currItem,
78            nextItem = itemWrapper.next(),
79            prevItem = itemWrapper.prev();
80        if (direction == "down" && nextItem.length) {
81            event.preventDefault();
82            currItem.attr("tabindex", "-1");
83            activatedTab = nextItem;
84            
85        } else if (direction == "up" && prevItem.length) {
86            event.preventDefault();
87            currItem.attr("tabindex", "-1");
88            activatedTab = prevItem;
89        }
90        activatedTab
91            .find(".toggle-header")
92            .attr("tabindex", "0")
93            .focus();
94    };
95
96    /**
97     * toggleFlip - helper for Flip component
98    */
99    var toggleFlip = function (currItem) {
100        var nextItem = currItem.next().length ? currItem.next() : currItem.prev();
101        currItem.attr("tabindex", "-1");
102        nextItem
103            .trigger("click")
104            .attr("tabindex", "0")
105            .focus();
106    };
107
108    /**
109     * componentLogic - object that contains list of components as a object key
110     * and function with logic that make this component WCAG friendly
111     * @type {Object}
112     */
113    var componentLogic = {
114        tabs: function (keyCode) {
115            var currTab = getWrapper("li.active");
116            if (currTab) {
117                if (keyCode == api.keys.right) {
118                    activateTab("right", currTab);
119                } else if (keyCode == api.keys.left) {
120                    activateTab("left", currTab);
121                }
122            }
123        },
124        accordion: function (keyCode, isShiftPressed, event) {
125            var currItem = getWrapper("div.toggle-header");
126            if (currItem) {
127                if (keyCode == api.keys.down) {
128                    activateItem("down", currItem, event);
129                } else if (keyCode == api.keys.up) {
130                    activateItem("up", currItem, event);
131                } else if (!isShiftPressed && keyCode == api.keys.tab) {
132                    activateItem("down", currItem, event);
133                } else if (isShiftPressed && keyCode == api.keys.tab){
134                    activateItem("up", currItem, event);
135                }
136            }
137        },
138        flip: function (keyCode) {
139            var currItem = getWrapper("[class*='Side']");
140            if (currItem) {
141                if (keyCode == api.keys.right || keyCode == api.keys.left) {
142                    toggleFlip(currItem);
143                }
144            }
145        }
146    };
147    /**
148    * bindEvents method get component name by calling 
149    * ["getComponentName"]{@link module:Accessibility.getComponentName} method and running apropriate to
150    * component logic
151    * @memberOf module:Accessibility
152    * @param {number} keycode keycode of pressed button on keyboard
153    * @alias module:Accessibility.bindEvents
154    * @private
155    * */
156    var bindEvents = function (keyCode, isShiftPressed, event) {
157        var component = getComponentName();
158        if (componentLogic[component]) {
159            componentLogic[component](keyCode, isShiftPressed, event);
160        }
161    };
162
163    /**
164    * This object stores keycode of keyboard buttons
165    * @type {Object}
166    * @memberOf module:Accessibility 
167    * @alias module:Accessibility.keys
168    * */
169    api.keys = {
170        end: 35,
171        home: 36,
172        left: 37,
173        up: 38,
174        right: 39,
175        down: 40,
176        delete: 46,
177        enter: 13,
178        space: 32,
179        tab: 9
180    };
181    /**
182         * indexedElements variable take list of all Indexed Element on a page by calling
183         * ["getAllIndexedElement"]{@link module:Accessibility.getAllIndexedElement} method
184         * @memberOf module:Accessibility
185         * @param {Object} properties list of properties for accordion component
186         * @alias module:Accessibility.indexedElements
187    */
188    api.indexedElements = getAllIndexedElement();
189    /**
190     * watchEvents method bind keyup event on document and on each trigger calls
191     * ["bindEvents"]{@link module:Accessibility.bindEvents}
192     * @memberOf module:Accessibility
193     * @alias module:Accessibility.watchEvents
194     */
195    api.watchEvents = function () {
196        $(document).on("keydown", function (event) {
197            var keyCode = event.keyCode,
198                isShiftPressed = event.shiftKey;
199            bindEvents(keyCode, isShiftPressed, event);
200        });
201    };
202    /**
203    * registerLogic method register accessability logic to
204    * ["componentLogic"]{@link module:Accessibility.componentLogic} list
205    * @memberOf module:Accessibility
206    * @param {string} componentName name of component which logic should be registered
207    * @param {Function} componentFunc function for component that will be triggered for accessability support
208    * @alias module:Accessibility.registerLogic
209    */
210    api.registerLogic = function (componentName, componentFunc) {
211        componentLogic[componentName] = componentFunc;
212    }
213    /**
214    * unregisterLogic method delete accessability logic from
215    * ["unregisterLogic"]{@link module:Accessibility.unregisterLogic} list
216    * @memberOf module:Accessibility
217    * @param {string} componentName name of component which logic should be deleted
218    * @alias module:Accessibility.unregisterLogic
219    */
220    api.unregisterLogic = function (componentName) {
221        delete componentLogic[componentName]
222    }
223    /**
224    * getRegisteredLogic method return list of accessability logic
225    * ["unregisterLogic"]{@link module:Accessibility.unregisterLogic} list
226    * @memberOf module:Accessibility
227    * @returns {Object} list of registered components and their logic
228    * @alias module:Accessibility.getRegisteredLogic
229    */
230    api.getRegisteredLogic = function () {
231        return componentLogic
232    }
233    /**
234        * initInstance method call
235        * ["watchEvents"]{@link module:Accessibility.watchEvents} method
236        * and call
237        * ["activateFirstElement"]{@link module:Accessibility.activateFirstElement}
238        * @memberOf module:Accessibility
239        * @method
240        * @alias module:Accessibility.initInstance
241        */
242    api.initInstance = function () {
243        api.watchEvents();
244        api.activateFirstElement();
245    };
246    /**
247     * init method calls 
248     * [".initInstance"]{@link module:Accessibility.initInstance} method.
249     * @memberOf module:Accessibility
250     * @alias module:Accessibility.init
251     */
252    api.init = function () {
253        api.initInstance();
254    };
255
256    return api;
257})(jQuery, document);
258
259XA.register("accessibility", XA.component.accessibility);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.