Compare commits
	
		
			7 Commits
		
	
	
		
			c86ed21c1e
			...
			translatio
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a886d6575f | |||
| 8124b08b88 | |||
| e80902e965 | |||
| c078eaa6c5 | |||
| 75a6df9d9d | |||
| 9dfc567d5c | |||
| 093d0c0997 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					node_modules/
 | 
				
			||||||
 | 
					public/bundle.js*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
 | 
					  build:
 | 
				
			||||||
 | 
					    image: node:latest
 | 
				
			||||||
 | 
					    commands:
 | 
				
			||||||
 | 
					      - npm install
 | 
				
			||||||
 | 
					      - npm run build
 | 
				
			||||||
  deploy:
 | 
					  deploy:
 | 
				
			||||||
    image: appleboy/drone-scp
 | 
					    image: appleboy/drone-scp
 | 
				
			||||||
    settings:
 | 
					    settings:
 | 
				
			||||||
@@ -14,6 +18,6 @@ steps:
 | 
				
			|||||||
        from_secret: ssh_user
 | 
					        from_secret: ssh_user
 | 
				
			||||||
      target:
 | 
					      target:
 | 
				
			||||||
        from_secret: path
 | 
					        from_secret: path
 | 
				
			||||||
      source: src/
 | 
					      source: public/
 | 
				
			||||||
      key:
 | 
					      key:
 | 
				
			||||||
        from_secret: ssh_key
 | 
					        from_secret: ssh_key
 | 
				
			||||||
							
								
								
									
										10
									
								
								i18next-parser.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    defaultNamespace: 'translation',
 | 
				
			||||||
 | 
					    lexers: {
 | 
				
			||||||
 | 
					        js: ['JsxLexer'], // we're writing jsx inside .js files
 | 
				
			||||||
 | 
					        default: ['JavascriptLexer'],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    locales: ['en', 'de'],
 | 
				
			||||||
 | 
					    output: 'public/lang/$LOCALE.json',
 | 
				
			||||||
 | 
					    input: [ 'src/*.js', 'public/*.html', ],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5269
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										31
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "kaefigrechner",
 | 
				
			||||||
 | 
					  "version": "0.0.1",
 | 
				
			||||||
 | 
					  "description": "Ein Rechner für die minimale Größe eines Rattenkäfigs nach Standard des VdRD e.V.",
 | 
				
			||||||
 | 
					  "main": "index.js",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "start": "webpack-dev-server --config webpack.config.js",
 | 
				
			||||||
 | 
					    "ex-trans": "i18next -c i18next-parser.config.js",
 | 
				
			||||||
 | 
					    "build": "webpack --config webpack.config.js"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "repository": {
 | 
				
			||||||
 | 
					    "type": "git",
 | 
				
			||||||
 | 
					    "url": "https://git.hyteck.de/moanos/RattenheimRechner"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "keywords": [
 | 
				
			||||||
 | 
					    "animal",
 | 
				
			||||||
 | 
					    "welfare"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "author": "Julian-Samuel Gebühr",
 | 
				
			||||||
 | 
					  "license": "AGPL-3.0-or-later",
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "webpack": "^5.93.0",
 | 
				
			||||||
 | 
					    "webpack-cli": "^5.1.4",
 | 
				
			||||||
 | 
					    "webpack-dev-server": "^5.0.4"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "i18next": "^23.12.2",
 | 
				
			||||||
 | 
					    "i18next-browser-languagedetector": "^8.0.0",
 | 
				
			||||||
 | 
					    "i18next-http-backend": "^2.5.2"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -144,7 +144,7 @@ label {
 | 
				
			|||||||
    border-radius: 10px;
 | 
					    border-radius: 10px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media screen and (min-width: 40em) {
 | 
					@media screen and (min-width: 800px) {
 | 
				
			||||||
    flex: 0 1 calc(25% - 0.5em);
 | 
					    flex: 0 1 calc(25% - 0.5em);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB  | 
| 
		 Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 432 B After Width: | Height: | Size: 432 B  | 
| 
		 Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB  | 
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB  | 
| 
		 Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB  | 
							
								
								
									
										1
									
								
								public/assets/img/info.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg class="text-grey-dark" width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor"><path d="M9.00026 12.6C9.00026 12.6 9.00026 12.1224 9.00026 11.5333V8.86666C9.00026 8.57211 8.76148 8.33333 8.46693 8.33333H7.93359" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.73346 5.26666C8.58619 5.26666 8.4668 5.38605 8.4668 5.53333C8.4668 5.68061 8.58619 5.8 8.73346 5.8C8.88074 5.8 9.00013 5.68061 9.00013 5.53333C9.00013 5.38605 8.88074 5.26666 8.73346 5.26666V5.26666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9 17C13.4183 17 17 13.4183 17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 834 B  | 
| 
		 Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB  | 
| 
		 Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB  | 
| 
		 Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 546 B  | 
| 
		 Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB  | 
| 
		 Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB  | 
| 
		 Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB  | 
| 
		 Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 639 B  | 
@@ -1,15 +1,17 @@
 | 
				
			|||||||
const MINIMUM_BASE_AREA = 0.5;
 | 
					const MINIMUM_BASE_AREA = 0.5;
 | 
				
			||||||
const MINIMUM_AREA_THREE_RATS = 1.8;
 | 
					const MINIMUM_AREA_THREE_RATS = 1.5;
 | 
				
			||||||
const AREA_PER_ADDITIONAL_RAT = 0.2;
 | 
					const AREA_PER_ADDITIONAL_RAT = 0.25;
 | 
				
			||||||
const MAXIMUM_FALL_HEIGHT = 0.5;
 | 
					const MAXIMUM_FALL_HEIGHT = 0.5;
 | 
				
			||||||
const MINIMUM_LENGTH = 0.8;
 | 
					const MINIMUM_LENGTH_LONG_SIDE = 0.8;
 | 
				
			||||||
 | 
					const MINIMUM_LENGTH_SHORT_SIDE = 0.5;
 | 
				
			||||||
const MINIMUM_FLOOR_HEIGHT = 0.3;
 | 
					const MINIMUM_FLOOR_HEIGHT = 0.3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FAILED_BASE_AREA = "base_area";
 | 
					const FAILED_BASE_AREA = "base_area";
 | 
				
			||||||
const FAILED_OVERALL_AREA = "overall_area";
 | 
					const FAILED_OVERALL_AREA = "overall_area";
 | 
				
			||||||
const FAILED_FALL_HEIGHT = "fall_height";
 | 
					const FAILED_FALL_HEIGHT = "fall_height";
 | 
				
			||||||
const FAILED_NUM_RATS = "num_rats";
 | 
					const FAILED_NUM_RATS = "num_rats";
 | 
				
			||||||
const FAILED_LENGTH = "length";
 | 
					const FAILED_MINIMUM_LENGTH_LONG_SIDE = "length_long_side";
 | 
				
			||||||
 | 
					const FAILED_MINIMUM_LENGTH_SHORT_SIDE= "length_short_side";
 | 
				
			||||||
const FAILED_FLOOR_HEIGHT = "floor_height"
 | 
					const FAILED_FLOOR_HEIGHT = "floor_height"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FAIL_CRITERIA = {
 | 
					const FAIL_CRITERIA = {
 | 
				
			||||||
@@ -18,7 +20,8 @@ const FAIL_CRITERIA = {
 | 
				
			|||||||
    [FAILED_FALL_HEIGHT]: `Die mögliche Fallhöhe darf nicht mehr als ${(MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}cm betragen.`,
 | 
					    [FAILED_FALL_HEIGHT]: `Die mögliche Fallhöhe darf nicht mehr als ${(MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}cm betragen.`,
 | 
				
			||||||
    [FAILED_FLOOR_HEIGHT]: `Der Mindestabstand zwischen Ebenen muss ${(MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}cm betragen.`,
 | 
					    [FAILED_FLOOR_HEIGHT]: `Der Mindestabstand zwischen Ebenen muss ${(MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}cm betragen.`,
 | 
				
			||||||
    [FAILED_NUM_RATS]: "Es müssen mindestens 3 Ratten zusammenleben, Paarhaltung ist nicht artgerecht.",
 | 
					    [FAILED_NUM_RATS]: "Es müssen mindestens 3 Ratten zusammenleben, Paarhaltung ist nicht artgerecht.",
 | 
				
			||||||
    [FAILED_LENGTH]: `Eine Seite des Käfig muss mindestens ${(MINIMUM_LENGTH * 100).toFixed(0)}cm lang sein um Rennen zu ermöglichen.`,
 | 
					    [FAILED_MINIMUM_LENGTH_LONG_SIDE]: `Die lange Seite des Käfig muss mindestens ${(MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}cm lang sein um Rennen zu ermöglichen.`,
 | 
				
			||||||
 | 
					    [FAILED_MINIMUM_LENGTH_SHORT_SIDE]: `Die kurze Seite des Käfig muss mindestens ${(MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}cm lang sein.`,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Dimensions {
 | 
					class Dimensions {
 | 
				
			||||||
@@ -66,8 +69,12 @@ function cageCheck(dimensions, numRats, numFullFloors) {
 | 
				
			|||||||
        failedCriteria[FAILED_FALL_HEIGHT] = FAIL_CRITERIA[FAILED_FALL_HEIGHT];
 | 
					        failedCriteria[FAILED_FALL_HEIGHT] = FAIL_CRITERIA[FAILED_FALL_HEIGHT];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dimensions.width < MINIMUM_LENGTH && dimensions.depth < MINIMUM_LENGTH) {
 | 
					    if (dimensions.width < MINIMUM_LENGTH_LONG_SIDE && dimensions.depth < MINIMUM_LENGTH_LONG_SIDE) {
 | 
				
			||||||
        failedCriteria[FAILED_LENGTH] = FAIL_CRITERIA[FAILED_LENGTH];
 | 
					        failedCriteria[FAILED_MINIMUM_LENGTH_LONG_SIDE] = FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_LONG_SIDE];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dimensions.width < MINIMUM_LENGTH_SHORT_SIDE || dimensions.depth < MINIMUM_LENGTH_SHORT_SIDE) {
 | 
				
			||||||
 | 
					        failedCriteria[FAILED_MINIMUM_LENGTH_SHORT_SIDE] = FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_SHORT_SIDE];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dimensions.height / numFullFloors < MINIMUM_FLOOR_HEIGHT) {
 | 
					    if (dimensions.height / numFullFloors < MINIMUM_FLOOR_HEIGHT) {
 | 
				
			||||||
							
								
								
									
										121
									
								
								public/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en" xmlns="http://www.w3.org/1999/html" xmlns="http://www.w3.org/1999/html">
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <title>Käfigrechner</title>
 | 
				
			||||||
 | 
					    <link rel="stylesheet" href="assets/css/style.css">
 | 
				
			||||||
 | 
					    <script src="assets/js/calculator.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <link rel="apple-touch-icon" sizes="180x180" href="assets/favicon/apple-touch-icon.png">
 | 
				
			||||||
 | 
					    <link rel="icon" type="image/png" sizes="32x32" href="assets/favicon/favicon-32x32.png">
 | 
				
			||||||
 | 
					    <link rel="icon" type="image/png" sizes="16x16" href="assets/favicon/favicon-16x16.png">
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="navigation-sticky">
 | 
				
			||||||
 | 
					    <a href="https://notfellchen.org">
 | 
				
			||||||
 | 
					        <b data-i18n-key="back-to-home">zurück zur Homepage</b>
 | 
				
			||||||
 | 
					    </a>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="img/translation-icon@2x.png" class="translation-icon" /   >
 | 
				
			||||||
 | 
					<select data-i18n-switcher class="locale-switcher">
 | 
				
			||||||
 | 
					    <option value="en">English</option>
 | 
				
			||||||
 | 
					    <option value="de">Deutsch</option>
 | 
				
			||||||
 | 
					</select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="content">
 | 
				
			||||||
 | 
					    <h1 data-i18n-key="app-name">Käfigrechner</h1>
 | 
				
			||||||
 | 
					    <div class="container-form">
 | 
				
			||||||
 | 
					        <div class="cards">
 | 
				
			||||||
 | 
					            <div class="card" id="card-SavicSuiteRoyaleXL">
 | 
				
			||||||
 | 
					                <label for="SavicSuiteRoyaleXL">
 | 
				
			||||||
 | 
					                    <input type="checkbox" id="SavicSuiteRoyaleXL"/>
 | 
				
			||||||
 | 
					                    <div class="card-photo">
 | 
				
			||||||
 | 
					                        <img src="assets/img/savic-xl.jpeg">
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div class="info-container">
 | 
				
			||||||
 | 
					                        <h4><b>Savic Suite Royale XL</b></h4>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="card" id="card-SavicSuiteRoyale95Double">
 | 
				
			||||||
 | 
					                <label for="SavicSuiteRoyale95Double">
 | 
				
			||||||
 | 
					                    <input type="checkbox" id="SavicSuiteRoyale95Double"/>
 | 
				
			||||||
 | 
					                    <div class="card-photo">
 | 
				
			||||||
 | 
					                        <div>
 | 
				
			||||||
 | 
					                            <img src="assets/img/savic-95-double.jpg">
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <div class="info-container">
 | 
				
			||||||
 | 
					                            <h4><b>Savic Suite Royale 95 Double</b></h4>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="card" id="card-TiakiKleintierkäfigEtagere">
 | 
				
			||||||
 | 
					                <label for="TiakiKleintierkäfigEtagere">
 | 
				
			||||||
 | 
					                    <input type="checkbox" id="TiakiKleintierkäfigEtagere"/>
 | 
				
			||||||
 | 
					                    <div class="card-photo">
 | 
				
			||||||
 | 
					                        <img src="assets/img/tiaki.jpeg">
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div class="info-container">
 | 
				
			||||||
 | 
					                        <h4><b>TIAKI Kleintierkäfig Étagère</b></h4>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="card" id="card-ManualMeasurements">
 | 
				
			||||||
 | 
					                <label for="form-cage-measurements">Käfigmaße</label>
 | 
				
			||||||
 | 
					                <form id="form-cage-measurements" class="form-measurements">
 | 
				
			||||||
 | 
					                    <div class="input-measurement">
 | 
				
			||||||
 | 
					                        <label for="width" data-i18n-key="width-cm">Breite (cm)</label>
 | 
				
			||||||
 | 
					                        <input class="measurement" type="number" id="width">
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div class="input-measurement">
 | 
				
			||||||
 | 
					                        <label for="depth" data-i18n-key="depth-cm">Tiefe (cm)</label>
 | 
				
			||||||
 | 
					                        <input class="measurement" type="number" id="depth">
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div class="input-measurement">
 | 
				
			||||||
 | 
					                        <label for="height" data-i18n-key="height-cm">Höhe (cm)</label>
 | 
				
			||||||
 | 
					                        <input class="measurement" type="number" id="height">
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </form>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container-inputs">
 | 
				
			||||||
 | 
					        <div class="input-element">
 | 
				
			||||||
 | 
					            <label for="numFullFloors" data-i18n-key="full-floors">Vollebenen</label>
 | 
				
			||||||
 | 
					            <div class="tooltip">
 | 
				
			||||||
 | 
					                <svg class="text-grey-dark" width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor"><path d="M9.00026 12.6C9.00026 12.6 9.00026 12.1224 9.00026 11.5333V8.86666C9.00026 8.57211 8.76148 8.33333 8.46693 8.33333H7.93359" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.73346 5.26666C8.58619 5.26666 8.4668 5.38605 8.4668 5.53333C8.4668 5.68061 8.58619 5.8 8.73346 5.8C8.88074 5.8 9.00013 5.68061 9.00013 5.53333C9.00013 5.38605 8.88074 5.26666 8.73346 5.26666V5.26666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9 17C13.4183 17 17 13.4183 17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
 | 
				
			||||||
 | 
					                <span class="tooltiptext" data-i18n-key="full-floors-tooltip">Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens.</span>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="ncontainer">
 | 
				
			||||||
 | 
					                <div class="input-group">
 | 
				
			||||||
 | 
					                    <button id="decreaseFloorNum">-</button>
 | 
				
			||||||
 | 
					                    <input type="text" id="numFullFloors" value="3" readonly>
 | 
				
			||||||
 | 
					                    <button id="increaseFloorNum">+</button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="input-element">
 | 
				
			||||||
 | 
					            <div class="slidecontainer">
 | 
				
			||||||
 | 
					                <label for="numRats" id="labelNumRats" data-i18n-key="number-of-rats">Anzahl an Ratten ?</label>
 | 
				
			||||||
 | 
					                <input type="range" min="3" max="15" value="4" class="slider" id="numRats">
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container output-element" id="resultsDiv">
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script src="./bundle.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										10
									
								
								public/lang/de.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "back-to-home": "Zurück zur Homepage",
 | 
				
			||||||
 | 
					  "app-name": "Käfigrechner",
 | 
				
			||||||
 | 
					  "number-of-rats": "Anzahl an Ratten",
 | 
				
			||||||
 | 
					  "full-floors": "Vollebenen",
 | 
				
			||||||
 | 
					  "width-cm": "Breite (cm)",
 | 
				
			||||||
 | 
					  "depth-cm": "Tiefe (cm)",
 | 
				
			||||||
 | 
					  "height-cm": "Höhe (cm)",
 | 
				
			||||||
 | 
					  "full-floors-tooltip": "Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens."
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								public/lang/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "back-to-home": "Back to home",
 | 
				
			||||||
 | 
					  "app-name": "Cage Calculator",
 | 
				
			||||||
 | 
					  "number-of-rats": "Number of Rats",
 | 
				
			||||||
 | 
					  "full-floors": "Full floors",
 | 
				
			||||||
 | 
					  "width-cm": "Width (cm)",
 | 
				
			||||||
 | 
					  "depth-cm": "Depth (cm)",
 | 
				
			||||||
 | 
					  "height-cm": "Height (cm)",
 | 
				
			||||||
 | 
					  "full-floors-tooltip": "A full floor is each floor with a area greater than 0.5m², including the bottom of the cage."
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										252
									
								
								src/index.html
									
									
									
									
									
								
							
							
						
						@@ -1,252 +0,0 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html lang="en" xmlns="http://www.w3.org/1999/html" xmlns="http://www.w3.org/1999/html">
 | 
					 | 
				
			||||||
<head>
 | 
					 | 
				
			||||||
    <meta charset="UTF-8">
 | 
					 | 
				
			||||||
    <title>Käfigrechner</title>
 | 
					 | 
				
			||||||
    <link rel="stylesheet" href="assets/css/style.css">
 | 
					 | 
				
			||||||
    <script src="assets/calculator.js"></script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <link rel="apple-touch-icon" sizes="180x180" href="assets/favicon/apple-touch-icon.png">
 | 
					 | 
				
			||||||
    <link rel="icon" type="image/png" sizes="32x32" href="assets/favicon/favicon-32x32.png">
 | 
					 | 
				
			||||||
    <link rel="icon" type="image/png" sizes="16x16" href="assets/favicon/favicon-16x16.png">
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div class="navigation-sticky">
 | 
					 | 
				
			||||||
    <a href="https://notfellchen.org">
 | 
					 | 
				
			||||||
        <b>zurück zur Homepage</b>
 | 
					 | 
				
			||||||
    </a>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div class="content">
 | 
					 | 
				
			||||||
    <h1>Käfigrechner</h1>
 | 
					 | 
				
			||||||
    <div class="container-form">
 | 
					 | 
				
			||||||
        <div class="cards">
 | 
					 | 
				
			||||||
            <div class="card" id="card-SavicSuiteRoyaleXL">
 | 
					 | 
				
			||||||
                <label for="SavicSuiteRoyaleXL">
 | 
					 | 
				
			||||||
                    <input type="checkbox" id="SavicSuiteRoyaleXL"/>
 | 
					 | 
				
			||||||
                    <div class="card-photo">
 | 
					 | 
				
			||||||
                        <img src="assets/img/savic-xl.jpeg">
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div class="info-container">
 | 
					 | 
				
			||||||
                        <h4><b>Savic Suite Royale XL</b></h4>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </label>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <div class="card" id="card-SavicSuiteRoyale95Double">
 | 
					 | 
				
			||||||
                <label for="SavicSuiteRoyale95Double">
 | 
					 | 
				
			||||||
                    <input type="checkbox" id="SavicSuiteRoyale95Double"/>
 | 
					 | 
				
			||||||
                    <div class="card-photo">
 | 
					 | 
				
			||||||
                        <div>
 | 
					 | 
				
			||||||
                            <img src="assets/img/savic-95-double.jpg">
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                        <div class="info-container">
 | 
					 | 
				
			||||||
                            <h4><b>Savic Suite Royale 95 Double</b></h4>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </label>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <div class="card" id="card-TiakiKleintierkäfigEtagere">
 | 
					 | 
				
			||||||
                <label for="TiakiKleintierkäfigEtagere">
 | 
					 | 
				
			||||||
                    <input type="checkbox" id="TiakiKleintierkäfigEtagere"/>
 | 
					 | 
				
			||||||
                    <div class="card-photo">
 | 
					 | 
				
			||||||
                        <img src="assets/img/tiaki.jpeg">
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div class="info-container">
 | 
					 | 
				
			||||||
                        <h4><b>TIAKI Kleintierkäfig Étagère</b></h4>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </label>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <div class="card" id="card-ManualMeasurements">
 | 
					 | 
				
			||||||
                <label for="form-cage-measurements">Käfigmaße</label>
 | 
					 | 
				
			||||||
                <form id="form-cage-measurements" class="form-measurements">
 | 
					 | 
				
			||||||
                    <div class="input-measurement">
 | 
					 | 
				
			||||||
                        <label for="width">Breite (cm)</label>
 | 
					 | 
				
			||||||
                        <input class="measurement" type="number" id="width">
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div class="input-measurement">
 | 
					 | 
				
			||||||
                        <label for="depth">Tiefe (cm)</label>
 | 
					 | 
				
			||||||
                        <input class="measurement" type="number" id="depth">
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div class="input-measurement">
 | 
					 | 
				
			||||||
                        <label for="height">Höhe (cm)</label>
 | 
					 | 
				
			||||||
                        <input class="measurement" type="number" id="height">
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </form>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="container-inputs">
 | 
					 | 
				
			||||||
        <div class="input-element">
 | 
					 | 
				
			||||||
            <label for="numFullFloors">Vollebenen</label>
 | 
					 | 
				
			||||||
            <div class="tooltip">
 | 
					 | 
				
			||||||
                <svg class="text-grey-dark" width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor"><path d="M9.00026 12.6C9.00026 12.6 9.00026 12.1224 9.00026 11.5333V8.86666C9.00026 8.57211 8.76148 8.33333 8.46693 8.33333H7.93359" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.73346 5.26666C8.58619 5.26666 8.4668 5.38605 8.4668 5.53333C8.4668 5.68061 8.58619 5.8 8.73346 5.8C8.88074 5.8 9.00013 5.68061 9.00013 5.53333C9.00013 5.38605 8.88074 5.26666 8.73346 5.26666V5.26666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9 17C13.4183 17 17 13.4183 17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
 | 
					 | 
				
			||||||
                <span class="tooltiptext">Als Vollebenen zählen alle Ebenen die größer als 0.5m² sind, inklusive des Käfigbodens.</span>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div class="ncontainer">
 | 
					 | 
				
			||||||
                <div class="input-group">
 | 
					 | 
				
			||||||
                    <button onclick="decreaseFloorNum()">-</button>
 | 
					 | 
				
			||||||
                    <input type="text" id="numFullFloors" value="3" readonly>
 | 
					 | 
				
			||||||
                    <button onclick="increaseFloorNum()">+</button>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div class="input-element">
 | 
					 | 
				
			||||||
            <div class="slidecontainer">
 | 
					 | 
				
			||||||
                <label for="numRats" id="labelNumRats">Anzahl an Ratten ?</label>
 | 
					 | 
				
			||||||
                <input type="range" min="3" max="15" value="4" class="slider" id="numRats">
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="container output-element" id="resultsDiv">
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const inputWidth = document.getElementById("width");
 | 
					 | 
				
			||||||
    inputWidth.onchange = updateViaManualMeasurements;
 | 
					 | 
				
			||||||
    const inputDepth = document.getElementById("depth");
 | 
					 | 
				
			||||||
    inputDepth.onchange = updateViaManualMeasurements;
 | 
					 | 
				
			||||||
    const inputHeight = document.getElementById("height");
 | 
					 | 
				
			||||||
    inputHeight.onchange = updateViaManualMeasurements;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const selectSavicSuiteRoyaleXL = document.getElementById("SavicSuiteRoyaleXL");
 | 
					 | 
				
			||||||
    const selectSavicSuiteRoyale95Double = document.getElementById("SavicSuiteRoyale95Double");
 | 
					 | 
				
			||||||
    const selectTiakiKleintierkäfigEtagere = document.getElementById("TiakiKleintierkäfigEtagere");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const cardSavicSuiteRoyaleXL = document.getElementById("card-SavicSuiteRoyaleXL");
 | 
					 | 
				
			||||||
    const cardSavicSuiteRoyale95Double = document.getElementById("card-SavicSuiteRoyale95Double");
 | 
					 | 
				
			||||||
    const cardTiakiKleintierkäfigEtagere = document.getElementById("card-TiakiKleintierkäfigEtagere");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function markActiveCage(cageName) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cardSavicSuiteRoyaleXL.classList.remove("card-active");
 | 
					 | 
				
			||||||
        cardSavicSuiteRoyale95Double.classList.remove("card-active");
 | 
					 | 
				
			||||||
        cardTiakiKleintierkäfigEtagere.classList.remove("card-active");
 | 
					 | 
				
			||||||
        if (cageName != "") {
 | 
					 | 
				
			||||||
            const activeCage = document.getElementById("card-" + cageName);
 | 
					 | 
				
			||||||
            activeCage.classList.add("card-active")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function updateCage(event) {
 | 
					 | 
				
			||||||
        selectSavicSuiteRoyaleXL.checked = false;
 | 
					 | 
				
			||||||
        selectSavicSuiteRoyale95Double.checked = false;
 | 
					 | 
				
			||||||
        selectTiakiKleintierkäfigEtagere.checked = false;
 | 
					 | 
				
			||||||
        const selectedCage = event.currentTarget
 | 
					 | 
				
			||||||
        selectedCage.checked = true;
 | 
					 | 
				
			||||||
        const cageName = selectedCage.id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        console.log(cageName);
 | 
					 | 
				
			||||||
        var dim = getCageDimensions(cageName);
 | 
					 | 
				
			||||||
        inputWidth.value = dim.width;
 | 
					 | 
				
			||||||
        inputDepth.value = dim.depth;
 | 
					 | 
				
			||||||
        inputHeight.value = dim.height;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        markActiveCage(cageName);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        update();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    selectSavicSuiteRoyaleXL.onchange = updateCage;
 | 
					 | 
				
			||||||
    selectSavicSuiteRoyale95Double.onchange = updateCage;
 | 
					 | 
				
			||||||
    selectTiakiKleintierkäfigEtagere.onchange = updateCage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var labelNumRats = document.getElementById("labelNumRats");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var ratSlider = document.getElementById("numRats");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    labelNumRats.innerHTML = `Anzahl an Ratten: ` + ratSlider.value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ratSlider.oninput = function () {
 | 
					 | 
				
			||||||
        labelNumRats.innerHTML = `Anzahl an Ratten: ` + this.value;
 | 
					 | 
				
			||||||
        update();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Full floor functions
 | 
					 | 
				
			||||||
    var fullFloorNum = document.getElementById("numFullFloors");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function getCageDimensions(cageName) {
 | 
					 | 
				
			||||||
        console.log(cageName);
 | 
					 | 
				
			||||||
        if (cageName == "SavicSuiteRoyaleXL") {
 | 
					 | 
				
			||||||
            return new Dimensions(115, 67.5, 153);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (cageName == "SavicSuiteRoyale95Double") {
 | 
					 | 
				
			||||||
            return new Dimensions(95, 63, 120);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (cageName == "TiakiKleintierkäfigEtagere") {
 | 
					 | 
				
			||||||
            return new Dimensions(93.5, 63, 141.2);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function getResultFromChecks(checks) {
 | 
					 | 
				
			||||||
        console.log(checks.length)
 | 
					 | 
				
			||||||
        if (Object.keys(checks).length > 0) {
 | 
					 | 
				
			||||||
            const ul = document.createElement('ul');
 | 
					 | 
				
			||||||
            for (const key in checks) {
 | 
					 | 
				
			||||||
                const li = document.createElement('li');
 | 
					 | 
				
			||||||
                li.textContent = `❌` + checks[key];
 | 
					 | 
				
			||||||
                ul.appendChild(li);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return ul;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            const p = document.createElement('p');
 | 
					 | 
				
			||||||
            p.innerHTML = "✅ Der Käfig erfüllt alle Kriterien!"
 | 
					 | 
				
			||||||
            return p;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function updateViaManualMeasurements() {
 | 
					 | 
				
			||||||
        markActiveCage("ManualMeasurements");
 | 
					 | 
				
			||||||
        update();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function update() {
 | 
					 | 
				
			||||||
        const width = inputWidth.value
 | 
					 | 
				
			||||||
        const depth = inputDepth.value
 | 
					 | 
				
			||||||
        const height = inputHeight.value
 | 
					 | 
				
			||||||
        const dimensions = new Dimensions(width / 100, depth / 100, height / 100);
 | 
					 | 
				
			||||||
        const failed_checks = cageCheck(dimensions, ratSlider.value, fullFloorNum.value);
 | 
					 | 
				
			||||||
        console.log(failed_checks);
 | 
					 | 
				
			||||||
        let resultsDiv = document.getElementById("resultsDiv");
 | 
					 | 
				
			||||||
        resultsDiv.innerHTML = `<strong>Ergebnis</strong>`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const result = getResultFromChecks(failed_checks);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        resultsDiv.appendChild(result);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function decreaseFloorNum() {
 | 
					 | 
				
			||||||
        var input = document.getElementById('numFullFloors');
 | 
					 | 
				
			||||||
        var value = parseInt(input.value);
 | 
					 | 
				
			||||||
        if (value > 0) {
 | 
					 | 
				
			||||||
            input.value = value - 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        update();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function increaseFloorNum() {
 | 
					 | 
				
			||||||
        var input = document.getElementById('numFullFloors');
 | 
					 | 
				
			||||||
        var value = parseInt(input.value);
 | 
					 | 
				
			||||||
        input.value = value + 1;
 | 
					 | 
				
			||||||
        update();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    update();
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
							
								
								
									
										196
									
								
								src/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,196 @@
 | 
				
			|||||||
 | 
					const inputDecreaseFloorNum = document.getElementById("decreaseFloorNum");
 | 
				
			||||||
 | 
					inputDecreaseFloorNum.onclick = decreaseFloorNum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const inputIncreaseFloorNum = document.getElementById("increaseFloorNum");
 | 
				
			||||||
 | 
					inputIncreaseFloorNum.onclick = increaseFloorNum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const inputWidth = document.getElementById("width");
 | 
				
			||||||
 | 
					inputWidth.onchange = updateViaManualMeasurements;
 | 
				
			||||||
 | 
					const inputDepth = document.getElementById("depth");
 | 
				
			||||||
 | 
					inputDepth.onchange = updateViaManualMeasurements;
 | 
				
			||||||
 | 
					const inputHeight = document.getElementById("height");
 | 
				
			||||||
 | 
					inputHeight.onchange = updateViaManualMeasurements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const selectSavicSuiteRoyaleXL = document.getElementById("SavicSuiteRoyaleXL");
 | 
				
			||||||
 | 
					const selectSavicSuiteRoyale95Double = document.getElementById("SavicSuiteRoyale95Double");
 | 
				
			||||||
 | 
					const selectTiakiKleintierkäfigEtagere = document.getElementById("TiakiKleintierkäfigEtagere");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cardSavicSuiteRoyaleXL = document.getElementById("card-SavicSuiteRoyaleXL");
 | 
				
			||||||
 | 
					const cardSavicSuiteRoyale95Double = document.getElementById("card-SavicSuiteRoyale95Double");
 | 
				
			||||||
 | 
					const cardTiakiKleintierkäfigEtagere = document.getElementById("card-TiakiKleintierkäfigEtagere");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function markActiveCage(cageName) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cardSavicSuiteRoyaleXL.classList.remove("card-active");
 | 
				
			||||||
 | 
					    cardSavicSuiteRoyale95Double.classList.remove("card-active");
 | 
				
			||||||
 | 
					    cardTiakiKleintierkäfigEtagere.classList.remove("card-active");
 | 
				
			||||||
 | 
					    if (cageName != "") {
 | 
				
			||||||
 | 
					        const activeCage = document.getElementById("card-" + cageName);
 | 
				
			||||||
 | 
					        activeCage.classList.add("card-active")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updateCage(event) {
 | 
				
			||||||
 | 
					    selectSavicSuiteRoyaleXL.checked = false;
 | 
				
			||||||
 | 
					    selectSavicSuiteRoyale95Double.checked = false;
 | 
				
			||||||
 | 
					    selectTiakiKleintierkäfigEtagere.checked = false;
 | 
				
			||||||
 | 
					    const selectedCage = event.currentTarget
 | 
				
			||||||
 | 
					    selectedCage.checked = true;
 | 
				
			||||||
 | 
					    const cageName = selectedCage.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log(cageName);
 | 
				
			||||||
 | 
					    var dim = getCageDimensions(cageName);
 | 
				
			||||||
 | 
					    inputWidth.value = dim.width;
 | 
				
			||||||
 | 
					    inputDepth.value = dim.depth;
 | 
				
			||||||
 | 
					    inputHeight.value = dim.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    markActiveCage(cageName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					selectSavicSuiteRoyaleXL.onchange = updateCage;
 | 
				
			||||||
 | 
					selectSavicSuiteRoyale95Double.onchange = updateCage;
 | 
				
			||||||
 | 
					selectTiakiKleintierkäfigEtagere.onchange = updateCage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var labelNumRats = document.getElementById("labelNumRats");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var ratSlider = document.getElementById("numRats");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					labelNumRats.innerHTML = `Anzahl an Ratten: ` + ratSlider.value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ratSlider.oninput = function () {
 | 
				
			||||||
 | 
					    labelNumRats.innerHTML = `Anzahl an Ratten: ` + this.value;
 | 
				
			||||||
 | 
					    update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Full floor functions
 | 
				
			||||||
 | 
					var fullFloorNum = document.getElementById("numFullFloors");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getCageDimensions(cageName) {
 | 
				
			||||||
 | 
					    console.log(cageName);
 | 
				
			||||||
 | 
					    if (cageName == "SavicSuiteRoyaleXL") {
 | 
				
			||||||
 | 
					        return new Dimensions(115, 67.5, 153);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (cageName == "SavicSuiteRoyale95Double") {
 | 
				
			||||||
 | 
					        return new Dimensions(95, 63, 120);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (cageName == "TiakiKleintierkäfigEtagere") {
 | 
				
			||||||
 | 
					        return new Dimensions(93.5, 63, 141.2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getResultFromChecks(checks) {
 | 
				
			||||||
 | 
					    console.log(checks.length)
 | 
				
			||||||
 | 
					    if (Object.keys(checks).length > 0) {
 | 
				
			||||||
 | 
					        const ul = document.createElement('ul');
 | 
				
			||||||
 | 
					        for (const key in checks) {
 | 
				
			||||||
 | 
					            const li = document.createElement('li');
 | 
				
			||||||
 | 
					            li.textContent = `❌` + checks[key];
 | 
				
			||||||
 | 
					            ul.appendChild(li);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ul;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        const p = document.createElement('p');
 | 
				
			||||||
 | 
					        p.innerHTML = "✅ Der Käfig erfüllt alle Kriterien!"
 | 
				
			||||||
 | 
					        return p;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updateViaManualMeasurements() {
 | 
				
			||||||
 | 
					    markActiveCage("ManualMeasurements");
 | 
				
			||||||
 | 
					    update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function update() {
 | 
				
			||||||
 | 
					    const width = inputWidth.value
 | 
				
			||||||
 | 
					    const depth = inputDepth.value
 | 
				
			||||||
 | 
					    const height = inputHeight.value
 | 
				
			||||||
 | 
					    const dimensions = new Dimensions(width / 100, depth / 100, height / 100);
 | 
				
			||||||
 | 
					    const failed_checks = cageCheck(dimensions, ratSlider.value, fullFloorNum.value);
 | 
				
			||||||
 | 
					    console.log(failed_checks);
 | 
				
			||||||
 | 
					    let resultsDiv = document.getElementById("resultsDiv");
 | 
				
			||||||
 | 
					    resultsDiv.innerHTML = `<strong>Ergebnis</strong>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const result = getResultFromChecks(failed_checks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resultsDiv.appendChild(result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function decreaseFloorNum() {
 | 
				
			||||||
 | 
					    var input = document.getElementById('numFullFloors');
 | 
				
			||||||
 | 
					    var value = parseInt(input.value);
 | 
				
			||||||
 | 
					    if (value > 0) {
 | 
				
			||||||
 | 
					        input.value = value - 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function increaseFloorNum() {
 | 
				
			||||||
 | 
					    var input = document.getElementById('numFullFloors');
 | 
				
			||||||
 | 
					    var value = parseInt(input.value);
 | 
				
			||||||
 | 
					    input.value = value + 1;
 | 
				
			||||||
 | 
					    update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import i18next from "i18next";
 | 
				
			||||||
 | 
					import LanguageDetector from "i18next-browser-languagedetector";
 | 
				
			||||||
 | 
					import HttpApi from "i18next-http-backend";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function initI18next() {
 | 
				
			||||||
 | 
					    // We use() the backend and await it to load
 | 
				
			||||||
 | 
					    // the translations from the network
 | 
				
			||||||
 | 
					    await i18next
 | 
				
			||||||
 | 
					        .use(HttpApi)
 | 
				
			||||||
 | 
					        .use(LanguageDetector)
 | 
				
			||||||
 | 
					        .init({
 | 
				
			||||||
 | 
					            lng: "en",
 | 
				
			||||||
 | 
					            supportedLngs: ["en", "de"],
 | 
				
			||||||
 | 
					            nonExplicitSupportedLngs: true,
 | 
				
			||||||
 | 
					            fallbackLng: "en",
 | 
				
			||||||
 | 
					            debug: true,
 | 
				
			||||||
 | 
					            backend: {
 | 
				
			||||||
 | 
					                loadPath: "/lang/{{lng}}.json",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function translatePageElements() {
 | 
				
			||||||
 | 
					    const translatableElements = document.querySelectorAll(
 | 
				
			||||||
 | 
					        "[data-i18n-key]",
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    translatableElements.forEach((el) => {
 | 
				
			||||||
 | 
					        const key = el.getAttribute("data-i18n-key");
 | 
				
			||||||
 | 
					        el.innerHTML = i18next.t(key);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function bindLocaleSwitcher(initialValue) {
 | 
				
			||||||
 | 
					    const switcher = document.querySelector(
 | 
				
			||||||
 | 
					        "[data-i18n-switcher]",
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    switcher.value = initialValue;
 | 
				
			||||||
 | 
					    switcher.onchange = (e) => {
 | 
				
			||||||
 | 
					        i18next
 | 
				
			||||||
 | 
					            .changeLanguage(e.target.value)
 | 
				
			||||||
 | 
					            .then(translatePageElements);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(async function () {
 | 
				
			||||||
 | 
					    await initI18next();
 | 
				
			||||||
 | 
					    translatePageElements();
 | 
				
			||||||
 | 
					    bindLocaleSwitcher(i18next.resolvedLanguage);
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
							
								
								
									
										25
									
								
								webpack.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					const path = require("path");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const port = 3000;
 | 
				
			||||||
 | 
					const openBrowser = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    entry: {
 | 
				
			||||||
 | 
					        app: ["./src/index.js"],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    output: {
 | 
				
			||||||
 | 
					        filename: "bundle.js",
 | 
				
			||||||
 | 
					        path: path.resolve(__dirname, "public"),
 | 
				
			||||||
 | 
					        publicPath: "/",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    mode: "development",
 | 
				
			||||||
 | 
					    devtool: "source-map",
 | 
				
			||||||
 | 
					    devServer: {
 | 
				
			||||||
 | 
					        port: port,
 | 
				
			||||||
 | 
					        open: openBrowser,
 | 
				
			||||||
 | 
					        historyApiFallback: {
 | 
				
			||||||
 | 
					            index: "index.html",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        static: "public",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||