)" ),
"",
@@ -639,19 +640,20 @@ void ArticleRequest::bodyFinished()
fmt::format_to( std::back_inserter( head ),
FMT_COMPILE(
- R"(
)" ),
+
![{6}]()
+ )" ),
dictId,
collapse ? R"(style="cursor:pointer;")" : "",
"",
Html::escape( tr( "From " ).toStdString() ),
Html::escape( activeDict->getName() ),
collapse ? "gdexpandicon" : "gdcollapseicon",
- "" );
+ "",
+ collapse ? "false" : "true" );
head += R"(
)";
@@ -669,7 +671,7 @@ void ArticleRequest::bodyFinished()
fmt::format_to(
std::back_inserter( head ),
FMT_COMPILE(
- R"(
)" ),
+ R"()" ),
LangCoder::intToCode2( activeDict->getLangFrom() ).toStdString(),
LangCoder::intToCode2( activeDict->getLangTo() ).toStdString(),
collapse ? "none" : "block",
@@ -692,7 +694,7 @@ void ArticleRequest::bodyFinished()
qWarning() << "getDataSlice error:" << e.what();
}
- auto separator = R"(
)"
+ Html::escape( tr( "Compound expressions: " ).toUtf8().data() )
- + "";
+ + "";
firstCompoundWasFound = true;
}
@@ -877,14 +879,13 @@ void ArticleRequest::compoundSearchNextStep( bool lastSearchSucceeded )
// The last word was the last possible to start from
if ( firstCompoundWasFound ) {
- footer += "";
+ footer += "
";
}
// Now add links to all the individual words. They conclude the result.
footer += R"(
)"
- + Html::escape( tr( "Individual words: " ).toUtf8().data() )
- + "";
+ footer += "
";
footer += "";
diff --git a/src/article_netmgr.cc b/src/article_netmgr.cc
index 55bfea33be..c668a8c81d 100644
--- a/src/article_netmgr.cc
+++ b/src/article_netmgr.cc
@@ -85,9 +85,6 @@ QNetworkReply * ArticleNetworkAccessManager::getArticleReply( const QNetworkRequ
QNetworkRequest newReq;
newReq.setUrl( url );
newReq.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy );
- if ( hideGoldenDictHeader && url.scheme().startsWith( "http", Qt::CaseInsensitive ) ) {
- newReq.setRawHeader( "User-Agent", req.rawHeader( "User-Agent" ).replace( qApp->applicationName().toUtf8(), "" ) );
- }
QNetworkReply * reply = QNetworkAccessManager::createRequest( op, newReq, nullptr );
@@ -222,7 +219,31 @@ sptr< Dictionary::DataRequest > ArticleNetworkAccessManager::handleLookupScheme(
}
// See if we have some dictionaries muted
- QStringList mutedDictLists = Utils::Url::queryItemValue( url, "muted" ).split( ',' );
+ QString mutedDictsEncoded = Utils::Url::queryItemValue( url, "muted" );
+ QStringList mutedDictLists;
+
+ if ( !mutedDictsEncoded.isEmpty() ) {
+ mutedDictLists = mutedDictsEncoded.split( ',' );
+ }
+ else {
+ // If muted is not provided in URL, we get it from config
+ const Config::Class * cfg = GlobalBroadcaster::instance()->getConfig();
+ if ( cfg ) {
+ bool isPopup = Utils::Url::queryItemValue( url, "popup" ) == "1";
+ const Config::Group * grp = cfg->getGroup( group );
+ const Config::DictionarySets * mutedDictionaries;
+ if ( group == GroupId::AllGroupId ) {
+ mutedDictionaries = isPopup ? &cfg->popupMutedDictionaries : &cfg->mutedDictionaries;
+ }
+ else {
+ mutedDictionaries = grp ? ( isPopup ? &grp->popupMutedDictionaries : &grp->mutedDictionaries ) : nullptr;
+ }
+
+ if ( mutedDictionaries ) {
+ mutedDictLists = mutedDictionaries->values();
+ }
+ }
+ }
QSet< QString > mutedDicts( mutedDictLists.begin(), mutedDictLists.end() );
// Unpack contexts
diff --git a/src/article_netmgr.hh b/src/article_netmgr.hh
index e64149597b..049543571d 100644
--- a/src/article_netmgr.hh
+++ b/src/article_netmgr.hh
@@ -30,7 +30,6 @@ class ArticleNetworkAccessManager: public QNetworkAccessManager
const vector< sptr< Dictionary::Class > > & dictionaries;
const ArticleMaker & articleMaker;
const bool & disallowContentFromOtherSites;
- const bool & hideGoldenDictHeader;
QMimeDatabase db;
public:
@@ -38,13 +37,11 @@ public:
ArticleNetworkAccessManager( QObject * parent,
const vector< sptr< Dictionary::Class > > & dictionaries_,
const ArticleMaker & articleMaker_,
- const bool & disallowContentFromOtherSites_,
- const bool & hideGoldenDictHeader_ ):
+ const bool & disallowContentFromOtherSites_ ):
QNetworkAccessManager( parent ),
dictionaries( dictionaries_ ),
articleMaker( articleMaker_ ),
- disallowContentFromOtherSites( disallowContentFromOtherSites_ ),
- hideGoldenDictHeader( hideGoldenDictHeader_ )
+ disallowContentFromOtherSites( disallowContentFromOtherSites_ )
{
}
diff --git a/src/common/folding.cc b/src/common/folding.cc
index 1d8ebac989..af7f2098f0 100644
--- a/src/common/folding.cc
+++ b/src/common/folding.cc
@@ -40,6 +40,21 @@ std::u32string apply( const std::u32string & in, bool preserveWildcards )
return caseFolded;
}
+std::string applyForIndex( const QString & in )
+{
+ // remove diacritics (normalization)
+ auto temp = in.normalized( QString::NormalizationForm_KD ).remove( RX::accentPunc ).toStdU32String();
+ // case folding
+ std::u32string caseFolded;
+ caseFolded.reserve( temp.size() );
+ char32_t buf[ foldCaseMaxOut ];
+ for ( const char32_t ch : temp ) {
+ auto n = foldCase( ch, buf );
+ caseFolded.append( buf, n );
+ }
+ return Text::toUtf8( caseFolded );
+}
+
std::u32string applySimpleCaseOnly( const std::u32string & in )
{
const char32_t * nextChar = in.data();
diff --git a/src/common/folding.hh b/src/common/folding.hh
index c36a262fb3..54e3c15d6d 100644
--- a/src/common/folding.hh
+++ b/src/common/folding.hh
@@ -26,7 +26,7 @@ enum {
/// Applies the folding algorithm to each character in the given string,
/// making another one as a result.
std::u32string apply( const std::u32string &, bool preserveWildcards = false );
-
+std::string applyForIndex( const QString & in );
/// Applies only simple case folding algorithm. Since many dictionaries have
/// different case style, we interpret words differing only by case as synonyms.
std::u32string applySimpleCaseOnly( const std::u32string & );
diff --git a/src/common/globalbroadcaster.cc b/src/common/globalbroadcaster.cc
index d09cfca469..8f2151f820 100644
--- a/src/common/globalbroadcaster.cc
+++ b/src/common/globalbroadcaster.cc
@@ -16,7 +16,7 @@ GlobalBroadcaster::GlobalBroadcaster( QObject * parent ):
QStringList whiteUrlHosts = { "googleapis.com", "gstatic.com" };
for ( auto & host : std::as_const( whiteUrlHosts ) ) {
- whitelist.insert( host );
+ hostWhitelist.insert( host );
}
}
@@ -40,29 +40,39 @@ Config::Preferences * GlobalBroadcaster::getPreference() const
return config ? &config->preferences : nullptr;
}
-void GlobalBroadcaster::addWhitelist( QString host )
+void GlobalBroadcaster::addHostWhitelist( QString host )
{
- whitelist.insert( host );
+ hostWhitelist.insert( host );
}
-bool GlobalBroadcaster::existedInWhitelist( QString host ) const
+void GlobalBroadcaster::addRefererWhitelist( QString host )
+{
+ refererWhitelist.insert( host );
+}
+
+bool existedInWhitelistInternal( const QSet< QString > & whitelist, QString host )
{
for ( const QString & item : whitelist ) {
- // Exact match - e.g. "www.example.com" matches "www.example.com"
if ( host == item ) {
return true;
}
-
- // Extract base domain from both host and item for comparison
QString urlBaseDomain = Utils::Url::extractBaseDomain( host );
QString itemBaseDomain = Utils::Url::extractBaseDomain( item );
-
- // Compare base domains
if ( urlBaseDomain == itemBaseDomain ) {
return true;
}
}
- return false; // No match found
+ return false;
+}
+
+bool GlobalBroadcaster::existedInHostWhitelist( QString host ) const
+{
+ return existedInWhitelistInternal( hostWhitelist, host );
+}
+
+bool GlobalBroadcaster::existedInRefererWhitelist( QString host ) const
+{
+ return existedInWhitelistInternal( refererWhitelist, host );
}
diff --git a/src/common/globalbroadcaster.hh b/src/common/globalbroadcaster.hh
index 3bb12f573b..f303919d90 100644
--- a/src/common/globalbroadcaster.hh
+++ b/src/common/globalbroadcaster.hh
@@ -32,13 +32,17 @@ class GlobalBroadcaster: public QObject
const AudioPlayerPtr * audioPlayer = nullptr;
std::vector< sptr< Dictionary::Class > > * allDictionaries = nullptr;
Instances::Groups * groups = nullptr;
- QSet< QString > whitelist;
+ QSet< QString > hostWhitelist;
+ QSet< QString > refererWhitelist;
Icons::DictionaryIconName _icon_names;
QMap< QString, QString > lsaIdToPathMap;
QMap< QString, QString > lsaPathToIdMap;
QMap< QString, sptr< Dictionary::Class > > dictMap;
+
public:
+ std::atomic_bool is_popup;
+
void setConfig( Config::Class * _config );
Config::Class * getConfig() const;
void setAudioPlayer( const AudioPlayerPtr * _audioPlayer );
@@ -54,32 +58,14 @@ public:
// For backward compatibility
Config::Preferences * getPreference() const;
GlobalBroadcaster( QObject * parent = nullptr );
- /// \brief Add a host to whitelist.
- ///
- /// The host should be a full domain. For subdomain matching, add the base domain
- /// (e.g. "example.com"). For special TLDs, add the appropriate form
- /// (e.g. "example.com.uk" for UK sites).
- ///
- /// \param host The host to add to whitelist
- void addWhitelist( QString host );
-
- /// \brief Check if a host exists in the whitelist
- ///
- /// This method checks for exact matches and base domain matches:
- /// 1. Direct string matching - e.g. "www.example.com" matches "www.example.com"
- /// 2. Base domain matching using Utils::Url::extractBaseDomain() - e.g. "example.com" matches "www.example.com"
- ///
- /// Generic pattern handling for TLDs like .com.xx, .co.xx, .org.xx:
- /// - For "www.example.com.jp", the base domain is "example.com"
- /// - For "api.service.org.uk", the base domain is "service.org"
- ///
- /// Cross-TLD matching requires explicit entries:
- /// - To match both ".com" and ".com.xx" domains, both "example.com" and "example.com.xx"
- /// need to be added to the whitelist separately
- ///
+ /// \param host The host to add to host whitelist
+ void addHostWhitelist( QString host );
+ void addRefererWhitelist( QString host );
+
/// \param host The host to check
- /// \return true if the host is in the whitelist, false otherwise
- bool existedInWhitelist( QString host ) const;
+ /// \return true if the host is in the host whitelist, false otherwise
+ bool existedInHostWhitelist( QString host ) const;
+ bool existedInRefererWhitelist( QString host ) const;
static GlobalBroadcaster * instance();
unsigned currentGroupId;
QString translateLineText{};
@@ -101,5 +87,5 @@ signals:
void indexingDictionary( QString );
- void websiteDictionarySignal( QString, QString, QString );
+ void websiteDictionarySignal( QString, QString, QString, bool, QString );
};
diff --git a/src/common/globalregex.cc b/src/common/globalregex.cc
index abe14a5c8b..b1301e21e6 100644
--- a/src/common/globalregex.cc
+++ b/src/common/globalregex.cc
@@ -74,6 +74,7 @@ QRegularExpression Mdx::styleElement( R"((