NavigationHistoryEntry.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Heap/Heap.h>
  7. #include <LibJS/Runtime/Realm.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/Bindings/NavigationHistoryEntryPrototype.h>
  10. #include <LibWeb/DOM/Document.h>
  11. #include <LibWeb/HTML/DocumentState.h>
  12. #include <LibWeb/HTML/Navigation.h>
  13. #include <LibWeb/HTML/NavigationHistoryEntry.h>
  14. #include <LibWeb/HTML/Window.h>
  15. namespace Web::HTML {
  16. JS::NonnullGCPtr<NavigationHistoryEntry> NavigationHistoryEntry::create(JS::Realm& realm, JS::NonnullGCPtr<SessionHistoryEntry> she)
  17. {
  18. return realm.heap().allocate<NavigationHistoryEntry>(realm, realm, she);
  19. }
  20. NavigationHistoryEntry::NavigationHistoryEntry(JS::Realm& realm, JS::NonnullGCPtr<SessionHistoryEntry> she)
  21. : DOM::EventTarget(realm)
  22. , m_session_history_entry(she)
  23. {
  24. }
  25. NavigationHistoryEntry::~NavigationHistoryEntry() = default;
  26. void NavigationHistoryEntry::initialize(JS::Realm& realm)
  27. {
  28. Base::initialize(realm);
  29. set_prototype(&Bindings::ensure_web_prototype<Bindings::NavigationHistoryEntryPrototype>(realm, "NavigationHistoryEntry"));
  30. }
  31. void NavigationHistoryEntry::visit_edges(JS::Cell::Visitor& visitor)
  32. {
  33. Base::visit_edges(visitor);
  34. visitor.visit(m_session_history_entry);
  35. }
  36. // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationhistoryentry-url
  37. WebIDL::ExceptionOr<Optional<String>> NavigationHistoryEntry::url() const
  38. {
  39. // The url getter steps are:
  40. // 1. Let document be this's relevant global object's associated Document.
  41. auto& document = verify_cast<HTML::Window>(relevant_global_object(*this)).associated_document();
  42. // 2. If document is not fully active, then return the empty string.
  43. if (!document.is_fully_active())
  44. return String {};
  45. // 3. Let she be this's session history entry.
  46. auto const& she = this->m_session_history_entry;
  47. // 4. If she's document does not equal document, and she's document state's request referrer policy
  48. // is "no-referrer" or "origin", then return null.
  49. if ((she->document_state->document() != &document)
  50. && (she->document_state->request_referrer_policy() == ReferrerPolicy::ReferrerPolicy::NoReferrer
  51. || she->document_state->request_referrer_policy() == ReferrerPolicy::ReferrerPolicy::Origin))
  52. return OptionalNone {};
  53. // 5. Return she's URL, serialized.
  54. return TRY_OR_THROW_OOM(vm(), String::from_deprecated_string(she->url.serialize()));
  55. }
  56. // https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationhistoryentry-key
  57. String NavigationHistoryEntry::key() const
  58. {
  59. // The key of a NavigationHistoryEntry nhe is given by the return value of the following algorithm:
  60. // 1. If nhe's relevant global object's associated Document is not fully active, then return the empty string.
  61. auto& associated_document = verify_cast<HTML::Window>(relevant_global_object(*this)).associated_document();
  62. if (!associated_document.is_fully_active())
  63. return {};
  64. // 2. Return nhe's session history entry's navigation API key.
  65. return m_session_history_entry->navigation_api_key;
  66. }
  67. // https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationhistoryentry-id
  68. String NavigationHistoryEntry::id() const
  69. {
  70. // The ID of a NavigationHistoryEntry nhe is given by the return value of the following algorithm:
  71. // 1. If nhe's relevant global object's associated Document is not fully active, then return the empty string.
  72. auto& associated_document = verify_cast<HTML::Window>(relevant_global_object(*this)).associated_document();
  73. if (!associated_document.is_fully_active())
  74. return {};
  75. // 2. Return nhe's session history entry's navigation API ID.
  76. return m_session_history_entry->navigation_api_id;
  77. }
  78. // https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigationhistoryentry-index
  79. i64 NavigationHistoryEntry::index() const
  80. {
  81. // The index of a NavigationHistoryEntry nhe is given by the return value of the following algorithm:
  82. // 1. If nhe's relevant global object's associated Document is not fully active, then return −1.
  83. auto& this_relevant_global_object = verify_cast<HTML::Window>(relevant_global_object(*this));
  84. if (!this_relevant_global_object.associated_document().is_fully_active())
  85. return -1;
  86. // 2. Return the result of getting the navigation API entry index of this's session history entry
  87. // within this's relevant global object's navigation API.
  88. return this_relevant_global_object.navigation()->get_the_navigation_api_entry_index(*m_session_history_entry);
  89. }
  90. // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationhistoryentry-samedocument
  91. bool NavigationHistoryEntry::same_document() const
  92. {
  93. // The sameDocument getter steps are:
  94. // 1. Let document be this's relevant global object's associated Document.
  95. auto& document = verify_cast<HTML::Window>(relevant_global_object(*this)).associated_document();
  96. // 2. If document is not fully active, then return false.
  97. if (!document.is_fully_active())
  98. return false;
  99. // 3. Return true if this's session history entry's document equals document, and false otherwise.
  100. return m_session_history_entry->document_state->document() == &document;
  101. }
  102. // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigationhistoryentry-getstate
  103. WebIDL::ExceptionOr<JS::Value> NavigationHistoryEntry::get_state()
  104. {
  105. // The getState() method steps are:
  106. // 1. If this's relevant global object's associated Document is not fully active, then return undefined.
  107. auto& associated_document = verify_cast<HTML::Window>(relevant_global_object(*this)).associated_document();
  108. if (!associated_document.is_fully_active())
  109. return JS::js_undefined();
  110. // 2. Return StructuredDeserialize(this's session history entry's navigation API state). Rethrow any exceptions.
  111. // NOTE: This can in theory throw an exception, if attempting to deserialize a large ArrayBuffer
  112. // when not enough memory is available.
  113. return structured_deserialize(vm(), m_session_history_entry->navigation_api_state, realm(), {});
  114. }
  115. void NavigationHistoryEntry::set_ondispose(WebIDL::CallbackType* event_handler)
  116. {
  117. set_event_handler_attribute(HTML::EventNames::dispose, event_handler);
  118. }
  119. WebIDL::CallbackType* NavigationHistoryEntry::ondispose()
  120. {
  121. return event_handler_attribute(HTML::EventNames::dispose);
  122. }
  123. }