diff --git a/kiwix-desktop.pro b/kiwix-desktop.pro
index 8d370af0..296db7d4 100644
--- a/kiwix-desktop.pro
+++ b/kiwix-desktop.pro
@@ -5,7 +5,7 @@
#-------------------------------------------------
QT += core gui network
-QT += webenginewidgets
+QT += webenginewidgets webchannel
QT += printsupport
# Avoid stripping incompatible files, due to false identification as executables, on WSL
@@ -85,6 +85,7 @@ SOURCES += \
src/tabbar.cpp \
src/contentmanagerside.cpp \
src/readinglistbar.cpp \
+ src/tableofcontentbar.cpp \
src/klistwidgetitem.cpp \
src/opdsrequestmanager.cpp \
src/localkiwixserver.cpp \
@@ -135,6 +136,7 @@ HEADERS += \
src/tabbar.h \
src/contentmanagerside.h \
src/readinglistbar.h \
+ src/tableofcontentbar.h \
src/klistwidgetitem.h \
src/opdsrequestmanager.h \
src/localkiwixserver.h \
@@ -145,6 +147,7 @@ HEADERS += \
src/portutils.h \
src/css_constants.h \
src/multizimbutton.h \
+ src/kiwixwebchannelobject.h \
FORMS += \
src/choiceitem.ui \
@@ -157,7 +160,8 @@ FORMS += \
src/contentmanagerside.ui \
src/readinglistbar.ui \
ui/localkiwixserver.ui \
- ui/settings.ui
+ ui/settings.ui \
+ src/tableofcontentbar.ui \
include(subprojects/QtSingleApplication/src/qtsingleapplication.pri)
CODECFORSRC = UTF-8
@@ -224,6 +228,7 @@ RESOURCES += \
resources/translations.qrc \
resources/contentmanager.qrc \
resources/settingsmanager.qrc \
- resources/style.qrc
+ resources/style.qrc \
+ resources/js.qrc
RC_ICONS = resources/icons/kiwix/app_icon.ico
diff --git a/resources/css/style.css b/resources/css/style.css
index e3b08c85..c0b10a68 100644
--- a/resources/css/style.css
+++ b/resources/css/style.css
@@ -400,3 +400,71 @@ ContentTypeFilter {
width: 0;
height: 0;
}
+
+#tableofcontentbar {
+ background-color: white;
+}
+
+#tableofcontentbar QTreeWidget,
+#tableofcontentbar QLabel,
+#tableofcontentbar QFrame {
+ background-color: white;
+}
+
+#tableofcontentbar QTreeWidget {
+ outline: none;
+}
+
+#tableofcontentbar QTreeWidget::item {
+ height: 26px;
+ padding: 0px 10px;
+ outline: none;
+ border-top: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+}
+
+#tableofcontentbar QTreeWidget::item:selected,
+#tableofcontentbar QTreeWidget::item:hover {
+ outline: none;
+ border-top: 1px solid #3366CC;
+ border-bottom: 1px solid #3366CC;
+ background-color: #D9E9FF;
+ color: black;
+}
+
+#tableofcontentbar QTreeWidget::branch:selected,
+#tableofcontentbar QTreeWidget::branch:hover {
+ outline: none;
+ border-top: 1px solid #3366CC;
+ border-bottom: 1px solid #3366CC;
+ background-color: #D9E9FF;
+}
+
+#tableofcontentbar QTreeWidget::branch:has-children:closed {
+ padding: 5px; /* Can only change icon size with padding. */
+ image: url(:/icons/caret-up-solid.svg);
+}
+
+#tableofcontentbar QTreeWidget::branch:has-children {
+ padding: 5px; /* Can only change icon size with padding. */
+ image: url(:/icons/caret-down-solid.svg);
+}
+
+#tableofcontentbar #titleLabel {
+ padding: 0px;
+ margin: 10px;
+}
+
+#tableofcontentbar #hideLabel {
+ margin: 13px 10px 10px; /* 3px to match bottom with titleLabel */
+}
+
+#tableofcontentbar QScrollBar {
+ width: 5px;
+ border: none;
+ outline: none;
+}
+
+#tableofcontentbar QScrollBar::handle {
+ background-color: grey;
+}
diff --git a/resources/js.qrc b/resources/js.qrc
new file mode 100644
index 00000000..39a8210a
--- /dev/null
+++ b/resources/js.qrc
@@ -0,0 +1,5 @@
+
+
+ js/tableofcontent.js
+
+
diff --git a/resources/js/tableofcontent.js b/resources/js/tableofcontent.js
new file mode 100644
index 00000000..8ada9c6e
--- /dev/null
+++ b/resources/js/tableofcontent.js
@@ -0,0 +1,75 @@
+/**
+ * Construct recurseData.str as a JSON Array that contains their header text,
+ * link, and children headers.
+ *
+ * References:
+ * https://stackoverflow.com/questions/187619/is-there-a-javascript-solution-to-generating-a-table-of-contents-for-a-page
+ * @param elem DOM element
+ * @param recurseData Object with fields: { level : int, toc : str, count : int, Set : levelSet }
+ */
+function recurseChild(elem, recurseData)
+{
+ if (elem !== "undefined")
+ {
+ if(elem.nodeName.match(/^H\d+$/) && elem.textContent)
+ {
+ var headerText = elem.textContent.trim();
+ var prevLevel = recurseData.level;
+ var level = elem.nodeName.substr(1);
+ var anchor = "kiwix-toc-" + recurseData.count;
+ var anchorLink = window.location.href.replace(location.hash,"") + '#' + anchor;
+ recurseData.count += 1;
+
+ var anchorElem = document.createElement("a");
+ anchorElem.id = anchor;
+
+ /* Wrap header content with something we can reference. */
+ elem.insertAdjacentElement("afterbegin", anchorElem);
+
+ if (level < prevLevel)
+ {
+ /* Complete current element and the parent element.*/
+ recurseData.toc += ']}]}, ';
+ }
+ else if (level == prevLevel)
+ {
+ /* Complete current element*/
+ recurseData.toc += ']}, ';
+ }
+
+ recurseData.level = parseInt(level);
+ recurseData.levelSet.add(parseInt(level));
+ recurseData.toc += '{"text" : "' + headerText.replace(/"/g, '\\"') + '", "anchor": "' + anchorLink + '", ' + '"child" : [';
+ }
+
+ var c = elem.children;
+ for (var i = 0; i < c.length; i++)
+ recurseChild(c[i], recurseData);
+ }
+}
+
+function tocJSON()
+{
+ /* level used to track current header level.
+ toc used to store constructed list.
+ count used to uniquely identify each list item in toc.
+ levelSet used to retrieve the levels disregarding header level value.
+ */
+ var recurseData = { level: 0, toc: '{ "url" : "' + window.location.href.replace(location.hash,"") + '", "table" : [', count: 0, levelSet: new Set};
+ recurseChild(document.body, recurseData);
+
+ var levelArray = Array.from(recurseData.levelSet).sort();
+ levelArray.sort(function(a, b){return a - b});
+ var level = levelArray.indexOf(recurseData.level) + 1;
+
+ /* End un-closed lists */
+ if (level)
+ recurseData.toc += (new Array(level + 1)).join(']}');
+ recurseData.toc += ']}';
+ return recurseData.toc;
+}
+
+new QWebChannel(qt.webChannelTransport, function(channel) {
+ var kiwixObj = channel.objects.kiwixChannelObj;
+ kiwixObj.sendTableOfContent(tocJSON());
+});
diff --git a/src/kiwixapp.cpp b/src/kiwixapp.cpp
index ed29b526..0404d6de 100644
--- a/src/kiwixapp.cpp
+++ b/src/kiwixapp.cpp
@@ -435,8 +435,8 @@ void KiwixApp::createActions()
});
mpa_actions[ToggleFullscreenAction]->setCheckable(true);
- CREATE_ACTION_SHORTCUT(ToggleTOCAction, gt("table-of-content"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_1));
- HIDE_ACTION(ToggleTOCAction);
+ CREATE_ACTION_ICON_SHORTCUT(ToggleTOCAction, "toc", gt("table-of-content"), QKeySequence(Qt::CTRL | Qt::Key_M));
+ mpa_actions[ToggleTOCAction]->setCheckable(true);
CREATE_ACTION_ICON_SHORTCUT(OpenMultiZimAction, "filter", gt("search-options"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_L));
@@ -492,6 +492,7 @@ void KiwixApp::handleItemsState(TabType tabType)
auto libraryOrSettingsTab = (tabType == TabType::LibraryTab || tabType == TabType::SettingsTab);
auto notBookmarkableTab = libraryOrSettingsTab || getTabWidget()->currentArticleUrl().isEmpty();
auto app = KiwixApp::instance();
+ app->getAction(KiwixApp::ToggleTOCAction)->setDisabled(libraryOrSettingsTab);
app->getAction(KiwixApp::ToggleReadingListAction)->setDisabled(libraryOrSettingsTab);
app->getAction(KiwixApp::ToggleAddBookmarkAction)->setDisabled(notBookmarkableTab);
app->getAction(KiwixApp::FindInPageAction)->setDisabled(libraryOrSettingsTab);
diff --git a/src/kiwixwebchannelobject.h b/src/kiwixwebchannelobject.h
new file mode 100644
index 00000000..f14e94d0
--- /dev/null
+++ b/src/kiwixwebchannelobject.h
@@ -0,0 +1,19 @@
+#ifndef KIWIXWEBCHANNELOBJECT_H
+#define KIWIXWEBCHANNELOBJECT_H
+
+#include
+
+class KiwixWebChannelObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit KiwixWebChannelObject(QObject *parent = nullptr) : QObject(parent) {};
+
+ Q_INVOKABLE void sendTableOfContent(const QString& tableJson) { emit tableOfContentChanged(tableJson); };
+
+signals:
+ void tableOfContentChanged(const QString& tableJson);
+};
+
+#endif // KIWIXWEBCHANNELOBJECT_H
diff --git a/src/kprofile.cpp b/src/kprofile.cpp
index 6659ebbd..3aba83c2 100644
--- a/src/kprofile.cpp
+++ b/src/kprofile.cpp
@@ -4,6 +4,26 @@
#include
#include
#include
+#include
+#include
+
+namespace
+{
+
+QWebEngineScript getScript(QString filename,
+ QWebEngineScript::InjectionPoint point = QWebEngineScript::DocumentReady)
+{
+ QWebEngineScript script;
+ script.setInjectionPoint(point);
+ script.setWorldId(QWebEngineScript::UserWorld);
+
+ QFile scriptFile(filename);
+ scriptFile.open(QIODevice::ReadOnly);
+ script.setSourceCode(scriptFile.readAll());
+ return script;
+}
+
+}
QString askForSaveFilePath(const QString& suggestedName)
{
@@ -36,6 +56,10 @@ KProfile::KProfile(QObject *parent) :
#else // Qt 5.13 and later
setUrlRequestInterceptor(new ExternalReqInterceptor(this));
#endif
+
+ scripts()->insert(getScript(":/js/tableofcontent.js"));
+ scripts()->insert(getScript(":/qtwebchannel/qwebchannel.js",
+ QWebEngineScript::DocumentCreation));
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 6b2feb85..a298e9c2 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -45,6 +45,8 @@ MainWindow::MainWindow(QWidget *parent) :
this, &MainWindow::toggleFullScreen);
connect(app->getAction(KiwixApp::ToggleReadingListAction), &QAction::toggled,
this, &MainWindow::readingListToggled);
+ connect(app->getAction(KiwixApp::ToggleTOCAction), &QAction::toggled,
+ this, &MainWindow::tableOfContentToggled);
connect(app->getAction(KiwixApp::AboutAction), &QAction::triggered,
mp_about, &QDialog::show);
connect(app->getAction(KiwixApp::DonateAction), &QAction::triggered,
@@ -170,9 +172,18 @@ void MainWindow::resizeEvent(QResizeEvent *event)
updateTabButtons();
}
+void checkActionNoSignal(KiwixApp::Actions actionFlag, bool checked)
+{
+ const auto action = KiwixApp::instance()->getAction(actionFlag);
+ const bool oldState = action->blockSignals(true);
+ action->setChecked(checked);
+ action->blockSignals(oldState);
+}
+
void MainWindow::readingListToggled(bool state)
{
if (state) {
+ checkActionNoSignal(KiwixApp::ToggleTOCAction, false);
mp_ui->sideBar->setCurrentWidget(mp_ui->readinglistbar);
mp_ui->sideBar->show();
}
@@ -181,16 +192,33 @@ void MainWindow::readingListToggled(bool state)
}
}
+void MainWindow::tableOfContentToggled(bool state)
+{
+ if (state) {
+ checkActionNoSignal(KiwixApp::ToggleReadingListAction, false);
+ mp_ui->sideBar->setCurrentWidget(mp_ui->tableofcontentbar);
+ mp_ui->sideBar->show();
+ }
+ else {
+ mp_ui->sideBar->hide();
+ }
+}
+
void MainWindow::tabChanged(TabType tabType)
{
QAction *readingList = KiwixApp::instance()->getAction(KiwixApp::ToggleReadingListAction);
+ QAction *tableOfContent = KiwixApp::instance()->getAction(KiwixApp::ToggleTOCAction);
if (tabType == TabType::SettingsTab) {
mp_ui->sideBar->hide();
} else if(tabType == TabType::LibraryTab) {
mp_ui->sideBar->setCurrentWidget(mp_ui->contentmanagerside);
mp_ui->sideBar->show();
- } else {
- readingListToggled(readingList->isChecked());
+ } else if (readingList->isChecked()) {
+ readingListToggled(true);
+ } else if (tableOfContent->isChecked()) {
+ tableOfContentToggled(true);
+ } else {
+ mp_ui->sideBar->hide();
}
}
@@ -203,3 +231,8 @@ TopWidget *MainWindow::getTopWidget()
{
return mp_ui->mainToolBar;
}
+
+TableOfContentBar *MainWindow::getTableOfContentBar()
+{
+ return mp_ui->tableofcontentbar;
+}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index a97bef15..4e580d1a 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -14,6 +14,8 @@ namespace Ui {
class MainWindow;
}
+class TableOfContentBar;
+
class MainWindow : public QMainWindow
{
Q_OBJECT
@@ -25,6 +27,7 @@ class MainWindow : public QMainWindow
TabBar* getTabBar();
TopWidget* getTopWidget();
QWidget getMainView();
+ TableOfContentBar *getTableOfContentBar();
protected:
bool eventFilter(QObject* object, QEvent* event) override;
@@ -35,6 +38,7 @@ private slots:
void toggleFullScreen();
void tabChanged(TabBar::TabType);
void readingListToggled(bool state);
+ void tableOfContentToggled(bool state);
void hideTabAndTop();
void showTabAndTop();
void updateTabButtons();
diff --git a/src/tableofcontentbar.cpp b/src/tableofcontentbar.cpp
new file mode 100644
index 00000000..f3252dc8
--- /dev/null
+++ b/src/tableofcontentbar.cpp
@@ -0,0 +1,72 @@
+#include "tableofcontentbar.h"
+#include "ui_tableofcontentbar.h"
+#include "kiwixapp.h"
+#include
+#include
+
+TableOfContentBar::TableOfContentBar(QWidget *parent) :
+ QFrame(parent),
+ ui(new Ui::tableofcontentbar)
+{
+ ui->setupUi(this);
+ ui->titleLabel->setFont(QFont("Selawik", 18, QFont::Weight::Medium));
+ ui->titleLabel->setText(gt("table-of-content"));
+ ui->hideLabel->setFont(QFont("Selawik", 12));
+ ui->hideLabel->setTextFormat(Qt::RichText);
+
+ /* href is needed to make hide clickable, but not used. So Kiwix it is :) */
+ ui->hideLabel->setText("" + gt("hide") + "");
+ connect(ui->hideLabel, &QLabel::linkActivated, this, [=](){
+ KiwixApp::instance()->getAction(KiwixApp::ToggleTOCAction)->setChecked(false);
+ });
+
+ ui->tree->setRootIsDecorated(false);
+ connect(ui->tree, &QTreeWidget::itemActivated, this, [=](QTreeWidgetItem* item) {
+ emit navigationRequested(item->data(0, Qt::UserRole).toString());
+ });
+}
+
+TableOfContentBar::~TableOfContentBar()
+{
+ delete ui;
+}
+
+namespace
+{
+
+void populateItem(const QJsonArray& headerArray, QTreeWidgetItem* parent)
+{
+ for (int i = 0; i < headerArray.size(); i++)
+ {
+ const auto header = headerArray[i].toObject();
+ const auto item = new QTreeWidgetItem(parent);
+ item->setExpanded(true);
+
+ auto numberList = parent->data(0, Qt::UserRole + 1).toStringList();
+ numberList.append(QString::number(i + 1));
+ item->setData(0, Qt::UserRole + 1, numberList);
+
+ const auto itemNum = numberList.join(".");
+ const auto display = itemNum + " " + header["text"].toString();
+ item->setData(0, Qt::DisplayRole, display);
+ item->setData(0, Qt::FontRole, QFont("Selawik", 12));
+ item->setData(0, Qt::UserRole, header["anchor"].toString());
+ item->setToolTip(0, display);
+ populateItem(header["child"].toArray(), item);
+ }
+}
+
+}
+
+void TableOfContentBar::setupTree(const QJsonDocument& table)
+{
+ const auto tableUrl = table["url"].toString();
+ const auto webView = KiwixApp::instance()->getTabWidget()->currentWebView();
+ const auto currentUrl = webView->url().url(QUrl::RemoveFragment);
+ if (tableUrl != currentUrl)
+ return;
+
+ ui->tree->clear();
+ ui->tree->invisibleRootItem()->setData(0, Qt::UserRole + 1, QStringList{});
+ populateItem(table["table"].toArray(), ui->tree->invisibleRootItem());
+}
diff --git a/src/tableofcontentbar.h b/src/tableofcontentbar.h
new file mode 100644
index 00000000..0566ad7f
--- /dev/null
+++ b/src/tableofcontentbar.h
@@ -0,0 +1,28 @@
+#ifndef TABLEOFCONTENTBAR_H
+#define TABLEOFCONTENTBAR_H
+
+#include
+
+namespace Ui {
+class tableofcontentbar;
+}
+
+class TableOfContentBar : public QFrame
+{
+ Q_OBJECT
+
+public:
+ explicit TableOfContentBar(QWidget *parent = nullptr);
+ ~TableOfContentBar();
+
+public slots:
+ void setupTree(const QJsonDocument& table);
+
+signals:
+ void navigationRequested(const QUrl& anchor);
+
+private:
+ Ui::tableofcontentbar *ui;
+};
+
+#endif // TABLEOFCONTENTBAR_H
diff --git a/src/tableofcontentbar.ui b/src/tableofcontentbar.ui
new file mode 100644
index 00000000..8ebf8750
--- /dev/null
+++ b/src/tableofcontentbar.ui
@@ -0,0 +1,130 @@
+
+
+ tableofcontentbar
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
-
+
+
+
+ 16
+
+
+
+
+
+
+ 0
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+
+
+ 0
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ QFrame::NoFrame
+
+
+ 0
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+ Qt::ElideRight
+
+
+ 30
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
diff --git a/src/topwidget.cpp b/src/topwidget.cpp
index c29d5927..9843b0bf 100644
--- a/src/topwidget.cpp
+++ b/src/topwidget.cpp
@@ -30,6 +30,9 @@ TopWidget::TopWidget(QWidget *parent) :
QAction *random = app->getAction(KiwixApp::RandomArticleAction);
addAction(random);
+ QAction *toc = app->getAction(KiwixApp::ToggleTOCAction);
+ addAction(toc);
+
// For CSS
if (QGuiApplication::isLeftToRight()) {
widgetForAction(back)->setObjectName("leftHistoryButton");
diff --git a/src/webview.cpp b/src/webview.cpp
index 2004de7d..70420795 100644
--- a/src/webview.cpp
+++ b/src/webview.cpp
@@ -16,6 +16,10 @@ class QMenu;
#include
#include
#include
+#include
+#include
+#include "kiwixwebchannelobject.h"
+#include "tableofcontentbar.h"
zim::Entry getArchiveEntryFromUrl(const zim::Archive& archive, const QUrl& url);
QString askForSaveFilePath(const QString& suggestedName);
@@ -97,6 +101,19 @@ WebView::WebView(QWidget *parent)
}
});
#endif
+
+ const auto channel = new QWebChannel(this);
+ const auto kiwixChannelObj = new KiwixWebChannelObject;
+ page()->setWebChannel(channel, QWebEngineScript::UserWorld);
+ channel->registerObject("kiwixChannelObj", kiwixChannelObj);
+
+ const auto tabbar = KiwixApp::instance()->getTabWidget();
+ connect(tabbar, &TabBar::currentTitleChanged, this, &WebView::onCurrentTitleChanged);
+ connect(kiwixChannelObj, &KiwixWebChannelObject::tableOfContentChanged, this, &WebView::onTableOfContentRecieved);
+
+ const auto tocbar = KiwixApp::instance()->getMainWindow()->getTableOfContentBar();
+ connect(this, &WebView::tableOfContentChanged, tocbar, &TableOfContentBar::setupTree);
+ connect(tocbar, &TableOfContentBar::navigationRequested, this, &WebView::onNavigationRequested);
}
WebView::~WebView()
@@ -190,7 +207,48 @@ void WebView::saveViewContent()
catch (...) { /* Blank */}
}
-void WebView::addHistoryItemAction(QMenu *menu, const QWebEngineHistoryItem &item, int n) const
+void WebView::onCurrentTitleChanged()
+{
+ const auto tabbar = KiwixApp::instance()->getTabWidget();
+ const auto tableObject = m_tableOfContent.object();
+ const auto tableValid = tableObject["url"].toString() == url().url();
+
+ /* When table invalid, then we are loading and the emit will be
+ handled by KiwixWebChannelObject::tableOfContentChanged.
+ */
+ if (tabbar->currentWebView() == this && tableValid)
+ emit tableOfContentChanged(m_tableOfContent);
+}
+
+void WebView::onTableOfContentRecieved(const QString& tableJson)
+{
+ const auto tabbar = KiwixApp::instance()->getTabWidget();
+ m_tableOfContent = QJsonDocument::fromJson(tableJson.toUtf8());
+
+ if (tabbar->currentWebView() == this)
+ emit tableOfContentChanged(m_tableOfContent);
+}
+
+void WebView::onNavigationRequested(const QUrl &anchor)
+{
+ const auto tabbar = KiwixApp::instance()->getTabWidget();
+ const auto currentUrl = url().url();
+ const auto anchorNoHash = anchor.url(QUrl::RemoveFragment);
+
+ if (tabbar->currentWebView() == this && anchorNoHash == currentUrl)
+ {
+ setUrl(anchor);
+
+ /* We need to reset the url, otherwise repeated navigations
+ and url checks from the TableOfContentBar would fail.
+ */
+ setUrl(currentUrl);
+ }
+}
+
+void WebView::addHistoryItemAction(QMenu *menu,
+ const QWebEngineHistoryItem &item,
+ int n) const
{
QAction *a = menu->addAction(item.title());
a->setData(QVariant::fromValue(n));
diff --git a/src/webview.h b/src/webview.h
index e2419946..8045fc82 100644
--- a/src/webview.h
+++ b/src/webview.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "findinpagebar.h"
@@ -53,6 +54,7 @@ public slots:
signals:
void iconChanged(const QIcon& icon);
void zimIdChanged(const QString& zimId);
+ void tableOfContentChanged(const QJsonDocument& table);
protected:
virtual QWebEngineView* createWindow(QWebEnginePage::WebWindowType type);
@@ -67,12 +69,16 @@ public slots:
private slots:
void gotoTriggeredHistoryItemAction();
+ void onCurrentTitleChanged();
+ void onTableOfContentRecieved(const QString& tableJson);
+ void onNavigationRequested(const QUrl& anchor);
private:
void addHistoryItemAction(QMenu *menu, const QWebEngineHistoryItem &item, int n) const;
void applyCorrectZoomFactor();
QMenu* createStandardContextMenu();
QMenu* createLinkContextMenu();
+ QJsonDocument m_tableOfContent;
};
#endif // WEBVIEW_H
diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui
index dd2749e3..269b91bf 100644
--- a/ui/mainwindow.ui
+++ b/ui/mainwindow.ui
@@ -145,6 +145,7 @@
+
@@ -201,6 +202,12 @@
1
+
+ TableOfContentBar
+ QWidget
+
+ 1
+