TEST
WAI-ARIA メモ
最終更新:
eriax
-
view
aria-controls による連動型選択肢
<!DOCTYPE html>
<title>TEST</title>
<style type="text/css">
@media screen {
*[aria-hidden="true"] {
display: none;
}
*.aria-hidden {
display: none;
}
}
</style>
<script type="text/javascript">
var _GenerateAssociation =
function () {
var _SetAriaHidden_Select =
function () {
return function SetAriaHidden_Select (select) {
var controls = select.getAttribute ('aria-controls');
if (! controls) {
return;
}
controls = controls.split (/\s+/);
var index = select.selectedIndex - 1;
var count = controls.length;
var d = select.ownerDocument;
var i;
var n;
for (i = 0; i < index; ++i) {
n = d.getElementById (controls[i]);
if (! n) {
continue;
}
if (n.getAttribute ('aria-hidden') !== 'true') {
n.setAttribute ('aria-hidden', 'true');
_AddClass (n, 'aria-hidden');
}
_SetAriaHidden_All (n, true);
}
if (index < 0) {
_SetAriaHidden_All (select, true);
}
else {
n = d.getElementById (controls[index]);
if (n) {
n.setAttribute ('aria-hidden', 'false');
_RemoveClass (n, 'aria-hidden');
try {
var e = d.createEvent ('HTMLEvents');
e.initEvent ('change', false, false);
n.dispatchEvent (e);
}
catch (err) {
n.fireEvent ('onchange');
}
}
}
for (i += 1; i < count; ++i) {
n = d.getElementById (controls[i]);
if (! n) {
continue;
}
if (n.getAttribute ('aria-hidden') !== 'true') {
n.setAttribute ('aria-hidden', 'true');
_AddClass (n, 'aria-hidden');
}
_SetAriaHidden_All (n, true);
}
};
} ();
var _SetAriaHidden_All =
function () {
return function SetAriaHidden_All (elt, hidden) {
var controls = elt.getAttribute ('aria-controls');
if (! controls) {
return;
}
controls = controls.split (/\s+/);
hidden = String (hidden);
var count = controls.length;
var d = elt.ownerDocument;
var i;
var n;
for (i = 0; i < count; ++i) {
n = d.getElementById (controls[i]);
if (! n) {
continue;
}
n.setAttribute ('aria-hidden', hidden);
_AddClass (n, 'aria-hidden');
SetAriaHidden_All (n, hidden);
}
};
} ();
var _AddClass =
function () {
return function AddClass (elt, className) {
var c = elt.className;
k = className.replace (/\W/g, '$&');
if (! new RegExp ('(?:^|\s)' + k + '(?:\s|$)').test (c)) {
c += '\x20' + className;
elt.className = c.replace (/^\s+|\s+$/g, '').replace (/\s+/g, '\x20');
}
};
} ();
var _RemoveClass =
function () {
return function RemoveClass (elt, className) {
var c = elt.className;
k = className.replace (/\W/g, '$&');
if (new RegExp ('(?:^|\s)' + k + '(?:\s|$)').test (c)) {
c = c.replace (new RegExp (k), '');
elt.className = c.replace (/^\s+|\s+$/g, '').replace (/\s+/g, '\x20');
}
};
} ();
return function () {
return function GenerateAssociation (startIDs) {
return function handleEvent (e) {
switch (e.type) {
case 'load' :
var count = startIDs.length;
var d = e.target || this.document;
var i;
var c;
for (i = 0; i < count; ++i) {
c = d.getElementById (startIDs[i]);
if (c) {
_SetAriaHidden_All (c, true);
_SetAriaHidden_Select (c);
}
}
return;
case 'change' :
var c = e.currentTarget || this;
_SetAriaHidden_Select (c);
return;
}
};
};
} ();
} ();
var anAssociation1 = _GenerateAssociation ([ 'start' ]);
</script>
<body onload="return anAssociation1.call (this, event);">
<form action="#">
<p>
<select id="start" aria-controls="C1 C2 C3" onchange="return anAssociation1.call (this, event);">
<option>-</option>
<option>Category 1</option>
<option>Category 2</option>
<option>Category 3</option>
</select>
<select id="C1" aria-controls="C1-1 C1-2 C1-3" onchange="return anAssociation1.call (this, event);">
<option>-</option>
<option>Category 1-1</option>
<option>Category 1-2</option>
<option>Category 1-3</option>
</select>
<select id="C1-1">
<option>-</option>
<option>Category 1-1-1</option>
<option>Category 1-1-2</option>
<option>Category 1-1-3</option>
</select>
<select id="C1-2">
<option>-</option>
<option>Category 1-2-1</option>
<option>Category 1-2-2</option>
<option>Category 1-2-3</option>
</select>
<select id="C1-3">
<option>-</option>
<option>Category 1-3-1</option>
<option>Category 1-3-2</option>
<option>Category 1-3-3</option>
</select>
<select id="C2" aria-controls="C2-1 C2-2 C2-3" onchange="return anAssociation1.call (this, event);">
<option>-</option>
<option>Category 2-1</option>
<option>Category 2-2</option>
<option>Category 2-3</option>
</select>
<select id="C2-1">
<option>-</option>
<option>Category 2-1-1</option>
<option>Category 2-1-2</option>
<option>Category 2-1-3</option>
</select>
<select id="C2-2">
<option>-</option>
<option>Category 2-2-1</option>
<option>Category 2-2-2</option>
<option>Category 2-2-3</option>
</select>
<select id="C2-3">
<option>-</option>
<option>Category 2-3-1</option>
<option>Category 2-3-2</option>
<option>Category 2-3-3</option>
</select>
<select id="C3" aria-controls="C3-1 C3-2 C3-3" onchange="return anAssociation1.call (this, event);">
<option>-</option>
<option>Category 3-1</option>
<option>Category 3-2</option>
<option>Category 3-3</option>
</select>
<select id="C3-1">
<option>-</option>
<option>Category 3-1-1</option>
<option>Category 3-1-2</option>
<option>Category 3-1-3</option>
</select>
<select id="C3-2">
<option>-</option>
<option>Category 3-2-1</option>
<option>Category 3-2-2</option>
<option>Category 3-2-3</option>
</select>
<select id="C3-3">
<option>-</option>
<option>Category 3-3-1</option>
<option>Category 3-3-2</option>
<option>Category 3-3-3</option>
</select>
</p>
</form>
aria-controls と aria-labelledby
<!DOCTYPE html>
<title>TEST</title>
<body>
<form action="#" onclick="
var target = event.target || event.srcElement;
var currentTarget = event.currentTarget || this;
var doc = target.ownerDocument;
switch (target.tagName) {
case 'IMG' :
var source = target;
var result;
var t;
for (t = target; t; t = t.parentNode) {
result = t.getAttribute ('aria-controls');
if (result) {
result = doc.getElementById (result);
if (! result) {
break;
}
if (result.tagName === 'IMG') {
result.src = source.src;
result.alt = source.alt;
}
break;
}
if (t === currentTarget) {
break;
}
}
return;
case 'INPUT' :
var sources = target.getAttribute ('aria-labelledby');
var source;
var results;
var result;
var t;
var i;
if (! sources) {
return;
}
sources = sources.replace (/^\s+|\s+$/g, '').replace (/\s+/g, '\x20').split (/\x20/);
for (i = 0; source = sources[i]; ++i) {
source = doc.getElementById (source);
sources[i] = source ? (source.tagName === 'IMG') ? source : null : null;
}
for (t = target; t; t = t.parentNode) {
results = t.getAttribute ('aria-controls');
if (results) {
results = results.replace (/^\s+|\s+$/g, '').replace (/\s+/g, '\x20').split (/\x20/);
for (i = 0; result = results[i]; ++i) {
source = sources[i];
if (! source) {
continue;
}
result = doc.getElementById (result);
if (! result) {
continue;
}
if (result.tagName === 'IMG') {
result.src = source.src;
result.alt = source.alt;
}
}
}
if (t === currentTarget) {
break;
}
}
return;
}
">
<fieldset>
<legend>画像を選んで下さい</legend>
<ul>
<li aria-controls="A">
<span>A グループ:</span>
<img id="A0" src="A0.png" alt="A0">
<img id="A1" src="A1.png" alt="A1">
<img id="A2" src="A2.png" alt="A2">
<img id="A3" src="A3.png" alt="A3">
</li>
<li aria-controls="B">
<span>B グループ:</span>
<img id="B0" src="B0.png" alt="B0">
<img id="B1" src="B1.png" alt="B1">
</li>
<li aria-controls="C">
<span>C グループ:</span>
<img id="C0" src="C0.png" alt="C0">
<img id="C1" src="C1.png" alt="C1">
<img id="C2" src="C2.png" alt="C2">
</li>
</ul>
<ul>
<li aria-controls="A B C">
<input type="button" value="お勧めの組み合わせ 1" aria-labelledby="A0 B0 C1">
<input type="button" value="お勧めの組み合わせ 2" aria-labelledby="A3 B1 C0">
<input type="button" value="お勧めの組み合わせ 3" aria-labelledby="A2 B1 C1">
</li>
</ul>
<img src="0.png" alt="dummy">
</fieldset>
<fieldset>
<legend>結果</legend>
<p>
<img id="A" src="blank.png" alt="*">
<img id="B" src="blank.png" alt="*">
<img id="C" src="blank.png" alt="*">
</p>
</fieldset>
</form>