Index: Nevow/nevow/js/Divmod/Runtime/__init__.js
===================================================================
--- Nevow/nevow/js/Divmod/Runtime/__init__.js	(revision 9702)
+++ Nevow/nevow/js/Divmod/Runtime/__init__.js	(working copy)
@@ -484,6 +484,22 @@
      */
     function importNode(self, node, deep) {
         return document.importNode(node, deep);
+    },
+
+    /**
+     * Retrieve an element from the document by id, where the element is
+     * expected to be the child of a particular node (typically a widget's
+     * top-most node). Note that this method does not enforce that the element
+     * ultimately located is, in fact, a child of the node passed in; the API
+     * is merely to allow for platfom-specific workarounds for certain edge
+     * cases.
+     */
+    function getElementByIdWithNode(self, node, id) {
+        var foundNode = node.ownerDocument.getElementById(id);
+        if (foundNode == null) {
+            throw Divmod.Runtime.NodeNotFound('Node with id ' + id + ' not found');
+        }
+        return foundNode;
     });
 
 Divmod.Runtime.Firefox = Divmod.Runtime.Platform.subclass('Divmod.Runtime.Firefox');
@@ -740,6 +756,43 @@
         var tmpNode = document.createElement('div');
         tmpNode.innerHTML = nodeXML;
         return tmpNode.firstChild.cloneNode(deep);
+    },
+
+    function getElementByIdWithNode(self, node, id) {
+        var foundNode = node.ownerDocument.getElementById(id);
+        if (foundNode == null) {
+            // We didn't find it, maybe we need a workaround.
+
+            // Let's find the root node of the hierarchy.
+            var root = node;
+            while (root.parentNode != null) {
+                root = root.parentNode;
+            }
+
+            var DOCUMENT_FRAGMENT_NODE = 11;
+            if (root.nodeType == DOCUMENT_FRAGMENT_NODE) {
+                // We're in a DocumentFragment, and thus getElementById won't
+                // find any of our children. Let's insert ourselves into the
+                // document temporarily.
+                var currentParent = node.parentNode;
+                var nextSibling = node.nextSibling;
+                currentParent.removeChild(node);
+                document.documentElement.appendChild(node);
+
+                // Try again
+                foundNode = node.ownerDocument.getElementById(id);
+
+                // And now put us back where we used to be.
+                node.parentNode.removeChild(node);
+                currentParent.insertBefore(node, nextSibling);
+            }
+        }
+
+        if (foundNode == null) {
+            throw Divmod.Runtime.NodeNotFound('Node with id ' + id + ' not found');
+        }
+
+        return foundNode;
     });
 
 
Index: Nevow/nevow/js/Nevow/Athena/Tests/__init__.js
===================================================================
--- Nevow/nevow/js/Nevow/Athena/Tests/__init__.js	(revision 9702)
+++ Nevow/nevow/js/Nevow/Athena/Tests/__init__.js	(working copy)
@@ -286,6 +286,58 @@
         var node = self.childWidgets[0].nodeById('foo');
         self.assertEquals(node.className, 'foo');
         self.assertEquals(node.tagName.toLowerCase(), 'span');
+    },
+
+    /**
+     * Test that nodeById throws NodeNotFound when the node cannot be located.
+     */
+    function test_nodeByIdNotFound(self) {
+        var _find = function () { return self.childWidgets[0].nodeById('nonexistent'); };
+        self.assertThrows(Divmod.Runtime.NodeNotFound, _find);
+    },
+
+    function addDynamicWidget(self, child) {
+        var d = self.callRemote('getDynamicWidget');
+        d.addCallback(
+            function (widgetInfo) {
+                return child.addChildWidgetFromWidgetInfo(widgetInfo);
+            });
+        return d;
+    },
+
+    /**
+     * Test that nodeById is able to locate nodes in a dynamically instantiated
+     * widget that has not yet been added as a child somewhere in the browser
+     * document.
+     */
+    function test_nodeByIdInDynamicOrphan(self) {
+        var child = self.childWidgets[1];
+        var d = self.addDynamicWidget(child);
+        d.addCallback(
+            function (widget) {
+                var node = widget.nodeById('foo');
+                self.assertEquals(node.className, 'foo');
+                self.assertEquals(node.tagName.toLowerCase(), 'span');
+            });
+        return d;
+    },
+
+    /**
+     * Test that nodeById is able to locate nodes in a dynamically instantiated
+     * widget that has already been added as a child somewhere in the browser
+     * document.
+     */
+    function test_nodeByIdInDynamicChild(self) {
+        var child = self.childWidgets[1];
+        var d = self.addDynamicWidget(child);
+        d.addCallback(
+            function (widget) {
+                child.node.appendChild(widget.node);
+                var node = widget.nodeById('foo');
+                self.assertEquals(node.className, 'foo');
+                self.assertEquals(node.tagName.toLowerCase(), 'span');
+            });
+        return d;
     });
 
 
Index: Nevow/nevow/js/Nevow/Athena/__init__.js
===================================================================
--- Nevow/nevow/js/Nevow/Athena/__init__.js	(revision 9702)
+++ Nevow/nevow/js/Nevow/Athena/__init__.js	(working copy)
@@ -779,7 +779,8 @@
     },
 
     function nodeById(self, id) {
-        return document.getElementById('athenaid:' + self.objectID + '-' + id);
+        var translatedId = 'athenaid:' + self.objectID + '-' + id;
+        return Divmod.Runtime.theRuntime.getElementByIdWithNode(self.node, translatedId);
     },
 
     function nodesByAttribute(self, attrName, attrValue) {
Index: Nevow/nevow/test/livetest_athena.py
===================================================================
--- Nevow/nevow/test/livetest_athena.py	(revision 9702)
+++ Nevow/nevow/test/livetest_athena.py	(working copy)
@@ -328,7 +328,19 @@
         """
         e = NodeLocationSubElement1()
         e.setFragmentParent(self)
+        e2 = NodeLocationSubElement2()
+        e2.setFragmentParent(self)
+        return [e, e2]
+
+
+    def getDynamicWidget(self):
+        """
+        Return a widget dynamically for us to have more fun with.
+        """
+        e = NodeLocationSubElement1()
+        e.setFragmentParent(self)
         return e
+    expose(getDynamicWidget)
 
 
 
