Use CSS classes on html list items for checkbox support
If we replace the bullet character with a UC checkbox character, it looks ok in a browser, and the HTML parser can recover the BlockMarker attribute from the css class. [ChangeLog][QtGui][Text] Checkbox list items can now be read and written in both HTML and Markdown, including conversions. Task-number: QTBUG-103714 Change-Id: Ic6b74512075cd4ac16d6f80fdf55b221447491a9 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> (cherry picked from commit eee9d252028c4b3b743c77a406cd6939eda3962f) Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
91cb059e3d
commit
e58a29bdae
@ -2372,6 +2372,8 @@ QString QTextHtmlExporter::toHtml(ExportMode mode)
|
|||||||
html += "<style type=\"text/css\">\n"_L1;
|
html += "<style type=\"text/css\">\n"_L1;
|
||||||
html += "p, li { white-space: pre-wrap; }\n"_L1;
|
html += "p, li { white-space: pre-wrap; }\n"_L1;
|
||||||
html += "hr { height: 1px; border-width: 0; }\n"_L1;
|
html += "hr { height: 1px; border-width: 0; }\n"_L1;
|
||||||
|
html += "li.unchecked::marker { content: \"\\2610\"; }\n"_L1;
|
||||||
|
html += "li.checked::marker { content: \"\\2612\"; }\n"_L1;
|
||||||
html += "</style>"_L1;
|
html += "</style>"_L1;
|
||||||
html += "</head><body"_L1;
|
html += "</head><body"_L1;
|
||||||
|
|
||||||
@ -3038,7 +3040,7 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
|
|||||||
|
|
||||||
html += " style=\""_L1;
|
html += " style=\""_L1;
|
||||||
html += styleString;
|
html += styleString;
|
||||||
html += "\">"_L1;
|
html += "\">\n"_L1;
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "<li"_L1;
|
html += "<li"_L1;
|
||||||
@ -3051,6 +3053,18 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
|
|||||||
|
|
||||||
defaultCharFormat.merge(block.charFormat());
|
defaultCharFormat.merge(block.charFormat());
|
||||||
}
|
}
|
||||||
|
if (block.blockFormat().hasProperty(QTextFormat::BlockMarker)) {
|
||||||
|
switch (block.blockFormat().marker()) {
|
||||||
|
case QTextBlockFormat::MarkerType::Checked:
|
||||||
|
html += " class=\"checked\""_L1;
|
||||||
|
break;
|
||||||
|
case QTextBlockFormat::MarkerType::Unchecked:
|
||||||
|
html += " class=\"unchecked\""_L1;
|
||||||
|
break;
|
||||||
|
case QTextBlockFormat::MarkerType::NoMarker:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QTextBlockFormat blockFormat = block.blockFormat();
|
const QTextBlockFormat blockFormat = block.blockFormat();
|
||||||
|
@ -1636,6 +1636,14 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Html_li:
|
||||||
|
if (key == "class"_L1) {
|
||||||
|
if (value == "unchecked"_L1)
|
||||||
|
node->blockFormat.setMarker(QTextBlockFormat::MarkerType::Unchecked);
|
||||||
|
else if (value == "checked"_L1)
|
||||||
|
node->blockFormat.setMarker(QTextBlockFormat::MarkerType::Checked);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Html_a:
|
case Html_a:
|
||||||
if (key == "href"_L1)
|
if (key == "href"_L1)
|
||||||
node->charFormat.setAnchorHref(value);
|
node->charFormat.setAnchorHref(value);
|
||||||
|
@ -274,6 +274,8 @@ void tst_QTextDocument::init()
|
|||||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
|
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
|
||||||
"p, li { white-space: pre-wrap; }\n"
|
"p, li { white-space: pre-wrap; }\n"
|
||||||
"hr { height: 1px; border-width: 0; }\n"
|
"hr { height: 1px; border-width: 0; }\n"
|
||||||
|
"li.unchecked::marker { content: \"\\2610\"; }\n"
|
||||||
|
"li.checked::marker { content: \"\\2612\"; }\n"
|
||||||
"</style></head>"
|
"</style></head>"
|
||||||
"<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\">\n");
|
"<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\">\n");
|
||||||
htmlHead = htmlHead.arg(defaultFont.family())
|
htmlHead = htmlHead.arg(defaultFont.family())
|
||||||
@ -1371,7 +1373,7 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
QTest::newRow("lists") << QTextDocumentFragment(&doc)
|
QTest::newRow("lists") << QTextDocumentFragment(&doc)
|
||||||
<<
|
<<
|
||||||
QString("EMPTYBLOCK") +
|
QString("EMPTYBLOCK") +
|
||||||
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>");
|
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1394,7 +1396,7 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
QTest::newRow("charfmt-for-list-item") << QTextDocumentFragment(&doc)
|
QTest::newRow("charfmt-for-list-item") << QTextDocumentFragment(&doc)
|
||||||
<<
|
<<
|
||||||
QString("EMPTYBLOCK") +
|
QString("EMPTYBLOCK") +
|
||||||
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>");
|
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1424,7 +1426,7 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
QTest::newRow("list-indent") << QTextDocumentFragment(&doc)
|
QTest::newRow("list-indent") << QTextDocumentFragment(&doc)
|
||||||
<<
|
<<
|
||||||
QString("EMPTYBLOCK") +
|
QString("EMPTYBLOCK") +
|
||||||
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>");
|
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\">\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1712,7 +1714,7 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
|
|
||||||
QTest::newRow("list-ul-margin") << QTextDocumentFragment(&doc)
|
QTest::newRow("list-ul-margin") << QTextDocumentFragment(&doc)
|
||||||
<< QString("EMPTYBLOCK") +
|
<< QString("EMPTYBLOCK") +
|
||||||
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>");
|
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
CREATE_DOC_AND_CURSOR();
|
CREATE_DOC_AND_CURSOR();
|
||||||
@ -1722,12 +1724,12 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
cursor.insertHtml(listHtml);
|
cursor.insertHtml(listHtml);
|
||||||
|
|
||||||
QTest::newRow("nested-lists-one") << QTextDocumentFragment(&doc)
|
QTest::newRow("nested-lists-one") << QTextDocumentFragment(&doc)
|
||||||
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
|
<< QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; "
|
||||||
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
||||||
"item-1</li>\n<li DEFAULTBLOCKSTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li "
|
"item-1</li>\n<li DEFAULTBLOCKSTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li "
|
||||||
"DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2\n<ul "
|
"DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2\n<ul "
|
||||||
"DEFAULTULSTYLE 3;\"><li DEFAULTBLOCKSTYLE>item-2.2.1</li></ul></li>\n"
|
"DEFAULTULSTYLE 3;\">\n<li DEFAULTBLOCKSTYLE>item-2.2.1</li></ul></li>\n"
|
||||||
"<li DEFAULTBLOCKSTYLE>item-2.3\n<ul DEFAULTULSTYLE 3;\"><li DEFAULTBLOCKSTYLE>"
|
"<li DEFAULTBLOCKSTYLE>item-2.3\n<ul DEFAULTULSTYLE 3;\">\n<li DEFAULTBLOCKSTYLE>"
|
||||||
"item-2.3.1</li></ul></li></ul></li>\n<li DEFAULTLASTLISTYLE>item-3</li></ul>");
|
"item-2.3.1</li></ul></li></ul></li>\n<li DEFAULTLASTLISTYLE>item-3</li></ul>");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -1736,9 +1738,9 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
cursor.insertHtml(listHtml);
|
cursor.insertHtml(listHtml);
|
||||||
|
|
||||||
QTest::newRow("nested-lists-two") << QTextDocumentFragment(&doc)
|
QTest::newRow("nested-lists-two") << QTextDocumentFragment(&doc)
|
||||||
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
|
<< QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; "
|
||||||
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
||||||
"item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li "
|
"item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li "
|
||||||
"DEFAULTBLOCKSTYLE>item-2.1</li></ul></li></ul>");
|
"DEFAULTBLOCKSTYLE>item-2.1</li></ul></li></ul>");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -1748,9 +1750,9 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
cursor.insertHtml(listHtml);
|
cursor.insertHtml(listHtml);
|
||||||
|
|
||||||
QTest::newRow("nested-lists-three") << QTextDocumentFragment(&doc)
|
QTest::newRow("nested-lists-three") << QTextDocumentFragment(&doc)
|
||||||
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
|
<< QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; "
|
||||||
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
||||||
"item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li "
|
"item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li "
|
||||||
"DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2</li></ul>"
|
"DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2</li></ul>"
|
||||||
"</li></ul>");
|
"</li></ul>");
|
||||||
}
|
}
|
||||||
@ -1761,12 +1763,23 @@ void tst_QTextDocument::toHtml_data()
|
|||||||
cursor.insertHtml(listHtml);
|
cursor.insertHtml(listHtml);
|
||||||
|
|
||||||
QTest::newRow("not-nested-list") << QTextDocumentFragment(&doc)
|
QTest::newRow("not-nested-list") << QTextDocumentFragment(&doc)
|
||||||
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
|
<< QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; "
|
||||||
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
|
||||||
"item-1.1</li>\n<li DEFAULTBLOCKSTYLE>item-1.2</li></ul>\n<ul DEFAULTULSTYLE 1;\">"
|
"item-1.1</li>\n<li DEFAULTBLOCKSTYLE>item-1.2</li></ul>\n<ul DEFAULTULSTYLE 1;\">\n"
|
||||||
"<li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; "
|
"<li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; "
|
||||||
"margin-right:0px; -qt-block-indent:0; text-indent:0px;\">item-2.1</li></ul>");
|
"margin-right:0px; -qt-block-indent:0; text-indent:0px;\">item-2.1</li></ul>");
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
CREATE_DOC_AND_CURSOR();
|
||||||
|
const QString listHtml = "<ul><li>bullet</li><li class=\"unchecked\">unchecked item</li><li class=\"checked\">checked item</li></ul>";
|
||||||
|
cursor.insertHtml(listHtml);
|
||||||
|
|
||||||
|
QTest::newRow("list with and without checkboxes") << QTextDocumentFragment(&doc)
|
||||||
|
<< QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n"
|
||||||
|
"<li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">bullet</li>\n"
|
||||||
|
"<li class=\"unchecked\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">unchecked item</li>\n"
|
||||||
|
"<li class=\"checked\" style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">checked item</li></ul>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QTextDocument::toHtml()
|
void tst_QTextDocument::toHtml()
|
||||||
|
@ -502,6 +502,9 @@ void tst_QTextMarkdownWriter::fromHtml_data()
|
|||||||
QTest::newRow("preformats with embedded backticks") <<
|
QTest::newRow("preformats with embedded backticks") <<
|
||||||
"<pre>none `one` ``two``</pre>plain<pre>```three``` ````four````</pre>plain" <<
|
"<pre>none `one` ``two``</pre>plain<pre>```three``` ````four````</pre>plain" <<
|
||||||
"```\nnone `one` ``two``\n\n```\nplain\n\n```\n```three``` ````four````\n\n```\nplain\n\n";
|
"```\nnone `one` ``two``\n\n```\nplain\n\n```\n```three``` ````four````\n\n```\nplain\n\n";
|
||||||
|
QTest::newRow("list items with and without checkboxes") <<
|
||||||
|
"<ul><li>bullet</li><li class=\"unchecked\">unchecked item</li><li class=\"checked\">checked item</li></ul>" <<
|
||||||
|
"- bullet\n- [ ] unchecked item\n- [x] checked item\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QTextMarkdownWriter::fromHtml()
|
void tst_QTextMarkdownWriter::fromHtml()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user