Revision: 3834
Author: felix8a
Date: Thu Nov 5 14:56:31 2009
Log: event-related fixes for IE
http://codereview.appspot.com/140051
This fixes http://code.google.com/p/google-caja/issues/detail?id=1132
1. Support event.currentTarget on IE.
2. YUI has a couple special behaviors on IE.
Since YUI in caja on IE will detect the browser as IE,
YUI will try to do the IE-specific things:
2a. IE doesn't support event.relatedTarget,
so YUI tries to set it.
Caja does support event.relatedTarget,
and it's read-only (per DOM spec),
so YUI's attempt to set it throws an exception.
This change adds a relatedTarget setter that
ignores the new value and doesn't throw.
2b. IE has some non-standard functions that
YUI will call: el.hasFocus() and el.setActive().
setActive is a weaker form of focus().
It makes the element 'active',
which means it will have focus when the window gets focus,
but doesn't force the window to be focused.
This change adds support for both methods,
delegating to the IE functions.
el.setActive() is restricted the same way as el.focus(),
it's only allowed when isProcessingEvent___
[email protected]
http://code.google.com/p/google-caja/source/detail?r=3834
Modified:
/trunk/src/com/google/caja/plugin/domita.js
/trunk/tests/com/google/caja/plugin/domita_test_untrusted.html
=======================================
--- /trunk/src/com/google/caja/plugin/domita.js Thu Oct 15 15:42:13 2009
+++ /trunk/src/com/google/caja/plugin/domita.js Thu Nov 5 14:56:31 2009
@@ -2135,6 +2135,23 @@
this.node___.focus();
}
};
+ // IE-specific method. Sets the element that will have focus when the
+ // window has focus, without focusing the window.
+ if (document.documentElement.setActive) {
+ TameElement.prototype.setActive = function () {
+ if (imports.isProcessingEvent___) {
+ this.node___.setActive();
+ }
+ };
+ ___.grantTypedMethod(TameElement.prototype, 'setActive');
+ }
+ // IE-specific method.
+ if (document.documentElement.hasFocus) {
+ TameElement.prototype.hasFocus = function () {
+ return this.node___.hasFocus();
+ };
+ ___.grantTypedMethod(TameElement.prototype, 'hasFocus');
+ }
TameElement.prototype.getId = function () {
return this.getAttribute('id') || '';
};
@@ -2947,6 +2964,14 @@
}
return tameRelatedNode(t, true, defaultTameNode);
};
+ // relatedTarget is read-only. this dummy setter is because some code
+ // tries to workaround IE by setting a relatedTarget when it's not set.
+ // code in a sandbox can't tell the difference between "falsey because
+ // relatedTarget is not supported" and "falsey because relatedTarget is
+ // outside sandbox".
+ TameEvent.prototype.setRelatedTarget = function (newValue) {
+ return newValue;
+ };
TameEvent.prototype.getFromElement = function () {
return tameRelatedNode(this.event___.fromElement, true,
defaultTameNode);
};
@@ -4065,6 +4090,10 @@
*/
function plugin_dispatchEvent___(thisNode, event, pluginId, handler) {
event = (event || window.event);
+ // support currentTarget on IE[678]
+ if (!event.currentTarget) {
+ event.currentTarget = thisNode;
+ }
var sig = String(handler).match(/^function\b[^\)]*\)/);
var imports = ___.getImports(pluginId);
if (imports.domitaTrace___ & 0x1) {
=======================================
--- /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Wed Nov
4 20:56:10 2009
+++ /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Thu Nov
5 14:56:31 2009
@@ -18,15 +18,26 @@
.testcontainer { background: yellow; border: 2px solid yellow }
.clickme { border: 2px solid fuchsia; }
.waiting { border: 2px solid aqua; }
+ .manual { background: #eef; border: 2px solid #00f; }
.passed { background: #c0ffc0; border: 2px solid #c0ffc0 }
.invisible { display: none; float: left }
.inline { display: inline }
</style>
-<p class="waiting testcontainer" id="test-timeout-and-interval">
- Timeouts and Intervals<br>
+<p class="manual testcontainer" id="test-related-target-mouse-container">
+ <span id="test-related-target-mouse">
+ Move mouse here to see event.relatedTarget.
+ Rapid motion from outside sandbox should show a null relatedTarget.
+ </span>
+ <br />
+ <span id="test-related-target-mouse-info"> </span>
</p>
+<p class="clickme testcontainer" id="test-related-target">
+ <b id="test-related-target-child">click me (test-related-target)
+ </b>
+</p>
+
<p class="clickme testcontainer" id="test-add-event-listener">
<b id="test-add-event-listener-label">click me</b>
</p>
@@ -87,7 +98,16 @@
onclick="pass('test-onclick-handler');">click me</b>
</p>
+<p class="clickme testcontainer" id="test-current-target">
+ <b id="test-current-target-child">click me</b>
+</p>
+
+<p class="waiting testcontainer" id="test-timeout-and-interval">
+ Timeouts and Intervals<br>
+</p>
+
<br>
+
<div class="testcontainer" id="test-document-write">
<div>
<p>Before <code>document.write</code></p>
@@ -909,6 +929,57 @@
// nothing to do here
});
+jsunitRegister('testCurrentTarget',
+ function testCurrentTarget() {
+ var parent = document.getElementById('test-current-target');
+ var child = document.getElementById('test-current-target-child');
+ var gotChildClick = false;
+ parent.addEventListener('click', parentClick, false);
+ child.addEventListener('click', childClick, false);
+
+ function childClick(event) {
+ assertEquals('test-current-target-child', event.currentTarget.id);
+ gotChildClick = true;
+ }
+
+ function parentClick(event) {
+ assertEquals('test-current-target', event.currentTarget.id);
+ assertTrue(gotChildClick);
+ pass('test-current-target');
+ }
+});
+
+jsunitRegister('testRelatedTarget',
+ function testRelatedTarget() {
+ var child = document.getElementById('test-related-target-child');
+ child.addEventListener('click', childClick, false);
+
+ function childClick(event) {
+ // get should work. in manual clicks, relatedTarget is null, but in
+ // webdriver simulated clicks, it's non-null.
+ assertEquals(event.relatedTarget, event.relatedTarget);
+ // set doesn't have to work, but shouldn't throw an error
+ event.relatedTarget = [];
+ pass('test-related-target');
+ }
+
+ // TODO: webdriver doesn't have a good way of testing relatedTarget.
+ // there are two cases we care about: relatedTarget is an element in the
+ // sandbox, and relatedTarget is an element outside the sandbox.
+
+ var mouse = document.getElementById('test-related-target-mouse');
+ var info = document.getElementById('test-related-target-mouse-info');
+ mouse.addEventListener('mouseover', mouseReport, false);
+ mouse.addEventListener('mouseout', mouseReport, false);
+
+ function mouseReport(event) {
+ var r = event.relatedTarget;
+ r = r && (r.tagName + '#' + r.id);
+ info.innerHTML = event.type + ' ' + String(r);
+ }
+});
+
+
jsunitRegister('testDocumentWrite',
function testDocumentWrite() {
// TODO(mikesamuel): This is wrong because we don't allow the insertion
point
@@ -3061,13 +3132,18 @@
var input = document.getElementById('test-focus-blur-1');
input.focus();
input.blur();
- // TODO: verify focus does change. requires an event-driven tester.
+ // IE specific methods
+ if (input.hasFocus) {
+ assertEquals('boolean', typeof input.hasFocus());
+ }
+ if (input.setActive) {
+ input.setActive();
+ }
+ // TODO: can't verify focus changes in webdriver, because webdriver runs
+ // without focusing the browser window, so onfocus never gets fired.
pass('test-focus-blur');
});
-// TODO: can't test onfocus/onblur in webdriver, because webdriver
-// runs without focusing the browser, so onfocus never fires.
-
// form:onreset uses the same logic path as input:onfocus
jsunitRegister('testOnReset',
function testOnReset() {