Index: Source/core/html/HTMLFormElement.cpp |
diff --git a/Source/core/html/HTMLFormElement.cpp b/Source/core/html/HTMLFormElement.cpp |
index 089fde6522475add928e10b5772f182147afaf8d..0406277c9d5ad14758e591d26e814e464dcb59dd 100644 |
--- a/Source/core/html/HTMLFormElement.cpp |
+++ b/Source/core/html/HTMLFormElement.cpp |
@@ -28,9 +28,12 @@ |
#include <limits> |
#include "HTMLNames.h" |
#include "bindings/v8/Dictionary.h" |
+#include "bindings/v8/NewScriptState.h" |
#include "bindings/v8/ScriptController.h" |
#include "bindings/v8/ScriptEventListener.h" |
+#include "bindings/v8/ScriptPromiseResolverWithContext.h" |
#include "core/dom/Attribute.h" |
+#include "core/dom/AutocompleteError.h" |
#include "core/dom/Document.h" |
#include "core/dom/ElementTraversal.h" |
#include "core/dom/IdTargetObserverRegistry.h" |
@@ -85,6 +88,60 @@ HTMLFormElement::~HTMLFormElement() |
document().formController().willDeleteForm(this); |
} |
+class AutocompleteRequest { |
+public: |
+ static PassOwnPtr<AutocompleteRequest> create(HTMLFormElement* form) |
+ { |
+ return adoptPtr(new AutocompleteRequest(form)); |
+ } |
+ |
+ ScriptPromise promise() |
+ { |
+ return m_resolver->promise(); |
+ } |
+ |
+ void setResult(HTMLFormElement::AutocompleteResult result) |
+ { |
+ ASSERT(!m_isResultSet); |
+ m_result = result; |
+ m_isResultSet = true; |
+ } |
+ |
+ void dispatchAndFulfill() |
+ { |
+ ASSERT(m_isResultSet); |
+ |
+ String reason; |
+ if (m_result == HTMLFormElement::AutocompleteResultErrorDisabled) |
+ reason = "disabled"; |
+ else if (m_result == HTMLFormElement::AutocompleteResultErrorCancel) |
+ reason = "cancel"; |
+ else if (m_result == HTMLFormElement::AutocompleteResultErrorInvalid) |
+ reason = "invalid"; |
+ |
+ RefPtrWillBeRawPtr<Event> event = reason.isEmpty() ? Event::createBubble(EventTypeNames::autocomplete) : AutocompleteErrorEvent::create(reason); |
+ event->setTarget(m_form); |
+ m_form->dispatchEvent(event.release()); |
+ |
+ if (reason.isEmpty()) |
+ m_resolver->resolve(V8UndefinedType()); |
+ else |
+ m_resolver->reject(AutocompleteError::create(reason)); |
+ } |
+ |
+private: |
+ AutocompleteRequest(HTMLFormElement* form) |
+ : m_form(form) |
+ , m_resolver(ScriptPromiseResolverWithContext::create(NewScriptState::current(toIsolate(form->executionContext())))) |
+ , m_isResultSet(false) |
+ { } |
+ |
+ HTMLFormElement* m_form; |
+ RefPtr<ScriptPromiseResolverWithContext> m_resolver; |
+ HTMLFormElement::AutocompleteResult m_result; |
+ bool m_isResultSet; |
+}; |
+ |
bool HTMLFormElement::rendererIsNeeded(const RenderStyle& style) |
{ |
if (!m_wasDemoted) |
@@ -416,53 +473,55 @@ void HTMLFormElement::reset() |
m_isInResetFunction = false; |
} |
-void HTMLFormElement::requestAutocomplete(const Dictionary& details) |
+ScriptPromise HTMLFormElement::requestAutocomplete(const Dictionary& details) |
{ |
- String errorMessage; |
+ OwnPtr<AutocompleteRequest> request = AutocompleteRequest::create(this); |
+ ScriptPromise promise = request->promise(); |
+ String errorMessage; |
if (!document().frame()) |
errorMessage = "requestAutocomplete: form is not owned by a displayed document."; |
else if (!shouldAutocomplete()) |
errorMessage = "requestAutocomplete: form autocomplete attribute is set to off."; |
else if (!UserGestureIndicator::processingUserGesture()) |
errorMessage = "requestAutocomplete: must be called in response to a user gesture."; |
+ else if (!!m_pendingAutocompleteRequest) |
+ errorMessage = "requestAutocomplete: already in progess."; |
if (!errorMessage.isEmpty()) { |
document().addConsoleMessage(RenderingMessageSource, LogMessageLevel, errorMessage); |
- finishRequestAutocomplete(AutocompleteResultErrorDisabled); |
+ doFinishRequestAutocomplete(AutocompleteResultErrorDisabled, request.release()); |
} else { |
+ m_pendingAutocompleteRequest = request.release(); |
document().frame()->loader().client()->didRequestAutocomplete(this, details); |
} |
+ |
+ return promise; |
} |
void HTMLFormElement::finishRequestAutocomplete(AutocompleteResult result) |
{ |
- RefPtrWillBeRawPtr<Event> event = nullptr; |
- if (result == AutocompleteResultSuccess) |
- event = Event::createBubble(EventTypeNames::autocomplete); |
- else if (result == AutocompleteResultErrorDisabled) |
- event = AutocompleteErrorEvent::create("disabled"); |
- else if (result == AutocompleteResultErrorCancel) |
- event = AutocompleteErrorEvent::create("cancel"); |
- else if (result == AutocompleteResultErrorInvalid) |
- event = AutocompleteErrorEvent::create("invalid"); |
- else |
- ASSERT_NOT_REACHED(); |
+ doFinishRequestAutocomplete(result, m_pendingAutocompleteRequest.release()); |
+} |
- event->setTarget(this); |
- m_pendingAutocompleteEvents.append(event.release()); |
+void HTMLFormElement::doFinishRequestAutocomplete(AutocompleteResult result, PassOwnPtr<AutocompleteRequest> request) |
+{ |
+ request->setResult(result); |
+ m_finishedAutocompleteRequests.append(request); |
- // Dispatch events later as this API is meant to work asynchronously in all situations and implementations. |
+ // Finish the request later as this API is meant to work asynchronously in all situations and implementations. |
if (!m_requestAutocompleteTimer.isActive()) |
m_requestAutocompleteTimer.startOneShot(0, FROM_HERE); |
} |
void HTMLFormElement::requestAutocompleteTimerFired(Timer<HTMLFormElement>*) |
{ |
- WillBeHeapVector<RefPtrWillBeMember<Event> > pendingEvents; |
- m_pendingAutocompleteEvents.swap(pendingEvents); |
- for (size_t i = 0; i < pendingEvents.size(); ++i) |
- dispatchEvent(pendingEvents[i].release()); |
+ Vector<OwnPtr<AutocompleteRequest> > finishedRequests; |
+ m_finishedAutocompleteRequests.swap(finishedRequests); |
+ |
+ RefPtr<HTMLFormElement> protector(this); |
+ for (size_t i = 0; i < finishedRequests.size(); ++i) |
+ finishedRequests[i]->dispatchAndFulfill(); |
} |
void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomicString& value) |