mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 20:07:34 +00:00
LibWeb: Add SessionHistoryTraversalQueue
This commit is contained in:
parent
6d866dc5ba
commit
08788072c1
5 changed files with 134 additions and 80 deletions
|
@ -939,61 +939,64 @@ WebIDL::ExceptionOr<void> Navigable::navigate(
|
||||||
// for historyEntry, given navigable, "navigate", sourceSnapshotParams,
|
// for historyEntry, given navigable, "navigate", sourceSnapshotParams,
|
||||||
// targetSnapshotParams, navigationId, navigationParams, cspNavigationType, with allowPOST
|
// targetSnapshotParams, navigationId, navigationParams, cspNavigationType, with allowPOST
|
||||||
// set to true and completionSteps set to the following step:
|
// set to true and completionSteps set to the following step:
|
||||||
populate_session_history_entry_document(history_entry, navigation_params, navigation_id, source_snapshot_params, [this, history_entry, history_handling] {
|
populate_session_history_entry_document(history_entry, navigation_params, navigation_id, source_snapshot_params, [this, history_entry, history_handling, navigation_id] {
|
||||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#finalize-a-cross-document-navigation
|
traversable_navigable()->append_session_history_traversal_steps([this, history_entry, history_handling, navigation_id] {
|
||||||
|
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#finalize-a-cross-document-navigation
|
||||||
|
|
||||||
// 1. FIXME: Assert: this is running on navigable's traversable navigable's session history traversal queue.
|
// 1. FIXME: Assert: this is running on navigable's traversable navigable's session history traversal queue.
|
||||||
|
|
||||||
// 2. Set navigable's is delaying load events to false.
|
// 2. Set navigable's is delaying load events to false.
|
||||||
set_delaying_load_events(false);
|
set_delaying_load_events(false);
|
||||||
|
|
||||||
// 3. If historyEntry's document is null, then return.
|
// 3. If historyEntry's document is null, then return.
|
||||||
if (!history_entry->document_state->document())
|
if (!history_entry->document_state->document())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 4. FIXME: If all of the following are true:
|
// 4. FIXME: If all of the following are true:
|
||||||
// - navigable's parent is null;
|
// - navigable's parent is null;
|
||||||
// - historyEntry's document's browsing context is not an auxiliary browsing context whose opener browsing context is non-null; and
|
// - historyEntry's document's browsing context is not an auxiliary browsing context whose opener browsing context is non-null; and
|
||||||
// - historyEntry's document's origin is not navigable's active document's origin
|
// - historyEntry's document's origin is not navigable's active document's origin
|
||||||
// then set historyEntry's document state's navigable target name to the empty string.
|
// then set historyEntry's document state's navigable target name to the empty string.
|
||||||
|
|
||||||
// 5. Let entryToReplace be navigable's active session history entry if historyHandling is "replace", otherwise null.
|
// 5. Let entryToReplace be navigable's active session history entry if historyHandling is "replace", otherwise null.
|
||||||
auto entry_to_replace = history_handling == HistoryHandlingBehavior::Replace ? active_session_history_entry() : nullptr;
|
auto entry_to_replace = history_handling == HistoryHandlingBehavior::Replace ? active_session_history_entry() : nullptr;
|
||||||
|
|
||||||
// 6. Let traversable be navigable's traversable navigable.
|
// 6. Let traversable be navigable's traversable navigable.
|
||||||
auto traversable = traversable_navigable();
|
auto traversable = traversable_navigable();
|
||||||
|
|
||||||
// 7. Let targetStep be null.
|
// 7. Let targetStep be null.
|
||||||
int target_step;
|
int target_step;
|
||||||
|
|
||||||
// 8. Let targetEntries be the result of getting session history entries for navigable.
|
// 8. Let targetEntries be the result of getting session history entries for navigable.
|
||||||
auto& target_entries = get_session_history_entries();
|
auto& target_entries = get_session_history_entries();
|
||||||
|
|
||||||
// 9. If entryToReplace is null, then:
|
// 9. If entryToReplace is null, then:
|
||||||
if (entry_to_replace == nullptr) {
|
if (entry_to_replace == nullptr) {
|
||||||
// FIXME: 1. Clear the forward session history of traversable.
|
// FIXME: 1. Clear the forward session history of traversable.
|
||||||
|
traversable->clear_the_forward_session_history();
|
||||||
|
|
||||||
// 2. Set targetStep to traversable's current session history step + 1.
|
// 2. Set targetStep to traversable's current session history step + 1.
|
||||||
target_step = traversable->current_session_history_step() + 1;
|
target_step = traversable->current_session_history_step() + 1;
|
||||||
|
|
||||||
// 3. Set historyEntry's step to targetStep.
|
// 3. Set historyEntry's step to targetStep.
|
||||||
history_entry->step = target_step;
|
history_entry->step = target_step;
|
||||||
|
|
||||||
// 4. Append historyEntry to targetEntries.
|
// 4. Append historyEntry to targetEntries.
|
||||||
target_entries.append(move(history_entry));
|
target_entries.append(move(history_entry));
|
||||||
} else {
|
} else {
|
||||||
// 1. Replace entryToReplace with historyEntry in targetEntries.
|
// 1. Replace entryToReplace with historyEntry in targetEntries.
|
||||||
*(target_entries.find(*entry_to_replace)) = history_entry;
|
*(target_entries.find(*entry_to_replace)) = history_entry;
|
||||||
|
|
||||||
// 2. Set historyEntry's step to entryToReplace's step.
|
// 2. Set historyEntry's step to entryToReplace's step.
|
||||||
history_entry->step = entry_to_replace->step;
|
history_entry->step = entry_to_replace->step;
|
||||||
|
|
||||||
// 3. Set targetStep to traversable's current session history step.
|
// 3. Set targetStep to traversable's current session history step.
|
||||||
target_step = traversable->current_session_history_step();
|
target_step = traversable->current_session_history_step();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10. Apply the history step targetStep to traversable.
|
// 10. Apply the history step targetStep to traversable.
|
||||||
traversable->apply_the_history_step(target_step);
|
traversable->apply_the_history_step(target_step);
|
||||||
|
});
|
||||||
}).release_value_but_fixme_should_propagate_errors();
|
}).release_value_but_fixme_should_propagate_errors();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1022,10 +1025,11 @@ void Navigable::reload()
|
||||||
// 2. Let traversable be navigable's traversable navigable.
|
// 2. Let traversable be navigable's traversable navigable.
|
||||||
auto traversable = traversable_navigable();
|
auto traversable = traversable_navigable();
|
||||||
|
|
||||||
// FIXME: 3. Append the following session history traversal steps to traversable:
|
// 3. Append the following session history traversal steps to traversable:
|
||||||
|
traversable->append_session_history_traversal_steps([traversable] {
|
||||||
// 1. Apply pending history changes to traversable with true.
|
// 1. Apply pending history changes to traversable with true.
|
||||||
traversable->apply_pending_history_changes();
|
traversable->apply_pending_history_changes();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,30 +102,31 @@ WebIDL::ExceptionOr<void> NavigableContainer::create_new_child_navigable()
|
||||||
// 11. Let traversable be parentNavigable's traversable navigable.
|
// 11. Let traversable be parentNavigable's traversable navigable.
|
||||||
auto traversable = parent_navigable->traversable_navigable();
|
auto traversable = parent_navigable->traversable_navigable();
|
||||||
|
|
||||||
// FIXME: 12. Append the following session history traversal steps to traversable:
|
// 12. Append the following session history traversal steps to traversable:
|
||||||
|
traversable->append_session_history_traversal_steps([traversable, navigable, parent_navigable, history_entry] {
|
||||||
|
// 1. Let parentDocState be parentNavigable's active session history entry's document state.
|
||||||
|
|
||||||
// 1. Let parentDocState be parentNavigable's active session history entry's document state.
|
auto parent_doc_state = parent_navigable->active_session_history_entry()->document_state;
|
||||||
|
|
||||||
auto parent_doc_state = parent_navigable->active_session_history_entry()->document_state;
|
// 2. Let targetStepSHE be the first session history entry in traversable's session history entries whose document state equals parentDocState.
|
||||||
|
auto target_step_she = *(traversable->session_history_entries().find_if([parent_doc_state](auto& entry) {
|
||||||
|
return entry->document_state == parent_doc_state;
|
||||||
|
}));
|
||||||
|
|
||||||
// 2. Let targetStepSHE be the first session history entry in traversable's session history entries whose document state equals parentDocState.
|
// 3. Set historyEntry's step to targetStepSHE's step.
|
||||||
auto target_step_she = *(traversable->session_history_entries().find_if([parent_doc_state](auto& entry) {
|
history_entry->step = target_step_she->step;
|
||||||
return entry->document_state == parent_doc_state;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 3. Set historyEntry's step to targetStepSHE's step.
|
// 4. Let nestedHistory be a new nested history whose id is navigable's id and entries list is « historyEntry ».
|
||||||
history_entry->step = target_step_she->step;
|
DocumentState::NestedHistory nested_history {
|
||||||
|
.id = navigable->id(),
|
||||||
|
.entries { *history_entry },
|
||||||
|
};
|
||||||
|
|
||||||
// 4. Let nestedHistory be a new nested history whose id is navigable's id and entries list is « historyEntry ».
|
// 5. Append nestedHistory to parentDocState's nested histories.
|
||||||
DocumentState::NestedHistory nested_history {
|
parent_doc_state->nested_histories().append(move(nested_history));
|
||||||
.id = navigable->id(),
|
|
||||||
.entries { *history_entry },
|
|
||||||
};
|
|
||||||
|
|
||||||
// 5. Append nestedHistory to parentDocState's nested histories.
|
// FIXME: 6. Update for navigable creation/destruction given traversable
|
||||||
parent_doc_state->nested_histories().append(move(nested_history));
|
});
|
||||||
|
|
||||||
// FIXME: 6. Update for navigable creation/destruction given traversable
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -342,10 +343,11 @@ void NavigableContainer::destroy_the_child_navigable()
|
||||||
// 7. Let traversable be container's node navigable's traversable navigable.
|
// 7. Let traversable be container's node navigable's traversable navigable.
|
||||||
auto traversable = this->navigable()->traversable_navigable();
|
auto traversable = this->navigable()->traversable_navigable();
|
||||||
|
|
||||||
// FIXME: 8. Append the following session history traversal steps to traversable:
|
// 8. Append the following session history traversal steps to traversable:
|
||||||
|
traversable->append_session_history_traversal_steps([traversable] {
|
||||||
// 1. Apply pending history changes to traversable.
|
// 1. Apply pending history changes to traversable.
|
||||||
traversable->apply_pending_history_changes();
|
traversable->apply_pending_history_changes();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibCore/Timer.h>
|
||||||
|
|
||||||
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-traversal-queue
|
||||||
|
class SessionHistoryTraversalQueue {
|
||||||
|
public:
|
||||||
|
SessionHistoryTraversalQueue()
|
||||||
|
{
|
||||||
|
m_timer = Core::Timer::create_single_shot(0, [this] {
|
||||||
|
while (m_queue.size() > 0) {
|
||||||
|
auto steps = m_queue.take_first();
|
||||||
|
steps();
|
||||||
|
}
|
||||||
|
}).release_value_but_fixme_should_propagate_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(JS::SafeFunction<void()> steps)
|
||||||
|
{
|
||||||
|
m_queue.append(move(steps));
|
||||||
|
if (!m_timer->is_active()) {
|
||||||
|
m_timer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector<JS::SafeFunction<void()>> m_queue;
|
||||||
|
RefPtr<Core::Timer> m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -479,24 +479,25 @@ void TraversableNavigable::traverse_the_history_by_delta(int delta)
|
||||||
// FIXME: 2. If sourceDocument is given, then:
|
// FIXME: 2. If sourceDocument is given, then:
|
||||||
|
|
||||||
// 3. Append the following session history traversal steps to traversable:
|
// 3. Append the following session history traversal steps to traversable:
|
||||||
|
append_session_history_traversal_steps([this, delta] {
|
||||||
|
// 1. Let allSteps be the result of getting all used history steps for traversable.
|
||||||
|
auto all_steps = get_all_used_history_steps();
|
||||||
|
|
||||||
// 1. Let allSteps be the result of getting all used history steps for traversable.
|
// 2. Let currentStepIndex be the index of traversable's current session history step within allSteps.
|
||||||
auto all_steps = get_all_used_history_steps();
|
auto current_step_index = *all_steps.find_first_index(current_session_history_step());
|
||||||
|
|
||||||
// 2. Let currentStepIndex be the index of traversable's current session history step within allSteps.
|
// 3. Let targetStepIndex be currentStepIndex plus delta
|
||||||
auto current_step_index = *all_steps.find_first_index(current_session_history_step());
|
auto target_step_index = current_step_index + delta;
|
||||||
|
|
||||||
// 3. Let targetStepIndex be currentStepIndex plus delta
|
// 4. If allSteps[targetStepIndex] does not exist, then abort these steps.
|
||||||
auto target_step_index = current_step_index + delta;
|
if (target_step_index >= all_steps.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 4. If allSteps[targetStepIndex] does not exist, then abort these steps.
|
// 5. Apply the history step allSteps[targetStepIndex] to traversable, with checkForUserCancelation set to true,
|
||||||
if (target_step_index >= all_steps.size()) {
|
// sourceSnapshotParams set to sourceSnapshotParams, and initiatorToCheck set to initiatorToCheck.
|
||||||
return;
|
apply_the_history_step(all_steps[target_step_index]);
|
||||||
}
|
});
|
||||||
|
|
||||||
// 5. Apply the history step allSteps[targetStepIndex] to traversable, with checkForUserCancelation set to true,
|
|
||||||
// sourceSnapshotParams set to sourceSnapshotParams, and initiatorToCheck set to initiatorToCheck.
|
|
||||||
apply_the_history_step(all_steps[target_step_index]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-pending-history-changes
|
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#apply-pending-history-changes
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibWeb/HTML/Navigable.h>
|
#include <LibWeb/HTML/Navigable.h>
|
||||||
|
#include <LibWeb/HTML/SessionHistoryTraversalQueue.h>
|
||||||
#include <LibWeb/HTML/VisibilityState.h>
|
#include <LibWeb/HTML/VisibilityState.h>
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
@ -47,6 +48,11 @@ public:
|
||||||
|
|
||||||
void destroy_top_level_traversable();
|
void destroy_top_level_traversable();
|
||||||
|
|
||||||
|
void append_session_history_traversal_steps(JS::SafeFunction<void()> steps)
|
||||||
|
{
|
||||||
|
m_session_history_traversal_queue.append(move(steps));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TraversableNavigable();
|
TraversableNavigable();
|
||||||
|
|
||||||
|
@ -65,6 +71,8 @@ private:
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/document-sequences.html#system-visibility-state
|
// https://html.spec.whatwg.org/multipage/document-sequences.html#system-visibility-state
|
||||||
VisibilityState m_system_visibility_state { VisibilityState::Visible };
|
VisibilityState m_system_visibility_state { VisibilityState::Visible };
|
||||||
|
|
||||||
|
SessionHistoryTraversalQueue m_session_history_traversal_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue