Implemented file drop inputs, Preparing more tools

Update app.py, excel-password-remover.yml, and 30 more files...
This commit is contained in:
2025-02-25 23:53:43 +01:00
parent ec905b4735
commit 65db2dea5a
32 changed files with 422 additions and 24 deletions

2
app.py
View File

@@ -15,6 +15,7 @@ from website.l10n.utils import get_user_lang, localize, reload_strings, l10n_url
from website.renderers.applet import render_applet_scripts, render_applet_head
from website.renderers.button import render_button
from website.renderers.code import render_code_block
from website.renderers.file_input import render_file_input
from website.renderers.headings import render_heading, render_h2, render_h1, render_h3, render_h4
from website.renderers.paragraph import render_paragraph
from website.renderers.lists import render_list_ul
@@ -126,6 +127,7 @@ def inject_processors():
render_applet_scripts=render_applet_scripts,
render_applet_head=render_applet_head,
render_code_block=render_code_block,
render_file_input=render_file_input,
# Commons
url_for=url_for,

View File

@@ -0,0 +1,8 @@
applets:
- id: "excel-password-remover"
resources:
scripts:
- "excel-password-remover.mjs"
stylesheets:
- "excel-password-remover.css"

View File

@@ -0,0 +1,8 @@
applets:
- id: "png-chunk-analyser"
resources:
scripts:
- "png-chunk-analyser.mjs"
stylesheets:
- "png-chunk-analyser.css"

View File

@@ -0,0 +1,8 @@
applets:
- id: "png-optimizer"
resources:
scripts:
- "png-optimizer.mjs"
stylesheets:
- "png-optimizer.css"

View File

@@ -9,6 +9,8 @@ na: N/A
yes: Yes
no: No
accept: Accept
width: Width
height: Height
width.min: Minimum width
@@ -59,3 +61,17 @@ none.ms: None
none.mp: None
none.fs: None
none.fp: None
eula.short: EULA
eula.long: End-user license agreement (EULA)
dont.ask.again: "Don't ask again"
file.drop.upload: "Choose file(s)"
file.drop.clear: "Clear selection"
file.drop.label.single: "Choose or drop a file:"
file.drop.label.multiple: "Choose or drop files:"
file.drop.select.single: "Drop your file here"
file.drop.select.multiple: "Drop your files here"
file.drop.selected.single: "You selected 1 file"
file.drop.selected.multiple: "You selected <span class=\"np-file-drop-count\">???</span> files"

View File

@@ -9,7 +9,8 @@ og.description: 'TODO: description'
header.title: Contact
email.title: Email
email.compose: Send an email to <i>herwin.bozet@gmail.com</i>
email.compose.gmail: Send an email to <i>herwin.bozet@gmail.com</i>
email.compose.nibblepoker: Send an email to <i>herwin.bozet@nibblepoker.lu</i>
twitter.title: Twitter
twitter.compose: Compose DM to @NibblePoker on Twitter

View File

@@ -35,3 +35,12 @@ usage.p1: >-
demo.title: Demonstration video
links.title: Links
content.link.demo: Demo hosted on GitHub
eula.1: "This tool is for use only with files you have permission to unlock.<br>
If you dont have authorization, contact the appropriate authority.<br>
You are responsible for how you use this tool."
eula.2: "No data is sent online, as everything happens in your browser with JavaScript.<br>
However, do not use this tool for sensitive files unless you have permission from the relevant authorities to avoid legal issues."
eula.3: "The tool doesn't reveal the original password, as its secure and not stored in plain text; it simply removes it."
eula.4: "By using this tool, you accept full responsibility, and it is provided “as is”, without any warranty."

View File

@@ -9,6 +9,8 @@ na: Non-applicable
yes: Oui
no: Non
accept: Accepter
width: Largeur
height: Hauteur
width.min: Largeur minimale
@@ -59,3 +61,17 @@ none.ms: Aucun
none.mp: Aucuns
none.fs: Aucune
none.fp: Aucunes
eula.short: CLUF
eula.long: Contrat de licence utilisateur final (CLUF)
dont.ask.again: "Ne plus demander"
file.drop.upload: "Ajouter fichier(s)"
file.drop.clear: "Vider la séléction"
file.drop.label.single: "Choisissez ou déposez un fichier:"
file.drop.label.multiple: "Choisissez ou déposez des fichiers:"
file.drop.select.single: "Déposez votre fichier ici"
file.drop.select.multiple: "Déposez vos fichiers ici"
file.drop.selected.single: "Vous avez séléctionné 1 fichier"
file.drop.selected.multiple: "Vous avez séléctionné <span class=\"np-file-drop-count\">???</span> fichiers"

View File

@@ -9,7 +9,8 @@ og.description: 'TODO: description'
header.title: Contact
email.title: Courriel
email.compose: Envoyer un courriel à <i>herwin.bozet@gmail.com</i>
email.compose.gmail: Envoyer un courriel à <i>herwin.bozet@gmail.com</i>
email.compose.nibblepoker: Envoyer un courriel à <i>herwin.bozet@nibblepoker.lu</i>
twitter.title: Twitter
twitter.compose: Composer un message privé pour @NibblePoker sur Twitter

View File

@@ -0,0 +1,31 @@
tools:
- id: "excel-password-remover"
applet_id: "excel-password-remover"
metadata:
head:
title_key: "meta.title"
description_key: "meta.description"
opengraph:
title_key: "meta.title"
description_key: "meta.description"
type: null
url: null
image_url: "/resources/NibblePoker/images/tools/excel-password-remover/excel-password-remover.png"
image_type: null
twitter:
title_key: "meta.title"
description_key: "meta.description"
index:
priority: 100
enable: true
title_key: "meta.title"
preamble_key: "meta.description"
image_url: "/resources/NibblePoker/images/tools/excel-password-remover/excel-password-remover.png"
image_alt_key: ""
general:
icon: "fab fa-python"
title_key: "meta.title"
subtitle_key: "article.subtitle"
tags:
- "undefined"

View File

@@ -0,0 +1,31 @@
tools:
- id: "png-chunk-analyser"
applet_id: "png-chunk-analyser"
metadata:
head:
title_key: "meta.title"
description_key: "meta.description"
opengraph:
title_key: "meta.title"
description_key: "meta.description"
type: null
url: null
image_url: "/resources/NibblePoker/images/tools/excel-password-remover/excel-password-remover.png"
image_type: null
twitter:
title_key: "meta.title"
description_key: "meta.description"
index:
priority: 100
enable: true
title_key: "meta.title"
preamble_key: "meta.description"
image_url: "/resources/NibblePoker/images/tools/excel-password-remover/excel-password-remover.png"
image_alt_key: ""
general:
icon: "fab fa-python"
title_key: "meta.title"
subtitle_key: "article.subtitle"
tags:
- "undefined"

View File

@@ -0,0 +1,31 @@
tools:
- id: "png-optimizer"
applet_id: "png-optimizer"
metadata:
head:
title_key: "meta.title"
description_key: "meta.description"
opengraph:
title_key: "meta.title"
description_key: "meta.description"
type: null
url: null
image_url: "/resources/NibblePoker/images/tools/excel-password-remover/excel-password-remover.png"
image_type: null
twitter:
title_key: "meta.title"
description_key: "meta.description"
index:
priority: 100
enable: true
title_key: "meta.title"
preamble_key: "meta.description"
image_url: "/resources/NibblePoker/images/tools/excel-password-remover/excel-password-remover.png"
image_alt_key: ""
general:
icon: "fab fa-python"
title_key: "meta.title"
subtitle_key: "article.subtitle"
tags:
- "undefined"

View File

@@ -0,0 +1,36 @@
const excelFileRegex = /^.*\.xls[xm]$/gi;
const excelWorksheetRegex = /^xl\/worksheets\/.*.xml$/gi;
var outputZip;
var outputZipFilename = "default-filename.error.zip";
var filesTotalCount = 0;
var filesProcessedCount = 0;
var passwordsRemoved = 0;
// Tool-centric stuff
{
/** @type {string} */
const appletId = "excel-password-remover";
///** @type {HTMLElement} */
//const eEulaContainer = document.querySelector(`#${appletId}-eula`);
///** @type {HTMLInputElement} */
//const eEulaDontAskAgainOption = document.querySelector(`input#${appletId}-eula-remember`);
///** @type {HTMLButtonElement} */
//const eEulaAcceptButton = document.querySelector(`button#${appletId}-eula-accept`);
/*function acceptTerms() {
document.getElementById("warning").hidden = true;
document.getElementById("file-select").hidden = false;
}*/
window.onload = function () {
/*console.log(eEulaContainer);
console.log(eEulaDontAskAgainOption);
console.log(eEulaAcceptButton);
eEulaAcceptButton.addEventListener("click", function() {
eEulaContainer.hidden = true;
});*/
}
}

View File

@@ -0,0 +1,15 @@
.np-file-input-drop-container {
position: relative;
}
.np-file-drop-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
input[type=file].np-file-input-drop {
opacity: 0;
cursor: pointer;
}

View File

@@ -1,6 +1,11 @@
// NibblePoker - Mandatory Scripts
// Author: Herwin Bozet (@NibblePoker)
// License: Public Domain (This code)
// Remark: This modules contains all the scripts that are globally required on this website
import {fadeIn} from "./nibblepoker-ui"
class CpuArchitecture {
/*class CpuArchitecture {
constructor(id, name) {
this.id = id;
this.name = name;
@@ -29,7 +34,7 @@ function getCpuArchitecture(userAgent = navigator.userAgent) {
return CpuArchitectures.RiscV;
}
return CpuArchitectures.Unknown;
}
}*/
let isSidebarVisible = true;
let eContentModal = document.getElementById("modal-content");
@@ -72,9 +77,92 @@ document.addEventListener("DOMContentLoaded", () => {
// TODO: Autodetect mobile screens, close it, and add classes to make it over the rest with dark modal bkgd.
// Printing the detected CPU architecture
const detectedCpuArch= getCpuArchitecture();
/*const detectedCpuArch= getCpuArchitecture();
let cpuArchPrintouts = document.querySelectorAll(".data-cpu-arch");
cpuArchPrintouts.forEach(element => {
element.textContent = detectedCpuArch.name;
});*/
// Setting up the file drop inputs
document.querySelectorAll(".np-file-input-root-container").forEach(eRootContainer => {
//console.log(eRootContainer);
/** @type {HTMLInputElement} */
const eFileDropInput = eRootContainer.querySelector("input[type=file]");
if(eFileDropInput == null) {
return;
}
/** @type {string} */
const inputId = eFileDropInput.getAttribute("id");
//console.log(inputId);
/** @type {HTMLElement} */
const eFileDropTextEmpty = eRootContainer.querySelector(`#${inputId}-text-drop`);
/** @type {HTMLElement} */
const eFileDropTextSingle = eRootContainer.querySelector(`#${inputId}-text-file-single`);
/** @type {HTMLElement} */
const eFileDropTextMultiple = eRootContainer.querySelector(`#${inputId}-text-file-multiple`);
/** @type {HTMLButtonElement} */
const eFileDropAddButton = eRootContainer.querySelector(`button#${inputId}-add`);
/** @type {HTMLButtonElement} */
const eFileDropClearButton = eRootContainer.querySelector(`button#${inputId}-reset`);
/** @type {NodeListOf<HTMLElement>} */
const eFileDropSelectionCounts = eRootContainer.querySelectorAll(`.np-file-drop-count`);
if(eFileDropAddButton !== null) {
eFileDropAddButton.addEventListener("click", function() {
eFileDropInput.click();
});
}
if(eFileDropClearButton !== null) {
eFileDropClearButton.addEventListener("click", function() {
eFileDropInput.value = '';
if(eFileDropTextSingle !== null) {
eFileDropTextSingle.hidden = true;
}
if(eFileDropTextMultiple !== null) {
eFileDropTextMultiple.hidden = true;
}
if(eFileDropTextEmpty !== null) {
eFileDropTextEmpty.hidden = false;
}
});
}
eFileDropInput.addEventListener('change', function(e) {
let fileCount = e.target.files.length;
if(fileCount === 1 && eFileDropTextSingle !== null) {
if(eFileDropTextEmpty !== null) {
eFileDropTextEmpty.hidden = true;
}
if(eFileDropTextMultiple !== null) {
eFileDropTextMultiple.hidden = true;
}
eFileDropTextSingle.hidden = false;
}
if(fileCount >= 1 && eFileDropTextMultiple !== null) {
if(eFileDropTextEmpty !== null) {
eFileDropTextEmpty.hidden = true;
}
if(eFileDropTextSingle !== null) {
eFileDropTextSingle.hidden = true;
}
eFileDropSelectionCounts.forEach(eFileDropSelectionCount => {
eFileDropSelectionCount.innerText = `${fileCount}`;
});
eFileDropTextMultiple.hidden = false;
}
});
});
});

View File

@@ -0,0 +1,22 @@
<section id="{{ applet_data.id }}-eula">
{{ render_h2(l10n("eula.long", "commons", user_lang)) }}
{{ render_paragraph(l10n("eula.1", applet_data.id, user_lang)) }}
{{ render_paragraph(l10n("eula.2", applet_data.id, user_lang)) }}
{{ render_paragraph(l10n("eula.3", applet_data.id, user_lang)) }}
{{ render_paragraph(l10n("eula.4", applet_data.id, user_lang)) }}
</section>
<section id="{{ applet_data.id }}-input">
{{ render_h2(l10n("file.selection.title", applet_data.id, user_lang)) }}
<p>123</p>
</section>
<section id="{{ applet_data.id }}-details">
{{ render_h2(l10n("details.title", applet_data.id, user_lang)) }}
<p>123</p>
</section>
<section id="{{ applet_data.id }}-licenses">
{{ render_h2(l10n("licenses.title", applet_data.id, user_lang)) }}
<p>123</p>
</section>

View File

@@ -0,0 +1,5 @@
{{ render_h2(l10n("upload.title", "commons", user_lang)) }}
{{ render_file_input("test-input", true, None, true, true) }}

View File

View File

@@ -23,6 +23,8 @@
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/NibblePoker/IndevCSS/nibblepoker.min.css">
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/Quantum/Quantum.min.css">
<link rel="stylesheet" href="{{ url_for("static", filename="resources/NibblePoker/css/extra.css") }}">
{% block extra_stylesheets %}{% endblock %}
<meta charset="UTF-8">

View File

@@ -1,4 +1,6 @@
<button class="p-mxs r-s border b-light t-nowrap {{ button_extra_classes }}"
<button
{% if button_id is not none %}id="{{ button_id }}" {% endif %}
class="p-mxs r-s border b-light t-nowrap {{ button_extra_classes }}"
{% if button_disabled %}disabled{% endif %}>
{{ button_inner_html }}
</button>

View File

@@ -1,4 +1,8 @@
{% if code_language is none %}
<code class="code ox-auto w-full d-inline-block position-relative">
{% else %}
<code class="code ox-auto w-full d-inline-block position-relative language-{{ code_language }}">
{% endif %}
{% for code_line in code_lines %}
<span class="code-line t-nowrap">{{ code_line }}</span><br>
{% endfor %}

View File

@@ -0,0 +1,58 @@
<div class="np-file-input-root-container">
{% if file_upload_button %}
<button id="{{ file_input_id }}-add" class="p-xs r-s border btn-primary">
<i class="fa-duotone fa-solid fa-cloud-arrow-up mr-xs"></i>
{{ l10n("file.drop.upload", "commons", user_lang) }}
</button>
{% endif %}
{% if file_clear_button %}
<button id="{{ file_input_id }}-reset" class="p-xs r-s border btn-warning">
{{ l10n("file.drop.clear", "commons", user_lang) }}
</button>
{% endif %}
{% if file_upload_button or file_clear_button %}
<br>
{% endif %}
<div class="np-file-input-drop-container border r-s bkgd-blank">
<p class="np-file-drop-text"
id="{{ file_input_id }}-text-drop">
{% if file_multiple %}
{{ l10n("file.drop.select.multiple", "commons", user_lang) }}
{% else %}
{{ l10n("file.drop.select.single", "commons", user_lang) }}
{% endif %}
</p>
<p class="np-file-drop-text"
id="{{ file_input_id }}-text-file-single"
hidden>
{{ l10n("file.drop.selected.single", "commons", user_lang) }}
</p>
<p class="np-file-drop-text"
id="{{ file_input_id }}-text-file-multiple"
hidden>
{{ l10n("file.drop.selected.multiple", "commons", user_lang) }}
</p>
<label for="{{ file_input_id }}"
hidden>
{% if file_multiple %}
{{ l10n("file.drop.label.multiple", "commons", user_lang) }}
{% else %}
{{ l10n("file.drop.label.single", "commons", user_lang) }}
{% endif %}
</label>
<input type="file"
id="{{ file_input_id }}"
name="{{ file_input_id }}"
{% if file_accept is not none %}accept="{{ file_accept }}"{% endif %}
class="np-file-input-drop w-full p-l"
{% if file_multiple %}multiple{% endif %}
/>
</div>
</div>

View File

@@ -10,10 +10,15 @@
{% block main_content %}
{{ render_h1(l10n("email.title", "contact", user_lang), "fad fa-mail-bulk", "herwin.bozet@gmail.com") }}
<p class="m-s">
<a href="mailto:Herwin Bozet<herwin.bozet@nibblepoker.lu>?subject=Contact%20via%20NibblePoker.lu" class="a-hidden button-link">
<button class="p-xs r-s border b-light success"><i class="fad fa-external-link-alt mr-xs"></i>{{ l10n("email.compose.nibblepoker", "contact", user_lang) }}</button>
</a>
</p>
<!--<p class="m-s">
<a href="mailto:Herwin Bozet<herwin.bozet@gmail.com>?subject=Contact%20via%20NibblePoker.lu" class="a-hidden button-link">
<button class="p-xs r-s border b-light success"><i class="fad fa-external-link-alt mr-xs"></i>{{ l10n("email.compose", "contact", user_lang) }}</button>
</a>
</p>
</p>-->
{{ render_h1(l10n("twitter.title", "contact", user_lang), "fab fa-twitter", "@NibblePoker") }}
<p class="m-s">

View File

@@ -1 +0,0 @@
{% extends "tools/_tool.jinja" %}

View File

@@ -1,10 +1,11 @@
from flask import render_template
def render_button(inner_html: str, disabled: bool = False) -> str:
def render_button(inner_html: str, disabled: bool = False, id: str = None) -> str:
return render_template(
"elements/button.jinja",
button_inner_html=inner_html,
button_disabled=disabled,
button_extra_classes=""
button_extra_classes="",
button_id=id,
)

View File

@@ -1,5 +1,4 @@
import html
import re
from typing import Optional
from flask import render_template
@@ -19,13 +18,3 @@ def render_code_block(code_lines: list[str], language: Optional[str] = None):
code_lines=_code_lines,
code_language=language,
)
# return re.sub('>\s*<span', "><span",
# re.sub('<br>\s*</code>', "</code>",
# render_template(
# "elements/code.jinja",
# code_lines=_code_lines,
# code_language=language,
# )
# )
# )

View File

@@ -1,3 +1,13 @@
from flask import render_template
def render_file_input() -> str:
return ""
def render_file_input(input_id: str, multiple: bool, accept: str = None,
upload_button: bool = False, clear_button: bool = False) -> str:
return render_template(
"elements/file-input.jinja",
file_input_id=input_id,
file_multiple=multiple,
file_accept=accept,
file_upload_button=upload_button,
file_clear_button=clear_button,
)