mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
Ladybird: Allow right clicking and inspecting elements
This adds "Inspect Element" (currently the only entry) to the context menu for the page, which will do what you expect (most of the time), and bring up the Inspector with hovered element selected.
This commit is contained in:
parent
15211cd753
commit
09773048b6
Notes:
sideshowbarker
2024-07-16 20:26:59 +09:00
Author: https://github.com/MacDue Commit: https://github.com/SerenityOS/serenity/commit/09773048b6 Pull-request: https://github.com/SerenityOS/serenity/pull/18733
@ -330,11 +330,28 @@ BrowserWindow::BrowserWindow(Browser::CookieJar& cookie_jar, StringView webdrive
|
||||
QObject::connect(m_tabs_container, &QTabWidget::tabCloseRequested, this, &BrowserWindow::close_tab);
|
||||
QObject::connect(close_current_tab_action, &QAction::triggered, this, &BrowserWindow::close_current_tab);
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QObject::connect(this, &QWidget::customContextMenuRequested, this, &BrowserWindow::show_context_menu);
|
||||
|
||||
new_tab(s_settings->new_tab_page(), Web::HTML::ActivateTab::Yes);
|
||||
|
||||
setCentralWidget(m_tabs_container);
|
||||
}
|
||||
|
||||
void BrowserWindow::show_context_menu(QPoint const& point)
|
||||
{
|
||||
QMenu contextMenu("Context menu", this);
|
||||
|
||||
QAction inspect_action("&Inspect Element", this);
|
||||
connect(&inspect_action, &QAction::triggered, this, [this] {
|
||||
if (!m_current_tab)
|
||||
return;
|
||||
m_current_tab->view().show_inspector(WebContentView::InspectorTarget::HoveredElement);
|
||||
});
|
||||
contextMenu.addAction(&inspect_action);
|
||||
contextMenu.exec(mapToGlobal(point));
|
||||
}
|
||||
|
||||
void BrowserWindow::set_current_tab(Tab* tab)
|
||||
{
|
||||
m_current_tab = tab;
|
||||
|
@ -49,6 +49,7 @@ public slots:
|
||||
void reset_zoom();
|
||||
void select_all();
|
||||
void copy_selected_text();
|
||||
void show_context_menu(QPoint const&);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
@ -37,10 +37,10 @@ InspectorWidget::InspectorWidget()
|
||||
auto top_tap_widget = new QTabWidget;
|
||||
splitter->addWidget(top_tap_widget);
|
||||
|
||||
auto dom_tree_view = new QTreeView;
|
||||
dom_tree_view->setHeaderHidden(true);
|
||||
dom_tree_view->setModel(&m_dom_model);
|
||||
QObject::connect(dom_tree_view->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
m_dom_tree_view = new QTreeView;
|
||||
m_dom_tree_view->setHeaderHidden(true);
|
||||
m_dom_tree_view->setModel(&m_dom_model);
|
||||
QObject::connect(m_dom_tree_view->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
[this](QItemSelection const& selected, QItemSelection const&) {
|
||||
auto indexes = selected.indexes();
|
||||
if (indexes.size()) {
|
||||
@ -48,7 +48,7 @@ InspectorWidget::InspectorWidget()
|
||||
set_selection(index);
|
||||
}
|
||||
});
|
||||
add_tab(top_tap_widget, dom_tree_view, "DOM");
|
||||
add_tab(top_tap_widget, m_dom_tree_view, "DOM");
|
||||
|
||||
auto accessibility_tree_view = new QTreeView;
|
||||
accessibility_tree_view->setHeaderHidden(true);
|
||||
@ -74,6 +74,11 @@ InspectorWidget::InspectorWidget()
|
||||
void InspectorWidget::set_dom_json(StringView dom_json)
|
||||
{
|
||||
m_dom_model.set_underlying_model(WebView::DOMTreeModel::create(dom_json));
|
||||
m_dom_loaded = true;
|
||||
if (m_pending_selection.has_value())
|
||||
set_selection(m_pending_selection.release_value());
|
||||
else
|
||||
select_default_node();
|
||||
}
|
||||
|
||||
void InspectorWidget::set_accessibility_json(StringView accessibility_json)
|
||||
@ -87,6 +92,8 @@ void InspectorWidget::clear_dom_json()
|
||||
// The accessibility tree is pretty much another form of the DOM tree, so should be cleared at the time time.
|
||||
m_accessibility_model.set_underlying_model(nullptr);
|
||||
clear_style_json();
|
||||
clear_selection();
|
||||
m_dom_loaded = false;
|
||||
}
|
||||
|
||||
void InspectorWidget::load_style_json(StringView computed_style_json, StringView resolved_style_json, StringView custom_properties_json)
|
||||
@ -101,6 +108,7 @@ void InspectorWidget::clear_style_json()
|
||||
m_computed_style_model.set_underlying_model(nullptr);
|
||||
m_resolved_style_model.set_underlying_model(nullptr);
|
||||
m_custom_properties_model.set_underlying_model(nullptr);
|
||||
clear_selection();
|
||||
}
|
||||
|
||||
void InspectorWidget::closeEvent(QCloseEvent* event)
|
||||
@ -108,6 +116,40 @@ void InspectorWidget::closeEvent(QCloseEvent* event)
|
||||
event->accept();
|
||||
if (on_close)
|
||||
on_close();
|
||||
clear_selection();
|
||||
}
|
||||
|
||||
void InspectorWidget::clear_selection()
|
||||
{
|
||||
m_selection = {};
|
||||
m_dom_tree_view->clearSelection();
|
||||
}
|
||||
|
||||
void InspectorWidget::set_selection(Selection selection)
|
||||
{
|
||||
if (!m_dom_loaded) {
|
||||
m_pending_selection = selection;
|
||||
return;
|
||||
}
|
||||
|
||||
auto* model = verify_cast<WebView::DOMTreeModel>(m_dom_model.underlying_model().ptr());
|
||||
auto index = model->index_for_node(selection.dom_node_id, selection.pseudo_element);
|
||||
auto qt_index = m_dom_model.to_qt(index);
|
||||
|
||||
if (!qt_index.isValid()) {
|
||||
dbgln("Failed to set DOM inspector selection! Could not find valid model index for node: {}", selection.dom_node_id);
|
||||
return;
|
||||
}
|
||||
|
||||
m_dom_tree_view->scrollTo(qt_index);
|
||||
m_dom_tree_view->setCurrentIndex(qt_index);
|
||||
}
|
||||
|
||||
void InspectorWidget::select_default_node()
|
||||
{
|
||||
clear_style_json();
|
||||
m_dom_tree_view->collapseAll();
|
||||
m_dom_tree_view->setCurrentIndex({});
|
||||
}
|
||||
|
||||
void InspectorWidget::set_selection(GUI::ModelIndex index)
|
||||
|
@ -30,6 +30,13 @@ public:
|
||||
bool operator==(Selection const& other) const = default;
|
||||
};
|
||||
|
||||
bool dom_loaded() const { return m_dom_loaded; }
|
||||
|
||||
void set_selection(Selection);
|
||||
void clear_selection();
|
||||
|
||||
void select_default_node();
|
||||
|
||||
void clear_dom_json();
|
||||
void set_dom_json(StringView dom_json);
|
||||
|
||||
@ -52,6 +59,11 @@ private:
|
||||
ModelTranslator m_computed_style_model {};
|
||||
ModelTranslator m_resolved_style_model {};
|
||||
ModelTranslator m_custom_properties_model {};
|
||||
|
||||
QTreeView* m_dom_tree_view { nullptr };
|
||||
|
||||
bool m_dom_loaded { false };
|
||||
Optional<Selection> m_pending_selection {};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,11 @@ public:
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
RefPtr<GUI::Model> underlying_model()
|
||||
{
|
||||
return m_model;
|
||||
}
|
||||
|
||||
virtual int columnCount(QModelIndex const& parent) const override;
|
||||
virtual int rowCount(QModelIndex const& parent) const override;
|
||||
virtual QVariant data(QModelIndex const&, int role) const override;
|
||||
|
@ -540,12 +540,22 @@ bool WebContentView::is_inspector_open() const
|
||||
return m_inspector_widget && m_inspector_widget->isVisible();
|
||||
}
|
||||
|
||||
void WebContentView::show_inspector()
|
||||
void WebContentView::show_inspector(InspectorTarget inspector_target)
|
||||
{
|
||||
bool inspector_previously_loaded = m_inspector_widget;
|
||||
ensure_inspector_widget();
|
||||
if (!inspector_previously_loaded || !m_inspector_widget->dom_loaded()) {
|
||||
inspect_dom_tree();
|
||||
inspect_accessibility_tree();
|
||||
}
|
||||
m_inspector_widget->show();
|
||||
inspect_dom_tree();
|
||||
inspect_accessibility_tree();
|
||||
|
||||
if (inspector_target == InspectorTarget::HoveredElement) {
|
||||
auto hovered_node = get_hovered_node_id();
|
||||
m_inspector_widget->set_selection({ hovered_node });
|
||||
} else {
|
||||
m_inspector_widget->select_default_node();
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentView::update_zoom()
|
||||
|
@ -93,7 +93,12 @@ public:
|
||||
void did_get_js_console_messages(i32 start_index, Vector<DeprecatedString> message_types, Vector<DeprecatedString> messages);
|
||||
|
||||
void show_js_console();
|
||||
void show_inspector();
|
||||
|
||||
enum class InspectorTarget {
|
||||
Document,
|
||||
HoveredElement
|
||||
};
|
||||
void show_inspector(InspectorTarget = InspectorTarget::Document);
|
||||
|
||||
Ladybird::ConsoleWidget* console() { return m_console_widget; };
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user