| Index: third_party/WebKit/Source/core/dom/FormElementObserver.cpp
|
| diff --git a/third_party/WebKit/Source/core/dom/FormElementObserver.cpp b/third_party/WebKit/Source/core/dom/FormElementObserver.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dfef5f440a2e0e75a1f1037a22f890c803168b51
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/dom/FormElementObserver.cpp
|
| @@ -0,0 +1,164 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "core/dom/FormElementObserver.h"
|
| +
|
| +#include "core/css/CSSComputedStyleDeclaration.h"
|
| +#include "core/dom/MutationCallback.h"
|
| +#include "core/dom/MutationObserver.h"
|
| +#include "core/dom/MutationObserverInit.h"
|
| +#include "core/dom/MutationRecord.h"
|
| +#include "core/dom/StaticNodeList.h"
|
| +#include "core/html/HTMLElement.h"
|
| +#include "core/html/HTMLFormElement.h"
|
| +#include "core/html/HTMLInputElement.h"
|
| +#include "public/web/WebElement.h"
|
| +#include "public/web/WebFormElementObserverCallback.h"
|
| +
|
| +namespace blink {
|
| +
|
| +class FormElementObserver::ObserverCallback : public MutationCallback {
|
| + public:
|
| + explicit ObserverCallback(FormElementObserver&);
|
| + DECLARE_VIRTUAL_TRACE();
|
| +
|
| + ExecutionContext* GetExecutionContext() const override;
|
| +
|
| + void Register(HTMLElement&);
|
| + void Dispose();
|
| +
|
| + private:
|
| + void Call(const HeapVector<Member<MutationRecord>>& records,
|
| + MutationObserver*) override;
|
| +
|
| + Member<FormElementObserver> element_observer_;
|
| + Member<MutationObserver> mutation_observer_;
|
| +};
|
| +
|
| +FormElementObserver::ObserverCallback::ObserverCallback(
|
| + FormElementObserver& element_observer)
|
| + : element_observer_(element_observer) {
|
| + mutation_observer_ = MutationObserver::Create(this);
|
| +}
|
| +
|
| +ExecutionContext* FormElementObserver::ObserverCallback::GetExecutionContext()
|
| + const {
|
| + return element_observer_->document_;
|
| +}
|
| +
|
| +void FormElementObserver::ObserverCallback::Register(HTMLElement& element) {
|
| + {
|
| + Vector<String> filter;
|
| + filter.ReserveCapacity(3);
|
| + filter.push_back(String("action"));
|
| + filter.push_back(String("class"));
|
| + filter.push_back(String("style"));
|
| + MutationObserverInit init;
|
| + init.setAttributes(true);
|
| + init.setAttributeFilter(filter);
|
| + mutation_observer_->observe(&element, init, ASSERT_NO_EXCEPTION);
|
| + }
|
| + {
|
| + MutationObserverInit init;
|
| + init.setChildList(true);
|
| + mutation_observer_->observe(element.parentElement(), init,
|
| + ASSERT_NO_EXCEPTION);
|
| + }
|
| +}
|
| +
|
| +void FormElementObserver::ObserverCallback::Dispose() {
|
| + mutation_observer_->disconnect();
|
| +}
|
| +
|
| +void FormElementObserver::ObserverCallback::Call(
|
| + const HeapVector<Member<MutationRecord>>& records,
|
| + MutationObserver*) {
|
| + for (const auto& record : records) {
|
| + if (record->type() == "childList") {
|
| + for (unsigned i = 0; i < record->removedNodes()->length(); ++i) {
|
| + if (!record->removedNodes()->item(i)->IsHTMLElement())
|
| + continue;
|
| + element_observer_->NotifyMutation(
|
| + *ToHTMLElement(record->removedNodes()->item(i)));
|
| + }
|
| + } else {
|
| + HTMLElement& element = *ToHTMLElement(record->target());
|
| + if (record->attributeName() == "action") {
|
| + // If the action was modified, we just assume that the form as
|
| + // submitted.
|
| + element_observer_->NotifyMutation(element);
|
| + } else {
|
| + // Otherwise, either "style" or "class" was modified. Check the
|
| + // computed style.
|
| + CSSComputedStyleDeclaration* style =
|
| + CSSComputedStyleDeclaration::Create(&element);
|
| + if (style->GetPropertyValue(CSSPropertyDisplay) == "none")
|
| + element_observer_->NotifyMutation(element);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +DEFINE_TRACE(FormElementObserver::ObserverCallback) {
|
| + visitor->Trace(element_observer_);
|
| + visitor->Trace(mutation_observer_);
|
| + MutationCallback::Trace(visitor);
|
| +}
|
| +
|
| +FormElementObserver::FormElementObserver(Document& document)
|
| + : document_(&document) {}
|
| +
|
| +FormElementObserver::~FormElementObserver() {}
|
| +
|
| +void FormElementObserver::EnsureObserver() {
|
| + if (!callback_)
|
| + callback_ = new ObserverCallback(*this);
|
| +}
|
| +
|
| +void FormElementObserver::ClearObserver() {
|
| + if (callback_) {
|
| + callback_->Dispose();
|
| + callback_ = nullptr;
|
| + }
|
| +}
|
| +
|
| +void FormElementObserver::Observe(
|
| + HTMLFormElement& element,
|
| + std::unique_ptr<WebFormElementObserverCallback> callback) {
|
| + ObserveInternal(element, std::move(callback));
|
| +}
|
| +
|
| +void FormElementObserver::Observe(
|
| + HTMLInputElement& element,
|
| + std::unique_ptr<WebFormElementObserverCallback> callback) {
|
| + ObserveInternal(element, std::move(callback));
|
| +}
|
| +
|
| +void FormElementObserver::ObserveInternal(
|
| + HTMLElement& element,
|
| + std::unique_ptr<WebFormElementObserverCallback> callback) {
|
| + DCHECK(element.parentElement());
|
| + CHECK(callbacks_.Set(&element, std::move(callback)).is_new_entry);
|
| + EnsureObserver();
|
| + callback_->Register(element);
|
| +}
|
| +
|
| +void FormElementObserver::NotifyMutation(HTMLElement& element) {
|
| + if (!callbacks_.Contains(&element))
|
| + return;
|
| + auto it = callbacks_.find(&element);
|
| + it->value->ElementWasHiddenOrRemoved();
|
| + callbacks_.erase(it);
|
| + if (callbacks_.IsEmpty())
|
| + ClearObserver();
|
| +}
|
| +
|
| +DEFINE_TRACE(FormElementObserver) {
|
| + visitor->Trace(document_);
|
| + visitor->Trace(callback_);
|
| + visitor->Trace(mutation_observer_);
|
| + visitor->Trace(callbacks_);
|
| +}
|
| +
|
| +} // namespace blink
|
|
|