MutationObserver.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/Bindings/MainThreadVM.h>
  7. #include <LibWeb/Bindings/WindowObject.h>
  8. #include <LibWeb/DOM/MutationObserver.h>
  9. #include <LibWeb/DOM/Node.h>
  10. namespace Web::DOM {
  11. // https://dom.spec.whatwg.org/#dom-mutationobserver-mutationobserver
  12. MutationObserver::MutationObserver(Bindings::WindowObject& window_object, Bindings::CallbackType callback)
  13. : m_callback(move(callback))
  14. {
  15. // 1. Set this’s callback to callback.
  16. // 2. Append this to this’s relevant agent’s mutation observers.
  17. auto* agent_custom_data = verify_cast<Bindings::WebEngineCustomData>(window_object.vm().custom_data());
  18. agent_custom_data->mutation_observers.append(*this);
  19. }
  20. // https://dom.spec.whatwg.org/#dom-mutationobserver-observe
  21. ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserverInit options)
  22. {
  23. // 1. If either options["attributeOldValue"] or options["attributeFilter"] exists, and options["attributes"] does not exist, then set options["attributes"] to true.
  24. if ((options.attribute_old_value.has_value() || options.attribute_filter.has_value()) && !options.attributes.has_value())
  25. options.attributes = true;
  26. // 2. If options["characterDataOldValue"] exists and options["characterData"] does not exist, then set options["characterData"] to true.
  27. if (options.character_data_old_value.has_value() && !options.character_data.has_value())
  28. options.character_data = true;
  29. // 3. If none of options["childList"], options["attributes"], and options["characterData"] is true, then throw a TypeError.
  30. if (!options.child_list && (!options.attributes.has_value() || !options.attributes.value()) && (!options.character_data.has_value() || !options.character_data.value()))
  31. return SimpleException { SimpleExceptionType::TypeError, "Options must have one of childList, attributes or characterData set to true." };
  32. // 4. If options["attributeOldValue"] is true and options["attributes"] is false, then throw a TypeError.
  33. // NOTE: If attributeOldValue is present, attributes will be present because of step 1.
  34. if (options.attribute_old_value.has_value() && options.attribute_old_value.value() && !options.attributes.value())
  35. return SimpleException { SimpleExceptionType::TypeError, "attributes must be true if attributeOldValue is true." };
  36. // 5. If options["attributeFilter"] is present and options["attributes"] is false, then throw a TypeError.
  37. // NOTE: If attributeFilter is present, attributes will be present because of step 1.
  38. if (options.attribute_filter.has_value() && !options.attributes.value())
  39. return SimpleException { SimpleExceptionType::TypeError, "attributes must be true if attributeFilter is present." };
  40. // 6. If options["characterDataOldValue"] is true and options["characterData"] is false, then throw a TypeError.
  41. // NOTE: If characterDataOldValue is present, characterData will be present because of step 2.
  42. if (options.character_data_old_value.has_value() && options.character_data_old_value.value() && !options.character_data.value())
  43. return SimpleException { SimpleExceptionType::TypeError, "characterData must be true if characterDataOldValue is true." };
  44. // 7. For each registered of target’s registered observer list, if registered’s observer is this:
  45. bool updated_existing_observer = false;
  46. for (auto& registered_observer : target.registered_observers_list()) {
  47. if (registered_observer.observer.ptr() != this)
  48. continue;
  49. updated_existing_observer = true;
  50. // 1. For each node of this’s node list, remove all transient registered observers whose source is registered from node’s registered observer list.
  51. for (auto& node : m_node_list) {
  52. // FIXME: Is this correct?
  53. if (node.is_null())
  54. continue;
  55. node->registered_observers_list().remove_all_matching([&registered_observer](RegisteredObserver& observer) {
  56. return is<TransientRegisteredObserver>(observer) && verify_cast<TransientRegisteredObserver>(observer).source.ptr() == &registered_observer;
  57. });
  58. }
  59. // 2. Set registered’s options to options.
  60. registered_observer.options = options;
  61. break;
  62. }
  63. // 8. Otherwise:
  64. if (!updated_existing_observer) {
  65. // 1. Append a new registered observer whose observer is this and options is options to target’s registered observer list.
  66. auto new_registered_observer = RegisteredObserver::create(*this, options);
  67. target.add_registered_observer(new_registered_observer);
  68. // 2. Append target to this’s node list.
  69. m_node_list.append(target.make_weak_ptr());
  70. }
  71. return {};
  72. }
  73. // https://dom.spec.whatwg.org/#dom-mutationobserver-disconnect
  74. void MutationObserver::disconnect()
  75. {
  76. // 1. For each node of this’s node list, remove any registered observer from node’s registered observer list for which this is the observer.
  77. for (auto& node : m_node_list) {
  78. // FIXME: Is this correct?
  79. if (node.is_null())
  80. continue;
  81. node->registered_observers_list().remove_all_matching([this](RegisteredObserver& registered_observer) {
  82. return registered_observer.observer.ptr() == this;
  83. });
  84. }
  85. // 2. Empty this’s record queue.
  86. m_record_queue.clear();
  87. }
  88. // https://dom.spec.whatwg.org/#dom-mutationobserver-takerecords
  89. NonnullRefPtrVector<MutationRecord> MutationObserver::take_records()
  90. {
  91. // 1. Let records be a clone of this’s record queue.
  92. auto records = m_record_queue;
  93. // 2. Empty this’s record queue.
  94. m_record_queue.clear();
  95. // 3. Return records.
  96. return records;
  97. }
  98. }