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-2026 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#ifdef __GNUC__
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
26#endif
27#include <swbuf.h>
28#include <swmodule.h>
29#include <utilxml.h>
30#ifdef __GNUC__
31#pragma GCC diagnostic pop
32#endif
33
34
35namespace Filters {
36
38 : sword::TEIHTMLHREF()
39{
40 setPassThruUnknownEscapeString(true); // the HTML widget will render the HTML escape codes
41}
42
43bool TeiToHtml::handleToken(sword::SWBuf &buf, const char *token,
44 sword::BasicFilterUserData *userData)
45{
46 using namespace std::literals;
47 // manually process if it wasn't a simple substitution
48
49 if (!substituteToken(buf, token)) {
50
51 sword::XMLTag const tag(token);
52 std::string_view const tagName(tag.getName());
53
54 if (tagName == "ref"sv) {
55
56 if (!tag.isEndTag() && !tag.isEmpty()) {
57
58 const char * attribute = tag.getAttribute("osisRef");
59 if (attribute != nullptr)
60 renderReference(attribute, buf, userData);
61 else {
62 attribute = tag.getAttribute("target");
63 renderTargetReference(attribute, buf, userData);
64 }
65
66 }
67 else if (tag.isEndTag()) {
68 buf.append("</a>");
69 }
70 else { // empty reference marker
71 // -- what should we do? nothing for now.
72 }
73 }
74 else if (tagName == "hi"sv) { // <hi> highlighted text
75 const sword::SWBuf type = tag.getAttribute("rend");
76
77 if ((!tag.isEndTag()) && (!tag.isEmpty())) {
78 if (type == "bold") {
79 buf.append("<span class=\"bold\">");
80 }
81 else if (type == "illuminated") {
82 buf.append("<span class=\"illuminated\">");
83 }
84 else if (type == "italic") {
85 buf.append("<span class=\"italic\">");
86 }
87 else if (type == "line-through") {
88 buf.append("<span class=\"line-through\">");
89 }
90 else if (type == "normal") {
91 buf.append("<span class=\"normal\">");
92 }
93 else if (type == "small-caps") {
94 buf.append("<span class=\"small-caps\">");
95 }
96 else if (type == "underline") {
97 buf.append("<span class=\"underline\">");
98 }
99 else {
100 buf.append("<span>"); //don't break markup, </span> is inserted later
101 }
102 }
103 else if (tag.isEndTag()) { //all hi replacements are html spans
104 buf.append("</span>");
105 }
106 }
107 else { //all tokens handled by OSISHTMLHref will run through the filter now
108 return sword::TEIHTMLHREF::handleToken(buf, token, userData);
109 }
110 }
111
112 return false;
113}
114
115void TeiToHtml::renderReference(const char *osisRef, sword::SWBuf &buf,
116 sword::BasicFilterUserData *myUserData)
117{
118
119 if (QString ref = osisRef; !ref.isEmpty()) {
120 //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.
121 //If the osisRef is something like "ModuleID:key comes here" then the
122 // modulename is given, so we'll use that one
123
124 CSwordModuleInfo * mod;
125 QString hrefRef;
126
127 //if the osisRef like "GerLut:key" contains a module, use that
128 if (auto const pos = ref.indexOf(':');
129 (pos > 0)
130 && (pos < ref.size() - 1)
131 && ref.at(pos - 1).isLetter()
132 && ref.at(pos + 1).isLetter())
133 {
134 hrefRef = ref.mid(pos + 1);
135 mod = CSwordBackend::instance().findModuleByName(ref.left(pos));
136 if (!mod)
138 QStringLiteral("standardBible"));
139 } else {
140 hrefRef = ref;
142 QStringLiteral("standardBible"));
143 }
144 if (!mod)
147
148 if (mod) {
149 ReferenceManager::ParseOptions const options{
150 mod->name(),
151 QString::fromUtf8(myUserData->key->getText()),
152 mod->swordModule().getLanguage()};
153
154 buf.append("<a href=\"")
155 .append( // create the hyperlink with key and mod
157 *mod,
159 ).toUtf8().constData()
160 )
161 .append("\" crossrefs=\"")
162 // ref must contain the osisRef module marker if there was any:
163 .append(ReferenceManager::parseVerseReference(ref, options).toUtf8().constData())
164 .append("\">");
165 }
166 // should we add something if there were no referenced module available?
167 }
168}
169
170void TeiToHtml::renderTargetReference(const char *osisRef, sword::SWBuf &buf,
171 sword::BasicFilterUserData *myUserData)
172{
173 if (QString ref = osisRef; !ref.isEmpty()) {
174 //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.
175 //If the target is something like "ModuleID:key comes here" then the
176 // modulename is given, so we'll use that one
177
178 CSwordModuleInfo * mod;
179 auto const & backend = CSwordBackend::instance();
180
181 //if the target like "GerLut:key" contains a module, use that
182 if (auto const pos = ref.indexOf(':'); pos >= 0) {
183 QString newModuleName = ref.left(pos);
184 ref.remove(0, pos + 1);
185
186 mod = backend.findModuleByName(newModuleName);
187 if (!mod)
188 mod = backend.findModuleByName(myUserData->module->getName());
189 } else {
190 mod = backend.findModuleByName(myUserData->module->getName());
191 }
192
193 if (mod) {
194 ReferenceManager::ParseOptions const options{
195 mod->name(),
196 QString::fromUtf8(myUserData->key->getText()),
197 mod->swordModule().getLanguage()};
198
199 buf.append("<a class=\"crossreference\" href=\"")
200 .append( // create the hyperlink with key and mod
202 *mod,
203 ref.toUtf8().constData()
204 ).toUtf8().constData()
205 )
206 .append("\">");
207 }
208 }
209}
210
211} // 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:497
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:43
QString parseVerseReference(QString const &ref, ParseOptions const &options)
QString encodeHyperlink(CSwordModuleInfo const &module, QString const &key)