зеркало из https://github.com/mozilla/gecko-dev.git
360 строки
11 KiB
HTML
360 строки
11 KiB
HTML
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<title>Test for SMIL accessKey support</title>
|
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
</head>
|
|
<body>
|
|
<a target="_blank"
|
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=587910">Mozilla Bug
|
|
587910</a>
|
|
<p id="display"></p>
|
|
<div id="content" style="display: none">
|
|
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
|
|
<circle cx="20" cy="20" r="15" fill="blue" id="circle"/>
|
|
</svg>
|
|
</div>
|
|
<pre id="test">
|
|
<script class="testbody" type="text/javascript">
|
|
<![CDATA[
|
|
/** Test for SMIL accessKey support **/
|
|
|
|
const gSvgns = "http://www.w3.org/2000/svg";
|
|
var gSvg = document.getElementById("svg");
|
|
SimpleTest.waitForExplicitFinish();
|
|
|
|
function main()
|
|
{
|
|
gSvg.pauseAnimations();
|
|
|
|
// Basic syntax
|
|
testOk('accessKey(a)', 'a');
|
|
testOk(' accessKey(a) ', 'a');
|
|
testNotOk('accessKey (a)', 'a');
|
|
testNotOk('accessKey( a)', 'a');
|
|
testNotOk('accessKey(a )', 'a');
|
|
testNotOk('accessKey(a)', 'b');
|
|
testNotOk('accessKey()', ' ');
|
|
|
|
// Test the test framework itself
|
|
testOk('accessKey(a)', 97);
|
|
|
|
// Allow for either accessKey (SVG / SMIL Animation) or accesskey (SMIL2+)
|
|
testOk('accesskey(a)', 'a');
|
|
|
|
// Offset
|
|
testOk('accessKey(a)+0s', 'a');
|
|
testOk('accessKey(a) + 0min', 'a');
|
|
testOk('accessKey(a) -0h', 'a');
|
|
testOk('accessKey(a)+100ms', 'a', 0, 0.1);
|
|
testOk('accessKey(a)-0.1s', 'a', 0, -0.1);
|
|
|
|
// Id references are not allowed
|
|
testNotOk('svg.accessKey(a)', 'a');
|
|
testNotOk('window.accessKey(a)', 'a');
|
|
|
|
// Case sensitivity
|
|
testOk('accessKey(A)', 'A');
|
|
testNotOk('accessKey(a)', 'A');
|
|
testNotOk('accessKey(A)', 'a');
|
|
|
|
// Test unusual characters
|
|
testOk('accessKey(-)', '-');
|
|
testOk('accessKey(\\)', '\\');
|
|
testOk('accessKey( )', ' ');
|
|
testOk('accessKey(\x0D)', 0, 13); // Return
|
|
testOk('accessKey(\x0D)', 0, 14); // Enter
|
|
testOk('accessKey(\n)', 0, 13); // New line
|
|
testOk('accessKey(\r)', 0, 13); // Carriage return
|
|
testOk('accessKey(\x08)', 0, 8); // Backspace
|
|
testOk('accessKey(\x1B)', 0, 0x1B); // Escape
|
|
testOk('accessKey(\x7F)', 0, 46); // Del
|
|
|
|
// Check some disallowed keys
|
|
// -- For now we don't allow tab since the interaction with focus causes
|
|
// confusing results
|
|
testNotOk('accessKey(\x09)', 0, 9); // Tab
|
|
|
|
// Test setting the keyCode field
|
|
testNotOk('accessKey(a)', 0, 97);
|
|
testOk('accessKey(a)', 97, 66); // Give priority to charCode field
|
|
testNotOk('accessKey(a)', 98, 97); // Give priority to charCode field
|
|
|
|
// Test unicode
|
|
testOk("accessKey(\u20AC)", 8364); // euro-symbol
|
|
|
|
// Test an astral character just to make sure we don't crash
|
|
testOk("accessKey(\uD835\uDC00)", 119808); // mathematical bold capital A
|
|
// 0x1D400
|
|
// Test bad surrogate pairs don't confuse us either
|
|
testNotOk("accessKey(\uD800\uD800)", 97);
|
|
testNotOk("accessKey(\uD80020)", 97);
|
|
testNotOk("accessKey(\uD800)", 97);
|
|
|
|
// Test modifiers
|
|
// -- When matching on charCode ignore shift and alt
|
|
testNotOk('accessKey(a)', 'a', 0, 0, { ctrl: true });
|
|
testNotOk('accessKey(a)', 'a', 0, 0, { meta: true });
|
|
testOk('accessKey(a)', 'a', 0, 0, { alt: true });
|
|
testOk('accessKey(a)', 'a', 0, 0, { shift: true });
|
|
testNotOk('accessKey(a)', 'a', 0, 0, { shift: true, ctrl: true });
|
|
testNotOk('accessKey(a)', 'a', 0, 0, { alt: true, meta: true });
|
|
// -- When matching on keyCode ignore all
|
|
testNotOk('accessKey(\x0D)', 0, 13, 0, { ctrl: true });
|
|
testNotOk('accessKey(\x0D)', 0, 13, 0, { meta: true });
|
|
testNotOk('accessKey(\x0D)', 0, 13, 0, { alt: true });
|
|
testNotOk('accessKey(\x0D)', 0, 13, 0, { shift: true });
|
|
testNotOk('accessKey(\x0D)', 0, 13, 0, { shift: true, ctrl: true });
|
|
|
|
testOpenEnd();
|
|
testPreventDefault();
|
|
testDispatchToWindow();
|
|
testAdoptNode();
|
|
testFauxEvent();
|
|
|
|
SimpleTest.finish();
|
|
}
|
|
|
|
function testOk(spec, charCode, keyCode, offset, modifiers)
|
|
{
|
|
if (typeof offset == 'undefined') offset = 0;
|
|
var msg = "No interval created for '" + spec +
|
|
"' with input [charCode: " + charCode + "; keyCode: " + keyCode + "]" +
|
|
getModifiersDescr(modifiers);
|
|
ok(test(spec, charCode, keyCode, offset, modifiers), msg);
|
|
}
|
|
|
|
function testNotOk(spec, charCode, keyCode, offset, modifiers)
|
|
{
|
|
if (typeof offset == 'undefined') offset = 0;
|
|
var msg = "Interval unexpectedly created for '" + spec +
|
|
"' with input [charCode: " + charCode + "; keyCode: " + keyCode + "]" +
|
|
getModifiersDescr(modifiers);
|
|
ok(!test(spec, charCode, keyCode, offset, modifiers), msg);
|
|
}
|
|
|
|
function getModifiersDescr(modifiers)
|
|
{
|
|
if (typeof modifiers != 'object')
|
|
return '';
|
|
var str = ' modifiers set:';
|
|
for (var key in modifiers) {
|
|
if (modifiers[key]) str += ' ' + key;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
function test(spec, charCode, keyCode, offset, modifiers)
|
|
{
|
|
gSvg.setCurrentTime(1);
|
|
ok(gSvg.animationsPaused(), "Expected animations to be paused");
|
|
|
|
var anim = createAnim(spec);
|
|
var evt = createEvent(charCode, keyCode, modifiers);
|
|
|
|
document.getElementById('circle').dispatchEvent(evt);
|
|
|
|
var gotStartTimeOk = true;
|
|
try {
|
|
var start = anim.getStartTime();
|
|
if (offset) {
|
|
var expected = gSvg.getCurrentTime() + offset;
|
|
ok(Math.abs(expected - start) <= 0.00001,
|
|
"Unexpected start time for animation with begin: " + spec +
|
|
" got " + start + ", expected " + expected);
|
|
} else {
|
|
is(start, gSvg.getCurrentTime() + offset,
|
|
"Unexpected start time for animation with begin: " + spec);
|
|
}
|
|
} catch(e) {
|
|
is(e.code, DOMException.INVALID_STATE_ERR,
|
|
"Unexpected exception code: " + e);
|
|
gotStartTimeOk = false;
|
|
}
|
|
|
|
anim.parentNode.removeChild(anim);
|
|
|
|
return gotStartTimeOk;
|
|
}
|
|
|
|
function createAnim(beginSpec)
|
|
{
|
|
var anim = document.createElementNS(gSvgns, 'animate');
|
|
anim.setAttribute('attributeName', 'cx');
|
|
anim.setAttribute('values', '0; 100');
|
|
anim.setAttribute('dur', '10s');
|
|
anim.setAttribute('begin', beginSpec);
|
|
return document.getElementById('circle').appendChild(anim);
|
|
}
|
|
|
|
function createEvent(charCode, keyCode, modifiers)
|
|
{
|
|
if (typeof charCode == 'string') {
|
|
is(charCode.length, 1,
|
|
"If charCode is a string it should be 1 character long");
|
|
charCode = charCode.charCodeAt(0);
|
|
} else if (typeof charCode == 'undefined') {
|
|
charCode = 0;
|
|
}
|
|
args = { ctrl: false, alt: false, shift: false, meta: false };
|
|
if (typeof modifiers == 'object') {
|
|
for (var key in modifiers)
|
|
args[key] = modifiers[key];
|
|
}
|
|
if (typeof keyCode == 'undefined') keyCode = 0;
|
|
var evt = document.createEvent("KeyboardEvent");
|
|
evt.initKeyEvent("keypress", true, true, window,
|
|
args['ctrl'],
|
|
args['alt'],
|
|
args['shift'],
|
|
args['meta'],
|
|
keyCode,
|
|
charCode);
|
|
return evt;
|
|
}
|
|
|
|
function testOpenEnd()
|
|
{
|
|
// Test that an end specification with an accesskey value is treated as open
|
|
// ended
|
|
gSvg.setCurrentTime(0);
|
|
ok(gSvg.animationsPaused(), "Expected animations to be paused");
|
|
|
|
var anim = createAnim('0s; 2s');
|
|
anim.setAttribute('end', '1s; accessKey(a)');
|
|
|
|
gSvg.setCurrentTime(2);
|
|
|
|
try {
|
|
is(anim.getStartTime(), 2,
|
|
"Unexpected start time for second interval of open-ended animation");
|
|
} catch(e) {
|
|
is(e.code, DOMException.INVALID_STATE_ERR,
|
|
"Unexpected exception code:" + e.code);
|
|
ok(false, "Failed to recognise accessKey as qualifying for creating an " +
|
|
"open-ended interval");
|
|
}
|
|
|
|
anim.parentNode.removeChild(anim);
|
|
}
|
|
|
|
function testPreventDefault()
|
|
{
|
|
// SVG/SMIL don't specify what should happen if preventDefault is called on
|
|
// the keypress event. For now, for consistency with event timing we ignore
|
|
// it.
|
|
gSvg.setCurrentTime(1);
|
|
ok(gSvg.animationsPaused(), "Expected animations to be paused");
|
|
|
|
var anim = createAnim('accessKey(a)');
|
|
var evt = createEvent('a');
|
|
|
|
var circle = document.getElementById('circle');
|
|
var func = function(evt) { evt.preventDefault(); }
|
|
circle.addEventListener('keypress', func, false);
|
|
circle.dispatchEvent(evt);
|
|
|
|
try {
|
|
var start = anim.getStartTime();
|
|
} catch(e) {
|
|
ok(false, "preventDefault() cancelled accessKey handling");
|
|
}
|
|
|
|
circle.removeEventListener('keypress', func, false);
|
|
anim.parentNode.removeChild(anim);
|
|
}
|
|
|
|
function testDispatchToWindow()
|
|
{
|
|
gSvg.setCurrentTime(1);
|
|
ok(gSvg.animationsPaused(), "Expected animations to be paused");
|
|
|
|
var anim = createAnim('accessKey(a)');
|
|
var evt = createEvent('a');
|
|
|
|
window.dispatchEvent(evt);
|
|
|
|
try {
|
|
var start = anim.getStartTime();
|
|
} catch(e) {
|
|
ok(false, "Key event dispatched to the window failed to trigger " +
|
|
"accesskey handling");
|
|
}
|
|
|
|
anim.parentNode.removeChild(anim);
|
|
}
|
|
|
|
function testAdoptNode()
|
|
{
|
|
gSvg.setCurrentTime(1);
|
|
ok(gSvg.animationsPaused(), "Expected animations to be paused");
|
|
|
|
// Create a new document with an animation element
|
|
var newdoc = document.implementation.createDocument(gSvgns, 'svg', null);
|
|
var anim = newdoc.createElementNS(gSvgns, 'animate');
|
|
anim.setAttribute('attributeName', 'cx');
|
|
anim.setAttribute('values', '0; 100');
|
|
anim.setAttribute('dur', '10s');
|
|
anim.setAttribute('begin', 'accesskey(a)');
|
|
newdoc.documentElement.appendChild(anim);
|
|
|
|
// Adopt
|
|
ok(anim.ownerDocument !== document,
|
|
"Expected newly created animation to belong to a different doc");
|
|
document.adoptNode(anim);
|
|
document.getElementById('circle').appendChild(anim);
|
|
ok(anim.ownerDocument === document,
|
|
"Expected newly created animation to belong to the same doc");
|
|
|
|
var evt = createEvent('a');
|
|
|
|
// Now fire an event at the original window and check nothing happens
|
|
newdoc.dispatchEvent(evt);
|
|
try {
|
|
var start = anim.getStartTime();
|
|
ok(false, "Adopted node still receiving accesskey events from old doc");
|
|
} catch(e) {
|
|
// Ok
|
|
}
|
|
|
|
// And then fire at our window
|
|
document.dispatchEvent(evt);
|
|
try {
|
|
var start = anim.getStartTime();
|
|
} catch(e) {
|
|
ok(false, "Adopted node failed to catch accesskey event");
|
|
}
|
|
|
|
anim.parentNode.removeChild(anim);
|
|
}
|
|
|
|
function testFauxEvent()
|
|
{
|
|
// Test a non-KeyEvent labelled as a key event
|
|
gSvg.setCurrentTime(0);
|
|
ok(gSvg.animationsPaused(), "Expected animations to be paused");
|
|
|
|
var anim = createAnim('accessKey(a)');
|
|
var evt = document.createEvent("SVGEvents");
|
|
evt.initEvent("keypress", true, true);
|
|
document.getElementById('circle').dispatchEvent(evt);
|
|
|
|
// We're really just testing that the above didn't crash us, but while we're
|
|
// at it, just do a sanity check that we didn't also create an interval
|
|
try {
|
|
var start = anim.getStartTime();
|
|
ok(false, "Faux event generated interval");
|
|
} catch(e) {
|
|
// All is well
|
|
}
|
|
|
|
anim.parentNode.removeChild(anim);
|
|
}
|
|
|
|
window.addEventListener("load", main, false);
|
|
]]>
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|