inline css/svg files to avoid the use of external resources
@@ -14,13 +14,6 @@ env = Environment(
|
|||||||
|
|
||||||
default_template = env.get_template("error.html")
|
default_template = env.get_template("error.html")
|
||||||
|
|
||||||
def get_resources_folder() -> str:
|
|
||||||
"""
|
|
||||||
Get resources folder that contains stylesheet and icons for the error page.
|
|
||||||
If you pass resources_use_cdn=True to render(), local resources are not used.
|
|
||||||
"""
|
|
||||||
return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources')
|
|
||||||
|
|
||||||
|
|
||||||
def fill_params(params: dict):
|
def fill_params(params: dict):
|
||||||
if not params.get('time'):
|
if not params.get('time'):
|
||||||
@@ -30,7 +23,7 @@ def fill_params(params: dict):
|
|||||||
params['ray_id'] = secrets.token_hex(8)
|
params['ray_id'] = secrets.token_hex(8)
|
||||||
|
|
||||||
|
|
||||||
def render(params: dict, allow_html: bool=True, use_cdn: bool=True) -> str:
|
def render(params: dict, allow_html: bool=True) -> str:
|
||||||
"""
|
"""
|
||||||
Render a customized Cloudflare error page.
|
Render a customized Cloudflare error page.
|
||||||
"""
|
"""
|
||||||
@@ -40,4 +33,4 @@ def render(params: dict, allow_html: bool=True, use_cdn: bool=True) -> str:
|
|||||||
params['what_happened'] = html.escape(params.get('what_happened', ''))
|
params['what_happened'] = html.escape(params.get('what_happened', ''))
|
||||||
params['what_can_i_do'] = html.escape(params.get('what_can_i_do', ''))
|
params['what_can_i_do'] = html.escape(params.get('what_can_i_do', ''))
|
||||||
|
|
||||||
return default_template.render(params=params, resources_use_cdn=use_cdn)
|
return default_template.render(params=params)
|
||||||
|
|||||||
@@ -299,10 +299,9 @@
|
|||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} UTC`;
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} UTC`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderEjs(params, use_cdn = true) {
|
function renderEjs(params) {
|
||||||
return template({
|
return template({
|
||||||
params: params,
|
params: params,
|
||||||
resources_use_cdn: use_cdn
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,4 +53,4 @@ def index(name: str):
|
|||||||
fill_cf_template_params(params)
|
fill_cf_template_params(params)
|
||||||
|
|
||||||
# Render the error page
|
# Render the error page
|
||||||
return render_cf_error_page(params, use_cdn=True)
|
return render_cf_error_page(params)
|
||||||
|
|||||||
@@ -125,5 +125,4 @@ def get(name: str):
|
|||||||
return template.render(base=cf_template,
|
return template.render(base=cf_template,
|
||||||
params=params,
|
params=params,
|
||||||
url=request.url,
|
url=request.url,
|
||||||
description='Cloudflare error page',
|
description='Cloudflare error page')
|
||||||
resources_use_cdn=True)
|
|
||||||
|
|||||||
@@ -14,22 +14,10 @@ from flask import (
|
|||||||
examples_dir = os.path.dirname(os.path.abspath(__file__))
|
examples_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.append(os.path.dirname(examples_dir))
|
sys.path.append(os.path.dirname(examples_dir))
|
||||||
|
|
||||||
from cloudflare_error_page import get_resources_folder, render as render_cf_error_page
|
from cloudflare_error_page import render as render_cf_error_page
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# Resources required for the error page can be loaded from Cloudflare CDN. But in case of changes, you can set use_cdn = False to use bundled resources.
|
|
||||||
use_cdn = True
|
|
||||||
|
|
||||||
if not use_cdn:
|
|
||||||
res_folder = get_resources_folder()
|
|
||||||
|
|
||||||
# This handler is used to provide stylesheet and icon resources for the error page. If you pass use_cdn=True to render_cf_error_page
|
|
||||||
# or if your site is under proxy of Cloudflare (the cdn-cgi folder is already provided by Cloudflare), this handler can be removed.
|
|
||||||
@app.route('/cdn-cgi/<path:path>')
|
|
||||||
def cdn_cgi(path: str):
|
|
||||||
return send_from_directory(res_folder, path)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
@@ -66,7 +54,7 @@ def index():
|
|||||||
})
|
})
|
||||||
|
|
||||||
# Render the error page
|
# Render the error page
|
||||||
return render_cf_error_page(params, use_cdn=use_cdn), 500
|
return render_cf_error_page(params), 500
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -20,6 +20,5 @@ Homepage = "https://github.com/donlon/cloudflare-error-page"
|
|||||||
[tool.hatch.build]
|
[tool.hatch.build]
|
||||||
include = [
|
include = [
|
||||||
"cloudflare_error_page/*.py",
|
"cloudflare_error_page/*.py",
|
||||||
"cloudflare_error_page/resources/*",
|
|
||||||
"cloudflare_error_page/templates/*",
|
"cloudflare_error_page/templates/*",
|
||||||
]
|
]
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 725 B After Width: | Height: | Size: 725 B |
|
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 675 B |
|
Before Width: | Height: | Size: 519 B After Width: | Height: | Size: 519 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 346 B |
|
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 810 B |
1
resources/styles/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
main.css
|
||||||
123
resources/templates/error.ejs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
|
||||||
|
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
|
||||||
|
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
|
||||||
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
|
||||||
|
<head>
|
||||||
|
<%
|
||||||
|
let error_code = params.error_code || 500;
|
||||||
|
let title = params.title || 'Internal server error';
|
||||||
|
let html_title_output = params.html_title || (error_code + ': ' + title);
|
||||||
|
%>
|
||||||
|
<title><%= html_title_output %></title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||||
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<!-- @INLINE_CSS_HERE@ -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="cf-wrapper">
|
||||||
|
<div id="cf-error-details" class="p-0">
|
||||||
|
<header class="mx-auto pt-10 lg:pt-6 lg:px-8 w-240 lg:w-full mb-8">
|
||||||
|
<h1 class="inline-block sm:block sm:mb-2 font-light text-60 lg:text-4xl text-black-dark leading-tight mr-2">
|
||||||
|
<span class="inline-block"><%= title %></span>
|
||||||
|
<span class="code-label">Error code <%= error_code %></span>
|
||||||
|
</h1>
|
||||||
|
<% let more_info = params.more_information || {}; %>
|
||||||
|
<% if (!more_info.hidden) { %>
|
||||||
|
<div>
|
||||||
|
Visit <a href="<%= more_info.link || 'https://www.cloudflare.com/' %>" target="_blank" rel="noopener noreferrer"><%= more_info.text || 'cloudflare.com' %></a> for <%= more_info.for || "more information" %>.
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<div class="<%= more_info.hidden ? '' : 'mt-3' %>"><%= params.time %></div>
|
||||||
|
</header>
|
||||||
|
<div class="my-8 bg-gradient-gray">
|
||||||
|
<div class="w-240 lg:w-full mx-auto">
|
||||||
|
<div class="clearfix md:px-8">
|
||||||
|
<% for (let item_id of ['browser', 'cloudflare', 'host']) { %>
|
||||||
|
<%
|
||||||
|
let icon, default_location, default_name, text_color, status_text;
|
||||||
|
|
||||||
|
if (item_id === 'browser') {
|
||||||
|
icon = 'browser';
|
||||||
|
default_location = 'You';
|
||||||
|
default_name = 'Browser';
|
||||||
|
} else if (item_id === 'cloudflare') {
|
||||||
|
icon = 'cloud';
|
||||||
|
default_location = 'San Francisco';
|
||||||
|
default_name = 'Cloudflare';
|
||||||
|
} else {
|
||||||
|
icon = 'server';
|
||||||
|
default_location = 'Website';
|
||||||
|
default_name = 'Host';
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = params[item_id + '_status'] || {};
|
||||||
|
let status = item.status || 'ok';
|
||||||
|
|
||||||
|
if (item.status_text_color) {
|
||||||
|
text_color = item.status_text_color;
|
||||||
|
} else if (status === 'ok') {
|
||||||
|
text_color = '#9bca3e'; // text-green-success
|
||||||
|
} else if (status === 'error') {
|
||||||
|
text_color = '#bd2426'; // text-red-error
|
||||||
|
}
|
||||||
|
|
||||||
|
status_text = item.status_text || (status === 'ok' ? 'Working' : 'Error');
|
||||||
|
%>
|
||||||
|
<div id="cf-<%= item_id %>-status" class="<% if (params.error_source === item_id) { %>cf-error-source<% } %> relative w-1/3 md:w-full py-15 md:p-0 md:py-8 md:text-left md:border-solid md:border-0 md:border-b md:border-gray-400 overflow-hidden float-left md:float-none text-center">
|
||||||
|
<div class="relative mb-10 md:m-0">
|
||||||
|
<span class="cf-icon-<%= icon %> block md:hidden h-20 bg-center bg-no-repeat"></span>
|
||||||
|
<span class="cf-icon-<%= status %> w-12 h-12 absolute left-1/2 md:left-auto md:right-0 md:top-0 -ml-6 -bottom-4"></span>
|
||||||
|
</div>
|
||||||
|
<span class="md:block w-full truncate"><%= item.location || default_location %></span>
|
||||||
|
<%
|
||||||
|
let _name_style;
|
||||||
|
if ((item.name || default_name) === 'Cloudflare') {
|
||||||
|
_name_style = 'style="color: #2f7bbf;"'
|
||||||
|
} else{
|
||||||
|
_name_style = ''
|
||||||
|
}
|
||||||
|
%>
|
||||||
|
<h3 class="md:inline-block mt-3 md:mt-0 text-2xl text-gray-600 font-light leading-1.3" <%-_name_style %>><%= item.name || default_name %></h3>
|
||||||
|
<span class="leading-1.3 text-2xl" style="color: <%= text_color %>"><%= status_text %></span>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-240 lg:w-full mx-auto mb-8 lg:px-8">
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="w-1/2 md:w-full float-left pr-6 md:pb-10 md:pr-0 leading-relaxed">
|
||||||
|
<h2 class="text-3xl font-normal leading-1.3 mb-4">What happened?</h2>
|
||||||
|
<%= (params.what_happened || 'There is an internal server error on Cloudflare\'s network.') %>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2 md:w-full float-left leading-relaxed">
|
||||||
|
<h2 class="text-3xl font-normal leading-1.3 mb-4">What can I do?</h2>
|
||||||
|
<%= (params.what_can_i_do || 'Please try again in a few minutes.') %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
|
||||||
|
<p class="text-13">
|
||||||
|
<span class="cf-footer-item sm:block sm:mb-1">Ray ID: <strong class="font-semibold"><%= params.ray_id %></strong></span>
|
||||||
|
<span class="cf-footer-separator sm:hidden">•</span>
|
||||||
|
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
|
||||||
|
Your IP:
|
||||||
|
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
|
||||||
|
<span class="hidden" id="cf-footer-ip"><%= params.client_ip || '1.1.1.1' %></span>
|
||||||
|
<span class="cf-footer-separator sm:hidden">•</span>
|
||||||
|
</span>
|
||||||
|
<% let perf_sec_by = params.perf_sec_by || {}; %>
|
||||||
|
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance & security by</span> <a rel="noopener noreferrer" href="<%= perf_sec_by.link || 'https://www.cloudflare.com/' %>" id="brand_link" target="_blank"><%= perf_sec_by.text || 'Cloudflare' %></a></span>
|
||||||
|
</p>
|
||||||
|
</div><!-- /.error-footer -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
114
resources/templates/error.html
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
|
||||||
|
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
|
||||||
|
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
|
||||||
|
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
|
||||||
|
<head>
|
||||||
|
{% set error_code = params.error_code or 500 %}
|
||||||
|
{% set title = params.title or 'Internal server error' %}
|
||||||
|
{% set html_title = params.html_title or ((error_code | string) + ': ' + title) %}
|
||||||
|
<title>{{ html_title }}</title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||||
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
{% block header %}{% endblock %}
|
||||||
|
<!-- @INLINE_CSS_HERE@ -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="cf-wrapper">
|
||||||
|
<div id="cf-error-details" class="p-0">
|
||||||
|
<header class="mx-auto pt-10 lg:pt-6 lg:px-8 w-240 lg:w-full mb-8">
|
||||||
|
<h1 class="inline-block sm:block sm:mb-2 font-light text-60 lg:text-4xl text-black-dark leading-tight mr-2">
|
||||||
|
<span class="inline-block">{{ title }}</span>
|
||||||
|
<span class="code-label">Error code {{ error_code }}</span>
|
||||||
|
</h1>
|
||||||
|
{% set more_info = params.more_information or {} %}
|
||||||
|
{% if not more_info.hidden or false %}{# default: shown #}
|
||||||
|
<div>
|
||||||
|
Visit <a href="{{more_info.link or 'https://www.cloudflare.com/'}}" target="_blank" rel="noopener noreferrer">{{more_info.text or 'cloudflare.com'}}</a> for {{more_info.for or 'more information'}}.
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="mt-3">{{ params.time }}</div>
|
||||||
|
</header>
|
||||||
|
<div class="my-8 bg-gradient-gray">
|
||||||
|
<div class="w-240 lg:w-full mx-auto">
|
||||||
|
<div class="clearfix md:px-8">
|
||||||
|
{% for item_id in ['browser', 'cloudflare', 'host'] %}
|
||||||
|
{% if item_id == 'browser' %}
|
||||||
|
{% set icon = 'browser' %}
|
||||||
|
{% set default_location = 'You' %}
|
||||||
|
{% set default_name = 'Browser' %}
|
||||||
|
{% elif item_id == 'cloudflare' %}
|
||||||
|
{% set icon = 'cloud' %}
|
||||||
|
{% set default_location = 'San Francisco' %}
|
||||||
|
{% set default_name = 'Cloudflare' %}
|
||||||
|
{% else %}
|
||||||
|
{% set icon = 'server' %}
|
||||||
|
{% set default_location = 'Website' %}
|
||||||
|
{% set default_name = 'Host' %}
|
||||||
|
{% endif %}
|
||||||
|
{% set item = params.get(item_id + '_status', {}) %}
|
||||||
|
{% set status = item.status or 'ok' %}
|
||||||
|
{% if item.status_text_color %}
|
||||||
|
{% set text_color = item.status_text_color %}
|
||||||
|
{% elif status == 'ok' %}
|
||||||
|
{% set text_color = '#9bca3e' %}{# text-green-success #}
|
||||||
|
{% elif status == 'error' %}
|
||||||
|
{% set text_color = '#bd2426' %}{# text-red-error #}
|
||||||
|
{% endif %}
|
||||||
|
{% set status_text = item.status_text or ('Working' if status == 'ok' else 'Error') %}
|
||||||
|
<div id="cf-{{item_id}}-status" class="{{'cf-error-source' if params.error_source == item_id else ''}} relative w-1/3 md:w-full py-15 md:p-0 md:py-8 md:text-left md:border-solid md:border-0 md:border-b md:border-gray-400 overflow-hidden float-left md:float-none text-center">
|
||||||
|
<div class="relative mb-10 md:m-0">
|
||||||
|
<span class="cf-icon-{{icon}} block md:hidden h-20 bg-center bg-no-repeat"></span>
|
||||||
|
<span class="cf-icon-{{status}} w-12 h-12 absolute left-1/2 md:left-auto md:right-0 md:top-0 -ml-6 -bottom-4"></span>
|
||||||
|
</div>
|
||||||
|
<span class="md:block w-full truncate">{{item.location or default_location}}</span>
|
||||||
|
{% set _name_style = 'style="color: #2f7bbf;"' if ((item.name or default_name) == 'Cloudflare') else '' %}
|
||||||
|
<h3 class="md:inline-block mt-3 md:mt-0 text-2xl text-gray-600 font-light leading-1.3" {{_name_style | safe}}>{{item.name or default_name}}</h3>
|
||||||
|
<span class="leading-1.3 text-2xl" style="color: {{text_color}}">{{status_text}}</span>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-240 lg:w-full mx-auto mb-8 lg:px-8">
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="w-1/2 md:w-full float-left pr-6 md:pb-10 md:pr-0 leading-relaxed">
|
||||||
|
<h2 class="text-3xl font-normal leading-1.3 mb-4">What happened?</h2>
|
||||||
|
{{ (params.what_happened or '<p>There is an internal server error on Cloudflare\'s network.</p>') | safe }}
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2 md:w-full float-left leading-relaxed">
|
||||||
|
<h2 class="text-3xl font-normal leading-1.3 mb-4">What can I do?</h2>
|
||||||
|
{{ (params.what_can_i_do or '<p>Please try again in a few minutes.</p>') | safe }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
|
||||||
|
<p class="text-13">
|
||||||
|
<span class="cf-footer-item sm:block sm:mb-1">Ray ID: <strong class="font-semibold">{{ params.ray_id }}</strong></span>
|
||||||
|
<span class="cf-footer-separator sm:hidden">•</span>
|
||||||
|
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
|
||||||
|
Your IP:
|
||||||
|
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
|
||||||
|
<span class="hidden" id="cf-footer-ip">{{ params.client_ip or '1.1.1.1' }}</span>
|
||||||
|
<span class="cf-footer-separator sm:hidden">•</span>
|
||||||
|
</span>
|
||||||
|
{% set perf_sec_by = params.perf_sec_by or {} %}
|
||||||
|
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance & security by</span> <a rel="noopener noreferrer" href="{{perf_sec_by.link or 'https://www.cloudflare.com/'}}" id="brand_link" target="_blank">{{perf_sec_by.text or 'Cloudflare'}}</a></span>
|
||||||
|
|
||||||
|
{% set creator_info = params.creator_info or {} %}
|
||||||
|
{% if not creator_info.get('hidden', True) %}{# default: hidden #}
|
||||||
|
<span class="cf-footer-separator sm:hidden">•</span>
|
||||||
|
<span class="cf-footer-item sm:block sm:mb-1">Created with <a href="{{creator_info.link}}" target="_blank">{{creator_info.text}}</a></span>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div><!-- /.error-footer -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
73
scripts/inline_resources.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
|
||||||
|
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
resources_folder = os.path.join(root,'resources')
|
||||||
|
|
||||||
|
|
||||||
|
def read_file(path: str) -> str:
|
||||||
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def write_file(path: str, data: str):
|
||||||
|
with open(path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_svg_to_data_uri(data: str) -> str:
|
||||||
|
data = data.replace('<?xml version="1.0" encoding="UTF-8"?>', '')
|
||||||
|
data = re.sub(r'\n\s*', '', data, flags=re.DOTALL)
|
||||||
|
uri = 'data:image/svg+xml;utf8,'
|
||||||
|
uri += quote(data)
|
||||||
|
return uri
|
||||||
|
|
||||||
|
|
||||||
|
def inline_svg_resources(css_file: str, svg_files: list[str], output_file: str):
|
||||||
|
css_data = read_file(css_file)
|
||||||
|
for svg_file in svg_files:
|
||||||
|
svg_data = read_file(os.path.join(os.path.dirname(css_file), svg_file))
|
||||||
|
svg_uri = convert_svg_to_data_uri(svg_data)
|
||||||
|
css_data = css_data.replace(svg_file, svg_uri)
|
||||||
|
print(f'inline_svg_resources writing to {output_file}')
|
||||||
|
write_file(output_file, css_data)
|
||||||
|
|
||||||
|
|
||||||
|
def inline_css_resource(original_file: str, css_file: str, output_file: str):
|
||||||
|
css_data = read_file(css_file)
|
||||||
|
original_data = read_file(original_file)
|
||||||
|
original_data = original_data.replace('<!-- @INLINE_CSS_HERE@ -->',
|
||||||
|
f'<style>{css_data}</style>')
|
||||||
|
note = 'Note: This is generated with scripts/inline_resources.py. Please do not edit this file manually.'
|
||||||
|
if original_file.endswith('.ejs'):
|
||||||
|
original_data = f'<%# {note} %>\n' + original_data
|
||||||
|
else:
|
||||||
|
original_data = f'{{# {note} #}}\n' + original_data
|
||||||
|
print(f'inline_css_resource writing to {output_file}')
|
||||||
|
write_file(output_file, original_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
inline_svg_resources(
|
||||||
|
os.path.join(resources_folder, 'styles/main-original.css'),
|
||||||
|
[
|
||||||
|
'../images/cf-icon-browser.svg',
|
||||||
|
'../images/cf-icon-cloud.svg',
|
||||||
|
'../images/cf-icon-server.svg',
|
||||||
|
'../images/cf-icon-ok.svg',
|
||||||
|
'../images/cf-icon-error.svg',
|
||||||
|
],
|
||||||
|
os.path.join(resources_folder, 'styles/main.css'),
|
||||||
|
)
|
||||||
|
inline_css_resource(
|
||||||
|
os.path.join(resources_folder, 'templates/error.html'),
|
||||||
|
os.path.join(resources_folder, 'styles/main.css'),
|
||||||
|
os.path.join(root, 'cloudflare_error_page/templates/error.html'),
|
||||||
|
)
|
||||||
|
inline_css_resource(
|
||||||
|
os.path.join(resources_folder, 'templates/error.ejs'),
|
||||||
|
os.path.join(resources_folder, 'styles/main.css'),
|
||||||
|
os.path.join(root, 'editor/resources/template.ejs'),
|
||||||
|
)
|
||||||