-
-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce Table of Content Without Intense JS Invasion #1237
Conversation
Bug report - when the TOC is not empty the attempt to open the TOC sidebar results in the latter growing wider and wider indefinitely. |
@veloman-yunkan I can't seem to replicate this. Is this happening on any zim? |
fe978e1
to
331855e
Compare
It happens on ray_charles.zim for sure |
Screencast.from.11-07-2024.08.22.37.PM.webm |
@veloman-yunkan Would like to confirm if you are on Qt6? I have tested Qt5 and Qt6, where Qt6 seems to be the version that this bug happens |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the initial feedback from a quick and very superficial review
No, I am a qtsaur. I don't use the most recent version. |
Is this assessment based on your understanding of the implementation or a result of some measurement? |
@veloman-yunkan It is more like my own understanding and observation from other Stackoverflowers:
|
331855e
to
388441f
Compare
@veloman-yunkan Should be fixed now. Somehow under the same settings, QListWidget in ReadingListBar doesn't have this problem. This might be due to either styling or underlying widget differences. |
6d4aca1
to
ada6708
Compare
ada6708
to
dee816b
Compare
Do we ever expect "large data amounts" for TOC?
Back to the previous comment, if the TOC is not going to be overwhelmingly large this shouldn't matter a lot.
How come the TOC is already in the DOM when we go to a new page? Did you mean switching tabs? |
The entries in the TOC need to be double clicked for the navigation to happen. Was it intended to be like that? |
I do believe this PR is better than #1201. The loses I mentioned are more for acknowledging some minor inconveniences we face. In the grand scheme of things, it is not closr enough to offset the benefits by TOC to Qt side. |
Do I get it right that in this implementation TOC subsections are collapsible while in the JS-based implementation they aren't? |
@veloman-yunkan Its supposed to be single click. I will change this. |
@veloman-yunkan In JS they weren't collapsible. |
@ShaopengLin @veloman-yunkan Don't try to handle collabsable sections in the content. Focus only on the behaviour of the TOC sidebar. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this iteration my focus was on the injected JS script.
I am now also inclined to consider this solution as a superior one. Hoping that we won't discover a major deficiency in this approach that will make us shift back to the JS-based version. |
dee816b
to
19d767f
Compare
5093e72
to
80e412b
Compare
src/tableofcontentbar.cpp
Outdated
void populateItem(QJsonArray& headerArr, QTreeWidgetItem* parent, int level) | ||
{ | ||
while (!headerArr.isEmpty()) | ||
{ | ||
const auto header = headerArr.first().toObject(); | ||
const int headerLevel = header["level"].toInt(); | ||
if (headerLevel <= level) | ||
return; | ||
else | ||
headerArr.pop_front(); | ||
|
||
const auto item = new QTreeWidgetItem(parent); | ||
item->setExpanded(true); | ||
|
||
auto numberList = parent->data(0, Qt::UserRole + 1).toStringList(); | ||
numberList.append(QString::number(parent->childCount())); | ||
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(headerArr, item, headerLevel); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intuition tells me that this combination of iteration and recursion is redundant (and to my taste a little confusing). I feel that this algorithm can be rewritten in a clearer way with iteration alone (you will need an additional nested loop for ascending up the hierarchy to the QTreeWidgetItem
corresponding to the new level). To add more clarity please extract the code responsible for the creation and initialization of a new QTreeWidgetItem
into a helper function of its own.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
80e412b
to
c6aac3f
Compare
src/tableofcontentbar.cpp
Outdated
/* find correct parent level to insert */ | ||
while (headerLevel <= curParentItem->data(0, LevelRole).toInt()) | ||
{ | ||
curParentItem = curParentItem->parent(); | ||
|
||
/* Unfortunate that top-level items not parented by invisibleRoot */ | ||
if (!curParentItem) | ||
curParentItem = ui->tree->invisibleRootItem(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the assumptions about level values in the header data? Can there be gaps like in the following sequence: {h1, h3, h4, h4, h2, h4}
? Does your algorithm handle such cases? Otherwise, assuming absence of gaps i.e. all levels on a branch from the root to the leaf are filled, why do you need LevelRole
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there can be gaps. During parsing, we use their level to determine the correct parent, but the tree is constructed as if there are no gaps ( i.e. { h2, h4 }
will be repesented in the tree as if it is { h1, h2 }
). Having perfect headers is an unlikely assumption...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I see now that probably under such conditions combining recursion with iteration makes more sense. Without recursion you have to store in the tree items intermediate data like level and the number-list (this one was present in your previous implementation too). Here is a cleaner and more comprehensible scheme:
QJsonArray takeDeeperEntries(QJsonArray& headerArr, int level)
{
QJsonArray result;
while (!headerArr.isEmpty() ) {
const auto& nextHeader = headerArr.first().toObject();
if ( nextHeader["level"].toInt() <= level )
break;
result.push_back(nextHeader);
headerArr.pop_front();
}
return result;
}
void createSubTree(QTreeWidgetItem* parent, QString parentNo, QJsonArray headerArr)
{
while (!headerArr.isEmpty()) {
const auto& childHeader = headerArr.takeAt(0).toObject();
const int childLevel = childHeader["level"].toInt();
const QString childNo = parentNo + "." + QString::number(parent->childCount() + 1);
QTreeWidgetItem* childItem = createChildItem(parent, childNo, childHeader);
const QJsonArray deeperStuff = takeDeeperEntries(headerArr, childLevel);
setupSubTree(childItem, childNo, deeperStuff);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
c6aac3f
to
dce40be
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Since C++ is not a typo-safe language the compiler didn't detect the contamination of this PR by a subtle spelling error, however I believe that no user will be affected if we merge the PR as is.
A couple of comments regarding functionality:
- navigation via TOC isn't recorded in the history.
- when a section in the content is collapsed clicking a TOC entry belonging to that section has no effect
src/webview.h
Outdated
@@ -67,12 +69,15 @@ public slots: | |||
|
|||
private slots: | |||
void gotoTriggeredHistoryItemAction(); | |||
void onCurrentTitleChanged(); | |||
void onHeadersRecieved(const QJsonObject& headers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
recieve -> receive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
I believe those can be addressed in a follow-up PR (if they need to be fixed at all). |
dce40be
to
208097b
Compare
Don't forget to open tickets! |
Setup for header anchor injection
Add channel to communicate between web page and Qt
Re-enabled ToggleTOCAction to display the bar.
Only one should be in checked state.
Signal emits the headers in pre-order in JSON format
Recursively load the header JSON.
Setting URL with anchor hash will act as navigation.
Elided item text is expanded here.
208097b
to
36a2782
Compare
Alternative to #1201. FIx #42
Changes:
Benefits:
Loses: