<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, KeyboardEvent.DOM_VK_RETURN); testOk('accessKey(\n)', 0, KeyboardEvent.DOM_VK_RETURN); // New line testOk('accessKey(\r)', 0, KeyboardEvent.DOM_VK_RETURN); // Carriage return testOk('accessKey(\x08)', 0, KeyboardEvent.DOM_VK_BACK_SPACE); testOk('accessKey(\x1B)', 0, KeyboardEvent.DOM_VK_ESCAPE); testOk('accessKey(\x7F)', 0, KeyboardEvent.DOM_VK_DELETE); // 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.name, "InvalidStateError", "Unexpected exception: " + e.name); is(e.code, DOMException.INVALID_STATE_ERR, "Unexpected exception code: " + e.code); 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.name, "InvalidStateError", "Unexpected exception:" + e.name); 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>