update to fisrt version
This commit is contained in:
@@ -27,7 +27,9 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flask",
|
"flask",
|
||||||
"gunicorn"
|
"gunicorn",
|
||||||
|
"python-dotenv",
|
||||||
|
"anki-hsk-creator",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
@@ -35,7 +37,8 @@ dev = [
|
|||||||
"pytest",
|
"pytest",
|
||||||
"black",
|
"black",
|
||||||
"pylint",
|
"pylint",
|
||||||
"flakehell"
|
"flake8",
|
||||||
|
"flake8-pyproject",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
@@ -53,6 +56,7 @@ extra-dependencies = [
|
|||||||
|
|
||||||
[tool.hatch.envs.default.scripts]
|
[tool.hatch.envs.default.scripts]
|
||||||
format = "black --target-version=py314 src tests && isort src tests"
|
format = "black --target-version=py314 src tests && isort src tests"
|
||||||
|
lint = "flake8 src"
|
||||||
|
|
||||||
[tool.hatch.envs.types]
|
[tool.hatch.envs.types]
|
||||||
extra-dependencies = [
|
extra-dependencies = [
|
||||||
@@ -128,7 +132,7 @@ msg-template="{path}:{module}:{line}: [{msg_id}({symbol}), {obj}] {msg}"
|
|||||||
logging-format-style="new"
|
logging-format-style="new"
|
||||||
logging-modules="logging"
|
logging-modules="logging"
|
||||||
|
|
||||||
[tool.flakehell]
|
[tool.flake8]
|
||||||
max_line_length = 88
|
max_line_length = 88
|
||||||
format = "grouped"
|
format = "grouped"
|
||||||
show_source = false
|
show_source = false
|
||||||
@@ -143,7 +147,7 @@ exclude = [
|
|||||||
"*.egg-info",
|
"*.egg-info",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.flakehell.plugins]
|
[tool.flake8.plugins]
|
||||||
mccabe = ["+C*"]
|
mccabe = ["+C*"]
|
||||||
pycodestyle = ["+E*", "+W*", "-E203", "-E501", "-W503"]
|
pycodestyle = ["+E*", "+W*", "-E203", "-E501", "-W503"]
|
||||||
pyflakes = ["+F*"]
|
pyflakes = ["+F*"]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2026-present Wolfang Torres <wolfang.torres@gmail.com>
|
# SPDX-FileCopyrightText: 2026-present Wolfang Torres <wolfang.torres@gmail.com>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
__version__ = "0.0.1"
|
__version__ = "1.0.0"
|
||||||
|
|||||||
@@ -2,17 +2,21 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Pip
|
# Pip
|
||||||
|
from dotenv import load_dotenv
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
# Local
|
# Local
|
||||||
from .homescreen import homescreen
|
from .homescreen import homescreen
|
||||||
from .mainapp import mainapp
|
from .mainapp import mainapp
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
def create_app(*args):
|
|
||||||
|
def create_app():
|
||||||
|
"""Creates the Flask App"""
|
||||||
# create and configure the app
|
# create and configure the app
|
||||||
app = Flask(__name__, instance_relative_config=True)
|
app = Flask(__name__, instance_relative_config=True)
|
||||||
app.config["APPLICATION_ROOT"] = "/hsk"
|
app.config["APPLICATION_ROOT"] = "/hskankicreator"
|
||||||
|
|
||||||
# ensure the instance folder exists
|
# ensure the instance folder exists
|
||||||
instance_path = Path(app.instance_path)
|
instance_path = Path(app.instance_path)
|
||||||
|
|||||||
@@ -6,18 +6,20 @@ homescreen = Blueprint(
|
|||||||
"homescreen",
|
"homescreen",
|
||||||
__name__,
|
__name__,
|
||||||
template_folder="templates",
|
template_folder="templates",
|
||||||
url_prefix="/hsk",
|
url_prefix="/hskankicreator",
|
||||||
static_folder="static",
|
static_folder="static",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@homescreen.route("/")
|
@homescreen.route("/")
|
||||||
def index():
|
def index():
|
||||||
return render_template(f"index.html")
|
"""main page"""
|
||||||
|
return render_template("index.html")
|
||||||
|
|
||||||
|
|
||||||
@homescreen.route("/favicon.ico")
|
@homescreen.route("/favicon.ico")
|
||||||
def favicon():
|
def favicon():
|
||||||
|
"""favicon"""
|
||||||
return send_from_directory(
|
return send_from_directory(
|
||||||
current_app.static_folder, "favicon.ico", mimetype="image/vnd.microsoft.icon"
|
current_app.static_folder, "favicon.ico", mimetype="image/vnd.microsoft.icon"
|
||||||
)
|
)
|
||||||
@@ -26,7 +28,7 @@ def favicon():
|
|||||||
@homescreen.route("/", defaults={"page": "index"})
|
@homescreen.route("/", defaults={"page": "index"})
|
||||||
@homescreen.route("/<page>")
|
@homescreen.route("/<page>")
|
||||||
def show(page):
|
def show(page):
|
||||||
print(page)
|
"""general entry for other pages"""
|
||||||
try:
|
try:
|
||||||
return render_template(f"{page}.html")
|
return render_template(f"{page}.html")
|
||||||
except TemplateNotFound:
|
except TemplateNotFound:
|
||||||
|
|||||||
@@ -1,28 +1,168 @@
|
|||||||
|
# Standard Library
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
# Pip
|
# Pip
|
||||||
from flask import Blueprint, render_template, request
|
from anki_hsk_creator import api
|
||||||
|
from anki_hsk_creator.constants import DICT_TYPE, PHRASES_TYPE
|
||||||
|
from anki_hsk_creator.utility import ProcessFile
|
||||||
|
from flask import (
|
||||||
|
Blueprint,
|
||||||
|
make_response,
|
||||||
|
redirect,
|
||||||
|
render_template,
|
||||||
|
request,
|
||||||
|
send_from_directory,
|
||||||
|
url_for,
|
||||||
|
)
|
||||||
|
|
||||||
mainapp = Blueprint(
|
mainapp = Blueprint(
|
||||||
"mainapp",
|
"mainapp",
|
||||||
__name__,
|
__name__,
|
||||||
template_folder="templates",
|
template_folder="templates",
|
||||||
url_prefix="/hsk/app",
|
url_prefix="/hskankicreator/app",
|
||||||
static_folder="static",
|
static_folder="static",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@mainapp.route("/", methods=["GET", "POST"])
|
@mainapp.route("/", methods=["GET"])
|
||||||
def show():
|
def app():
|
||||||
|
"""Main app entry pages"""
|
||||||
|
return render_template("app.html")
|
||||||
|
|
||||||
|
|
||||||
|
@mainapp.route("/list", methods=["GET"])
|
||||||
|
@mainapp.route("/list/", methods=["GET"])
|
||||||
|
@mainapp.route("/list/<path:listing_path>", methods=["GET"])
|
||||||
|
def file_list(listing_path=""):
|
||||||
|
"""Path for file lister"""
|
||||||
|
listing_path = Path(listing_path)
|
||||||
|
root_files = {file: [] for file in api.list_input_files()}
|
||||||
|
level = root_files
|
||||||
|
level_path = Path()
|
||||||
|
for part in listing_path.parts:
|
||||||
|
level_path = level_path / part
|
||||||
|
level[level_path] = {file: [] for file in api.list_input_files(level_path)}
|
||||||
|
level = level[level_path]
|
||||||
|
|
||||||
|
if listing_path:
|
||||||
|
file_data = api.analize_input_files(listing_path)
|
||||||
|
else:
|
||||||
|
file_data = api.analize_input_files(None)
|
||||||
|
return render_template(
|
||||||
|
"file_list.html",
|
||||||
|
file_data=file_data,
|
||||||
|
root_files=root_files,
|
||||||
|
listing_path=listing_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mainapp.route("/download/<path:listing_path>", methods=["GET"])
|
||||||
|
def download(listing_path):
|
||||||
|
"""Download a file from DATA_FOLDER / DOWNLOAD"""
|
||||||
|
download_path = api.get_output_folder() / listing_path
|
||||||
|
return send_from_directory(download_path.parent, download_path.name)
|
||||||
|
|
||||||
|
|
||||||
|
@mainapp.route("/resource/<path:listing_path>", methods=["GET"])
|
||||||
|
def resource(listing_path):
|
||||||
|
"""Gets a file from DATA_FOLDER / RESOURCES"""
|
||||||
|
download_path = api.get_resources_folder() / listing_path
|
||||||
|
return send_from_directory(download_path.parent, download_path.name)
|
||||||
|
|
||||||
|
|
||||||
|
@mainapp.route("/create", methods=["GET", "POST"])
|
||||||
|
@mainapp.route("/create/", methods=["GET", "POST"])
|
||||||
|
@mainapp.route("/create/<path:listing_path>", methods=["GET", "POST"])
|
||||||
|
def create(listing_path=""):
|
||||||
|
"""Main text editor"""
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
|
if api.is_file(listing_path):
|
||||||
|
text = api.read_input_file(listing_path)
|
||||||
|
else:
|
||||||
|
text = ""
|
||||||
args = request.args.to_dict()
|
args = request.args.to_dict()
|
||||||
deck_type = args.get("deck_type", "")
|
deck_type = args.get("deck_type", "")
|
||||||
language = args.get("language", "")
|
language_id = args.get("language_id", "")
|
||||||
output_type = args.get("output_type", "")
|
if not deck_type and not language_id:
|
||||||
if not deck_type or not language or not output_type:
|
|
||||||
state = "new"
|
state = "new"
|
||||||
|
elif not deck_type or not language_id:
|
||||||
|
state = "partial"
|
||||||
else:
|
else:
|
||||||
state = "complete"
|
state = "complete"
|
||||||
elif request.method == "POST":
|
# output_type = args.get("output_type", "")
|
||||||
state = "ready"
|
# if not deck_type or not language_id or not output_type:
|
||||||
|
return render_template(
|
||||||
|
"create.html",
|
||||||
|
data={
|
||||||
|
"text": text,
|
||||||
|
"deck_type": deck_type,
|
||||||
|
"language_id": language_id,
|
||||||
|
"state": state,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
listing_path = Path(listing_path)
|
||||||
form = request.form.to_dict()
|
form = request.form.to_dict()
|
||||||
|
args = request.args.to_dict()
|
||||||
|
process_file = api.create_input_file(
|
||||||
|
listing_path.name.split(".")[0],
|
||||||
|
"." + args["deck_type"],
|
||||||
|
form["text"],
|
||||||
|
listing_path.parent,
|
||||||
|
)
|
||||||
|
if args["deck_type"] in DICT_TYPE:
|
||||||
|
api.pre_process_a_dictionary_file(process_file, args["language_id"])
|
||||||
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"mainapp.process",
|
||||||
|
listing_path=process_file.relative_dictionary_resource_file,
|
||||||
|
language_id=args["language_id"],
|
||||||
|
),
|
||||||
|
code=303,
|
||||||
|
)
|
||||||
|
elif args["deck_type"] in PHRASES_TYPE:
|
||||||
|
final_file = api.process_a_phrases_file(process_file, args["language_id"])
|
||||||
|
response = make_response(
|
||||||
|
send_from_directory(final_file.parent, final_file.name)
|
||||||
|
)
|
||||||
|
response.set_cookie("download_started", "true", max_age=10)
|
||||||
|
return response
|
||||||
|
|
||||||
return render_template(f"app.html", data=locals())
|
|
||||||
|
@mainapp.route("/process/<path:listing_path>", methods=["GET", "POST"])
|
||||||
|
def process(listing_path):
|
||||||
|
"""Post process tsv file"""
|
||||||
|
listing_path = Path(listing_path)
|
||||||
|
input_file = listing_path.parent
|
||||||
|
input_file = input_file.parent / f"{input_file.name}.txt"
|
||||||
|
process_file = ProcessFile(input_file)
|
||||||
|
languages = process_file.available_dictionary_languages
|
||||||
|
args = request.args.to_dict()
|
||||||
|
language_id = args.get("language_id", listing_path.stem.split(".")[1])
|
||||||
|
if request.method == "GET":
|
||||||
|
if not language_id:
|
||||||
|
state = "new"
|
||||||
|
text = ""
|
||||||
|
else:
|
||||||
|
state = "complete"
|
||||||
|
text = api.read_dictionary_file(process_file, language_id)
|
||||||
|
output_type = args.get("output_type", "")
|
||||||
|
return render_template(
|
||||||
|
"process.html",
|
||||||
|
languages=languages,
|
||||||
|
data={
|
||||||
|
"output_type": output_type,
|
||||||
|
"language_id": language_id,
|
||||||
|
"state": state,
|
||||||
|
"text": text,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif request.method == "POST":
|
||||||
|
form = request.form.to_dict()
|
||||||
|
api.write_resource_file(process_file, language_id, form["text"])
|
||||||
|
final_file = api.process_a_dictionary_file(process_file, language_id)
|
||||||
|
response = make_response(
|
||||||
|
send_from_directory(final_file.parent, final_file.name)
|
||||||
|
)
|
||||||
|
response.set_cookie("download_started", "true", max_age=10)
|
||||||
|
return response
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
/>
|
/>
|
||||||
<meta name="description" content="" />
|
<meta name="description" content="" />
|
||||||
<meta name="keywords" content="" />
|
<meta name="keywords" content="" />
|
||||||
<link rel="stylesheet" href="static/assets/css/main.css" />
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='assets/css/main.css') }}"
|
||||||
|
/>
|
||||||
<link
|
<link
|
||||||
rel="shortcut icon"
|
rel="shortcut icon"
|
||||||
href="{{ url_for('static', filename='favicon.ico') }}"
|
href="{{ url_for('static', filename='favicon.ico') }}"
|
||||||
@@ -23,108 +26,31 @@
|
|||||||
<!-- Section -->
|
<!-- Section -->
|
||||||
<section id="first" style="padding-top: 3em">
|
<section id="first" style="padding-top: 3em">
|
||||||
<header>
|
<header>
|
||||||
<h2>Select the deck type</h2>
|
<h2>HSK Anki Creator</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="text_area" class="content">
|
<div id="text_area" class="content"></div>
|
||||||
<p>
|
|
||||||
<strong>Paste here the word list</strong>
|
|
||||||
</p>
|
|
||||||
<form id="taxt_form" method="POST">
|
|
||||||
<div class="fields">
|
|
||||||
<div class="field">
|
|
||||||
<textarea name="text" id="text" rows="15"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ul class="actions">
|
|
||||||
<li>
|
|
||||||
<input
|
|
||||||
id="process"
|
|
||||||
type="submit"
|
|
||||||
value="Process"
|
|
||||||
class="button primary"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<form id="settings_form" method="GET">
|
|
||||||
<ul class="items">
|
<ul class="items">
|
||||||
<li>
|
<li>
|
||||||
<h3>Deck Type</h3>
|
<h3>Actions:</h3>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<a
|
||||||
type="radio"
|
href="{{ url_for('mainapp.file_list') }}"
|
||||||
id="type1"
|
class="button primary large"
|
||||||
name="deck_type"
|
>List Files</a
|
||||||
value="dictionary"
|
>
|
||||||
checked
|
|
||||||
/>
|
|
||||||
<label for="type1">Dictionary Deck</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<a
|
||||||
type="radio"
|
href="{{ url_for('mainapp.create') }}"
|
||||||
id="type2"
|
class="button primary large"
|
||||||
name="deck_type"
|
>Create File</a
|
||||||
value="phrases"
|
>
|
||||||
/>
|
|
||||||
<label for="type2">Phrases List</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="type3"
|
|
||||||
name="deck_type"
|
|
||||||
value="paragraph"
|
|
||||||
/>
|
|
||||||
<label for="type3">Paragraph Dictation</label>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h3>Language</h3>
|
|
||||||
<select id="language" name="language">
|
|
||||||
<option value="en">English</option>
|
|
||||||
<option value="es">Spanish</option>
|
|
||||||
<option value="ru">Russian</option>
|
|
||||||
<option value="fr">French</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h3>Output</h3>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="out1"
|
|
||||||
name="output_type"
|
|
||||||
value="anki"
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
<label for="out1">Anki Deck</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="out2"
|
|
||||||
name="output_type"
|
|
||||||
value="quiz"
|
|
||||||
/>
|
|
||||||
<label for="out2">Quizlet deck</label>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<input
|
|
||||||
id="settings_button"
|
|
||||||
type="submit"
|
|
||||||
value="Lock-in Settings"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<a href=".">Reset Settings</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -136,63 +62,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="static/assets/js/jquery.min.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/jquery.min.js') }}/"></script>
|
||||||
<script src="static/assets/js/jquery.scrolly.min.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/jquery.scrolly.min.js') }}/"></script>
|
||||||
<script src="static/assets/js/browser.min.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/browser.min.js') }}/"></script>
|
||||||
<script src="static/assets/js/breakpoints.min.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/breakpoints.min.js') }}/"></script>
|
||||||
<script src="static/assets/js/util.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/util.js') }}/"></script>
|
||||||
<script src="static/assets/js/main.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/main.js') }}/"></script>
|
||||||
<script src="static/assets/js/app.js"></script>
|
<script src="{{ url_for('static', filename='assets/js/app.js') }}/"></script>
|
||||||
<script>
|
<script></script>
|
||||||
const serverData = {{ data | tojson }};
|
|
||||||
if (serverData.state === "new") {
|
|
||||||
$("#text_area").hide();
|
|
||||||
$("#text").prop('disabled', true);
|
|
||||||
$("#process").prop('disabled', true);
|
|
||||||
}
|
|
||||||
if (serverData.state === "complete") {
|
|
||||||
// Set values to inputs
|
|
||||||
if (serverData.deck_type === "dictionary") {
|
|
||||||
$('#type1').prop('checked', true);
|
|
||||||
}
|
|
||||||
if (serverData.deck_type === "phrases") {
|
|
||||||
$('#type2').prop('checked', true);
|
|
||||||
}
|
|
||||||
if (serverData.deck_type === "paragraph") {
|
|
||||||
$('#type3').prop('checked', true);
|
|
||||||
}
|
|
||||||
$('#language').val(serverData.language);
|
|
||||||
if (serverData.output_type === "anki") {
|
|
||||||
$('#out1').prop('checked', true);
|
|
||||||
}
|
|
||||||
if (serverData.output_type === "quiz") {
|
|
||||||
$('#out2').prop('checked', true);
|
|
||||||
}
|
|
||||||
// Disable inputs
|
|
||||||
$('#type1').prop('disabled', true);
|
|
||||||
$('#type2').prop('disabled', true);
|
|
||||||
$('#type3').prop('disabled', true);
|
|
||||||
$('#language').prop('disabled', true);
|
|
||||||
$('#out1').prop('disabled', true);
|
|
||||||
$('#out2').prop('disabled', true);
|
|
||||||
$("#settings_button").prop('disabled', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#taxt_form').addEventListener('submit', function(e) {
|
|
||||||
// Get current URL query parameters
|
|
||||||
const currentParams = new URLSearchParams(window.location.search);
|
|
||||||
// Loop through current parameters and append them to the form
|
|
||||||
currentParams.forEach((value, key) => {
|
|
||||||
// Check if the input already exists to prevent duplicates
|
|
||||||
if (!this.querySelector(`input[name="${key}"]`)) {
|
|
||||||
const hiddenInput = document.createElement('input');
|
|
||||||
hiddenInput.type = 'hidden';
|
|
||||||
hiddenInput.name = key;
|
|
||||||
hiddenInput.value = value;
|
|
||||||
this.appendChild(hiddenInput);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
241
src/anki_creator_flask/templates/create.html
Normal file
241
src/anki_creator_flask/templates/create.html
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>HSK card creator</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, user-scalable=no"
|
||||||
|
/>
|
||||||
|
<meta name="description" content="" />
|
||||||
|
<meta name="keywords" content="" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='assets/css/main.css') }}"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="shortcut icon"
|
||||||
|
href="{{ url_for('static', filename='favicon.ico') }}"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
#loader-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #1a1a1a; /* Dark background */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 9999; /* Ensures it stays on top of everything */
|
||||||
|
transition:
|
||||||
|
opacity 0.5s ease,
|
||||||
|
visibility 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The spinning visual indicator */
|
||||||
|
.loader {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: 5px solid #333;
|
||||||
|
border-top: 5px solid #3498db; /* Blue accent color */
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Descriptive status text */
|
||||||
|
.loader-text {
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
margin-top: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyframe for rotation animation */
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smooth fade-out state triggered by JS */
|
||||||
|
.loader-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="is-preload">
|
||||||
|
<!-- Full-screen preloader container -->
|
||||||
|
<div id="loader-wrapper">
|
||||||
|
<div class="loader"></div>
|
||||||
|
<p class="loader-text">Loading, please wait...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wrapper -->
|
||||||
|
<div id="wrapper">
|
||||||
|
<!-- Section -->
|
||||||
|
<section id="first" style="padding-top: 3em">
|
||||||
|
<header>
|
||||||
|
<h2>Select the deck type</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div id="text_area" class="content">
|
||||||
|
<p>
|
||||||
|
<strong>Paste here the word list</strong>
|
||||||
|
</p>
|
||||||
|
<form id="text_form" method="POST">
|
||||||
|
<div class="fields">
|
||||||
|
<div class="field">
|
||||||
|
<textarea name="text" id="text" rows="15"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul class="actions">
|
||||||
|
<li>
|
||||||
|
<input
|
||||||
|
id="process_button"
|
||||||
|
type="submit"
|
||||||
|
value="Process"
|
||||||
|
class="button primary"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<form id="settings_form" method="GET">
|
||||||
|
<ul class="items">
|
||||||
|
<li>
|
||||||
|
<h3>Deck Type</h3>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="type1"
|
||||||
|
name="deck_type"
|
||||||
|
value="dictionary"
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
<label for="type1">Dictionary Deck</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="type2"
|
||||||
|
name="deck_type"
|
||||||
|
value="phrases"
|
||||||
|
/>
|
||||||
|
<label for="type2">Phrases List</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="type3"
|
||||||
|
name="deck_type"
|
||||||
|
value="paragraph"
|
||||||
|
/>
|
||||||
|
<label for="type3">Paragraph Dictation</label>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h3>Language</h3>
|
||||||
|
<select id="language_id" name="language_id">
|
||||||
|
<option value="en">English</option>
|
||||||
|
<option value="es">Spanish</option>
|
||||||
|
<option value="ru">Russian</option>
|
||||||
|
<option value="fr">French</option>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input
|
||||||
|
id="settings_button"
|
||||||
|
type="submit"
|
||||||
|
value="Lock-in Settings"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<a href="{{ url_for('mainapp.create') }}">Reset Settings</a>
|
||||||
|
<br />
|
||||||
|
<a href="{{ url_for('mainapp.app') }}">Back</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Copyright -->
|
||||||
|
<div class="copyright">
|
||||||
|
© HSK creator. Wolfang Torres. All rights reserved 2026. Design:
|
||||||
|
<a href="https://html5up.net">HTML5 UP</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/jquery.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/jquery.scrolly.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/browser.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/breakpoints.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/util.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/main.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/app.js') }}/"></script>
|
||||||
|
<script>
|
||||||
|
const serverData = {{ data | tojson }};
|
||||||
|
if (serverData.state === "new") {
|
||||||
|
$("#process_button").prop('disabled', true);
|
||||||
|
$('#text').val(serverData.text);
|
||||||
|
}
|
||||||
|
if (serverData.state === "partial" || serverData.state === "complete" ) {
|
||||||
|
$("#process_button").prop('disabled', true);
|
||||||
|
// Set values to inputs
|
||||||
|
if (serverData.deck_type !== "" ) {
|
||||||
|
if (serverData.deck_type === "dictionary") {
|
||||||
|
$('#type1').prop('checked', true);
|
||||||
|
}
|
||||||
|
if (serverData.deck_type === "phrases") {
|
||||||
|
$('#type2').prop('checked', true);
|
||||||
|
}
|
||||||
|
if (serverData.deck_type === "paragraph") {
|
||||||
|
$('#type3').prop('checked', true);
|
||||||
|
}
|
||||||
|
$('#type1').prop('readonly', true);
|
||||||
|
$('#type2').prop('readonly', true);
|
||||||
|
$('#type3').prop('readonly', true);
|
||||||
|
}
|
||||||
|
if (serverData.language_id !== "" ) {
|
||||||
|
$('#language_id').val(serverData.language_id);
|
||||||
|
$('#language_id').prop('readonly', true);
|
||||||
|
}
|
||||||
|
$('#text').val(serverData.text);
|
||||||
|
}
|
||||||
|
if (serverData.state === "complete") {
|
||||||
|
$("#process_button").prop('disabled', false);
|
||||||
|
$("#settings_button").prop('disabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#text_form').on('submit', function(e) {
|
||||||
|
// Add the class that triggers the CSS fade transition
|
||||||
|
$("#loader-wrapper").removeClass("loader-hidden");
|
||||||
|
document.cookie = 'download_started=; Max-Age=0; path=/';
|
||||||
|
const checkDownload = setInterval(() => {
|
||||||
|
if (document.cookie.includes('download_started=true')) {
|
||||||
|
clearInterval(checkDownload);
|
||||||
|
console.log('File successfully downloaded!');
|
||||||
|
$("#loader-wrapper").addClass("loader-hidden");
|
||||||
|
this.disabled = false;
|
||||||
|
document.cookie = 'download_started=; Max-Age=0; path=/';
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
$(window).on("load", function() {
|
||||||
|
$("#loader-wrapper").addClass("loader-hidden");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
256
src/anki_creator_flask/templates/file_list.html
Normal file
256
src/anki_creator_flask/templates/file_list.html
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>HSK card creator</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, user-scalable=no"
|
||||||
|
/>
|
||||||
|
<meta name="description" content="" />
|
||||||
|
<meta name="keywords" content="" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='assets/css/main.css') }}"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="shortcut icon"
|
||||||
|
href="{{ url_for('static', filename='favicon.ico') }}"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
/* Base tree styling */
|
||||||
|
.tree {
|
||||||
|
--spacing: 1.5rem;
|
||||||
|
--radius: 4px;
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree ul {
|
||||||
|
margin-left: calc(var(--spacing) / -2);
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree li {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding-left: calc(var(--spacing) * 1.5);
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical connecting lines */
|
||||||
|
.tree ul li::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: calc(var(--spacing) / 2);
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border-left: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide the vertical line after the last item
|
||||||
|
.tree ul li:last-child::before {
|
||||||
|
display: none;
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* Horizontal branch lines */
|
||||||
|
.tree ul li::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: calc(var(--spacing) / 2);
|
||||||
|
top: calc(var(--spacing) / 2);
|
||||||
|
width: calc(var(--spacing) * 0.8);
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Folder Summary Customization */
|
||||||
|
.tree summary {
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom toggle markers using pseudo-elements */
|
||||||
|
.tree details[closed] > summary::before {
|
||||||
|
content: "📁 ";
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree details[open] > summary::before {
|
||||||
|
content: "📂 ";
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File items customization */
|
||||||
|
.tree .file::before {
|
||||||
|
content: "📄 ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree .file {
|
||||||
|
font-weight: normal;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="is-preload">
|
||||||
|
<!-- Wrapper -->
|
||||||
|
<div id="wrapper">
|
||||||
|
<!-- Section -->
|
||||||
|
<section id="first">
|
||||||
|
<!-- File broser -->
|
||||||
|
<header>
|
||||||
|
<h2>Files</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<h3>Current Path: {{ listing_path or "-" }}</h3>
|
||||||
|
<ul class="items">
|
||||||
|
<li>
|
||||||
|
<strong>Input files:</strong>
|
||||||
|
<ul>
|
||||||
|
{% for file in file_data['input'] %}
|
||||||
|
<li>
|
||||||
|
{% if file.suffixes %}
|
||||||
|
<a
|
||||||
|
href="{{ url_for('mainapp.create', listing_path=file , deck_type=file.suffixes[0][1:]) }}"
|
||||||
|
>
|
||||||
|
{{ file.name }}
|
||||||
|
</a>
|
||||||
|
{% else %} {{ file.name }} {% endif %}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Resources files:</strong>
|
||||||
|
<ul>
|
||||||
|
{% for file in file_data['resources'] %} {% if file.suffix ==
|
||||||
|
".wav" %}
|
||||||
|
<audio controls>
|
||||||
|
<source
|
||||||
|
src="{{ url_for('mainapp.resource', listing_path=file) }}"
|
||||||
|
type="audio/wav"
|
||||||
|
/>
|
||||||
|
Your browser does not support the audio element.
|
||||||
|
</audio>
|
||||||
|
{% elif file.suffix == ".tsv" %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ url_for('mainapp.process', listing_path=file) }}"
|
||||||
|
>{{ file.name }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>{{ file.name }}</li>
|
||||||
|
{% endif %} {% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Output files:</strong>
|
||||||
|
<ul>
|
||||||
|
{% for file in file_data['output'] %}
|
||||||
|
<li>
|
||||||
|
{% if file.suffix %}
|
||||||
|
<a href="{{ url_for('mainapp.download', listing_path=file) }}"
|
||||||
|
>{{ file.name }}</a
|
||||||
|
>
|
||||||
|
{% else %} {{ file.name }} {% endif %}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="tree">
|
||||||
|
<ul>
|
||||||
|
<!-- Root Folder -->
|
||||||
|
{% for file1 in root_files %}
|
||||||
|
<li>
|
||||||
|
<details
|
||||||
|
{%
|
||||||
|
if
|
||||||
|
root_files[file1]
|
||||||
|
%}
|
||||||
|
open{%
|
||||||
|
else
|
||||||
|
%}closed{%
|
||||||
|
endif
|
||||||
|
%}
|
||||||
|
>
|
||||||
|
<summary>
|
||||||
|
<a
|
||||||
|
href="{{ url_for('mainapp.file_list', listing_path=file1) }}"
|
||||||
|
>{{ file1 }}</a
|
||||||
|
>
|
||||||
|
</summary>
|
||||||
|
<ul>
|
||||||
|
{% for file2 in root_files[file1] %} {% if file2.suffix %}
|
||||||
|
<li class="file">
|
||||||
|
<a
|
||||||
|
href="{{ url_for('mainapp.file_list', listing_path=file2) }}#first"
|
||||||
|
>{{ file2.name }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
<details
|
||||||
|
{%
|
||||||
|
if
|
||||||
|
root_files[file1][file2]
|
||||||
|
%}
|
||||||
|
open{%
|
||||||
|
else
|
||||||
|
%}closed{%
|
||||||
|
endif
|
||||||
|
%}
|
||||||
|
>
|
||||||
|
<summary>
|
||||||
|
<a
|
||||||
|
href="{{ url_for('mainapp.file_list', listing_path=file2) }}#first"
|
||||||
|
>{{ file2.name }}</a
|
||||||
|
>
|
||||||
|
</summary>
|
||||||
|
<ul>
|
||||||
|
{% for file3 in root_files[file1][file2] %}
|
||||||
|
<li class="file">
|
||||||
|
<a
|
||||||
|
href="{{ url_for('mainapp.file_list', listing_path=file3) }}#first"
|
||||||
|
>{{ file3.name }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
{% endif %} {% endfor %}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Copyright -->
|
||||||
|
<div class="copyright">
|
||||||
|
© HSK creator. Wolfang Torres. All rights reserved 2026. Design:
|
||||||
|
<a href="https://html5up.net">HTML5 UP</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/jquery.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/jquery.scrolly.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/browser.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/breakpoints.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/util.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/main.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/app.js') }}/"></script>
|
||||||
|
<script></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
219
src/anki_creator_flask/templates/process.html
Normal file
219
src/anki_creator_flask/templates/process.html
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
<!doctype html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>HSK card creator</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, user-scalable=no"
|
||||||
|
/>
|
||||||
|
<meta name="description" content="" />
|
||||||
|
<meta name="keywords" content="" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='assets/css/main.css') }}"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="shortcut icon"
|
||||||
|
href="{{ url_for('static', filename='favicon.ico') }}"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
#loader-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #1a1a1a; /* Dark background */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 9999; /* Ensures it stays on top of everything */
|
||||||
|
transition:
|
||||||
|
opacity 0.5s ease,
|
||||||
|
visibility 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The spinning visual indicator */
|
||||||
|
.loader {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: 5px solid #333;
|
||||||
|
border-top: 5px solid #3498db; /* Blue accent color */
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Descriptive status text */
|
||||||
|
.loader-text {
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
margin-top: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyframe for rotation animation */
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smooth fade-out state triggered by JS */
|
||||||
|
.loader-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="is-preload">
|
||||||
|
<!-- Full-screen preloader container -->
|
||||||
|
<div id="loader-wrapper">
|
||||||
|
<div class="loader"></div>
|
||||||
|
<p class="loader-text">Loading, please wait...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Wrapper -->
|
||||||
|
<div id="wrapper">
|
||||||
|
<!-- Section -->
|
||||||
|
<section id="first" style="padding-top: 3em">
|
||||||
|
<header>
|
||||||
|
<h2>Select the deck type</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div id="text_area" class="content">
|
||||||
|
<p>
|
||||||
|
<strong>Delete unwanted Rows and Modify definitions</strong>
|
||||||
|
</p>
|
||||||
|
<form id="text_form" method="POST">
|
||||||
|
<div class="fields">
|
||||||
|
<div id="table" class="field">
|
||||||
|
<textarea name="text" id="text" rows="15"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul class="actions">
|
||||||
|
<li>
|
||||||
|
<input
|
||||||
|
id="process_button"
|
||||||
|
type="submit"
|
||||||
|
value="Process"
|
||||||
|
class="button primary"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<form id="settings_form" method="GET">
|
||||||
|
<ul class="items">
|
||||||
|
<li>
|
||||||
|
<h3>Language</h3>
|
||||||
|
<select id="language_id" name="language_id">
|
||||||
|
{% if 'en' in languages %}
|
||||||
|
<option value="en">English</option>
|
||||||
|
{% endif %} {% if 'es' in languages %}
|
||||||
|
<option value="es">Spanish</option>
|
||||||
|
{% endif %} {% if 'ru' in languages %}
|
||||||
|
<option value="ru">Russian</option>
|
||||||
|
{% endif %} {% if 'fr' in languages %}
|
||||||
|
<option value="fr">French</option>
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h3>Output</h3>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="out1"
|
||||||
|
name="output_type"
|
||||||
|
value="anki"
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
<label for="out1">Anki Deck</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="out2"
|
||||||
|
name="output_type"
|
||||||
|
value="quiz"
|
||||||
|
/>
|
||||||
|
<label for="out2">Quizlet deck</label>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input
|
||||||
|
id="settings_button"
|
||||||
|
type="submit"
|
||||||
|
value="Lock-in Settings"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<a href="{{ url_for('mainapp.app') }}">Back</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</form>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Copyright -->
|
||||||
|
<div class="copyright">
|
||||||
|
© HSK creator. Wolfang Torres. All rights reserved 2026. Design:
|
||||||
|
<a href="https://html5up.net">HTML5 UP</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/jquery.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/jquery.scrolly.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/browser.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/breakpoints.min.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/util.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/main.js') }}/"></script>
|
||||||
|
<script src="{{ url_for('static', filename='assets/js/app.js') }}/"></script>
|
||||||
|
<script>
|
||||||
|
// Quizlet is disabled for the moment
|
||||||
|
$("#out2").prop('disabled', true);
|
||||||
|
//Get datafor the controls
|
||||||
|
const serverData = {{ data | tojson }};
|
||||||
|
if (serverData.state === "new") {
|
||||||
|
$("#process_button").prop('disabled', true);
|
||||||
|
$('#text').val(serverData.text);
|
||||||
|
}
|
||||||
|
if (serverData.state === "complete" ) {
|
||||||
|
// Set values to inputs
|
||||||
|
if (serverData.language_id !== "" ) {
|
||||||
|
$('#language_id').val(serverData.language_id);
|
||||||
|
$('#language_id').prop('readonly', true);
|
||||||
|
}
|
||||||
|
$('#text').val(serverData.text);
|
||||||
|
}
|
||||||
|
// Loader while procesing
|
||||||
|
$('#text_form').on('submit', function(e) {
|
||||||
|
// Add the class that triggers the CSS fade transition
|
||||||
|
$("#loader-wrapper").removeClass("loader-hidden");
|
||||||
|
document.cookie = 'download_started=; Max-Age=0; path=/';
|
||||||
|
const checkDownload = setInterval(() => {
|
||||||
|
if (document.cookie.includes('download_started=true')) {
|
||||||
|
clearInterval(checkDownload);
|
||||||
|
console.log('File successfully downloaded!');
|
||||||
|
$("#loader-wrapper").addClass("loader-hidden");
|
||||||
|
this.disabled = false;
|
||||||
|
document.cookie = 'download_started=; Max-Age=0; path=/';
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
$(window).on("load", function() {
|
||||||
|
$("#loader-wrapper").addClass("loader-hidden");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user