mirror of
https://github.com/kiwix/libkiwix.git
synced 2025-08-03 10:16:03 -04:00
New 404 error page
The page doesn't support translation, yet. The new 404 error page is used only when accessing ZIM file content (i.e. as a response from the `/content` API endpoint). One notable difference from the previous error page is that now no hint is provided about whether the error is due to trying to access a non-existent book/ZIM-file or non-existent resource inside a valid book/ZIM-file (previously such a hint was present in the suggested search URL). However, when displayed in the viewer this difference can be seen in the viewer toolbar - book related buttons are hidden if the URL points to a non-existent book. This change breaks some unit tests. They will be fixed in a separate commit.
This commit is contained in:
parent
107421cdab
commit
5eb31d7286
@ -1121,15 +1121,6 @@ InternalServer::search_catalog(const RequestContext& request,
|
||||
namespace
|
||||
{
|
||||
|
||||
ParameterizedMessage suggestSearchMsg(const std::string& searchURL, const std::string& pattern)
|
||||
{
|
||||
return ParameterizedMessage("suggest-search",
|
||||
{
|
||||
{ "PATTERN", pattern },
|
||||
{ "SEARCH_URL", searchURL }
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The content security policy below is set on responses to the /content
|
||||
// endpoint in order to prevent the ZIM content from interfering with the
|
||||
@ -1183,9 +1174,7 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
||||
} catch (const std::out_of_range& e) {}
|
||||
|
||||
if (archive == nullptr) {
|
||||
const std::string searchURL = m_root + "/search?pattern=" + kiwix::urlEncode(pattern);
|
||||
return UrlNotFoundResponse(request)
|
||||
+ suggestSearchMsg(searchURL, kiwix::urlDecode(pattern));
|
||||
return NewHTTP404Response(request, m_root, m_root + url);
|
||||
}
|
||||
|
||||
const std::string archiveUuid(archive->getUuid());
|
||||
@ -1230,9 +1219,7 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
||||
if (m_verbose.load())
|
||||
printf("Failed to find %s\n", urlStr.c_str());
|
||||
|
||||
std::string searchURL = m_root + "/search?content=" + bookName + "&pattern=" + kiwix::urlEncode(pattern);
|
||||
return UrlNotFoundResponse(request)
|
||||
+ suggestSearchMsg(searchURL, kiwix::urlDecode(pattern));
|
||||
return NewHTTP404Response(request, m_root, m_root + url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,6 +368,21 @@ std::unique_ptr<ContentResponse> ContentResponseBlueprint::generateResponseObjec
|
||||
return r;
|
||||
}
|
||||
|
||||
NewHTTP404Response::NewHTTP404Response(const RequestContext& request,
|
||||
const std::string& root,
|
||||
const std::string& urlPath)
|
||||
: ContentResponseBlueprint(&request,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
"text/html; charset=utf-8",
|
||||
RESOURCE::templates::sexy404_html,
|
||||
/*includeKiwixResponseData=*/false)
|
||||
{
|
||||
*this->m_data = Data(Data::Object{
|
||||
{"root", root },
|
||||
{"url_path", urlPath}
|
||||
});
|
||||
}
|
||||
|
||||
HTTPErrorResponse::HTTPErrorResponse(const RequestContext& request,
|
||||
int httpStatusCode,
|
||||
const std::string& pageTitleMsgId,
|
||||
|
@ -145,6 +145,13 @@ protected: //data
|
||||
std::unique_ptr<Data> m_data;
|
||||
};
|
||||
|
||||
struct NewHTTP404Response : ContentResponseBlueprint
|
||||
{
|
||||
NewHTTP404Response(const RequestContext& request,
|
||||
const std::string& root,
|
||||
const std::string& urlPath);
|
||||
};
|
||||
|
||||
struct HTTPErrorResponse : ContentResponseBlueprint
|
||||
{
|
||||
HTTPErrorResponse(const RequestContext& request,
|
||||
|
@ -1,6 +1,7 @@
|
||||
skin/caret.png
|
||||
skin/bittorrent.png
|
||||
skin/magnet.png
|
||||
skin/404.svg
|
||||
skin/feed.svg
|
||||
skin/langSelector.svg
|
||||
skin/download.png
|
||||
@ -11,9 +12,11 @@ skin/iso6391To3.js
|
||||
skin/isotope.pkgd.min.js
|
||||
skin/index.js
|
||||
skin/autoComplete/autoComplete.min.js
|
||||
skin/error.css
|
||||
skin/kiwix.css
|
||||
skin/taskbar.css
|
||||
skin/index.css
|
||||
skin/fonts/DMSans-Regular.ttf
|
||||
skin/fonts/Poppins.ttf
|
||||
skin/fonts/Roboto.ttf
|
||||
skin/search_results.css
|
||||
@ -42,6 +45,7 @@ templates/url_of_search_results_css.tmpl
|
||||
templates/viewer_settings.js
|
||||
templates/no_js_library_page.html
|
||||
templates/no_js_download.html
|
||||
templates/sexy404.html
|
||||
opensearchdescription.xml
|
||||
ft_opensearchdescription.xml
|
||||
catalog_v2_searchdescription.xml
|
||||
|
1
static/skin/404.svg
Normal file
1
static/skin/404.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.4 KiB |
153
static/skin/error.css
Normal file
153
static/skin/error.css
Normal file
@ -0,0 +1,153 @@
|
||||
@font-face {
|
||||
font-family:"DM Sans";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src : url('../skin/fonts/DMSans-Regular.ttf?KIWIXCACHEID');
|
||||
}
|
||||
@font-face {
|
||||
font-family:"DM Sans Bold";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src : url('../skin/fonts/DMSans-Regular.ttf?KIWIXCACHEID');
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(to bottom right, #ffffff, #e6e6e6);
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
header {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
|
||||
margin-top: 15%;
|
||||
margin-bottom: 15%;
|
||||
}
|
||||
|
||||
header img {
|
||||
width: 60%;
|
||||
min-width: 200px;
|
||||
max-width: 500px;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
header, .intro {
|
||||
font-family: "DM Sans";
|
||||
}
|
||||
|
||||
.intro {
|
||||
font-size: 1em;
|
||||
padding: 0 10%;
|
||||
line-height: 1.2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.intro h1 {
|
||||
line-height: 1.1em;
|
||||
font-family: "DM Sans Bold";
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.intro code {
|
||||
font-family: monospace;
|
||||
font-size: 1.1em;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.advice {
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
margin-bottom: 15%;
|
||||
margin-top: 5em;
|
||||
|
||||
background-color: #ffffff;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid #b7b7b7;
|
||||
|
||||
padding: 2em;
|
||||
|
||||
font-family: "DM Sans";
|
||||
font-size: .9em;
|
||||
box-sizing: border-box;
|
||||
|
||||
align-items: normal;
|
||||
}
|
||||
|
||||
.advice p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.advice p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.advice p.list-intro {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.advice ul {
|
||||
list-style-type: square;
|
||||
margin: 0;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.advice ul li {
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.advice p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
/* sm: 640px+ */
|
||||
@media (width >= 40rem) {
|
||||
header {
|
||||
margin-bottom: 1em;
|
||||
margin-top: 5em;
|
||||
}
|
||||
|
||||
header img {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.intro h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.advice {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/* xl: 1280px+ */
|
||||
@media (width >= 80rem) {
|
||||
.intro h1 {
|
||||
font-size: 3.4em;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2xl: 1536px+ */
|
||||
@media (width >= 96rem) {
|
||||
header img {
|
||||
width: 25%;
|
||||
min-width: 200px;
|
||||
max-width: 500px;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.advice {
|
||||
width: 25%;
|
||||
min-width: 200px;
|
||||
min-width: 300px;
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
BIN
static/skin/fonts/DMSans-Regular.ttf
Normal file
BIN
static/skin/fonts/DMSans-Regular.ttf
Normal file
Binary file not shown.
31
static/templates/sexy404.html
Normal file
31
static/templates/sexy404.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>Page not found</title>
|
||||
<link type="text/css" href="{{root}}/skin/error.css?KIWIXCACHEID" rel="Stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<img src="{{root}}/skin/404.svg?KIWIXCACHEID"
|
||||
alt="Not found!"
|
||||
aria-label="Not found!"
|
||||
title="Not found!">
|
||||
</header>
|
||||
<section class="intro">
|
||||
<h1>Oops. Page not found.</h1>
|
||||
<p>The requested path was not found:</p>
|
||||
<p><code>{{url_path}}</code></p>
|
||||
</section>
|
||||
<section class="advice">
|
||||
<p>The content you're looking for may still be available, but it might be located at a different place within the ZIM file.</p>
|
||||
<p class="list-intro">Please:</p>
|
||||
<ul>
|
||||
<li>Try using the search function to find the content you want</li>
|
||||
<li>Look for keywords or titles related to the information you're seeking</li>
|
||||
</ul>
|
||||
<p>This approach should help you locate the desired content, even if the original link isn't working properly.</p>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
@ -58,6 +58,8 @@ const ResourceCollection resources200Compressible{
|
||||
{ STATIC_CONTENT, "/ROOT%23%3F/skin/autoComplete/autoComplete.min.js?cacheid=1191aaaf" },
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/autoComplete/css/autoComplete.css" },
|
||||
{ STATIC_CONTENT, "/ROOT%23%3F/skin/autoComplete/css/autoComplete.css?cacheid=f2d376c4" },
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/error.css" },
|
||||
{ STATIC_CONTENT, "/ROOT%23%3F/skin/error.css?cacheid=c49d1586" },
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/i18n.js" },
|
||||
{ STATIC_CONTENT, "/ROOT%23%3F/skin/i18n.js?cacheid=071abc9a" },
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.css" },
|
||||
@ -106,6 +108,8 @@ const ResourceCollection resources200Compressible{
|
||||
};
|
||||
|
||||
const ResourceCollection resources200Uncompressible{
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/404.svg" },
|
||||
{ STATIC_CONTENT, "/ROOT%23%3F/skin/404.svg?cacheid=b6d648af" },
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/bittorrent.png" },
|
||||
{ STATIC_CONTENT, "/ROOT%23%3F/skin/bittorrent.png?cacheid=4f5c6882" },
|
||||
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/blank.html" },
|
||||
@ -339,6 +343,12 @@ R"EXPECTEDRESULT( <link type="text/css" href="./skin/kiwix.css?cacheid=3948b8
|
||||
/* url */ "/ROOT%23%3F/content/zimfile/A/index",
|
||||
""
|
||||
},
|
||||
{
|
||||
/* url */ "/ROOT%23%3F/content/invalid-book/whatever",
|
||||
R"EXPECTEDRESULT( <link type="text/css" href="/ROOT%23%3F/skin/error.css?cacheid=c49d1586" rel="Stylesheet" />
|
||||
<img src="/ROOT%23%3F/skin/404.svg?cacheid=b6d648af"
|
||||
)EXPECTEDRESULT"
|
||||
},
|
||||
{
|
||||
// Searching in a ZIM file without a full-text index returns
|
||||
// a page rendered from static/templates/no_search_result_html
|
||||
|
Loading…
x
Reference in New Issue
Block a user