[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    Re: gmail problem investigated: frame onload
From:       Allan Sandfeld Jensen <kde () carewolf ! com>
Date:       2004-10-04 16:53:24
Message-ID: 200410041853.24905.kde () carewolf ! com
[Download RAW message or body]

On Monday 04 October 2004 16:41, David Faure wrote:
> With Rainder Endres' help, I managed to track down the reason gmail won't
> load. The onload event listener for frames and iframes is registered on the
> wrong body: the main body instead of the frame's body. Which means only one
> gets executed, and the JS code waits for ever.
>
> Testcase [gmail uses iframes, but it's the same with frames] :
>
> ==> blank.html <==
> Hello world
>
> ==> frameset.html <==
> <html>
> <frameset rows="*,*,*">
> <frame name="main" src="blank.html" onload="alert('loaded main')">
> <frame name="blank" src="blank.html" onload="alert('loaded blank')">
> </frameset>
> </html>
>
> The problem is HTMLFrameElementImpl::parseAttribute (for ATTR_ONLOAD).
> The code says:
>         static_cast<HTMLDocumentImpl*>( getDocument() )->body()->
>               setHTMLEventListener(EventImpl::LOAD_EVENT,
>            
> getDocument()->createHTMLEventListener(attr->value().string(),"onload"));
> And this obviously finds the main <body> element, since getDocument() for
> the frame element finds the main document.
>
> Did this ever work in KHTML? I thought it did, but looking at the code, I
> fail to see how. Since the attributes are parsed before the frame is
> "attached", so there is no KHTMLPart for the frame yet... i.e. no way to
> find the right document (or body) from that code. So do we need to store
> the value of the load and unload listeners until attach? We would then need
> to have some code somewhere that sets the listener on the frame's body when
> creating it..... I'm working now on a patch that attempts to do that.

I've been looking at how Safari handles it, and have come up with the attached 
patch. It works on your test example, but I do not have a gmail-account to 
test with.

`Allan

["safari.diff" (text/x-diff)]

Index: html/html_baseimpl.cpp
===================================================================
RCS file: /home/kde/kdelibs/khtml/html/html_baseimpl.cpp,v
retrieving revision 1.198
diff -u -3 -p -r1.198 html_baseimpl.cpp
--- html/html_baseimpl.cpp	16 Apr 2004 22:48:25 -0000	1.198
+++ html/html_baseimpl.cpp	4 Oct 2004 16:44:28 -0000
@@ -280,14 +280,12 @@ void HTMLFrameElementImpl::parseAttribut
         // when attached, has no effect
         break;
     case ATTR_ONLOAD:
-        static_cast<HTMLDocumentImpl*>( getDocument() )->body()
-              ->setHTMLEventListener(EventImpl::LOAD_EVENT,
-            getDocument()->createHTMLEventListener(attr->value().string(),"onload"));
 +        setHTMLEventListener(EventImpl::LOAD_EVENT,
+                                \
getDocument()->createHTMLEventListener(attr->value().string(),"onload"));  break;
     case ATTR_ONUNLOAD:
-        static_cast<HTMLDocumentImpl*>( getDocument() )->body()
-              ->setHTMLEventListener(EventImpl::UNLOAD_EVENT,
-            getDocument()->createHTMLEventListener(attr->value().string(),"onunload"));
 +        setHTMLEventListener(EventImpl::UNLOAD_EVENT,
+                                \
getDocument()->createHTMLEventListener(attr->value().string(),"onunload"));  break;

     default:
Index: xml/dom_docimpl.cpp
===================================================================
RCS file: /home/kde/kdelibs/khtml/xml/dom_docimpl.cpp,v
retrieving revision 1.292
diff -u -3 -p -r1.292 dom_docimpl.cpp
--- xml/dom_docimpl.cpp	19 Sep 2004 13:33:06 -0000	1.292
+++ xml/dom_docimpl.cpp	4 Oct 2004 16:44:29 -0000
@@ -50,6 +50,7 @@
 #include "rendering/render_replaced.h"
 #include "rendering/render_arena.h"
 #include "rendering/render_layer.h"
+#include "rendering/render_frames.h"

 #include "khtmlview.h"
 #include "khtml_part.h"
@@ -1670,7 +1671,7 @@ NodeImpl::Id DocumentImpl::getId( NodeIm
     QConstString n(_name->s, _name->l);
     bool cs = true; // case sensitive
     if (_type != NodeImpl::NamespaceId) {
-        if (_nsURI)
+        if (_nsURI)
             nsid = getId( NodeImpl::NamespaceId, 0, 0, _nsURI, false, false, 0 ) << \
16;

         // Each document maintains a mapping of tag name -> id for every tag name \
encountered @@ -2271,6 +2272,58 @@ void DocumentImpl::setDecoderCodec(const
     m_decoderMibEnum = codec->mibEnum();
 }

+ElementImpl *DocumentImpl::ownerElement()
+{
+    KHTMLView *childView = view();
+    if (!childView)
+        return 0;
+    KHTMLPart *childPart = childView->part();
+    if (!childPart)
+        return 0;
+    KHTMLPart *parent = childPart->parentPart();
+    if (!parent)
+        return 0;
+    ChildFrame *childFrame = parent->frame(childPart);
+    if (!childFrame)
+        return 0;
+    RenderPart *renderPart = childFrame->m_frame;
+    if (!renderPart)
+        return 0;
+    return static_cast<ElementImpl *>(renderPart->element());
+}
+
+DOMString DocumentImpl::domain() const
+{
+    if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and \
space) +        m_domain = KURL(URL()).host(); // Initially set to the host
+    return m_domain;
+}
+
+void DocumentImpl::setDomain(const DOMString &newDomain, bool force /*=false*/)
+{
+    if ( force ) {
+        m_domain = newDomain;
+        return;
+    }
+    if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and \
space) +        m_domain = KURL(URL()).host(); // Initially set to the host
+
+    // Both NS and IE specify that changing the domain is only allowed when
+    // the new domain is a suffix of the old domain.
+    int oldLength = m_domain.length();
+    int newLength = newDomain.length();
+    if ( newLength < oldLength ) // e.g. newDomain=kde.org (7) and \
m_domain=www.kde.org (11) +    {
+        DOMString test = m_domain.copy();
+        if ( test[oldLength - newLength - 1] == '.' ) // Check that it's a \
subdomain, not e.g. "de.org" +        {
+            test.remove( 0, oldLength - newLength ); // now test is "kde.org" from \
m_domain +            if ( test == newDomain )                 // and we check that \
it's the same thing as newDomain +                m_domain = newDomain;
+        }
+    }
+}
+
 DOMString DocumentImpl::toString() const
 {
     DOMString result;
Index: xml/dom_docimpl.h
===================================================================
RCS file: /home/kde/kdelibs/khtml/xml/dom_docimpl.h,v
retrieving revision 1.133
diff -u -3 -p -r1.133 dom_docimpl.h
--- xml/dom_docimpl.h	19 Sep 2004 13:33:06 -0000	1.133
+++ xml/dom_docimpl.h	4 Oct 2004 16:44:29 -0000
@@ -426,6 +426,13 @@ public:
      */
     void processHttpEquiv(const DOMString &equiv, const DOMString &content);

+    // Returns the owning element in the parent document.
+    // Returns 0 if this is the top level document.
+    ElementImpl *ownerElement();
+
+    DOMString domain() const;
+    void setDomain( const DOMString &newDomain, bool force = false ); // not part of \
the DOM +
     bool isURLAllowed(const QString& url) const;

     DOMString toString() const;
@@ -519,6 +526,9 @@ protected:
     int m_decoderMibEnum;

     khtml::RenderArena* m_renderArena;
+
+private:
+    mutable DOMString m_domain;
 };

 class DocumentFragmentImpl : public NodeBaseImpl
Index: xml/dom_nodeimpl.cpp
===================================================================
RCS file: /home/kde/kdelibs/khtml/xml/dom_nodeimpl.cpp,v
retrieving revision 1.238
diff -u -3 -p -r1.238 dom_nodeimpl.cpp
--- xml/dom_nodeimpl.cpp	8 Sep 2004 12:59:38 -0000	1.238
+++ xml/dom_nodeimpl.cpp	4 Oct 2004 16:44:29 -0000
@@ -323,10 +323,14 @@ void NodeImpl::addEventListener(int id,
 	m_regdListeners->setAutoDelete(true);
     }

-    // remove existing ones of the same type - ### is this correct (or do we ignore \
the new one?) +    listener->ref();
+
+    // remove existing identical listener set with identical arguments - the DOM2
+    // spec says that "duplicate instances are discarded" in this case.
     removeEventListener(id,listener,useCapture);

     m_regdListeners->append(rl);
+    listener->deref();
 }

 void NodeImpl::removeEventListener(int id, EventListener *listener, bool useCapture)
@@ -491,6 +495,28 @@ void NodeImpl::dispatchWindowEvent(int _
     dispatchGenericEvent( evt, exceptioncode );
     if (!evt->defaultPrevented() && doc->document())
 	doc->document()->defaultEventHandler(evt);
+
+    if (_id == EventImpl::LOAD_EVENT && !evt->propagationStopped() && \
doc->document()) { +        // For onload events, send them to the enclosing frame \
only. +        // This is a DOM extension and is independent of bubbling/capturing \
rules of +        // the DOM.  You send the event only to the enclosing frame.  It \
does not +        // bubble through the parent document.
+        DOM::ElementImpl* elt = doc->document()->ownerElement();
+        if (elt && (elt->getDocument()->domain().isNull() ||
+                    elt->getDocument()->domain() == doc->document()->domain())) {
+            // We also do a security check, since we don't want to allow the \
enclosing +            // iframe to see loads of child documents in other domains.
+            evt->setCurrentTarget(elt);
+
+            // Capturing first.
+            elt->handleLocalEvents(evt,true);
+
+            // Bubbling second.
+            if (!evt->propagationStopped())
+                elt->handleLocalEvents(evt,false);
+        }
+    }
+
     doc->deref();
     evt->deref();
 }



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic