PageSourceSearch

https://www.varsom.no/Content/Scripts/External/radioGroupActiveDescendant.js

js varsom.no collected 2026-09-24 17:14:27 UTC 4,988 bytes, 168 lines download raw bytes

1/*
2*   This content is licensed according to the W3C Software License at
3*   https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
4*
5*   File:   radioGroup.js
6*
7*   Desc:   Radio group widget using aria-activedescendant that implements ARIA Authoring Practices
8*/
9
10/*
11*   @constructor radioGroupActiveDescendent
12*
13*   @desc
14*       Wrapper for ARIA radiogroup control using ARIA active-descendant.  Any descendant
15*       element with role=radio will be included in this radiogroup as a radiobutton2.
16*
17*   @param domNode
18*       The DOM element node that serves as the radiogroup container.
19*/
20
21// Merk: Denne er endret fra default for å støtte korrekte roller (tablist / tab)
22var RadioGroup = function (domNode) {
23
24    this.domNode = domNode;
25
26    this.radioButtons = [];
27
28    this.firstRadioButton = null;
29    this.lastRadioButton = null;
30
31    this.keyCode = Object.freeze({
32        'TAB': 9,
33        'SPACE': 32,
34        'LEFT': 37,
35        'UP': 38,
36        'RIGHT': 39,
37        'DOWN': 40
38    });
39};
40
41RadioGroup.prototype.init = function () {
42
43    this.domNode.addEventListener('keydown', this.handleKeydown.bind(this));
44    this.domNode.addEventListener('focus', this.handleFocus.bind(this));
45    this.domNode.addEventListener('blur', this.handleBlur.bind(this));
46    // initialize
47    if (!this.domNode.getAttribute('role')) {
48        this.domNode.setAttribute('role', 'radiogroup');
49    }
50
51    var rbs = this.domNode.querySelectorAll('[role=radio], [role=tab]');
52
53    for (var i = 0; i < rbs.length; i++) {
54        var rb = new RadioButtonActiveDescendant(rbs[i], this);
55        rb.init();
56        this.radioButtons.push(rb);
57        if (!this.firstRadioButton) {
58            this.firstRadioButton = rb;
59        }
60        this.lastRadioButton = rb;
61    }
62    this.domNode.tabIndex = 0;
63};
64
65RadioGroup.prototype.setChecked = function (currentItem) {
66    for (var i = 0; i < this.radioButtons.length; i++) {
67        var rb = this.radioButtons[i];
68        rb.domNode.setAttribute('aria-checked', 'false');
69        rb.domNode.classList.remove('focus');
70    }
71    currentItem.domNode.setAttribute('aria-checked', 'true');
72    currentItem.domNode.classList.add('focus');
73    currentItem.domNode.click();
74    this.domNode.setAttribute('aria-activedescendant', currentItem.domNode.id);
75    this.domNode.focus();
76};
77
78RadioGroup.prototype.setCheckedToPreviousItem = function (currentItem) {
79    var index;
80
81    if (currentItem === this.firstRadioButton) {
82        this.setChecked(this.lastRadioButton);
83    }
84    else {
85        index = this.radioButtons.indexOf(currentItem);
86        this.setChecked(this.radioButtons[index - 1]);
87    }
88};
89
90RadioGroup.prototype.setCheckedToNextItem = function (currentItem) {
91    var index;
92
93    if (currentItem === this.lastRadioButton) {
94        this.setChecked(this.firstRadioButton);
95    }
96    else {
97        index = this.radioButtons.indexOf(currentItem);
98        this.setChecked(this.radioButtons[index + 1]);
99    }
100};
101
102RadioGroup.prototype.getCurrentRadioButton = function () {
103    var id = this.domNode.getAttribute('aria-activedescendant');
104    if (!id) {
105        this.domNode.setAttribute('aria-activedescendant', this.firstRadioButton.domNode.id);
106        return this.firstRadioButton;
107    }
108    for (var i = 0; i < this.radioButtons.length; i++) {
109        var rb = this.radioButtons[i];
110        if (rb.domNode.id === id) {
111            return rb;
112        }
113    }
114    this.domNode.setAttribute('aria-activedescendant', this.firstRadioButton.domNode.id);
115    return this.firstRadioButton;
116};
117
118// Event Handlers
119
120RadioGroup.prototype.handleKeydown = function (event) {
121    var flag = false;
122
123    var currentItem = this.getCurrentRadioButton();
124    switch (event.keyCode) {
125        case this.keyCode.SPACE:
126            this.setChecked(currentItem);
127            flag = true;
128            break;
129
130        case this.keyCode.UP:
131            this.setCheckedToPreviousItem(currentItem);
132            flag = true;
133            break;
134
135        case this.keyCode.DOWN:
136            this.setCheckedToNextItem(currentItem);
137            flag = true;
138            break;
139
140        case this.keyCode.LEFT:
141            this.setCheckedToPreviousItem(currentItem);
142            flag = true;
143            break;
144
145        case this.keyCode.RIGHT:
146            this.setCheckedToNextItem(currentItem);
147            flag = true;
148            break;
149
150        default:
151            break;
152    }
153
154    if (flag) {
155        event.stopPropagation();
156        event.preventDefault();
157    }
158};
159
160RadioGroup.prototype.handleFocus = function () {
161    var currentItem = this.getCurrentRadioButton();
162    currentItem.domNode.classList.add('focus');
163};
164
165RadioGroup.prototype.handleBlur = function () {
166    var currentItem = this.getCurrentRadioButton();
167    currentItem.domNode.classList.remove('focus');
168};

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.