浏览代码

LibWeb: Add the submit event to HTMLFormElement

Also adds the ability to submit from JavaScript.
Luke 4 年之前
父节点
当前提交
773df8826d

+ 1 - 0
Libraries/LibWeb/CMakeLists.txt

@@ -318,6 +318,7 @@ libweb_js_wrapper(HTML/HTMLUListElement)
 libweb_js_wrapper(HTML/HTMLUnknownElement)
 libweb_js_wrapper(HTML/HTMLVideoElement)
 libweb_js_wrapper(HTML/ImageData)
+libweb_js_wrapper(HTML/SubmitEvent)
 libweb_js_wrapper(HighResolutionTime/Performance)
 libweb_js_wrapper(SVG/SVGElement)
 libweb_js_wrapper(SVG/SVGGeometryElement)

+ 1 - 0
Libraries/LibWeb/Forward.h

@@ -270,6 +270,7 @@ class MouseEventWrapper;
 class NodeWrapper;
 class PerformanceWrapper;
 class ScriptExecutionContext;
+class SubmitEventWrapper;
 class SVGElementWrapper;
 class SVGGeometryElementWrapper;
 class SVGGraphicsElementWrapper;

+ 7 - 0
Libraries/LibWeb/HTML/HTMLElement.cpp

@@ -26,6 +26,7 @@
 
 #include <AK/StringBuilder.h>
 #include <LibWeb/DOM/Document.h>
+#include <LibWeb/HTML/HTMLAnchorElement.h>
 #include <LibWeb/HTML/HTMLElement.h>
 #include <LibWeb/Layout/TextNode.h>
 
@@ -131,4 +132,10 @@ String HTMLElement::inner_text()
     return builder.to_string();
 }
 
+bool HTMLElement::cannot_navigate() const
+{
+    // FIXME: Return true if element's node document is not fully active
+    return !is<HTML::HTMLAnchorElement>(this) && !is_connected();
+}
+
 }

+ 2 - 0
Libraries/LibWeb/HTML/HTMLElement.h

@@ -46,6 +46,8 @@ public:
     String inner_text();
     void set_inner_text(StringView);
 
+    bool cannot_navigate() const;
+
 private:
     virtual bool is_html_element() const final { return true; }
 

+ 40 - 1
Libraries/LibWeb/HTML/HTMLFormElement.cpp

@@ -25,8 +25,10 @@
  */
 
 #include <AK/StringBuilder.h>
+#include <LibWeb/HTML/EventNames.h>
 #include <LibWeb/HTML/HTMLFormElement.h>
 #include <LibWeb/HTML/HTMLInputElement.h>
+#include <LibWeb/HTML/SubmitEvent.h>
 #include <LibWeb/InProcessWebView.h>
 #include <LibWeb/Page/Frame.h>
 #include <LibWeb/URLEncoder.h>
@@ -42,8 +44,11 @@ HTMLFormElement::~HTMLFormElement()
 {
 }
 
-void HTMLFormElement::submit(RefPtr<HTMLInputElement> submitter)
+void HTMLFormElement::submit_form(RefPtr<HTMLElement> submitter, bool from_submit_binding)
 {
+    if (cannot_navigate())
+        return;
+
     if (action().is_null()) {
         dbg() << "Unsupported form action ''";
         return;
@@ -60,6 +65,35 @@ void HTMLFormElement::submit(RefPtr<HTMLInputElement> submitter)
         effective_method = "get";
     }
 
+    if (!from_submit_binding) {
+        if (m_firing_submission_events)
+            return;
+
+        m_firing_submission_events = true;
+
+        // FIXME: If the submitter element's no-validate state is false...
+
+        RefPtr<HTMLElement> submitter_button;
+
+        if (submitter != this)
+            submitter_button = submitter;
+
+        auto submit_event = SubmitEvent::create(EventNames::submit, submitter_button);
+        submit_event->set_bubbles(true);
+        submit_event->set_cancelable(true);
+        bool continue_ = dispatch_event(submit_event);
+
+        m_firing_submission_events = false;
+
+        if (!continue_)
+            return;
+
+        // This is checked again because arbitrary JS may have run when handling submit,
+        // which may have changed the result.
+        if (cannot_navigate())
+            return;
+    }
+
     URL url(document().complete_url(action()));
 
     if (!url.is_valid()) {
@@ -109,4 +143,9 @@ void HTMLFormElement::submit(RefPtr<HTMLInputElement> submitter)
         page->load(request);
 }
 
+void HTMLFormElement::submit()
+{
+    submit_form(this, true);
+}
+
 }

+ 7 - 1
Libraries/LibWeb/HTML/HTMLFormElement.h

@@ -41,7 +41,13 @@ public:
     String action() const { return attribute(HTML::AttributeNames::action); }
     String method() const { return attribute(HTML::AttributeNames::method); }
 
-    void submit(RefPtr<HTMLInputElement> submitter);
+    void submit_form(RefPtr<HTMLElement> submitter, bool from_submit_binding = false);
+
+    // NOTE: This is for the JS bindings. Use submit_form instead.
+    void submit();
+
+private:
+    bool m_firing_submission_events { false };
 };
 
 }

+ 2 - 0
Libraries/LibWeb/HTML/HTMLFormElement.idl

@@ -5,4 +5,6 @@ interface HTMLFormElement : HTMLElement {
     [Reflect=accept-charset] attribute DOMString acceptCharset;
     [Reflect=novalidate] attribute boolean noValidate;
 
+    void submit();
+
 }

+ 1 - 2
Libraries/LibWeb/HTML/HTMLInputElement.cpp

@@ -55,8 +55,7 @@ void HTMLInputElement::did_click_button(Badge<Layout::ButtonBox>)
 
     if (type().equals_ignoring_case("submit")) {
         if (auto* form = first_ancestor_of_type<HTMLFormElement>()) {
-            // FIXME: Remove this const_cast once we have a non-const first_ancestor_of_type.
-            form->submit(this);
+            form->submit_form(this);
         }
         return;
     }

+ 54 - 0
Libraries/LibWeb/HTML/SubmitEvent.h

@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <LibWeb/DOM/Event.h>
+
+namespace Web::HTML {
+
+class SubmitEvent final : public DOM::Event {
+public:
+    using WrapperType = Bindings::SubmitEventWrapper;
+
+    static NonnullRefPtr<SubmitEvent> create(const FlyString& event_name, RefPtr<HTMLElement> submitter)
+    {
+        return adopt(*new SubmitEvent(event_name, submitter));
+    }
+
+    const RefPtr<HTMLElement> submitter() const { return m_submitter; }
+
+private:
+    SubmitEvent(const FlyString& event_name, RefPtr<HTMLElement> submitter)
+        : DOM::Event(event_name)
+        , m_submitter(submitter)
+    {
+    }
+
+    RefPtr<HTMLElement> m_submitter;
+};
+
+}

+ 5 - 0
Libraries/LibWeb/HTML/SubmitEvent.idl

@@ -0,0 +1,5 @@
+interface SubmitEvent : Event {
+
+    readonly attribute HTMLElement? submitter;
+
+}