Added basic Formula Wizard, Added script to compile SASS and TS, many other random changes.

Update .gitignore, .htaccess, and 68 more files...
This commit is contained in:
2023-08-02 17:06:58 +02:00
parent 6fb621e550
commit 4cf950b5dd
70 changed files with 4128 additions and 182 deletions

8
.gitignore vendored
View File

@@ -1,9 +1,17 @@
# IDE-related folders
.idea/
# Node.JS
node_modules/
package-lock.json
# Static resources
resources/DecimalJs/
resources/DecimalJsLight/
resources/FontAwesomePro/
resources/HighlightJS/
resources/GliderJs/
resources/PlotlyJs/
resources/NibblePoker/css/*.css
resources/NibblePoker/scss/trash

View File

@@ -11,12 +11,17 @@
# Fixing some encoding issues on non-HTML files.
# Mostly affects the old privacy policies written in french.
AddCharset utf-8 .css .txt .js .md
AddCharset utf-8 .css .txt .js .md .ts .mjs
#<Files ~ "\.txt?$">
# Header set Content-Type "text/plain; charset=utf-8"
#</Files>
#AddDefaultCharset utf-8
# Adding MIME types
AddType text/typescript .ts
AddType text/javascript .js
AddType text/javascript .mjs
# Correcting some default options for security and language/content redirection.
# FollowSymlinks is also on since it's required for "mod_rewrite" and the server is jailed.
Options -Indexes +FollowSymlinks -ExecCGI
@@ -47,18 +52,31 @@ ErrorDocument 404 /error.php
#Header set Pragma "no-cache"
#Header set Expires 0
# Setting up GZIP
<ifModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>
# # # Setting some headers for security.
# # #Header always set X-Detected-Country "NK"
# # Header always set X-Frame-Options "deny"
Header always set X-Frame-Options "deny"
# # Header always set Content-Security-Policy "default-src 'self' files.nibblepoker.lu; img-src 'self' files.nibblepoker.lu data:; object-src 'none'; child-src 'self'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content"
# # Header always set X-XSS-Protection " 1; mode=block"
# # Header always set Referrer-Policy "no-referrer"
# # Header always set X-Content-Type-Options "nosniff"
# # Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# # #Header always set Cache-Control "max-age=300, public"
# # Header always set Access-Control-Allow-Origin "*"
# # Header unset X-Powered-By
# # #Header always set X-Powered-By "Amiga 1200, Kickstart 3.1"
Header always set X-XSS-Protection " 1; mode=block"
Header always set Referrer-Policy "no-referrer"
Header always set X-Content-Type-Options "nosniff"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
#Header always set Cache-Control "max-age=300, public"
Header always set Access-Control-Allow-Origin "*"
Header unset X-Powered-By
#Header always set X-Powered-By "Amiga 1200, Kickstart 3.1"
Header always set Permissions-Policy "browsing-topics=(), interest-cohort=()"
# Handling all other redirections.
RewriteEngine On

65
about/index.php Normal file
View File

@@ -0,0 +1,65 @@
<?php
$start_time = microtime(true);
set_include_path('../');
include_once 'commons/config.php';
include_once 'commons/langs.php';
?>
<!DOCTYPE html>
<html lang="<?php echo($user_language); ?>">
<head>
<?php include 'commons/DOM/head.php'; ?>
<title><?php print(localize('about.head.title')); ?></title>
<meta name="description" content="<?php print(localize('about.head.description')); ?>">
<meta property="og:title" content="<?php print(localize('about.og.title')); ?>"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="<?php echo($host_uri . l10n_url_abs('/')); ?>"/>
<meta property="og:image" content="<?php echo($host_uri); ?>/resources/NibblePoker/images/logos/v2_opengraph.png"/>
<meta property="og:image:type" content="image/png"/>
<meta property="og:description" content="<?php print(localize('about.og.description')); ?>"/>
</head>
<body>
<?php
include_once 'commons/DOM/utils.php';
$SIDEBAR_IDS = ['about'];
include 'commons/DOM/sidebar.php';
?>
<header class="w-full p-m pl-s">
<h1 class="t-size-17 t-w-500">
<i class="fad fa-user t-size-16 mr-s t-muted"></i><?php print(localize("about.header.title")); ?>
</h1>
<?php include 'commons/DOM/header-lang.php'; ?>
</header>
<main id="main" class="rl-m border border-r-0 p-l">
<?php printMainHeader(localize("about.topmost.title"), "fab fa-twitter", "@NibblePoker"); ?>
<p class="m-s">
<a href="https://twitter.com/messages/compose?recipient_id=937370791334895616" class="bland-link button-link">
<button class="p-xs r-s border b-light primary"><?php print(localize("contact.twitter.compose")); ?></button>
</a>
</p>
<div class="px-xxs">
<?php printSubHeader(localize("about.education.title"), null, null); ?>
<details>
<summary>ABC</summary>
DEF
</details>
<?php printSubHeader(localize("about.skills.title"), null, null); ?>
<?php printSubHeader(localize("about.work.title"), null, null); ?>
</div>
</main>
<?php
include 'commons/DOM/footer.php';
include 'commons/DOM/scripts.php';
?>
</body>
</html>
<?php
$end_time = microtime(true);
if($print_execution_timer) {
echo("<!-- PHP execution took " . round(($end_time - $start_time) * 1000, 2) . " ms -->");
}
?>

View File

@@ -8,7 +8,7 @@ if(basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
include_once 'commons/langs.php';
?>
<footer class="d-flex flex-align-center w-full p-s py-xs">
<button id="sidebar-toggle-footer" class="p-xs border r-s t-size-10">
<button id="sidebar-toggle-footer" class="p-xs border r-s t-size-10" aria-label="<?php echo(localize("footer.alt.sidebar.button")); ?>">
<i class="fa fa-bars px-xxs" aria-hidden="true"></i>
</button>
<p class="flex-fill t-center t-size-10 t-w-500 t-muted">

View File

@@ -54,6 +54,7 @@ function printSidebarEntry($url, $title, $icon, $activeId) {
<?php
printSidebarEntry("https://files.nibblepoker.lu/", localize("sidebar.text.downloads"), "fad fa-download", "");
printSidebarEntry("https://git.nibblepoker.lu/", localize("sidebar.text.gitea"), "fad fa-code", "");
//printSidebarEntry("https://wiki.nibblepoker.lu/", localize("sidebar.text.wiki"), "fad fa-books", "");
?>
</div>
<hr class="subtle">

View File

@@ -59,4 +59,23 @@ function printMainHeader(string $text, ?string $iconId = null, ?string $rightTex
));
}
function printSubHeader(string $text, ?string $anchorId = null, ?string $backgroundClass = "bkgd-math"): void {
if(is_null($backgroundClass)) {
$backgroundClass = "bkgd-math";
}
$headingText = getMainHeader(
$text,
null,
null,
$anchorId,
69, // Forcing it as a non-first of main heading.
$backgroundClass,
3
);
$headingText = str_replace("t-size-14", "t-size-11", $headingText);
echo($headingText);
}
?>

View File

@@ -92,6 +92,7 @@ abstract class ComposerElementModifiers {
// Containers
const CONTAINER_SCROLL_HORIZONTAL = ["horizontal-scroll", "overflow-x-scroll hide-scrollbar"];
const CONTAINER_SCROLL_HORIZONTAL_AUTO = ["horizontal-scroll-auto", "overflow-x-auto"];
const CONTAINER_CARD = ["card", "card"];
// Buttons

View File

@@ -0,0 +1,51 @@
<?php
// Making sure the file is included and not accessed directly.
if(basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
header('HTTP/1.1 403 Forbidden');
die();
}
// Including required helpers.
include_once 'commons/langs.php';
class OpenGraphData {
public string $title;
public string $description;
public string $type;
public string $url;
public string $image;
public string $image_type;
function __construct(array $title, array $description, string $type, string $url, string $image,
string $image_type) {
global $default_language;
global $user_language;
$this->title = array_key_exists($user_language, $title) ? $title[$user_language] :
(array_key_exists($default_language, $title) ? $title[$default_language] : $title[0]);
$this->description = array_key_exists($user_language, $description) ? $description[$user_language] :
(array_key_exists($default_language, $description) ? $description[$default_language] : $description[0]);
$this->type = $type;
$this->url = $url;
$this->image = $image;
$this->image_type = $image_type;
}
static function from_json(array $json_data): ?OpenGraphData {
foreach(["title", "description", "type", "url", "image", "image_type"] as $wantedKey) {
if(!key_exists($wantedKey, $json_data)) {
return null;
}
}
return new OpenGraphData(
$json_data["title"],
$json_data["description"],
$json_data["type"],
$json_data["url"],
$json_data["image"],
$json_data["image_type"]
);
}
}

View File

@@ -10,6 +10,9 @@ include_once 'commons/config.php';
include_once 'commons/langs.php';
include_once 'commons/content.php';
// Required to handle opengraph data
include_once 'commons/content/opengraph.php';
// Required to make headings
include_once 'commons/DOM/utils.php';
@@ -18,20 +21,25 @@ class ToolInfoFile {
public string $domFile;
public ?string $langFile;
public array $codeFilesPaths;
public array $moduleFilesPaths;
public array $styleFilesPaths;
public string $icon;
public string $titleKey;
public ?string $subTitleKey;
public OpenGraphData $openGraphData;
function __construct(string $domFile, ?string $langFile, ?array $codeFilesPaths, ?array $styleFilesPaths,
?string $icon, ?string $titleKey, ?string $subTitleKey) {
function __construct(string $domFile, ?string $langFile, ?array $codeFilesPaths, ?array $moduleFilesPaths,
?array $styleFilesPaths, ?string $icon, ?string $titleKey, ?string $subTitleKey,
array $opengraph) {
$this->domFile = $domFile;
$this->langFile = $langFile;
$this->codeFilesPaths = is_null($codeFilesPaths) ? array() : $codeFilesPaths;
$this->moduleFilesPaths = is_null($moduleFilesPaths) ? array() : $moduleFilesPaths;
$this->styleFilesPaths = is_null($styleFilesPaths) ? array() : $styleFilesPaths;
$this->icon = is_null($icon) ? "fad fa-question" : $icon;
$this->titleKey = is_null($titleKey) ? "unset" : $titleKey;
$this->subTitleKey = $subTitleKey;
$this->openGraphData = OpenGraphData::from_json($opengraph);
}
static function from_json(array $json_data): ?ToolInfoFile {
@@ -42,10 +50,12 @@ class ToolInfoFile {
$json_data["dom"],
key_exists("lang", $json_data) ? $json_data["lang"] : null,
key_exists("code", $json_data) ? $json_data["code"] : null,
key_exists("module", $json_data) ? $json_data["module"] : null,
key_exists("styles", $json_data) ? $json_data["styles"] : null,
key_exists("icon", $json_data) ? $json_data["icon"] : null,
key_exists("title", $json_data) ? $json_data["title"] : null,
key_exists("subtitle", $json_data) ? $json_data["subtitle"] : null
key_exists("subtitle", $json_data) ? $json_data["subtitle"] : null,
$json_data["opengraph"]
);
}
@@ -72,6 +82,14 @@ class ToolInfoFile {
}
}
foreach($this->moduleFilesPaths as $moduleFilePath) {
if(!(file_exists($moduleFilePath) && is_file($moduleFilePath))) {
$contentManager->hasError = true;
$contentManager->errorMessageKey = "content.error.message.missing.file.module";
return;
}
}
foreach($this->styleFilesPaths as $styleFilePath) {
if(!(file_exists($styleFilePath) && is_file($styleFilePath))) {
$contentManager->hasError = true;
@@ -108,10 +126,23 @@ abstract class ToolsContent {
for($iCodeFilePath = 0; $iCodeFilePath < count($toolInfo->codeFilesPaths); $iCodeFilePath++) {
$toolInfo->codeFilesPaths[$iCodeFilePath] = realpath(
$contentRootPath . "/items/" . $toolInfo->codeFilesPaths[$iCodeFilePath]);
$toolInfo->codeFilesPaths[$iCodeFilePath] = str_replace(
"\\", "/", $toolInfo->codeFilesPaths[$iCodeFilePath]
);
}
for($iModuleFilePath = 0; $iModuleFilePath < count($toolInfo->moduleFilesPaths); $iModuleFilePath++) {
$toolInfo->moduleFilesPaths[$iModuleFilePath] = realpath(
$contentRootPath . "/items/" . $toolInfo->moduleFilesPaths[$iModuleFilePath]);
$toolInfo->moduleFilesPaths[$iModuleFilePath] = str_replace(
"\\", "/", $toolInfo->moduleFilesPaths[$iModuleFilePath]
);
}
for($iStyleFilePath = 0; $iStyleFilePath < count($toolInfo->styleFilesPaths); $iStyleFilePath++) {
$toolInfo->styleFilesPaths[$iStyleFilePath] = realpath(
$contentRootPath . "/items/" . $toolInfo->styleFilesPaths[$iStyleFilePath]);
$toolInfo->styleFilesPaths[$iStyleFilePath] = str_replace(
"\\", "/", $toolInfo->styleFilesPaths[$iStyleFilePath]
);
}
} else {
$contentManager->hasError = true;

View File

@@ -31,8 +31,3 @@ function add_code_modal(string $id, string $title, string $text) {
}
?>

File diff suppressed because one or more lines are too long

View File

@@ -16,7 +16,7 @@ for main_dir_entry in os.listdir("./"):
if main_dir_entry.startswith("_"):
continue
print("Checking ./{}".format(main_dir_entry))
print("> Processing ./{}".format(main_dir_entry))
if not os.path.isdir(os.path.join("./", main_dir_entry)):
continue

View File

@@ -0,0 +1,41 @@
{
"about.head.title": "About - NibblePoker",
"about.head.description": "TODO: description",
"about.og.title": "NibblePoker - About",
"about.og.description": "TODO: description",
"about.header.title": "About",
"about.part.year.single": "year",
"about.part.year.multiple": "years",
"about.part.since": "since",
"about.education.title": "Education",
"about.skills.title": "Skills",
"about.work.title": "Work Experience",
"about.work.ctie.title": "Government IT Centre (CTIE)",
"about.work.ctie.role.1": "<abbr title=\"Internet-of-Things\">IoT</abbr> Developer Internship",
"about.work.ctie.location": "Luxembourg",
"about.work.computrade.title": "CompuTrade Luxembourg Ltd",
"about.work.computrade.role.1": "Full & Half-time student job",
"about.work.computrade.location": "Steinfort, Luxembourg",
"about.work.lih.title": "Luxembourg Institute of Health (LIH)",
"about.work.lih.role.1": "IT Support Internship",
"about.work.lih.location": "Luxembourg",
"about.work.crlux.title": "Luxembourg Red Cross",
"about.work.crlux.role.1": "Volunteer Excel VBA programmer.",
"about.work.crlux.location": "Luxembourg",
"about.work.buttek.title": "Luxembourg Red Cross - Buttek",
"about.work.buttek.role.1": "Volunteer ???",
"about.work.buttek.role.2": "Student cashier ???",
"about.work.buttek.location": "Luxembourg",
"about.work.current.title": "Current employer kept private",
"about.work.current.role.1": "???",
"about.work.current.location": "Belgium"
}

View File

@@ -5,6 +5,9 @@
"contact.og.description": "TODO: description",
"contact.header.title": "Contact",
"contact.email.title": "Email",
"contact.email.compose": "Send an email to <i>herwin.bozet@gmail.com</i>",
"contact.twitter.title": "Twitter",
"contact.twitter.compose": "Compose DM to @NibblePoker on Twitter"

View File

@@ -1,4 +1,5 @@
{
"footer.text.privacy": "Privacy policy",
"footer.alt.sidebar.button": "Open and close the navigation sidebar.",
"footer.alt.logo": "Website's logo"
}

View File

@@ -3,5 +3,17 @@
"home.head.description": "TODO: description",
"home.og.title": "NibblePoker",
"home.og.description": "TODO: description",
"home.header.title": "Homepage"
"home.header.title": "Homepage",
"home.showcase.title": "Showcase",
"home.updates.title": "Updates",
"home.updates.text.privacy": "●&nbsp;&nbsp;Updated our privacy policy.",
"home.updates.2.date": "August 15 2023",
"home.updates.2.text.1": "●&nbsp;&nbsp;The website is back online.",
"home.updates.2.text.2": "●&nbsp;&nbsp;New and much lighter design.",
"home.updates.2.text.3": "●&nbsp;&nbsp;Changed our host to <a href=\"https://hostbrr.com/\">HostBrr</a>.",
"home.updates.2.text.4": "●&nbsp;&nbsp;Added a section for web-based tools.",
"home.updates.1.date": "September 9 2022",
"home.updates.1.text.1": "●&nbsp;&nbsp;Changed our host to v6Node."
}

View File

@@ -23,7 +23,7 @@
"privacy.v2.data.title": "Data collection",
"privacy.v2.data.intro.1": "This websites only collects data through generic access logs in order to detect and block bad actors from accessing this website.",
"privacy.v2.data.intro.2": "None of the data collected is used for any other purpose,it is never shared with any other third-party and is never use in any sort of analytics.",
"privacy.v2.data.intro.2": "None of the data collected is used for any other purpose, it is never shared with any other third-party and is never use in any sort of analytics.",
"privacy.v2.data.private.1": "Here is the list of private data being collected:",
"privacy.v2.data.private_list.1": "IP address",
"privacy.v2.data.private_list.2": "Browser's User-Agent",
@@ -57,7 +57,18 @@
"privacy.v2.third.intro.2": "The goal of this system is to improve your browsing experience with the help of a private caching service and custom traffic filtering rules.",
"privacy.v2.third.intro.3": "None of the data that may be gathered by v6Node or the system described above is ever used or stored.",
"privacy.v2.third.intro.4": "If you'd wish to consult their privacy policy and their partners', you can do so by using the following URLs:",
"privacy.v2.cookies.title": "Cookies",
"privacy.v2.cookies.intro.1": "Our websites doesn't use nor store any cookies in your browser."
"privacy.v2.cookies.intro.1": "Our websites doesn't use nor store any cookies in your browser.",
"privacy.v2.personal.title": "Personal Measures &amp; Convictions",
"privacy.v2.personal.disabled.intro": "While not required by any laws, we decided to improve your online privacy by disabling some features:",
"privacy.v2.personal.disabled.list.1": "Disabling hidden <a href=\"https://wikipedia.org/wiki/HTTP_referer\">HTTP Referer</a> system.",
"privacy.v2.personal.disabled.list.2": "Disabling Google's predatory <i>Topics API</i> and defunct <a href=\"https://www.eff.org/deeplinks/2021/03/googles-floc-terrible-idea\"><i>Cohort</i></a> ad-serving systems.",
"privacy.v2.personal.disabled.list.3": "Preventing any external third-party code from being injected into the page.",
"privacy.v2.personal.tracking.text.1": "It is our belief that the web and modern technology in general should never be used to track and spy on people in any way shape or form.",
"privacy.v2.personal.tracking.text.2": "We believe that any service that is in any way trying to force you to disable any ad-blocking or privacy-enhancing extensions should be avoided at all cost and shunned for their practices.",
"privacy.v2.personal.tracking.text.3": "Modern website should <b>never</b> break with those type of extensions unless they are purposefully built to track you to near-illegal extents, this excuse is only used to force you to accept these predatory practices.",
"_privacy.v2.personal.transparency.text.": "Additionally, we believe in the principles of transparency and openness [???]",
"privacy.v2.personal.recommendations": "We also strongly recommend you to read the <acronym title=\"European Union Agency for Cybersecurity\">ENISA</acronym>'s <i>Privacy considerations of online behavioural tracking report</i> in order to improve your online privacy."
}

View File

@@ -9,6 +9,7 @@
"sidebar.text.links": "Links",
"sidebar.text.downloads": "Downloads",
"sidebar.text.gitea": "Git Repos.",
"sidebar.text.wiki": "Wiki",
"sidebar.text.about": "About",
"sidebar.text.contact": "Contact"
}

View File

@@ -0,0 +1,9 @@
{
"about.head.title": "À-propos - NibblePoker",
"about.head.description": "TODO: description",
"about.og.title": "NibblePoker - À-propos",
"about.og.description": "TODO: description",
"about.header.title": "À-propos"
}

View File

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

View File

@@ -1,4 +1,5 @@
{
"footer.text.privacy": "Politique de confidentialité",
"footer.alt.sidebar.button": "Ouvrir et fermer le menu latéral de navigation.",
"footer.alt.logo": "Logo du site web"
}

View File

@@ -3,5 +3,17 @@
"home.head.description": "TODO: description",
"home.og.title": "NibblePoker",
"home.og.description": "TODO: description",
"home.header.title": "Page d'accueil"
"home.header.title": "Page d'accueil",
"home.showcase.title": "Vitrine",
"home.updates.title": "Updates",
"home.updates.text.privacy": "●&nbsp;&nbsp;Mise-à-jour de notre politique de confidentialité.",
"home.updates.2.date": "15 Août 2023",
"home.updates.2.text.1": "●&nbsp;&nbsp;Le site internet est à nouveau disponible.",
"home.updates.2.text.2": "●&nbsp;&nbsp;Mise en place d'un nouveau design plus léger.",
"home.updates.2.text.3": "●&nbsp;&nbsp;Changement d'hébergeur vers <a href=\"https://hostbrr.com/\">HostBrr</a>.",
"home.updates.2.text.4": "●&nbsp;&nbsp;Ajout d'une nouvelle section pour les outils.",
"home.updates.1.date": " 9 Septembre 2022",
"home.updates.1.text.1": "●&nbsp;&nbsp;Changement d'hébergeur vers v6Node."
}

View File

@@ -9,6 +9,7 @@
"sidebar.text.links": "Liens",
"sidebar.text.downloads": "Téléchargements",
"sidebar.text.gitea": "Dépôts Git",
"sidebar.text.wiki": "Wiki",
"sidebar.text.about": "À-propos",
"sidebar.text.contact": "Contact"
}

View File

@@ -0,0 +1,7 @@
{
"tools.head.title": "Outils - NibblePoker",
"tools.head.description": "TODO: description",
"tools.og.title": "NibblePoker - Outils",
"tools.og.description": "TODO: description",
"tools.header.title": "Outils"
}

48
compile.bat Normal file
View File

@@ -0,0 +1,48 @@
@echo off
cd /D "%~dp0"
:compile-lang
echo Compiling lang files...
python commons/strings/compile.py
:compile-sass
echo Compiling SASS files...
pushd %CD%
cd %~dp0\resources\NibblePoker\scss\
call "%~dp0node_modules\.bin\sass" nibblepoker.scss:../css/nibblepoker.css -q
call "%~dp0node_modules\.bin\sass" nibblepoker.scss:../css/nibblepoker.min.css -q --style compressed
popd
:compile-typescript
echo Compiling TypeScript for ".js" files...
call .\node_modules\.bin\tsc
:fix-typescript-imports
echo Fixing import paths for ".js" files manually...
node .\fix-import-path.js "tools/items/formula-wizard/code.js" "decimal" "decimal.min.mjs"
:minify-js
echo Minifying JS manually...
pushd %CD%
cd %~dp0\resources\DecimalJs\10.4.3\
echo ^> resources\DecimalJs\10.4.3\decimal.mjs
call "%~dp0node_modules\.bin\terser" decimal.mjs -c -m --toplevel -o decimal.min.mjs
cd %~dp0\resources\DecimalJsLight\2.5.1\
echo ^> resources\DecimalJsLight\2.5.1\decimal.mjs
call "%~dp0node_modules\.bin\terser" decimal.mjs -c -m --toplevel -o decimal.min.mjs
cd %~dp0\tools\items\formula-wizard\
echo ^> tools\items\formula-wizard\code.js
call "%~dp0node_modules\.bin\terser" code.js -c passes=9 --module --ecma 2019 --mangle --toplevel -o code.min.js
:: Due to the fact I used interfaces and because terser has its limits, I need to manually minify some properties.
:: It is done this way to avoid having to make some arcane incantations that may break if terser feels like it some day.
:: TODO: Make a post minifier
cd %~dp0\tools\items\b64-tools\
echo ^> tools\items\b64-tools\code.js
call "%~dp0node_modules\.bin\terser" code.js -c --module --ecma 2017 --mangle -o code.min.js
popd

View File

@@ -31,6 +31,13 @@ include 'commons/DOM/sidebar.php';
</header>
<main id="main" class="rl-m border border-r-0 p-l">
<?php printMainHeader(localize("contact.email.title"), "fad fa-mail-bulk", "herwin.bozet@gmail.com"); ?>
<p class="m-s">
<a href="mailto:Herwin Bozet<herwin.bozet@gmail.com>?subject=Contact%20via%20NibblePoker.lu" class="bland-link button-link">
<button class="p-xs r-s border b-light success"><?php print(localize("contact.email.compose")); ?></button>
</a>
</p>
<?php printMainHeader(localize("contact.twitter.title"), "fab fa-twitter", "@NibblePoker"); ?>
<p class="m-s">
<a href="https://twitter.com/messages/compose?recipient_id=937370791334895616" class="bland-link button-link">

View File

@@ -166,7 +166,7 @@
"parts": [
{
"type": "code", "indent": 2,
"modifiers": ["horizontal-scroll", "code-block"],
"modifiers": ["horizontal-scroll-auto", "code-block"],
"code": [
"lscom.exe [-a|--show-all] [-d|--show-device] [-D <str>|--divider <str>] [-f|--show-friendly]",
" [-h|--help] [-H|--short-help] [-n|--show-name-raw] [-P|--no-pretty] [-s|--sort]",
@@ -198,7 +198,7 @@
"parts": [
{
"type": "code", "indent": 2,
"modifiers": ["horizontal-scroll", "code-block"],
"modifiers": ["horizontal-scroll-auto", "code-block"],
"code": [
" *┬> No launch arguments:",
" └──> ${Raw name} => COM1",

View File

@@ -59,7 +59,7 @@
"parts": [
{
"type": "code", "indent": 2,
"modifiers": ["horizontal-scroll", "code-block"],
"modifiers": ["horizontal-scroll-auto-auto-auto-auto", "code-block"],
"code": [
"lscom.exe [-a|--show-all] [-d|--show-device] [-D <str>|--divider <str>] [-f|--show-friendly]",
" [-h|--help] [-n|--show-name-raw] [-P|--no-pretty] [-s|--sort] [-S|--sort-reverse]",
@@ -90,7 +90,7 @@
"parts": [
{
"type": "code", "indent": 2,
"modifiers": ["horizontal-scroll", "code-block"],
"modifiers": ["horizontal-scroll-auto-auto-auto-auto", "code-block"],
"code": [
" *┬> No launch arguments:",
" └──> ${Raw name} => COM1",

54
fix-import-path.js Normal file
View File

@@ -0,0 +1,54 @@
const fs = require("fs");
const path = require("path");
// Grabbing launch arguments
if(process.argv.length !== 5) {
console.error('!> Invalid syntax !');
console.error('Use: node fix-import-path.js <input_file> <import_name> <replacement_file>');
process.exit(1);
}
const inputFile = process.argv[2];
const inputImportName = process.argv[3];
const inputReplacement = process.argv[4];
let filesToProcess = [inputFile];
// Fixing the files
for(const fileToProcess of filesToProcess) {
console.log("> Replacing '"+inputImportName+"' with '"+inputReplacement+"' in '"+fileToProcess+"' ...");
const inputFileLines = fs.readFileSync(fileToProcess).toString().split("\n");
if(inputFileLines == null) {
console.error('!> Failed to read lines !');
process.exit(2);
}
const outputFileLines = [];
for(let inputLine of inputFileLines) {
if(inputLine.startsWith("import") && inputLine.includes("from")) {
inputLine = inputLine.split(/['"]+/);
// inputLine is now an array !
//console.log(inputLine);
inputLine[inputLine.length - 2] = inputLine[inputLine.length - 2].replace(
inputImportName, inputReplacement
);
inputLine = inputLine.join("\"");
}
outputFileLines.push(inputLine);
}
try {
fs.unlinkSync(fileToProcess);
fs.writeFileSync(fileToProcess, outputFileLines.join("\n"), "utf8");
} catch(err) {
console.error(err);
}
}

1
fix-import-path.min.js vendored Normal file
View File

@@ -0,0 +1 @@
const fs=require("fs"),path=require("path"),inputFile=(5!==process.argv.length&&(console.error("!> Invalid syntax !"),console.error("Use: node fix-import-path.js <input_file> <import_name> <replacement_file>"),process.exit(1)),process.argv[2]),inputImportName=process.argv[3],inputReplacement=process.argv[4];let filesToProcess=[inputFile];for(const a of filesToProcess){console.log("> Replacing '"+inputImportName+"' with '"+inputReplacement+"' in '"+a+"' ...");const b=fs.readFileSync(a).toString().split("\n"),c=(null==b&&(console.error("!> Failed to read lines !"),process.exit(2)),[]);for(let e of b)e.startsWith("import")&&e.includes("from")&&((e=e.split(/['"]+/))[e.length-2]=e[e.length-2].replace(inputImportName,inputReplacement),e=e.join('"')),c.push(e);try{fs.unlinkSync(a),fs.writeFileSync(a,c.join("\n"),"utf8")}catch(e){console.error(e)}}

View File

@@ -3,6 +3,9 @@ $start_time = microtime(true);
set_include_path('./');
include_once 'commons/config.php';
include_once 'commons/langs.php';
// Page-specific config
$enable_glider = true;
?>
<!DOCTYPE html>
<html lang="<?php echo($user_language); ?>">
@@ -35,45 +38,30 @@ include 'commons/DOM/sidebar.php';
<p class="mt-xs ml-s"><?php print(localize("home.intro.text.1")); ?></p>
<p class="mt-xs ml-s"><?php print(localize("home.intro.text.2")); ?></p>
<?php printMainHeader("Applications"); ?>
<!-- If 'r-*' is used, 'o-hidden' needs to be too => https://stackoverflow.com/a/8582304 -->
<table class="stylish w-full mt-xs table-p-xs r-s o-hidden border">
<thead>
<tr>
<th>Version</th>
<th>Downloads</th>
<th>Downloads</th>
</tr>
</thead>
<tbody>
<tr>
<td>C11</td>
<td>C12</td>
<td>C13</td>
</tr>
<tr>
<td>C21</td>
<td>C22</td>
<td>C23</td>
</tr>
</tbody>
</table>
<?php printMainHeader(localize("home.showcase.title")); ?>
<div class="mt-xs mx-s">
<div class="glider">
<img src="/resources/NibblePoker/images/content/lscom/lscom-legacy-simple.png" alt="test123">
<img src="/resources/NibblePoker/images/content/lscom/lscom-legacy-simple.png" alt="test123">
<img src="/resources/NibblePoker/images/content/lscom/lscom-legacy-simple.png" alt="test123">
<img src="/resources/NibblePoker/images/content/lscom/lscom-legacy-simple.png" alt="test123">
</div>
</div>
<?php printMainHeader("Testing"); ?>
<p class="mt-xs ml-s"><?php print(localize("home.intro.text.1")); ?></p>
<br>
<button class="p-xs border r-s">aaa</button>
<br>
<input class="p-xs border r-s" type="text">
<br>
<?php printMainHeader(localize("home.intro.title")); ?>
<p class="mt-xs ml-s">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed <span class="code">do eiusmod tempor</span> incididunt ut labore et dolore magna aliqua.<br>
Mauris ultrices eros in cursus turpis massa tincidunt dui.<br>
Pulvinar elementum integer enim neque. Nunc mi ipsum faucibus vitae aliquet nec.
</p>
<?php printMainHeader(localize("home.updates.title")); ?>
<p class="mt-xs ml-s t-w-600"><i class="fad fa-calendar-alt mr-xs"></i><?php print(localize("home.updates.2.date")); ?></p>
<p class="mt-xxs ml-m">
<?php print(localize("home.updates.2.text.1")); ?><br>
<?php print(localize("home.updates.2.text.2")); ?><br>
<?php print(localize("home.updates.2.text.3")); ?><br>
<?php print(localize("home.updates.2.text.4")); ?><br>
<?php print(localize("home.updates.text.privacy")); ?>
</p>
<p class="mt-s ml-s t-w-600"><i class="fad fa-calendar-alt mr-xs"></i><?php print(localize("home.updates.1.date")); ?></p>
<p class="mt-xxs ml-m">
<?php print(localize("home.updates.1.text.1")); ?><br>
<?php print(localize("home.updates.text.privacy")); ?>
</p>
</main>
<?php
include 'commons/DOM/footer.php';

120
links/index.bak.php Normal file
View File

@@ -0,0 +1,120 @@
<?php
set_include_path('../commons/');
include_once 'config.php';
include_once 'langs.php';
?>
<!DOCTYPE html>
<html lang="<?php echo($user_language); ?>">
<head>
<?php include 'headers.php'; ?>
<title>Links - Nibble Poker</title>
<meta name="description" content="A collection of links to all the other locations we are active on.">
<meta property="og:title" content="Nibble Poker - Links" />
<meta property="og:type" content="website" />
<meta property="og:url" content="<?php echo($host_uri); ?>/" />
<meta property="og:image" content="<?php echo($host_uri); ?>/resources/Azias/logos/v2_opengraph.png"/>
<meta property="og:image:type" content="image/png"/>
<meta property="og:description" content="A collection of links to all the other locations we are active on."/>
</head>
<body class="with-custom-webkit-scrollbars with-custom-css-scrollbars dark-mode" data-dm-shortcut-enabled="true" data-sidebar-shortcut-enabled="true">
<?php include 'body-root.php'; ?>
<div class="page-wrapper with-sidebar with-navbar-fixed-bottom">
<?php $SIDEBAR_ID = 'links'; include 'sidebar.php'; ?>
<div class="content-wrapper">
<div class="container-fluid">
<div id="page-title-bar" class="card p-0 pl-20 m-0 square-corners bg-very-dark title-bkgd navbar">
<h2 class="content-title font-size-24 mt-20 text-truncate">
<i class="fad fa-link"></i>&nbsp;<?php print(localize("links.title")); ?>
</h2>
<?php include 'header-lang.php'; ?>
</div>
<div class="content mx-auto w-lg-p90">
<div class="card p-0 mx-0">
<div class="px-card py-10 border-bottom px-20">
<div class="container-fluid">
<div class="row">
<div class="col-5 col-lg-12">
<h2 class="card-title font-size-18 m-0">
<i class="fab fa-github"></i>&nbsp;&nbsp;GitHub
</h2>
</div>
<div class="col-7 hidden-lg-and-up text-right font-italic">
<h2 class="card-title font-size-18 m-0 text-super-muted">aziascreations</h2>
</div>
</div>
</div>
</div>
<!--<div class="content mx-15 my-15"><p>[Contains the most recent repositories and blablabla...]</p>
</div>-->
<div class="px-card py-10 bg-light-lm bg-very-dark-dm rounded-bottom px-20">
<p class="font-size-12 m-0">
<i class="fad fa-globe"></i> https://github.com/aziascreations
<a class="ml-20" href="https://github.com/aziascreations">
<span class="badge badge-primary">
<?php print(localize('links.visit.button')); ?>
</span>
</a>
</p>
</div>
</div>
<div class="card p-0 mx-0">
<div class="px-card py-10 border-bottom px-20">
<div class="container-fluid">
<div class="row">
<div class="col-5 col-lg-12">
<h2 class="card-title font-size-18 m-0">
<i class="fab fa-twitter"></i>&nbsp;&nbsp;Twitter
</h2>
</div>
<div class="col-7 hidden-lg-and-up text-right font-italic">
<h2 class="card-title font-size-18 m-0 text-super-muted">@nibblepoker</h2>
</div>
</div>
</div>
</div>
<div class="px-card py-10 bg-light-lm bg-very-dark-dm rounded-bottom px-20">
<p class="font-size-12 m-0">
<i class="fad fa-globe"></i> https://twitter.com/NibblePoker
<a class="ml-20" href="https://twitter.com/NibblePoker">
<span class="badge badge-primary">
<?php print(localize('links.visit.button')); ?>
</span>
</a>
</p>
</div>
</div>
<div class="card p-0 mx-0">
<div class="px-card py-10 border-bottom px-20">
<div class="container-fluid">
<div class="row">
<div class="col-5 col-lg-12">
<h2 class="card-title font-size-18 m-0">
<i class="fab fa-linkedin"></i>&nbsp;&nbsp;LinkedIn
</h2>
</div>
<div class="col-7 hidden-lg-and-up text-right font-italic">
<h2 class="card-title font-size-18 m-0 text-super-muted">NibblePoker</h2>
</div>
</div>
</div>
</div>
<div class="px-card py-10 bg-light-lm bg-very-dark-dm rounded-bottom px-20">
<p class="font-size-12 m-0">
<i class="fad fa-globe"></i> https://www.linkedin.com/in/herwin-bozet-60aa6310b/
<a class="ml-20" href="https://www.linkedin.com/in/herwin-bozet-60aa6310b/">
<span class="badge badge-primary">
<?php print(localize('links.visit.button')); ?>
</span>
</a>
</p>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
</div>
<script src="/resources/HalfMoon/1.1.1/js/halfmoon.min.js"></script>
<script src="/resources/Azias/js/nibblepoker.lu.js"></script>
</body>
</html>

9
package.json Normal file
View File

@@ -0,0 +1,9 @@
{
"devDependencies": {
"minify": "^10.2.0",
"rollup": "^3.26.2",
"sass": "^1.63.6",
"terser": "^5.19.0",
"typescript": "^5.1.6"
}
}

View File

@@ -109,9 +109,41 @@ include 'commons/DOM/sidebar.php';
</p>
<?php printMainHeader(localize("privacy.v2.cookies.title"), "fad fa-cookie-bite"); ?>
<p class="mt-xs ml-s">
<p class="mt-xs ml-s">
<?php print(localize('privacy.v2.cookies.intro.1')); ?>
</p>
</p>
<?php printMainHeader(localize("privacy.v2.personal.title"), "fad fa-fist-raised"); ?>
<p class="mt-xs ml-s">
<?php print(localize('privacy.v2.personal.disabled.intro')); ?>
<br>
<span class="ml-s">
<i class="fad fa-circle t-size-6"></i>&nbsp;&nbsp;<?php print(localize('privacy.v2.personal.disabled.list.1')); ?>
</span>
<br>
<span class="ml-s">
<i class="fad fa-circle t-size-6"></i>&nbsp;&nbsp;<?php print(localize('privacy.v2.personal.disabled.list.2')); ?>
</span>
<br>
<span class="ml-s">
<i class="fad fa-circle t-size-6"></i>&nbsp;&nbsp;<?php print(localize('privacy.v2.personal.disabled.list.3')); ?>
</span>
</p>
<p class="mt-s ml-s">
<?php print(localize('privacy.v2.personal.tracking.text.1')); ?><br>
<?php print(localize('privacy.v2.personal.tracking.text.2')); ?><br>
<?php print(localize('privacy.v2.personal.tracking.text.3')); ?>
</p>
<p class="mt-s ml-s">
<?php print(localize('privacy.v2.personal.transparency.text.1')); ?>
</p>
<p class="mt-s ml-s">
<?php print(localize('privacy.v2.personal.recommendations')); ?>
<br>
<i class="fad fa-globe ml-s t-size-8"></i>
<a href="https://www.enisa.europa.eu/publications/privacy-considerations-of-online-behavioural-tracking">https://www.enisa.europa.eu/publications/privacy-considerations-of-online-behavioural-tracking</a>
<span class="ml-s">(<?php print(localize('lang.english')); ?>)</span>
</p>
<?php printMainHeader(localize("privacy.v2.update.title"), "fad fa-sync-alt"); ?>
<p class="mt-xs ml-s">
@@ -191,14 +223,10 @@ include 'commons/DOM/sidebar.php';
<p class="mt-s ml-s">
<?php print(localize('privacy.complaint.text.2')); ?><br>
<i class="fad fa-globe t-size-8 ml-s"></i>
<a href="https://ec.europa.eu/info/law/law-topic/data-protection/reform/rights-citizens/redress/what-should-i-do-if-i-think-my-personal-data-protection-rights-havent-been-respected_en">
https://ec.europa.eu/
</a>
<a href="https://ec.europa.eu/info/law/law-topic/data-protection/reform/rights-citizens/redress/what-should-i-do-if-i-think-my-personal-data-protection-rights-havent-been-respected_en">https://ec.europa.eu/</a>
<span class="ml-s">(<?php print(localize('lang.english')); ?>)</span><br>
<i class="fad fa-globe t-size-8 ml-s"></i>
<a href="https://gegevensbeschermingsautoriteit.be/citoyen/agir/introduire-une-plainte">
https://gegevensbeschermingsautoriteit.be/
</a>
<a href="https://gegevensbeschermingsautoriteit.be/citoyen/agir/introduire-une-plainte">https://gegevensbeschermingsautoriteit.be/</a>
<span class="ml-s">(<?php print(localize('lang.french')); ?>)</span><br>
</p>

View File

@@ -2,17 +2,20 @@
???
## Preamble
This repository is only a mirror and should never be cloned and served as-is.
This repository is only a mirror and should never be cloned and served as-is since it's missing some
components.
The [.htaccess](.htaccess) file has been made public **on purpose** since it does not contain any
private information and because it could be used by other people to create their website more easily
since these configuration files are a nightmare to work with.<br>
Especially with redirections to handle language changes and whatnot.
The [.htaccess](.htaccess) files has been made public **on purpose** since they don't contain any
private information and because they could be used by other people to create their website more easily.
## Content
### Blog
## Features
### Content
Unfinished, but all the files should be contained in the `content/` folder.
### Composer
### Tools
### Honeypot & Tarpits
There are a couple of files in the `honeypot/` and `tarpit/` folders that are used
to serve some basic fake files and pages that are often requested by automated scanners in order
@@ -28,7 +31,9 @@ These files are required and need to be installed manually for the website to wo
* Font Awesome Pro v5.15.3
* `/resources/FontAwesomePro/`
* Highlight.js v11.6.0
* `/resources/HighlightJS/`
* `/resources/HighlightJS/`
* Glider.js v1.7.6
* `/resources/GliderJs/`
## Licenses
@@ -37,8 +42,6 @@ Here is a list of the licenses for any third-party thing included in this reposi
* [Quantum Font](https://sesohq.sellfy.store/p/3enu/) by [sesohq](https://www.sesohq.com/)
* Free font with no apparent usage restrictions.
* [GliderJS](https://nickpiscitelli.github.io/Glider.js/)
* Uses the [MIT license](https://github.com/NickPiscitelli/Glider.js/blob/master/LICENSE.txt)
All licenses are also included as-is in their project's respective folder.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -1,7 +1,11 @@
// Creating the galleries from Glider.js
window.addEventListener('load', function(){
document.querySelectorAll(".glider").forEach(element => {
new Glider(element, {
console.debug("Creating glider...");
console.debug(element);
let glider = new Glider(element, {
slidesToShow: 1,
draggable: true,
scrollLock: true,
@@ -27,6 +31,7 @@ window.addEventListener('load', function(){
}
]
});
console.debug(glider);
// Processing the images
const eImages = [];

View File

@@ -69,13 +69,14 @@ document.addEventListener("DOMContentLoaded", () => {
//showContentModal(eContentModal);
[eContentModal, document.getElementById("modal-content-cross"), eContentModalInner].forEach(value => {
value.onclick = function() {
fadeOut(eContentModal, 175).then(r => {
eContentModalInner.innerHTML = "";
});
}
})
// FIXME: Fix this shit !
//[eContentModal, document.getElementById("modal-content-cross"), eContentModalInner].forEach(value => {
// value.onclick = function() {
// fadeOut(eContentModal, 175).then(r => {
// eContentModalInner.innerHTML = "";
// });
// }
//})
// TODO: Autodetect mobile screens, close it, and add classes to make it over the rest with dark modal bkgd.
});

View File

@@ -12,18 +12,25 @@
}
.border {
border: 1px solid #{$color-border-all};
border: 1px solid;
&.b-light {
border: 1px solid #{$color-border-light};
}
//&.b-light {
// border: 1px solid #{$color-border-light};
//}
}
* {
.dark-mode & {
border-color: #{$color-border-all};
}
}
//main {
// .border {
// border: 1px solid #{$color-border-main};
// }
//}
//* {
// .dark-mode & {
// border-color: #{$color-border-all};
// }
//}
@include border-maker("t", "top");
@include border-maker("b", "bottom");

View File

@@ -49,6 +49,9 @@
.flex-align-center {
align-items: center;
}
.flex-align-start {
align-items: flex-start;
}
// Missing: start | end

View File

@@ -6,6 +6,9 @@
.w-full {
width: 100%;
}
.wm-full {
max-width: 100%;
}
.h-full {
height: 100%;

View File

@@ -14,6 +14,7 @@
/* Utilities > Spacing > Sided > Variable Sizes */
//@include axis-spacing-maker("m", "margin", "xxs", calc(#{$margin-base-size} * 0.25));
@include axis-spacing-maker("m", "margin", "xs", calc(#{$margin-base-size} * 0.5));
@include axis-spacing-maker("m", "margin", "s", calc(#{$margin-base-size} * 0.75));
@include axis-spacing-maker("m", "margin", "m", #{$margin-base-size});

View File

@@ -18,6 +18,7 @@
/* Utilities > Spacing > Sided > Variable Sizes */
@include sided-spacing-maker("m", "margin", "xxs", calc(#{$margin-base-size} * 0.25));
@include sided-spacing-maker("m", "margin", "xs", calc(#{$margin-base-size} * 0.5));
@include sided-spacing-maker("m", "margin", "s", calc(#{$margin-base-size} * 0.75));
@include sided-spacing-maker("m", "margin", "m", #{$margin-base-size});

View File

@@ -0,0 +1,3 @@
/*# sourceMappingURL=borders.css.map */

View File

@@ -0,0 +1 @@
/*# sourceMappingURL=borders.min.css.map */

View File

@@ -12,7 +12,7 @@
@import 'config';
/* Externals */
@import 'external/reset';
@import 'external/reset'; // Not resetting it for checkboxes !
@import 'external/quantum';
/* Variables */
@@ -46,8 +46,10 @@
@import 'site/scrollbar';
@import 'site/input'; // Has ugly fix for download buttons
@import 'site/table'; // Uses copied paddings for cells & ugly rounding fix
@import 'site/code'; // Uses forced borders, roundings and paddings
/* Site > Misc */
@import 'site/borders'; // Applies the colors mostly, the size are in the elements !
@import 'site/backgrounds';
/* Site > Fixes */
@@ -56,7 +58,6 @@
/* Site > Unsorted */
@import 'site/image';
@import 'site/wedge';
@import 'site/code'; // Uses copied borders, roundings and paddings
@import 'site/content'; // Uses fixed sizes and floats
@import 'site/video';
@import 'site/modal';

View File

@@ -0,0 +1,36 @@
.border, code, .code, kbd {
border-color: #{$color-border-surround};
//&.b-light {
// border: 1px solid #{$color-border-light};
//}
}
code, .code, kbd {
border-color: #{$color-border-code};
}
main {
.border {
border-color: #{$color-border-main};
//&.b-light {
// border: 1px solid #{$color-border-light};
//}
}
}
table.stylish {
// Fixing border issues when using rounded corners by using a "fake" one using the background's color.
// It will look like utter shit when rounded on firefox because its rendering engine cannot clip rounded corners apparently.
// I guess that's what being at less than 3% of the market share does to you and your ability to care about basic shit.
&.border {
background-color: #{$color-border-main};
}
}
// Special fix for select inputs' dropdown menu
//select.border option::before {
// border: 1px solid deeppink !important;
//}

View File

@@ -13,7 +13,7 @@ code {
.code, kbd {
background-color: #{$color-background-code};
border: 1px solid #{$color-border-code};
border: 1px solid;
// Using '.r-s'
border-radius: calc(#{$border-base-radius} * 0.75);

View File

@@ -4,7 +4,7 @@
/* Site > Elements > Inputs > Commons */
button, input {
button, input, textarea, select {
border: 0;
// Removing ugly-ass white glow when editing text-related inputs.
@@ -19,6 +19,37 @@ button, input {
box-shadow: 0px 0px 3px 0px #{$color-input-glow};
}
}
&:disabled {
cursor: not-allowed;
}
}
label {
cursor: pointer;
user-select: none;
}
/* Site > Elements > Inputs > Checkbox */
input[type=checkbox] {
width: 1.65em;
height: 1.65em;
background-color: #{$color-background-checkbox-unchecked};
cursor: pointer;
&:checked {
background-color: #{$color-background-checkbox-checked};
}
position: relative;
vertical-align: middle;
}
input[type="checkbox"] + label {
position: relative;
display: inline-block;
vertical-align: middle;
}
/* Site > Elements > Inputs > Buttons */
@@ -38,6 +69,30 @@ button {
background-color: #{$color-background-button-primary-hover};
}
}
&.success {
background-color: #{$color-background-button-success};
&:hover {
background-color: #{$color-background-button-success-hover};
}
}
&.error {
background-color: #{$color-background-button-error};
&:hover {
background-color: #{$color-background-button-error-hover};
}
}
&.warning {
background-color: #{$color-background-button-warning};
&:hover {
background-color: #{$color-background-button-warning-hover};
}
}
}
// Ugly fix for download buttons
@@ -75,4 +130,11 @@ button + button, .button-link + .button-link > button {
//&[open] > div {
// height: auto;
//}
}
textarea {
&.no-resize {
resize: none;
}
}

View File

@@ -25,12 +25,7 @@ table.stylish {
border-right: 1.5px solid #{$color-table-border};
}
// Fixing border issues when using rounded corners by using a "fake" one using the background's color.
// It will look like utter shit when rounded on firefox because its rendering engine cannot clip rounded corners apparently.
// I guess that's what being at less than 3% of the market share does to you and your ability to care about basic shit.
&.border {
background-color: #{$color-border-all};
}
// See 'site/border.scss' for border fix.
}
// Applying .p-xs and .p-s to all cells if needed
@@ -53,6 +48,7 @@ table.stylish {
}
}
// Centers the cells' content vertically
.table-v-center {
tr, td {
vertical-align: middle;

View File

@@ -4,7 +4,7 @@
/* Site > Text > Commons */
p, a, h1, h2, h3, h4, h5, h6, td, th, .code, summary {
p, a, h1, h2, h3, h4, h5, h6, td, th, .code, summary, label {
color: #{$color-text-regular-normal};
}

View File

@@ -63,13 +63,155 @@ $color-apollo-custom-20: mix($color-apollo-39, $color-apollo-38, 60%);
$color-apollo-custom-30: mix($color-apollo-01, $color-apollo-03, 80%); // Primary button
$color-apollo-custom-31: mix($color-apollo-01, $color-apollo-03, 65%); // Primary button hover
//$color-test-01: mix(#7b6aa5, #000000, 33%);
$color-test-02: #007c7d;
/* Variables > Palettes > Material UI */
// https://materialui.co/colors
/* Variables > Colors */
$color-material-blueGrey-50: #eceff1;
$color-material-blueGrey-100: #cfd8dc;
$color-material-blueGrey-200: #b0bec5;
$color-material-blueGrey-300: #90a4ae;
$color-material-blueGrey-400: #78909c;
$color-material-blueGrey-500: #607d8b;
$color-material-blueGrey-600: #546e7a;
$color-material-blueGrey-700: #455a64;
$color-material-blueGrey-800: #37474f;
$color-material-blueGrey-900: #263238;
$color-material-blueGrey-1000: #151D21;
$color-material-blueGrey-850: mix($color-material-blueGrey-800, $color-material-blueGrey-900, 50%);
//$color-material-blueGrey-925: mix($color-material-blueGrey-1000, $color-material-blueGrey-900, 25%);
$color-material-blueGrey-950: mix($color-material-blueGrey-1000, $color-material-blueGrey-900, 50%);
/* Variables > Palettes > WinUI 3 */
$color-winui-00: #191919;
$color-winui-01: #1D1D1D;
$color-winui-02: #202020;
$color-winui-03: #232323;
$color-winui-04: #272727;
$color-winui-05: #323232;
$color-winui-06: #3E3E3E;
// https://flatuicolors.com/palette/defo
/* Variables > Palettes > Misc */
//$color-test-01: mix(#7b6aa5, #000000, 33%);
//$color-test-02: #007c7d;
/* Variables > Colors Mappings */
$color-unset: $color-apollo-34;
//$color-unset: deeppink;
/* Variables > Theme selection */
// Available themes:
// * Teal Supreme (teal)
// * WinUI 3 (winui)
// * La Moiti Leune (moon)
$theme: teal;
/* Variables > Colors Mappings > Backgrounds & Borders */
$color-background-body: map-get((
teal: $color-apollo-custom-00,
winui: $color-winui-02,
moon: $color-unset,
), $theme);
$color-background-main: map-get((
teal: $color-apollo-custom-02,
winui: $color-winui-04,
moon: $color-unset,
), $theme);
$color-background-surround: map-get((
teal: $color-apollo-custom-00,
winui: $color-winui-02,
moon: $color-unset,
), $theme);
// FIXME: Remove its usage !
// Left: Code, Kbd, Scrollbar ???
$color-border-all: $color-unset; // Default border
$color-border-light: $color-unset; // For .b-light class (No longer exists !)
$color-border-surround: map-get((
teal: $color-apollo-38,
winui: $color-winui-01,
moon: $color-unset,
), $theme);
$color-border-main: map-get((
teal: $color-apollo-38, // $color-apollo-custom-20;
winui: $color-winui-03,
moon: $color-unset,
), $theme);
$color-background-main-headings: map-get((
teal: $color-apollo-custom-03,
winui: $color-unset,
moon: $color-unset,
), $theme);
$color-background-code: map-get((
teal: $color-apollo-custom-20,
winui: $color-unset,
moon: $color-unset,
), $theme);
$color-border-code: map-get((
teal: #{$color-border-surround}CF,
winui: $color-unset,
moon: $color-unset,
), $theme);
$color-background-table-main: map-get((
teal: $color-apollo-custom-01,
winui: $color-unset,
moon: $color-unset,
), $theme);
$color-background-table-dual: map-get((
teal: $color-apollo-custom-00,
winui: $color-unset,
moon: $color-unset,
), $theme);
$color-table-border: map-get((
teal: $color-apollo-39,
winui: $color-unset,
moon: $color-unset,
), $theme);
$color-background-inputs: $color-apollo-40;
$color-background-checkbox-checked: $color-apollo-08;
$color-background-checkbox-unchecked: $color-apollo-27;
$color-background-button: $color-apollo-40;
$color-background-button-hover: $color-apollo-custom-10;
$color-background-button-primary: #{$color-apollo-custom-30};
$color-background-button-primary-hover: #{$color-apollo-custom-31};
$color-background-button-success: #{$color-apollo-07};
$color-background-button-success-hover: #{$color-apollo-08};
$color-background-button-error: #{$color-apollo-26};
$color-background-button-error-hover: #{$color-apollo-27};
$color-background-button-warning: #{$color-apollo-20};
$color-background-button-warning-hover: #{$color-apollo-21};
/* Variables > Colors Mappings > Text */
$color-text-regular-normal: $color-apollo-45;
$color-text-inputs: $color-apollo-45;
@@ -82,8 +224,8 @@ $color-link-hover: rgb(253, 255, 251);
$color-link-blue: #{$color-apollo-04};
$color-link-blue-hover: #{$color-apollo-05};
$color-border-all: $color-apollo-38;
$color-border-light: $color-apollo-custom-20;
//$color-border-all: $color-apollo-38;
//$color-border-light: $color-apollo-custom-20;
$color-input-glow: $color-apollo-02;
@@ -91,56 +233,13 @@ $color-wedge-blue-background: $color-apollo-03;
$color-wedge-blue-border: $color-apollo-02;
//$color-background-body: $color-apollo-custom-00;
//$color-background-main: $color-apollo-39;
////$color-background-surround: $color-apollo-40;
//$color-background-main: $color-apollo-custom-02;
//$color-background-surround: $color-apollo-custom-00;
$color-background-body: $color-apollo-custom-00;
$color-background-main: $color-apollo-custom-02;
$color-background-surround: $color-apollo-custom-00;
// TMP
//$color-background-main: mix(#333c57, #566c86, 60%);
//$color-background-surround: mix(#333c57, #566c86, 80%);
//$color-background-main-headings: $color-apollo-40;
$color-background-main-headings: $color-apollo-custom-03;
$color-background-code: #{$color-apollo-custom-20};
$color-border-code: #{$color-border-all}CF;
$color-background-table-main: $color-apollo-custom-01;
$color-background-table-dual: $color-apollo-custom-00;
//$color-table-border: $color-apollo-41;
$color-table-border: $color-apollo-39;
$color-background-inputs: $color-apollo-40;
$color-background-button: $color-apollo-40;
$color-background-button-hover: $color-apollo-custom-10;
$color-background-button-primary: #{$color-apollo-custom-30};
$color-background-button-primary-hover: #{$color-apollo-custom-31};
$_color-white-lighter: rgb(253, 255, 251);
$_color-white-light: rgb(235, 237, 233);
$_color-white-medium: rgb(217, 222, 218);
$_color-white-dark: rgb(199, 207, 204);
$_color-black-lighter: rgb(43, 46, 51);
$_color-black-light: rgb(37, 40, 45);
$_color-black-medium: rgb(31, 34, 39);
$_color-black-dark: rgb(25, 28, 32);
$_color-black-full: rgb(13, 14, 26);
$_color-text-white-065: rgba(255, 255, 255, 0.65);
$_color-text-white-075: rgba(255, 255, 255, 0.75);
$_color-text-white-085: rgba(255, 255, 255, 0.85);
$_color-blue-light: #4f6dce;
$_color-blue-medium: #3b5dc8;
$_color-blue-dark: #3353b6;
$_color-white-muted: #FFFFFF96;
//rgba(255, 255, 255, 0.6)
//
//// TMP V2
//$color-background-body: $color-material-blueGrey-900;
//$color-background-main: $color-material-blueGrey-950;
//$color-background-surround: $color-material-blueGrey-900;
/* Variables > Scrollbar */

View File

@@ -6,11 +6,39 @@
"fr": "Convertisseur SVG vers PNG"
},
"preamble": {
"en": "",
"fr": ""
"en": "TODO: Description",
"fr": "TODO: Description"
},
"_image": "",
"tags": ["converter", "svg", "png"],
"priority": 100
},
{
"id": "formula-wizard",
"title": {
"en": "Formula Wizard",
"fr": "Ensorceleur de formules"
},
"preamble": {
"en": "TODO: Description",
"fr": "TODO: Description"
},
"_image": "",
"tags": ["converter"],
"priority": 200
},
{
"id": "b64-tools",
"title": {
"en": "Base64 Tools",
"fr": "Outils pour Base64"
},
"preamble": {
"en": "TODO: Description",
"fr": "TODO: Description"
},
"_image": "",
"tags": ["converter"],
"priority": 210
}
]

View File

@@ -55,15 +55,44 @@ if($contentManager->hasError) {
<!DOCTYPE html>
<html lang="<?php echo($user_language); ?>">
<head>
<?php include 'commons/DOM/head.php'; ?>
<title><?php print(localize('tools.head.title')); ?></title>
<meta name="description" content="<?php print(localize('tools.head.description')); ?>">
<meta property="og:title" content="<?php print(localize('tools.og.title')); ?>"/>
<meta property="og:type" content="website"/>
<?php
include 'commons/DOM/head.php';
// Preparing values for the head's tags.
if($contentManager->displayType == ContentDisplayType::SEARCH) {
$tool_head_title = localize('tools.head.description');
$tool_head_description = localize('tools.head.description');
$tool_head_og_title = localize('tools.og.title');
$tool_head_og_description = localize('tools.og.description');
$tool_head_og_image_url = $host_uri . "/resources/NibblePoker/images/logos/v2_opengraph.png";
$tool_head_og_image_type = "image/png";
$tool_head_og_type = "website";
} elseif($contentManager->displayType == ContentDisplayType::CONTENT) {
$tool_head_title = $toolInfo->openGraphData->title;
$tool_head_description = $toolInfo->openGraphData->description;
$tool_head_og_title = $toolInfo->openGraphData->title;
$tool_head_og_description = $toolInfo->openGraphData->description;
$tool_head_og_image_url = $host_uri . $toolInfo->openGraphData->image;
$tool_head_og_image_type = $toolInfo->openGraphData->image_type;
$tool_head_og_type = $toolInfo->openGraphData->type;
}
?>
<title><?php echo($tool_head_title); ?></title>
<meta name="description" content="<?php echo($tool_head_description); ?>">
<meta property="og:title" content="<?php echo($tool_head_og_title); ?>"/>
<meta property="og:type" content="<?php echo($tool_head_og_type); ?>"/>
<meta property="og:url" content="<?php echo($host_uri . l10n_url_abs('/')); ?>"/>
<meta property="og:image" content="<?php echo($host_uri); ?>/resources/NibblePoker/images/logos/v2_opengraph.png"/>
<meta property="og:image:type" content="image/png"/>
<meta property="og:description" content="<?php print(localize('tools.og.description')); ?>"/>
<meta property="og:image" content="<?php echo($tool_head_og_image_url); ?>"/>
<meta property="og:image:type" content="<?php echo($tool_head_og_image_type); ?>"/>
<meta property="og:description" content="<?php echo($tool_head_og_description); ?>"/>
<?php
if(!$contentManager->hasError && $contentManager->displayType == ContentDisplayType::CONTENT) {
foreach($toolInfo->styleFilesPaths as $styleFilePath) {
echo('<link rel="stylesheet" href="'.substr($styleFilePath, strlen($dir_root)).'">');
}
}
?>
</head>
<body>
<?php
@@ -165,9 +194,12 @@ include 'commons/DOM/scripts.php';
// Including the tool's scripts if required.
if(!$contentManager->hasError && $contentManager->displayType == ContentDisplayType::CONTENT) {
foreach($toolInfo->codeFilesPaths as $codeFilePath) {
foreach($toolInfo->codeFilesPaths as $codeFilePath) {
echo('<script src="'.substr($codeFilePath, strlen($dir_root)).'"></script>');
}
}
foreach($toolInfo->moduleFilesPaths as $moduleFilePath) {
echo('<script src="'.substr($moduleFilePath, strlen($dir_root)).'" type="module"></script>');
}
}
?>
</body>

View File

@@ -0,0 +1,25 @@
{
"dom": "b64-tools/page.php",
"lang": "b64-tools/lang.json",
"code": [],
"module": [
"b64-tools/code.min.js"
],
"styles": [],
"icon": "fad fa-magic",
"title": "tool.b64-tools.title",
"opengraph": {
"title": {
"en": "Base64 Tools",
"fr": "Outils pour Base64"
},
"description": {
"en": "TODO: Description",
"fr": "TODO: Description"
},
"type": "website",
"url": "https://nibblepoker.lu/tools/b64-tools",
"image": "/resources/NibblePoker/images/placeholder.png",
"image_type": "image/png"
}
}

View File

@@ -0,0 +1,112 @@
"use strict";
const langKey = document.documentElement.lang.match("(en|fr)") ? document.documentElement.lang : "en";
const langData = {
en: {
"alert.textarea.missing.text": "The 'TextArea' element for text is missing !",
"alert.textarea.missing.b64": "The 'TextArea' element for base64 is missing !",
"alert.textarea.mismatch.text": "The 'TextArea' element for text isn't declared as a 'TextArea'!",
"alert.textarea.mismatch.b64": "The 'TextArea' element for base64 isn't declared as a 'TextArea'!",
"alert.other.missing": "An element is missing from the page !",
"alert.other.mismatch": "An element is no declared with the proper element type !",
},
fr: {
"alert.textarea.missing.text": "L'élément 'TextArea' pour le texte est introuvable !",
"alert.textarea.missing.b64": "L'élément 'TextArea' pour les données base64 est introuvable !",
"alert.textarea.mismatch.text": "L'élément 'TextArea' pour le texte n'est pas un 'TextArea'!",
"alert.textarea.mismatch.b64": "L'élément 'TextArea' pour les données base64 n'est pas un 'TextArea'!",
"alert.other.missing": "Un élément de la page est introuvable !",
"alert.other.mismatch": "Un élément de la page n'est pas bien déclaré !",
}
};
function localize(stringKey) {
let _langData = langKey in langData ? langData[langKey] : langData.en;
return stringKey in _langData ? _langData[stringKey] : (stringKey in langData["en"] ? langData["en"][stringKey] : stringKey);
}
const idPrefix = "tool-b64-tools-";
const eTextTextarea = document.getElementById(idPrefix + "ta-text");
const eBase64Textarea = document.getElementById(idPrefix + "ta-b64");
const eClearAllButton = document.getElementById(idPrefix + "btn-clear-all");
const eClearTextButton = document.getElementById(idPrefix + "btn-clear-text");
const eClearBase64Button = document.getElementById(idPrefix + "btn-clear-b64");
const eConvertTextButton = document.getElementById(idPrefix + "btn-convert-text");
const eConvertBase64Button = document.getElementById(idPrefix + "btn-convert-b64");
const eSelectEncoding = document.getElementById(idPrefix + "encoding");
const eCheckboxPadding = document.getElementById(idPrefix + "checkbox-padding");
if (eTextTextarea == null) {
alert(localize("alert.textarea.missing.text"));
throw new Error(localize("alert.textarea.missing.text"));
}
if (eBase64Textarea == null) {
alert(localize("alert.textarea.missing.b64"));
throw new Error(localize("alert.textarea.missing.b64"));
}
if (eClearAllButton == null || eClearTextButton == null || eClearBase64Button == null || eConvertTextButton == null ||
eConvertBase64Button == null || eCheckboxPadding == null || eSelectEncoding == null) {
alert(localize("alert.other.missing"));
throw new Error(localize("alert.other.missing"));
}
var TextEncoding;
(function (TextEncoding) {
TextEncoding[TextEncoding["UTF8"] = 0] = "UTF8";
TextEncoding[TextEncoding["ASCII"] = 1] = "ASCII";
TextEncoding[TextEncoding["UNICODE"] = 2] = "UNICODE";
})(TextEncoding || (TextEncoding = {}));
if (!(eTextTextarea instanceof HTMLTextAreaElement)) {
alert(localize("alert.textarea.mismatch.text"));
throw new Error(localize("alert.textarea.mismatch.text"));
}
if (!(eBase64Textarea instanceof HTMLTextAreaElement)) {
alert(localize("alert.textarea.mismatch.b64"));
throw new Error(localize("alert.textarea.mismatch.b64"));
}
if (!(eCheckboxPadding instanceof HTMLInputElement)) {
alert(localize("alert.other.mismatch"));
throw new Error(localize("alert.other.mismatch"));
}
if (!(eSelectEncoding instanceof HTMLSelectElement)) {
alert(localize("alert.other.mismatch"));
throw new Error(localize("alert.other.mismatch"));
}
function shouldAddPadding() {
return eCheckboxPadding.checked;
}
function getTextEncoding() {
switch (eSelectEncoding.value) {
case "utf8":
return TextEncoding.UTF8;
case "unicode":
return TextEncoding.UNICODE;
case "ascii":
return TextEncoding.ASCII;
default:
return TextEncoding.UTF8;
}
}
function getText() {
switch (getTextEncoding()) {
case TextEncoding.UTF8:
break;
case TextEncoding.UNICODE:
return new TextEncoder().encode(eTextTextarea.value);
case TextEncoding.ASCII:
break;
}
return null;
}
eClearAllButton.addEventListener('click', function handleClick() {
eTextTextarea.value = "";
eBase64Textarea.value = "";
});
eClearTextButton.addEventListener('click', function handleClick() {
eTextTextarea.value = "";
});
eClearBase64Button.addEventListener('click', function handleClick() {
eBase64Textarea.value = "";
});
eConvertTextButton.addEventListener('click', function handleClick() {
eBase64Textarea.value = "";
});
eConvertBase64Button.addEventListener('click', function handleClick() {
eTextTextarea.value = "";
});
//# sourceMappingURL=code.js.map

View File

@@ -0,0 +1,137 @@
const langKey= document.documentElement.lang.match("(en|fr)") ? document.documentElement.lang : "en";
const langData = {
en: {
"alert.textarea.missing.text": "The 'TextArea' element for text is missing !",
"alert.textarea.missing.b64": "The 'TextArea' element for base64 is missing !",
"alert.textarea.mismatch.text": "The 'TextArea' element for text isn't declared as a 'TextArea'!",
"alert.textarea.mismatch.b64": "The 'TextArea' element for base64 isn't declared as a 'TextArea'!",
"alert.other.missing": "An element is missing from the page !",
"alert.other.mismatch": "An element is no declared with the proper element type !",
},
fr: {
"alert.textarea.missing.text": "L'élément 'TextArea' pour le texte est introuvable !",
"alert.textarea.missing.b64": "L'élément 'TextArea' pour les données base64 est introuvable !",
"alert.textarea.mismatch.text": "L'élément 'TextArea' pour le texte n'est pas un 'TextArea'!",
"alert.textarea.mismatch.b64": "L'élément 'TextArea' pour les données base64 n'est pas un 'TextArea'!",
"alert.other.missing": "Un élément de la page est introuvable !",
"alert.other.mismatch": "Un élément de la page n'est pas bien déclaré !",
}
}
function localize(stringKey: string): string {
// @ts-ignore -> Implicit any on "langData[langKey]"
let _langData = langKey in langData ? langData[langKey] : langData.en;
return stringKey in _langData ? _langData[stringKey] : (
// @ts-ignore -> Implicit any on " langData["en"][stringKey]"
stringKey in langData["en"] ? langData["en"][stringKey] : stringKey
);
}
const idPrefix : string = "tool-b64-tools-"
const eTextTextarea : HTMLElement | null = document.getElementById(idPrefix + "ta-text");
const eBase64Textarea : HTMLElement | null = document.getElementById(idPrefix + "ta-b64");
const eClearAllButton : HTMLElement | null = document.getElementById(idPrefix + "btn-clear-all");
const eClearTextButton : HTMLElement | null = document.getElementById(idPrefix + "btn-clear-text");
const eClearBase64Button : HTMLElement | null = document.getElementById(idPrefix + "btn-clear-b64");
const eConvertTextButton : HTMLElement | null = document.getElementById(idPrefix + "btn-convert-text");
const eConvertBase64Button : HTMLElement | null = document.getElementById(idPrefix + "btn-convert-b64");
const eSelectEncoding : HTMLElement | null = document.getElementById(idPrefix + "encoding");
const eCheckboxPadding : HTMLElement | null = document.getElementById(idPrefix + "checkbox-padding");
// Checking if the elements exist
if(eTextTextarea == null) {
alert(localize("alert.textarea.missing.text"));
throw new Error(localize("alert.textarea.missing.text"));
}
if(eBase64Textarea == null) {
alert(localize("alert.textarea.missing.b64"));
throw new Error(localize("alert.textarea.missing.b64"));
}
if(eClearAllButton == null || eClearTextButton == null || eClearBase64Button == null || eConvertTextButton == null ||
eConvertBase64Button == null || eCheckboxPadding == null || eSelectEncoding == null) {
alert(localize("alert.other.missing"));
throw new Error(localize("alert.other.missing"));
}
// Other stuff
enum TextEncoding {
UTF8,
ASCII,
UNICODE,
}
// Checking their type
if(!(eTextTextarea instanceof HTMLTextAreaElement)) {
alert(localize("alert.textarea.mismatch.text"));
throw new Error(localize("alert.textarea.mismatch.text"));
}
if(!(eBase64Textarea instanceof HTMLTextAreaElement)) {
alert(localize("alert.textarea.mismatch.b64"));
throw new Error(localize("alert.textarea.mismatch.b64"));
}
if(!(eCheckboxPadding instanceof HTMLInputElement)) {
alert(localize("alert.other.mismatch"));
throw new Error(localize("alert.other.mismatch"));
}
if(!(eSelectEncoding instanceof HTMLSelectElement)) {
alert(localize("alert.other.mismatch"));
throw new Error(localize("alert.other.mismatch"));
}
// Generic functions
function shouldAddPadding(): boolean {
return (eCheckboxPadding as HTMLInputElement).checked;
}
function getTextEncoding(): TextEncoding {
switch((eSelectEncoding as HTMLSelectElement).value) {
case "utf8":
return TextEncoding.UTF8;
case "unicode":
return TextEncoding.UNICODE;
case "ascii":
return TextEncoding.ASCII;
default:
return TextEncoding.UTF8;
}
}
function getText(): Uint8Array | null {
switch(getTextEncoding()) {
case TextEncoding.UTF8:
break;
case TextEncoding.UNICODE:
return new TextEncoder().encode((eTextTextarea as HTMLTextAreaElement).value);
case TextEncoding.ASCII:
break; //return new Buffer(string, "ascii");
}
return null;
}
// Setting up button actions
eClearAllButton.addEventListener('click', function handleClick() {
eTextTextarea.value = "";
eBase64Textarea.value = "";
});
eClearTextButton.addEventListener('click', function handleClick() {
eTextTextarea.value = "";
});
eClearBase64Button.addEventListener('click', function handleClick() {
eBase64Textarea.value = "";
});
eConvertTextButton.addEventListener('click', function handleClick() {
eBase64Textarea.value = "";
});
eConvertBase64Button.addEventListener('click', function handleClick() {
eTextTextarea.value = "";
});

View File

@@ -0,0 +1,26 @@
{
"en": {
"tool.b64-tools.title": "Base64 Tools",
"tool.b64-tools.text": "Text",
"tool.b64-tools.base64": "Base64",
"tool.b64-tools.actions": "Other actions",
"tool.b64-tools.actions.clear.all": "Clear All",
"tool.b64-tools.actions.clear.text": "Clear",
"tool.b64-tools.actions.clear.base64": "Clear",
"tool.b64-tools.actions.convert.text": "Convert to Base64",
"tool.b64-tools.actions.convert.b64": "Convert to text",
"tool.b64-tools.options": "Options"
},
"fr": {
"tool.b64-tools.title": "Outils pour Base64",
"tool.b64-tools.text": "Texte",
"tool.b64-tools.base64": "Base64",
"tool.b64-tools.actions": "Autres actions",
"tool.b64-tools.actions.clear.all": "Nettoyer Tout",
"tool.b64-tools.actions.clear.text": "Nettoyer",
"tool.b64-tools.actions.clear.base64": "Nettoyer",
"tool.b64-tools.actions.convert.text": "Convertir en Base64",
"tool.b64-tools.actions.convert.b64": "Convertir en texte",
"tool.b64-tools.options": "Options"
}
}

View File

@@ -0,0 +1,68 @@
<?php
echo(getMainHeader(localize("tool.b64-tools.text"), null, null, null,
true, "bkgd-math", 3, false, false, true));
?>
<div class="p-xs pb-0">
<label for="tool-b64-tools-ta-text"></label>
<textarea id="tool-b64-tools-ta-text" class="my-xs w-full no-resize border r-s" name="" rows="10"></textarea>
<?php
echo('<button id="tool-b64-tools-btn-convert-text" class="p-mxs r-s border b-light primary">');
echo('<span class="text-monospace"><i class="fad fa-file-search"></i>&nbsp;&nbsp;');
echo(localize("tool.b64-tools.actions.convert.text"));
echo('</span></button>');
echo('<button id="tool-b64-tools-btn-clear-text" class="p-mxs r-s border b-light primary">');
echo('<span class="text-monospace"><i class="fad fa-file-search"></i>&nbsp;&nbsp;');
echo(localize("tool.b64-tools.actions.clear.text"));
echo('</span></button>');
echo('<div class="f-right">');
echo('<label for="tool-b64-tools-encoding" class="mr-xs">Encoding:</label>');
echo('<select id="tool-b64-tools-encoding">');
echo('<option value="utf8">UTF-8</option>');
echo('<option value="unicode">Unicode</option>');
echo('<option value="ascii">ASCII</option>');
echo('</select>');
echo('</div>');
?>
</div>
<?php
echo(getMainHeader(localize("tool.b64-tools.base64"), null, null, null,
true, "bkgd-math", 3, false, false, true));
?>
<div class="p-xs pb-0">
<label for="tool-b64-tools-ta-b64"></label>
<textarea id="tool-b64-tools-ta-b64" class="my-xs w-full no-resize border r-s" name="" rows="10"></textarea>
<?php
echo('<button id="tool-b64-tools-btn-convert-b64" class="p-mxs r-s border b-light primary">');
echo('<span class="text-monospace"><i class="fad fa-file-search"></i>&nbsp;&nbsp;');
echo(localize("tool.b64-tools.actions.convert.b64"));
echo('</span></button>');
echo('<button id="tool-b64-tools-btn-clear-b64" class="p-mxs r-s border b-light primary">');
echo('<span class="text-monospace"><i class="fad fa-file-search"></i>&nbsp;&nbsp;');
echo(localize("tool.b64-tools.actions.clear.base64"));
echo('</span></button>');
echo('<div class="f-right">');
echo('<input class="border r-s my-0" type="checkbox" id="tool-b64-tools-checkbox-padding" name="vehicle1" value="Bike">');
echo('<label for="tool-b64-tools-checkbox-padding">&nbsp;Add padding</label>');
echo('</div>');
?>
</div>
<?php
echo(getMainHeader(localize("tool.b64-tools.actions"), null, null, null,
true, "bkgd-math", 3, false, false, true));
echo('<div class="px-xs pt-s">');
echo('<button id="tool-b64-tools-btn-clear-all" class="p-mxs r-s border b-light primary">');
echo('<span class="text-monospace"><i class="fad fa-file-search"></i>&nbsp;&nbsp;');
echo(localize("tool.b64-tools.actions.clear.all"));
echo('</span></button>');
echo('</div>');
?>

View File

@@ -0,0 +1,27 @@
{
"dom": "formula-wizard/page.php",
"lang": "formula-wizard/lang.json",
"code": [],
"module": [
"formula-wizard/code.min.js"
],
"styles": [
"formula-wizard/styles.css"
],
"icon": "fad fa-magic",
"title": "tool.formula-wizard.title",
"opengraph": {
"title": {
"en": "Formula Wizard",
"fr": "Ensorceleur de formules"
},
"description": {
"en": "TODO: Description",
"fr": "TODO: Description"
},
"type": "website",
"url": "https://nibblepoker.lu/tools/formula-wizard",
"image": "/resources/NibblePoker/images/placeholder.png",
"image_type": "image/png"
}
}

View File

@@ -0,0 +1,804 @@
import { Decimal } from "../../../resources/DecimalJs/10.4.3/decimal.min.mjs";
const version = [0, 0, 1];
console.log("Initializing 'Formula Wizard v" + version.join(".") + "'...");
const startTime = new Date().getMilliseconds();
Decimal.set({ precision: 25, rounding: 8 });
console.debug("Preparing langs...");
const langKey = document.documentElement.lang.match("(en|fr)") ? document.documentElement.lang : "en";
const langData = {
en: {
"unit.any.name": "Not Important",
"unit.watt.name": "Watt",
"unit.ampere.name": "Ampere",
"unit.ohm.name": "Ohm",
"unit.ohm.desc": "Electrical Resistance",
"unit.volt.name": "Volt",
"unit.farad.name": "Farad",
"error.formulaValue.noParent": "Attempting to get a formula's value whose parent formula isn't set !",
"error.formulaValue.noSource": "Attempting to get a formula's value whose value source is null !",
"error.formulaContext.tooSmall": "The current calculation context is too small !",
"ui.formulaCount": "formulas",
"formula.ohm_law.name": "Ohm's Law",
"dataset.resistor-e3.name": "E3 IEC Resistors",
"dataset.resistor-e3.desc": "???",
"dataset.resistor-e6.name": "E6 IEC Resistors",
"dataset.resistor-e6.desc": "???",
"dataset.resistor-e12.name": "E12 IEC Resistors",
"dataset.resistor-e12.desc": "???",
"dataset.resistor-e24.name": "E24 IEC Resistors",
"dataset.resistor-e24.desc": "???",
"dataset.resistor-e48.name": "E48 IEC Resistors",
"dataset.resistor-e48.desc": "???",
"dataset.capacitor-iec.name": "IEC E24 Capacitors",
"dataset.capacitor-iec.desc": "???",
"context.type.disabled.name": "Disabled",
"context.type.constant.name": "Constant",
"context.type.continuous.name": "Continuous",
"context.type.valueRange.name": "Value Range",
"context.type.dataSetRange.name": "Set-based Range",
"context.type.disabled.desc": "???",
"context.type.constant.desc": "???",
"context.type.continuous.desc": "???",
"context.type.valueRange.desc": "???",
"context.type.dataSetRange.desc": "???",
},
fr: {
"unit.ampere.name": "Ampère",
"unit.ohm.desc": "Résistance électrique",
"_error.formulaValue.noParent": "",
"_error.formulaValue.noSource": "",
"ui.formulaCount": "formules",
"formula.ohm_law.name": "Loi d'Ohm",
"context.type.disabled.name": "Désactivé",
"context.type.constant.name": "Constante",
"context.type.continuous.name": "Continue",
"context.type.valueRange.name": "Valeurs distinctes",
"context.type.dataSetRange.name": "Set de valeurs",
}
};
function localize(stringKey) {
let _langData = langKey in langData ? langData[langKey] : langData.en;
return stringKey in _langData ? _langData[stringKey] : (stringKey in langData["en"] ? langData["en"][stringKey] : stringKey);
}
console.debug("Preparing scales...");
const scales = {
SI: new class {
constructor() {
this.formatName = (unit) => {
return unit.symbol;
};
this.formatSymbol = (unit) => {
return unit.symbol;
};
this.scaleFactors = [];
}
},
IMPERIAL_DISTANCE: new class {
constructor() {
this.formatName = (unit) => {
return unit.symbol;
};
this.formatSymbol = (unit) => {
return unit.symbol;
};
this.scaleFactors = [];
}
},
IMPERIAL_WEIGHT: new class {
constructor() {
this.formatName = (unit) => {
return unit.symbol;
};
this.formatSymbol = (unit) => {
return unit.symbol;
};
this.scaleFactors = [];
}
},
TIME_SECONDS: new class {
constructor() {
this.formatName = (unit) => {
return unit.symbol;
};
this.formatSymbol = (unit) => {
return unit.symbol;
};
this.scaleFactors = [];
}
},
NONE: new class {
constructor() {
this.formatName = (unit) => {
return unit.name;
};
this.formatSymbol = (unit) => {
return unit.symbol;
};
this.scaleFactors = [];
}
},
};
const scaleFactors = {
SI_GIGA: new class {
constructor() {
this.scale = scales.SI;
this.multiplier = new Decimal('1e9');
this.prefix = "giga";
this.suffix = "";
this.symbol = "G";
}
},
SI_MEGA: new class {
constructor() {
this.scale = scales.SI;
this.multiplier = new Decimal('1e6');
this.prefix = "mega";
this.suffix = "";
this.symbol = "M";
}
},
SI_KILO: new class {
constructor() {
this.scale = scales.SI;
this.multiplier = new Decimal('1e3');
this.prefix = "kilo";
this.suffix = "";
this.symbol = "k";
}
},
SI_BASE: new class {
constructor() {
this.scale = scales.SI;
this.multiplier = new Decimal('1');
this.prefix = "";
this.suffix = "";
this.symbol = "";
}
},
SI_CENTI: new class {
constructor() {
this.scale = scales.SI;
this.multiplier = new Decimal('1e-2');
this.prefix = "centi";
this.suffix = "";
this.symbol = "c";
}
},
SI_MILLI: new class {
constructor() {
this.scale = scales.SI;
this.multiplier = new Decimal('1e-3');
this.prefix = "milli";
this.suffix = "";
this.symbol = "m";
}
},
TIME_MILLI: new class {
constructor() {
this.scale = scales.TIME_SECONDS;
this.multiplier = new Decimal('1e-3');
this.prefix = "milli";
this.suffix = "";
this.symbol = "m";
}
},
TIME_BASE: new class {
constructor() {
this.scale = scales.TIME_SECONDS;
this.multiplier = new Decimal('1');
this.prefix = "";
this.suffix = "";
this.symbol = "";
}
},
TIME_MINUTE: new class {
constructor() {
this.scale = scales.TIME_SECONDS;
this.multiplier = new Decimal('60');
this.prefix = "";
this.suffix = "";
this.symbol = "";
}
},
TIME_HOUR: new class {
constructor() {
this.scale = scales.TIME_SECONDS;
this.multiplier = new Decimal('3600');
this.prefix = "";
this.suffix = "";
this.symbol = "";
}
},
TIME_DAY: new class {
constructor() {
this.scale = scales.TIME_SECONDS;
this.multiplier = new Decimal('86400');
this.prefix = "";
this.suffix = "";
this.symbol = "";
}
},
};
Object.keys(scaleFactors).forEach(scaleFactorKey => {
const scaleFactor = scaleFactors[scaleFactorKey];
scaleFactor.scale.scaleFactors.push(scaleFactor);
});
function scaleToBase(value, scaleFactor) {
return value.times(scaleFactor.multiplier);
}
function scaleFromBase(value, scaleFactor) {
return value.dividedBy(scaleFactor.multiplier);
}
console.debug("Preparing units...");
class Unit {
constructor(unitKey, symbol, scale) {
this.name = localize("unit." + unitKey + ".name");
this.symbol = symbol;
this.scale = scale;
this.description = localize("unit." + unitKey + ".desc");
}
}
const units = {
ANY: new Unit("any", "", scales.NONE),
WATT: new Unit("watt", "W", scales.SI),
VOLT: new Unit("volt", "V", scales.SI),
AMPERE: new Unit("ampere", "A", scales.SI),
OHM: new Unit("ohm", "Ω", scales.SI),
FARAD: new Unit("farad", "F", scales.SI),
METER: new Unit("meter", "m", scales.SI),
INCH: new Unit("inch", "in", scales.IMPERIAL_DISTANCE),
POUND: new Unit("pound", "p", scales.IMPERIAL_WEIGHT),
};
console.debug("Preparing formulas...");
class FormulaContextHandler {
constructor(contextValueIndex) {
this.contextValueIndex = contextValueIndex;
}
getContextValue(context) {
if (context.length <= this.contextValueIndex) {
alert(localize("error.formulaContext.tooSmall"));
throw new Error(localize("error.formulaContext.tooSmall"));
}
return context[this.contextValueIndex];
}
}
class FormulaValue {
constructor(unit, scaleFactor) {
this.unit = unit;
this.scaleFactor = scaleFactor;
this.parentFormula = null;
this.valueSource = null;
}
getFormulaValue(context) {
if (this.parentFormula === null) {
alert(localize("error.formulaValue.noParent"));
throw new Error(localize("error.formulaValue.noParent"));
}
if (this.valueSource === null) {
alert(localize("error.formulaValue.noSource"));
throw new Error(localize("error.formulaValue.noSource"));
}
if (this.valueSource instanceof FormulaContextHandler) {
return this.valueSource.getContextValue(context);
}
return scaleFromBase(scaleToBase(this.valueSource.getVariantValue(this.parentFormula, context), this.valueSource.getOutputValueDefinition().scaleFactor), this.scaleFactor);
}
}
class Formula {
constructor(values, variants, formulaKey, categories, wikiLink) {
this.values = values;
this.variants = variants;
this.formulaKey = formulaKey;
this.name = localize("formula." + formulaKey + ".name");
this.description = localize("formula." + formulaKey + ".desc");
this.categories = categories;
this.wikiLink = wikiLink;
this.values.forEach(value => {
value.parentFormula = this;
});
}
getClone() {
const clonedFormulaValues = [];
this.values.forEach(originalValue => {
clonedFormulaValues.push(new FormulaValue(originalValue.unit, originalValue.scaleFactor));
});
return new Formula(clonedFormulaValues, this.variants, this.formulaKey, this.categories, this.wikiLink);
}
}
const formulas = {
OHM_LAW: new Formula([
new FormulaValue(units.OHM, scaleFactors.SI_BASE),
new FormulaValue(units.AMPERE, scaleFactors.SI_BASE),
new FormulaValue(units.VOLT, scaleFactors.SI_BASE),
], [
new class {
constructor() {
this.description = "V=I*R";
this.getVariantValue = (formula, context) => {
return formula.values[0].getFormulaValue(context).times(formula.values[1].getFormulaValue(context));
};
this.getInputValuesDefinition = () => {
return [this.parentFormula.values[0], this.parentFormula.values[1]];
};
this.getOutputValueDefinition = () => {
return this.parentFormula.values[2];
};
this.getMathMl = (formula) => {
return "<math><mi>" +
formula.values[2].unit.symbol +
"</mi><mo>=</mo><mi>" +
formula.values[0].unit.symbol +
"</mi><mo>*</mo><mi>" +
formula.values[1].unit.symbol +
"</mi></math>";
};
this.parentFormula = null;
}
},
new class {
constructor() {
this.description = "I=V/R";
this.getVariantValue = (formula, context) => {
return formula.values[2].getFormulaValue(context).dividedBy(formula.values[0].getFormulaValue(context));
};
this.getInputValuesDefinition = () => {
return [this.parentFormula.values[0], this.parentFormula.values[2]];
};
this.getOutputValueDefinition = () => {
return this.parentFormula.values[1];
};
this.getMathMl = (formula) => {
return "<math><mi>" +
formula.values[1].unit.symbol +
"</mi><mo>=</mo><mfrac><mi>" +
formula.values[2].unit.symbol +
"</mi><mi>" +
formula.values[0].unit.symbol +
"</mi></mfrac></math>";
};
this.parentFormula = null;
}
},
new class {
constructor() {
this.description = "R=V/I";
this.getVariantValue = (formula, context) => {
return formula.values[2].getFormulaValue(context).dividedBy(formula.values[1].getFormulaValue(context));
};
this.getInputValuesDefinition = () => {
return [this.parentFormula.values[2], this.parentFormula.values[1]];
};
this.getOutputValueDefinition = () => {
return this.parentFormula.values[0];
};
this.getMathMl = (formula) => {
return "<math><mi>" +
formula.values[0].unit.symbol +
"</mi><mo>=</mo><mfrac><mi>" +
formula.values[2].unit.symbol +
"</mi><mi>" +
formula.values[1].unit.symbol +
"</mi></mfrac></math>";
};
this.parentFormula = null;
}
},
], "ohm_law", ["electricity"], new URL("https://wikipedia.org/wiki/Ohm's_law")),
};
Object.keys(formulas).forEach(formulaKey => {
formulas[formulaKey].variants.forEach(formulaVariant => {
formulaVariant.parentFormula = formulas[formulaKey];
});
});
class ContextType {
constructor(name, description) {
this.name = name;
this.description = description;
}
}
const contextTypes = {
DISABLED: new ContextType(localize("context.type.disabled.name"), localize("context.type.disabled.desc")),
CONSTANT: new ContextType(localize("context.type.constant.name"), localize("context.type.constant.desc")),
CONTINUOUS: new ContextType(localize("context.type.continuous.name"), localize("context.type.continuous.desc")),
VALUE_RANGE: new ContextType(localize("context.type.valueRange.name"), localize("context.type.valueRange.desc")),
DATASET_RANG: new ContextType(localize("context.type.dataSetRange.name"), localize("context.type.dataSetRange.desc")),
};
console.debug("Preparing sets...");
class DataSet {
constructor(name, description, values, unit, scaleFactor) {
this.name = name;
this.description = description;
this.values = values;
this.unit = unit;
this.scaleFactor = scaleFactor;
if (unit.scale != scaleFactor.scale) {
alert("");
throw Error("");
}
}
getDataSet() {
return this.values;
}
}
const e3Range = [1, 2.2, 4.7];
const e6Range = [1, 1.5, 2.2, 3.3, 4.7, 6.8];
const e12Range = [1, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2];
const e24Range = [
1, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2, 2.2, 2.4, 2.7, 3, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1
];
const e48Range = [
1, 1.05, 1.1, 1.15, 1.21, 1.27, 1.33, 1.4, 1.47, 1.54, 1.62, 1.69, 1.78, 1.87, 1.96, 2.05, 2.15, 2.26, 2.37, 2.49,
2.61, 2.74, 2.87, 3.01, 3.16, 3.32, 3.48, 3.65, 3.83, 4.02, 4.22, 4.42, 4.64, 4.87, 5.11, 5.36, 5.62, 5.9, 6.19,
6.49, 6.81, 7.15, 7.5, 7.87, 8.25, 8.66, 9.09, 9.53
];
const resistorsScales = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000];
const capacitorScales = [10e-12, 10e-11, 10e-10, 10e-9, 10e-8, 10e-7, 10e-6, 10e-5, 10e-4, 10e-3, 10e-2];
const sets = {
RESISTOR_E3: new DataSet(localize("dataset.resistor-e3.name"), localize("dataset.resistor-e3.desc"), resistorsScales.flatMap((e3Scale) => e3Range.map((e3Multiplier) => new Decimal(e3Scale).times(e3Multiplier))), units.OHM, scaleFactors.SI_BASE),
RESISTOR_E6: new DataSet(localize("dataset.resistor-e6.name"), localize("dataset.resistor-e6.desc"), resistorsScales.flatMap((e6Scale) => e6Range.map((e6Multiplier) => new Decimal(e6Scale).times(e6Multiplier))), units.OHM, scaleFactors.SI_BASE),
RESISTOR_E12: new DataSet(localize("dataset.resistor-e12.name"), localize("dataset.resistor-e12.desc"), resistorsScales.flatMap((e12Scale) => e12Range.map((e12Multiplier) => new Decimal(e12Scale).times(e12Multiplier))), units.OHM, scaleFactors.SI_BASE),
RESISTOR_E24: new DataSet(localize("dataset.resistor-e24.name"), localize("dataset.resistor-e24.desc"), resistorsScales.flatMap((e24Scale) => e24Range.map((e24Multiplier) => new Decimal(e24Scale).times(e24Multiplier))), units.OHM, scaleFactors.SI_BASE),
RESISTOR_E48: new DataSet(localize("dataset.resistor-e48.name"), localize("dataset.resistor-e48.desc"), resistorsScales.flatMap((e48Scale) => e48Range.map((e48Multiplier) => new Decimal(e48Scale).times(e48Multiplier))), units.OHM, scaleFactors.SI_BASE),
CAPACITOR_IEC: new DataSet(localize("dataset.capacitor-iec.name"), localize("dataset.capacitor-iec.desc"), capacitorScales.flatMap((cScale) => e24Range.map((eMultiplier) => new Decimal(cScale).times(eMultiplier))), units.FARAD, scaleFactors.SI_BASE),
};
console.debug("Preparing UI...");
const idWorkbenchFormulaPrefix = "fw-workbench-formula-";
const idWorkbenchFormulaSpawnPoint = idWorkbenchFormulaPrefix + "spawn";
const idTemplateFormula = "template-workbench-formula";
const idFormulaName = idWorkbenchFormulaPrefix + "name";
const idFormulaInputs = idWorkbenchFormulaPrefix + "inputs";
const idFormulaOutputs = idWorkbenchFormulaPrefix + "outputs";
const classTemplateFormulaValue = "formula-value-input-form";
const idTemplateFormulaValue = idTemplateFormula + "-value";
const idFormulaValuePrefix = idWorkbenchFormulaPrefix + "value-";
const idFormulaValueId = idFormulaValuePrefix + "id";
const idFormulaValueName = idFormulaValuePrefix + "name";
const idFormulaValueLink = idFormulaValuePrefix + "link";
const idFormulaValueTestValue = idFormulaValuePrefix + "test-value";
const idFormulaValueTestScale = idFormulaValuePrefix + "test-scale";
const idFormulaValueTestValueSet = idFormulaValuePrefix + "test-value-set";
let eTemplateWorkbenchFormula = document.getElementById(idTemplateFormula);
let eTemplateWorkbenchFormulaValue = document.getElementById(idTemplateFormulaValue);
if (eTemplateWorkbenchFormula === null || eTemplateWorkbenchFormulaValue === null) {
alert("error.ui.workbench.noTemplate");
throw Error("error.ui.workbench.noTemplate");
}
eTemplateWorkbenchFormula = eTemplateWorkbenchFormula.cloneNode(true).content;
eTemplateWorkbenchFormulaValue = eTemplateWorkbenchFormulaValue.cloneNode(true).content;
const eWorkbenchFormulaSpawnPoint = document.querySelector(`a#${idWorkbenchFormulaSpawnPoint}`);
if (eWorkbenchFormulaSpawnPoint === null) {
alert("error.ui.workbench.noAnchor");
throw Error("error.ui.workbench.noAnchor");
}
let uiWorkbenchFormulas = [];
var WorkbenchFormulaValueTypes;
(function (WorkbenchFormulaValueTypes) {
WorkbenchFormulaValueTypes[WorkbenchFormulaValueTypes["INPUT"] = 0] = "INPUT";
WorkbenchFormulaValueTypes[WorkbenchFormulaValueTypes["OUTPUT"] = 1] = "OUTPUT";
})(WorkbenchFormulaValueTypes || (WorkbenchFormulaValueTypes = {}));
class WorkbenchFormulaValueUiElement {
constructor(rootElement, formulaValue, parentFormulaElement, valueType) {
this.rootElement = rootElement;
this.idSuffix = Date.now().toString() + Math.floor(Math.random() * 9999);
this.valueType = valueType;
this.formulaValue = formulaValue;
this.parentFormulaElement = parentFormulaElement;
this.eFormulaValueId = rootElement.querySelector(`input#${idFormulaValueId}`);
this.eFormulaValueName = rootElement.querySelector(`p#${idFormulaValueName}`);
this.eFormulaValueLink = rootElement.querySelector(`select#${idFormulaValueLink}`);
this.eFormulaValueTestValue = rootElement.querySelector(`input#${idFormulaValueTestValue}`);
this.eFormulaValueTestScale = rootElement.querySelector(`select#${idFormulaValueTestScale}`);
this.eFormulaValueTestValueSet = rootElement.querySelector(`select#${idFormulaValueTestValueSet}`);
if ([this.eFormulaValueId, this.eFormulaValueName, this.eFormulaValueLink, this.eFormulaValueTestValue,
this.eFormulaValueTestScale, this.eFormulaValueTestValueSet].some((item) => item === null)) {
alert("error.ui.formula.value.missingElement");
throw Error("error.ui.formula.value.missingElement");
}
this.rootElement.querySelectorAll(`input, select, p, div`).forEach(eFormInput => {
if (eFormInput.hasAttribute("id")) {
eFormInput.setAttribute("id", eFormInput.getAttribute("id") + this.idSuffix);
}
});
this.rootElement.querySelectorAll(`label`).forEach(eFormLabel => {
if (eFormLabel.hasAttribute("for")) {
eFormLabel.setAttribute("for", eFormLabel.getAttribute("for") + this.idSuffix);
}
});
this.eFormulaValueName.innerText = `${this.formulaValue.unit.name} (${this.formulaValue.unit.symbol})`;
this.toggleField(this.eFormulaValueTestValueSet, true);
if (this.valueType === WorkbenchFormulaValueTypes.INPUT) {
this.setupInput();
}
else {
this.setupOutput();
}
}
toggleTestMode(hidden) {
this.eFormulaValueTestScale.parentNode.parentNode.hidden = hidden;
this.eFormulaValueTestScale.parentNode.parentNode.hidden = hidden;
}
toggleField(eFormField, hidden) {
eFormField.parentNode.parentNode.hidden = hidden;
}
setupInput() {
console.log("Setting up as input...");
this.toggleField(this.eFormulaValueId, true);
}
setupOutput() {
console.log("Setting up as output...");
this.toggleField(this.eFormulaValueLink, true);
}
static getNew(formulaValue, parentFormulaElement, valueType) {
const eNewWorkbenchFormulaValue = eTemplateWorkbenchFormulaValue.cloneNode(true).firstElementChild;
if (eNewWorkbenchFormulaValue === null) {
alert("error.ui.workbench.formula.value.cannotGetElement");
throw Error("error.ui.workbench.formula.value.cannotGetElement");
}
return new WorkbenchFormulaValueUiElement(eNewWorkbenchFormulaValue, formulaValue, parentFormulaElement, valueType);
}
}
class WorkbenchFormulaUiElement {
constructor(rootElement, formulaVariant) {
this.rootElement = rootElement;
this.idSuffix = Date.now().toString();
this.formulaVariant = formulaVariant;
this.eFormulaName = rootElement.querySelector(`p#${idFormulaName}`);
this.eFormulaInputs = rootElement.querySelector(`div#${idFormulaInputs}`);
this.eFormulaOutputs = rootElement.querySelector(`div#${idFormulaOutputs}`);
if ([this.eFormulaName, this.eFormulaInputs, this.eFormulaOutputs].some((item) => item === null)) {
alert("error.ui.formula.missingElement");
throw Error("error.ui.formula.missingElement");
}
this.eFormulaName.innerText = this.formulaVariant.parentFormula.name;
this.inputValueElements = [];
this.formulaVariant.getInputValuesDefinition().forEach(variantValue => {
const newInputValueElement = WorkbenchFormulaValueUiElement.getNew(variantValue, this, WorkbenchFormulaValueTypes.INPUT);
this.inputValueElements.push(newInputValueElement);
this.eFormulaInputs.appendChild(newInputValueElement.rootElement);
});
this.outputValueElements = [];
[this.formulaVariant.getOutputValueDefinition()].forEach(variantValue => {
const newOutputValueElement = WorkbenchFormulaValueUiElement.getNew(variantValue, this, WorkbenchFormulaValueTypes.OUTPUT);
this.outputValueElements.push(newOutputValueElement);
this.eFormulaOutputs.appendChild(newOutputValueElement.rootElement);
});
}
toggleTestMode(hidden) {
}
static createNew(formulaVariant) {
const eNewWorkbenchFormula = eTemplateWorkbenchFormula.cloneNode(true).firstElementChild;
if (eNewWorkbenchFormula === null) {
alert("error.ui.workbench.formula.cannotGetElement");
throw Error("error.ui.workbench.formula.cannotGetElement");
}
const newWorkbenchUiElement = new WorkbenchFormulaUiElement(eNewWorkbenchFormula, formulaVariant);
uiWorkbenchFormulas.push(newWorkbenchUiElement);
eWorkbenchFormulaSpawnPoint.parentNode.insertBefore(newWorkbenchUiElement.rootElement, eWorkbenchFormulaSpawnPoint);
return newWorkbenchUiElement;
}
}
const idCatalogPrefix = "fw-catalog-";
const idCatalogCategoryPrefix = idCatalogPrefix + "category-";
const idCatalogCategoryCount = idCatalogPrefix + "formula-count";
const eCategoryContainers = {};
document.querySelectorAll('[id]').forEach((element) => {
if (element.id.startsWith(idCatalogCategoryPrefix)) {
eCategoryContainers[element.id.replace(idCatalogCategoryPrefix, "")] = element;
}
});
const eFormulaCount = document.getElementById(idCatalogCategoryCount);
if (eFormulaCount !== null) {
eFormulaCount.innerText = Object.keys(formulas).length.toString();
}
let eTemplateFormula = document.getElementById("template-formula-available");
let eTemplateFormulaVariant = document.getElementById("template-formula-available-variant");
if (eTemplateFormula === null || eTemplateFormulaVariant === null) {
alert("error.ui.catalog.noTemplate");
throw Error("error.ui.catalog.noTemplate");
}
Object.keys(formulas).forEach(formulaKey => {
const hasValidCategory = formulas[formulaKey].categories.every(function (categoryId) {
return Object.keys(eCategoryContainers).indexOf(categoryId) !== -1;
});
if (hasValidCategory) {
let eNewFormula = eTemplateFormula.content.cloneNode(true);
let eNewFormulaTitle = eNewFormula.querySelector("p");
if (eNewFormulaTitle !== null) {
eNewFormulaTitle.innerText = formulas[formulaKey].name;
}
let eNewFormulaVariants = eNewFormula.querySelector("div.fw-variants");
if (eNewFormulaVariants === null) {
alert("");
throw Error("");
}
eNewFormulaVariants.innerHTML = "";
formulas[formulaKey].variants.forEach(variant => {
let eNewFormulaVariant = eTemplateFormulaVariant.content.cloneNode(true);
let eNewFormulaVariantButton = eNewFormulaVariant.querySelector("button");
if (eNewFormulaVariantButton === null) {
alert("");
throw Error("");
}
eNewFormulaVariantButton.innerHTML = variant.getMathMl(formulas[formulaKey]);
eNewFormulaVariantButton.title = variant.description;
eNewFormulaVariantButton.onclick = function () {
WorkbenchFormulaUiElement.createNew(variant);
};
eNewFormulaVariants.appendChild(eNewFormulaVariant);
});
formulas[formulaKey].categories.forEach(categoryKey => {
if (Object.keys(eCategoryContainers).includes(categoryKey)) {
eCategoryContainers[categoryKey].appendChild(eNewFormula);
}
});
}
});
const idContextComponentPrefix = "fw-context-component-";
const idContextComponentId = idContextComponentPrefix + "id";
const idContextComponentDelete = idContextComponentPrefix + "delete";
const idContextComponentTypes = idContextComponentPrefix + "type";
const idContextComponentManualValue = idContextComponentPrefix + "manual-value";
const idContextComponentManualValues = idContextComponentManualValue + "s";
const idContextComponentRangeFrom = idContextComponentPrefix + "range-from";
const idContextComponentRangeTo = idContextComponentPrefix + "range-to";
const idContextComponentRangeStep = idContextComponentPrefix + "range-step";
const idContextComponentSets = idContextComponentPrefix + "set";
const idContextComponentUnit = idContextComponentPrefix + "unit";
const idContextComponentScale = idContextComponentPrefix + "scale";
let uiContextComponents = [];
let eTemplateContextComponent = document.getElementById("template-context-component");
if (eTemplateContextComponent === null) {
alert("error.ui.context.noTemplate");
throw Error("error.ui.context.noTemplate");
}
eTemplateContextComponent = eTemplateContextComponent.cloneNode(true).content;
const eContextTypes = eTemplateContextComponent.getElementById(idContextComponentTypes);
const eContextSets = eTemplateContextComponent.getElementById(idContextComponentSets);
const eContextUnits = eTemplateContextComponent.getElementById(idContextComponentUnit);
const eContextScales = eTemplateContextComponent.getElementById(idContextComponentScale);
if ([eContextTypes, eContextSets, eContextUnits, eContextScales].some((item) => item === null)) {
alert("error.ui.context.noSets");
throw Error("error.ui.context.noSets");
}
Object.keys(contextTypes).forEach(value => {
const eNewContextTypesOption = document.createElement("option");
eNewContextTypesOption.setAttribute("value", value);
eNewContextTypesOption.innerText = contextTypes[value].name;
eContextTypes.appendChild(eNewContextTypesOption);
});
Object.keys(sets).forEach(value => {
const eNewContextSetsOption = document.createElement("option");
eNewContextSetsOption.setAttribute("value", value);
eNewContextSetsOption.innerText = sets[value].name;
eContextSets.appendChild(eNewContextSetsOption);
});
Object.keys(units).forEach(unitKey => {
const eNewContextUnitsOption = document.createElement("option");
eNewContextUnitsOption.setAttribute("value", unitKey);
eNewContextUnitsOption.innerText = units[unitKey].name;
eContextUnits.appendChild(eNewContextUnitsOption);
});
Object.keys(scaleFactors).forEach(scaleKey => {
const eNewContextScalesOption = document.createElement("option");
eNewContextScalesOption.setAttribute("value", scaleKey);
eNewContextScalesOption.innerText = scaleFactors[scaleKey].prefix;
eContextScales.appendChild(eNewContextScalesOption);
});
let eContextStatusMessage = document.getElementById("fw-text-context-middle");
if (eContextStatusMessage === null) {
alert("error.ui.context.noStatus");
throw Error("error.ui.context.noStatus");
}
let eContextAddButton = document.getElementById("fw-button-add-context");
let eContextDebugButton = document.getElementById("fw-button-debug-context");
if (eContextAddButton === null || eContextDebugButton === null) {
alert("error.ui.context.missingButton");
throw Error("error.ui.context.missingButton");
}
class ContextComponentUiElement {
constructor(rootElement) {
this.rootElement = rootElement;
this.idSuffix = Date.now().toString();
this.eIdLabel = rootElement.querySelector(`label[for="${idContextComponentId}"]`);
this.eIdInput = rootElement.querySelector(`input#${idContextComponentId}`);
this.eDeleteButton = rootElement.querySelector(`button#${idContextComponentDelete}`);
this.eTypeLabel = rootElement.querySelector(`label[for="${idContextComponentTypes}"]`);
this.eTypeSelect = rootElement.querySelector(`select#${idContextComponentTypes}`);
this.eManualValueLabel = rootElement.querySelector(`label[for="${idContextComponentManualValue}"]`);
this.eManualValueInput = rootElement.querySelector(`input#${idContextComponentManualValue}`);
this.eManualValuesLabel = rootElement.querySelector(`label[for="${idContextComponentManualValues}"]`);
this.eManualValuesInput = rootElement.querySelector(`input#${idContextComponentManualValues}`);
this.eRangeFromLabel = rootElement.querySelector(`label[for="${idContextComponentRangeFrom}"]`);
this.eRangeFromInput = rootElement.querySelector(`input#${idContextComponentRangeFrom}`);
this.eRangeToLabel = rootElement.querySelector(`label[for="${idContextComponentRangeTo}"]`);
this.eRangeToInput = rootElement.querySelector(`input#${idContextComponentRangeTo}`);
this.eRangeStepLabel = rootElement.querySelector(`label[for="${idContextComponentRangeStep}"]`);
this.eRangeStepInput = rootElement.querySelector(`input#${idContextComponentRangeStep}`);
this.eDataSetLabel = rootElement.querySelector(`label[for="${idContextComponentSets}"]`);
this.eDataSetSelect = rootElement.querySelector(`select#${idContextComponentSets}`);
this.eUnitLabel = rootElement.querySelector(`label[for="${idContextComponentUnit}"]`);
this.eUnitSelect = rootElement.querySelector(`select#${idContextComponentUnit}`);
this.eScaleLabel = rootElement.querySelector(`label[for="${idContextComponentScale}"]`);
this.eScaleSelect = rootElement.querySelector(`select#${idContextComponentScale}`);
this.allElements = [
this.eIdLabel, this.eIdInput, this.eDeleteButton, this.eTypeLabel, this.eTypeSelect,
this.eManualValuesLabel, this.eManualValuesInput, this.eRangeFromLabel, this.eRangeFromInput,
this.eRangeToLabel, this.eRangeToInput, this.eRangeStepLabel, this.eRangeStepInput, this.eDataSetLabel,
this.eDataSetSelect, this.eUnitLabel, this.eUnitSelect, this.eScaleLabel, this.eScaleSelect,
this.eManualValueLabel, this.eManualValueInput
];
if (this.allElements.some((item) => item === null)) {
alert("error.ui.context.component.missingElement");
throw Error("error.ui.context.component.missingElement");
}
rootElement.querySelectorAll(`input, select`).forEach(eFormInput => {
if (eFormInput.hasAttribute("id")) {
eFormInput.setAttribute("id", eFormInput.getAttribute("id") + this.idSuffix);
}
});
rootElement.querySelectorAll(`label`).forEach(eFormLabel => {
if (eFormLabel.hasAttribute("for")) {
eFormLabel.setAttribute("for", eFormLabel.getAttribute("for") + this.idSuffix);
}
});
this.eDeleteButton.removeAttribute('id');
this.eIdInput.value = this.idSuffix;
this.eTypeSelect.onchange = this.onTypeChange.bind(this);
this.eDeleteButton.onclick = this.onDeleteClick.bind(this);
this.onTypeChange(null);
}
onTypeChange(event) {
this.allElements.forEach(eFormElement => {
this.toggleField(eFormElement, true);
});
this.toggleField(this.eIdLabel, false);
this.toggleField(this.eTypeLabel, false);
if (this.getContextType() !== contextTypes.DISABLED) {
this.toggleField(this.eUnitLabel, false);
this.toggleField(this.eScaleLabel, false);
}
switch (this.getContextType()) {
case contextTypes.CONSTANT:
this.toggleField(this.eManualValueInput, false);
break;
case contextTypes.CONTINUOUS:
this.toggleField(this.eRangeFromLabel, false);
this.toggleField(this.eRangeToLabel, false);
this.toggleField(this.eRangeStepLabel, false);
break;
case contextTypes.VALUE_RANGE:
this.toggleField(this.eManualValuesInput, false);
break;
case contextTypes.DATASET_RANG:
this.toggleField(this.eDataSetLabel, false);
break;
}
}
onDeleteClick(event) {
this.rootElement.remove();
uiContextComponents = uiContextComponents.filter(item => item !== this);
if (uiContextComponents.length < 1) {
eContextStatusMessage.hidden = false;
}
}
toggleField(eFormField, hidden) {
eFormField.parentNode.parentNode.hidden = hidden;
}
getContextType() {
return contextTypes[this.eTypeSelect.value];
}
}
eContextAddButton.onclick = function () {
const eNewContextComponent = eTemplateContextComponent.cloneNode(true).firstElementChild;
if (eNewContextComponent === null) {
alert("error.ui.context.component.cannotGetElement");
throw Error("error.ui.context.component.cannotGetElement");
}
const newContextComponent = new ContextComponentUiElement(eNewContextComponent);
uiContextComponents.push(newContextComponent);
eContextStatusMessage.parentNode.insertBefore(newContextComponent.rootElement, eContextStatusMessage);
eContextStatusMessage.hidden = true;
};
const endTime = new Date().getMilliseconds();
console.log("Done, took " + (endTime - startTime) + "ms !");
//# sourceMappingURL=code.js.map

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,51 @@
{
"en": {
"tool.formula-wizard.title": "Formula Wizard - (W.I.P)",
"tool.formula-wizard.output.graph": "Output Graph",
"tool.formula-wizard.workbench": "Formula Workbench",
"tool.formula-wizard.workbench.context": "Context",
"tool.formula-wizard.workbench.context.components": "Components:",
"tool.formula-wizard.workbench.context.placeholder": "No components present in the context.<br>Use the button below to add one :)",
"tool.formula-wizard.workbench.placeholder": "???",
"tool.formula-wizard.workbench.formula.inputs": "Input(s):",
"tool.formula-wizard.workbench.formula.outputs": "Output(s):",
"tool.formula-wizard.workbench.formula.value.expand": "Enable live experiment mode",
"tool.formula-wizard.categories": "Available Formulas",
"tool.formula-wizard.categories.electricity": "Electricity",
"tool.formula-wizard.categories.convert": "Converters",
"tool.formula-wizard.categories.physics": "Physics",
"tool.formula-wizard.categories.chemistry": "Chemistry",
"tool.formula-wizard.categories.radioactivity": "Radioactivity",
"tool.formula-wizard.button.context.add": "Add a context element.",
"tool.formula-wizard.button.context.debug": "Show debugging print-out of current context.",
"tool.formula-wizard.source": "Downloads & Source Code"
},
"fr": {
"tool.formula-wizard.title": "Ensorceleur de formules - (W.I.P)",
"tool.formula-wizard.output.graph": "Graphes des résultats",
"tool.formula-wizard.workbench": "Atelier de formule",
"tool.formula-wizard.workbench.context": "Contexte",
"tool.formula-wizard.workbench.context.components": "Composantes:",
"tool.formula-wizard.workbench.context.placeholder": "Aucune composante n'est présente dans le contexte.<br>Utilisez les bouttons ci-dessous pour en ajouter :)",
"tool.formula-wizard.workbench.placeholder": "???",
"tool.formula-wizard.workbench.formula.inputs": "Entrée(s):",
"tool.formula-wizard.workbench.formula.outputs": "Sortie(s):",
"tool.formula-wizard.categories": "Formules disponible",
"tool.formula-wizard.categories.electricity": "Électricité",
"tool.formula-wizard.categories.convert": "Convertisseurs",
"tool.formula-wizard.categories.physics": "Physique",
"tool.formula-wizard.categories.chemistry": "Chimie",
"tool.formula-wizard.categories.radioactivity": "Radioactivité",
"tool.formula-wizard.button.context.add": "Ajouter un élement au contexte.",
"tool.formula-wizard.button.context.debug": "Afficher un récapitulatif de débogage pour le contexte actuel.",
"tool.formula-wizard.source": "Télechargements & code source"
}
}

View File

@@ -0,0 +1,432 @@
<?php
echo(getMainHeader(localize("tool.formula-wizard.introduction.title"), null, null, null,
true, "bkgd-math", 3, false, false, true));
?>
<div class="m-s mt-xs">
<p>Welcome to the <i>Formula Wizard</i> !</p>
<p class="mt-xs">This tool was made ???.</p>
<p class="mt-xs">
If any formula you need is missing, you can email me at
<a href="mailto:herwin.bozet@gmail.com.com?subject=Formula%20Wizard%20Request">herwin.bozet@gmail.com</a>
and I'll look into it.</p>
<p>I'll look into it ASAP and should take less than a couple of days.</p>
</div>
<?php
echo(getMainHeader(localize("tool.formula-wizard.output.graph"), null, null, null,
true, "bkgd-math", 3, false, false, true));
?>
<div class="m-s mt-xs">
<p>TODO</p>
</div>
<?php
echo(getMainHeader(localize("tool.formula-wizard.workbench"), null, null, null,
true, "bkgd-math", 3, false, false, true));
?>
<template id="template-context-component">
<div class="my-xs ml-xs context-component-form">
<table class="border stylish table-v-center">
<tr>
<td>
<label for="fw-context-component-id" class="mx-xs t-center">Id:</label>
</td>
<td>
<input id="fw-context-component-id" type="text" class="p-mxs w-full">
</td>
<td>
<button id="fw-context-component-delete" class="error p-mxs px-xs"
title="<?php echo(localize("tool.formula-wizard.button.context.add")); ?>">
<i class="fad fa-trash-alt"></i>
</button>
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-type" class="mx-xs t-center">Type:</label>
</td>
<td colspan="2">
<select id="fw-context-component-type" class="w-full p-mxs">
</select>
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-manual-value" class="mx-xs t-center">Value:</label>
</td>
<td colspan="2">
<input id="fw-context-component-manual-value" type="number" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-manual-values" class="mx-xs t-center">Values:</label>
</td>
<td colspan="2">
<input id="fw-context-component-manual-values" type="text" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-range-from" class="mx-xs t-center">From:</label>
</td>
<td colspan="2">
<input id="fw-context-component-range-from" type="number" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-range-to" class="mx-xs t-center">To:</label>
</td>
<td colspan="2">
<input id="fw-context-component-range-to" type="number" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-range-step" class="mx-xs t-center">Step:</label>
</td>
<td colspan="2">
<input id="fw-context-component-range-step" type="number" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-set" class="mx-xs t-center">Set:</label>
</td>
<td colspan="2">
<select id="fw-context-component-set" class="w-full p-mxs">
</select>
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-unit" class="mx-xs t-center">Unit:</label>
</td>
<td colspan="2">
<select id="fw-context-component-unit" class="w-full p-mxs">
</select>
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-scale" class="mx-xs t-center">Scale:</label>
</td>
<td colspan="2">
<select id="fw-context-component-scale" class="w-full p-mxs">
</select>
</td>
</tr>
</table>
</div>
</template>
<template id="template-workbench-formula-value">
<div class="my-xs ml-xs formula-value-input-form">
<table class="border stylish table-v-center">
<tr>
<td colspan="2">
<p id="fw-workbench-formula-value-name" class="p-xxs t-center t-w-500">${value.name}</p>
</td>
</tr>
<tr>
<td>
<label for="fw-workbench-formula-value-id" class="mx-xs t-center">Id:</label>
</td>
<td>
<input id="fw-workbench-formula-value-id" type="text" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-workbench-formula-value-link" class="mx-xs t-center">Link:</label>
</td>
<td>
<select id="fw-workbench-formula-value-link" class="p-mxs w-full">
</select>
</td>
</tr>
<tr>
<td>
<label for="fw-workbench-formula-value-test-value" class="mx-xs t-center">Value:</label>
</td>
<td>
<input id="fw-workbench-formula-value-test-value" type="number" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-workbench-formula-value-test-value-set" class="mx-xs t-center">Scale:</label>
</td>
<td>
<select id="fw-workbench-formula-value-test-value-set" class="p-mxs w-full">
</select>
</td>
</tr>
<tr>
<td>
<label for="fw-workbench-formula-value-test-scale" class="mx-xs t-center">Scale:</label>
</td>
<td>
<select id="fw-workbench-formula-value-test-scale" class="p-mxs w-full">
</select>
</td>
</tr>
</table>
</div>
</template>
<template id="template-workbench-formula">
<div class="border border-t-0 border-l-0 border-r-0">
<table>
<tr>
<td class="border border-t-0 border-l-0 border-b-0 p-xs mobile-hide">
<p class="t-size-14"><i class="fad fa-grip-vertical"></i></p>
</td>
<td class="w-full">
<p id="fw-workbench-formula-name" class="p-xxs t-w-600 t-center border border-t-0 border-l-0 border-r-0">${formula.name}</p>
<div class="fw-formula-io">
<div id="fw-workbench-formula-inputs" class="p-xxs">
<p class="t-w-500 t-italic">
<?php echo(localize("tool.formula-wizard.workbench.formula.inputs")); ?>
</p>
</div>
<div id="fw-workbench-formula-outputs" class="p-xxs border border-l-0 border-r-0">
<p class="t-w-500 t-italic">
<?php echo(localize("tool.formula-wizard.workbench.formula.outputs")); ?>
</p>
</div>
</div>
</td>
</tr>
</table>
</div>
</template>
<div class="m-s mt-xs">
<div class=" border r-s bkgd-grid w-full">
<div class="border border-t-0 border-l-0 border-r-0">
<table>
<tr>
<td class="border border-t-0 border-l-0 border-b-0 p-xs mobile-hide">
<p class="t-size-14"><i class="fad fa-grip-vertical"></i></p>
</td>
<td class="w-full">
<p class="p-xxs t-w-600 t-center border border-t-0 border-l-0 border-r-0 fw-workbench-name">
<?php echo(localize("tool.formula-wizard.workbench.context")); ?>
</p>
<div class="fw-formula-io">
<div class="fw-formula-components p-xxs">
<p class="t-w-500 t-italic">
<?php echo(localize("tool.formula-wizard.workbench.context.components")); ?>
</p>
<!-- The graph's axis will point to these - Not the other way around -->
<p id="fw-text-context-middle" class="my-xs ml-xs">
<?php echo(localize("tool.formula-wizard.workbench.context.placeholder")); ?>
</p>
<div class="my-xs ml-xs">
<button id="fw-button-add-context" class="success p-mxs px-xs border r-s"
title="<?php echo(localize("tool.formula-wizard.button.context.add")); ?>">
<i class="fad fa-plus"></i>
</button>
<button id="fw-button-debug-context" class="warning p-mxs px-xs border r-s"
title="<?php echo(localize("tool.formula-wizard.button.context.debug")); ?>">
<i class="fad fa-bug"></i>
</button>
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="border border-t-0 border-l-0 border-r-0">
<table>
<tr>
<td class="border border-t-0 border-l-0 border-b-0 p-xs mobile-hide">
<p class="t-size-14"><i class="fad fa-grip-vertical"></i></p>
</td>
<td class="w-full">
<p class="p-xxs t-w-600 t-center border border-t-0 border-l-0 border-r-0 fw-workbench-name">${formula.name}</p>
<div class="fw-formula-io">
<div class="fw-formula-inputs p-xxs">
<p class="t-w-500 t-italic">
<?php echo(localize("tool.formula-wizard.workbench.formula.inputs")); ?>
</p>
<div class="border r-s d-inline-block bkgd-surround my-xs ml-xs">
<label for="test-123" class="mx-xs t-center">Ohms (Ω)</label>
<input id="test-123" type="text" class="p-mxs rr-s border border-t-0 border-b-0 border-r-0">
</div>
<div class="my-xs ml-xs formula-value-input-form">
<table class="border stylish table-v-center">
<tr>
<td colspan="2">
<p class="p-xxs t-center t-w-500">Current (A)</p>
</td>
</tr>
<tr>
<td>
<label for="test-123" class="mx-xs t-center">Link:</label>
</td>
<td>
<select id="fw-context-component-unit" class="p-mxs w-full">
</select>
</td>
</tr>
<!--<tr>
<td colspan="2" class="p-xxs bkgd-blank">
</td>
</tr>-->
<tr>
<td>
<label for="fw-context-component-unit" class="mx-xs t-center">Value:</label>
</td>
<td>
<input id="fw-context-component-unit" type="number" class="p-mxs w-full">
</td>
</tr>
<tr>
<td>
<label for="fw-context-component-scale" class="mx-xs t-center">Scale:</label>
</td>
<td>
<select id="fw-context-component-scale" class="p-mxs w-full">
</select>
</td>
</tr>
</table>
</div>
<button id="fw-context-component-delete" class="primary p-mxs px-xs border r-s"
title="<?php echo(localize("tool.formula-wizard.workbench.formula.value.expand")); ?>">
<i class="fad fa-vial"></i>
</button>
</div>
<div class="fw-formula-outputs p-xxs border border-l-0 border-r-0">
<p class="t-w-500 t-italic">
<?php echo(localize("tool.formula-wizard.workbench.formula.outputs")); ?>
</p>
<div class="border r-s d-inline-block bkgd-surround my-xs ml-xs">
<label for="test-123" class="mx-xs t-center">Volts (V)</label>
<input id="test-123" type="text" class="p-mxs rr-s border border-t-0 border-b-0 border-r-0" disabled>
</div>
<br>
<div class="border r-s d-inline-block bkgd-surround my-xs ml-xs">
<label for="test-123" class="mx-xs t-center">Watts (W)</label>
<input id="test-123" type="text" class="p-mxs rr-s border border-t-0 border-b-0 border-r-0">
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
<a id="fw-workbench-formula-spawn"></a>
<div class="border border-t-0 border-l-0 border-r-0">
<table>
<tr>
<td class="border border-t-0 border-l-0 border-b-0 p-xs mobile-hide">
<p class="t-size-14"><i class="fad fa-grip-vertical"></i></p>
</td>
<td class="w-full">
<p class="p-xxs t-w-600 t-center border border-t-0 border-l-0 border-r-0 fw-workbench-name">${formula.graph}</p>
<div class="fw-formula-io">
<div class="w-formula-graphing p-xxs">
<p class="t-w-500 t-italic">Inputs:</p>
<div class="border r-s d-inline-block bkgd-surround my-xs ml-xs">
<label for="test-123" class="mx-xs t-center">Style</label>
<input id="test-123" type="text" class="p-mxs rr-s border border-t-0 border-b-0 border-r-0">
</div>
<br>
<div class="border r-s d-inline-block bkgd-surround my-xs ml-xs">
<label for="test-123" class="mx-xs t-center">X/Y/Z-Axis (From context or calculated)</label>
<input id="test-123" type="text" class="p-mxs rr-s border border-t-0 border-b-0 border-r-0">
</div>
<!-- ON/OFF -> Add extra ranges as sliders, or refuse to proceed -->
<!-- Highlights, limits, extra styles, ... -->
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="p-xxs">
<p class="t-center t-muted t-size-8">Selected formulas will appear here, all seems good.</p>
</div>
</div>
</div>
<?php
echo(getMainHeader(localize("tool.formula-wizard.categories"), null, "<span id='fw-catalog-formula-count'></span>", null,
true, "bkgd-math", 3, false, false, true));
?>
<!-- Template used for every formula -->
<template id="template-formula-available">
<div class="border border-b-0 border-l-0 border-r-0 p-xxs px-s">
<p class="t-w-500 t-italic t-underline">${formula.name}</p>
<div class="fw-variants">
${formula.variants}
</div>
</div>
</template>
<!-- Template used for every formula variant -->
<template id="template-formula-available-variant">
<button class="t-size-15 primary p-xxs border r-m">
${formula.variant.mathml}
</button>
</template>
<div class="m-s mt-xs">
<details class="border rt-s bkgd-grid" id="fw-catalog-category-electricity" open>
<summary class="t-w-600 p-xs"><i class="fad fa-bolt mr-xs"></i><?php echo(localize("tool.formula-wizard.categories.electricity")); ?></summary>
</details>
<details class="border border-t-0 bkgd-grid p-xs" id="fw-catalog-category-converter">
<summary class="t-w-600"><i class="fad fa-sync-alt mr-xs"></i><?php echo(localize("tool.formula-wizard.categories.convert")); ?></summary>
</details>
<details class="border border-t-0 bkgd-grid p-xs" id="fw-catalog-category-physics">
<summary class="t-w-600"><i class="fad fa-apple-alt mr-xs"></i></i><?php echo(localize("tool.formula-wizard.categories.physics")); ?></summary>
</details>
<details class="border border-t-0 bkgd-grid p-xs" id="fw-catalog-category-chemistry">
<summary class="t-w-600"><i class="fad fa-flask mr-xs"></i><?php echo(localize("tool.formula-wizard.categories.chemistry")); ?></summary>
</details>
<details class="border border-t-0 bkgd-grid p-xs" id="fw-catalog-category-radioactivity">
<summary class="t-w-600"><i class="fad fa-radiation mr-xs"></i><?php echo(localize("tool.formula-wizard.categories.radioactivity")); ?></summary>
</details>
</div>
<?php
echo(getMainHeader(localize("tool.formula-wizard.source"), null, null, null,
true, "bkgd-math", 3, false, false, true));
?>
<div id="formula-wizard.test"></div>

View File

@@ -0,0 +1,21 @@
/* https://cssflex-generator.netlify.app/ */
.fw-variants {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
align-content: center;
width: 100%;
overflow: auto;
flex-direction: row;
}
.fw-variants div, .fw-variants button {
margin: 5px;
}
.fw-workbench-name {
border-bottom: 1px solid;
}

View File

@@ -0,0 +1,18 @@
{
"files": [
"code.min.js"
],
"properties": [
"WATT",
"VOLT",
"AMPERE",
"OHM",
"METER",
"INCH",
"POUND",
"symbol",
"symbol",
"symbol",
"symbol"
]
}

View File

@@ -4,6 +4,22 @@
"code": [
"svg-to-png/code.min.js"
],
"styles": [],
"module": [],
"icon": "fad fa-exchange-alt",
"title": "tool.svg-to-png.title"
"title": "tool.svg-to-png.title",
"opengraph": {
"title": {
"en": "SVG to PNG Converter",
"fr": "Convertisseur SVG vers PNG"
},
"description": {
"en": "TODO: Description",
"fr": "TODO: Description"
},
"type": "website",
"url": "https://nibblepoker.lu/tools/svg-to-png",
"image": "/resources/NibblePoker/images/placeholder.png",
"image_type": "image/png"
}
}

113
tsconfig.json Normal file
View File

@@ -0,0 +1,113 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2019", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "ES6", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
"removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
"noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
"alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"files": [
"tools/items/b64-tools/code.ts",
"tools/items/formula-wizard/code.ts"
]
}