BibleTime
teitohtml.cpp
Go to the documentation of this file.
1/*********
2*
3* In the name of the Father, and of the Son, and of the Holy Spirit.
4*
5* This file is part of BibleTime's source code, https://bibletime.info/
6*
7* Copyright 1999-2025 by the BibleTime developers.
8* The BibleTime source code is licensed under the GNU General Public License
9* version 2.0.
10*
11**********/
12
13#include "teitohtml.h"
14
15#include <QString>
16#include <string_view>
17#include "../config/btconfig.h"
18#include "../drivers/cswordmoduleinfo.h"
19#include "../managers/cswordbackend.h"
20#include "../managers/referencemanager.h"
21
22// Sword includes:
23#pragma GCC diagnostic push
24#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
25#include <swbuf.h>
26#include <swmodule.h>
27#include <utilxml.h>
28#pragma GCC diagnostic pop
29
30
31namespace Filters {
32
34 : sword::TEIHTMLHREF()
35{
36 setPassThruUnknownEscapeString(true); // the HTML widget will render the HTML escape codes
37}
38
39bool TeiToHtml::handleToken(sword::SWBuf &buf, const char *token,
40 sword::BasicFilterUserData *userData)
41{
42 using namespace std::literals;
43 // manually process if it wasn't a simple substitution
44
45 if (!substituteToken(buf, token)) {
46
47 sword::XMLTag const tag(token);
48 std::string_view const tagName(tag.getName());
49
50 if (tagName == "ref"sv) {
51
52 if (!tag.isEndTag() && !tag.isEmpty()) {
53
54 const char * attribute = tag.getAttribute("osisRef");
55 if (attribute != nullptr)
56 renderReference(attribute, buf, userData);
57 else {
58 attribute = tag.getAttribute("target");
59 renderTargetReference(attribute, buf, userData);
60 }
61
62 }
63 else if (tag.isEndTag()) {
64 buf.append("</a>");
65 }
66 else { // empty reference marker
67 // -- what should we do? nothing for now.
68 }
69 }
70 else if (tagName == "hi"sv) { // <hi> highlighted text
71 const sword::SWBuf type = tag.getAttribute("rend");
72
73 if ((!tag.isEndTag()) && (!tag.isEmpty())) {
74 if (type == "bold") {
75 buf.append("<span class=\"bold\">");
76 }
77 else if (type == "illuminated") {
78 buf.append("<span class=\"illuminated\">");
79 }
80 else if (type == "italic") {
81 buf.append("<span class=\"italic\">");
82 }
83 else if (type == "line-through") {
84 buf.append("<span class=\"line-through\">");
85 }
86 else if (type == "normal") {
87 buf.append("<span class=\"normal\">");
88 }
89 else if (type == "small-caps") {
90 buf.append("<span class=\"small-caps\">");
91 }
92 else if (type == "underline") {
93 buf.append("<span class=\"underline\">");
94 }
95 else {
96 buf.append("<span>"); //don't break markup, </span> is inserted later
97 }
98 }
99 else if (tag.isEndTag()) { //all hi replacements are html spans
100 buf.append("</span>");
101 }
102 }
103 else { //all tokens handled by OSISHTMLHref will run through the filter now
104 return sword::TEIHTMLHREF::handleToken(buf, token, userData);
105 }
106 }
107
108 return false;
109}
110
111void TeiToHtml::renderReference(const char *osisRef, sword::SWBuf &buf,
112 sword::BasicFilterUserData *myUserData)
113{
114
115 if (QString ref = osisRef; !ref.isEmpty()) {
116 //find out the mod, using the current module makes sense if it's a bible or commentary because the refs link into a bible by default.
117 //If the osisRef is something like "ModuleID:key comes here" then the
118 // modulename is given, so we'll use that one
119
120 CSwordModuleInfo * mod;
121 QString hrefRef;
122
123 //if the osisRef like "GerLut:key" contains a module, use that
124 if (auto const pos = ref.indexOf(':');
125 (pos > 0)
126 && (pos < ref.size() - 1)
127 && ref.at(pos - 1).isLetter()
128 && ref.at(pos + 1).isLetter())
129 {
130 hrefRef = ref.mid(pos + 1);
131 mod = CSwordBackend::instance().findModuleByName(ref.left(pos));
132 if (!mod)
134 QStringLiteral("standardBible"));
135 } else {
136 hrefRef = ref;
138 QStringLiteral("standardBible"));
139 }
140 if (!mod)
143
144 if (mod) {
145 ReferenceManager::ParseOptions const options{
146 mod->name(),
147 QString::fromUtf8(myUserData->key->getText()),
148 mod->swordModule().getLanguage()};
149
150 buf.append("<a href=\"")
151 .append( // create the hyperlink with key and mod
153 *mod,
155 ).toUtf8().constData()
156 )
157 .append("\" crossrefs=\"")
158 // ref must contain the osisRef module marker if there was any:
159 .append(ReferenceManager::parseVerseReference(ref, options).toUtf8().constData())
160 .append("\">");
161 }
162 // should we add something if there were no referenced module available?
163 }
164}
165
166void TeiToHtml::renderTargetReference(const char *osisRef, sword::SWBuf &buf,
167 sword::BasicFilterUserData *myUserData)
168{
169 if (QString ref = osisRef; !ref.isEmpty()) {
170 //find out the mod, using the current module makes sense if it's a bible or commentary because the refs link into a bible by default.
171 //If the target is something like "ModuleID:key comes here" then the
172 // modulename is given, so we'll use that one
173
174 CSwordModuleInfo * mod;
175 auto const & backend = CSwordBackend::instance();
176
177 //if the target like "GerLut:key" contains a module, use that
178 if (auto const pos = ref.indexOf(':'); pos >= 0) {
179 QString newModuleName = ref.left(pos);
180 ref.remove(0, pos + 1);
181
182 mod = backend.findModuleByName(newModuleName);
183 if (!mod)
184 mod = backend.findModuleByName(myUserData->module->getName());
185 } else {
186 mod = backend.findModuleByName(myUserData->module->getName());
187 }
188
189 if (mod) {
190 ReferenceManager::ParseOptions const options{
191 mod->name(),
192 QString::fromUtf8(myUserData->key->getText()),
193 mod->swordModule().getLanguage()};
194
195 buf.append("<a class=\"crossreference\" href=\"")
196 .append( // create the hyperlink with key and mod
198 *mod,
199 ref.toUtf8().constData()
200 ).toUtf8().constData()
201 )
202 .append("\">");
203 }
204 }
205}
206
207} // namespace Filters
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
CSwordModuleInfo * getDefaultSwordModuleByType(const QString &moduleType)
Returns default sword module info class for a given module type.
Definition btconfig.cpp:494
CSwordModuleInfo * findFirstAvailableModule(CSwordModuleInfo::ModuleType type)
CSwordModuleInfo * findModuleByName(const QString &name) const
Searches for a module with the given name.
static CSwordBackend & instance() noexcept
QString const & name() const
sword::SWModule & swordModule() const
void renderTargetReference(const char *osisRef, sword::SWBuf &buf, sword::BasicFilterUserData *myUserData)
void renderReference(const char *osisRef, sword::SWBuf &buf, sword::BasicFilterUserData *myUserData)
bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) override
Definition teitohtml.cpp:39
QString parseVerseReference(QString const &ref, ParseOptions const &options)
QString encodeHyperlink(CSwordModuleInfo const &module, QString const &key)